4 This file is part of PulseAudio.
6 Copyright 2004-2006 Lennart Poettering
7 Copyright 2004 Joe Marcus Clarke
8 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
10 PulseAudio is free software; you can redistribute it and/or modify
11 it under the terms of the GNU Lesser General Public License as
12 published by the Free Software Foundation; either version 2.1 of the
13 License, or (at your option) any later version.
15 PulseAudio is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Lesser General Public License for more details.
20 You should have received a copy of the GNU Lesser General Public
21 License along with PulseAudio; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
42 #include <sys/types.h>
50 #ifdef HAVE_SYS_RESOURCE_H
51 #include <sys/resource.h>
74 #include <samplerate.h>
76 #include <pulse/xmalloc.h>
77 #include <pulse/util.h>
79 #include <pulsecore/core-error.h>
80 #include <pulsecore/winsock.h>
81 #include <pulsecore/log.h>
83 #include "core-util.h"
85 /* Not all platforms have this */
87 #define MSG_NOSIGNAL 0
91 #define PA_USER_RUNTIME_PATH_PREFIX "/tmp/pulse-"
94 #define PA_USER_RUNTIME_PATH_PREFIX "%TEMP%\\pulse-"
100 #define PULSE_ROOTENV "PULSE_ROOT"
102 int pa_set_root(HANDLE handle) {
103 char library_path[MAX_PATH + sizeof(PULSE_ROOTENV) + 1], *sep;
105 strcpy(library_path, PULSE_ROOTENV "=");
107 if (!GetModuleFileName(handle, library_path + sizeof(PULSE_ROOTENV), MAX_PATH))
110 sep = strrchr(library_path, '\\');
114 if (_putenv(library_path) < 0)
122 /** Make a file descriptor nonblock. Doesn't do any error checking */
123 void pa_make_nonblock_fd(int fd) {
128 if ((v = fcntl(fd, F_GETFL)) >= 0)
129 if (!(v & O_NONBLOCK))
130 fcntl(fd, F_SETFL, v|O_NONBLOCK);
131 #elif defined(OS_IS_WIN32)
133 if (ioctlsocket(fd, FIONBIO, &arg) < 0) {
134 if (WSAGetLastError() == WSAENOTSOCK)
135 pa_log_warn("WARNING: Only sockets can be made non-blocking!");
138 pa_log_warn("WARNING: Non-blocking I/O not supported.!");
142 /** Creates a directory securely */
143 int pa_make_secure_dir(const char* dir, mode_t m, uid_t uid, gid_t gid) {
160 if (r < 0 && errno != EEXIST)
164 if (uid == (uid_t)-1)
166 if (gid == (gid_t)-1)
168 chown(dir, uid, gid);
176 if (lstat(dir, &st) < 0)
178 if (stat(dir, &st) < 0)
183 if (!S_ISDIR(st.st_mode) ||
184 (st.st_uid != uid) ||
185 (st.st_gid != gid) ||
186 ((st.st_mode & 0777) != m)) {
191 pa_log_warn("secure directory creation not supported on Win32.");
201 /* Return a newly allocated sting containing the parent directory of the specified file */
202 char *pa_parent_dir(const char *fn) {
203 char *slash, *dir = pa_xstrdup(fn);
205 if ((slash = (char*) pa_path_get_filename(dir)) == dir) {
214 /* Creates a the parent directory of the specified path securely */
215 int pa_make_secure_parent_dir(const char *fn, mode_t m, uid_t uid, gid_t gid) {
219 if (!(dir = pa_parent_dir(fn)))
222 if (pa_make_secure_dir(dir, m, uid, gid) < 0)
232 /** Platform independent read function. Necessary since not all
233 * systems treat all file descriptors equal. If type is
234 * non-NULL it is used to cache the type of the fd. This is
235 * useful for making sure that only a single syscall is executed per
236 * function call. The variable pointed to should be initialized to 0
238 ssize_t pa_read(int fd, void *buf, size_t count, int *type) {
242 if (!type || *type == 0) {
245 if ((r = recv(fd, buf, count, 0)) >= 0)
248 if (WSAGetLastError() != WSAENOTSOCK) {
249 errno = WSAGetLastError();
259 return read(fd, buf, count);
262 /** Similar to pa_read(), but handles writes */
263 ssize_t pa_write(int fd, const void *buf, size_t count, int *type) {
265 if (!type || *type == 0) {
268 if ((r = send(fd, buf, count, MSG_NOSIGNAL)) >= 0)
272 if (WSAGetLastError() != WSAENOTSOCK) {
273 errno = WSAGetLastError();
277 if (errno != ENOTSOCK)
285 return write(fd, buf, count);
288 /** Calls read() in a loop. Makes sure that as much as 'size' bytes,
289 * unless EOF is reached or an error occured */
290 ssize_t pa_loop_read(int fd, void*data, size_t size, int *type) {
306 if ((r = pa_read(fd, data, size, type)) < 0)
313 data = (uint8_t*) data + r;
320 /** Similar to pa_loop_read(), but wraps write() */
321 ssize_t pa_loop_write(int fd, const void*data, size_t size, int *type) {
337 if ((r = pa_write(fd, data, size, type)) < 0)
344 data = (const uint8_t*) data + r;
351 /* Print a warning messages in case that the given signal is not
352 * blocked or trapped */
353 void pa_check_signal_is_blocked(int sig) {
354 #ifdef HAVE_SIGACTION
358 /* If POSIX threads are supported use thread-aware
359 * pthread_sigmask() function, to check if the signal is
360 * blocked. Otherwise fall back to sigprocmask() */
363 if (pthread_sigmask(SIG_SETMASK, NULL, &set) < 0) {
365 if (sigprocmask(SIG_SETMASK, NULL, &set) < 0) {
366 pa_log("sigprocmask(): %s", pa_cstrerror(errno));
373 if (sigismember(&set, sig))
376 /* Check whether the signal is trapped */
378 if (sigaction(sig, NULL, &sa) < 0) {
379 pa_log("sigaction(): %s", pa_cstrerror(errno));
383 if (sa.sa_handler != SIG_DFL)
386 pa_log("WARNING: %s is not trapped. This might cause malfunction!", pa_strsignal(sig));
387 #else /* HAVE_SIGACTION */
388 pa_log("WARNING: %s might not be trapped. This might cause malfunction!", pa_strsignal(sig));
392 /* The following function is based on an example from the GNU libc
393 * documentation. This function is similar to GNU's asprintf(). */
394 char *pa_sprintf_malloc(const char *format, ...) {
404 c = pa_xrealloc(c, size);
406 va_start(ap, format);
407 r = vsnprintf(c, size, format, ap);
410 if (r > -1 && r < size)
413 if (r > -1) /* glibc 2.1 */
420 /* Same as the previous function, but use a va_list instead of an
422 char *pa_vsprintf_malloc(const char *format, va_list ap) {
434 c = pa_xrealloc(c, size);
435 r = vsnprintf(c, size, format, aq);
439 if (r > -1 && r < size)
442 if (r > -1) /* glibc 2.1 */
449 /* Similar to OpenBSD's strlcpy() function */
450 char *pa_strlcpy(char *b, const char *s, size_t l) {
451 assert(b && s && l > 0);
458 #define NICE_LEVEL (-15)
460 /* Raise the priority of the current process as much as possible and
461 sensible: set the nice level to -15 and enable realtime scheduling if
463 void pa_raise_priority(void) {
465 #ifdef HAVE_SYS_RESOURCE_H
466 if (setpriority(PRIO_PROCESS, 0, NICE_LEVEL) < 0)
467 pa_log_warn("setpriority(): %s", pa_cstrerror(errno));
469 pa_log_info("Successfully gained nice level %i.", NICE_LEVEL);
472 #ifdef _POSIX_PRIORITY_SCHEDULING
474 struct sched_param sp;
476 if (sched_getparam(0, &sp) < 0) {
477 pa_log("sched_getparam(): %s", pa_cstrerror(errno));
481 sp.sched_priority = 1;
482 if (sched_setscheduler(0, SCHED_FIFO, &sp) < 0) {
483 pa_log_warn("sched_setscheduler(): %s", pa_cstrerror(errno));
487 pa_log_info("Successfully enabled SCHED_FIFO scheduling.");
492 if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS))
493 pa_log_warn("SetPriorityClass() failed: 0x%08X", GetLastError());
495 pa_log_info("Successfully gained high priority class.");
499 /* Reset the priority to normal, inverting the changes made by pa_raise_priority() */
500 void pa_reset_priority(void) {
502 SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS);
505 #ifdef _POSIX_PRIORITY_SCHEDULING
507 struct sched_param sp;
508 sched_getparam(0, &sp);
509 sp.sched_priority = 0;
510 sched_setscheduler(0, SCHED_OTHER, &sp);
514 #ifdef HAVE_SYS_RESOURCE_H
515 setpriority(PRIO_PROCESS, 0, 0);
519 /* Set the FD_CLOEXEC flag for a fd */
520 int pa_fd_set_cloexec(int fd, int b) {
526 if ((v = fcntl(fd, F_GETFD, 0)) < 0)
529 v = (v & ~FD_CLOEXEC) | (b ? FD_CLOEXEC : 0);
531 if (fcntl(fd, F_SETFD, v) < 0)
538 /* Try to parse a boolean string value.*/
539 int pa_parse_boolean(const char *v) {
541 if (!strcmp(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || !strcasecmp(v, "on"))
543 else if (!strcmp(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || !strcasecmp(v, "off"))
549 /* Split the specified string wherever one of the strings in delimiter
550 * occurs. Each time it is called returns a newly allocated string
551 * with pa_xmalloc(). The variable state points to, should be
552 * initiallized to NULL before the first call. */
553 char *pa_split(const char *c, const char *delimiter, const char**state) {
554 const char *current = *state ? *state : c;
560 l = strcspn(current, delimiter);
566 return pa_xstrndup(current, l);
569 /* What is interpreted as whitespace? */
570 #define WHITESPACE " \t\n"
572 /* Split a string into words. Otherwise similar to pa_split(). */
573 char *pa_split_spaces(const char *c, const char **state) {
574 const char *current = *state ? *state : c;
577 if (!*current || *c == 0)
580 current += strspn(current, WHITESPACE);
581 l = strcspn(current, WHITESPACE);
585 return pa_xstrndup(current, l);
588 /* Return the name of an UNIX signal. Similar to GNU's strsignal() */
589 const char *pa_strsignal(int sig) {
591 case SIGINT: return "SIGINT";
592 case SIGTERM: return "SIGTERM";
594 case SIGUSR1: return "SIGUSR1";
597 case SIGUSR2: return "SIGUSR2";
600 case SIGXCPU: return "SIGXCPU";
603 case SIGPIPE: return "SIGPIPE";
606 case SIGCHLD: return "SIGCHLD";
609 case SIGHUP: return "SIGHUP";
611 default: return "UNKNOWN SIGNAL";
617 /* Check whether the specified GID and the group name match */
618 static int is_group(gid_t gid, const char *name) {
619 struct group group, *result = NULL;
624 #ifdef HAVE_GETGRGID_R
625 #ifdef _SC_GETGR_R_SIZE_MAX
626 n = sysconf(_SC_GETGR_R_SIZE_MAX);
631 data = pa_xmalloc(n);
633 if (getgrgid_r(gid, &group, data, n, &result) < 0 || !result) {
634 pa_log("getgrgid_r(%u): %s", (unsigned)gid, pa_cstrerror(errno));
638 r = strcmp(name, result->gr_name) == 0;
643 /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) that do not
644 * support getgrgid_r. */
645 if ((result = getgrgid(gid)) == NULL) {
646 pa_log("getgrgid(%u): %s", gid, pa_cstrerror(errno));
650 r = strcmp(name, result->gr_name) == 0;
658 /* Check the current user is member of the specified group */
659 int pa_own_uid_in_group(const char *name, gid_t *gid) {
660 GETGROUPS_T *gids, tgid;
661 int n = sysconf(_SC_NGROUPS_MAX);
666 gids = pa_xmalloc(sizeof(GETGROUPS_T)*n);
668 if ((n = getgroups(n, gids)) < 0) {
669 pa_log("getgroups(): %s", pa_cstrerror(errno));
673 for (i = 0; i < n; i++) {
674 if (is_group(gids[i], name) > 0) {
681 if (is_group(tgid = getgid(), name) > 0) {
695 /* Check whether the specifc user id is a member of the specified group */
696 int pa_uid_in_group(uid_t uid, const char *name) {
699 struct group grbuf, *gr;
703 g_n = sysconf(_SC_GETGR_R_SIZE_MAX);
704 g_buf = pa_xmalloc(g_n);
706 p_n = sysconf(_SC_GETPW_R_SIZE_MAX);
707 p_buf = pa_xmalloc(p_n);
709 if (getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr) != 0 || !gr)
713 for (i = gr->gr_mem; *i; i++) {
714 struct passwd pwbuf, *pw;
716 if (getpwnam_r(*i, &pwbuf, p_buf, (size_t) p_n, &pw) != 0 || !pw)
719 if (pw->pw_uid == uid) {
732 /* Get the GID of a gfiven group, return (gid_t) -1 on failure. */
733 gid_t pa_get_gid_of_group(const char *name) {
734 gid_t ret = (gid_t) -1;
737 struct group grbuf, *gr;
739 g_n = sysconf(_SC_GETGR_R_SIZE_MAX);
740 g_buf = pa_xmalloc(g_n);
742 if (getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr) != 0 || !gr)
752 int pa_check_in_group(gid_t g) {
753 gid_t gids[NGROUPS_MAX];
756 if ((r = getgroups(NGROUPS_MAX, gids)) < 0)
766 #else /* HAVE_GRP_H */
768 int pa_own_uid_in_group(const char *name, gid_t *gid) {
773 int pa_uid_in_group(uid_t uid, const char *name) {
777 gid_t pa_get_gid_of_group(const char *name) {
781 int pa_check_in_group(gid_t g) {
787 /* Lock or unlock a file entirely.
788 (advisory on UNIX, mandatory on Windows) */
789 int pa_lock_fd(int fd, int b) {
793 /* Try a R/W lock first */
795 flock.l_type = b ? F_WRLCK : F_UNLCK;
796 flock.l_whence = SEEK_SET;
800 if (fcntl(fd, F_SETLKW, &flock) >= 0)
803 /* Perhaps the file descriptor qas opened for read only, than try again with a read lock. */
804 if (b && errno == EBADF) {
805 flock.l_type = F_RDLCK;
806 if (fcntl(fd, F_SETLKW, &flock) >= 0)
810 pa_log("%slock: %s", !b? "un" : "",
811 pa_cstrerror(errno));
815 HANDLE h = (HANDLE)_get_osfhandle(fd);
817 if (b && LockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF))
819 if (!b && UnlockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF))
822 pa_log("%slock failed: 0x%08X", !b ? "un" : "", GetLastError());
828 /* Remove trailing newlines from a string */
829 char* pa_strip_nl(char *s) {
832 s[strcspn(s, "\r\n")] = 0;
836 /* Create a temporary lock file and lock it. */
837 int pa_lock_lockfile(const char *fn) {
844 if ((fd = open(fn, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR)) < 0) {
845 pa_log("failed to create lock file '%s': %s", fn,
846 pa_cstrerror(errno));
850 if (pa_lock_fd(fd, 1) < 0) {
851 pa_log("failed to lock file '%s'.", fn);
855 if (fstat(fd, &st) < 0) {
856 pa_log("failed to fstat() file '%s'.", fn);
860 /* Check wheter the file has been removed meanwhile. When yes, restart this loop, otherwise, we're done */
861 if (st.st_nlink >= 1)
864 if (pa_lock_fd(fd, 0) < 0) {
865 pa_log("failed to unlock file '%s'.", fn);
870 pa_log("failed to close file '%s'.", fn);
887 /* Unlock a temporary lcok file */
888 int pa_unlock_lockfile(const char *fn, int fd) {
890 assert(fn && fd >= 0);
892 if (unlink(fn) < 0) {
893 pa_log_warn("WARNING: unable to remove lock file '%s': %s",
894 fn, pa_cstrerror(errno));
898 if (pa_lock_fd(fd, 0) < 0) {
899 pa_log_warn("WARNING: failed to unlock file '%s'.", fn);
904 pa_log_warn("WARNING: failed to close lock file '%s': %s",
905 fn, pa_cstrerror(errno));
912 /* Try to open a configuration file. If "env" is specified, open the
913 * value of the specified environment variable. Otherwise look for a
914 * file "local" in the home directory or a file "global" in global
915 * file system. If "result" is non-NULL, a pointer to a newly
916 * allocated buffer containing the used configuration file is
918 FILE *pa_open_config_file(const char *global, const char *local, const char *env, char **result, const char *mode) {
925 if (!getenv(PULSE_ROOTENV))
929 if (env && (fn = getenv(env))) {
931 if (!ExpandEnvironmentStrings(fn, buf, PATH_MAX))
937 *result = pa_xstrdup(fn);
939 return fopen(fn, mode);
946 if ((e = getenv("PULSE_CONFIG_PATH")))
947 fn = lfn = pa_sprintf_malloc("%s/%s", e, local);
948 else if (pa_get_home_dir(h, sizeof(h)))
949 fn = lfn = pa_sprintf_malloc("%s/.pulse/%s", h, local);
955 if (!ExpandEnvironmentStrings(lfn, buf, PATH_MAX))
963 *result = pa_xstrdup(fn);
968 if (errno != ENOENT) {
969 pa_log_warn("WARNING: failed to open configuration file '%s': %s",
970 lfn, pa_cstrerror(errno));
985 if (!ExpandEnvironmentStrings(global, buf, PATH_MAX))
991 *result = pa_xstrdup(global);
993 return fopen(global, mode);
996 /* Format the specified data as a hexademical string */
997 char *pa_hexstr(const uint8_t* d, size_t dlength, char *s, size_t slength) {
999 const char hex[] = "0123456789abcdef";
1000 assert(d && s && slength > 0);
1002 while (i < dlength && j+3 <= slength) {
1003 s[j++] = hex[*d >> 4];
1004 s[j++] = hex[*d & 0xF];
1010 s[j < slength ? j : slength] = 0;
1014 /* Convert a hexadecimal digit to a number or -1 if invalid */
1015 static int hexc(char c) {
1016 if (c >= '0' && c <= '9')
1019 if (c >= 'A' && c <= 'F')
1020 return c - 'A' + 10;
1022 if (c >= 'a' && c <= 'f')
1023 return c - 'a' + 10;
1028 /* Parse a hexadecimal string as created by pa_hexstr() to a BLOB */
1029 size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength) {
1033 while (j < dlength && *p) {
1036 if ((b = hexc(*(p++))) < 0)
1039 d[j] = (uint8_t) (b << 4);
1044 if ((b = hexc(*(p++))) < 0)
1047 d[j] |= (uint8_t) b;
1054 /* Returns nonzero when *s starts with *pfx */
1055 int pa_startswith(const char *s, const char *pfx) {
1063 return strlen(s) >= l && strncmp(s, pfx, l) == 0;
1066 /* Returns nonzero when *s ends with *sfx */
1067 int pa_endswith(const char *s, const char *sfx) {
1076 return l1 >= l2 && strcmp(s+l1-l2, sfx) == 0;
1079 /* if fn is null return the PulseAudio run time path in s (/tmp/pulse)
1080 * if fn is non-null and starts with / return fn in s
1081 * otherwise append fn to the run time path and return it in s */
1082 char *pa_runtime_path(const char *fn, char *s, size_t l) {
1086 if (fn && *fn == '/')
1088 if (fn && strlen(fn) >= 3 && isalpha(fn[0]) && fn[1] == ':' && fn[2] == '\\')
1090 return pa_strlcpy(s, fn, l);
1092 if ((e = getenv("PULSE_RUNTIME_PATH"))) {
1095 snprintf(s, l, "%s%c%s", e, PATH_SEP, fn);
1097 snprintf(s, l, "%s", e);
1103 snprintf(s, l, "%s%s%c%s", PA_USER_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u)), PATH_SEP, fn);
1105 snprintf(s, l, "%s%s", PA_USER_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u)));
1113 ExpandEnvironmentStrings(buf, s, l);
1120 /* Convert the string s to a signed integer in *ret_i */
1121 int pa_atoi(const char *s, int32_t *ret_i) {
1126 l = strtol(s, &x, 0);
1131 *ret_i = (int32_t) l;
1136 /* Convert the string s to an unsigned integer in *ret_u */
1137 int pa_atou(const char *s, uint32_t *ret_u) {
1142 l = strtoul(s, &x, 0);
1147 *ret_u = (uint32_t) l;