Rework state/runtime directory logic
[pulseaudio-mirror.git] / src / pulsecore / core-util.c
blob41bf42d3a9ffa1cbd9ce040512b2e1ce5e21c396
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>
44 #ifdef HAVE_STRTOF_L
45 #include <locale.h>
46 #endif
48 #ifdef HAVE_SCHED_H
49 #include <sched.h>
50 #endif
52 #ifdef HAVE_SYS_RESOURCE_H
53 #include <sys/resource.h>
54 #endif
56 #ifdef HAVE_SYS_CAPABILITY_H
57 #include <sys/capability.h>
58 #endif
60 #ifdef HAVE_SYS_MMAN_H
61 #include <sys/mman.h>
62 #endif
64 #ifdef HAVE_PTHREAD
65 #include <pthread.h>
66 #endif
68 #ifdef HAVE_NETDB_H
69 #include <netdb.h>
70 #endif
72 #ifdef HAVE_WINDOWS_H
73 #include <windows.h>
74 #endif
76 #ifdef HAVE_PWD_H
77 #include <pwd.h>
78 #endif
80 #ifdef HAVE_GRP_H
81 #include <grp.h>
82 #endif
84 #ifdef HAVE_LIBSAMPLERATE
85 #include <samplerate.h>
86 #endif
88 #include <pulse/xmalloc.h>
89 #include <pulse/util.h>
90 #include <pulse/utf8.h>
92 #include <pulsecore/core-error.h>
93 #include <pulsecore/winsock.h>
94 #include <pulsecore/log.h>
95 #include <pulsecore/macro.h>
96 #include <pulsecore/thread.h>
98 #include "core-util.h"
100 /* Not all platforms have this */
101 #ifndef MSG_NOSIGNAL
102 #define MSG_NOSIGNAL 0
103 #endif
105 #ifdef OS_IS_WIN32
107 #define PULSE_ROOTENV "PULSE_ROOT"
109 int pa_set_root(HANDLE handle) {
110 char library_path[MAX_PATH + sizeof(PULSE_ROOTENV) + 1], *sep;
112 strcpy(library_path, PULSE_ROOTENV "=");
114 if (!GetModuleFileName(handle, library_path + sizeof(PULSE_ROOTENV), MAX_PATH))
115 return 0;
117 sep = strrchr(library_path, PA_PATH_SEP_CHAR);
118 if (sep)
119 *sep = '\0';
121 if (_putenv(library_path) < 0)
122 return 0;
124 return 1;
127 #endif
129 /** Make a file descriptor nonblock. Doesn't do any error checking */
130 void pa_make_fd_nonblock(int fd) {
132 #ifdef O_NONBLOCK
133 int v;
134 pa_assert(fd >= 0);
136 pa_assert_se((v = fcntl(fd, F_GETFL)) >= 0);
138 if (!(v & O_NONBLOCK))
139 pa_assert_se(fcntl(fd, F_SETFL, v|O_NONBLOCK) >= 0);
141 #elif defined(OS_IS_WIN32)
142 u_long arg = 1;
143 if (ioctlsocket(fd, FIONBIO, &arg) < 0) {
144 pa_assert_se(WSAGetLastError() == WSAENOTSOCK);
145 pa_log_warn("Only sockets can be made non-blocking!");
147 #else
148 pa_log_warn("Non-blocking I/O not supported.!");
149 #endif
153 /* Set the FD_CLOEXEC flag for a fd */
154 void pa_make_fd_cloexec(int fd) {
156 #ifdef FD_CLOEXEC
157 int v;
158 pa_assert(fd >= 0);
160 pa_assert_se((v = fcntl(fd, F_GETFD, 0)) >= 0);
162 if (!(v & FD_CLOEXEC))
163 pa_assert_se(fcntl(fd, F_SETFD, v|FD_CLOEXEC) >= 0);
164 #endif
168 /** Creates a directory securely */
169 int pa_make_secure_dir(const char* dir, mode_t m, uid_t uid, gid_t gid) {
170 struct stat st;
171 int r;
173 pa_assert(dir);
175 #ifdef OS_IS_WIN32
176 r = mkdir(dir);
177 #else
179 mode_t u;
180 u = umask((~m) & 0777);
181 r = mkdir(dir, m);
182 umask(u);
184 #endif
186 if (r < 0 && errno != EEXIST)
187 return -1;
189 #ifdef HAVE_CHOWN
190 if (uid == (uid_t)-1)
191 uid = getuid();
192 if (gid == (gid_t)-1)
193 gid = getgid();
194 (void) chown(dir, uid, gid);
195 #endif
197 #ifdef HAVE_CHMOD
198 chmod(dir, m);
199 #endif
201 #ifdef HAVE_LSTAT
202 if (lstat(dir, &st) < 0)
203 #else
204 if (stat(dir, &st) < 0)
205 #endif
206 goto fail;
208 #ifndef OS_IS_WIN32
209 if (!S_ISDIR(st.st_mode) ||
210 (st.st_uid != uid) ||
211 (st.st_gid != gid) ||
212 ((st.st_mode & 0777) != m)) {
213 errno = EACCES;
214 goto fail;
216 #else
217 pa_log_warn("Secure directory creation not supported on Win32.");
218 #endif
220 return 0;
222 fail:
223 rmdir(dir);
224 return -1;
227 /* Return a newly allocated sting containing the parent directory of the specified file */
228 char *pa_parent_dir(const char *fn) {
229 char *slash, *dir = pa_xstrdup(fn);
231 if ((slash = (char*) pa_path_get_filename(dir)) == dir) {
232 pa_xfree(dir);
233 return NULL;
236 *(slash-1) = 0;
237 return dir;
240 /* Creates a the parent directory of the specified path securely */
241 int pa_make_secure_parent_dir(const char *fn, mode_t m, uid_t uid, gid_t gid) {
242 int ret = -1;
243 char *dir;
245 if (!(dir = pa_parent_dir(fn)))
246 goto finish;
248 if (pa_make_secure_dir(dir, m, uid, gid) < 0)
249 goto finish;
251 ret = 0;
253 finish:
254 pa_xfree(dir);
255 return ret;
258 /** Platform independent read function. Necessary since not all
259 * systems treat all file descriptors equal. If type is
260 * non-NULL it is used to cache the type of the fd. This is
261 * useful for making sure that only a single syscall is executed per
262 * function call. The variable pointed to should be initialized to 0
263 * by the caller. */
264 ssize_t pa_read(int fd, void *buf, size_t count, int *type) {
266 #ifdef OS_IS_WIN32
268 if (!type || *type == 0) {
269 ssize_t r;
271 if ((r = recv(fd, buf, count, 0)) >= 0)
272 return r;
274 if (WSAGetLastError() != WSAENOTSOCK) {
275 errno = WSAGetLastError();
276 return r;
279 if (type)
280 *type = 1;
283 #endif
285 return read(fd, buf, count);
288 /** Similar to pa_read(), but handles writes */
289 ssize_t pa_write(int fd, const void *buf, size_t count, int *type) {
291 if (!type || *type == 0) {
292 ssize_t r;
294 if ((r = send(fd, buf, count, MSG_NOSIGNAL)) >= 0)
295 return r;
297 #ifdef OS_IS_WIN32
298 if (WSAGetLastError() != WSAENOTSOCK) {
299 errno = WSAGetLastError();
300 return r;
302 #else
303 if (errno != ENOTSOCK)
304 return r;
305 #endif
307 if (type)
308 *type = 1;
311 return write(fd, buf, count);
314 /** Calls read() in a loop. Makes sure that as much as 'size' bytes,
315 * unless EOF is reached or an error occured */
316 ssize_t pa_loop_read(int fd, void*data, size_t size, int *type) {
317 ssize_t ret = 0;
318 int _type;
320 pa_assert(fd >= 0);
321 pa_assert(data);
322 pa_assert(size);
324 if (!type) {
325 _type = 0;
326 type = &_type;
329 while (size > 0) {
330 ssize_t r;
332 if ((r = pa_read(fd, data, size, type)) < 0)
333 return r;
335 if (r == 0)
336 break;
338 ret += r;
339 data = (uint8_t*) data + r;
340 size -= r;
343 return ret;
346 /** Similar to pa_loop_read(), but wraps write() */
347 ssize_t pa_loop_write(int fd, const void*data, size_t size, int *type) {
348 ssize_t ret = 0;
349 int _type;
351 pa_assert(fd >= 0);
352 pa_assert(data);
353 pa_assert(size);
355 if (!type) {
356 _type = 0;
357 type = &_type;
360 while (size > 0) {
361 ssize_t r;
363 if ((r = pa_write(fd, data, size, type)) < 0)
364 return r;
366 if (r == 0)
367 break;
369 ret += r;
370 data = (const uint8_t*) data + r;
371 size -= r;
374 return ret;
377 /** Platform independent read function. Necessary since not all
378 * systems treat all file descriptors equal. */
379 int pa_close(int fd) {
381 #ifdef OS_IS_WIN32
382 int ret;
384 if ((ret = closesocket(fd)) == 0)
385 return 0;
387 if (WSAGetLastError() != WSAENOTSOCK) {
388 errno = WSAGetLastError();
389 return ret;
391 #endif
393 return close(fd);
396 /* Print a warning messages in case that the given signal is not
397 * blocked or trapped */
398 void pa_check_signal_is_blocked(int sig) {
399 #ifdef HAVE_SIGACTION
400 struct sigaction sa;
401 sigset_t set;
403 /* If POSIX threads are supported use thread-aware
404 * pthread_sigmask() function, to check if the signal is
405 * blocked. Otherwise fall back to sigprocmask() */
407 #ifdef HAVE_PTHREAD
408 if (pthread_sigmask(SIG_SETMASK, NULL, &set) < 0) {
409 #endif
410 if (sigprocmask(SIG_SETMASK, NULL, &set) < 0) {
411 pa_log("sigprocmask(): %s", pa_cstrerror(errno));
412 return;
414 #ifdef HAVE_PTHREAD
416 #endif
418 if (sigismember(&set, sig))
419 return;
421 /* Check whether the signal is trapped */
423 if (sigaction(sig, NULL, &sa) < 0) {
424 pa_log("sigaction(): %s", pa_cstrerror(errno));
425 return;
428 if (sa.sa_handler != SIG_DFL)
429 return;
431 pa_log_warn("%s is not trapped. This might cause malfunction!", pa_sig2str(sig));
432 #else /* HAVE_SIGACTION */
433 pa_log_warn("%s might not be trapped. This might cause malfunction!", pa_sig2str(sig));
434 #endif
437 /* The following function is based on an example from the GNU libc
438 * documentation. This function is similar to GNU's asprintf(). */
439 char *pa_sprintf_malloc(const char *format, ...) {
440 int size = 100;
441 char *c = NULL;
443 pa_assert(format);
445 for(;;) {
446 int r;
447 va_list ap;
449 c = pa_xrealloc(c, size);
451 va_start(ap, format);
452 r = vsnprintf(c, size, format, ap);
453 va_end(ap);
455 c[size-1] = 0;
457 if (r > -1 && r < size)
458 return c;
460 if (r > -1) /* glibc 2.1 */
461 size = r+1;
462 else /* glibc 2.0 */
463 size *= 2;
467 /* Same as the previous function, but use a va_list instead of an
468 * ellipsis */
469 char *pa_vsprintf_malloc(const char *format, va_list ap) {
470 int size = 100;
471 char *c = NULL;
473 pa_assert(format);
475 for(;;) {
476 int r;
477 va_list aq;
479 c = pa_xrealloc(c, size);
481 va_copy(aq, ap);
482 r = vsnprintf(c, size, format, aq);
483 va_end(aq);
485 c[size-1] = 0;
487 if (r > -1 && r < size)
488 return c;
490 if (r > -1) /* glibc 2.1 */
491 size = r+1;
492 else /* glibc 2.0 */
493 size *= 2;
497 /* Similar to OpenBSD's strlcpy() function */
498 char *pa_strlcpy(char *b, const char *s, size_t l) {
499 pa_assert(b);
500 pa_assert(s);
501 pa_assert(l > 0);
503 strncpy(b, s, l);
504 b[l-1] = 0;
505 return b;
508 /* Make the current thread a realtime thread, and acquire the highest
509 * rtprio we can get that is less or equal the specified parameter. If
510 * the thread is already realtime, don't do anything. */
511 int pa_make_realtime(int rtprio) {
513 #ifdef _POSIX_PRIORITY_SCHEDULING
514 struct sched_param sp;
515 int r, policy;
517 memset(&sp, 0, sizeof(sp));
518 policy = 0;
520 if ((r = pthread_getschedparam(pthread_self(), &policy, &sp)) != 0) {
521 pa_log("pthread_getschedgetparam(): %s", pa_cstrerror(r));
522 return -1;
525 if (policy == SCHED_FIFO && sp.sched_priority >= rtprio) {
526 pa_log_info("Thread already being scheduled with SCHED_FIFO with priority %i.", sp.sched_priority);
527 return 0;
530 sp.sched_priority = rtprio;
531 if ((r = pthread_setschedparam(pthread_self(), SCHED_FIFO, &sp)) != 0) {
533 while (sp.sched_priority > 1) {
534 sp.sched_priority --;
536 if ((r = pthread_setschedparam(pthread_self(), SCHED_FIFO, &sp)) == 0) {
537 pa_log_info("Successfully enabled SCHED_FIFO scheduling for thread, with priority %i, which is lower than the requested %i.", sp.sched_priority, rtprio);
538 return 0;
542 pa_log_warn("pthread_setschedparam(): %s", pa_cstrerror(r));
543 return -1;
546 pa_log_info("Successfully enabled SCHED_FIFO scheduling for thread, with priority %i.", sp.sched_priority);
547 return 0;
548 #else
549 return -1;
550 #endif
553 /* This is merely used for giving the user a hint. This is not correct
554 * for anything security related */
555 pa_bool_t pa_can_realtime(void) {
557 if (geteuid() == 0)
558 return TRUE;
560 #if defined(HAVE_SYS_RESOURCE_H) && defined(RLIMIT_RTPRIO)
562 struct rlimit rl;
564 if (getrlimit(RLIMIT_RTPRIO, &rl) >= 0)
565 if (rl.rlim_cur > 0 || rl.rlim_cur == RLIM_INFINITY)
566 return TRUE;
568 #endif
570 #if defined(HAVE_SYS_CAPABILITY_H) && defined(CAP_SYS_NICE)
572 cap_t cap;
574 if ((cap = cap_get_proc())) {
575 cap_flag_value_t flag = CAP_CLEAR;
577 if (cap_get_flag(cap, CAP_SYS_NICE, CAP_EFFECTIVE, &flag) >= 0)
578 if (flag == CAP_SET) {
579 cap_free(cap);
580 return TRUE;
583 cap_free(cap);
586 #endif
588 return FALSE;
591 /* This is merely used for giving the user a hint. This is not correct
592 * for anything security related */
593 pa_bool_t pa_can_high_priority(void) {
595 if (geteuid() == 0)
596 return TRUE;
598 #if defined(HAVE_SYS_RESOURCE_H) && defined(RLIMIT_RTPRIO)
600 struct rlimit rl;
602 if (getrlimit(RLIMIT_NICE, &rl) >= 0)
603 if (rl.rlim_cur >= 21 || rl.rlim_cur == RLIM_INFINITY)
604 return TRUE;
606 #endif
608 #if defined(HAVE_SYS_CAPABILITY_H) && defined(CAP_SYS_NICE)
610 cap_t cap;
612 if ((cap = cap_get_proc())) {
613 cap_flag_value_t flag = CAP_CLEAR;
615 if (cap_get_flag(cap, CAP_SYS_NICE, CAP_EFFECTIVE, &flag) >= 0)
616 if (flag == CAP_SET) {
617 cap_free(cap);
618 return TRUE;
621 cap_free(cap);
624 #endif
626 return FALSE;
629 /* Raise the priority of the current process as much as possible that
630 * is <= the specified nice level..*/
631 int pa_raise_priority(int nice_level) {
633 #ifdef HAVE_SYS_RESOURCE_H
634 if (setpriority(PRIO_PROCESS, 0, nice_level) < 0) {
635 int n;
637 for (n = nice_level+1; n < 0; n++) {
639 if (setpriority(PRIO_PROCESS, 0, n) == 0) {
640 pa_log_info("Successfully acquired nice level %i, which is lower than the requested %i.", n, nice_level);
641 return 0;
645 pa_log_warn("setpriority(): %s", pa_cstrerror(errno));
646 return -1;
649 pa_log_info("Successfully gained nice level %i.", nice_level);
650 #endif
652 #ifdef OS_IS_WIN32
653 if (nice_level < 0) {
654 if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS)) {
655 pa_log_warn("SetPriorityClass() failed: 0x%08X", GetLastError());
656 return .-1;
657 } else
658 pa_log_info("Successfully gained high priority class.");
660 #endif
662 return 0;
665 /* Reset the priority to normal, inverting the changes made by
666 * pa_raise_priority() and pa_make_realtime()*/
667 void pa_reset_priority(void) {
668 #ifdef HAVE_SYS_RESOURCE_H
669 struct sched_param sp;
671 setpriority(PRIO_PROCESS, 0, 0);
673 memset(&sp, 0, sizeof(sp));
674 pa_assert_se(pthread_setschedparam(pthread_self(), SCHED_OTHER, &sp) == 0);
675 #endif
677 #ifdef OS_IS_WIN32
678 SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS);
679 #endif
682 /* Try to parse a boolean string value.*/
683 int pa_parse_boolean(const char *v) {
684 pa_assert(v);
686 if (!strcmp(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || !strcasecmp(v, "on"))
687 return 1;
688 else if (!strcmp(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || !strcasecmp(v, "off"))
689 return 0;
691 return -1;
694 /* Split the specified string wherever one of the strings in delimiter
695 * occurs. Each time it is called returns a newly allocated string
696 * with pa_xmalloc(). The variable state points to, should be
697 * initiallized to NULL before the first call. */
698 char *pa_split(const char *c, const char *delimiter, const char**state) {
699 const char *current = *state ? *state : c;
700 size_t l;
702 if (!*current)
703 return NULL;
705 l = strcspn(current, delimiter);
706 *state = current+l;
708 if (**state)
709 (*state)++;
711 return pa_xstrndup(current, l);
714 /* What is interpreted as whitespace? */
715 #define WHITESPACE " \t\n"
717 /* Split a string into words. Otherwise similar to pa_split(). */
718 char *pa_split_spaces(const char *c, const char **state) {
719 const char *current = *state ? *state : c;
720 size_t l;
722 if (!*current || *c == 0)
723 return NULL;
725 current += strspn(current, WHITESPACE);
726 l = strcspn(current, WHITESPACE);
728 *state = current+l;
730 return pa_xstrndup(current, l);
733 PA_STATIC_TLS_DECLARE(signame, pa_xfree);
735 /* Return the name of an UNIX signal. Similar to Solaris sig2str() */
736 const char *pa_sig2str(int sig) {
737 char *t;
739 if (sig <= 0)
740 goto fail;
742 #ifdef NSIG
743 if (sig >= NSIG)
744 goto fail;
745 #endif
747 #ifdef HAVE_SIG2STR
749 char buf[SIG2STR_MAX];
751 if (sig2str(sig, buf) == 0) {
752 pa_xfree(PA_STATIC_TLS_GET(signame));
753 t = pa_sprintf_malloc("SIG%s", buf);
754 PA_STATIC_TLS_SET(signame, t);
755 return t;
758 #else
760 switch(sig) {
761 #ifdef SIGHUP
762 case SIGHUP: return "SIGHUP";
763 #endif
764 case SIGINT: return "SIGINT";
765 #ifdef SIGQUIT
766 case SIGQUIT: return "SIGQUIT";
767 #endif
768 case SIGILL: return "SIGULL";
769 #ifdef SIGTRAP
770 case SIGTRAP: return "SIGTRAP";
771 #endif
772 case SIGABRT: return "SIGABRT";
773 #ifdef SIGBUS
774 case SIGBUS: return "SIGBUS";
775 #endif
776 case SIGFPE: return "SIGFPE";
777 #ifdef SIGKILL
778 case SIGKILL: return "SIGKILL";
779 #endif
780 #ifdef SIGUSR1
781 case SIGUSR1: return "SIGUSR1";
782 #endif
783 case SIGSEGV: return "SIGSEGV";
784 #ifdef SIGUSR2
785 case SIGUSR2: return "SIGUSR2";
786 #endif
787 #ifdef SIGPIPE
788 case SIGPIPE: return "SIGPIPE";
789 #endif
790 #ifdef SIGALRM
791 case SIGALRM: return "SIGALRM";
792 #endif
793 case SIGTERM: return "SIGTERM";
794 #ifdef SIGSTKFLT
795 case SIGSTKFLT: return "SIGSTKFLT";
796 #endif
797 #ifdef SIGCHLD
798 case SIGCHLD: return "SIGCHLD";
799 #endif
800 #ifdef SIGCONT
801 case SIGCONT: return "SIGCONT";
802 #endif
803 #ifdef SIGSTOP
804 case SIGSTOP: return "SIGSTOP";
805 #endif
806 #ifdef SIGTSTP
807 case SIGTSTP: return "SIGTSTP";
808 #endif
809 #ifdef SIGTTIN
810 case SIGTTIN: return "SIGTTIN";
811 #endif
812 #ifdef SIGTTOU
813 case SIGTTOU: return "SIGTTOU";
814 #endif
815 #ifdef SIGURG
816 case SIGURG: return "SIGURG";
817 #endif
818 #ifdef SIGXCPU
819 case SIGXCPU: return "SIGXCPU";
820 #endif
821 #ifdef SIGXFSZ
822 case SIGXFSZ: return "SIGXFSZ";
823 #endif
824 #ifdef SIGVTALRM
825 case SIGVTALRM: return "SIGVTALRM";
826 #endif
827 #ifdef SIGPROF
828 case SIGPROF: return "SIGPROF";
829 #endif
830 #ifdef SIGWINCH
831 case SIGWINCH: return "SIGWINCH";
832 #endif
833 #ifdef SIGIO
834 case SIGIO: return "SIGIO";
835 #endif
836 #ifdef SIGPWR
837 case SIGPWR: return "SIGPWR";
838 #endif
839 #ifdef SIGSYS
840 case SIGSYS: return "SIGSYS";
841 #endif
844 #ifdef SIGRTMIN
845 if (sig >= SIGRTMIN && sig <= SIGRTMAX) {
846 pa_xfree(PA_STATIC_TLS_GET(signame));
847 t = pa_sprintf_malloc("SIGRTMIN+%i", sig - SIGRTMIN);
848 PA_STATIC_TLS_SET(signame, t);
849 return t;
851 #endif
853 #endif
855 fail:
857 pa_xfree(PA_STATIC_TLS_GET(signame));
858 t = pa_sprintf_malloc("SIG%i", sig);
859 PA_STATIC_TLS_SET(signame, t);
860 return t;
863 #ifdef HAVE_GRP_H
865 /* Check whether the specified GID and the group name match */
866 static int is_group(gid_t gid, const char *name) {
867 struct group group, *result = NULL;
868 long n;
869 void *data;
870 int r = -1;
872 #ifdef HAVE_GETGRGID_R
873 #ifdef _SC_GETGR_R_SIZE_MAX
874 n = sysconf(_SC_GETGR_R_SIZE_MAX);
875 #else
876 n = -1;
877 #endif
878 if (n < 0) n = 512;
879 data = pa_xmalloc(n);
881 if (getgrgid_r(gid, &group, data, n, &result) < 0 || !result) {
882 pa_log("getgrgid_r(%u): %s", (unsigned)gid, pa_cstrerror(errno));
883 goto finish;
886 r = strcmp(name, result->gr_name) == 0;
888 finish:
889 pa_xfree(data);
890 #else
891 /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) that do not
892 * support getgrgid_r. */
893 if ((result = getgrgid(gid)) == NULL) {
894 pa_log("getgrgid(%u): %s", gid, pa_cstrerror(errno));
895 goto finish;
898 r = strcmp(name, result->gr_name) == 0;
900 finish:
901 #endif
903 return r;
906 /* Check the current user is member of the specified group */
907 int pa_own_uid_in_group(const char *name, gid_t *gid) {
908 GETGROUPS_T *gids, tgid;
909 int n = sysconf(_SC_NGROUPS_MAX);
910 int r = -1, i;
912 pa_assert(n > 0);
914 gids = pa_xmalloc(sizeof(GETGROUPS_T)*n);
916 if ((n = getgroups(n, gids)) < 0) {
917 pa_log("getgroups(): %s", pa_cstrerror(errno));
918 goto finish;
921 for (i = 0; i < n; i++) {
922 if (is_group(gids[i], name) > 0) {
923 *gid = gids[i];
924 r = 1;
925 goto finish;
929 if (is_group(tgid = getgid(), name) > 0) {
930 *gid = tgid;
931 r = 1;
932 goto finish;
935 r = 0;
937 finish:
939 pa_xfree(gids);
940 return r;
943 /* Check whether the specifc user id is a member of the specified group */
944 int pa_uid_in_group(uid_t uid, const char *name) {
945 char *g_buf, *p_buf;
946 long g_n, p_n;
947 struct group grbuf, *gr;
948 char **i;
949 int r = -1;
951 g_n = sysconf(_SC_GETGR_R_SIZE_MAX);
952 g_buf = pa_xmalloc(g_n);
954 p_n = sysconf(_SC_GETPW_R_SIZE_MAX);
955 p_buf = pa_xmalloc(p_n);
957 if (getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr) != 0 || !gr)
958 goto finish;
960 r = 0;
961 for (i = gr->gr_mem; *i; i++) {
962 struct passwd pwbuf, *pw;
964 if (getpwnam_r(*i, &pwbuf, p_buf, (size_t) p_n, &pw) != 0 || !pw)
965 continue;
967 if (pw->pw_uid == uid) {
968 r = 1;
969 break;
973 finish:
974 pa_xfree(g_buf);
975 pa_xfree(p_buf);
977 return r;
980 /* Get the GID of a gfiven group, return (gid_t) -1 on failure. */
981 gid_t pa_get_gid_of_group(const char *name) {
982 gid_t ret = (gid_t) -1;
983 char *g_buf;
984 long g_n;
985 struct group grbuf, *gr;
987 g_n = sysconf(_SC_GETGR_R_SIZE_MAX);
988 g_buf = pa_xmalloc(g_n);
990 if (getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr) != 0 || !gr)
991 goto finish;
993 ret = gr->gr_gid;
995 finish:
996 pa_xfree(g_buf);
997 return ret;
1000 int pa_check_in_group(gid_t g) {
1001 gid_t gids[NGROUPS_MAX];
1002 int r;
1004 if ((r = getgroups(NGROUPS_MAX, gids)) < 0)
1005 return -1;
1007 for (; r > 0; r--)
1008 if (gids[r-1] == g)
1009 return 1;
1011 return 0;
1014 #else /* HAVE_GRP_H */
1016 int pa_own_uid_in_group(const char *name, gid_t *gid) {
1017 return -1;
1021 int pa_uid_in_group(uid_t uid, const char *name) {
1022 return -1;
1025 gid_t pa_get_gid_of_group(const char *name) {
1026 return (gid_t) -1;
1029 int pa_check_in_group(gid_t g) {
1030 return -1;
1033 #endif
1035 /* Lock or unlock a file entirely.
1036 (advisory on UNIX, mandatory on Windows) */
1037 int pa_lock_fd(int fd, int b) {
1038 #ifdef F_SETLKW
1039 struct flock flock;
1041 /* Try a R/W lock first */
1043 flock.l_type = b ? F_WRLCK : F_UNLCK;
1044 flock.l_whence = SEEK_SET;
1045 flock.l_start = 0;
1046 flock.l_len = 0;
1048 if (fcntl(fd, F_SETLKW, &flock) >= 0)
1049 return 0;
1051 /* Perhaps the file descriptor qas opened for read only, than try again with a read lock. */
1052 if (b && errno == EBADF) {
1053 flock.l_type = F_RDLCK;
1054 if (fcntl(fd, F_SETLKW, &flock) >= 0)
1055 return 0;
1058 pa_log("%slock: %s", !b? "un" : "", pa_cstrerror(errno));
1059 #endif
1061 #ifdef OS_IS_WIN32
1062 HANDLE h = (HANDLE)_get_osfhandle(fd);
1064 if (b && LockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF))
1065 return 0;
1066 if (!b && UnlockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF))
1067 return 0;
1069 pa_log("%slock failed: 0x%08X", !b ? "un" : "", GetLastError());
1070 #endif
1072 return -1;
1075 /* Remove trailing newlines from a string */
1076 char* pa_strip_nl(char *s) {
1077 pa_assert(s);
1079 s[strcspn(s, "\r\n")] = 0;
1080 return s;
1083 /* Create a temporary lock file and lock it. */
1084 int pa_lock_lockfile(const char *fn) {
1085 int fd = -1;
1086 pa_assert(fn);
1088 for (;;) {
1089 struct stat st;
1091 if ((fd = open(fn, O_CREAT|O_RDWR
1092 #ifdef O_NOCTTY
1093 |O_NOCTTY
1094 #endif
1095 #ifdef O_NOFOLLOW
1096 |O_NOFOLLOW
1097 #endif
1098 , S_IRUSR|S_IWUSR)) < 0) {
1099 pa_log_warn("Failed to create lock file '%s': %s", fn, pa_cstrerror(errno));
1100 goto fail;
1103 if (pa_lock_fd(fd, 1) < 0) {
1104 pa_log_warn("Failed to lock file '%s'.", fn);
1105 goto fail;
1108 if (fstat(fd, &st) < 0) {
1109 pa_log_warn("Failed to fstat() file '%s': %s", fn, pa_cstrerror(errno));
1110 goto fail;
1113 /* Check wheter the file has been removed meanwhile. When yes,
1114 * restart this loop, otherwise, we're done */
1115 if (st.st_nlink >= 1)
1116 break;
1118 if (pa_lock_fd(fd, 0) < 0) {
1119 pa_log_warn("Failed to unlock file '%s'.", fn);
1120 goto fail;
1123 if (pa_close(fd) < 0) {
1124 pa_log_warn("Failed to close file '%s': %s", fn, pa_cstrerror(errno));
1125 fd = -1;
1126 goto fail;
1129 fd = -1;
1132 return fd;
1134 fail:
1136 if (fd >= 0)
1137 pa_close(fd);
1139 return -1;
1142 /* Unlock a temporary lcok file */
1143 int pa_unlock_lockfile(const char *fn, int fd) {
1144 int r = 0;
1145 pa_assert(fd >= 0);
1147 if (fn) {
1148 if (unlink(fn) < 0) {
1149 pa_log_warn("Unable to remove lock file '%s': %s", fn, pa_cstrerror(errno));
1150 r = -1;
1154 if (pa_lock_fd(fd, 0) < 0) {
1155 pa_log_warn("Failed to unlock file '%s'.", fn);
1156 r = -1;
1159 if (pa_close(fd) < 0) {
1160 pa_log_warn("Failed to close '%s': %s", fn, pa_cstrerror(errno));
1161 r = -1;
1164 return r;
1167 static char *get_pulse_home(void) {
1168 char h[PATH_MAX];
1169 struct stat st;
1171 if (!pa_get_home_dir(h, sizeof(h))) {
1172 pa_log_error("Failed to get home directory.");
1173 return NULL;
1176 if (stat(h, &st) < 0) {
1177 pa_log_error("Failed to stat home directory %s: %s", h, pa_cstrerror(errno));
1178 return NULL;
1181 if (st.st_uid != getuid()) {
1182 pa_log_error("Home directory %s not ours.", h);
1183 return NULL;
1186 return pa_sprintf_malloc("%s" PA_PATH_SEP ".pulse", h);
1189 char *pa_get_state_dir(void) {
1190 char *d;
1192 /* The state directory shall contain dynamic data that should be
1193 * kept across reboots, and is private to this user */
1195 if (!(d = pa_xstrdup(getenv("PULSE_STATE_PATH"))))
1196 if (!(d = get_pulse_home()))
1197 return NULL;
1199 /* If PULSE_STATE_PATH and PULSE_RUNTIME_PATH point to the same
1200 * dir then this will break. */
1202 if (pa_make_secure_dir(d, 0700, (pid_t) -1, (pid_t) -1) < 0) {
1203 pa_log_error("Failed to create secure directory: %s", pa_cstrerror(errno));
1204 pa_xfree(d);
1205 return NULL;
1208 return d;
1211 static char* make_random_dir(mode_t m) {
1212 static const char table[] =
1213 "abcdefghijklmnopqrstuvwxyz"
1214 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1215 "0123456789";
1217 char fn[24] = "/tmp/pulse-";
1219 fn[sizeof(fn)-1] = 0;
1221 for (;;) {
1222 unsigned i;
1223 int r;
1224 mode_t u;
1225 int saved_errno;
1227 for (i = 11; i < sizeof(fn)-1; i++)
1228 fn[i] = table[rand() % (sizeof(table)-1)];
1230 u = umask((~m) & 0777);
1231 r = mkdir(fn, m);
1232 saved_errno = errno;
1233 umask(u);
1235 if (r >= 0)
1236 return pa_xstrdup(fn);
1238 errno = saved_errno;
1240 if (errno != EEXIST) {
1241 pa_log_error("Failed to create random directory %s: %s", fn, pa_cstrerror(errno));
1242 return NULL;
1247 static int make_random_dir_and_link(mode_t m, const char *k) {
1248 char *p;
1250 if (!(p = make_random_dir(m)))
1251 return -1;
1253 if (symlink(p, k) < 0) {
1254 int saved_errno = errno;
1256 if (errno != EEXIST)
1257 pa_log_error("Failed to symlink %s to %s: %s", k, p, pa_cstrerror(errno));
1259 rmdir(p);
1260 pa_xfree(p);
1262 errno = saved_errno;
1263 return -1;
1266 return 0;
1269 char *pa_get_runtime_dir(void) {
1270 char *d, *k = NULL, *p = NULL, *t = NULL, *mid;
1271 struct stat st;
1273 /* The runtime directory shall contain dynamic data that needs NOT
1274 * to be kept accross reboots and is usuallly private to the user,
1275 * except in system mode, where it might be accessible by other
1276 * users, too. Since we need POSIX locking and UNIX sockets in
1277 * this directory, we link it to a random subdir in /tmp, if it
1278 * was not explicitly configured. */
1280 if ((d = getenv("PULSE_RUNTIME_PATH"))) {
1281 mode_t m;
1283 m = pa_in_system_mode() ? 0755 : 0700;
1285 if (pa_make_secure_dir(d, m, (pid_t) -1, (pid_t) -1) < 0) {
1286 pa_log_error("Failed to create secure directory: %s", pa_cstrerror(errno));
1287 goto fail;
1290 return pa_xstrdup(d);
1293 if (!(d = get_pulse_home()))
1294 goto fail;
1296 if (!(mid = pa_machine_id())) {
1297 pa_xfree(d);
1298 goto fail;
1301 k = pa_sprintf_malloc("%s" PA_PATH_SEP "%s:runtime", d, mid);
1302 pa_xfree(d);
1303 pa_xfree(mid);
1305 for (;;) {
1306 /* OK, first let's check if the "runtime" symlink is already
1307 * existant */
1309 if (!(p = pa_readlink(k))) {
1311 if (errno != ENOENT) {
1312 pa_log_error("Failed to stat runtime directory %s: %s", k, pa_cstrerror(errno));
1313 goto fail;
1316 /* Hmm, so the runtime directory didn't exist yet, so let's
1317 * create one in /tmp and symlink that to it */
1319 if (make_random_dir_and_link(0700, k) < 0) {
1321 /* Mhmm, maybe another process was quicker than us,
1322 * let's check if that was valid */
1323 if (errno == EEXIST)
1324 continue;
1326 goto fail;
1329 return k;
1332 /* Make sure that this actually makes sense */
1333 if (!pa_is_path_absolute(p)) {
1334 pa_log_error("Path %s in link %s is not absolute.", p, k);
1335 goto fail;
1338 /* Hmm, so this symlink is still around, make sure nobody fools
1339 * us */
1341 if (lstat(p, &st) < 0) {
1343 if (errno != ENOENT) {
1344 pa_log_error("Failed to stat runtime directory %s: %s", p, pa_cstrerror(errno));
1345 goto fail;
1348 } else {
1350 if (S_ISDIR(st.st_mode) &&
1351 (st.st_uid == getuid()) &&
1352 ((st.st_mode & 0777) == 0700)) {
1354 pa_xfree(p);
1355 return k;
1358 pa_log_info("Hmm, runtime path exists, but points to an invalid directory. Changing runtime directory.");
1361 pa_xfree(p);
1362 p = NULL;
1364 /* Hmm, so the link points to some nonexisting or invalid
1365 * dir. Let's replace it by a new link. We first create a
1366 * temporary link and then rename that to allow concurrent
1367 * execution of this function. */
1369 t = pa_sprintf_malloc("%s.tmp", k);
1371 if (make_random_dir_and_link(0700, t) < 0) {
1373 if (errno != EEXIST) {
1374 pa_log_error("Failed to symlink %s: %s", t, pa_cstrerror(errno));
1375 goto fail;
1378 pa_xfree(t);
1379 t = NULL;
1381 /* Hmm, someone lese was quicker then us. Let's give
1382 * him some time to finish, and retry. */
1383 pa_msleep(10);
1384 continue;
1387 /* OK, we succeeded in creating the temporary symlink, so
1388 * let's rename it */
1389 if (rename(t, k) < 0) {
1390 pa_log_error("Failed to rename %s to %s: %s", t, k, pa_cstrerror(errno));
1391 goto fail;
1394 pa_xfree(t);
1395 return k;
1398 fail:
1399 pa_xfree(p);
1400 pa_xfree(k);
1401 pa_xfree(t);
1403 return NULL;
1406 /* Try to open a configuration file. If "env" is specified, open the
1407 * value of the specified environment variable. Otherwise look for a
1408 * file "local" in the home directory or a file "global" in global
1409 * file system. If "result" is non-NULL, a pointer to a newly
1410 * allocated buffer containing the used configuration file is
1411 * stored there.*/
1412 FILE *pa_open_config_file(const char *global, const char *local, const char *env, char **result) {
1413 const char *fn;
1414 #ifdef OS_IS_WIN32
1415 char buf[PATH_MAX];
1417 if (!getenv(PULSE_ROOTENV))
1418 pa_set_root(NULL);
1419 #endif
1421 if (env && (fn = getenv(env))) {
1422 FILE *f;
1424 #ifdef OS_IS_WIN32
1425 if (!ExpandEnvironmentStrings(fn, buf, PATH_MAX))
1426 return NULL;
1427 fn = buf;
1428 #endif
1430 if ((f = fopen(fn, "r"))) {
1431 if (result)
1432 *result = pa_xstrdup(fn);
1434 return f;
1437 pa_log_warn("Failed to open configuration file '%s': %s", fn, pa_cstrerror(errno));
1438 return NULL;
1441 if (local) {
1442 const char *e;
1443 char *lfn;
1444 char h[PATH_MAX];
1445 FILE *f;
1447 if ((e = getenv("PULSE_CONFIG_PATH")))
1448 fn = lfn = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", e, local);
1449 else if (pa_get_home_dir(h, sizeof(h)))
1450 fn = lfn = pa_sprintf_malloc("%s" PA_PATH_SEP ".pulse" PA_PATH_SEP "%s", h, local);
1451 else
1452 return NULL;
1454 #ifdef OS_IS_WIN32
1455 if (!ExpandEnvironmentStrings(lfn, buf, PATH_MAX)) {
1456 pa_xfree(lfn);
1457 return NULL;
1459 fn = buf;
1460 #endif
1462 if ((f = fopen(fn, "r"))) {
1463 if (result)
1464 *result = pa_xstrdup(fn);
1466 pa_xfree(lfn);
1467 return f;
1470 if (errno != ENOENT) {
1471 pa_log_warn("Failed to open configuration file '%s': %s", fn, pa_cstrerror(errno));
1472 pa_xfree(lfn);
1473 return NULL;
1476 pa_xfree(lfn);
1479 if (global) {
1480 FILE *f;
1482 #ifdef OS_IS_WIN32
1483 if (!ExpandEnvironmentStrings(global, buf, PATH_MAX))
1484 return NULL;
1485 global = buf;
1486 #endif
1488 if ((f = fopen(global, "r"))) {
1490 if (result)
1491 *result = pa_xstrdup(global);
1493 return f;
1495 } else
1496 errno = ENOENT;
1498 return NULL;
1501 char *pa_find_config_file(const char *global, const char *local, const char *env) {
1502 const char *fn;
1503 #ifdef OS_IS_WIN32
1504 char buf[PATH_MAX];
1506 if (!getenv(PULSE_ROOTENV))
1507 pa_set_root(NULL);
1508 #endif
1510 if (env && (fn = getenv(env))) {
1512 #ifdef OS_IS_WIN32
1513 if (!ExpandEnvironmentStrings(fn, buf, PATH_MAX))
1514 return NULL;
1515 fn = buf;
1516 #endif
1518 if (access(fn, R_OK) == 0)
1519 return pa_xstrdup(fn);
1521 pa_log_warn("Failed to access configuration file '%s': %s", fn, pa_cstrerror(errno));
1522 return NULL;
1525 if (local) {
1526 const char *e;
1527 char *lfn;
1528 char h[PATH_MAX];
1530 if ((e = getenv("PULSE_CONFIG_PATH")))
1531 fn = lfn = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", e, local);
1532 else if (pa_get_home_dir(h, sizeof(h)))
1533 fn = lfn = pa_sprintf_malloc("%s" PA_PATH_SEP ".pulse" PA_PATH_SEP "%s", h, local);
1534 else
1535 return NULL;
1537 #ifdef OS_IS_WIN32
1538 if (!ExpandEnvironmentStrings(lfn, buf, PATH_MAX)) {
1539 pa_xfree(lfn);
1540 return NULL;
1542 fn = buf;
1543 #endif
1545 if (access(fn, R_OK) == 0) {
1546 char *r = pa_xstrdup(fn);
1547 pa_xfree(lfn);
1548 return r;
1551 if (errno != ENOENT) {
1552 pa_log_warn("Failed to access configuration file '%s': %s", fn, pa_cstrerror(errno));
1553 pa_xfree(lfn);
1554 return NULL;
1557 pa_xfree(lfn);
1560 if (global) {
1561 #ifdef OS_IS_WIN32
1562 if (!ExpandEnvironmentStrings(global, buf, PATH_MAX))
1563 return NULL;
1564 global = buf;
1565 #endif
1567 if (access(global, R_OK) == 0)
1568 return pa_xstrdup(global);
1569 } else
1570 errno = ENOENT;
1572 return NULL;
1575 /* Format the specified data as a hexademical string */
1576 char *pa_hexstr(const uint8_t* d, size_t dlength, char *s, size_t slength) {
1577 size_t i = 0, j = 0;
1578 const char hex[] = "0123456789abcdef";
1580 pa_assert(d);
1581 pa_assert(s);
1582 pa_assert(slength > 0);
1584 while (i < dlength && j+3 <= slength) {
1585 s[j++] = hex[*d >> 4];
1586 s[j++] = hex[*d & 0xF];
1588 d++;
1589 i++;
1592 s[j < slength ? j : slength] = 0;
1593 return s;
1596 /* Convert a hexadecimal digit to a number or -1 if invalid */
1597 static int hexc(char c) {
1598 if (c >= '0' && c <= '9')
1599 return c - '0';
1601 if (c >= 'A' && c <= 'F')
1602 return c - 'A' + 10;
1604 if (c >= 'a' && c <= 'f')
1605 return c - 'a' + 10;
1607 return -1;
1610 /* Parse a hexadecimal string as created by pa_hexstr() to a BLOB */
1611 size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength) {
1612 size_t j = 0;
1614 pa_assert(p);
1615 pa_assert(d);
1617 while (j < dlength && *p) {
1618 int b;
1620 if ((b = hexc(*(p++))) < 0)
1621 return (size_t) -1;
1623 d[j] = (uint8_t) (b << 4);
1625 if (!*p)
1626 return (size_t) -1;
1628 if ((b = hexc(*(p++))) < 0)
1629 return (size_t) -1;
1631 d[j] |= (uint8_t) b;
1632 j++;
1635 return j;
1638 /* Returns nonzero when *s starts with *pfx */
1639 pa_bool_t pa_startswith(const char *s, const char *pfx) {
1640 size_t l;
1642 pa_assert(s);
1643 pa_assert(pfx);
1645 l = strlen(pfx);
1647 return strlen(s) >= l && strncmp(s, pfx, l) == 0;
1650 /* Returns nonzero when *s ends with *sfx */
1651 pa_bool_t pa_endswith(const char *s, const char *sfx) {
1652 size_t l1, l2;
1654 pa_assert(s);
1655 pa_assert(sfx);
1657 l1 = strlen(s);
1658 l2 = strlen(sfx);
1660 return l1 >= l2 && strcmp(s+l1-l2, sfx) == 0;
1663 pa_bool_t pa_is_path_absolute(const char *fn) {
1664 pa_assert(fn);
1666 #ifndef OS_IS_WIN32
1667 return *fn == '/';
1668 #else
1669 return strlen(fn) >= 3 && isalpha(fn[0]) && fn[1] == ':' && fn[2] == '\\';
1670 #endif
1673 char *pa_make_path_absolute(const char *p) {
1674 char *r;
1675 char *cwd;
1677 pa_assert(p);
1679 if (pa_is_path_absolute(p))
1680 return pa_xstrdup(p);
1682 if (!(cwd = pa_getcwd()))
1683 return pa_xstrdup(p);
1685 r = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", cwd, p);
1686 pa_xfree(cwd);
1687 return r;
1690 /* if fn is null return the PulseAudio run time path in s (~/.pulse)
1691 * if fn is non-null and starts with / return fn
1692 * otherwise append fn to the run time path and return it */
1693 static char *get_path(const char *fn, pa_bool_t rt) {
1694 char *rtp;
1696 if (pa_is_path_absolute(fn))
1697 return pa_xstrdup(fn);
1699 rtp = rt ? pa_get_runtime_dir() : pa_get_state_dir();
1701 if (!rtp)
1702 return NULL;
1704 if (fn) {
1705 char *r;
1706 r = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", rtp, fn);
1707 pa_xfree(rtp);
1708 return r;
1709 } else
1710 return rtp;
1713 char *pa_runtime_path(const char *fn) {
1714 return get_path(fn, 1);
1717 char *pa_state_path(const char *fn) {
1718 return get_path(fn, 0);
1721 /* Convert the string s to a signed integer in *ret_i */
1722 int pa_atoi(const char *s, int32_t *ret_i) {
1723 char *x = NULL;
1724 long l;
1726 pa_assert(s);
1727 pa_assert(ret_i);
1729 errno = 0;
1730 l = strtol(s, &x, 0);
1732 if (!x || *x || errno != 0)
1733 return -1;
1735 if ((int32_t) l != l)
1736 return -1;
1738 *ret_i = (int32_t) l;
1740 return 0;
1743 /* Convert the string s to an unsigned integer in *ret_u */
1744 int pa_atou(const char *s, uint32_t *ret_u) {
1745 char *x = NULL;
1746 unsigned long l;
1748 pa_assert(s);
1749 pa_assert(ret_u);
1751 errno = 0;
1752 l = strtoul(s, &x, 0);
1754 if (!x || *x || errno != 0)
1755 return -1;
1757 if ((uint32_t) l != l)
1758 return -1;
1760 *ret_u = (uint32_t) l;
1762 return 0;
1765 #ifdef HAVE_STRTOF_L
1766 static locale_t c_locale = NULL;
1768 static void c_locale_destroy(void) {
1769 freelocale(c_locale);
1771 #endif
1773 int pa_atod(const char *s, double *ret_d) {
1774 char *x = NULL;
1775 double f;
1776 int r = 0;
1778 pa_assert(s);
1779 pa_assert(ret_d);
1781 /* This should be locale independent */
1783 #ifdef HAVE_STRTOF_L
1785 PA_ONCE_BEGIN {
1787 if ((c_locale = newlocale(LC_ALL_MASK, "C", NULL)))
1788 atexit(c_locale_destroy);
1790 } PA_ONCE_END;
1792 if (c_locale) {
1793 errno = 0;
1794 f = strtod_l(s, &x, c_locale);
1795 } else
1796 #endif
1798 errno = 0;
1799 f = strtod(s, &x);
1802 if (!x || *x || errno != 0)
1803 r = -1;
1804 else
1805 *ret_d = f;
1807 return r;
1810 /* Same as snprintf, but guarantees NUL-termination on every platform */
1811 int pa_snprintf(char *str, size_t size, const char *format, ...) {
1812 int ret;
1813 va_list ap;
1815 pa_assert(str);
1816 pa_assert(size > 0);
1817 pa_assert(format);
1819 va_start(ap, format);
1820 ret = pa_vsnprintf(str, size, format, ap);
1821 va_end(ap);
1823 return ret;
1826 /* Same as vsnprintf, but guarantees NUL-termination on every platform */
1827 int pa_vsnprintf(char *str, size_t size, const char *format, va_list ap) {
1828 int ret;
1830 pa_assert(str);
1831 pa_assert(size > 0);
1832 pa_assert(format);
1834 ret = vsnprintf(str, size, format, ap);
1836 str[size-1] = 0;
1838 if (ret < 0)
1839 ret = strlen(str);
1841 return PA_MIN((int) size-1, ret);
1844 /* Truncate the specified string, but guarantee that the string
1845 * returned still validates as UTF8 */
1846 char *pa_truncate_utf8(char *c, size_t l) {
1847 pa_assert(c);
1848 pa_assert(pa_utf8_valid(c));
1850 if (strlen(c) <= l)
1851 return c;
1853 c[l] = 0;
1855 while (l > 0 && !pa_utf8_valid(c))
1856 c[--l] = 0;
1858 return c;
1861 char *pa_getcwd(void) {
1862 size_t l = 128;
1864 for (;;) {
1865 char *p = pa_xnew(char, l);
1866 if (getcwd(p, l))
1867 return p;
1869 if (errno != ERANGE)
1870 return NULL;
1872 pa_xfree(p);
1873 l *= 2;
1877 void *pa_will_need(const void *p, size_t l) {
1878 #ifdef RLIMIT_MEMLOCK
1879 struct rlimit rlim;
1880 #endif
1881 const void *a;
1882 size_t size;
1883 int r;
1884 size_t bs;
1886 pa_assert(p);
1887 pa_assert(l > 0);
1889 a = PA_PAGE_ALIGN_PTR(p);
1890 size = (const uint8_t*) p + l - (const uint8_t*) a;
1892 #ifdef HAVE_POSIX_MADVISE
1893 if ((r = posix_madvise((void*) a, size, POSIX_MADV_WILLNEED)) == 0) {
1894 pa_log_debug("posix_madvise() worked fine!");
1895 return (void*) p;
1897 #endif
1899 /* Most likely the memory was not mmap()ed from a file and thus
1900 * madvise() didn't work, so let's misuse mlock() do page this
1901 * stuff back into RAM. Yeah, let's fuck with the MM! It's so
1902 * inviting, the man page of mlock() tells us: "All pages that
1903 * contain a part of the specified address range are guaranteed to
1904 * be resident in RAM when the call returns successfully." */
1906 #ifdef RLIMIT_MEMLOCK
1907 pa_assert_se(getrlimit(RLIMIT_MEMLOCK, &rlim) == 0);
1909 if (rlim.rlim_cur < PA_PAGE_SIZE) {
1910 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));
1911 return (void*) p;
1914 bs = PA_PAGE_ALIGN(rlim.rlim_cur);
1915 #else
1916 bs = PA_PAGE_SIZE*4;
1917 #endif
1919 pa_log_debug("posix_madvise() failed (or doesn't exist), trying mlock(): %s", pa_cstrerror(r));
1921 #ifdef HAVE_MLOCK
1922 while (size > 0 && bs > 0) {
1924 if (bs > size)
1925 bs = size;
1927 if (mlock(a, bs) < 0) {
1928 bs = PA_PAGE_ALIGN(bs / 2);
1929 continue;
1932 pa_assert_se(munlock(a, bs) == 0);
1934 a = (const uint8_t*) a + bs;
1935 size -= bs;
1937 #endif
1939 if (bs <= 0)
1940 pa_log_debug("mlock() failed too (or doesn't exist), giving up: %s", pa_cstrerror(errno));
1941 else
1942 pa_log_debug("mlock() worked fine!");
1944 return (void*) p;
1947 void pa_close_pipe(int fds[2]) {
1948 pa_assert(fds);
1950 if (fds[0] >= 0)
1951 pa_assert_se(pa_close(fds[0]) == 0);
1953 if (fds[1] >= 0)
1954 pa_assert_se(pa_close(fds[1]) == 0);
1956 fds[0] = fds[1] = -1;
1959 char *pa_readlink(const char *p) {
1960 size_t l = 100;
1962 for (;;) {
1963 char *c;
1964 ssize_t n;
1966 c = pa_xnew(char, l);
1968 if ((n = readlink(p, c, l-1)) < 0) {
1969 pa_xfree(c);
1970 return NULL;
1973 if ((size_t) n < l-1) {
1974 c[n] = 0;
1975 return c;
1978 pa_xfree(c);
1979 l *= 2;
1983 int pa_close_all(int except_fd, ...) {
1984 va_list ap;
1985 int n = 0, i, r;
1986 int *p;
1988 va_start(ap, except_fd);
1990 if (except_fd >= 0)
1991 for (n = 1; va_arg(ap, int) >= 0; n++)
1994 va_end(ap);
1996 p = pa_xnew(int, n+1);
1998 va_start(ap, except_fd);
2000 i = 0;
2001 if (except_fd >= 0) {
2002 int fd;
2003 p[i++] = except_fd;
2005 while ((fd = va_arg(ap, int)) >= 0)
2006 p[i++] = fd;
2008 p[i] = -1;
2010 va_end(ap);
2012 r = pa_close_allv(p);
2013 free(p);
2015 return r;
2018 int pa_close_allv(const int except_fds[]) {
2019 struct rlimit rl;
2020 int fd;
2021 int saved_errno;
2023 #ifdef __linux__
2025 DIR *d;
2027 if ((d = opendir("/proc/self/fd"))) {
2029 struct dirent *de;
2031 while ((de = readdir(d))) {
2032 pa_bool_t found;
2033 long l;
2034 char *e = NULL;
2035 int i;
2037 if (de->d_name[0] == '.')
2038 continue;
2040 errno = 0;
2041 l = strtol(de->d_name, &e, 10);
2042 if (errno != 0 || !e || *e) {
2043 closedir(d);
2044 errno = EINVAL;
2045 return -1;
2048 fd = (int) l;
2050 if ((long) fd != l) {
2051 closedir(d);
2052 errno = EINVAL;
2053 return -1;
2056 if (fd < 3)
2057 continue;
2059 if (fd == dirfd(d))
2060 continue;
2062 found = FALSE;
2063 for (i = 0; except_fds[i] >= 0; i++)
2064 if (except_fds[i] == fd) {
2065 found = TRUE;
2066 break;
2069 if (found)
2070 continue;
2072 if (pa_close(fd) < 0) {
2073 saved_errno = errno;
2074 closedir(d);
2075 errno = saved_errno;
2077 return -1;
2081 closedir(d);
2082 return 0;
2085 #endif
2087 if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
2088 return -1;
2090 for (fd = 3; fd < (int) rl.rlim_max; fd++) {
2091 int i;
2092 pa_bool_t found;
2094 found = FALSE;
2095 for (i = 0; except_fds[i] >= 0; i++)
2096 if (except_fds[i] == fd) {
2097 found = TRUE;
2098 break;
2101 if (found)
2102 continue;
2104 if (pa_close(fd) < 0 && errno != EBADF)
2105 return -1;
2108 return 0;
2111 int pa_unblock_sigs(int except, ...) {
2112 va_list ap;
2113 int n = 0, i, r;
2114 int *p;
2116 va_start(ap, except);
2118 if (except >= 1)
2119 for (n = 1; va_arg(ap, int) >= 0; n++)
2122 va_end(ap);
2124 p = pa_xnew(int, n+1);
2126 va_start(ap, except);
2128 i = 0;
2129 if (except >= 1) {
2130 int sig;
2131 p[i++] = except;
2133 while ((sig = va_arg(ap, int)) >= 0)
2134 p[i++] = sig;
2136 p[i] = -1;
2138 va_end(ap);
2140 r = pa_unblock_sigsv(p);
2141 pa_xfree(p);
2143 return r;
2146 int pa_unblock_sigsv(const int except[]) {
2147 int i;
2148 sigset_t ss;
2150 if (sigemptyset(&ss) < 0)
2151 return -1;
2153 for (i = 0; except[i] > 0; i++)
2154 if (sigaddset(&ss, except[i]) < 0)
2155 return -1;
2157 return sigprocmask(SIG_SETMASK, &ss, NULL);
2160 int pa_reset_sigs(int except, ...) {
2161 va_list ap;
2162 int n = 0, i, r;
2163 int *p;
2165 va_start(ap, except);
2167 if (except >= 1)
2168 for (n = 1; va_arg(ap, int) >= 0; n++)
2171 va_end(ap);
2173 p = pa_xnew(int, n+1);
2175 va_start(ap, except);
2177 i = 0;
2178 if (except >= 1) {
2179 int sig;
2180 p[i++] = except;
2182 while ((sig = va_arg(ap, int)) >= 0)
2183 sig = p[i++];
2185 p[i] = -1;
2187 va_end(ap);
2189 r = pa_reset_sigsv(p);
2190 pa_xfree(p);
2192 return r;
2195 int pa_reset_sigsv(const int except[]) {
2196 int sig;
2198 for (sig = 1; sig < _NSIG; sig++) {
2199 pa_bool_t reset = TRUE;
2201 switch (sig) {
2202 case SIGKILL:
2203 case SIGSTOP:
2204 reset = FALSE;
2205 break;
2207 default: {
2208 int i;
2210 for (i = 0; except[i] > 0; i++) {
2211 if (sig == except[i]) {
2212 reset = FALSE;
2213 break;
2219 if (reset) {
2220 struct sigaction sa;
2222 memset(&sa, 0, sizeof(sa));
2223 sa.sa_handler = SIG_DFL;
2225 /* On Linux the first two RT signals are reserved by
2226 * glibc, and sigaction() will return EINVAL for them. */
2227 if ((sigaction(sig, &sa, NULL) < 0))
2228 if (errno != EINVAL)
2229 return -1;
2233 return 0;
2236 void pa_set_env(const char *key, const char *value) {
2237 pa_assert(key);
2238 pa_assert(value);
2240 putenv(pa_sprintf_malloc("%s=%s", key, value));
2243 pa_bool_t pa_in_system_mode(void) {
2244 const char *e;
2246 if (!(e = getenv("PULSE_SYSTEM")))
2247 return FALSE;
2249 return !!atoi(e);
2252 char *pa_machine_id(void) {
2253 FILE *f;
2254 size_t l;
2256 if ((f = fopen(PA_MACHINE_ID"x", "r"))) {
2257 char ln[34] = "", *r;
2259 r = fgets(ln, sizeof(ln)-1, f);
2260 fclose(f);
2262 if (r)
2263 return pa_xstrdup(pa_strip_nl(ln));
2266 l = 100;
2268 for (;;) {
2269 char *c;
2271 c = pa_xnew(char, l);
2273 if (!pa_get_host_name(c, l)) {
2275 if (errno == EINVAL || errno == ENAMETOOLONG) {
2276 pa_xfree(c);
2277 l *= 2;
2278 continue;
2281 return NULL;
2284 if (strlen(c) < l-1)
2285 return c;
2287 /* Hmm, the hostname is as long the space we offered the
2288 * function, we cannot know if it fully fit in, so let's play
2289 * safe and retry. */
2291 pa_xfree(c);
2292 l *= 2;