]> code.delx.au - pulseaudio/blob - src/pulsecore/core-util.c
Merge commit 'origin/master-tx' into master-tx
[pulseaudio] / src / pulsecore / core-util.c
1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2004 Joe Marcus Clarke
6 Copyright 2006-2007 Pierre Ossman <ossman@cendio.se> for Cendio AB
7
8 PulseAudio is free software; you can redistribute it and/or modify
9 it under the terms of the GNU Lesser General Public License as
10 published by the Free Software Foundation; either version 2.1 of the
11 License, or (at your option) any later version.
12
13 PulseAudio is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public
19 License along with PulseAudio; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 USA.
22 ***/
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <stdarg.h>
29 #include <stdlib.h>
30 #include <signal.h>
31 #include <errno.h>
32 #include <string.h>
33 #include <stdio.h>
34 #include <fcntl.h>
35 #include <unistd.h>
36 #include <limits.h>
37 #include <time.h>
38 #include <ctype.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <sys/time.h>
42 #include <dirent.h>
43 #include <regex.h>
44 #include <langinfo.h>
45 #include <sys/utsname.h>
46
47 #ifdef HAVE_STRTOF_L
48 #include <locale.h>
49 #endif
50
51 #ifdef HAVE_SCHED_H
52 #include <sched.h>
53 #endif
54
55 #ifdef HAVE_SYS_RESOURCE_H
56 #include <sys/resource.h>
57 #endif
58
59 #ifdef HAVE_SYS_CAPABILITY_H
60 #include <sys/capability.h>
61 #endif
62
63 #ifdef HAVE_SYS_MMAN_H
64 #include <sys/mman.h>
65 #endif
66
67 #ifdef HAVE_PTHREAD
68 #include <pthread.h>
69 #endif
70
71 #ifdef HAVE_NETDB_H
72 #include <netdb.h>
73 #endif
74
75 #ifdef HAVE_WINDOWS_H
76 #include <windows.h>
77 #endif
78
79 #ifdef HAVE_PWD_H
80 #include <pwd.h>
81 #endif
82
83 #ifdef HAVE_GRP_H
84 #include <grp.h>
85 #endif
86
87 #ifdef HAVE_LIBSAMPLERATE
88 #include <samplerate.h>
89 #endif
90
91 #include <pulse/xmalloc.h>
92 #include <pulse/util.h>
93 #include <pulse/utf8.h>
94
95 #include <pulsecore/core-error.h>
96 #include <pulsecore/winsock.h>
97 #include <pulsecore/log.h>
98 #include <pulsecore/macro.h>
99 #include <pulsecore/thread.h>
100
101 #include "core-util.h"
102
103 /* Not all platforms have this */
104 #ifndef MSG_NOSIGNAL
105 #define MSG_NOSIGNAL 0
106 #endif
107
108 #ifdef OS_IS_WIN32
109
110 #define PULSE_ROOTENV "PULSE_ROOT"
111
112 int pa_set_root(HANDLE handle) {
113 char library_path[MAX_PATH + sizeof(PULSE_ROOTENV) + 1], *sep;
114
115 strcpy(library_path, PULSE_ROOTENV "=");
116
117 /* FIXME: Needs to set errno */
118
119 if (!GetModuleFileName(handle, library_path + sizeof(PULSE_ROOTENV), MAX_PATH))
120 return 0;
121
122 sep = strrchr(library_path, PA_PATH_SEP_CHAR);
123 if (sep)
124 *sep = '\0';
125
126 if (_putenv(library_path) < 0)
127 return 0;
128
129 return 1;
130 }
131
132 #endif
133
134 /** Make a file descriptor nonblock. Doesn't do any error checking */
135 void pa_make_fd_nonblock(int fd) {
136
137 #ifdef O_NONBLOCK
138 int v;
139 pa_assert(fd >= 0);
140
141 pa_assert_se((v = fcntl(fd, F_GETFL)) >= 0);
142
143 if (!(v & O_NONBLOCK))
144 pa_assert_se(fcntl(fd, F_SETFL, v|O_NONBLOCK) >= 0);
145
146 #elif defined(OS_IS_WIN32)
147 u_long arg = 1;
148 if (ioctlsocket(fd, FIONBIO, &arg) < 0) {
149 pa_assert_se(WSAGetLastError() == WSAENOTSOCK);
150 pa_log_warn("Only sockets can be made non-blocking!");
151 }
152 #else
153 pa_log_warn("Non-blocking I/O not supported.!");
154 #endif
155
156 }
157
158 /* Set the FD_CLOEXEC flag for a fd */
159 void pa_make_fd_cloexec(int fd) {
160
161 #ifdef FD_CLOEXEC
162 int v;
163 pa_assert(fd >= 0);
164
165 pa_assert_se((v = fcntl(fd, F_GETFD, 0)) >= 0);
166
167 if (!(v & FD_CLOEXEC))
168 pa_assert_se(fcntl(fd, F_SETFD, v|FD_CLOEXEC) >= 0);
169 #endif
170
171 }
172
173 /** Creates a directory securely */
174 int pa_make_secure_dir(const char* dir, mode_t m, uid_t uid, gid_t gid) {
175 struct stat st;
176 int r, saved_errno;
177
178 pa_assert(dir);
179
180 #ifdef OS_IS_WIN32
181 r = mkdir(dir);
182 #else
183 {
184 mode_t u;
185 u = umask((~m) & 0777);
186 r = mkdir(dir, m);
187 umask(u);
188 }
189 #endif
190
191 if (r < 0 && errno != EEXIST)
192 return -1;
193
194 #ifdef HAVE_CHOWN
195 if (uid == (uid_t)-1)
196 uid = getuid();
197 if (gid == (gid_t)-1)
198 gid = getgid();
199 (void) chown(dir, uid, gid);
200 #endif
201
202 #ifdef HAVE_CHMOD
203 chmod(dir, m);
204 #endif
205
206 #ifdef HAVE_LSTAT
207 if (lstat(dir, &st) < 0)
208 #else
209 if (stat(dir, &st) < 0)
210 #endif
211 goto fail;
212
213 #ifndef OS_IS_WIN32
214 if (!S_ISDIR(st.st_mode) ||
215 (st.st_uid != uid) ||
216 (st.st_gid != gid) ||
217 ((st.st_mode & 0777) != m)) {
218 errno = EACCES;
219 goto fail;
220 }
221 #else
222 pa_log_warn("Secure directory creation not supported on Win32.");
223 #endif
224
225 return 0;
226
227 fail:
228 saved_errno = errno;
229 rmdir(dir);
230 errno = saved_errno;
231
232 return -1;
233 }
234
235 /* Return a newly allocated sting containing the parent directory of the specified file */
236 char *pa_parent_dir(const char *fn) {
237 char *slash, *dir = pa_xstrdup(fn);
238
239 if ((slash = (char*) pa_path_get_filename(dir)) == dir) {
240 pa_xfree(dir);
241 errno = ENOENT;
242 return NULL;
243 }
244
245 *(slash-1) = 0;
246 return dir;
247 }
248
249 /* Creates a the parent directory of the specified path securely */
250 int pa_make_secure_parent_dir(const char *fn, mode_t m, uid_t uid, gid_t gid) {
251 int ret = -1;
252 char *dir;
253
254 if (!(dir = pa_parent_dir(fn)))
255 goto finish;
256
257 if (pa_make_secure_dir(dir, m, uid, gid) < 0)
258 goto finish;
259
260 ret = 0;
261
262 finish:
263 pa_xfree(dir);
264 return ret;
265 }
266
267 /** Platform independent read function. Necessary since not all
268 * systems treat all file descriptors equal. If type is
269 * non-NULL it is used to cache the type of the fd. This is
270 * useful for making sure that only a single syscall is executed per
271 * function call. The variable pointed to should be initialized to 0
272 * by the caller. */
273 ssize_t pa_read(int fd, void *buf, size_t count, int *type) {
274
275 #ifdef OS_IS_WIN32
276
277 if (!type || *type == 0) {
278 ssize_t r;
279
280 if ((r = recv(fd, buf, count, 0)) >= 0)
281 return r;
282
283 if (WSAGetLastError() != WSAENOTSOCK) {
284 errno = WSAGetLastError();
285 return r;
286 }
287
288 if (type)
289 *type = 1;
290 }
291
292 #endif
293
294 return read(fd, buf, count);
295 }
296
297 /** Similar to pa_read(), but handles writes */
298 ssize_t pa_write(int fd, const void *buf, size_t count, int *type) {
299
300 if (!type || *type == 0) {
301 ssize_t r;
302
303 if ((r = send(fd, buf, count, MSG_NOSIGNAL)) >= 0)
304 return r;
305
306 #ifdef OS_IS_WIN32
307 if (WSAGetLastError() != WSAENOTSOCK) {
308 errno = WSAGetLastError();
309 return r;
310 }
311 #else
312 if (errno != ENOTSOCK)
313 return r;
314 #endif
315
316 if (type)
317 *type = 1;
318 }
319
320 return write(fd, buf, count);
321 }
322
323 /** Calls read() in a loop. Makes sure that as much as 'size' bytes,
324 * unless EOF is reached or an error occured */
325 ssize_t pa_loop_read(int fd, void*data, size_t size, int *type) {
326 ssize_t ret = 0;
327 int _type;
328
329 pa_assert(fd >= 0);
330 pa_assert(data);
331 pa_assert(size);
332
333 if (!type) {
334 _type = 0;
335 type = &_type;
336 }
337
338 while (size > 0) {
339 ssize_t r;
340
341 if ((r = pa_read(fd, data, size, type)) < 0)
342 return r;
343
344 if (r == 0)
345 break;
346
347 ret += r;
348 data = (uint8_t*) data + r;
349 size -= (size_t) r;
350 }
351
352 return ret;
353 }
354
355 /** Similar to pa_loop_read(), but wraps write() */
356 ssize_t pa_loop_write(int fd, const void*data, size_t size, int *type) {
357 ssize_t ret = 0;
358 int _type;
359
360 pa_assert(fd >= 0);
361 pa_assert(data);
362 pa_assert(size);
363
364 if (!type) {
365 _type = 0;
366 type = &_type;
367 }
368
369 while (size > 0) {
370 ssize_t r;
371
372 if ((r = pa_write(fd, data, size, type)) < 0)
373 return r;
374
375 if (r == 0)
376 break;
377
378 ret += r;
379 data = (const uint8_t*) data + r;
380 size -= (size_t) r;
381 }
382
383 return ret;
384 }
385
386 /** Platform independent read function. Necessary since not all
387 * systems treat all file descriptors equal. */
388 int pa_close(int fd) {
389
390 #ifdef OS_IS_WIN32
391 int ret;
392
393 if ((ret = closesocket(fd)) == 0)
394 return 0;
395
396 if (WSAGetLastError() != WSAENOTSOCK) {
397 errno = WSAGetLastError();
398 return ret;
399 }
400 #endif
401
402 for (;;) {
403 int r;
404
405 if ((r = close(fd)) >= 0)
406 return r;
407
408 if (errno != EINTR)
409 return r;
410 }
411 }
412
413 /* Print a warning messages in case that the given signal is not
414 * blocked or trapped */
415 void pa_check_signal_is_blocked(int sig) {
416 #ifdef HAVE_SIGACTION
417 struct sigaction sa;
418 sigset_t set;
419
420 /* If POSIX threads are supported use thread-aware
421 * pthread_sigmask() function, to check if the signal is
422 * blocked. Otherwise fall back to sigprocmask() */
423
424 #ifdef HAVE_PTHREAD
425 if (pthread_sigmask(SIG_SETMASK, NULL, &set) < 0) {
426 #endif
427 if (sigprocmask(SIG_SETMASK, NULL, &set) < 0) {
428 pa_log("sigprocmask(): %s", pa_cstrerror(errno));
429 return;
430 }
431 #ifdef HAVE_PTHREAD
432 }
433 #endif
434
435 if (sigismember(&set, sig))
436 return;
437
438 /* Check whether the signal is trapped */
439
440 if (sigaction(sig, NULL, &sa) < 0) {
441 pa_log("sigaction(): %s", pa_cstrerror(errno));
442 return;
443 }
444
445 if (sa.sa_handler != SIG_DFL)
446 return;
447
448 pa_log_warn("%s is not trapped. This might cause malfunction!", pa_sig2str(sig));
449 #else /* HAVE_SIGACTION */
450 pa_log_warn("%s might not be trapped. This might cause malfunction!", pa_sig2str(sig));
451 #endif
452 }
453
454 /* The following function is based on an example from the GNU libc
455 * documentation. This function is similar to GNU's asprintf(). */
456 char *pa_sprintf_malloc(const char *format, ...) {
457 size_t size = 100;
458 char *c = NULL;
459
460 pa_assert(format);
461
462 for(;;) {
463 int r;
464 va_list ap;
465
466 c = pa_xrealloc(c, size);
467
468 va_start(ap, format);
469 r = vsnprintf(c, size, format, ap);
470 va_end(ap);
471
472 c[size-1] = 0;
473
474 if (r > -1 && (size_t) r < size)
475 return c;
476
477 if (r > -1) /* glibc 2.1 */
478 size = (size_t) r+1;
479 else /* glibc 2.0 */
480 size *= 2;
481 }
482 }
483
484 /* Same as the previous function, but use a va_list instead of an
485 * ellipsis */
486 char *pa_vsprintf_malloc(const char *format, va_list ap) {
487 size_t size = 100;
488 char *c = NULL;
489
490 pa_assert(format);
491
492 for(;;) {
493 int r;
494 va_list aq;
495
496 c = pa_xrealloc(c, size);
497
498 va_copy(aq, ap);
499 r = vsnprintf(c, size, format, aq);
500 va_end(aq);
501
502 c[size-1] = 0;
503
504 if (r > -1 && (size_t) r < size)
505 return c;
506
507 if (r > -1) /* glibc 2.1 */
508 size = (size_t) r+1;
509 else /* glibc 2.0 */
510 size *= 2;
511 }
512 }
513
514 /* Similar to OpenBSD's strlcpy() function */
515 char *pa_strlcpy(char *b, const char *s, size_t l) {
516 pa_assert(b);
517 pa_assert(s);
518 pa_assert(l > 0);
519
520 strncpy(b, s, l);
521 b[l-1] = 0;
522 return b;
523 }
524
525 /* Make the current thread a realtime thread, and acquire the highest
526 * rtprio we can get that is less or equal the specified parameter. If
527 * the thread is already realtime, don't do anything. */
528 int pa_make_realtime(int rtprio) {
529
530 #ifdef _POSIX_PRIORITY_SCHEDULING
531 struct sched_param sp;
532 int r, policy;
533
534 memset(&sp, 0, sizeof(sp));
535 policy = 0;
536
537 if ((r = pthread_getschedparam(pthread_self(), &policy, &sp)) != 0) {
538 pa_log("pthread_getschedgetparam(): %s", pa_cstrerror(r));
539 return -1;
540 }
541
542 if (policy == SCHED_FIFO && sp.sched_priority >= rtprio) {
543 pa_log_info("Thread already being scheduled with SCHED_FIFO with priority %i.", sp.sched_priority);
544 return 0;
545 }
546
547 sp.sched_priority = rtprio;
548 if ((r = pthread_setschedparam(pthread_self(), SCHED_FIFO, &sp)) != 0) {
549
550 while (sp.sched_priority > 1) {
551 sp.sched_priority --;
552
553 if ((r = pthread_setschedparam(pthread_self(), SCHED_FIFO, &sp)) == 0) {
554 pa_log_info("Successfully enabled SCHED_FIFO scheduling for thread, with priority %i, which is lower than the requested %i.", sp.sched_priority, rtprio);
555 return 0;
556 }
557 }
558
559 pa_log_warn("pthread_setschedparam(): %s", pa_cstrerror(r));
560 return -1;
561 }
562
563 pa_log_info("Successfully enabled SCHED_FIFO scheduling for thread, with priority %i.", sp.sched_priority);
564 return 0;
565 #else
566
567 errno = ENOTSUP;
568 return -1;
569 #endif
570 }
571
572 /* This is merely used for giving the user a hint. This is not correct
573 * for anything security related */
574 pa_bool_t pa_can_realtime(void) {
575
576 if (geteuid() == 0)
577 return TRUE;
578
579 #if defined(HAVE_SYS_RESOURCE_H) && defined(RLIMIT_RTPRIO)
580 {
581 struct rlimit rl;
582
583 if (getrlimit(RLIMIT_RTPRIO, &rl) >= 0)
584 if (rl.rlim_cur > 0 || rl.rlim_cur == RLIM_INFINITY)
585 return TRUE;
586 }
587 #endif
588
589 #if defined(HAVE_SYS_CAPABILITY_H) && defined(CAP_SYS_NICE)
590 {
591 cap_t cap;
592
593 if ((cap = cap_get_proc())) {
594 cap_flag_value_t flag = CAP_CLEAR;
595
596 if (cap_get_flag(cap, CAP_SYS_NICE, CAP_EFFECTIVE, &flag) >= 0)
597 if (flag == CAP_SET) {
598 cap_free(cap);
599 return TRUE;
600 }
601
602 cap_free(cap);
603 }
604 }
605 #endif
606
607 return FALSE;
608 }
609
610 /* This is merely used for giving the user a hint. This is not correct
611 * for anything security related */
612 pa_bool_t pa_can_high_priority(void) {
613
614 if (geteuid() == 0)
615 return TRUE;
616
617 #if defined(HAVE_SYS_RESOURCE_H) && defined(RLIMIT_RTPRIO)
618 {
619 struct rlimit rl;
620
621 if (getrlimit(RLIMIT_NICE, &rl) >= 0)
622 if (rl.rlim_cur >= 21 || rl.rlim_cur == RLIM_INFINITY)
623 return TRUE;
624 }
625 #endif
626
627 #if defined(HAVE_SYS_CAPABILITY_H) && defined(CAP_SYS_NICE)
628 {
629 cap_t cap;
630
631 if ((cap = cap_get_proc())) {
632 cap_flag_value_t flag = CAP_CLEAR;
633
634 if (cap_get_flag(cap, CAP_SYS_NICE, CAP_EFFECTIVE, &flag) >= 0)
635 if (flag == CAP_SET) {
636 cap_free(cap);
637 return TRUE;
638 }
639
640 cap_free(cap);
641 }
642 }
643 #endif
644
645 return FALSE;
646 }
647
648 /* Raise the priority of the current process as much as possible that
649 * is <= the specified nice level..*/
650 int pa_raise_priority(int nice_level) {
651
652 #ifdef HAVE_SYS_RESOURCE_H
653 if (setpriority(PRIO_PROCESS, 0, nice_level) < 0) {
654 int n;
655
656 for (n = nice_level+1; n < 0; n++) {
657
658 if (setpriority(PRIO_PROCESS, 0, n) == 0) {
659 pa_log_info("Successfully acquired nice level %i, which is lower than the requested %i.", n, nice_level);
660 return 0;
661 }
662 }
663
664 pa_log_warn("setpriority(): %s", pa_cstrerror(errno));
665 return -1;
666 }
667
668 pa_log_info("Successfully gained nice level %i.", nice_level);
669 #endif
670
671 #ifdef OS_IS_WIN32
672 if (nice_level < 0) {
673 if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS)) {
674 pa_log_warn("SetPriorityClass() failed: 0x%08X", GetLastError());
675 errno = EPERM;
676 return .-1;
677 } else
678 pa_log_info("Successfully gained high priority class.");
679 }
680 #endif
681
682 return 0;
683 }
684
685 /* Reset the priority to normal, inverting the changes made by
686 * pa_raise_priority() and pa_make_realtime()*/
687 void pa_reset_priority(void) {
688 #ifdef HAVE_SYS_RESOURCE_H
689 struct sched_param sp;
690
691 setpriority(PRIO_PROCESS, 0, 0);
692
693 memset(&sp, 0, sizeof(sp));
694 pa_assert_se(pthread_setschedparam(pthread_self(), SCHED_OTHER, &sp) == 0);
695 #endif
696
697 #ifdef OS_IS_WIN32
698 SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS);
699 #endif
700 }
701
702 static int match(const char *expr, const char *v) {
703 int k;
704 regex_t re;
705 int r;
706
707 if (regcomp(&re, expr, REG_NOSUB|REG_EXTENDED) != 0) {
708 errno = EINVAL;
709 return -1;
710 }
711
712 if ((k = regexec(&re, v, 0, NULL, 0)) == 0)
713 r = 1;
714 else if (k == REG_NOMATCH)
715 r = 0;
716 else
717 r = -1;
718
719 regfree(&re);
720
721 if (r < 0)
722 errno = EINVAL;
723
724 return r;
725 }
726
727 /* Try to parse a boolean string value.*/
728 int pa_parse_boolean(const char *v) {
729 const char *expr;
730 int r;
731 pa_assert(v);
732
733 /* First we check language independant */
734 if (!strcmp(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || !strcasecmp(v, "on"))
735 return 1;
736 else if (!strcmp(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || !strcasecmp(v, "off"))
737 return 0;
738
739 /* And then we check language dependant */
740 if ((expr = nl_langinfo(YESEXPR)))
741 if (expr[0])
742 if ((r = match(expr, v)) > 0)
743 return 1;
744
745 if ((expr = nl_langinfo(NOEXPR)))
746 if (expr[0])
747 if ((r = match(expr, v)) > 0)
748 return 0;
749
750 errno = EINVAL;
751 return -1;
752 }
753
754 /* Split the specified string wherever one of the strings in delimiter
755 * occurs. Each time it is called returns a newly allocated string
756 * with pa_xmalloc(). The variable state points to, should be
757 * initiallized to NULL before the first call. */
758 char *pa_split(const char *c, const char *delimiter, const char**state) {
759 const char *current = *state ? *state : c;
760 size_t l;
761
762 if (!*current)
763 return NULL;
764
765 l = strcspn(current, delimiter);
766 *state = current+l;
767
768 if (**state)
769 (*state)++;
770
771 return pa_xstrndup(current, l);
772 }
773
774 /* What is interpreted as whitespace? */
775 #define WHITESPACE " \t\n"
776
777 /* Split a string into words. Otherwise similar to pa_split(). */
778 char *pa_split_spaces(const char *c, const char **state) {
779 const char *current = *state ? *state : c;
780 size_t l;
781
782 if (!*current || *c == 0)
783 return NULL;
784
785 current += strspn(current, WHITESPACE);
786 l = strcspn(current, WHITESPACE);
787
788 *state = current+l;
789
790 return pa_xstrndup(current, l);
791 }
792
793 PA_STATIC_TLS_DECLARE(signame, pa_xfree);
794
795 /* Return the name of an UNIX signal. Similar to Solaris sig2str() */
796 const char *pa_sig2str(int sig) {
797 char *t;
798
799 if (sig <= 0)
800 goto fail;
801
802 #ifdef NSIG
803 if (sig >= NSIG)
804 goto fail;
805 #endif
806
807 #ifdef HAVE_SIG2STR
808 {
809 char buf[SIG2STR_MAX];
810
811 if (sig2str(sig, buf) == 0) {
812 pa_xfree(PA_STATIC_TLS_GET(signame));
813 t = pa_sprintf_malloc("SIG%s", buf);
814 PA_STATIC_TLS_SET(signame, t);
815 return t;
816 }
817 }
818 #else
819
820 switch(sig) {
821 #ifdef SIGHUP
822 case SIGHUP: return "SIGHUP";
823 #endif
824 case SIGINT: return "SIGINT";
825 #ifdef SIGQUIT
826 case SIGQUIT: return "SIGQUIT";
827 #endif
828 case SIGILL: return "SIGULL";
829 #ifdef SIGTRAP
830 case SIGTRAP: return "SIGTRAP";
831 #endif
832 case SIGABRT: return "SIGABRT";
833 #ifdef SIGBUS
834 case SIGBUS: return "SIGBUS";
835 #endif
836 case SIGFPE: return "SIGFPE";
837 #ifdef SIGKILL
838 case SIGKILL: return "SIGKILL";
839 #endif
840 #ifdef SIGUSR1
841 case SIGUSR1: return "SIGUSR1";
842 #endif
843 case SIGSEGV: return "SIGSEGV";
844 #ifdef SIGUSR2
845 case SIGUSR2: return "SIGUSR2";
846 #endif
847 #ifdef SIGPIPE
848 case SIGPIPE: return "SIGPIPE";
849 #endif
850 #ifdef SIGALRM
851 case SIGALRM: return "SIGALRM";
852 #endif
853 case SIGTERM: return "SIGTERM";
854 #ifdef SIGSTKFLT
855 case SIGSTKFLT: return "SIGSTKFLT";
856 #endif
857 #ifdef SIGCHLD
858 case SIGCHLD: return "SIGCHLD";
859 #endif
860 #ifdef SIGCONT
861 case SIGCONT: return "SIGCONT";
862 #endif
863 #ifdef SIGSTOP
864 case SIGSTOP: return "SIGSTOP";
865 #endif
866 #ifdef SIGTSTP
867 case SIGTSTP: return "SIGTSTP";
868 #endif
869 #ifdef SIGTTIN
870 case SIGTTIN: return "SIGTTIN";
871 #endif
872 #ifdef SIGTTOU
873 case SIGTTOU: return "SIGTTOU";
874 #endif
875 #ifdef SIGURG
876 case SIGURG: return "SIGURG";
877 #endif
878 #ifdef SIGXCPU
879 case SIGXCPU: return "SIGXCPU";
880 #endif
881 #ifdef SIGXFSZ
882 case SIGXFSZ: return "SIGXFSZ";
883 #endif
884 #ifdef SIGVTALRM
885 case SIGVTALRM: return "SIGVTALRM";
886 #endif
887 #ifdef SIGPROF
888 case SIGPROF: return "SIGPROF";
889 #endif
890 #ifdef SIGWINCH
891 case SIGWINCH: return "SIGWINCH";
892 #endif
893 #ifdef SIGIO
894 case SIGIO: return "SIGIO";
895 #endif
896 #ifdef SIGPWR
897 case SIGPWR: return "SIGPWR";
898 #endif
899 #ifdef SIGSYS
900 case SIGSYS: return "SIGSYS";
901 #endif
902 }
903
904 #ifdef SIGRTMIN
905 if (sig >= SIGRTMIN && sig <= SIGRTMAX) {
906 pa_xfree(PA_STATIC_TLS_GET(signame));
907 t = pa_sprintf_malloc("SIGRTMIN+%i", sig - SIGRTMIN);
908 PA_STATIC_TLS_SET(signame, t);
909 return t;
910 }
911 #endif
912
913 #endif
914
915 fail:
916
917 pa_xfree(PA_STATIC_TLS_GET(signame));
918 t = pa_sprintf_malloc("SIG%i", sig);
919 PA_STATIC_TLS_SET(signame, t);
920 return t;
921 }
922
923 #ifdef HAVE_GRP_H
924
925 /* Check whether the specified GID and the group name match */
926 static int is_group(gid_t gid, const char *name) {
927 struct group group, *result = NULL;
928 long n;
929 void *data;
930 int r = -1;
931
932 #ifdef HAVE_GETGRGID_R
933 #ifdef _SC_GETGR_R_SIZE_MAX
934 n = sysconf(_SC_GETGR_R_SIZE_MAX);
935 #else
936 n = -1;
937 #endif
938 if (n < 0)
939 n = 512;
940
941 data = pa_xmalloc((size_t) n);
942
943 errno = 0;
944 if (getgrgid_r(gid, &group, data, (size_t) n, &result) < 0 || !result) {
945 pa_log("getgrgid_r(%u): %s", (unsigned) gid, pa_cstrerror(errno));
946
947 if (!errno)
948 errno = ENOENT;
949
950 goto finish;
951 }
952
953 r = strcmp(name, result->gr_name) == 0;
954
955 finish:
956 pa_xfree(data);
957 #else
958 /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) that do not
959 * support getgrgid_r. */
960
961 errno = 0;
962 if ((result = getgrgid(gid)) == NULL) {
963 pa_log("getgrgid(%u): %s", gid, pa_cstrerror(errno));
964
965 if (!errno)
966 errno = ENOENT;
967
968 goto finish;
969 }
970
971 r = strcmp(name, result->gr_name) == 0;
972
973 finish:
974 #endif
975
976 return r;
977 }
978
979 /* Check the current user is member of the specified group */
980 int pa_own_uid_in_group(const char *name, gid_t *gid) {
981 GETGROUPS_T *gids, tgid;
982 long n = sysconf(_SC_NGROUPS_MAX);
983 int r = -1, i, k;
984
985 pa_assert(n > 0);
986
987 gids = pa_xmalloc(sizeof(GETGROUPS_T) * (size_t) n);
988
989 if ((n = getgroups((int) n, gids)) < 0) {
990 pa_log("getgroups(): %s", pa_cstrerror(errno));
991 goto finish;
992 }
993
994 for (i = 0; i < n; i++) {
995
996 if ((k = is_group(gids[i], name)) < 0)
997 goto finish;
998 else if (k > 0) {
999 *gid = gids[i];
1000 r = 1;
1001 goto finish;
1002 }
1003 }
1004
1005 if ((k = is_group(tgid = getgid(), name)) < 0)
1006 goto finish;
1007 else if (k > 0) {
1008 *gid = tgid;
1009 r = 1;
1010 goto finish;
1011 }
1012
1013 r = 0;
1014
1015 finish:
1016
1017 pa_xfree(gids);
1018 return r;
1019 }
1020
1021 /* Check whether the specifc user id is a member of the specified group */
1022 int pa_uid_in_group(uid_t uid, const char *name) {
1023 char *g_buf, *p_buf;
1024 long g_n, p_n;
1025 struct group grbuf, *gr;
1026 char **i;
1027 int r = -1;
1028
1029 g_n = sysconf(_SC_GETGR_R_SIZE_MAX);
1030 g_buf = pa_xmalloc((size_t) g_n);
1031
1032 p_n = sysconf(_SC_GETPW_R_SIZE_MAX);
1033 p_buf = pa_xmalloc((size_t) p_n);
1034
1035 errno = 0;
1036 if (getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr) != 0 || !gr) {
1037
1038 if (!errno)
1039 errno = ENOENT;
1040
1041 goto finish;
1042 }
1043
1044 r = 0;
1045 for (i = gr->gr_mem; *i; i++) {
1046 struct passwd pwbuf, *pw;
1047
1048 errno = 0;
1049 if (getpwnam_r(*i, &pwbuf, p_buf, (size_t) p_n, &pw) != 0 || !pw)
1050 continue;
1051
1052 if (pw->pw_uid == uid) {
1053 r = 1;
1054 break;
1055 }
1056 }
1057
1058 finish:
1059 pa_xfree(g_buf);
1060 pa_xfree(p_buf);
1061
1062 return r;
1063 }
1064
1065 /* Get the GID of a gfiven group, return (gid_t) -1 on failure. */
1066 gid_t pa_get_gid_of_group(const char *name) {
1067 gid_t ret = (gid_t) -1;
1068 char *g_buf;
1069 long g_n;
1070 struct group grbuf, *gr;
1071
1072 g_n = sysconf(_SC_GETGR_R_SIZE_MAX);
1073 g_buf = pa_xmalloc((size_t) g_n);
1074
1075 errno = 0;
1076 if (getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr) != 0 || !gr) {
1077
1078 if (!errno)
1079 errno = ENOENT;
1080
1081 goto finish;
1082 }
1083
1084 ret = gr->gr_gid;
1085
1086 finish:
1087 pa_xfree(g_buf);
1088 return ret;
1089 }
1090
1091 int pa_check_in_group(gid_t g) {
1092 gid_t gids[NGROUPS_MAX];
1093 int r;
1094
1095 if ((r = getgroups(NGROUPS_MAX, gids)) < 0)
1096 return -1;
1097
1098 for (; r > 0; r--)
1099 if (gids[r-1] == g)
1100 return 1;
1101
1102 return 0;
1103 }
1104
1105 #else /* HAVE_GRP_H */
1106
1107 int pa_own_uid_in_group(const char *name, gid_t *gid) {
1108 errno = ENOSUP;
1109 return -1;
1110
1111 }
1112
1113 int pa_uid_in_group(uid_t uid, const char *name) {
1114 errno = ENOSUP;
1115 return -1;
1116 }
1117
1118 gid_t pa_get_gid_of_group(const char *name) {
1119 errno = ENOSUP;
1120 return (gid_t) -1;
1121 }
1122
1123 int pa_check_in_group(gid_t g) {
1124 errno = ENOSUP;
1125 return -1;
1126 }
1127
1128 #endif
1129
1130 /* Lock or unlock a file entirely.
1131 (advisory on UNIX, mandatory on Windows) */
1132 int pa_lock_fd(int fd, int b) {
1133 #ifdef F_SETLKW
1134 struct flock flock;
1135
1136 /* Try a R/W lock first */
1137
1138 flock.l_type = (short) (b ? F_WRLCK : F_UNLCK);
1139 flock.l_whence = SEEK_SET;
1140 flock.l_start = 0;
1141 flock.l_len = 0;
1142
1143 if (fcntl(fd, F_SETLKW, &flock) >= 0)
1144 return 0;
1145
1146 /* Perhaps the file descriptor qas opened for read only, than try again with a read lock. */
1147 if (b && errno == EBADF) {
1148 flock.l_type = F_RDLCK;
1149 if (fcntl(fd, F_SETLKW, &flock) >= 0)
1150 return 0;
1151 }
1152
1153 pa_log("%slock: %s", !b? "un" : "", pa_cstrerror(errno));
1154 #endif
1155
1156 #ifdef OS_IS_WIN32
1157 HANDLE h = (HANDLE)_get_osfhandle(fd);
1158
1159 if (b && LockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF))
1160 return 0;
1161 if (!b && UnlockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF))
1162 return 0;
1163
1164 pa_log("%slock failed: 0x%08X", !b ? "un" : "", GetLastError());
1165
1166 /* FIXME: Needs to set errno! */
1167 #endif
1168
1169 return -1;
1170 }
1171
1172 /* Remove trailing newlines from a string */
1173 char* pa_strip_nl(char *s) {
1174 pa_assert(s);
1175
1176 s[strcspn(s, "\r\n")] = 0;
1177 return s;
1178 }
1179
1180 /* Create a temporary lock file and lock it. */
1181 int pa_lock_lockfile(const char *fn) {
1182 int fd = -1;
1183 pa_assert(fn);
1184
1185 for (;;) {
1186 struct stat st;
1187
1188 if ((fd = open(fn, O_CREAT|O_RDWR
1189 #ifdef O_NOCTTY
1190 |O_NOCTTY
1191 #endif
1192 #ifdef O_NOFOLLOW
1193 |O_NOFOLLOW
1194 #endif
1195 , S_IRUSR|S_IWUSR)) < 0) {
1196 pa_log_warn("Failed to create lock file '%s': %s", fn, pa_cstrerror(errno));
1197 goto fail;
1198 }
1199
1200 if (pa_lock_fd(fd, 1) < 0) {
1201 pa_log_warn("Failed to lock file '%s'.", fn);
1202 goto fail;
1203 }
1204
1205 if (fstat(fd, &st) < 0) {
1206 pa_log_warn("Failed to fstat() file '%s': %s", fn, pa_cstrerror(errno));
1207 goto fail;
1208 }
1209
1210 /* Check wheter the file has been removed meanwhile. When yes,
1211 * restart this loop, otherwise, we're done */
1212 if (st.st_nlink >= 1)
1213 break;
1214
1215 if (pa_lock_fd(fd, 0) < 0) {
1216 pa_log_warn("Failed to unlock file '%s'.", fn);
1217 goto fail;
1218 }
1219
1220 if (pa_close(fd) < 0) {
1221 pa_log_warn("Failed to close file '%s': %s", fn, pa_cstrerror(errno));
1222 fd = -1;
1223 goto fail;
1224 }
1225
1226 fd = -1;
1227 }
1228
1229 return fd;
1230
1231 fail:
1232
1233 if (fd >= 0) {
1234 int saved_errno = errno;
1235 pa_close(fd);
1236 errno = saved_errno;
1237 }
1238
1239 return -1;
1240 }
1241
1242 /* Unlock a temporary lcok file */
1243 int pa_unlock_lockfile(const char *fn, int fd) {
1244 int r = 0;
1245 pa_assert(fd >= 0);
1246
1247 if (fn) {
1248 if (unlink(fn) < 0) {
1249 pa_log_warn("Unable to remove lock file '%s': %s", fn, pa_cstrerror(errno));
1250 r = -1;
1251 }
1252 }
1253
1254 if (pa_lock_fd(fd, 0) < 0) {
1255 pa_log_warn("Failed to unlock file '%s'.", fn);
1256 r = -1;
1257 }
1258
1259 if (pa_close(fd) < 0) {
1260 pa_log_warn("Failed to close '%s': %s", fn, pa_cstrerror(errno));
1261 r = -1;
1262 }
1263
1264 return r;
1265 }
1266
1267 static char *get_pulse_home(void) {
1268 char h[PATH_MAX];
1269 struct stat st;
1270
1271 if (!pa_get_home_dir(h, sizeof(h))) {
1272 pa_log_error("Failed to get home directory.");
1273 return NULL;
1274 }
1275
1276 if (stat(h, &st) < 0) {
1277 pa_log_error("Failed to stat home directory %s: %s", h, pa_cstrerror(errno));
1278 return NULL;
1279 }
1280
1281 if (st.st_uid != getuid()) {
1282 pa_log_error("Home directory %s not ours.", h);
1283 errno = EACCES;
1284 return NULL;
1285 }
1286
1287 return pa_sprintf_malloc("%s" PA_PATH_SEP ".pulse", h);
1288 }
1289
1290 char *pa_get_state_dir(void) {
1291 char *d;
1292
1293 /* The state directory shall contain dynamic data that should be
1294 * kept across reboots, and is private to this user */
1295
1296 if (!(d = pa_xstrdup(getenv("PULSE_STATE_PATH"))))
1297 if (!(d = get_pulse_home()))
1298 return NULL;
1299
1300 /* If PULSE_STATE_PATH and PULSE_RUNTIME_PATH point to the same
1301 * dir then this will break. */
1302
1303 if (pa_make_secure_dir(d, 0700U, (uid_t) -1, (gid_t) -1) < 0) {
1304 pa_log_error("Failed to create secure directory: %s", pa_cstrerror(errno));
1305 pa_xfree(d);
1306 return NULL;
1307 }
1308
1309 return d;
1310 }
1311
1312 static char* make_random_dir(mode_t m) {
1313 static const char table[] =
1314 "abcdefghijklmnopqrstuvwxyz"
1315 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1316 "0123456789";
1317
1318 const char *tmpdir;
1319 char *fn;
1320 size_t pathlen;
1321
1322 if (!(tmpdir = getenv("TMPDIR")))
1323 if (!(tmpdir = getenv("TMP")))
1324 if (!(tmpdir = getenv("TEMP")))
1325 tmpdir = getenv("TEMPDIR");
1326
1327 if (!tmpdir || !pa_is_path_absolute(tmpdir))
1328 tmpdir = "/tmp";
1329
1330 fn = pa_sprintf_malloc("%s/pulse-XXXXXXXXXXXX", tmpdir);
1331 pathlen = strlen(fn);
1332
1333 for (;;) {
1334 size_t i;
1335 int r;
1336 mode_t u;
1337 int saved_errno;
1338
1339 for (i = pathlen - 12; i < pathlen; i++)
1340 fn[i] = table[rand() % (sizeof(table)-1)];
1341
1342 u = umask((~m) & 0777);
1343 r = mkdir(fn, m);
1344
1345 saved_errno = errno;
1346 umask(u);
1347 errno = saved_errno;
1348
1349 if (r >= 0)
1350 return fn;
1351
1352 if (errno != EEXIST) {
1353 pa_log_error("Failed to create random directory %s: %s", fn, pa_cstrerror(errno));
1354 pa_xfree(fn);
1355 return NULL;
1356 }
1357 }
1358 }
1359
1360 static int make_random_dir_and_link(mode_t m, const char *k) {
1361 char *p;
1362
1363 if (!(p = make_random_dir(m)))
1364 return -1;
1365
1366 if (symlink(p, k) < 0) {
1367 int saved_errno = errno;
1368
1369 if (errno != EEXIST)
1370 pa_log_error("Failed to symlink %s to %s: %s", k, p, pa_cstrerror(errno));
1371
1372 rmdir(p);
1373 pa_xfree(p);
1374
1375 errno = saved_errno;
1376 return -1;
1377 }
1378
1379 return 0;
1380 }
1381
1382 char *pa_get_runtime_dir(void) {
1383 char *d, *k = NULL, *p = NULL, *t = NULL, *mid;
1384 struct stat st;
1385 mode_t m;
1386
1387 /* The runtime directory shall contain dynamic data that needs NOT
1388 * to be kept accross reboots and is usuallly private to the user,
1389 * except in system mode, where it might be accessible by other
1390 * users, too. Since we need POSIX locking and UNIX sockets in
1391 * this directory, we link it to a random subdir in /tmp, if it
1392 * was not explicitly configured. */
1393
1394 m = pa_in_system_mode() ? 0755U : 0700U;
1395
1396 if ((d = getenv("PULSE_RUNTIME_PATH"))) {
1397
1398 if (pa_make_secure_dir(d, m, (uid_t) -1, (gid_t) -1) < 0) {
1399 pa_log_error("Failed to create secure directory: %s", pa_cstrerror(errno));
1400 goto fail;
1401 }
1402
1403 return pa_xstrdup(d);
1404 }
1405
1406 if (!(d = get_pulse_home()))
1407 goto fail;
1408
1409 if (pa_make_secure_dir(d, m, (uid_t) -1, (gid_t) -1) < 0) {
1410 pa_log_error("Failed to create secure directory: %s", pa_cstrerror(errno));
1411 goto fail;
1412 }
1413
1414 if (!(mid = pa_machine_id())) {
1415 pa_xfree(d);
1416 goto fail;
1417 }
1418
1419 k = pa_sprintf_malloc("%s" PA_PATH_SEP "%s:runtime", d, mid);
1420 pa_xfree(d);
1421 pa_xfree(mid);
1422
1423 for (;;) {
1424 /* OK, first let's check if the "runtime" symlink is already
1425 * existant */
1426
1427 if (!(p = pa_readlink(k))) {
1428
1429 if (errno != ENOENT) {
1430 pa_log_error("Failed to stat runtime directory %s: %s", k, pa_cstrerror(errno));
1431 goto fail;
1432 }
1433
1434 /* Hmm, so the runtime directory didn't exist yet, so let's
1435 * create one in /tmp and symlink that to it */
1436
1437 if (make_random_dir_and_link(0700, k) < 0) {
1438
1439 /* Mhmm, maybe another process was quicker than us,
1440 * let's check if that was valid */
1441 if (errno == EEXIST)
1442 continue;
1443
1444 goto fail;
1445 }
1446
1447 return k;
1448 }
1449
1450 /* Make sure that this actually makes sense */
1451 if (!pa_is_path_absolute(p)) {
1452 pa_log_error("Path %s in link %s is not absolute.", p, k);
1453 errno = ENOENT;
1454 goto fail;
1455 }
1456
1457 /* Hmm, so this symlink is still around, make sure nobody fools
1458 * us */
1459
1460 if (lstat(p, &st) < 0) {
1461
1462 if (errno != ENOENT) {
1463 pa_log_error("Failed to stat runtime directory %s: %s", p, pa_cstrerror(errno));
1464 goto fail;
1465 }
1466
1467 } else {
1468
1469 if (S_ISDIR(st.st_mode) &&
1470 (st.st_uid == getuid()) &&
1471 ((st.st_mode & 0777) == 0700)) {
1472
1473 pa_xfree(p);
1474 return k;
1475 }
1476
1477 pa_log_info("Hmm, runtime path exists, but points to an invalid directory. Changing runtime directory.");
1478 }
1479
1480 pa_xfree(p);
1481 p = NULL;
1482
1483 /* Hmm, so the link points to some nonexisting or invalid
1484 * dir. Let's replace it by a new link. We first create a
1485 * temporary link and then rename that to allow concurrent
1486 * execution of this function. */
1487
1488 t = pa_sprintf_malloc("%s.tmp", k);
1489
1490 if (make_random_dir_and_link(0700, t) < 0) {
1491
1492 if (errno != EEXIST) {
1493 pa_log_error("Failed to symlink %s: %s", t, pa_cstrerror(errno));
1494 goto fail;
1495 }
1496
1497 pa_xfree(t);
1498 t = NULL;
1499
1500 /* Hmm, someone lese was quicker then us. Let's give
1501 * him some time to finish, and retry. */
1502 pa_msleep(10);
1503 continue;
1504 }
1505
1506 /* OK, we succeeded in creating the temporary symlink, so
1507 * let's rename it */
1508 if (rename(t, k) < 0) {
1509 pa_log_error("Failed to rename %s to %s: %s", t, k, pa_cstrerror(errno));
1510 goto fail;
1511 }
1512
1513 pa_xfree(t);
1514 return k;
1515 }
1516
1517 fail:
1518 pa_xfree(p);
1519 pa_xfree(k);
1520 pa_xfree(t);
1521
1522 return NULL;
1523 }
1524
1525 /* Try to open a configuration file. If "env" is specified, open the
1526 * value of the specified environment variable. Otherwise look for a
1527 * file "local" in the home directory or a file "global" in global
1528 * file system. If "result" is non-NULL, a pointer to a newly
1529 * allocated buffer containing the used configuration file is
1530 * stored there.*/
1531 FILE *pa_open_config_file(const char *global, const char *local, const char *env, char **result) {
1532 const char *fn;
1533 #ifdef OS_IS_WIN32
1534 char buf[PATH_MAX];
1535
1536 if (!getenv(PULSE_ROOTENV))
1537 pa_set_root(NULL);
1538 #endif
1539
1540 if (env && (fn = getenv(env))) {
1541 FILE *f;
1542
1543 #ifdef OS_IS_WIN32
1544 if (!ExpandEnvironmentStrings(fn, buf, PATH_MAX))
1545 /* FIXME: Needs to set errno! */
1546 return NULL;
1547 fn = buf;
1548 #endif
1549
1550 if ((f = fopen(fn, "r"))) {
1551 if (result)
1552 *result = pa_xstrdup(fn);
1553
1554 return f;
1555 }
1556
1557 pa_log_warn("Failed to open configuration file '%s': %s", fn, pa_cstrerror(errno));
1558 return NULL;
1559 }
1560
1561 if (local) {
1562 const char *e;
1563 char *lfn;
1564 char h[PATH_MAX];
1565 FILE *f;
1566
1567 if ((e = getenv("PULSE_CONFIG_PATH")))
1568 fn = lfn = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", e, local);
1569 else if (pa_get_home_dir(h, sizeof(h)))
1570 fn = lfn = pa_sprintf_malloc("%s" PA_PATH_SEP ".pulse" PA_PATH_SEP "%s", h, local);
1571 else
1572 return NULL;
1573
1574 #ifdef OS_IS_WIN32
1575 if (!ExpandEnvironmentStrings(lfn, buf, PATH_MAX)) {
1576 /* FIXME: Needs to set errno! */
1577 pa_xfree(lfn);
1578 return NULL;
1579 }
1580 fn = buf;
1581 #endif
1582
1583 if ((f = fopen(fn, "r"))) {
1584 if (result)
1585 *result = pa_xstrdup(fn);
1586
1587 pa_xfree(lfn);
1588 return f;
1589 }
1590
1591 if (errno != ENOENT) {
1592 pa_log_warn("Failed to open configuration file '%s': %s", fn, pa_cstrerror(errno));
1593 pa_xfree(lfn);
1594 return NULL;
1595 }
1596
1597 pa_xfree(lfn);
1598 }
1599
1600 if (global) {
1601 FILE *f;
1602
1603 #ifdef OS_IS_WIN32
1604 if (!ExpandEnvironmentStrings(global, buf, PATH_MAX))
1605 /* FIXME: Needs to set errno! */
1606 return NULL;
1607 global = buf;
1608 #endif
1609
1610 if ((f = fopen(global, "r"))) {
1611
1612 if (result)
1613 *result = pa_xstrdup(global);
1614
1615 return f;
1616 }
1617 }
1618
1619 errno = ENOENT;
1620 return NULL;
1621 }
1622
1623 char *pa_find_config_file(const char *global, const char *local, const char *env) {
1624 const char *fn;
1625 #ifdef OS_IS_WIN32
1626 char buf[PATH_MAX];
1627
1628 if (!getenv(PULSE_ROOTENV))
1629 pa_set_root(NULL);
1630 #endif
1631
1632 if (env && (fn = getenv(env))) {
1633
1634 #ifdef OS_IS_WIN32
1635 if (!ExpandEnvironmentStrings(fn, buf, PATH_MAX))
1636 /* FIXME: Needs to set errno! */
1637 return NULL;
1638 fn = buf;
1639 #endif
1640
1641 if (access(fn, R_OK) == 0)
1642 return pa_xstrdup(fn);
1643
1644 pa_log_warn("Failed to access configuration file '%s': %s", fn, pa_cstrerror(errno));
1645 return NULL;
1646 }
1647
1648 if (local) {
1649 const char *e;
1650 char *lfn;
1651 char h[PATH_MAX];
1652
1653 if ((e = getenv("PULSE_CONFIG_PATH")))
1654 fn = lfn = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", e, local);
1655 else if (pa_get_home_dir(h, sizeof(h)))
1656 fn = lfn = pa_sprintf_malloc("%s" PA_PATH_SEP ".pulse" PA_PATH_SEP "%s", h, local);
1657 else
1658 return NULL;
1659
1660 #ifdef OS_IS_WIN32
1661 if (!ExpandEnvironmentStrings(lfn, buf, PATH_MAX)) {
1662 /* FIXME: Needs to set errno! */
1663 pa_xfree(lfn);
1664 return NULL;
1665 }
1666 fn = buf;
1667 #endif
1668
1669 if (access(fn, R_OK) == 0) {
1670 char *r = pa_xstrdup(fn);
1671 pa_xfree(lfn);
1672 return r;
1673 }
1674
1675 if (errno != ENOENT) {
1676 pa_log_warn("Failed to access configuration file '%s': %s", fn, pa_cstrerror(errno));
1677 pa_xfree(lfn);
1678 return NULL;
1679 }
1680
1681 pa_xfree(lfn);
1682 }
1683
1684 if (global) {
1685 #ifdef OS_IS_WIN32
1686 if (!ExpandEnvironmentStrings(global, buf, PATH_MAX))
1687 /* FIXME: Needs to set errno! */
1688 return NULL;
1689 global = buf;
1690 #endif
1691
1692 if (access(global, R_OK) == 0)
1693 return pa_xstrdup(global);
1694 }
1695
1696 errno = ENOENT;
1697
1698 return NULL;
1699 }
1700
1701 /* Format the specified data as a hexademical string */
1702 char *pa_hexstr(const uint8_t* d, size_t dlength, char *s, size_t slength) {
1703 size_t i = 0, j = 0;
1704 const char hex[] = "0123456789abcdef";
1705
1706 pa_assert(d);
1707 pa_assert(s);
1708 pa_assert(slength > 0);
1709
1710 while (i < dlength && j+3 <= slength) {
1711 s[j++] = hex[*d >> 4];
1712 s[j++] = hex[*d & 0xF];
1713
1714 d++;
1715 i++;
1716 }
1717
1718 s[j < slength ? j : slength] = 0;
1719 return s;
1720 }
1721
1722 /* Convert a hexadecimal digit to a number or -1 if invalid */
1723 static int hexc(char c) {
1724 if (c >= '0' && c <= '9')
1725 return c - '0';
1726
1727 if (c >= 'A' && c <= 'F')
1728 return c - 'A' + 10;
1729
1730 if (c >= 'a' && c <= 'f')
1731 return c - 'a' + 10;
1732
1733 errno = EINVAL;
1734 return -1;
1735 }
1736
1737 /* Parse a hexadecimal string as created by pa_hexstr() to a BLOB */
1738 size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength) {
1739 size_t j = 0;
1740
1741 pa_assert(p);
1742 pa_assert(d);
1743
1744 while (j < dlength && *p) {
1745 int b;
1746
1747 if ((b = hexc(*(p++))) < 0)
1748 return (size_t) -1;
1749
1750 d[j] = (uint8_t) (b << 4);
1751
1752 if (!*p)
1753 return (size_t) -1;
1754
1755 if ((b = hexc(*(p++))) < 0)
1756 return (size_t) -1;
1757
1758 d[j] |= (uint8_t) b;
1759 j++;
1760 }
1761
1762 return j;
1763 }
1764
1765 /* Returns nonzero when *s starts with *pfx */
1766 pa_bool_t pa_startswith(const char *s, const char *pfx) {
1767 size_t l;
1768
1769 pa_assert(s);
1770 pa_assert(pfx);
1771
1772 l = strlen(pfx);
1773
1774 return strlen(s) >= l && strncmp(s, pfx, l) == 0;
1775 }
1776
1777 /* Returns nonzero when *s ends with *sfx */
1778 pa_bool_t pa_endswith(const char *s, const char *sfx) {
1779 size_t l1, l2;
1780
1781 pa_assert(s);
1782 pa_assert(sfx);
1783
1784 l1 = strlen(s);
1785 l2 = strlen(sfx);
1786
1787 return l1 >= l2 && strcmp(s+l1-l2, sfx) == 0;
1788 }
1789
1790 pa_bool_t pa_is_path_absolute(const char *fn) {
1791 pa_assert(fn);
1792
1793 #ifndef OS_IS_WIN32
1794 return *fn == '/';
1795 #else
1796 return strlen(fn) >= 3 && isalpha(fn[0]) && fn[1] == ':' && fn[2] == '\\';
1797 #endif
1798 }
1799
1800 char *pa_make_path_absolute(const char *p) {
1801 char *r;
1802 char *cwd;
1803
1804 pa_assert(p);
1805
1806 if (pa_is_path_absolute(p))
1807 return pa_xstrdup(p);
1808
1809 if (!(cwd = pa_getcwd()))
1810 return pa_xstrdup(p);
1811
1812 r = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", cwd, p);
1813 pa_xfree(cwd);
1814 return r;
1815 }
1816
1817 /* if fn is null return the PulseAudio run time path in s (~/.pulse)
1818 * if fn is non-null and starts with / return fn
1819 * otherwise append fn to the run time path and return it */
1820 static char *get_path(const char *fn, pa_bool_t prependmid, pa_bool_t rt) {
1821 char *rtp;
1822
1823 if (pa_is_path_absolute(fn))
1824 return pa_xstrdup(fn);
1825
1826 rtp = rt ? pa_get_runtime_dir() : pa_get_state_dir();
1827
1828 if (!rtp)
1829 return NULL;
1830
1831 if (fn) {
1832 char *r;
1833
1834 if (prependmid) {
1835 char *mid;
1836
1837 if (!(mid = pa_machine_id())) {
1838 pa_xfree(rtp);
1839 return NULL;
1840 }
1841
1842 r = pa_sprintf_malloc("%s" PA_PATH_SEP "%s:%s", rtp, mid, fn);
1843 pa_xfree(mid);
1844 } else
1845 r = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", rtp, fn);
1846
1847 pa_xfree(rtp);
1848 return r;
1849 } else
1850 return rtp;
1851 }
1852
1853 char *pa_runtime_path(const char *fn) {
1854 return get_path(fn, FALSE, TRUE);
1855 }
1856
1857 char *pa_state_path(const char *fn, pa_bool_t appendmid) {
1858 return get_path(fn, appendmid, FALSE);
1859 }
1860
1861 /* Convert the string s to a signed integer in *ret_i */
1862 int pa_atoi(const char *s, int32_t *ret_i) {
1863 char *x = NULL;
1864 long l;
1865
1866 pa_assert(s);
1867 pa_assert(ret_i);
1868
1869 errno = 0;
1870 l = strtol(s, &x, 0);
1871
1872 if (!x || *x || errno) {
1873 if (!errno)
1874 errno = EINVAL;
1875 return -1;
1876 }
1877
1878 if ((int32_t) l != l) {
1879 errno = ERANGE;
1880 return -1;
1881 }
1882
1883 *ret_i = (int32_t) l;
1884
1885 return 0;
1886 }
1887
1888 /* Convert the string s to an unsigned integer in *ret_u */
1889 int pa_atou(const char *s, uint32_t *ret_u) {
1890 char *x = NULL;
1891 unsigned long l;
1892
1893 pa_assert(s);
1894 pa_assert(ret_u);
1895
1896 errno = 0;
1897 l = strtoul(s, &x, 0);
1898
1899 if (!x || *x || errno) {
1900 if (!errno)
1901 errno = EINVAL;
1902 return -1;
1903 }
1904
1905 if ((uint32_t) l != l) {
1906 errno = ERANGE;
1907 return -1;
1908 }
1909
1910 *ret_u = (uint32_t) l;
1911
1912 return 0;
1913 }
1914
1915 #ifdef HAVE_STRTOF_L
1916 static locale_t c_locale = NULL;
1917
1918 static void c_locale_destroy(void) {
1919 freelocale(c_locale);
1920 }
1921 #endif
1922
1923 int pa_atod(const char *s, double *ret_d) {
1924 char *x = NULL;
1925 double f;
1926
1927 pa_assert(s);
1928 pa_assert(ret_d);
1929
1930 /* This should be locale independent */
1931
1932 #ifdef HAVE_STRTOF_L
1933
1934 PA_ONCE_BEGIN {
1935
1936 if ((c_locale = newlocale(LC_ALL_MASK, "C", NULL)))
1937 atexit(c_locale_destroy);
1938
1939 } PA_ONCE_END;
1940
1941 if (c_locale) {
1942 errno = 0;
1943 f = strtod_l(s, &x, c_locale);
1944 } else
1945 #endif
1946 {
1947 errno = 0;
1948 f = strtod(s, &x);
1949 }
1950
1951 if (!x || *x || errno) {
1952 if (!errno)
1953 errno = EINVAL;
1954 return -1;
1955 }
1956
1957 *ret_d = f;
1958
1959 return 0;
1960 }
1961
1962 /* Same as snprintf, but guarantees NUL-termination on every platform */
1963 size_t pa_snprintf(char *str, size_t size, const char *format, ...) {
1964 size_t ret;
1965 va_list ap;
1966
1967 pa_assert(str);
1968 pa_assert(size > 0);
1969 pa_assert(format);
1970
1971 va_start(ap, format);
1972 ret = pa_vsnprintf(str, size, format, ap);
1973 va_end(ap);
1974
1975 return ret;
1976 }
1977
1978 /* Same as vsnprintf, but guarantees NUL-termination on every platform */
1979 size_t pa_vsnprintf(char *str, size_t size, const char *format, va_list ap) {
1980 int ret;
1981
1982 pa_assert(str);
1983 pa_assert(size > 0);
1984 pa_assert(format);
1985
1986 ret = vsnprintf(str, size, format, ap);
1987
1988 str[size-1] = 0;
1989
1990 if (ret < 0)
1991 return strlen(str);
1992
1993 if ((size_t) ret > size-1)
1994 return size-1;
1995
1996 return (size_t) ret;
1997 }
1998
1999 /* Truncate the specified string, but guarantee that the string
2000 * returned still validates as UTF8 */
2001 char *pa_truncate_utf8(char *c, size_t l) {
2002 pa_assert(c);
2003 pa_assert(pa_utf8_valid(c));
2004
2005 if (strlen(c) <= l)
2006 return c;
2007
2008 c[l] = 0;
2009
2010 while (l > 0 && !pa_utf8_valid(c))
2011 c[--l] = 0;
2012
2013 return c;
2014 }
2015
2016 char *pa_getcwd(void) {
2017 size_t l = 128;
2018
2019 for (;;) {
2020 char *p = pa_xmalloc(l);
2021 if (getcwd(p, l))
2022 return p;
2023
2024 if (errno != ERANGE)
2025 return NULL;
2026
2027 pa_xfree(p);
2028 l *= 2;
2029 }
2030 }
2031
2032 void *pa_will_need(const void *p, size_t l) {
2033 #ifdef RLIMIT_MEMLOCK
2034 struct rlimit rlim;
2035 #endif
2036 const void *a;
2037 size_t size;
2038 int r;
2039 size_t bs;
2040
2041 pa_assert(p);
2042 pa_assert(l > 0);
2043
2044 a = PA_PAGE_ALIGN_PTR(p);
2045 size = (size_t) ((const uint8_t*) p + l - (const uint8_t*) a);
2046
2047 #ifdef HAVE_POSIX_MADVISE
2048 if ((r = posix_madvise((void*) a, size, POSIX_MADV_WILLNEED)) == 0) {
2049 pa_log_debug("posix_madvise() worked fine!");
2050 return (void*) p;
2051 }
2052 #endif
2053
2054 /* Most likely the memory was not mmap()ed from a file and thus
2055 * madvise() didn't work, so let's misuse mlock() do page this
2056 * stuff back into RAM. Yeah, let's fuck with the MM! It's so
2057 * inviting, the man page of mlock() tells us: "All pages that
2058 * contain a part of the specified address range are guaranteed to
2059 * be resident in RAM when the call returns successfully." */
2060
2061 #ifdef RLIMIT_MEMLOCK
2062 pa_assert_se(getrlimit(RLIMIT_MEMLOCK, &rlim) == 0);
2063
2064 if (rlim.rlim_cur < PA_PAGE_SIZE) {
2065 pa_log_debug("posix_madvise() failed (or doesn't exist), resource limits don't allow mlock(), can't page in data: %s", pa_cstrerror(r));
2066 errno = EPERM;
2067 return (void*) p;
2068 }
2069
2070 bs = PA_PAGE_ALIGN((size_t) rlim.rlim_cur);
2071 #else
2072 bs = PA_PAGE_SIZE*4;
2073 #endif
2074
2075 pa_log_debug("posix_madvise() failed (or doesn't exist), trying mlock(): %s", pa_cstrerror(r));
2076
2077 #ifdef HAVE_MLOCK
2078 while (size > 0 && bs > 0) {
2079
2080 if (bs > size)
2081 bs = size;
2082
2083 if (mlock(a, bs) < 0) {
2084 bs = PA_PAGE_ALIGN(bs / 2);
2085 continue;
2086 }
2087
2088 pa_assert_se(munlock(a, bs) == 0);
2089
2090 a = (const uint8_t*) a + bs;
2091 size -= bs;
2092 }
2093 #endif
2094
2095 if (bs <= 0)
2096 pa_log_debug("mlock() failed too (or doesn't exist), giving up: %s", pa_cstrerror(errno));
2097 else
2098 pa_log_debug("mlock() worked fine!");
2099
2100 return (void*) p;
2101 }
2102
2103 void pa_close_pipe(int fds[2]) {
2104 pa_assert(fds);
2105
2106 if (fds[0] >= 0)
2107 pa_assert_se(pa_close(fds[0]) == 0);
2108
2109 if (fds[1] >= 0)
2110 pa_assert_se(pa_close(fds[1]) == 0);
2111
2112 fds[0] = fds[1] = -1;
2113 }
2114
2115 char *pa_readlink(const char *p) {
2116 size_t l = 100;
2117
2118 for (;;) {
2119 char *c;
2120 ssize_t n;
2121
2122 c = pa_xmalloc(l);
2123
2124 if ((n = readlink(p, c, l-1)) < 0) {
2125 pa_xfree(c);
2126 return NULL;
2127 }
2128
2129 if ((size_t) n < l-1) {
2130 c[n] = 0;
2131 return c;
2132 }
2133
2134 pa_xfree(c);
2135 l *= 2;
2136 }
2137 }
2138
2139 int pa_close_all(int except_fd, ...) {
2140 va_list ap;
2141 unsigned n = 0, i;
2142 int r, *p;
2143
2144 va_start(ap, except_fd);
2145
2146 if (except_fd >= 0)
2147 for (n = 1; va_arg(ap, int) >= 0; n++)
2148 ;
2149
2150 va_end(ap);
2151
2152 p = pa_xnew(int, n+1);
2153
2154 va_start(ap, except_fd);
2155
2156 i = 0;
2157 if (except_fd >= 0) {
2158 int fd;
2159 p[i++] = except_fd;
2160
2161 while ((fd = va_arg(ap, int)) >= 0)
2162 p[i++] = fd;
2163 }
2164 p[i] = -1;
2165
2166 va_end(ap);
2167
2168 r = pa_close_allv(p);
2169 free(p);
2170
2171 return r;
2172 }
2173
2174 int pa_close_allv(const int except_fds[]) {
2175 struct rlimit rl;
2176 int fd;
2177 int saved_errno;
2178
2179 #ifdef __linux__
2180
2181 DIR *d;
2182
2183 if ((d = opendir("/proc/self/fd"))) {
2184
2185 struct dirent *de;
2186
2187 while ((de = readdir(d))) {
2188 pa_bool_t found;
2189 long l;
2190 char *e = NULL;
2191 int i;
2192
2193 if (de->d_name[0] == '.')
2194 continue;
2195
2196 errno = 0;
2197 l = strtol(de->d_name, &e, 10);
2198 if (errno != 0 || !e || *e) {
2199 closedir(d);
2200 errno = EINVAL;
2201 return -1;
2202 }
2203
2204 fd = (int) l;
2205
2206 if ((long) fd != l) {
2207 closedir(d);
2208 errno = EINVAL;
2209 return -1;
2210 }
2211
2212 if (fd < 3)
2213 continue;
2214
2215 if (fd == dirfd(d))
2216 continue;
2217
2218 found = FALSE;
2219 for (i = 0; except_fds[i] >= 0; i++)
2220 if (except_fds[i] == fd) {
2221 found = TRUE;
2222 break;
2223 }
2224
2225 if (found)
2226 continue;
2227
2228 if (pa_close(fd) < 0) {
2229 saved_errno = errno;
2230 closedir(d);
2231 errno = saved_errno;
2232
2233 return -1;
2234 }
2235 }
2236
2237 closedir(d);
2238 return 0;
2239 }
2240
2241 #endif
2242
2243 if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
2244 return -1;
2245
2246 for (fd = 3; fd < (int) rl.rlim_max; fd++) {
2247 int i;
2248 pa_bool_t found;
2249
2250 found = FALSE;
2251 for (i = 0; except_fds[i] >= 0; i++)
2252 if (except_fds[i] == fd) {
2253 found = TRUE;
2254 break;
2255 }
2256
2257 if (found)
2258 continue;
2259
2260 if (pa_close(fd) < 0 && errno != EBADF)
2261 return -1;
2262 }
2263
2264 return 0;
2265 }
2266
2267 int pa_unblock_sigs(int except, ...) {
2268 va_list ap;
2269 unsigned n = 0, i;
2270 int r, *p;
2271
2272 va_start(ap, except);
2273
2274 if (except >= 1)
2275 for (n = 1; va_arg(ap, int) >= 0; n++)
2276 ;
2277
2278 va_end(ap);
2279
2280 p = pa_xnew(int, n+1);
2281
2282 va_start(ap, except);
2283
2284 i = 0;
2285 if (except >= 1) {
2286 int sig;
2287 p[i++] = except;
2288
2289 while ((sig = va_arg(ap, int)) >= 0)
2290 p[i++] = sig;
2291 }
2292 p[i] = -1;
2293
2294 va_end(ap);
2295
2296 r = pa_unblock_sigsv(p);
2297 pa_xfree(p);
2298
2299 return r;
2300 }
2301
2302 int pa_unblock_sigsv(const int except[]) {
2303 int i;
2304 sigset_t ss;
2305
2306 if (sigemptyset(&ss) < 0)
2307 return -1;
2308
2309 for (i = 0; except[i] > 0; i++)
2310 if (sigaddset(&ss, except[i]) < 0)
2311 return -1;
2312
2313 return sigprocmask(SIG_SETMASK, &ss, NULL);
2314 }
2315
2316 int pa_reset_sigs(int except, ...) {
2317 va_list ap;
2318 unsigned n = 0, i;
2319 int *p, r;
2320
2321 va_start(ap, except);
2322
2323 if (except >= 1)
2324 for (n = 1; va_arg(ap, int) >= 0; n++)
2325 ;
2326
2327 va_end(ap);
2328
2329 p = pa_xnew(int, n+1);
2330
2331 va_start(ap, except);
2332
2333 i = 0;
2334 if (except >= 1) {
2335 int sig;
2336 p[i++] = except;
2337
2338 while ((sig = va_arg(ap, int)) >= 0)
2339 sig = p[i++];
2340 }
2341 p[i] = -1;
2342
2343 va_end(ap);
2344
2345 r = pa_reset_sigsv(p);
2346 pa_xfree(p);
2347
2348 return r;
2349 }
2350
2351 int pa_reset_sigsv(const int except[]) {
2352 int sig;
2353
2354 for (sig = 1; sig < NSIG; sig++) {
2355 pa_bool_t reset = TRUE;
2356
2357 switch (sig) {
2358 case SIGKILL:
2359 case SIGSTOP:
2360 reset = FALSE;
2361 break;
2362
2363 default: {
2364 int i;
2365
2366 for (i = 0; except[i] > 0; i++) {
2367 if (sig == except[i]) {
2368 reset = FALSE;
2369 break;
2370 }
2371 }
2372 }
2373 }
2374
2375 if (reset) {
2376 struct sigaction sa;
2377
2378 memset(&sa, 0, sizeof(sa));
2379 sa.sa_handler = SIG_DFL;
2380
2381 /* On Linux the first two RT signals are reserved by
2382 * glibc, and sigaction() will return EINVAL for them. */
2383 if ((sigaction(sig, &sa, NULL) < 0))
2384 if (errno != EINVAL)
2385 return -1;
2386 }
2387 }
2388
2389 return 0;
2390 }
2391
2392 void pa_set_env(const char *key, const char *value) {
2393 pa_assert(key);
2394 pa_assert(value);
2395
2396 putenv(pa_sprintf_malloc("%s=%s", key, value));
2397 }
2398
2399 pa_bool_t pa_in_system_mode(void) {
2400 const char *e;
2401
2402 if (!(e = getenv("PULSE_SYSTEM")))
2403 return FALSE;
2404
2405 return !!atoi(e);
2406 }
2407
2408 char *pa_machine_id(void) {
2409 FILE *f;
2410 size_t l;
2411
2412 /* The returned value is supposed be some kind of ascii identifier
2413 * that is unique and stable across reboots. */
2414
2415 /* First we try the D-Bus UUID, which is the best option we have,
2416 * since it fits perfectly our needs and is not as volatile as the
2417 * hostname which might be set from dhcp. */
2418
2419 if ((f = fopen(PA_MACHINE_ID, "r"))) {
2420 char ln[34] = "", *r;
2421
2422 r = fgets(ln, sizeof(ln)-1, f);
2423 fclose(f);
2424
2425 pa_strip_nl(ln);
2426
2427 if (ln[0])
2428 return pa_xstrdup(ln);
2429 }
2430
2431 /* The we fall back to the host name. It supposed to be somewhat
2432 * unique, at least in a network, but may change. */
2433
2434 l = 100;
2435 for (;;) {
2436 char *c;
2437
2438 c = pa_xmalloc(l);
2439
2440 if (!pa_get_host_name(c, l)) {
2441
2442 if (errno != EINVAL && errno != ENAMETOOLONG)
2443 break;
2444
2445 } else if (strlen(c) < l-1) {
2446
2447 if (*c == 0) {
2448 pa_xfree(c);
2449 break;
2450 }
2451
2452 return c;
2453 }
2454
2455 /* Hmm, the hostname is as long the space we offered the
2456 * function, we cannot know if it fully fit in, so let's play
2457 * safe and retry. */
2458
2459 pa_xfree(c);
2460 l *= 2;
2461 }
2462
2463 /* If no hostname was set we use the POSIX hostid. It's usually
2464 * the IPv4 address. Mit not be that stable. */
2465 return pa_sprintf_malloc("%08lx", (unsigned long) gethostid);
2466 }
2467
2468 char *pa_uname_string(void) {
2469 struct utsname u;
2470
2471 pa_assert_se(uname(&u) == 0);
2472
2473 return pa_sprintf_malloc("%s %s %s %s", u.sysname, u.machine, u.release, u.version);
2474 }
2475
2476 #ifdef HAVE_VALGRIND_MEMCHECK_H
2477 pa_bool_t pa_in_valgrind(void) {
2478 static int b = 0;
2479
2480 /* To make heisenbugs a bit simpler to find we check for $VALGRIND
2481 * here instead of really checking whether we run in valgrind or
2482 * not. */
2483
2484 if (b < 1)
2485 b = getenv("VALGRIND") ? 2 : 1;
2486
2487 return b > 1;
2488 }
2489 #endif