add locale support to pa_parse_boolean()
[pulseaudio-mirror.git] / src / pulsecore / core-util.c
blobdcceec90a0e2cc82d7a524651ca3fda32e7888b4
1 /***
2 This file is part of PulseAudio.
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2004 Joe Marcus Clarke
6 Copyright 2006-2007 Pierre Ossman <ossman@cendio.se> for Cendio AB
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.
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.
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 ***/
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
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>
46 #ifdef HAVE_STRTOF_L
47 #include <locale.h>
48 #endif
50 #ifdef HAVE_SCHED_H
51 #include <sched.h>
52 #endif
54 #ifdef HAVE_SYS_RESOURCE_H
55 #include <sys/resource.h>
56 #endif
58 #ifdef HAVE_SYS_CAPABILITY_H
59 #include <sys/capability.h>
60 #endif
62 #ifdef HAVE_SYS_MMAN_H
63 #include <sys/mman.h>
64 #endif
66 #ifdef HAVE_PTHREAD
67 #include <pthread.h>
68 #endif
70 #ifdef HAVE_NETDB_H
71 #include <netdb.h>
72 #endif
74 #ifdef HAVE_WINDOWS_H
75 #include <windows.h>
76 #endif
78 #ifdef HAVE_PWD_H
79 #include <pwd.h>
80 #endif
82 #ifdef HAVE_GRP_H
83 #include <grp.h>
84 #endif
86 #ifdef HAVE_LIBSAMPLERATE
87 #include <samplerate.h>
88 #endif
90 #include <pulse/xmalloc.h>
91 #include <pulse/util.h>
92 #include <pulse/utf8.h>
94 #include <pulsecore/core-error.h>
95 #include <pulsecore/winsock.h>
96 #include <pulsecore/log.h>
97 #include <pulsecore/macro.h>
98 #include <pulsecore/thread.h>
100 #include "core-util.h"
102 /* Not all platforms have this */
103 #ifndef MSG_NOSIGNAL
104 #define MSG_NOSIGNAL 0
105 #endif
107 #ifdef OS_IS_WIN32
109 #define PULSE_ROOTENV "PULSE_ROOT"
111 int pa_set_root(HANDLE handle) {
112 char library_path[MAX_PATH + sizeof(PULSE_ROOTENV) + 1], *sep;
114 strcpy(library_path, PULSE_ROOTENV "=");
116 if (!GetModuleFileName(handle, library_path + sizeof(PULSE_ROOTENV), MAX_PATH))
117 return 0;
119 sep = strrchr(library_path, PA_PATH_SEP_CHAR);
120 if (sep)
121 *sep = '\0';
123 if (_putenv(library_path) < 0)
124 return 0;
126 return 1;
129 #endif
131 /** Make a file descriptor nonblock. Doesn't do any error checking */
132 void pa_make_fd_nonblock(int fd) {
134 #ifdef O_NONBLOCK
135 int v;
136 pa_assert(fd >= 0);
138 pa_assert_se((v = fcntl(fd, F_GETFL)) >= 0);
140 if (!(v & O_NONBLOCK))
141 pa_assert_se(fcntl(fd, F_SETFL, v|O_NONBLOCK) >= 0);
143 #elif defined(OS_IS_WIN32)
144 u_long arg = 1;
145 if (ioctlsocket(fd, FIONBIO, &arg) < 0) {
146 pa_assert_se(WSAGetLastError() == WSAENOTSOCK);
147 pa_log_warn("Only sockets can be made non-blocking!");
149 #else
150 pa_log_warn("Non-blocking I/O not supported.!");
151 #endif
155 /* Set the FD_CLOEXEC flag for a fd */
156 void pa_make_fd_cloexec(int fd) {
158 #ifdef FD_CLOEXEC
159 int v;
160 pa_assert(fd >= 0);
162 pa_assert_se((v = fcntl(fd, F_GETFD, 0)) >= 0);
164 if (!(v & FD_CLOEXEC))
165 pa_assert_se(fcntl(fd, F_SETFD, v|FD_CLOEXEC) >= 0);
166 #endif
170 /** Creates a directory securely */
171 int pa_make_secure_dir(const char* dir, mode_t m, uid_t uid, gid_t gid) {
172 struct stat st;
173 int r;
175 pa_assert(dir);
177 #ifdef OS_IS_WIN32
178 r = mkdir(dir);
179 #else
181 mode_t u;
182 u = umask((~m) & 0777);
183 r = mkdir(dir, m);
184 umask(u);
186 #endif
188 if (r < 0 && errno != EEXIST)
189 return -1;
191 #ifdef HAVE_CHOWN
192 if (uid == (uid_t)-1)
193 uid = getuid();
194 if (gid == (gid_t)-1)
195 gid = getgid();
196 (void) chown(dir, uid, gid);
197 #endif
199 #ifdef HAVE_CHMOD
200 chmod(dir, m);
201 #endif
203 #ifdef HAVE_LSTAT
204 if (lstat(dir, &st) < 0)
205 #else
206 if (stat(dir, &st) < 0)
207 #endif
208 goto fail;
210 #ifndef OS_IS_WIN32
211 if (!S_ISDIR(st.st_mode) ||
212 (st.st_uid != uid) ||
213 (st.st_gid != gid) ||
214 ((st.st_mode & 0777) != m)) {
215 errno = EACCES;
216 goto fail;
218 #else
219 pa_log_warn("Secure directory creation not supported on Win32.");
220 #endif
222 return 0;
224 fail:
225 rmdir(dir);
226 return -1;
229 /* Return a newly allocated sting containing the parent directory of the specified file */
230 char *pa_parent_dir(const char *fn) {
231 char *slash, *dir = pa_xstrdup(fn);
233 if ((slash = (char*) pa_path_get_filename(dir)) == dir) {
234 pa_xfree(dir);
235 return NULL;
238 *(slash-1) = 0;
239 return dir;
242 /* Creates a the parent directory of the specified path securely */
243 int pa_make_secure_parent_dir(const char *fn, mode_t m, uid_t uid, gid_t gid) {
244 int ret = -1;
245 char *dir;
247 if (!(dir = pa_parent_dir(fn)))
248 goto finish;
250 if (pa_make_secure_dir(dir, m, uid, gid) < 0)
251 goto finish;
253 ret = 0;
255 finish:
256 pa_xfree(dir);
257 return ret;
260 /** Platform independent read function. Necessary since not all
261 * systems treat all file descriptors equal. If type is
262 * non-NULL it is used to cache the type of the fd. This is
263 * useful for making sure that only a single syscall is executed per
264 * function call. The variable pointed to should be initialized to 0
265 * by the caller. */
266 ssize_t pa_read(int fd, void *buf, size_t count, int *type) {
268 #ifdef OS_IS_WIN32
270 if (!type || *type == 0) {
271 ssize_t r;
273 if ((r = recv(fd, buf, count, 0)) >= 0)
274 return r;
276 if (WSAGetLastError() != WSAENOTSOCK) {
277 errno = WSAGetLastError();
278 return r;
281 if (type)
282 *type = 1;
285 #endif
287 return read(fd, buf, count);
290 /** Similar to pa_read(), but handles writes */
291 ssize_t pa_write(int fd, const void *buf, size_t count, int *type) {
293 if (!type || *type == 0) {
294 ssize_t r;
296 if ((r = send(fd, buf, count, MSG_NOSIGNAL)) >= 0)
297 return r;
299 #ifdef OS_IS_WIN32
300 if (WSAGetLastError() != WSAENOTSOCK) {
301 errno = WSAGetLastError();
302 return r;
304 #else
305 if (errno != ENOTSOCK)
306 return r;
307 #endif
309 if (type)
310 *type = 1;
313 return write(fd, buf, count);
316 /** Calls read() in a loop. Makes sure that as much as 'size' bytes,
317 * unless EOF is reached or an error occured */
318 ssize_t pa_loop_read(int fd, void*data, size_t size, int *type) {
319 ssize_t ret = 0;
320 int _type;
322 pa_assert(fd >= 0);
323 pa_assert(data);
324 pa_assert(size);
326 if (!type) {
327 _type = 0;
328 type = &_type;
331 while (size > 0) {
332 ssize_t r;
334 if ((r = pa_read(fd, data, size, type)) < 0)
335 return r;
337 if (r == 0)
338 break;
340 ret += r;
341 data = (uint8_t*) data + r;
342 size -= r;
345 return ret;
348 /** Similar to pa_loop_read(), but wraps write() */
349 ssize_t pa_loop_write(int fd, const void*data, size_t size, int *type) {
350 ssize_t ret = 0;
351 int _type;
353 pa_assert(fd >= 0);
354 pa_assert(data);
355 pa_assert(size);
357 if (!type) {
358 _type = 0;
359 type = &_type;
362 while (size > 0) {
363 ssize_t r;
365 if ((r = pa_write(fd, data, size, type)) < 0)
366 return r;
368 if (r == 0)
369 break;
371 ret += r;
372 data = (const uint8_t*) data + r;
373 size -= r;
376 return ret;
379 /** Platform independent read function. Necessary since not all
380 * systems treat all file descriptors equal. */
381 int pa_close(int fd) {
383 #ifdef OS_IS_WIN32
384 int ret;
386 if ((ret = closesocket(fd)) == 0)
387 return 0;
389 if (WSAGetLastError() != WSAENOTSOCK) {
390 errno = WSAGetLastError();
391 return ret;
393 #endif
395 return close(fd);
398 /* Print a warning messages in case that the given signal is not
399 * blocked or trapped */
400 void pa_check_signal_is_blocked(int sig) {
401 #ifdef HAVE_SIGACTION
402 struct sigaction sa;
403 sigset_t set;
405 /* If POSIX threads are supported use thread-aware
406 * pthread_sigmask() function, to check if the signal is
407 * blocked. Otherwise fall back to sigprocmask() */
409 #ifdef HAVE_PTHREAD
410 if (pthread_sigmask(SIG_SETMASK, NULL, &set) < 0) {
411 #endif
412 if (sigprocmask(SIG_SETMASK, NULL, &set) < 0) {
413 pa_log("sigprocmask(): %s", pa_cstrerror(errno));
414 return;
416 #ifdef HAVE_PTHREAD
418 #endif
420 if (sigismember(&set, sig))
421 return;
423 /* Check whether the signal is trapped */
425 if (sigaction(sig, NULL, &sa) < 0) {
426 pa_log("sigaction(): %s", pa_cstrerror(errno));
427 return;
430 if (sa.sa_handler != SIG_DFL)
431 return;
433 pa_log_warn("%s is not trapped. This might cause malfunction!", pa_sig2str(sig));
434 #else /* HAVE_SIGACTION */
435 pa_log_warn("%s might not be trapped. This might cause malfunction!", pa_sig2str(sig));
436 #endif
439 /* The following function is based on an example from the GNU libc
440 * documentation. This function is similar to GNU's asprintf(). */
441 char *pa_sprintf_malloc(const char *format, ...) {
442 int size = 100;
443 char *c = NULL;
445 pa_assert(format);
447 for(;;) {
448 int r;
449 va_list ap;
451 c = pa_xrealloc(c, size);
453 va_start(ap, format);
454 r = vsnprintf(c, size, format, ap);
455 va_end(ap);
457 c[size-1] = 0;
459 if (r > -1 && r < size)
460 return c;
462 if (r > -1) /* glibc 2.1 */
463 size = r+1;
464 else /* glibc 2.0 */
465 size *= 2;
469 /* Same as the previous function, but use a va_list instead of an
470 * ellipsis */
471 char *pa_vsprintf_malloc(const char *format, va_list ap) {
472 int size = 100;
473 char *c = NULL;
475 pa_assert(format);
477 for(;;) {
478 int r;
479 va_list aq;
481 c = pa_xrealloc(c, size);
483 va_copy(aq, ap);
484 r = vsnprintf(c, size, format, aq);
485 va_end(aq);
487 c[size-1] = 0;
489 if (r > -1 && r < size)
490 return c;
492 if (r > -1) /* glibc 2.1 */
493 size = r+1;
494 else /* glibc 2.0 */
495 size *= 2;
499 /* Similar to OpenBSD's strlcpy() function */
500 char *pa_strlcpy(char *b, const char *s, size_t l) {
501 pa_assert(b);
502 pa_assert(s);
503 pa_assert(l > 0);
505 strncpy(b, s, l);
506 b[l-1] = 0;
507 return b;
510 /* Make the current thread a realtime thread, and acquire the highest
511 * rtprio we can get that is less or equal the specified parameter. If
512 * the thread is already realtime, don't do anything. */
513 int pa_make_realtime(int rtprio) {
515 #ifdef _POSIX_PRIORITY_SCHEDULING
516 struct sched_param sp;
517 int r, policy;
519 memset(&sp, 0, sizeof(sp));
520 policy = 0;
522 if ((r = pthread_getschedparam(pthread_self(), &policy, &sp)) != 0) {
523 pa_log("pthread_getschedgetparam(): %s", pa_cstrerror(r));
524 return -1;
527 if (policy == SCHED_FIFO && sp.sched_priority >= rtprio) {
528 pa_log_info("Thread already being scheduled with SCHED_FIFO with priority %i.", sp.sched_priority);
529 return 0;
532 sp.sched_priority = rtprio;
533 if ((r = pthread_setschedparam(pthread_self(), SCHED_FIFO, &sp)) != 0) {
535 while (sp.sched_priority > 1) {
536 sp.sched_priority --;
538 if ((r = pthread_setschedparam(pthread_self(), SCHED_FIFO, &sp)) == 0) {
539 pa_log_info("Successfully enabled SCHED_FIFO scheduling for thread, with priority %i, which is lower than the requested %i.", sp.sched_priority, rtprio);
540 return 0;
544 pa_log_warn("pthread_setschedparam(): %s", pa_cstrerror(r));
545 return -1;
548 pa_log_info("Successfully enabled SCHED_FIFO scheduling for thread, with priority %i.", sp.sched_priority);
549 return 0;
550 #else
551 return -1;
552 #endif
555 /* This is merely used for giving the user a hint. This is not correct
556 * for anything security related */
557 pa_bool_t pa_can_realtime(void) {
559 if (geteuid() == 0)
560 return TRUE;
562 #if defined(HAVE_SYS_RESOURCE_H) && defined(RLIMIT_RTPRIO)
564 struct rlimit rl;
566 if (getrlimit(RLIMIT_RTPRIO, &rl) >= 0)
567 if (rl.rlim_cur > 0 || rl.rlim_cur == RLIM_INFINITY)
568 return TRUE;
570 #endif
572 #if defined(HAVE_SYS_CAPABILITY_H) && defined(CAP_SYS_NICE)
574 cap_t cap;
576 if ((cap = cap_get_proc())) {
577 cap_flag_value_t flag = CAP_CLEAR;
579 if (cap_get_flag(cap, CAP_SYS_NICE, CAP_EFFECTIVE, &flag) >= 0)
580 if (flag == CAP_SET) {
581 cap_free(cap);
582 return TRUE;
585 cap_free(cap);
588 #endif
590 return FALSE;
593 /* This is merely used for giving the user a hint. This is not correct
594 * for anything security related */
595 pa_bool_t pa_can_high_priority(void) {
597 if (geteuid() == 0)
598 return TRUE;
600 #if defined(HAVE_SYS_RESOURCE_H) && defined(RLIMIT_RTPRIO)
602 struct rlimit rl;
604 if (getrlimit(RLIMIT_NICE, &rl) >= 0)
605 if (rl.rlim_cur >= 21 || rl.rlim_cur == RLIM_INFINITY)
606 return TRUE;
608 #endif
610 #if defined(HAVE_SYS_CAPABILITY_H) && defined(CAP_SYS_NICE)
612 cap_t cap;
614 if ((cap = cap_get_proc())) {
615 cap_flag_value_t flag = CAP_CLEAR;
617 if (cap_get_flag(cap, CAP_SYS_NICE, CAP_EFFECTIVE, &flag) >= 0)
618 if (flag == CAP_SET) {
619 cap_free(cap);
620 return TRUE;
623 cap_free(cap);
626 #endif
628 return FALSE;
631 /* Raise the priority of the current process as much as possible that
632 * is <= the specified nice level..*/
633 int pa_raise_priority(int nice_level) {
635 #ifdef HAVE_SYS_RESOURCE_H
636 if (setpriority(PRIO_PROCESS, 0, nice_level) < 0) {
637 int n;
639 for (n = nice_level+1; n < 0; n++) {
641 if (setpriority(PRIO_PROCESS, 0, n) == 0) {
642 pa_log_info("Successfully acquired nice level %i, which is lower than the requested %i.", n, nice_level);
643 return 0;
647 pa_log_warn("setpriority(): %s", pa_cstrerror(errno));
648 return -1;
651 pa_log_info("Successfully gained nice level %i.", nice_level);
652 #endif
654 #ifdef OS_IS_WIN32
655 if (nice_level < 0) {
656 if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS)) {
657 pa_log_warn("SetPriorityClass() failed: 0x%08X", GetLastError());
658 return .-1;
659 } else
660 pa_log_info("Successfully gained high priority class.");
662 #endif
664 return 0;
667 /* Reset the priority to normal, inverting the changes made by
668 * pa_raise_priority() and pa_make_realtime()*/
669 void pa_reset_priority(void) {
670 #ifdef HAVE_SYS_RESOURCE_H
671 struct sched_param sp;
673 setpriority(PRIO_PROCESS, 0, 0);
675 memset(&sp, 0, sizeof(sp));
676 pa_assert_se(pthread_setschedparam(pthread_self(), SCHED_OTHER, &sp) == 0);
677 #endif
679 #ifdef OS_IS_WIN32
680 SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS);
681 #endif
684 static int match(const char *expr, const char *v) {
685 int k;
686 regex_t re;
688 if (regcomp(&re, expr, REG_NOSUB|REG_EXTENDED) != 0) {
689 errno = EINVAL;
690 return -1;
693 if ((k = regexec(&re, v, 0, NULL, 0)) == 0)
694 return 1;
695 else if (k == REG_NOMATCH)
696 return 0;
698 errno = EINVAL;
699 return -1;
702 /* Try to parse a boolean string value.*/
703 int pa_parse_boolean(const char *v) {
704 const char *expr;
705 int r;
706 pa_assert(v);
708 /* First we check language independant */
709 if (!strcmp(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || !strcasecmp(v, "on"))
710 return 1;
711 else if (!strcmp(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || !strcasecmp(v, "off"))
712 return 0;
714 /* And then we check language dependant */
715 if ((expr = nl_langinfo(YESEXPR)))
716 if (expr[0])
717 if ((r = match(expr, v)) > 0)
718 return 1;
720 if ((expr = nl_langinfo(NOEXPR)))
721 if (expr[0])
722 if ((r = match(expr, v)) > 0)
723 return 0;
725 errno = EINVAL;
726 return -1;
729 /* Split the specified string wherever one of the strings in delimiter
730 * occurs. Each time it is called returns a newly allocated string
731 * with pa_xmalloc(). The variable state points to, should be
732 * initiallized to NULL before the first call. */
733 char *pa_split(const char *c, const char *delimiter, const char**state) {
734 const char *current = *state ? *state : c;
735 size_t l;
737 if (!*current)
738 return NULL;
740 l = strcspn(current, delimiter);
741 *state = current+l;
743 if (**state)
744 (*state)++;
746 return pa_xstrndup(current, l);
749 /* What is interpreted as whitespace? */
750 #define WHITESPACE " \t\n"
752 /* Split a string into words. Otherwise similar to pa_split(). */
753 char *pa_split_spaces(const char *c, const char **state) {
754 const char *current = *state ? *state : c;
755 size_t l;
757 if (!*current || *c == 0)
758 return NULL;
760 current += strspn(current, WHITESPACE);
761 l = strcspn(current, WHITESPACE);
763 *state = current+l;
765 return pa_xstrndup(current, l);
768 PA_STATIC_TLS_DECLARE(signame, pa_xfree);
770 /* Return the name of an UNIX signal. Similar to Solaris sig2str() */
771 const char *pa_sig2str(int sig) {
772 char *t;
774 if (sig <= 0)
775 goto fail;
777 #ifdef NSIG
778 if (sig >= NSIG)
779 goto fail;
780 #endif
782 #ifdef HAVE_SIG2STR
784 char buf[SIG2STR_MAX];
786 if (sig2str(sig, buf) == 0) {
787 pa_xfree(PA_STATIC_TLS_GET(signame));
788 t = pa_sprintf_malloc("SIG%s", buf);
789 PA_STATIC_TLS_SET(signame, t);
790 return t;
793 #else
795 switch(sig) {
796 #ifdef SIGHUP
797 case SIGHUP: return "SIGHUP";
798 #endif
799 case SIGINT: return "SIGINT";
800 #ifdef SIGQUIT
801 case SIGQUIT: return "SIGQUIT";
802 #endif
803 case SIGILL: return "SIGULL";
804 #ifdef SIGTRAP
805 case SIGTRAP: return "SIGTRAP";
806 #endif
807 case SIGABRT: return "SIGABRT";
808 #ifdef SIGBUS
809 case SIGBUS: return "SIGBUS";
810 #endif
811 case SIGFPE: return "SIGFPE";
812 #ifdef SIGKILL
813 case SIGKILL: return "SIGKILL";
814 #endif
815 #ifdef SIGUSR1
816 case SIGUSR1: return "SIGUSR1";
817 #endif
818 case SIGSEGV: return "SIGSEGV";
819 #ifdef SIGUSR2
820 case SIGUSR2: return "SIGUSR2";
821 #endif
822 #ifdef SIGPIPE
823 case SIGPIPE: return "SIGPIPE";
824 #endif
825 #ifdef SIGALRM
826 case SIGALRM: return "SIGALRM";
827 #endif
828 case SIGTERM: return "SIGTERM";
829 #ifdef SIGSTKFLT
830 case SIGSTKFLT: return "SIGSTKFLT";
831 #endif
832 #ifdef SIGCHLD
833 case SIGCHLD: return "SIGCHLD";
834 #endif
835 #ifdef SIGCONT
836 case SIGCONT: return "SIGCONT";
837 #endif
838 #ifdef SIGSTOP
839 case SIGSTOP: return "SIGSTOP";
840 #endif
841 #ifdef SIGTSTP
842 case SIGTSTP: return "SIGTSTP";
843 #endif
844 #ifdef SIGTTIN
845 case SIGTTIN: return "SIGTTIN";
846 #endif
847 #ifdef SIGTTOU
848 case SIGTTOU: return "SIGTTOU";
849 #endif
850 #ifdef SIGURG
851 case SIGURG: return "SIGURG";
852 #endif
853 #ifdef SIGXCPU
854 case SIGXCPU: return "SIGXCPU";
855 #endif
856 #ifdef SIGXFSZ
857 case SIGXFSZ: return "SIGXFSZ";
858 #endif
859 #ifdef SIGVTALRM
860 case SIGVTALRM: return "SIGVTALRM";
861 #endif
862 #ifdef SIGPROF
863 case SIGPROF: return "SIGPROF";
864 #endif
865 #ifdef SIGWINCH
866 case SIGWINCH: return "SIGWINCH";
867 #endif
868 #ifdef SIGIO
869 case SIGIO: return "SIGIO";
870 #endif
871 #ifdef SIGPWR
872 case SIGPWR: return "SIGPWR";
873 #endif
874 #ifdef SIGSYS
875 case SIGSYS: return "SIGSYS";
876 #endif
879 #ifdef SIGRTMIN
880 if (sig >= SIGRTMIN && sig <= SIGRTMAX) {
881 pa_xfree(PA_STATIC_TLS_GET(signame));
882 t = pa_sprintf_malloc("SIGRTMIN+%i", sig - SIGRTMIN);
883 PA_STATIC_TLS_SET(signame, t);
884 return t;
886 #endif
888 #endif
890 fail:
892 pa_xfree(PA_STATIC_TLS_GET(signame));
893 t = pa_sprintf_malloc("SIG%i", sig);
894 PA_STATIC_TLS_SET(signame, t);
895 return t;
898 #ifdef HAVE_GRP_H
900 /* Check whether the specified GID and the group name match */
901 static int is_group(gid_t gid, const char *name) {
902 struct group group, *result = NULL;
903 long n;
904 void *data;
905 int r = -1;
907 #ifdef HAVE_GETGRGID_R
908 #ifdef _SC_GETGR_R_SIZE_MAX
909 n = sysconf(_SC_GETGR_R_SIZE_MAX);
910 #else
911 n = -1;
912 #endif
913 if (n < 0) n = 512;
914 data = pa_xmalloc(n);
916 if (getgrgid_r(gid, &group, data, n, &result) < 0 || !result) {
917 pa_log("getgrgid_r(%u): %s", (unsigned)gid, pa_cstrerror(errno));
918 goto finish;
921 r = strcmp(name, result->gr_name) == 0;
923 finish:
924 pa_xfree(data);
925 #else
926 /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) that do not
927 * support getgrgid_r. */
928 if ((result = getgrgid(gid)) == NULL) {
929 pa_log("getgrgid(%u): %s", gid, pa_cstrerror(errno));
930 goto finish;
933 r = strcmp(name, result->gr_name) == 0;
935 finish:
936 #endif
938 return r;
941 /* Check the current user is member of the specified group */
942 int pa_own_uid_in_group(const char *name, gid_t *gid) {
943 GETGROUPS_T *gids, tgid;
944 int n = sysconf(_SC_NGROUPS_MAX);
945 int r = -1, i;
947 pa_assert(n > 0);
949 gids = pa_xmalloc(sizeof(GETGROUPS_T)*n);
951 if ((n = getgroups(n, gids)) < 0) {
952 pa_log("getgroups(): %s", pa_cstrerror(errno));
953 goto finish;
956 for (i = 0; i < n; i++) {
957 if (is_group(gids[i], name) > 0) {
958 *gid = gids[i];
959 r = 1;
960 goto finish;
964 if (is_group(tgid = getgid(), name) > 0) {
965 *gid = tgid;
966 r = 1;
967 goto finish;
970 r = 0;
972 finish:
974 pa_xfree(gids);
975 return r;
978 /* Check whether the specifc user id is a member of the specified group */
979 int pa_uid_in_group(uid_t uid, const char *name) {
980 char *g_buf, *p_buf;
981 long g_n, p_n;
982 struct group grbuf, *gr;
983 char **i;
984 int r = -1;
986 g_n = sysconf(_SC_GETGR_R_SIZE_MAX);
987 g_buf = pa_xmalloc(g_n);
989 p_n = sysconf(_SC_GETPW_R_SIZE_MAX);
990 p_buf = pa_xmalloc(p_n);
992 if (getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr) != 0 || !gr)
993 goto finish;
995 r = 0;
996 for (i = gr->gr_mem; *i; i++) {
997 struct passwd pwbuf, *pw;
999 if (getpwnam_r(*i, &pwbuf, p_buf, (size_t) p_n, &pw) != 0 || !pw)
1000 continue;
1002 if (pw->pw_uid == uid) {
1003 r = 1;
1004 break;
1008 finish:
1009 pa_xfree(g_buf);
1010 pa_xfree(p_buf);
1012 return r;
1015 /* Get the GID of a gfiven group, return (gid_t) -1 on failure. */
1016 gid_t pa_get_gid_of_group(const char *name) {
1017 gid_t ret = (gid_t) -1;
1018 char *g_buf;
1019 long g_n;
1020 struct group grbuf, *gr;
1022 g_n = sysconf(_SC_GETGR_R_SIZE_MAX);
1023 g_buf = pa_xmalloc(g_n);
1025 if (getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr) != 0 || !gr)
1026 goto finish;
1028 ret = gr->gr_gid;
1030 finish:
1031 pa_xfree(g_buf);
1032 return ret;
1035 int pa_check_in_group(gid_t g) {
1036 gid_t gids[NGROUPS_MAX];
1037 int r;
1039 if ((r = getgroups(NGROUPS_MAX, gids)) < 0)
1040 return -1;
1042 for (; r > 0; r--)
1043 if (gids[r-1] == g)
1044 return 1;
1046 return 0;
1049 #else /* HAVE_GRP_H */
1051 int pa_own_uid_in_group(const char *name, gid_t *gid) {
1052 return -1;
1056 int pa_uid_in_group(uid_t uid, const char *name) {
1057 return -1;
1060 gid_t pa_get_gid_of_group(const char *name) {
1061 return (gid_t) -1;
1064 int pa_check_in_group(gid_t g) {
1065 return -1;
1068 #endif
1070 /* Lock or unlock a file entirely.
1071 (advisory on UNIX, mandatory on Windows) */
1072 int pa_lock_fd(int fd, int b) {
1073 #ifdef F_SETLKW
1074 struct flock flock;
1076 /* Try a R/W lock first */
1078 flock.l_type = b ? F_WRLCK : F_UNLCK;
1079 flock.l_whence = SEEK_SET;
1080 flock.l_start = 0;
1081 flock.l_len = 0;
1083 if (fcntl(fd, F_SETLKW, &flock) >= 0)
1084 return 0;
1086 /* Perhaps the file descriptor qas opened for read only, than try again with a read lock. */
1087 if (b && errno == EBADF) {
1088 flock.l_type = F_RDLCK;
1089 if (fcntl(fd, F_SETLKW, &flock) >= 0)
1090 return 0;
1093 pa_log("%slock: %s", !b? "un" : "", pa_cstrerror(errno));
1094 #endif
1096 #ifdef OS_IS_WIN32
1097 HANDLE h = (HANDLE)_get_osfhandle(fd);
1099 if (b && LockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF))
1100 return 0;
1101 if (!b && UnlockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF))
1102 return 0;
1104 pa_log("%slock failed: 0x%08X", !b ? "un" : "", GetLastError());
1105 #endif
1107 return -1;
1110 /* Remove trailing newlines from a string */
1111 char* pa_strip_nl(char *s) {
1112 pa_assert(s);
1114 s[strcspn(s, "\r\n")] = 0;
1115 return s;
1118 /* Create a temporary lock file and lock it. */
1119 int pa_lock_lockfile(const char *fn) {
1120 int fd = -1;
1121 pa_assert(fn);
1123 for (;;) {
1124 struct stat st;
1126 if ((fd = open(fn, O_CREAT|O_RDWR
1127 #ifdef O_NOCTTY
1128 |O_NOCTTY
1129 #endif
1130 #ifdef O_NOFOLLOW
1131 |O_NOFOLLOW
1132 #endif
1133 , S_IRUSR|S_IWUSR)) < 0) {
1134 pa_log_warn("Failed to create lock file '%s': %s", fn, pa_cstrerror(errno));
1135 goto fail;
1138 if (pa_lock_fd(fd, 1) < 0) {
1139 pa_log_warn("Failed to lock file '%s'.", fn);
1140 goto fail;
1143 if (fstat(fd, &st) < 0) {
1144 pa_log_warn("Failed to fstat() file '%s': %s", fn, pa_cstrerror(errno));
1145 goto fail;
1148 /* Check wheter the file has been removed meanwhile. When yes,
1149 * restart this loop, otherwise, we're done */
1150 if (st.st_nlink >= 1)
1151 break;
1153 if (pa_lock_fd(fd, 0) < 0) {
1154 pa_log_warn("Failed to unlock file '%s'.", fn);
1155 goto fail;
1158 if (pa_close(fd) < 0) {
1159 pa_log_warn("Failed to close file '%s': %s", fn, pa_cstrerror(errno));
1160 fd = -1;
1161 goto fail;
1164 fd = -1;
1167 return fd;
1169 fail:
1171 if (fd >= 0)
1172 pa_close(fd);
1174 return -1;
1177 /* Unlock a temporary lcok file */
1178 int pa_unlock_lockfile(const char *fn, int fd) {
1179 int r = 0;
1180 pa_assert(fd >= 0);
1182 if (fn) {
1183 if (unlink(fn) < 0) {
1184 pa_log_warn("Unable to remove lock file '%s': %s", fn, pa_cstrerror(errno));
1185 r = -1;
1189 if (pa_lock_fd(fd, 0) < 0) {
1190 pa_log_warn("Failed to unlock file '%s'.", fn);
1191 r = -1;
1194 if (pa_close(fd) < 0) {
1195 pa_log_warn("Failed to close '%s': %s", fn, pa_cstrerror(errno));
1196 r = -1;
1199 return r;
1202 static char *get_pulse_home(void) {
1203 char h[PATH_MAX];
1204 struct stat st;
1206 if (!pa_get_home_dir(h, sizeof(h))) {
1207 pa_log_error("Failed to get home directory.");
1208 return NULL;
1211 if (stat(h, &st) < 0) {
1212 pa_log_error("Failed to stat home directory %s: %s", h, pa_cstrerror(errno));
1213 return NULL;
1216 if (st.st_uid != getuid()) {
1217 pa_log_error("Home directory %s not ours.", h);
1218 return NULL;
1221 return pa_sprintf_malloc("%s" PA_PATH_SEP ".pulse", h);
1224 char *pa_get_state_dir(void) {
1225 char *d;
1227 /* The state directory shall contain dynamic data that should be
1228 * kept across reboots, and is private to this user */
1230 if (!(d = pa_xstrdup(getenv("PULSE_STATE_PATH"))))
1231 if (!(d = get_pulse_home()))
1232 return NULL;
1234 /* If PULSE_STATE_PATH and PULSE_RUNTIME_PATH point to the same
1235 * dir then this will break. */
1237 if (pa_make_secure_dir(d, 0700, (pid_t) -1, (pid_t) -1) < 0) {
1238 pa_log_error("Failed to create secure directory: %s", pa_cstrerror(errno));
1239 pa_xfree(d);
1240 return NULL;
1243 return d;
1246 static char* make_random_dir(mode_t m) {
1247 static const char table[] =
1248 "abcdefghijklmnopqrstuvwxyz"
1249 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1250 "0123456789";
1252 char fn[24] = "/tmp/pulse-";
1254 fn[sizeof(fn)-1] = 0;
1256 for (;;) {
1257 unsigned i;
1258 int r;
1259 mode_t u;
1260 int saved_errno;
1262 for (i = 11; i < sizeof(fn)-1; i++)
1263 fn[i] = table[rand() % (sizeof(table)-1)];
1265 u = umask((~m) & 0777);
1266 r = mkdir(fn, m);
1267 saved_errno = errno;
1268 umask(u);
1270 if (r >= 0)
1271 return pa_xstrdup(fn);
1273 errno = saved_errno;
1275 if (errno != EEXIST) {
1276 pa_log_error("Failed to create random directory %s: %s", fn, pa_cstrerror(errno));
1277 return NULL;
1282 static int make_random_dir_and_link(mode_t m, const char *k) {
1283 char *p;
1285 if (!(p = make_random_dir(m)))
1286 return -1;
1288 if (symlink(p, k) < 0) {
1289 int saved_errno = errno;
1291 if (errno != EEXIST)
1292 pa_log_error("Failed to symlink %s to %s: %s", k, p, pa_cstrerror(errno));
1294 rmdir(p);
1295 pa_xfree(p);
1297 errno = saved_errno;
1298 return -1;
1301 return 0;
1304 char *pa_get_runtime_dir(void) {
1305 char *d, *k = NULL, *p = NULL, *t = NULL, *mid;
1306 struct stat st;
1308 /* The runtime directory shall contain dynamic data that needs NOT
1309 * to be kept accross reboots and is usuallly private to the user,
1310 * except in system mode, where it might be accessible by other
1311 * users, too. Since we need POSIX locking and UNIX sockets in
1312 * this directory, we link it to a random subdir in /tmp, if it
1313 * was not explicitly configured. */
1315 if ((d = getenv("PULSE_RUNTIME_PATH"))) {
1316 mode_t m;
1318 m = pa_in_system_mode() ? 0755 : 0700;
1320 if (pa_make_secure_dir(d, m, (pid_t) -1, (pid_t) -1) < 0) {
1321 pa_log_error("Failed to create secure directory: %s", pa_cstrerror(errno));
1322 goto fail;
1325 return pa_xstrdup(d);
1328 if (!(d = get_pulse_home()))
1329 goto fail;
1331 if (!(mid = pa_machine_id())) {
1332 pa_xfree(d);
1333 goto fail;
1336 k = pa_sprintf_malloc("%s" PA_PATH_SEP "%s:runtime", d, mid);
1337 pa_xfree(d);
1338 pa_xfree(mid);
1340 for (;;) {
1341 /* OK, first let's check if the "runtime" symlink is already
1342 * existant */
1344 if (!(p = pa_readlink(k))) {
1346 if (errno != ENOENT) {
1347 pa_log_error("Failed to stat runtime directory %s: %s", k, pa_cstrerror(errno));
1348 goto fail;
1351 /* Hmm, so the runtime directory didn't exist yet, so let's
1352 * create one in /tmp and symlink that to it */
1354 if (make_random_dir_and_link(0700, k) < 0) {
1356 /* Mhmm, maybe another process was quicker than us,
1357 * let's check if that was valid */
1358 if (errno == EEXIST)
1359 continue;
1361 goto fail;
1364 return k;
1367 /* Make sure that this actually makes sense */
1368 if (!pa_is_path_absolute(p)) {
1369 pa_log_error("Path %s in link %s is not absolute.", p, k);
1370 goto fail;
1373 /* Hmm, so this symlink is still around, make sure nobody fools
1374 * us */
1376 if (lstat(p, &st) < 0) {
1378 if (errno != ENOENT) {
1379 pa_log_error("Failed to stat runtime directory %s: %s", p, pa_cstrerror(errno));
1380 goto fail;
1383 } else {
1385 if (S_ISDIR(st.st_mode) &&
1386 (st.st_uid == getuid()) &&
1387 ((st.st_mode & 0777) == 0700)) {
1389 pa_xfree(p);
1390 return k;
1393 pa_log_info("Hmm, runtime path exists, but points to an invalid directory. Changing runtime directory.");
1396 pa_xfree(p);
1397 p = NULL;
1399 /* Hmm, so the link points to some nonexisting or invalid
1400 * dir. Let's replace it by a new link. We first create a
1401 * temporary link and then rename that to allow concurrent
1402 * execution of this function. */
1404 t = pa_sprintf_malloc("%s.tmp", k);
1406 if (make_random_dir_and_link(0700, t) < 0) {
1408 if (errno != EEXIST) {
1409 pa_log_error("Failed to symlink %s: %s", t, pa_cstrerror(errno));
1410 goto fail;
1413 pa_xfree(t);
1414 t = NULL;
1416 /* Hmm, someone lese was quicker then us. Let's give
1417 * him some time to finish, and retry. */
1418 pa_msleep(10);
1419 continue;
1422 /* OK, we succeeded in creating the temporary symlink, so
1423 * let's rename it */
1424 if (rename(t, k) < 0) {
1425 pa_log_error("Failed to rename %s to %s: %s", t, k, pa_cstrerror(errno));
1426 goto fail;
1429 pa_xfree(t);
1430 return k;
1433 fail:
1434 pa_xfree(p);
1435 pa_xfree(k);
1436 pa_xfree(t);
1438 return NULL;
1441 /* Try to open a configuration file. If "env" is specified, open the
1442 * value of the specified environment variable. Otherwise look for a
1443 * file "local" in the home directory or a file "global" in global
1444 * file system. If "result" is non-NULL, a pointer to a newly
1445 * allocated buffer containing the used configuration file is
1446 * stored there.*/
1447 FILE *pa_open_config_file(const char *global, const char *local, const char *env, char **result) {
1448 const char *fn;
1449 #ifdef OS_IS_WIN32
1450 char buf[PATH_MAX];
1452 if (!getenv(PULSE_ROOTENV))
1453 pa_set_root(NULL);
1454 #endif
1456 if (env && (fn = getenv(env))) {
1457 FILE *f;
1459 #ifdef OS_IS_WIN32
1460 if (!ExpandEnvironmentStrings(fn, buf, PATH_MAX))
1461 return NULL;
1462 fn = buf;
1463 #endif
1465 if ((f = fopen(fn, "r"))) {
1466 if (result)
1467 *result = pa_xstrdup(fn);
1469 return f;
1472 pa_log_warn("Failed to open configuration file '%s': %s", fn, pa_cstrerror(errno));
1473 return NULL;
1476 if (local) {
1477 const char *e;
1478 char *lfn;
1479 char h[PATH_MAX];
1480 FILE *f;
1482 if ((e = getenv("PULSE_CONFIG_PATH")))
1483 fn = lfn = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", e, local);
1484 else if (pa_get_home_dir(h, sizeof(h)))
1485 fn = lfn = pa_sprintf_malloc("%s" PA_PATH_SEP ".pulse" PA_PATH_SEP "%s", h, local);
1486 else
1487 return NULL;
1489 #ifdef OS_IS_WIN32
1490 if (!ExpandEnvironmentStrings(lfn, buf, PATH_MAX)) {
1491 pa_xfree(lfn);
1492 return NULL;
1494 fn = buf;
1495 #endif
1497 if ((f = fopen(fn, "r"))) {
1498 if (result)
1499 *result = pa_xstrdup(fn);
1501 pa_xfree(lfn);
1502 return f;
1505 if (errno != ENOENT) {
1506 pa_log_warn("Failed to open configuration file '%s': %s", fn, pa_cstrerror(errno));
1507 pa_xfree(lfn);
1508 return NULL;
1511 pa_xfree(lfn);
1514 if (global) {
1515 FILE *f;
1517 #ifdef OS_IS_WIN32
1518 if (!ExpandEnvironmentStrings(global, buf, PATH_MAX))
1519 return NULL;
1520 global = buf;
1521 #endif
1523 if ((f = fopen(global, "r"))) {
1525 if (result)
1526 *result = pa_xstrdup(global);
1528 return f;
1530 } else
1531 errno = ENOENT;
1533 return NULL;
1536 char *pa_find_config_file(const char *global, const char *local, const char *env) {
1537 const char *fn;
1538 #ifdef OS_IS_WIN32
1539 char buf[PATH_MAX];
1541 if (!getenv(PULSE_ROOTENV))
1542 pa_set_root(NULL);
1543 #endif
1545 if (env && (fn = getenv(env))) {
1547 #ifdef OS_IS_WIN32
1548 if (!ExpandEnvironmentStrings(fn, buf, PATH_MAX))
1549 return NULL;
1550 fn = buf;
1551 #endif
1553 if (access(fn, R_OK) == 0)
1554 return pa_xstrdup(fn);
1556 pa_log_warn("Failed to access configuration file '%s': %s", fn, pa_cstrerror(errno));
1557 return NULL;
1560 if (local) {
1561 const char *e;
1562 char *lfn;
1563 char h[PATH_MAX];
1565 if ((e = getenv("PULSE_CONFIG_PATH")))
1566 fn = lfn = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", e, local);
1567 else if (pa_get_home_dir(h, sizeof(h)))
1568 fn = lfn = pa_sprintf_malloc("%s" PA_PATH_SEP ".pulse" PA_PATH_SEP "%s", h, local);
1569 else
1570 return NULL;
1572 #ifdef OS_IS_WIN32
1573 if (!ExpandEnvironmentStrings(lfn, buf, PATH_MAX)) {
1574 pa_xfree(lfn);
1575 return NULL;
1577 fn = buf;
1578 #endif
1580 if (access(fn, R_OK) == 0) {
1581 char *r = pa_xstrdup(fn);
1582 pa_xfree(lfn);
1583 return r;
1586 if (errno != ENOENT) {
1587 pa_log_warn("Failed to access configuration file '%s': %s", fn, pa_cstrerror(errno));
1588 pa_xfree(lfn);
1589 return NULL;
1592 pa_xfree(lfn);
1595 if (global) {
1596 #ifdef OS_IS_WIN32
1597 if (!ExpandEnvironmentStrings(global, buf, PATH_MAX))
1598 return NULL;
1599 global = buf;
1600 #endif
1602 if (access(global, R_OK) == 0)
1603 return pa_xstrdup(global);
1604 } else
1605 errno = ENOENT;
1607 return NULL;
1610 /* Format the specified data as a hexademical string */
1611 char *pa_hexstr(const uint8_t* d, size_t dlength, char *s, size_t slength) {
1612 size_t i = 0, j = 0;
1613 const char hex[] = "0123456789abcdef";
1615 pa_assert(d);
1616 pa_assert(s);
1617 pa_assert(slength > 0);
1619 while (i < dlength && j+3 <= slength) {
1620 s[j++] = hex[*d >> 4];
1621 s[j++] = hex[*d & 0xF];
1623 d++;
1624 i++;
1627 s[j < slength ? j : slength] = 0;
1628 return s;
1631 /* Convert a hexadecimal digit to a number or -1 if invalid */
1632 static int hexc(char c) {
1633 if (c >= '0' && c <= '9')
1634 return c - '0';
1636 if (c >= 'A' && c <= 'F')
1637 return c - 'A' + 10;
1639 if (c >= 'a' && c <= 'f')
1640 return c - 'a' + 10;
1642 return -1;
1645 /* Parse a hexadecimal string as created by pa_hexstr() to a BLOB */
1646 size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength) {
1647 size_t j = 0;
1649 pa_assert(p);
1650 pa_assert(d);
1652 while (j < dlength && *p) {
1653 int b;
1655 if ((b = hexc(*(p++))) < 0)
1656 return (size_t) -1;
1658 d[j] = (uint8_t) (b << 4);
1660 if (!*p)
1661 return (size_t) -1;
1663 if ((b = hexc(*(p++))) < 0)
1664 return (size_t) -1;
1666 d[j] |= (uint8_t) b;
1667 j++;
1670 return j;
1673 /* Returns nonzero when *s starts with *pfx */
1674 pa_bool_t pa_startswith(const char *s, const char *pfx) {
1675 size_t l;
1677 pa_assert(s);
1678 pa_assert(pfx);
1680 l = strlen(pfx);
1682 return strlen(s) >= l && strncmp(s, pfx, l) == 0;
1685 /* Returns nonzero when *s ends with *sfx */
1686 pa_bool_t pa_endswith(const char *s, const char *sfx) {
1687 size_t l1, l2;
1689 pa_assert(s);
1690 pa_assert(sfx);
1692 l1 = strlen(s);
1693 l2 = strlen(sfx);
1695 return l1 >= l2 && strcmp(s+l1-l2, sfx) == 0;
1698 pa_bool_t pa_is_path_absolute(const char *fn) {
1699 pa_assert(fn);
1701 #ifndef OS_IS_WIN32
1702 return *fn == '/';
1703 #else
1704 return strlen(fn) >= 3 && isalpha(fn[0]) && fn[1] == ':' && fn[2] == '\\';
1705 #endif
1708 char *pa_make_path_absolute(const char *p) {
1709 char *r;
1710 char *cwd;
1712 pa_assert(p);
1714 if (pa_is_path_absolute(p))
1715 return pa_xstrdup(p);
1717 if (!(cwd = pa_getcwd()))
1718 return pa_xstrdup(p);
1720 r = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", cwd, p);
1721 pa_xfree(cwd);
1722 return r;
1725 /* if fn is null return the PulseAudio run time path in s (~/.pulse)
1726 * if fn is non-null and starts with / return fn
1727 * otherwise append fn to the run time path and return it */
1728 static char *get_path(const char *fn, pa_bool_t prependmid, pa_bool_t rt) {
1729 char *rtp;
1731 if (pa_is_path_absolute(fn))
1732 return pa_xstrdup(fn);
1734 rtp = rt ? pa_get_runtime_dir() : pa_get_state_dir();
1736 if (!rtp)
1737 return NULL;
1739 if (fn) {
1740 char *r;
1742 if (prependmid) {
1743 char *mid;
1745 if (!(mid = pa_machine_id())) {
1746 pa_xfree(rtp);
1747 return NULL;
1750 r = pa_sprintf_malloc("%s" PA_PATH_SEP "%s:%s", rtp, mid, fn);
1751 pa_xfree(mid);
1752 } else
1753 r = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", rtp, fn);
1755 pa_xfree(rtp);
1756 return r;
1757 } else
1758 return rtp;
1761 char *pa_runtime_path(const char *fn) {
1762 return get_path(fn, FALSE, TRUE);
1765 char *pa_state_path(const char *fn, pa_bool_t appendmid) {
1766 return get_path(fn, appendmid, FALSE);
1769 /* Convert the string s to a signed integer in *ret_i */
1770 int pa_atoi(const char *s, int32_t *ret_i) {
1771 char *x = NULL;
1772 long l;
1774 pa_assert(s);
1775 pa_assert(ret_i);
1777 errno = 0;
1778 l = strtol(s, &x, 0);
1780 if (!x || *x || errno != 0)
1781 return -1;
1783 if ((int32_t) l != l)
1784 return -1;
1786 *ret_i = (int32_t) l;
1788 return 0;
1791 /* Convert the string s to an unsigned integer in *ret_u */
1792 int pa_atou(const char *s, uint32_t *ret_u) {
1793 char *x = NULL;
1794 unsigned long l;
1796 pa_assert(s);
1797 pa_assert(ret_u);
1799 errno = 0;
1800 l = strtoul(s, &x, 0);
1802 if (!x || *x || errno != 0)
1803 return -1;
1805 if ((uint32_t) l != l)
1806 return -1;
1808 *ret_u = (uint32_t) l;
1810 return 0;
1813 #ifdef HAVE_STRTOF_L
1814 static locale_t c_locale = NULL;
1816 static void c_locale_destroy(void) {
1817 freelocale(c_locale);
1819 #endif
1821 int pa_atod(const char *s, double *ret_d) {
1822 char *x = NULL;
1823 double f;
1824 int r = 0;
1826 pa_assert(s);
1827 pa_assert(ret_d);
1829 /* This should be locale independent */
1831 #ifdef HAVE_STRTOF_L
1833 PA_ONCE_BEGIN {
1835 if ((c_locale = newlocale(LC_ALL_MASK, "C", NULL)))
1836 atexit(c_locale_destroy);
1838 } PA_ONCE_END;
1840 if (c_locale) {
1841 errno = 0;
1842 f = strtod_l(s, &x, c_locale);
1843 } else
1844 #endif
1846 errno = 0;
1847 f = strtod(s, &x);
1850 if (!x || *x || errno != 0)
1851 r = -1;
1852 else
1853 *ret_d = f;
1855 return r;
1858 /* Same as snprintf, but guarantees NUL-termination on every platform */
1859 int pa_snprintf(char *str, size_t size, const char *format, ...) {
1860 int ret;
1861 va_list ap;
1863 pa_assert(str);
1864 pa_assert(size > 0);
1865 pa_assert(format);
1867 va_start(ap, format);
1868 ret = pa_vsnprintf(str, size, format, ap);
1869 va_end(ap);
1871 return ret;
1874 /* Same as vsnprintf, but guarantees NUL-termination on every platform */
1875 int pa_vsnprintf(char *str, size_t size, const char *format, va_list ap) {
1876 int ret;
1878 pa_assert(str);
1879 pa_assert(size > 0);
1880 pa_assert(format);
1882 ret = vsnprintf(str, size, format, ap);
1884 str[size-1] = 0;
1886 if (ret < 0)
1887 ret = strlen(str);
1889 return PA_MIN((int) size-1, ret);
1892 /* Truncate the specified string, but guarantee that the string
1893 * returned still validates as UTF8 */
1894 char *pa_truncate_utf8(char *c, size_t l) {
1895 pa_assert(c);
1896 pa_assert(pa_utf8_valid(c));
1898 if (strlen(c) <= l)
1899 return c;
1901 c[l] = 0;
1903 while (l > 0 && !pa_utf8_valid(c))
1904 c[--l] = 0;
1906 return c;
1909 char *pa_getcwd(void) {
1910 size_t l = 128;
1912 for (;;) {
1913 char *p = pa_xnew(char, l);
1914 if (getcwd(p, l))
1915 return p;
1917 if (errno != ERANGE)
1918 return NULL;
1920 pa_xfree(p);
1921 l *= 2;
1925 void *pa_will_need(const void *p, size_t l) {
1926 #ifdef RLIMIT_MEMLOCK
1927 struct rlimit rlim;
1928 #endif
1929 const void *a;
1930 size_t size;
1931 int r;
1932 size_t bs;
1934 pa_assert(p);
1935 pa_assert(l > 0);
1937 a = PA_PAGE_ALIGN_PTR(p);
1938 size = (const uint8_t*) p + l - (const uint8_t*) a;
1940 #ifdef HAVE_POSIX_MADVISE
1941 if ((r = posix_madvise((void*) a, size, POSIX_MADV_WILLNEED)) == 0) {
1942 pa_log_debug("posix_madvise() worked fine!");
1943 return (void*) p;
1945 #endif
1947 /* Most likely the memory was not mmap()ed from a file and thus
1948 * madvise() didn't work, so let's misuse mlock() do page this
1949 * stuff back into RAM. Yeah, let's fuck with the MM! It's so
1950 * inviting, the man page of mlock() tells us: "All pages that
1951 * contain a part of the specified address range are guaranteed to
1952 * be resident in RAM when the call returns successfully." */
1954 #ifdef RLIMIT_MEMLOCK
1955 pa_assert_se(getrlimit(RLIMIT_MEMLOCK, &rlim) == 0);
1957 if (rlim.rlim_cur < PA_PAGE_SIZE) {
1958 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));
1959 return (void*) p;
1962 bs = PA_PAGE_ALIGN(rlim.rlim_cur);
1963 #else
1964 bs = PA_PAGE_SIZE*4;
1965 #endif
1967 pa_log_debug("posix_madvise() failed (or doesn't exist), trying mlock(): %s", pa_cstrerror(r));
1969 #ifdef HAVE_MLOCK
1970 while (size > 0 && bs > 0) {
1972 if (bs > size)
1973 bs = size;
1975 if (mlock(a, bs) < 0) {
1976 bs = PA_PAGE_ALIGN(bs / 2);
1977 continue;
1980 pa_assert_se(munlock(a, bs) == 0);
1982 a = (const uint8_t*) a + bs;
1983 size -= bs;
1985 #endif
1987 if (bs <= 0)
1988 pa_log_debug("mlock() failed too (or doesn't exist), giving up: %s", pa_cstrerror(errno));
1989 else
1990 pa_log_debug("mlock() worked fine!");
1992 return (void*) p;
1995 void pa_close_pipe(int fds[2]) {
1996 pa_assert(fds);
1998 if (fds[0] >= 0)
1999 pa_assert_se(pa_close(fds[0]) == 0);
2001 if (fds[1] >= 0)
2002 pa_assert_se(pa_close(fds[1]) == 0);
2004 fds[0] = fds[1] = -1;
2007 char *pa_readlink(const char *p) {
2008 size_t l = 100;
2010 for (;;) {
2011 char *c;
2012 ssize_t n;
2014 c = pa_xnew(char, l);
2016 if ((n = readlink(p, c, l-1)) < 0) {
2017 pa_xfree(c);
2018 return NULL;
2021 if ((size_t) n < l-1) {
2022 c[n] = 0;
2023 return c;
2026 pa_xfree(c);
2027 l *= 2;
2031 int pa_close_all(int except_fd, ...) {
2032 va_list ap;
2033 int n = 0, i, r;
2034 int *p;
2036 va_start(ap, except_fd);
2038 if (except_fd >= 0)
2039 for (n = 1; va_arg(ap, int) >= 0; n++)
2042 va_end(ap);
2044 p = pa_xnew(int, n+1);
2046 va_start(ap, except_fd);
2048 i = 0;
2049 if (except_fd >= 0) {
2050 int fd;
2051 p[i++] = except_fd;
2053 while ((fd = va_arg(ap, int)) >= 0)
2054 p[i++] = fd;
2056 p[i] = -1;
2058 va_end(ap);
2060 r = pa_close_allv(p);
2061 free(p);
2063 return r;
2066 int pa_close_allv(const int except_fds[]) {
2067 struct rlimit rl;
2068 int fd;
2069 int saved_errno;
2071 #ifdef __linux__
2073 DIR *d;
2075 if ((d = opendir("/proc/self/fd"))) {
2077 struct dirent *de;
2079 while ((de = readdir(d))) {
2080 pa_bool_t found;
2081 long l;
2082 char *e = NULL;
2083 int i;
2085 if (de->d_name[0] == '.')
2086 continue;
2088 errno = 0;
2089 l = strtol(de->d_name, &e, 10);
2090 if (errno != 0 || !e || *e) {
2091 closedir(d);
2092 errno = EINVAL;
2093 return -1;
2096 fd = (int) l;
2098 if ((long) fd != l) {
2099 closedir(d);
2100 errno = EINVAL;
2101 return -1;
2104 if (fd < 3)
2105 continue;
2107 if (fd == dirfd(d))
2108 continue;
2110 found = FALSE;
2111 for (i = 0; except_fds[i] >= 0; i++)
2112 if (except_fds[i] == fd) {
2113 found = TRUE;
2114 break;
2117 if (found)
2118 continue;
2120 if (pa_close(fd) < 0) {
2121 saved_errno = errno;
2122 closedir(d);
2123 errno = saved_errno;
2125 return -1;
2129 closedir(d);
2130 return 0;
2133 #endif
2135 if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
2136 return -1;
2138 for (fd = 3; fd < (int) rl.rlim_max; fd++) {
2139 int i;
2140 pa_bool_t found;
2142 found = FALSE;
2143 for (i = 0; except_fds[i] >= 0; i++)
2144 if (except_fds[i] == fd) {
2145 found = TRUE;
2146 break;
2149 if (found)
2150 continue;
2152 if (pa_close(fd) < 0 && errno != EBADF)
2153 return -1;
2156 return 0;
2159 int pa_unblock_sigs(int except, ...) {
2160 va_list ap;
2161 int n = 0, i, r;
2162 int *p;
2164 va_start(ap, except);
2166 if (except >= 1)
2167 for (n = 1; va_arg(ap, int) >= 0; n++)
2170 va_end(ap);
2172 p = pa_xnew(int, n+1);
2174 va_start(ap, except);
2176 i = 0;
2177 if (except >= 1) {
2178 int sig;
2179 p[i++] = except;
2181 while ((sig = va_arg(ap, int)) >= 0)
2182 p[i++] = sig;
2184 p[i] = -1;
2186 va_end(ap);
2188 r = pa_unblock_sigsv(p);
2189 pa_xfree(p);
2191 return r;
2194 int pa_unblock_sigsv(const int except[]) {
2195 int i;
2196 sigset_t ss;
2198 if (sigemptyset(&ss) < 0)
2199 return -1;
2201 for (i = 0; except[i] > 0; i++)
2202 if (sigaddset(&ss, except[i]) < 0)
2203 return -1;
2205 return sigprocmask(SIG_SETMASK, &ss, NULL);
2208 int pa_reset_sigs(int except, ...) {
2209 va_list ap;
2210 int n = 0, i, r;
2211 int *p;
2213 va_start(ap, except);
2215 if (except >= 1)
2216 for (n = 1; va_arg(ap, int) >= 0; n++)
2219 va_end(ap);
2221 p = pa_xnew(int, n+1);
2223 va_start(ap, except);
2225 i = 0;
2226 if (except >= 1) {
2227 int sig;
2228 p[i++] = except;
2230 while ((sig = va_arg(ap, int)) >= 0)
2231 sig = p[i++];
2233 p[i] = -1;
2235 va_end(ap);
2237 r = pa_reset_sigsv(p);
2238 pa_xfree(p);
2240 return r;
2243 int pa_reset_sigsv(const int except[]) {
2244 int sig;
2246 for (sig = 1; sig < _NSIG; sig++) {
2247 pa_bool_t reset = TRUE;
2249 switch (sig) {
2250 case SIGKILL:
2251 case SIGSTOP:
2252 reset = FALSE;
2253 break;
2255 default: {
2256 int i;
2258 for (i = 0; except[i] > 0; i++) {
2259 if (sig == except[i]) {
2260 reset = FALSE;
2261 break;
2267 if (reset) {
2268 struct sigaction sa;
2270 memset(&sa, 0, sizeof(sa));
2271 sa.sa_handler = SIG_DFL;
2273 /* On Linux the first two RT signals are reserved by
2274 * glibc, and sigaction() will return EINVAL for them. */
2275 if ((sigaction(sig, &sa, NULL) < 0))
2276 if (errno != EINVAL)
2277 return -1;
2281 return 0;
2284 void pa_set_env(const char *key, const char *value) {
2285 pa_assert(key);
2286 pa_assert(value);
2288 putenv(pa_sprintf_malloc("%s=%s", key, value));
2291 pa_bool_t pa_in_system_mode(void) {
2292 const char *e;
2294 if (!(e = getenv("PULSE_SYSTEM")))
2295 return FALSE;
2297 return !!atoi(e);
2300 char *pa_machine_id(void) {
2301 FILE *f;
2302 size_t l;
2304 if ((f = fopen(PA_MACHINE_ID, "r"))) {
2305 char ln[34] = "", *r;
2307 r = fgets(ln, sizeof(ln)-1, f);
2308 fclose(f);
2310 if (r)
2311 return pa_xstrdup(pa_strip_nl(ln));
2314 l = 100;
2316 for (;;) {
2317 char *c;
2319 c = pa_xnew(char, l);
2321 if (!pa_get_host_name(c, l)) {
2323 if (errno == EINVAL || errno == ENAMETOOLONG) {
2324 pa_xfree(c);
2325 l *= 2;
2326 continue;
2329 return NULL;
2332 if (strlen(c) < l-1)
2333 return c;
2335 /* Hmm, the hostname is as long the space we offered the
2336 * function, we cannot know if it fully fit in, so let's play
2337 * safe and retry. */
2339 pa_xfree(c);
2340 l *= 2;