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
38 #include <sys/types.h>
42 #ifdef HAVE_LANGINFO_H
47 #include <sys/utsname.h>
50 #if defined(HAVE_REGEX_H)
52 #elif defined(HAVE_PCREPOSIX_H)
53 #include <pcreposix.h>
63 #if defined(__linux__) && !defined(SCHED_RESET_ON_FORK)
64 #define SCHED_RESET_ON_FORK 0x40000000
68 #ifdef HAVE_SYS_RESOURCE_H
69 #include <sys/resource.h>
72 #ifdef HAVE_SYS_CAPABILITY_H
73 #include <sys/capability.h>
76 #ifdef HAVE_SYS_MMAN_H
104 #ifdef HAVE_LIBSAMPLERATE
105 #include <samplerate.h>
117 #include <sys/personality.h>
120 #include <pulse/xmalloc.h>
121 #include <pulse/util.h>
122 #include <pulse/utf8.h>
124 #include <pulsecore/core-error.h>
125 #include <pulsecore/socket.h>
126 #include <pulsecore/log.h>
127 #include <pulsecore/macro.h>
128 #include <pulsecore/thread.h>
129 #include <pulsecore/strbuf.h>
130 #include <pulsecore/usergroup.h>
131 #include <pulsecore/strlist.h>
132 #include <pulsecore/cpu-x86.h>
133 #include <pulsecore/pipe.h>
135 #include "core-util.h"
137 /* Not all platforms have this */
139 #define MSG_NOSIGNAL 0
142 #define NEWLINE "\r\n"
143 #define WHITESPACE "\n\r \t"
145 static pa_strlist
*recorded_env
= NULL
;
149 #define PULSE_ROOTENV "PULSE_ROOT"
151 int pa_set_root(HANDLE handle
) {
152 char library_path
[MAX_PATH
], *sep
;
154 /* FIXME: Needs to set errno */
156 if (!GetModuleFileName(handle
, library_path
, MAX_PATH
))
159 sep
= strrchr(library_path
, PA_PATH_SEP_CHAR
);
163 if (!SetEnvironmentVariable(PULSE_ROOTENV
, library_path
))
171 /** Make a file descriptor nonblock. Doesn't do any error checking */
172 void pa_make_fd_nonblock(int fd
) {
178 pa_assert_se((v
= fcntl(fd
, F_GETFL
)) >= 0);
180 if (!(v
& O_NONBLOCK
))
181 pa_assert_se(fcntl(fd
, F_SETFL
, v
|O_NONBLOCK
) >= 0);
183 #elif defined(OS_IS_WIN32)
185 if (ioctlsocket(fd
, FIONBIO
, &arg
) < 0) {
186 pa_assert_se(WSAGetLastError() == WSAENOTSOCK
);
187 pa_log_warn("Only sockets can be made non-blocking!");
190 pa_log_warn("Non-blocking I/O not supported.!");
195 /* Set the FD_CLOEXEC flag for a fd */
196 void pa_make_fd_cloexec(int fd
) {
202 pa_assert_se((v
= fcntl(fd
, F_GETFD
, 0)) >= 0);
204 if (!(v
& FD_CLOEXEC
))
205 pa_assert_se(fcntl(fd
, F_SETFD
, v
|FD_CLOEXEC
) >= 0);
210 /** Creates a directory securely */
211 int pa_make_secure_dir(const char* dir
, mode_t m
, uid_t uid
, gid_t gid
) {
213 int r
, saved_errno
, fd
;
222 u
= umask((~m
) & 0777);
228 if (r
< 0 && errno
!= EEXIST
)
231 #if defined(HAVE_FSTAT) && !defined(OS_IS_WIN32)
245 if (fstat(fd
, &st
) < 0) {
246 pa_assert_se(pa_close(fd
) >= 0);
250 if (!S_ISDIR(st
.st_mode
)) {
251 pa_assert_se(pa_close(fd
) >= 0);
257 if (uid
== (uid_t
)-1)
259 if (gid
== (gid_t
)-1)
261 (void) fchown(fd
, uid
, gid
);
265 (void) fchmod(fd
, m
);
268 pa_assert_se(pa_close(fd
) >= 0);
272 if (lstat(dir
, &st
) < 0)
274 if (stat(dir
, &st
) < 0)
279 if (!S_ISDIR(st
.st_mode
) ||
280 (st
.st_uid
!= uid
) ||
281 (st
.st_gid
!= gid
) ||
282 ((st
.st_mode
& 0777) != m
)) {
287 pa_log_warn("Secure directory creation not supported on Win32.");
300 /* Return a newly allocated sting containing the parent directory of the specified file */
301 char *pa_parent_dir(const char *fn
) {
302 char *slash
, *dir
= pa_xstrdup(fn
);
304 if ((slash
= (char*) pa_path_get_filename(dir
)) == dir
) {
314 /* Creates a the parent directory of the specified path securely */
315 int pa_make_secure_parent_dir(const char *fn
, mode_t m
, uid_t uid
, gid_t gid
) {
319 if (!(dir
= pa_parent_dir(fn
)))
322 if (pa_make_secure_dir(dir
, m
, uid
, gid
) < 0)
332 /** Platform independent read function. Necessary since not all
333 * systems treat all file descriptors equal. If type is
334 * non-NULL it is used to cache the type of the fd. This is
335 * useful for making sure that only a single syscall is executed per
336 * function call. The variable pointed to should be initialized to 0
338 ssize_t
pa_read(int fd
, void *buf
, size_t count
, int *type
) {
342 if (!type
|| *type
== 0) {
345 if ((r
= recv(fd
, buf
, count
, 0)) >= 0)
348 if (WSAGetLastError() != WSAENOTSOCK
) {
349 errno
= WSAGetLastError();
362 if ((r
= read(fd
, buf
, count
)) < 0)
370 /** Similar to pa_read(), but handles writes */
371 ssize_t
pa_write(int fd
, const void *buf
, size_t count
, int *type
) {
373 if (!type
|| *type
== 0) {
377 if ((r
= send(fd
, buf
, count
, MSG_NOSIGNAL
)) < 0) {
389 if (WSAGetLastError() != WSAENOTSOCK
) {
390 errno
= WSAGetLastError();
394 if (errno
!= ENOTSOCK
)
405 if ((r
= write(fd
, buf
, count
)) < 0)
413 /** Calls read() in a loop. Makes sure that as much as 'size' bytes,
414 * unless EOF is reached or an error occurred */
415 ssize_t
pa_loop_read(int fd
, void*data
, size_t size
, int *type
) {
431 if ((r
= pa_read(fd
, data
, size
, type
)) < 0)
438 data
= (uint8_t*) data
+ r
;
445 /** Similar to pa_loop_read(), but wraps write() */
446 ssize_t
pa_loop_write(int fd
, const void*data
, size_t size
, int *type
) {
462 if ((r
= pa_write(fd
, data
, size
, type
)) < 0)
469 data
= (const uint8_t*) data
+ r
;
476 /** Platform independent read function. Necessary since not all
477 * systems treat all file descriptors equal. */
478 int pa_close(int fd
) {
483 if ((ret
= closesocket(fd
)) == 0)
486 if (WSAGetLastError() != WSAENOTSOCK
) {
487 errno
= WSAGetLastError();
495 if ((r
= close(fd
)) < 0)
503 /* Print a warning messages in case that the given signal is not
504 * blocked or trapped */
505 void pa_check_signal_is_blocked(int sig
) {
506 #ifdef HAVE_SIGACTION
510 /* If POSIX threads are supported use thread-aware
511 * pthread_sigmask() function, to check if the signal is
512 * blocked. Otherwise fall back to sigprocmask() */
515 if (pthread_sigmask(SIG_SETMASK
, NULL
, &set
) < 0) {
517 if (sigprocmask(SIG_SETMASK
, NULL
, &set
) < 0) {
518 pa_log("sigprocmask(): %s", pa_cstrerror(errno
));
525 if (sigismember(&set
, sig
))
528 /* Check whether the signal is trapped */
530 if (sigaction(sig
, NULL
, &sa
) < 0) {
531 pa_log("sigaction(): %s", pa_cstrerror(errno
));
535 if (sa
.sa_handler
!= SIG_DFL
)
538 pa_log_warn("%s is not trapped. This might cause malfunction!", pa_sig2str(sig
));
539 #else /* HAVE_SIGACTION */
540 pa_log_warn("%s might not be trapped. This might cause malfunction!", pa_sig2str(sig
));
544 /* The following function is based on an example from the GNU libc
545 * documentation. This function is similar to GNU's asprintf(). */
546 char *pa_sprintf_malloc(const char *format
, ...) {
556 c
= pa_xrealloc(c
, size
);
558 va_start(ap
, format
);
559 r
= vsnprintf(c
, size
, format
, ap
);
564 if (r
> -1 && (size_t) r
< size
)
567 if (r
> -1) /* glibc 2.1 */
574 /* Same as the previous function, but use a va_list instead of an
576 char *pa_vsprintf_malloc(const char *format
, va_list ap
) {
586 c
= pa_xrealloc(c
, size
);
589 r
= vsnprintf(c
, size
, format
, aq
);
594 if (r
> -1 && (size_t) r
< size
)
597 if (r
> -1) /* glibc 2.1 */
604 /* Similar to OpenBSD's strlcpy() function */
605 char *pa_strlcpy(char *b
, const char *s
, size_t l
) {
623 #ifdef _POSIX_PRIORITY_SCHEDULING
624 static int set_scheduler(int rtprio
) {
626 struct sched_param sp
;
632 dbus_error_init(&error
);
636 sp
.sched_priority
= rtprio
;
638 #ifdef SCHED_RESET_ON_FORK
639 if (pthread_setschedparam(pthread_self(), SCHED_RR
|SCHED_RESET_ON_FORK
, &sp
) == 0) {
640 pa_log_debug("SCHED_RR|SCHED_RESET_ON_FORK worked.");
645 if (pthread_setschedparam(pthread_self(), SCHED_RR
, &sp
) == 0) {
646 pa_log_debug("SCHED_RR worked.");
649 #endif /* HAVE_SCHED_H */
652 /* Try to talk to RealtimeKit */
654 if (!(bus
= dbus_bus_get(DBUS_BUS_SYSTEM
, &error
))) {
655 pa_log("Failed to connect to system bus: %s\n", error
.message
);
656 dbus_error_free(&error
);
661 /* We need to disable exit on disconnect because otherwise
662 * dbus_shutdown will kill us. See
663 * https://bugs.freedesktop.org/show_bug.cgi?id=16924 */
664 dbus_connection_set_exit_on_disconnect(bus
, FALSE
);
666 r
= rtkit_make_realtime(bus
, 0, rtprio
);
667 dbus_connection_unref(bus
);
670 pa_log_debug("RealtimeKit worked.");
683 /* Make the current thread a realtime thread, and acquire the highest
684 * rtprio we can get that is less or equal the specified parameter. If
685 * the thread is already realtime, don't do anything. */
686 int pa_make_realtime(int rtprio
) {
688 #ifdef _POSIX_PRIORITY_SCHEDULING
691 if (set_scheduler(rtprio
) >= 0) {
692 pa_log_info("Successfully enabled SCHED_RR scheduling for thread, with priority %i.", rtprio
);
696 for (p
= rtprio
-1; p
>= 1; p
--)
697 if (set_scheduler(p
) >= 0) {
698 pa_log_info("Successfully enabled SCHED_RR scheduling for thread, with priority %i, which is lower than the requested %i.", p
, rtprio
);
701 #elif defined(OS_IS_WIN32)
702 /* Windows only allows realtime scheduling to be set on a per process basis.
703 * Therefore, instead of making the thread realtime, just give it the highest non-realtime priority. */
704 if(SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL
)) {
705 pa_log_info("Successfully enabled THREAD_PRIORITY_TIME_CRITICAL scheduling for thread.");
709 pa_log_warn("SetThreadPriority() failed: 0x%08X", GetLastError());
714 pa_log_info("Failed to acquire real-time scheduling: %s", pa_cstrerror(errno
));
718 #ifdef HAVE_SYS_RESOURCE_H
719 static int set_nice(int nice_level
) {
725 dbus_error_init(&error
);
728 #ifdef HAVE_SYS_RESOURCE_H
729 if (setpriority(PRIO_PROCESS
, 0, nice_level
) >= 0) {
730 pa_log_debug("setpriority() worked.");
736 /* Try to talk to RealtimeKit */
738 if (!(bus
= dbus_bus_get(DBUS_BUS_SYSTEM
, &error
))) {
739 pa_log("Failed to connect to system bus: %s\n", error
.message
);
740 dbus_error_free(&error
);
745 /* We need to disable exit on disconnect because otherwise
746 * dbus_shutdown will kill us. See
747 * https://bugs.freedesktop.org/show_bug.cgi?id=16924 */
748 dbus_connection_set_exit_on_disconnect(bus
, FALSE
);
750 r
= rtkit_make_high_priority(bus
, 0, nice_level
);
751 dbus_connection_unref(bus
);
754 pa_log_debug("RealtimeKit worked.");
765 /* Raise the priority of the current process as much as possible that
766 * is <= the specified nice level..*/
767 int pa_raise_priority(int nice_level
) {
769 #ifdef HAVE_SYS_RESOURCE_H
772 if (set_nice(nice_level
) >= 0) {
773 pa_log_info("Successfully gained nice level %i.", nice_level
);
777 for (n
= nice_level
+1; n
< 0; n
++)
778 if (set_nice(n
) >= 0) {
779 pa_log_info("Successfully acquired nice level %i, which is lower than the requested %i.", n
, nice_level
);
783 pa_log_info("Failed to acquire high-priority scheduling: %s", pa_cstrerror(errno
));
788 if (nice_level
< 0) {
789 if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS
)) {
790 pa_log_warn("SetPriorityClass() failed: 0x%08X", GetLastError());
795 pa_log_info("Successfully gained high priority class.");
802 /* Reset the priority to normal, inverting the changes made by
803 * pa_raise_priority() and pa_make_realtime()*/
804 void pa_reset_priority(void) {
805 #ifdef HAVE_SYS_RESOURCE_H
806 struct sched_param sp
;
808 setpriority(PRIO_PROCESS
, 0, 0);
811 pthread_setschedparam(pthread_self(), SCHED_OTHER
, &sp
);
815 SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS
);
819 int pa_match(const char *expr
, const char *v
) {
824 if (regcomp(&re
, expr
, REG_NOSUB
|REG_EXTENDED
) != 0) {
829 if ((k
= regexec(&re
, v
, 0, NULL
, 0)) == 0)
831 else if (k
== REG_NOMATCH
)
844 /* Try to parse a boolean string value.*/
845 int pa_parse_boolean(const char *v
) {
849 /* First we check language independant */
850 if (!strcmp(v
, "1") || v
[0] == 'y' || v
[0] == 'Y' || v
[0] == 't' || v
[0] == 'T' || !strcasecmp(v
, "on"))
852 else if (!strcmp(v
, "0") || v
[0] == 'n' || v
[0] == 'N' || v
[0] == 'f' || v
[0] == 'F' || !strcasecmp(v
, "off"))
855 #ifdef HAVE_LANGINFO_H
856 /* And then we check language dependant */
857 if ((expr
= nl_langinfo(YESEXPR
)))
859 if (pa_match(expr
, v
) > 0)
862 if ((expr
= nl_langinfo(NOEXPR
)))
864 if (pa_match(expr
, v
) > 0)
872 /* Split the specified string wherever one of the strings in delimiter
873 * occurs. Each time it is called returns a newly allocated string
874 * with pa_xmalloc(). The variable state points to, should be
875 * initiallized to NULL before the first call. */
876 char *pa_split(const char *c
, const char *delimiter
, const char**state
) {
877 const char *current
= *state
? *state
: c
;
883 l
= strcspn(current
, delimiter
);
889 return pa_xstrndup(current
, l
);
892 /* Split a string into words. Otherwise similar to pa_split(). */
893 char *pa_split_spaces(const char *c
, const char **state
) {
894 const char *current
= *state
? *state
: c
;
897 if (!*current
|| *c
== 0)
900 current
+= strspn(current
, WHITESPACE
);
901 l
= strcspn(current
, WHITESPACE
);
905 return pa_xstrndup(current
, l
);
908 PA_STATIC_TLS_DECLARE(signame
, pa_xfree
);
910 /* Return the name of an UNIX signal. Similar to Solaris sig2str() */
911 const char *pa_sig2str(int sig
) {
924 char buf
[SIG2STR_MAX
];
926 if (sig2str(sig
, buf
) == 0) {
927 pa_xfree(PA_STATIC_TLS_GET(signame
));
928 t
= pa_sprintf_malloc("SIG%s", buf
);
929 PA_STATIC_TLS_SET(signame
, t
);
937 case SIGHUP
: return "SIGHUP";
939 case SIGINT
: return "SIGINT";
941 case SIGQUIT
: return "SIGQUIT";
943 case SIGILL
: return "SIGULL";
945 case SIGTRAP
: return "SIGTRAP";
947 case SIGABRT
: return "SIGABRT";
949 case SIGBUS
: return "SIGBUS";
951 case SIGFPE
: return "SIGFPE";
953 case SIGKILL
: return "SIGKILL";
956 case SIGUSR1
: return "SIGUSR1";
958 case SIGSEGV
: return "SIGSEGV";
960 case SIGUSR2
: return "SIGUSR2";
963 case SIGPIPE
: return "SIGPIPE";
966 case SIGALRM
: return "SIGALRM";
968 case SIGTERM
: return "SIGTERM";
970 case SIGSTKFLT
: return "SIGSTKFLT";
973 case SIGCHLD
: return "SIGCHLD";
976 case SIGCONT
: return "SIGCONT";
979 case SIGSTOP
: return "SIGSTOP";
982 case SIGTSTP
: return "SIGTSTP";
985 case SIGTTIN
: return "SIGTTIN";
988 case SIGTTOU
: return "SIGTTOU";
991 case SIGURG
: return "SIGURG";
994 case SIGXCPU
: return "SIGXCPU";
997 case SIGXFSZ
: return "SIGXFSZ";
1000 case SIGVTALRM
: return "SIGVTALRM";
1003 case SIGPROF
: return "SIGPROF";
1006 case SIGWINCH
: return "SIGWINCH";
1009 case SIGIO
: return "SIGIO";
1012 case SIGPWR
: return "SIGPWR";
1015 case SIGSYS
: return "SIGSYS";
1020 if (sig
>= SIGRTMIN
&& sig
<= SIGRTMAX
) {
1021 pa_xfree(PA_STATIC_TLS_GET(signame
));
1022 t
= pa_sprintf_malloc("SIGRTMIN+%i", sig
- SIGRTMIN
);
1023 PA_STATIC_TLS_SET(signame
, t
);
1032 pa_xfree(PA_STATIC_TLS_GET(signame
));
1033 t
= pa_sprintf_malloc("SIG%i", sig
);
1034 PA_STATIC_TLS_SET(signame
, t
);
1040 /* Check whether the specified GID and the group name match */
1041 static int is_group(gid_t gid
, const char *name
) {
1042 struct group
*group
= NULL
;
1046 if (!(group
= pa_getgrgid_malloc(gid
)))
1051 pa_log("pa_getgrgid_malloc(%u): %s", gid
, pa_cstrerror(errno
));
1056 r
= strcmp(name
, group
->gr_name
) == 0;
1059 pa_getgrgid_free(group
);
1064 /* Check the current user is member of the specified group */
1065 int pa_own_uid_in_group(const char *name
, gid_t
*gid
) {
1066 GETGROUPS_T
*gids
, tgid
;
1067 long n
= sysconf(_SC_NGROUPS_MAX
);
1072 gids
= pa_xmalloc(sizeof(GETGROUPS_T
) * (size_t) n
);
1074 if ((n
= getgroups((int) n
, gids
)) < 0) {
1075 pa_log("getgroups(): %s", pa_cstrerror(errno
));
1079 for (i
= 0; i
< n
; i
++) {
1081 if ((k
= is_group(gids
[i
], name
)) < 0)
1090 if ((k
= is_group(tgid
= getgid(), name
)) < 0)
1106 /* Check whether the specifc user id is a member of the specified group */
1107 int pa_uid_in_group(uid_t uid
, const char *name
) {
1108 struct group
*group
= NULL
;
1113 if (!(group
= pa_getgrnam_malloc(name
)))
1121 for (i
= group
->gr_mem
; *i
; i
++) {
1122 struct passwd
*pw
= NULL
;
1125 if (!(pw
= pa_getpwnam_malloc(*i
)))
1128 if (pw
->pw_uid
== uid
)
1131 pa_getpwnam_free(pw
);
1138 pa_getgrnam_free(group
);
1143 /* Get the GID of a gfiven group, return (gid_t) -1 on failure. */
1144 gid_t
pa_get_gid_of_group(const char *name
) {
1145 gid_t ret
= (gid_t
) -1;
1146 struct group
*gr
= NULL
;
1149 if (!(gr
= pa_getgrnam_malloc(name
)))
1159 pa_getgrnam_free(gr
);
1163 int pa_check_in_group(gid_t g
) {
1164 gid_t gids
[NGROUPS_MAX
];
1167 if ((r
= getgroups(NGROUPS_MAX
, gids
)) < 0)
1177 #else /* HAVE_GRP_H */
1179 int pa_own_uid_in_group(const char *name
, gid_t
*gid
) {
1185 int pa_uid_in_group(uid_t uid
, const char *name
) {
1190 gid_t
pa_get_gid_of_group(const char *name
) {
1195 int pa_check_in_group(gid_t g
) {
1202 /* Lock or unlock a file entirely.
1203 (advisory on UNIX, mandatory on Windows) */
1204 int pa_lock_fd(int fd
, int b
) {
1206 struct flock f_lock
;
1208 /* Try a R/W lock first */
1210 f_lock
.l_type
= (short) (b
? F_WRLCK
: F_UNLCK
);
1211 f_lock
.l_whence
= SEEK_SET
;
1215 if (fcntl(fd
, F_SETLKW
, &f_lock
) >= 0)
1218 /* Perhaps the file descriptor qas opened for read only, than try again with a read lock. */
1219 if (b
&& errno
== EBADF
) {
1220 f_lock
.l_type
= F_RDLCK
;
1221 if (fcntl(fd
, F_SETLKW
, &f_lock
) >= 0)
1225 pa_log("%slock: %s", !b
? "un" : "", pa_cstrerror(errno
));
1229 HANDLE h
= (HANDLE
)_get_osfhandle(fd
);
1231 if (b
&& LockFile(h
, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF))
1233 if (!b
&& UnlockFile(h
, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF))
1236 pa_log("%slock failed: 0x%08X", !b
? "un" : "", GetLastError());
1238 /* FIXME: Needs to set errno! */
1244 /* Remove trailing newlines from a string */
1245 char* pa_strip_nl(char *s
) {
1248 s
[strcspn(s
, NEWLINE
)] = 0;
1252 char *pa_strip(char *s
) {
1255 /* Drops trailing whitespace. Modifies the string in
1256 * place. Returns pointer to first non-space character */
1258 s
+= strspn(s
, WHITESPACE
);
1260 for (e
= s
; *e
; e
++)
1261 if (!strchr(WHITESPACE
, *e
))
1272 /* Create a temporary lock file and lock it. */
1273 int pa_lock_lockfile(const char *fn
) {
1280 if ((fd
= pa_open_cloexec(fn
, O_CREAT
|O_RDWR
1284 , S_IRUSR
|S_IWUSR
)) < 0) {
1285 pa_log_warn("Failed to create lock file '%s': %s", fn
, pa_cstrerror(errno
));
1289 if (pa_lock_fd(fd
, 1) < 0) {
1290 pa_log_warn("Failed to lock file '%s'.", fn
);
1294 if (fstat(fd
, &st
) < 0) {
1295 pa_log_warn("Failed to fstat() file '%s': %s", fn
, pa_cstrerror(errno
));
1299 /* Check whether the file has been removed meanwhile. When yes,
1300 * restart this loop, otherwise, we're done */
1301 if (st
.st_nlink
>= 1)
1304 if (pa_lock_fd(fd
, 0) < 0) {
1305 pa_log_warn("Failed to unlock file '%s'.", fn
);
1309 if (pa_close(fd
) < 0) {
1310 pa_log_warn("Failed to close file '%s': %s", fn
, pa_cstrerror(errno
));
1321 int saved_errno
= errno
;
1323 errno
= saved_errno
;
1329 /* Unlock a temporary lcok file */
1330 int pa_unlock_lockfile(const char *fn
, int fd
) {
1335 if (unlink(fn
) < 0) {
1336 pa_log_warn("Unable to remove lock file '%s': %s", fn
, pa_cstrerror(errno
));
1341 if (pa_lock_fd(fd
, 0) < 0) {
1342 pa_log_warn("Failed to unlock file '%s'.", fn
);
1346 if (pa_close(fd
) < 0) {
1347 pa_log_warn("Failed to close '%s': %s", fn
, pa_cstrerror(errno
));
1354 static char *get_pulse_home(void) {
1359 if (!(h
= pa_get_home_dir_malloc())) {
1360 pa_log_error("Failed to get home directory.");
1364 if (stat(h
, &st
) < 0) {
1365 pa_log_error("Failed to stat home directory %s: %s", h
, pa_cstrerror(errno
));
1370 if (st
.st_uid
!= getuid()) {
1371 pa_log_error("Home directory %s not ours.", h
);
1377 ret
= pa_sprintf_malloc("%s" PA_PATH_SEP
".pulse", h
);
1385 char *pa_get_state_dir(void) {
1388 /* The state directory shall contain dynamic data that should be
1389 * kept across reboots, and is private to this user */
1391 if (!(d
= pa_xstrdup(getenv("PULSE_STATE_PATH"))))
1392 if (!(d
= get_pulse_home()))
1395 /* If PULSE_STATE_PATH and PULSE_RUNTIME_PATH point to the same
1396 * dir then this will break. */
1398 if (pa_make_secure_dir(d
, 0700U, (uid_t
) -1, (gid_t
) -1) < 0) {
1399 pa_log_error("Failed to create secure directory: %s", pa_cstrerror(errno
));
1407 char *pa_get_home_dir_malloc(void) {
1409 size_t allocated
= 128;
1412 homedir
= pa_xmalloc(allocated
);
1414 if (!pa_get_home_dir(homedir
, allocated
)) {
1419 if (strlen(homedir
) < allocated
- 1)
1429 char *pa_get_binary_name_malloc(void) {
1431 size_t allocated
= 128;
1434 t
= pa_xmalloc(allocated
);
1436 if (!pa_get_binary_name(t
, allocated
)) {
1441 if (strlen(t
) < allocated
- 1)
1451 static char* make_random_dir(mode_t m
) {
1452 static const char table
[] =
1453 "abcdefghijklmnopqrstuvwxyz"
1454 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1460 fn
= pa_sprintf_malloc("%s" PA_PATH_SEP
"pulse-XXXXXXXXXXXX", pa_get_temp_dir());
1461 pathlen
= strlen(fn
);
1469 for (i
= pathlen
- 12; i
< pathlen
; i
++)
1470 fn
[i
] = table
[rand() % (sizeof(table
)-1)];
1472 u
= umask((~m
) & 0777);
1479 saved_errno
= errno
;
1481 errno
= saved_errno
;
1486 if (errno
!= EEXIST
) {
1487 pa_log_error("Failed to create random directory %s: %s", fn
, pa_cstrerror(errno
));
1494 static int make_random_dir_and_link(mode_t m
, const char *k
) {
1497 if (!(p
= make_random_dir(m
)))
1501 if (symlink(p
, k
) < 0) {
1502 int saved_errno
= errno
;
1504 if (errno
!= EEXIST
)
1505 pa_log_error("Failed to symlink %s to %s: %s", k
, p
, pa_cstrerror(errno
));
1510 errno
= saved_errno
;
1522 char *pa_get_runtime_dir(void) {
1523 char *d
, *k
= NULL
, *p
= NULL
, *t
= NULL
, *mid
;
1527 /* The runtime directory shall contain dynamic data that needs NOT
1528 * to be kept accross reboots and is usuallly private to the user,
1529 * except in system mode, where it might be accessible by other
1530 * users, too. Since we need POSIX locking and UNIX sockets in
1531 * this directory, we link it to a random subdir in /tmp, if it
1532 * was not explicitly configured. */
1534 m
= pa_in_system_mode() ? 0755U : 0700U;
1536 if ((d
= getenv("PULSE_RUNTIME_PATH"))) {
1538 if (pa_make_secure_dir(d
, m
, (uid_t
) -1, (gid_t
) -1) < 0) {
1539 pa_log_error("Failed to create secure directory: %s", pa_cstrerror(errno
));
1543 return pa_xstrdup(d
);
1546 if (!(d
= get_pulse_home()))
1549 if (pa_make_secure_dir(d
, m
, (uid_t
) -1, (gid_t
) -1) < 0) {
1550 pa_log_error("Failed to create secure directory: %s", pa_cstrerror(errno
));
1555 if (!(mid
= pa_machine_id())) {
1560 k
= pa_sprintf_malloc("%s" PA_PATH_SEP
"%s-runtime", d
, mid
);
1565 /* OK, first let's check if the "runtime" symlink is already
1568 if (!(p
= pa_readlink(k
))) {
1570 if (errno
!= ENOENT
) {
1571 pa_log_error("Failed to stat runtime directory %s: %s", k
, pa_cstrerror(errno
));
1576 /* Hmm, so the runtime directory didn't exist yet, so let's
1577 * create one in /tmp and symlink that to it */
1579 if (make_random_dir_and_link(0700, k
) < 0) {
1581 /* Mhmm, maybe another process was quicker than us,
1582 * let's check if that was valid */
1583 if (errno
== EEXIST
)
1589 /* No symlink possible, so let's just create the runtime directly */
1597 /* Make sure that this actually makes sense */
1598 if (!pa_is_path_absolute(p
)) {
1599 pa_log_error("Path %s in link %s is not absolute.", p
, k
);
1604 /* Hmm, so this symlink is still around, make sure nobody fools
1608 if (lstat(p
, &st
) < 0) {
1610 if (errno
!= ENOENT
) {
1611 pa_log_error("Failed to stat runtime directory %s: %s", p
, pa_cstrerror(errno
));
1617 if (S_ISDIR(st
.st_mode
) &&
1618 (st
.st_uid
== getuid()) &&
1619 ((st
.st_mode
& 0777) == 0700)) {
1625 pa_log_info("Hmm, runtime path exists, but points to an invalid directory. Changing runtime directory.");
1632 /* Hmm, so the link points to some nonexisting or invalid
1633 * dir. Let's replace it by a new link. We first create a
1634 * temporary link and then rename that to allow concurrent
1635 * execution of this function. */
1637 t
= pa_sprintf_malloc("%s.tmp", k
);
1639 if (make_random_dir_and_link(0700, t
) < 0) {
1641 if (errno
!= EEXIST
) {
1642 pa_log_error("Failed to symlink %s: %s", t
, pa_cstrerror(errno
));
1649 /* Hmm, someone lese was quicker then us. Let's give
1650 * him some time to finish, and retry. */
1655 /* OK, we succeeded in creating the temporary symlink, so
1656 * let's rename it */
1657 if (rename(t
, k
) < 0) {
1658 pa_log_error("Failed to rename %s to %s: %s", t
, k
, pa_cstrerror(errno
));
1674 /* Try to open a configuration file. If "env" is specified, open the
1675 * value of the specified environment variable. Otherwise look for a
1676 * file "local" in the home directory or a file "global" in global
1677 * file system. If "result" is non-NULL, a pointer to a newly
1678 * allocated buffer containing the used configuration file is
1680 FILE *pa_open_config_file(const char *global
, const char *local
, const char *env
, char **result
) {
1685 if (!getenv(PULSE_ROOTENV
))
1689 if (env
&& (fn
= getenv(env
))) {
1693 if (!ExpandEnvironmentStrings(fn
, buf
, PATH_MAX
))
1694 /* FIXME: Needs to set errno! */
1699 if ((f
= pa_fopen_cloexec(fn
, "r"))) {
1701 *result
= pa_xstrdup(fn
);
1706 pa_log_warn("Failed to open configuration file '%s': %s", fn
, pa_cstrerror(errno
));
1716 if ((e
= getenv("PULSE_CONFIG_PATH")))
1717 fn
= lfn
= pa_sprintf_malloc("%s" PA_PATH_SEP
"%s", e
, local
);
1718 else if ((h
= pa_get_home_dir_malloc())) {
1719 fn
= lfn
= pa_sprintf_malloc("%s" PA_PATH_SEP
".pulse" PA_PATH_SEP
"%s", h
, local
);
1725 if (!ExpandEnvironmentStrings(lfn
, buf
, PATH_MAX
)) {
1726 /* FIXME: Needs to set errno! */
1733 if ((f
= pa_fopen_cloexec(fn
, "r"))) {
1735 *result
= pa_xstrdup(fn
);
1741 if (errno
!= ENOENT
) {
1742 pa_log_warn("Failed to open configuration file '%s': %s", fn
, pa_cstrerror(errno
));
1754 if (!ExpandEnvironmentStrings(global
, buf
, PATH_MAX
))
1755 /* FIXME: Needs to set errno! */
1760 if ((f
= pa_fopen_cloexec(global
, "r"))) {
1763 *result
= pa_xstrdup(global
);
1773 char *pa_find_config_file(const char *global
, const char *local
, const char *env
) {
1778 if (!getenv(PULSE_ROOTENV
))
1782 if (env
&& (fn
= getenv(env
))) {
1785 if (!ExpandEnvironmentStrings(fn
, buf
, PATH_MAX
))
1786 /* FIXME: Needs to set errno! */
1791 if (access(fn
, R_OK
) == 0)
1792 return pa_xstrdup(fn
);
1794 pa_log_warn("Failed to access configuration file '%s': %s", fn
, pa_cstrerror(errno
));
1803 if ((e
= getenv("PULSE_CONFIG_PATH")))
1804 fn
= lfn
= pa_sprintf_malloc("%s" PA_PATH_SEP
"%s", e
, local
);
1805 else if ((h
= pa_get_home_dir_malloc())) {
1806 fn
= lfn
= pa_sprintf_malloc("%s" PA_PATH_SEP
".pulse" PA_PATH_SEP
"%s", h
, local
);
1812 if (!ExpandEnvironmentStrings(lfn
, buf
, PATH_MAX
)) {
1813 /* FIXME: Needs to set errno! */
1820 if (access(fn
, R_OK
) == 0) {
1821 char *r
= pa_xstrdup(fn
);
1826 if (errno
!= ENOENT
) {
1827 pa_log_warn("Failed to access configuration file '%s': %s", fn
, pa_cstrerror(errno
));
1837 if (!ExpandEnvironmentStrings(global
, buf
, PATH_MAX
))
1838 /* FIXME: Needs to set errno! */
1843 if (access(global
, R_OK
) == 0)
1844 return pa_xstrdup(global
);
1852 /* Format the specified data as a hexademical string */
1853 char *pa_hexstr(const uint8_t* d
, size_t dlength
, char *s
, size_t slength
) {
1854 size_t i
= 0, j
= 0;
1855 const char hex
[] = "0123456789abcdef";
1859 pa_assert(slength
> 0);
1861 while (i
< dlength
&& j
+3 <= slength
) {
1862 s
[j
++] = hex
[*d
>> 4];
1863 s
[j
++] = hex
[*d
& 0xF];
1869 s
[j
< slength
? j
: slength
] = 0;
1873 /* Convert a hexadecimal digit to a number or -1 if invalid */
1874 static int hexc(char c
) {
1875 if (c
>= '0' && c
<= '9')
1878 if (c
>= 'A' && c
<= 'F')
1879 return c
- 'A' + 10;
1881 if (c
>= 'a' && c
<= 'f')
1882 return c
- 'a' + 10;
1888 /* Parse a hexadecimal string as created by pa_hexstr() to a BLOB */
1889 size_t pa_parsehex(const char *p
, uint8_t *d
, size_t dlength
) {
1895 while (j
< dlength
&& *p
) {
1898 if ((b
= hexc(*(p
++))) < 0)
1901 d
[j
] = (uint8_t) (b
<< 4);
1906 if ((b
= hexc(*(p
++))) < 0)
1909 d
[j
] |= (uint8_t) b
;
1916 /* Returns nonzero when *s starts with *pfx */
1917 pa_bool_t
pa_startswith(const char *s
, const char *pfx
) {
1925 return strlen(s
) >= l
&& strncmp(s
, pfx
, l
) == 0;
1928 /* Returns nonzero when *s ends with *sfx */
1929 pa_bool_t
pa_endswith(const char *s
, const char *sfx
) {
1938 return l1
>= l2
&& strcmp(s
+l1
-l2
, sfx
) == 0;
1941 pa_bool_t
pa_is_path_absolute(const char *fn
) {
1947 return strlen(fn
) >= 3 && isalpha(fn
[0]) && fn
[1] == ':' && fn
[2] == '\\';
1951 char *pa_make_path_absolute(const char *p
) {
1957 if (pa_is_path_absolute(p
))
1958 return pa_xstrdup(p
);
1960 if (!(cwd
= pa_getcwd()))
1961 return pa_xstrdup(p
);
1963 r
= pa_sprintf_malloc("%s" PA_PATH_SEP
"%s", cwd
, p
);
1968 /* if fn is null return the PulseAudio run time path in s (~/.pulse)
1969 * if fn is non-null and starts with / return fn
1970 * otherwise append fn to the run time path and return it */
1971 static char *get_path(const char *fn
, pa_bool_t prependmid
, pa_bool_t rt
) {
1974 rtp
= rt
? pa_get_runtime_dir() : pa_get_state_dir();
1979 if (pa_is_path_absolute(fn
))
1980 return pa_xstrdup(fn
);
1988 if (!(mid
= pa_machine_id())) {
1993 r
= pa_sprintf_malloc("%s" PA_PATH_SEP
"%s-%s", rtp
, mid
, fn
);
1996 r
= pa_sprintf_malloc("%s" PA_PATH_SEP
"%s", rtp
, fn
);
2004 char *pa_runtime_path(const char *fn
) {
2005 return get_path(fn
, FALSE
, TRUE
);
2008 char *pa_state_path(const char *fn
, pa_bool_t appendmid
) {
2009 return get_path(fn
, appendmid
, FALSE
);
2012 /* Convert the string s to a signed integer in *ret_i */
2013 int pa_atoi(const char *s
, int32_t *ret_i
) {
2021 l
= strtol(s
, &x
, 0);
2023 if (!x
|| *x
|| errno
) {
2029 if ((int32_t) l
!= l
) {
2034 *ret_i
= (int32_t) l
;
2039 /* Convert the string s to an unsigned integer in *ret_u */
2040 int pa_atou(const char *s
, uint32_t *ret_u
) {
2048 l
= strtoul(s
, &x
, 0);
2050 if (!x
|| *x
|| errno
) {
2056 if ((uint32_t) l
!= l
) {
2061 *ret_u
= (uint32_t) l
;
2066 #ifdef HAVE_STRTOF_L
2067 static locale_t c_locale
= NULL
;
2069 static void c_locale_destroy(void) {
2070 freelocale(c_locale
);
2074 int pa_atod(const char *s
, double *ret_d
) {
2081 /* This should be locale independent */
2083 #ifdef HAVE_STRTOF_L
2087 if ((c_locale
= newlocale(LC_ALL_MASK
, "C", NULL
)))
2088 atexit(c_locale_destroy
);
2094 f
= strtod_l(s
, &x
, c_locale
);
2102 if (!x
|| *x
|| errno
) {
2113 /* Same as snprintf, but guarantees NUL-termination on every platform */
2114 size_t pa_snprintf(char *str
, size_t size
, const char *format
, ...) {
2119 pa_assert(size
> 0);
2122 va_start(ap
, format
);
2123 ret
= pa_vsnprintf(str
, size
, format
, ap
);
2129 /* Same as vsnprintf, but guarantees NUL-termination on every platform */
2130 size_t pa_vsnprintf(char *str
, size_t size
, const char *format
, va_list ap
) {
2134 pa_assert(size
> 0);
2137 ret
= vsnprintf(str
, size
, format
, ap
);
2144 if ((size_t) ret
> size
-1)
2147 return (size_t) ret
;
2150 /* Truncate the specified string, but guarantee that the string
2151 * returned still validates as UTF8 */
2152 char *pa_truncate_utf8(char *c
, size_t l
) {
2154 pa_assert(pa_utf8_valid(c
));
2161 while (l
> 0 && !pa_utf8_valid(c
))
2167 char *pa_getcwd(void) {
2171 char *p
= pa_xmalloc(l
);
2175 if (errno
!= ERANGE
)
2183 void *pa_will_need(const void *p
, size_t l
) {
2184 #ifdef RLIMIT_MEMLOCK
2195 a
= PA_PAGE_ALIGN_PTR(p
);
2196 size
= (size_t) ((const uint8_t*) p
+ l
- (const uint8_t*) a
);
2198 #ifdef HAVE_POSIX_MADVISE
2199 if ((r
= posix_madvise((void*) a
, size
, POSIX_MADV_WILLNEED
)) == 0) {
2200 pa_log_debug("posix_madvise() worked fine!");
2205 /* Most likely the memory was not mmap()ed from a file and thus
2206 * madvise() didn't work, so let's misuse mlock() do page this
2207 * stuff back into RAM. Yeah, let's fuck with the MM! It's so
2208 * inviting, the man page of mlock() tells us: "All pages that
2209 * contain a part of the specified address range are guaranteed to
2210 * be resident in RAM when the call returns successfully." */
2212 #ifdef RLIMIT_MEMLOCK
2213 pa_assert_se(getrlimit(RLIMIT_MEMLOCK
, &rlim
) == 0);
2215 if (rlim
.rlim_cur
< PA_PAGE_SIZE
) {
2216 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
));
2221 bs
= PA_PAGE_ALIGN((size_t) rlim
.rlim_cur
);
2223 bs
= PA_PAGE_SIZE
*4;
2226 pa_log_debug("posix_madvise() failed (or doesn't exist), trying mlock(): %s", pa_cstrerror(r
));
2229 while (size
> 0 && bs
> 0) {
2234 if (mlock(a
, bs
) < 0) {
2235 bs
= PA_PAGE_ALIGN(bs
/ 2);
2239 pa_assert_se(munlock(a
, bs
) == 0);
2241 a
= (const uint8_t*) a
+ bs
;
2247 pa_log_debug("mlock() failed too (or doesn't exist), giving up: %s", pa_cstrerror(errno
));
2249 pa_log_debug("mlock() worked fine!");
2254 void pa_close_pipe(int fds
[2]) {
2258 pa_assert_se(pa_close(fds
[0]) == 0);
2261 pa_assert_se(pa_close(fds
[1]) == 0);
2263 fds
[0] = fds
[1] = -1;
2266 char *pa_readlink(const char *p
) {
2267 #ifdef HAVE_READLINK
2276 if ((n
= readlink(p
, c
, l
-1)) < 0) {
2281 if ((size_t) n
< l
-1) {
2294 int pa_close_all(int except_fd
, ...) {
2299 va_start(ap
, except_fd
);
2302 for (n
= 1; va_arg(ap
, int) >= 0; n
++)
2307 p
= pa_xnew(int, n
+1);
2309 va_start(ap
, except_fd
);
2312 if (except_fd
>= 0) {
2316 while ((fd
= va_arg(ap
, int)) >= 0)
2323 r
= pa_close_allv(p
);
2329 int pa_close_allv(const int except_fds
[]) {
2338 if ((d
= opendir("/proc/self/fd"))) {
2342 while ((de
= readdir(d
))) {
2348 if (de
->d_name
[0] == '.')
2352 l
= strtol(de
->d_name
, &e
, 10);
2353 if (errno
!= 0 || !e
|| *e
) {
2361 if ((long) fd
!= l
) {
2374 for (i
= 0; except_fds
[i
] >= 0; i
++)
2375 if (except_fds
[i
] == fd
) {
2383 if (pa_close(fd
) < 0) {
2384 saved_errno
= errno
;
2386 errno
= saved_errno
;
2398 if (getrlimit(RLIMIT_NOFILE
, &rl
) >= 0)
2399 maxfd
= (int) rl
.rlim_max
;
2401 maxfd
= sysconf(_SC_OPEN_MAX
);
2403 for (fd
= 3; fd
< maxfd
; fd
++) {
2408 for (i
= 0; except_fds
[i
] >= 0; i
++)
2409 if (except_fds
[i
] == fd
) {
2417 if (pa_close(fd
) < 0 && errno
!= EBADF
)
2420 #endif /* !OS_IS_WIN32 */
2425 int pa_unblock_sigs(int except
, ...) {
2430 va_start(ap
, except
);
2433 for (n
= 1; va_arg(ap
, int) >= 0; n
++)
2438 p
= pa_xnew(int, n
+1);
2440 va_start(ap
, except
);
2447 while ((sig
= va_arg(ap
, int)) >= 0)
2454 r
= pa_unblock_sigsv(p
);
2460 int pa_unblock_sigsv(const int except
[]) {
2465 if (sigemptyset(&ss
) < 0)
2468 for (i
= 0; except
[i
] > 0; i
++)
2469 if (sigaddset(&ss
, except
[i
]) < 0)
2472 return sigprocmask(SIG_SETMASK
, &ss
, NULL
);
2478 int pa_reset_sigs(int except
, ...) {
2483 va_start(ap
, except
);
2486 for (n
= 1; va_arg(ap
, int) >= 0; n
++)
2491 p
= pa_xnew(int, n
+1);
2493 va_start(ap
, except
);
2500 while ((sig
= va_arg(ap
, int)) >= 0)
2507 r
= pa_reset_sigsv(p
);
2513 int pa_reset_sigsv(const int except
[]) {
2517 for (sig
= 1; sig
< NSIG
; sig
++) {
2518 pa_bool_t reset
= TRUE
;
2529 for (i
= 0; except
[i
] > 0; i
++) {
2530 if (sig
== except
[i
]) {
2539 struct sigaction sa
;
2541 memset(&sa
, 0, sizeof(sa
));
2542 sa
.sa_handler
= SIG_DFL
;
2544 /* On Linux the first two RT signals are reserved by
2545 * glibc, and sigaction() will return EINVAL for them. */
2546 if ((sigaction(sig
, &sa
, NULL
) < 0))
2547 if (errno
!= EINVAL
)
2556 void pa_set_env(const char *key
, const char *value
) {
2560 /* This is not thread-safe */
2563 SetEnvironmentVariable(key
, value
);
2565 setenv(key
, value
, 1);
2569 void pa_set_env_and_record(const char *key
, const char *value
) {
2573 /* This is not thread-safe */
2575 pa_set_env(key
, value
);
2576 recorded_env
= pa_strlist_prepend(recorded_env
, key
);
2579 void pa_unset_env_recorded(void) {
2581 /* This is not thread-safe */
2586 recorded_env
= pa_strlist_pop(recorded_env
, &s
);
2592 SetEnvironmentVariable(s
, NULL
);
2600 pa_bool_t
pa_in_system_mode(void) {
2603 if (!(e
= getenv("PULSE_SYSTEM")))
2609 char *pa_get_user_name_malloc(void) {
2613 #ifdef _SC_LOGIN_NAME_MAX
2614 k
= (ssize_t
) sysconf(_SC_LOGIN_NAME_MAX
);
2620 u
= pa_xnew(char, k
+1);
2622 if (!(pa_get_user_name(u
, k
))) {
2630 char *pa_get_host_name_malloc(void) {
2639 if (!pa_get_host_name(c
, l
)) {
2641 if (errno
!= EINVAL
&& errno
!= ENAMETOOLONG
)
2644 } else if (strlen(c
) < l
-1) {
2652 u
= pa_utf8_filter(c
);
2657 /* Hmm, the hostname is as long the space we offered the
2658 * function, we cannot know if it fully fit in, so let's play
2659 * safe and retry. */
2668 char *pa_machine_id(void) {
2672 /* The returned value is supposed be some kind of ascii identifier
2673 * that is unique and stable across reboots. */
2675 /* First we try the D-Bus UUID, which is the best option we have,
2676 * since it fits perfectly our needs and is not as volatile as the
2677 * hostname which might be set from dhcp. */
2679 if ((f
= pa_fopen_cloexec(PA_MACHINE_ID
, "r"))) {
2680 char ln
[34] = "", *r
;
2682 r
= fgets(ln
, sizeof(ln
)-1, f
);
2688 return pa_utf8_filter(ln
);
2691 if ((h
= pa_get_host_name_malloc()))
2695 /* If no hostname was set we use the POSIX hostid. It's usually
2696 * the IPv4 address. Might not be that stable. */
2697 return pa_sprintf_malloc("%08lx", (unsigned long) gethostid
);
2703 char *pa_session_id(void) {
2706 if (!(e
= getenv("XDG_SESSION_COOKIE")))
2709 return pa_utf8_filter(e
);
2712 char *pa_uname_string(void) {
2716 pa_assert_se(uname(&u
) >= 0);
2718 return pa_sprintf_malloc("%s %s %s %s", u
.sysname
, u
.machine
, u
.release
, u
.version
);
2724 i
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFO
);
2725 pa_assert_se(GetVersionEx(&i
));
2727 return pa_sprintf_malloc("Windows %d.%d (%d) %s", i
.dwMajorVersion
, i
.dwMinorVersion
, i
.dwBuildNumber
, i
.szCSDVersion
);
2731 #ifdef HAVE_VALGRIND_MEMCHECK_H
2732 pa_bool_t
pa_in_valgrind(void) {
2735 /* To make heisenbugs a bit simpler to find we check for $VALGRIND
2736 * here instead of really checking whether we run in valgrind or
2740 b
= getenv("VALGRIND") ? 2 : 1;
2746 unsigned pa_gcd(unsigned a
, unsigned b
) {
2757 void pa_reduce(unsigned *num
, unsigned *den
) {
2759 unsigned gcd
= pa_gcd(*num
, *den
);
2767 pa_assert(pa_gcd(*num
, *den
) == 1);
2770 unsigned pa_ncpus(void) {
2773 #ifdef _SC_NPROCESSORS_CONF
2774 ncpus
= sysconf(_SC_NPROCESSORS_CONF
);
2779 return ncpus
<= 0 ? 1 : (unsigned) ncpus
;
2782 char *pa_replace(const char*s
, const char*a
, const char *b
) {
2791 sb
= pa_strbuf_new();
2796 if (!(p
= strstr(s
, a
)))
2799 pa_strbuf_putsn(sb
, s
, p
-s
);
2800 pa_strbuf_puts(sb
, b
);
2804 pa_strbuf_puts(sb
, s
);
2806 return pa_strbuf_tostring_free(sb
);
2809 char *pa_escape(const char *p
, const char *chars
) {
2812 pa_strbuf
*buf
= pa_strbuf_new();
2814 for (s
= p
; *s
; ++s
) {
2816 pa_strbuf_putc(buf
, '\\');
2818 for (c
= chars
; *c
; ++c
) {
2820 pa_strbuf_putc(buf
, '\\');
2825 pa_strbuf_putc(buf
, *s
);
2828 return pa_strbuf_tostring_free(buf
);
2831 char *pa_unescape(char *p
) {
2833 pa_bool_t escaped
= FALSE
;
2835 for (s
= p
, d
= p
; *s
; s
++) {
2836 if (!escaped
&& *s
== '\\') {
2850 char *pa_realpath(const char *path
) {
2854 /* We want only abolsute paths */
2855 if (path
[0] != '/') {
2860 #if defined(__GLIBC__) || defined(__APPLE__)
2864 if (!(r
= realpath(path
, NULL
)))
2867 /* We copy this here in case our pa_xmalloc() is not
2868 * implemented on top of libc malloc() */
2872 #elif defined(PATH_MAX)
2875 path_buf
= pa_xmalloc(PATH_MAX
);
2877 #if defined(OS_IS_WIN32)
2878 if (!(t
= _fullpath(path_buf
, path
, _MAX_PATH
))) {
2883 if (!(t
= realpath(path
, path_buf
))) {
2890 #error "It's not clear whether this system supports realpath(..., NULL) like GNU libc does. If it doesn't we need a private version of realpath() here."
2896 void pa_disable_sigpipe(void) {
2899 struct sigaction sa
;
2903 if (sigaction(SIGPIPE
, NULL
, &sa
) < 0) {
2904 pa_log("sigaction(): %s", pa_cstrerror(errno
));
2908 sa
.sa_handler
= SIG_IGN
;
2910 if (sigaction(SIGPIPE
, &sa
, NULL
) < 0) {
2911 pa_log("sigaction(): %s", pa_cstrerror(errno
));
2917 void pa_xfreev(void**a
) {
2923 for (p
= a
; *p
; p
++)
2929 char **pa_split_spaces_strv(const char *s
) {
2931 unsigned i
= 0, n
= 8;
2932 const char *state
= NULL
;
2934 t
= pa_xnew(char*, n
);
2935 while ((e
= pa_split_spaces(s
, &state
))) {
2940 t
= pa_xrenew(char*, t
, n
);
2953 char* pa_maybe_prefix_path(const char *path
, const char *prefix
) {
2956 if (pa_is_path_absolute(path
))
2957 return pa_xstrdup(path
);
2959 return pa_sprintf_malloc("%s" PA_PATH_SEP
"%s", prefix
, path
);
2962 size_t pa_pipe_buf(int fd
) {
2967 if ((n
= fpathconf(fd
, _PC_PIPE_BUF
)) >= 0)
2978 void pa_reset_personality(void) {
2981 if (personality(PER_LINUX
) < 0)
2982 pa_log_warn("Uh, personality() failed: %s", pa_cstrerror(errno
));
2987 #if defined(__linux__) && !defined(__OPTIMIZE__)
2989 pa_bool_t
pa_run_from_build_tree(void) {
2991 pa_bool_t b
= FALSE
;
2993 /* We abuse __OPTIMIZE__ as a check whether we are a debug build
2996 if ((rp
= pa_readlink("/proc/self/exe"))) {
2997 b
= pa_startswith(rp
, PA_BUILDDIR
);
3006 const char *pa_get_temp_dir(void) {
3009 if ((t
= getenv("TMPDIR")) &&
3010 pa_is_path_absolute(t
))
3013 if ((t
= getenv("TMP")) &&
3014 pa_is_path_absolute(t
))
3017 if ((t
= getenv("TEMP")) &&
3018 pa_is_path_absolute(t
))
3021 if ((t
= getenv("TEMPDIR")) &&
3022 pa_is_path_absolute(t
))
3028 int pa_open_cloexec(const char *fn
, int flags
, mode_t mode
) {
3036 if ((fd
= open(fn
, flags
|O_CLOEXEC
, mode
)) >= 0)
3039 if (errno
!= EINVAL
)
3043 if ((fd
= open(fn
, flags
, mode
)) < 0)
3047 /* Some implementations might simply ignore O_CLOEXEC if it is not
3048 * understood, make sure FD_CLOEXEC is enabled anyway */
3050 pa_make_fd_cloexec(fd
);
3054 int pa_socket_cloexec(int domain
, int type
, int protocol
) {
3058 if ((fd
= socket(domain
, type
| SOCK_CLOEXEC
, protocol
)) >= 0)
3061 if (errno
!= EINVAL
)
3065 if ((fd
= socket(domain
, type
, protocol
)) < 0)
3069 /* Some implementations might simply ignore SOCK_CLOEXEC if it is
3070 * not understood, make sure FD_CLOEXEC is enabled anyway */
3072 pa_make_fd_cloexec(fd
);
3076 int pa_pipe_cloexec(int pipefd
[2]) {
3080 if ((r
= pipe2(pipefd
, O_CLOEXEC
)) >= 0)
3083 if (errno
!= EINVAL
&& errno
!= ENOSYS
)
3088 if ((r
= pipe(pipefd
)) < 0)
3092 pa_make_fd_cloexec(pipefd
[0]);
3093 pa_make_fd_cloexec(pipefd
[1]);
3098 int pa_accept_cloexec(int sockfd
, struct sockaddr
*addr
, socklen_t
*addrlen
) {
3102 if ((fd
= accept4(sockfd
, addr
, addrlen
, SOCK_CLOEXEC
)) >= 0)
3105 if (errno
!= EINVAL
&& errno
!= ENOSYS
)
3110 if ((fd
= accept(sockfd
, addr
, addrlen
)) < 0)
3114 pa_make_fd_cloexec(fd
);
3118 FILE* pa_fopen_cloexec(const char *path
, const char *mode
) {
3122 m
= pa_sprintf_malloc("%se", mode
);
3125 if ((f
= fopen(path
, m
))) {
3132 if (errno
!= EINVAL
)
3135 if (!(f
= fopen(path
, mode
)))
3139 pa_make_fd_cloexec(fileno(f
));
3143 void pa_nullify_stdfds(void) {
3146 pa_close(STDIN_FILENO
);
3147 pa_close(STDOUT_FILENO
);
3148 pa_close(STDERR_FILENO
);
3150 pa_assert_se(open("/dev/null", O_RDONLY
) == STDIN_FILENO
);
3151 pa_assert_se(open("/dev/null", O_WRONLY
) == STDOUT_FILENO
);
3152 pa_assert_se(open("/dev/null", O_WRONLY
) == STDERR_FILENO
);
3159 char *pa_read_line_from_file(const char *fn
) {
3161 char ln
[256] = "", *r
;
3163 if (!(f
= pa_fopen_cloexec(fn
, "r")))
3166 r
= fgets(ln
, sizeof(ln
)-1, f
);
3175 return pa_xstrdup(ln
);
3178 pa_bool_t
pa_running_in_vm(void) {
3180 #if defined(__i386__) || defined(__x86_64__)
3182 /* Both CPUID and DMI are x86 specific interfaces... */
3184 uint32_t eax
= 0x40000000;
3191 const char *const dmi_vendors
[] = {
3192 "/sys/class/dmi/id/sys_vendor",
3193 "/sys/class/dmi/id/board_vendor",
3194 "/sys/class/dmi/id/bios_vendor"
3199 for (i
= 0; i
< PA_ELEMENTSOF(dmi_vendors
); i
++) {
3202 if ((s
= pa_read_line_from_file(dmi_vendors
[i
]))) {
3204 if (pa_startswith(s
, "QEMU") ||
3205 /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
3206 pa_startswith(s
, "VMware") ||
3207 pa_startswith(s
, "VMW") ||
3208 pa_startswith(s
, "Microsoft Corporation") ||
3209 pa_startswith(s
, "innotek GmbH") ||
3210 pa_startswith(s
, "Xen")) {
3222 /* http://lwn.net/Articles/301888/ */
3225 __asm__
__volatile__ (
3226 /* ebx/rbx is being used for PIC! */
3227 " push %%"PA_REG_b
" \n\t"
3229 " mov %%ebx, %1 \n\t"
3230 " pop %%"PA_REG_b
" \n\t"
3232 : "=a" (eax
), "=r" (sig
.sig32
[0]), "=c" (sig
.sig32
[1]), "=d" (sig
.sig32
[2])
3236 if (pa_streq(sig
.text
, "XenVMMXenVMM") ||
3237 pa_streq(sig
.text
, "KVMKVMKVM") ||
3238 /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
3239 pa_streq(sig
.text
, "VMwareVMware") ||
3240 /* http://msdn.microsoft.com/en-us/library/bb969719.aspx */
3241 pa_streq(sig
.text
, "Microsoft Hv"))