4 This file is part of PulseAudio.
6 Copyright 2004-2006 Lennart Poettering
7 Copyright 2004 Joe Marcus Clarke
8 Copyright 2006-2007 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
41 #include <sys/types.h>
49 #ifdef HAVE_SYS_RESOURCE_H
50 #include <sys/resource.h>
53 #ifdef HAVE_SYS_CAPABILITY_H
54 #include <sys/capability.h>
77 #include <samplerate.h>
79 #include <pulse/xmalloc.h>
80 #include <pulse/util.h>
81 #include <pulse/utf8.h>
83 #include <pulsecore/core-error.h>
84 #include <pulsecore/winsock.h>
85 #include <pulsecore/log.h>
86 #include <pulsecore/macro.h>
88 #include "core-util.h"
90 /* Not all platforms have this */
92 #define MSG_NOSIGNAL 0
96 #define PA_USER_RUNTIME_PATH_PREFIX "/tmp/pulse-"
99 #define PA_USER_RUNTIME_PATH_PREFIX "%TEMP%\\pulse-"
100 #define PATH_SEP '\\'
105 #define PULSE_ROOTENV "PULSE_ROOT"
107 int pa_set_root(HANDLE handle
) {
108 char library_path
[MAX_PATH
+ sizeof(PULSE_ROOTENV
) + 1], *sep
;
110 strcpy(library_path
, PULSE_ROOTENV
"=");
112 if (!GetModuleFileName(handle
, library_path
+ sizeof(PULSE_ROOTENV
), MAX_PATH
))
115 sep
= strrchr(library_path
, '\\');
119 if (_putenv(library_path
) < 0)
127 /** Make a file descriptor nonblock. Doesn't do any error checking */
128 void pa_make_nonblock_fd(int fd
) {
133 if ((v
= fcntl(fd
, F_GETFL
)) >= 0)
134 if (!(v
& O_NONBLOCK
))
135 fcntl(fd
, F_SETFL
, v
|O_NONBLOCK
);
136 #elif defined(OS_IS_WIN32)
138 if (ioctlsocket(fd
, FIONBIO
, &arg
) < 0) {
139 if (WSAGetLastError() == WSAENOTSOCK
)
140 pa_log_warn("WARNING: Only sockets can be made non-blocking!");
143 pa_log_warn("WARNING: Non-blocking I/O not supported.!");
147 /** Creates a directory securely */
148 int pa_make_secure_dir(const char* dir
, mode_t m
, uid_t uid
, gid_t gid
) {
165 if (r
< 0 && errno
!= EEXIST
)
169 if (uid
== (uid_t
)-1)
171 if (gid
== (gid_t
)-1)
173 (void) chown(dir
, uid
, gid
);
181 if (lstat(dir
, &st
) < 0)
183 if (stat(dir
, &st
) < 0)
188 if (!S_ISDIR(st
.st_mode
) ||
189 (st
.st_uid
!= uid
) ||
190 (st
.st_gid
!= gid
) ||
191 ((st
.st_mode
& 0777) != m
)) {
196 pa_log_warn("secure directory creation not supported on Win32.");
206 /* Return a newly allocated sting containing the parent directory of the specified file */
207 char *pa_parent_dir(const char *fn
) {
208 char *slash
, *dir
= pa_xstrdup(fn
);
210 if ((slash
= (char*) pa_path_get_filename(dir
)) == dir
) {
219 /* Creates a the parent directory of the specified path securely */
220 int pa_make_secure_parent_dir(const char *fn
, mode_t m
, uid_t uid
, gid_t gid
) {
224 if (!(dir
= pa_parent_dir(fn
)))
227 if (pa_make_secure_dir(dir
, m
, uid
, gid
) < 0)
237 /** Platform independent read function. Necessary since not all
238 * systems treat all file descriptors equal. If type is
239 * non-NULL it is used to cache the type of the fd. This is
240 * useful for making sure that only a single syscall is executed per
241 * function call. The variable pointed to should be initialized to 0
243 ssize_t
pa_read(int fd
, void *buf
, size_t count
, int *type
) {
247 if (!type
|| *type
== 0) {
250 if ((r
= recv(fd
, buf
, count
, 0)) >= 0)
253 if (WSAGetLastError() != WSAENOTSOCK
) {
254 errno
= WSAGetLastError();
264 return read(fd
, buf
, count
);
267 /** Similar to pa_read(), but handles writes */
268 ssize_t
pa_write(int fd
, const void *buf
, size_t count
, int *type
) {
270 if (!type
|| *type
== 0) {
273 if ((r
= send(fd
, buf
, count
, MSG_NOSIGNAL
)) >= 0)
277 if (WSAGetLastError() != WSAENOTSOCK
) {
278 errno
= WSAGetLastError();
282 if (errno
!= ENOTSOCK
)
290 return write(fd
, buf
, count
);
293 /** Calls read() in a loop. Makes sure that as much as 'size' bytes,
294 * unless EOF is reached or an error occured */
295 ssize_t
pa_loop_read(int fd
, void*data
, size_t size
, int *type
) {
311 if ((r
= pa_read(fd
, data
, size
, type
)) < 0)
318 data
= (uint8_t*) data
+ r
;
325 /** Similar to pa_loop_read(), but wraps write() */
326 ssize_t
pa_loop_write(int fd
, const void*data
, size_t size
, int *type
) {
342 if ((r
= pa_write(fd
, data
, size
, type
)) < 0)
349 data
= (const uint8_t*) data
+ r
;
356 /** Platform independent read function. Necessary since not all
357 * systems treat all file descriptors equal. */
358 int pa_close(int fd
) {
362 ret
= closesocket(fd
);
366 if (WSAGetLastError() != WSAENOTSOCK
) {
367 errno
= WSAGetLastError();
375 /* Print a warning messages in case that the given signal is not
376 * blocked or trapped */
377 void pa_check_signal_is_blocked(int sig
) {
378 #ifdef HAVE_SIGACTION
382 /* If POSIX threads are supported use thread-aware
383 * pthread_sigmask() function, to check if the signal is
384 * blocked. Otherwise fall back to sigprocmask() */
387 if (pthread_sigmask(SIG_SETMASK
, NULL
, &set
) < 0) {
389 if (sigprocmask(SIG_SETMASK
, NULL
, &set
) < 0) {
390 pa_log("sigprocmask(): %s", pa_cstrerror(errno
));
397 if (sigismember(&set
, sig
))
400 /* Check whether the signal is trapped */
402 if (sigaction(sig
, NULL
, &sa
) < 0) {
403 pa_log("sigaction(): %s", pa_cstrerror(errno
));
407 if (sa
.sa_handler
!= SIG_DFL
)
410 pa_log("WARNING: %s is not trapped. This might cause malfunction!", pa_strsignal(sig
));
411 #else /* HAVE_SIGACTION */
412 pa_log("WARNING: %s might not be trapped. This might cause malfunction!", pa_strsignal(sig
));
416 /* The following function is based on an example from the GNU libc
417 * documentation. This function is similar to GNU's asprintf(). */
418 char *pa_sprintf_malloc(const char *format
, ...) {
428 c
= pa_xrealloc(c
, size
);
430 va_start(ap
, format
);
431 r
= vsnprintf(c
, size
, format
, ap
);
436 if (r
> -1 && r
< size
)
439 if (r
> -1) /* glibc 2.1 */
446 /* Same as the previous function, but use a va_list instead of an
448 char *pa_vsprintf_malloc(const char *format
, va_list ap
) {
458 c
= pa_xrealloc(c
, size
);
461 r
= vsnprintf(c
, size
, format
, aq
);
466 if (r
> -1 && r
< size
)
469 if (r
> -1) /* glibc 2.1 */
476 /* Similar to OpenBSD's strlcpy() function */
477 char *pa_strlcpy(char *b
, const char *s
, size_t l
) {
478 assert(b
&& s
&& l
> 0);
485 /* Make the current thread a realtime thread*/
486 void pa_make_realtime(void) {
488 #ifdef _POSIX_PRIORITY_SCHEDULING
489 struct sched_param sp
;
492 memset(&sp
, 0, sizeof(sp
));
495 if ((r
= pthread_getschedparam(pthread_self(), &policy
, &sp
)) != 0) {
496 pa_log("pthread_getschedgetparam(): %s", pa_cstrerror(r
));
500 sp
.sched_priority
= 1;
501 if ((r
= pthread_setschedparam(pthread_self(), SCHED_FIFO
, &sp
)) != 0) {
502 pa_log_warn("pthread_setschedparam(): %s", pa_cstrerror(r
));
506 pa_log_info("Successfully enabled SCHED_FIFO scheduling for thread.");
511 #define NICE_LEVEL (-11)
513 /* Raise the priority of the current process as much as possible and
514 sensible: set the nice level to -15.*/
515 void pa_raise_priority(void) {
517 #ifdef HAVE_SYS_RESOURCE_H
518 if (setpriority(PRIO_PROCESS
, 0, NICE_LEVEL
) < 0)
519 pa_log_warn("setpriority(): %s", pa_cstrerror(errno
));
521 pa_log_info("Successfully gained nice level %i.", NICE_LEVEL
);
525 if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS
))
526 pa_log_warn("SetPriorityClass() failed: 0x%08X", GetLastError());
528 pa_log_info("Successfully gained high priority class.");
532 /* Reset the priority to normal, inverting the changes made by
533 * pa_raise_priority() */
534 void pa_reset_priority(void) {
536 SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS
);
539 #ifdef HAVE_SYS_RESOURCE_H
540 setpriority(PRIO_PROCESS
, 0, 0);
544 /* Set the FD_CLOEXEC flag for a fd */
545 int pa_fd_set_cloexec(int fd
, int b
) {
551 if ((v
= fcntl(fd
, F_GETFD
, 0)) < 0)
554 v
= (v
& ~FD_CLOEXEC
) | (b
? FD_CLOEXEC
: 0);
556 if (fcntl(fd
, F_SETFD
, v
) < 0)
563 /* Try to parse a boolean string value.*/
564 int pa_parse_boolean(const char *v
) {
566 if (!strcmp(v
, "1") || v
[0] == 'y' || v
[0] == 'Y' || v
[0] == 't' || v
[0] == 'T' || !strcasecmp(v
, "on"))
568 else if (!strcmp(v
, "0") || v
[0] == 'n' || v
[0] == 'N' || v
[0] == 'f' || v
[0] == 'F' || !strcasecmp(v
, "off"))
574 /* Split the specified string wherever one of the strings in delimiter
575 * occurs. Each time it is called returns a newly allocated string
576 * with pa_xmalloc(). The variable state points to, should be
577 * initiallized to NULL before the first call. */
578 char *pa_split(const char *c
, const char *delimiter
, const char**state
) {
579 const char *current
= *state
? *state
: c
;
585 l
= strcspn(current
, delimiter
);
591 return pa_xstrndup(current
, l
);
594 /* What is interpreted as whitespace? */
595 #define WHITESPACE " \t\n"
597 /* Split a string into words. Otherwise similar to pa_split(). */
598 char *pa_split_spaces(const char *c
, const char **state
) {
599 const char *current
= *state
? *state
: c
;
602 if (!*current
|| *c
== 0)
605 current
+= strspn(current
, WHITESPACE
);
606 l
= strcspn(current
, WHITESPACE
);
610 return pa_xstrndup(current
, l
);
613 /* Return the name of an UNIX signal. Similar to GNU's strsignal() */
614 const char *pa_strsignal(int sig
) {
616 case SIGINT
: return "SIGINT";
617 case SIGTERM
: return "SIGTERM";
619 case SIGUSR1
: return "SIGUSR1";
622 case SIGUSR2
: return "SIGUSR2";
625 case SIGXCPU
: return "SIGXCPU";
628 case SIGPIPE
: return "SIGPIPE";
631 case SIGCHLD
: return "SIGCHLD";
634 case SIGHUP
: return "SIGHUP";
636 default: return "UNKNOWN SIGNAL";
642 /* Check whether the specified GID and the group name match */
643 static int is_group(gid_t gid
, const char *name
) {
644 struct group group
, *result
= NULL
;
649 #ifdef HAVE_GETGRGID_R
650 #ifdef _SC_GETGR_R_SIZE_MAX
651 n
= sysconf(_SC_GETGR_R_SIZE_MAX
);
656 data
= pa_xmalloc(n
);
658 if (getgrgid_r(gid
, &group
, data
, n
, &result
) < 0 || !result
) {
659 pa_log("getgrgid_r(%u): %s", (unsigned)gid
, pa_cstrerror(errno
));
663 r
= strcmp(name
, result
->gr_name
) == 0;
668 /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) that do not
669 * support getgrgid_r. */
670 if ((result
= getgrgid(gid
)) == NULL
) {
671 pa_log("getgrgid(%u): %s", gid
, pa_cstrerror(errno
));
675 r
= strcmp(name
, result
->gr_name
) == 0;
683 /* Check the current user is member of the specified group */
684 int pa_own_uid_in_group(const char *name
, gid_t
*gid
) {
685 GETGROUPS_T
*gids
, tgid
;
686 int n
= sysconf(_SC_NGROUPS_MAX
);
691 gids
= pa_xmalloc(sizeof(GETGROUPS_T
)*n
);
693 if ((n
= getgroups(n
, gids
)) < 0) {
694 pa_log("getgroups(): %s", pa_cstrerror(errno
));
698 for (i
= 0; i
< n
; i
++) {
699 if (is_group(gids
[i
], name
) > 0) {
706 if (is_group(tgid
= getgid(), name
) > 0) {
720 /* Check whether the specifc user id is a member of the specified group */
721 int pa_uid_in_group(uid_t uid
, const char *name
) {
724 struct group grbuf
, *gr
;
728 g_n
= sysconf(_SC_GETGR_R_SIZE_MAX
);
729 g_buf
= pa_xmalloc(g_n
);
731 p_n
= sysconf(_SC_GETPW_R_SIZE_MAX
);
732 p_buf
= pa_xmalloc(p_n
);
734 if (getgrnam_r(name
, &grbuf
, g_buf
, (size_t) g_n
, &gr
) != 0 || !gr
)
738 for (i
= gr
->gr_mem
; *i
; i
++) {
739 struct passwd pwbuf
, *pw
;
741 if (getpwnam_r(*i
, &pwbuf
, p_buf
, (size_t) p_n
, &pw
) != 0 || !pw
)
744 if (pw
->pw_uid
== uid
) {
757 /* Get the GID of a gfiven group, return (gid_t) -1 on failure. */
758 gid_t
pa_get_gid_of_group(const char *name
) {
759 gid_t ret
= (gid_t
) -1;
762 struct group grbuf
, *gr
;
764 g_n
= sysconf(_SC_GETGR_R_SIZE_MAX
);
765 g_buf
= pa_xmalloc(g_n
);
767 if (getgrnam_r(name
, &grbuf
, g_buf
, (size_t) g_n
, &gr
) != 0 || !gr
)
777 int pa_check_in_group(gid_t g
) {
778 gid_t gids
[NGROUPS_MAX
];
781 if ((r
= getgroups(NGROUPS_MAX
, gids
)) < 0)
791 #else /* HAVE_GRP_H */
793 int pa_own_uid_in_group(const char *name
, gid_t
*gid
) {
798 int pa_uid_in_group(uid_t uid
, const char *name
) {
802 gid_t
pa_get_gid_of_group(const char *name
) {
806 int pa_check_in_group(gid_t g
) {
812 /* Lock or unlock a file entirely.
813 (advisory on UNIX, mandatory on Windows) */
814 int pa_lock_fd(int fd
, int b
) {
818 /* Try a R/W lock first */
820 flock
.l_type
= b
? F_WRLCK
: F_UNLCK
;
821 flock
.l_whence
= SEEK_SET
;
825 if (fcntl(fd
, F_SETLKW
, &flock
) >= 0)
828 /* Perhaps the file descriptor qas opened for read only, than try again with a read lock. */
829 if (b
&& errno
== EBADF
) {
830 flock
.l_type
= F_RDLCK
;
831 if (fcntl(fd
, F_SETLKW
, &flock
) >= 0)
835 pa_log("%slock: %s", !b
? "un" : "",
836 pa_cstrerror(errno
));
840 HANDLE h
= (HANDLE
)_get_osfhandle(fd
);
842 if (b
&& LockFile(h
, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF))
844 if (!b
&& UnlockFile(h
, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF))
847 pa_log("%slock failed: 0x%08X", !b
? "un" : "", GetLastError());
853 /* Remove trailing newlines from a string */
854 char* pa_strip_nl(char *s
) {
857 s
[strcspn(s
, "\r\n")] = 0;
861 /* Create a temporary lock file and lock it. */
862 int pa_lock_lockfile(const char *fn
) {
869 if ((fd
= open(fn
, O_CREAT
|O_RDWR
, S_IRUSR
|S_IWUSR
)) < 0) {
870 pa_log("failed to create lock file '%s': %s", fn
,
871 pa_cstrerror(errno
));
875 if (pa_lock_fd(fd
, 1) < 0) {
876 pa_log("failed to lock file '%s'.", fn
);
880 if (fstat(fd
, &st
) < 0) {
881 pa_log("failed to fstat() file '%s'.", fn
);
885 /* Check wheter the file has been removed meanwhile. When yes, restart this loop, otherwise, we're done */
886 if (st
.st_nlink
>= 1)
889 if (pa_lock_fd(fd
, 0) < 0) {
890 pa_log("failed to unlock file '%s'.", fn
);
895 pa_log("failed to close file '%s'.", fn
);
912 /* Unlock a temporary lcok file */
913 int pa_unlock_lockfile(const char *fn
, int fd
) {
915 assert(fn
&& fd
>= 0);
917 if (unlink(fn
) < 0) {
918 pa_log_warn("WARNING: unable to remove lock file '%s': %s",
919 fn
, pa_cstrerror(errno
));
923 if (pa_lock_fd(fd
, 0) < 0) {
924 pa_log_warn("WARNING: failed to unlock file '%s'.", fn
);
929 pa_log_warn("WARNING: failed to close lock file '%s': %s",
930 fn
, pa_cstrerror(errno
));
937 /* Try to open a configuration file. If "env" is specified, open the
938 * value of the specified environment variable. Otherwise look for a
939 * file "local" in the home directory or a file "global" in global
940 * file system. If "result" is non-NULL, a pointer to a newly
941 * allocated buffer containing the used configuration file is
943 FILE *pa_open_config_file(const char *global
, const char *local
, const char *env
, char **result
, const char *mode
) {
950 if (!getenv(PULSE_ROOTENV
))
954 if (env
&& (fn
= getenv(env
))) {
956 if (!ExpandEnvironmentStrings(fn
, buf
, PATH_MAX
))
962 *result
= pa_xstrdup(fn
);
964 return fopen(fn
, mode
);
971 if ((e
= getenv("PULSE_CONFIG_PATH")))
972 fn
= lfn
= pa_sprintf_malloc("%s/%s", e
, local
);
973 else if (pa_get_home_dir(h
, sizeof(h
)))
974 fn
= lfn
= pa_sprintf_malloc("%s/.pulse/%s", h
, local
);
980 if (!ExpandEnvironmentStrings(lfn
, buf
, PATH_MAX
))
988 *result
= pa_xstrdup(fn
);
993 if (errno
!= ENOENT
) {
994 pa_log_warn("WARNING: failed to open configuration file '%s': %s",
995 lfn
, pa_cstrerror(errno
));
1010 if (!ExpandEnvironmentStrings(global
, buf
, PATH_MAX
))
1016 *result
= pa_xstrdup(global
);
1018 return fopen(global
, mode
);
1021 /* Format the specified data as a hexademical string */
1022 char *pa_hexstr(const uint8_t* d
, size_t dlength
, char *s
, size_t slength
) {
1023 size_t i
= 0, j
= 0;
1024 const char hex
[] = "0123456789abcdef";
1025 assert(d
&& s
&& slength
> 0);
1027 while (i
< dlength
&& j
+3 <= slength
) {
1028 s
[j
++] = hex
[*d
>> 4];
1029 s
[j
++] = hex
[*d
& 0xF];
1035 s
[j
< slength
? j
: slength
] = 0;
1039 /* Convert a hexadecimal digit to a number or -1 if invalid */
1040 static int hexc(char c
) {
1041 if (c
>= '0' && c
<= '9')
1044 if (c
>= 'A' && c
<= 'F')
1045 return c
- 'A' + 10;
1047 if (c
>= 'a' && c
<= 'f')
1048 return c
- 'a' + 10;
1053 /* Parse a hexadecimal string as created by pa_hexstr() to a BLOB */
1054 size_t pa_parsehex(const char *p
, uint8_t *d
, size_t dlength
) {
1058 while (j
< dlength
&& *p
) {
1061 if ((b
= hexc(*(p
++))) < 0)
1064 d
[j
] = (uint8_t) (b
<< 4);
1069 if ((b
= hexc(*(p
++))) < 0)
1072 d
[j
] |= (uint8_t) b
;
1079 /* Returns nonzero when *s starts with *pfx */
1080 int pa_startswith(const char *s
, const char *pfx
) {
1088 return strlen(s
) >= l
&& strncmp(s
, pfx
, l
) == 0;
1091 /* Returns nonzero when *s ends with *sfx */
1092 int pa_endswith(const char *s
, const char *sfx
) {
1101 return l1
>= l2
&& strcmp(s
+l1
-l2
, sfx
) == 0;
1104 /* if fn is null return the PulseAudio run time path in s (/tmp/pulse)
1105 * if fn is non-null and starts with / return fn in s
1106 * otherwise append fn to the run time path and return it in s */
1107 char *pa_runtime_path(const char *fn
, char *s
, size_t l
) {
1111 if (fn
&& *fn
== '/')
1113 if (fn
&& strlen(fn
) >= 3 && isalpha(fn
[0]) && fn
[1] == ':' && fn
[2] == '\\')
1115 return pa_strlcpy(s
, fn
, l
);
1117 if ((e
= getenv("PULSE_RUNTIME_PATH"))) {
1120 pa_snprintf(s
, l
, "%s%c%s", e
, PATH_SEP
, fn
);
1122 pa_snprintf(s
, l
, "%s", e
);
1128 pa_snprintf(s
, l
, "%s%s%c%s", PA_USER_RUNTIME_PATH_PREFIX
, pa_get_user_name(u
, sizeof(u
)), PATH_SEP
, fn
);
1130 pa_snprintf(s
, l
, "%s%s", PA_USER_RUNTIME_PATH_PREFIX
, pa_get_user_name(u
, sizeof(u
)));
1138 ExpandEnvironmentStrings(buf
, s
, l
);
1145 /* Convert the string s to a signed integer in *ret_i */
1146 int pa_atoi(const char *s
, int32_t *ret_i
) {
1151 l
= strtol(s
, &x
, 0);
1156 *ret_i
= (int32_t) l
;
1161 /* Convert the string s to an unsigned integer in *ret_u */
1162 int pa_atou(const char *s
, uint32_t *ret_u
) {
1167 l
= strtoul(s
, &x
, 0);
1172 *ret_u
= (uint32_t) l
;
1177 /* Same as snprintf, but guarantees NUL-termination on every platform */
1178 int pa_snprintf(char *str
, size_t size
, const char *format
, ...) {
1183 pa_assert(size
> 0);
1186 va_start(ap
, format
);
1187 ret
= vsnprintf(str
, size
, format
, ap
);
1195 /* Truncate the specified string, but guarantee that the string
1196 * returned still validates as UTF8 */
1197 char *pa_truncate_utf8(char *c
, size_t l
) {
1199 pa_assert(pa_utf8_valid(c
));
1206 while (l
> 0 && !pa_utf8_valid(c
))