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