• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***
2   This file is part of PulseAudio.
3 
4   Copyright 2004-2006 Lennart Poettering
5   Copyright 2004 Joe Marcus Clarke
6   Copyright 2006-2007 Pierre Ossman <ossman@cendio.se> for Cendio AB
7 
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.
12 
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.
17 
18   You should have received a copy of the GNU Lesser General Public
19   License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
20 ***/
21 
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 
26 #undef LOG_TAG
27 #define LOG_TAG "CoreUtil"
28 
29 #include <math.h>
30 #include <stdarg.h>
31 #include <stdlib.h>
32 #include <signal.h>
33 #include <errno.h>
34 #include <string.h>
35 #include <stdio.h>
36 #include <fcntl.h>
37 #include <unistd.h>
38 #include <limits.h>
39 #include <ctype.h>
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include <dirent.h>
43 
44 #ifdef HAVE_LANGINFO_H
45 #include <langinfo.h>
46 #endif
47 
48 #ifdef HAVE_UNAME
49 #include <sys/utsname.h>
50 #endif
51 
52 #if defined(HAVE_REGEX_H)
53 #include <regex.h>
54 #elif defined(HAVE_PCREPOSIX_H)
55 #include <pcreposix.h>
56 #endif
57 
58 #ifdef HAVE_STRTOD_L
59 #ifdef HAVE_LOCALE_H
60 #include <locale.h>
61 #endif
62 #ifdef HAVE_XLOCALE_H
63 #include <xlocale.h>
64 #endif
65 #endif
66 
67 #ifdef HAVE_SYS_RESOURCE_H
68 #include <sys/resource.h>
69 #endif
70 
71 #ifdef HAVE_SYS_CAPABILITY_H
72 #include <sys/capability.h>
73 #endif
74 
75 #ifdef HAVE_SYS_MMAN_H
76 #include <sys/mman.h>
77 #endif
78 
79 #ifdef HAVE_PTHREAD
80 #include <pthread.h>
81 #endif
82 
83 #ifdef HAVE_NETDB_H
84 #include <netdb.h>
85 #endif
86 
87 #ifdef HAVE_WINDOWS_H
88 #include <windows.h>
89 #include <shlobj.h>
90 #endif
91 
92 #ifndef ENOTSUP
93 #define ENOTSUP   135
94 #endif
95 
96 #ifdef HAVE_PWD_H
97 #include <pwd.h>
98 #endif
99 
100 #ifdef HAVE_GRP_H
101 #include <grp.h>
102 #endif
103 
104 #ifdef HAVE_LIBSAMPLERATE
105 #include <samplerate.h>
106 #endif
107 
108 #ifdef HAVE_DBUS
109 #include <pulsecore/rtkit.h>
110 #endif
111 
112 #if defined(__linux__) && !defined(__ANDROID__)
113 #include <sys/personality.h>
114 #endif
115 
116 #ifdef HAVE_CPUID_H
117 #include <cpuid.h>
118 #endif
119 
120 #include <pulse/xmalloc.h>
121 #include <pulse/util.h>
122 #include <pulse/utf8.h>
123 
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/pipe.h>
133 #include <pulsecore/once.h>
134 #include "log/audio_log.h"
135 
136 #include "core-util.h"
137 
138 /* Not all platforms have this */
139 #ifndef MSG_NOSIGNAL
140 #define MSG_NOSIGNAL 0
141 #endif
142 
143 #define NEWLINE "\r\n"
144 #define WHITESPACE "\n\r \t"
145 
146 static pa_strlist *recorded_env = NULL;
147 
148 #ifdef OS_IS_WIN32
149 static fd_set nonblocking_fds;
150 #endif
151 
152 #ifdef OS_IS_WIN32
153 
154 /* Returns the directory of the current DLL, with '/bin/' removed if it is the last component */
pa_win32_get_toplevel(HANDLE handle)155 char *pa_win32_get_toplevel(HANDLE handle) {
156     static char *toplevel = NULL;
157 
158     if (!toplevel) {
159         char library_path[MAX_PATH];
160         char *p;
161 
162         if (!GetModuleFileName(handle, library_path, MAX_PATH))
163             return NULL;
164 
165         toplevel = pa_xstrdup(library_path);
166 
167         p = strrchr(toplevel, PA_PATH_SEP_CHAR);
168         if (p)
169             *p = '\0';
170 
171         p = strrchr(toplevel, PA_PATH_SEP_CHAR);
172         if (p && pa_streq(p + 1, "bin"))
173             *p = '\0';
174     }
175 
176     return toplevel;
177 }
178 
pa_win32_get_system_appdata()179 char *pa_win32_get_system_appdata() {
180     static char appdata[MAX_PATH] = {0};
181 
182     if (!*appdata && SHGetFolderPathAndSubDirA(NULL, CSIDL_COMMON_APPDATA|CSIDL_FLAG_CREATE, NULL, SHGFP_TYPE_CURRENT, "PulseAudio", appdata) != S_OK)
183         return NULL;
184 
185     return appdata;
186 }
187 
188 #endif
189 
set_nonblock(int fd,bool nonblock)190 static void set_nonblock(int fd, bool nonblock) {
191 
192 #ifdef O_NONBLOCK
193     int v, nv;
194     pa_assert(fd >= 0);
195 
196     pa_assert_se((v = fcntl(fd, F_GETFL)) >= 0);
197 
198     if (nonblock)
199         nv = v | O_NONBLOCK;
200     else
201         nv = v & ~O_NONBLOCK;
202 
203     if (v != nv)
204         pa_assert_se(fcntl(fd, F_SETFL, nv) >= 0);
205 
206 #elif defined(OS_IS_WIN32)
207     u_long arg;
208 
209     if (nonblock)
210         arg = 1;
211     else
212         arg = 0;
213 
214     if (ioctlsocket(fd, FIONBIO, &arg) < 0) {
215         pa_assert_se(WSAGetLastError() == WSAENOTSOCK);
216         pa_log_warn("Only sockets can be made non-blocking!");
217         return;
218     }
219 
220     /* There is no method to query status, so we remember all fds */
221     if (nonblock)
222         FD_SET(fd, &nonblocking_fds);
223     else
224         FD_CLR(fd, &nonblocking_fds);
225 #else
226     pa_log_warn("Non-blocking I/O not supported.!");
227 #endif
228 
229 }
230 
231 /** Make a file descriptor nonblock. Doesn't do any error checking */
pa_make_fd_nonblock(int fd)232 void pa_make_fd_nonblock(int fd) {
233     set_nonblock(fd, true);
234 }
235 
236 /** Make a file descriptor blocking. Doesn't do any error checking */
pa_make_fd_block(int fd)237 void pa_make_fd_block(int fd) {
238     set_nonblock(fd, false);
239 }
240 
241 /** Query if a file descriptor is non-blocking */
pa_is_fd_nonblock(int fd)242 bool pa_is_fd_nonblock(int fd) {
243 
244 #ifdef O_NONBLOCK
245     int v;
246     pa_assert(fd >= 0);
247 
248     pa_assert_se((v = fcntl(fd, F_GETFL)) >= 0);
249 
250     return !!(v & O_NONBLOCK);
251 
252 #elif defined(OS_IS_WIN32)
253     return !!FD_ISSET(fd, &nonblocking_fds);
254 #else
255     return false;
256 #endif
257 
258 }
259 
260 /* Set the FD_CLOEXEC flag for a fd */
pa_make_fd_cloexec(int fd)261 void pa_make_fd_cloexec(int fd) {
262 
263 #ifdef FD_CLOEXEC
264     int v;
265     pa_assert(fd >= 0);
266 
267     pa_assert_se((v = fcntl(fd, F_GETFD, 0)) >= 0);
268 
269     if (!(v & FD_CLOEXEC))
270         pa_assert_se(fcntl(fd, F_SETFD, v|FD_CLOEXEC) >= 0);
271 #endif
272 
273 }
274 
275 /** Creates a directory securely. Will create parent directories recursively if
276  * required. This will not update permissions on parent directories if they
277  * already exist, however. */
pa_make_secure_dir(const char * dir,mode_t m,uid_t uid,gid_t gid,bool update_perms)278 int pa_make_secure_dir(const char* dir, mode_t m, uid_t uid, gid_t gid, bool update_perms) {
279     struct stat st;
280     int r, saved_errno;
281     bool retry = true;
282 
283     pa_assert(dir);
284 
285 again:
286 #ifdef OS_IS_WIN32
287     r = mkdir(dir);
288 #else
289 {
290     mode_t u;
291     u = umask((~m) & 0777);
292     r = mkdir(dir, m);
293     umask(u);
294 }
295 #endif
296 
297     if (r < 0 && errno == ENOENT && retry) {
298         /* If a parent directory in the path doesn't exist, try to create that
299          * first, then try again. */
300         pa_make_secure_parent_dir(dir, m, uid, gid, false);
301         retry = false;
302         goto again;
303     }
304 
305     if (r < 0 && errno != EEXIST)
306         return -1;
307 
308 #if defined(HAVE_FSTAT) && !defined(OS_IS_WIN32)
309 {
310     int fd;
311     if ((fd = open(dir,
312 #ifdef O_CLOEXEC
313                    O_CLOEXEC|
314 #endif
315 #ifdef O_NOCTTY
316                    O_NOCTTY|
317 #endif
318 #ifdef O_NOFOLLOW
319                    O_NOFOLLOW|
320 #endif
321                    O_RDONLY)) < 0)
322         goto fail;
323 
324     if (fstat(fd, &st) < 0) {
325         pa_assert_se(pa_close(fd) >= 0);
326         goto fail;
327     }
328 
329     if (!S_ISDIR(st.st_mode)) {
330         pa_assert_se(pa_close(fd) >= 0);
331         errno = EEXIST;
332         goto fail;
333     }
334 
335     if (!update_perms) {
336         pa_assert_se(pa_close(fd) >= 0);
337         return 0;
338     }
339 
340 #ifdef HAVE_FCHOWN
341     if (uid == (uid_t) -1)
342         uid = getuid();
343     if (gid == (gid_t) -1)
344         gid = getgid();
345     if (((st.st_uid != uid) || (st.st_gid != gid)) && fchown(fd, uid, gid) < 0) {
346         pa_assert_se(pa_close(fd) >= 0);
347         goto fail;
348     }
349 #endif
350 
351 #ifdef HAVE_FCHMOD
352     if ((st.st_mode & 07777) != m && fchmod(fd, m) < 0) {
353         pa_assert_se(pa_close(fd) >= 0);
354         goto fail;
355     };
356 #endif
357 
358     pa_assert_se(pa_close(fd) >= 0);
359 }
360 #else
361     pa_log_warn("Secure directory creation not supported on this platform.");
362 #endif
363 
364     return 0;
365 
366 fail:
367     saved_errno = errno;
368     rmdir(dir);
369     errno = saved_errno;
370 
371     return -1;
372 }
373 
374 /* Return a newly allocated sting containing the parent directory of the specified file */
pa_parent_dir(const char * fn)375 char *pa_parent_dir(const char *fn) {
376     char *slash, *dir = pa_xstrdup(fn);
377 
378     if ((slash = (char*) pa_path_get_filename(dir)) == dir) {
379         pa_xfree(dir);
380         errno = ENOENT;
381         return NULL;
382     }
383 
384     *(slash-1) = 0;
385     return dir;
386 }
387 
388 /* Creates a the parent directory of the specified path securely */
pa_make_secure_parent_dir(const char * fn,mode_t m,uid_t uid,gid_t gid,bool update_perms)389 int pa_make_secure_parent_dir(const char *fn, mode_t m, uid_t uid, gid_t gid, bool update_perms) {
390     int ret = -1;
391     char *dir;
392 
393     if (!(dir = pa_parent_dir(fn)))
394         goto finish;
395 
396     if (pa_make_secure_dir(dir, m, uid, gid, update_perms) < 0)
397         goto finish;
398 
399     ret = 0;
400 
401 finish:
402     pa_xfree(dir);
403     return ret;
404 }
405 
406 /** Platform independent read function. Necessary since not all
407  * systems treat all file descriptors equal. If type is
408  * non-NULL it is used to cache the type of the fd. This is
409  * useful for making sure that only a single syscall is executed per
410  * function call. The variable pointed to should be initialized to 0
411  * by the caller. */
pa_read(int fd,void * buf,size_t count,int * type)412 ssize_t pa_read(int fd, void *buf, size_t count, int *type) {
413 
414 #ifdef OS_IS_WIN32
415 
416     if (!type || *type == 0) {
417         ssize_t r;
418 
419         if ((r = recv(fd, buf, count, 0)) >= 0)
420             return r;
421 
422         if (WSAGetLastError() != WSAENOTSOCK) {
423             errno = WSAGetLastError();
424             if (errno == WSAEWOULDBLOCK)
425                 errno = EAGAIN;
426             return r;
427         }
428 
429         if (type)
430             *type = 1;
431     }
432 
433 #endif
434 
435     for (;;) {
436         ssize_t r;
437 
438         if ((r = read(fd, buf, count)) < 0)
439             if (errno == EINTR)
440                 continue;
441 
442         return r;
443     }
444 }
445 
446 /** Similar to pa_read(), but handles writes */
pa_write(int fd,const void * buf,size_t count,int * type)447 ssize_t pa_write(int fd, const void *buf, size_t count, int *type) {
448 
449     if (!type || *type == 0) {
450         ssize_t r;
451 
452         for (;;) {
453             if ((r = send(fd, buf, count, MSG_NOSIGNAL)) < 0) {
454 
455                 if (errno == EINTR)
456                     continue;
457 
458                 break;
459             }
460 
461             return r;
462         }
463 
464 #ifdef OS_IS_WIN32
465         if (WSAGetLastError() != WSAENOTSOCK) {
466             errno = WSAGetLastError();
467             if (errno == WSAEWOULDBLOCK)
468                 errno = EAGAIN;
469             return r;
470         }
471 #else
472         if (errno != ENOTSOCK)
473             return r;
474 #endif
475 
476         if (type)
477             *type = 1;
478     }
479 
480     for (;;) {
481         ssize_t r;
482 
483         if ((r = write(fd, buf, count)) < 0)
484             if (errno == EINTR)
485                 continue;
486 
487         return r;
488     }
489 }
490 
491 /** Calls read() in a loop. Makes sure that as much as 'size' bytes,
492  * unless EOF is reached or an error occurred */
pa_loop_read(int fd,void * data,size_t size,int * type)493 ssize_t pa_loop_read(int fd, void*data, size_t size, int *type) {
494     ssize_t ret = 0;
495     int _type;
496 
497     pa_assert(fd >= 0);
498     pa_assert(data);
499     pa_assert(size);
500 
501     if (!type) {
502         _type = 0;
503         type = &_type;
504     }
505 
506     while (size > 0) {
507         ssize_t r;
508 
509         if ((r = pa_read(fd, data, size, type)) < 0)
510             return r;
511 
512         if (r == 0)
513             break;
514 
515         ret += r;
516         data = (uint8_t*) data + r;
517         size -= (size_t) r;
518     }
519 
520     return ret;
521 }
522 
523 /** Similar to pa_loop_read(), but wraps write() */
pa_loop_write(int fd,const void * data,size_t size,int * type)524 ssize_t pa_loop_write(int fd, const void*data, size_t size, int *type) {
525     ssize_t ret = 0;
526     int _type;
527 
528     pa_assert(fd >= 0);
529     pa_assert(data);
530     pa_assert(size);
531 
532     if (!type) {
533         _type = 0;
534         type = &_type;
535     }
536 
537     while (size > 0) {
538         ssize_t r;
539 
540         if ((r = pa_write(fd, data, size, type)) < 0)
541             return r;
542 
543         if (r == 0)
544             break;
545 
546         ret += r;
547         data = (const uint8_t*) data + r;
548         size -= (size_t) r;
549     }
550 
551     return ret;
552 }
553 
554 /** Platform independent close function. Necessary since not all
555  * systems treat all file descriptors equal. */
pa_close(int fd)556 int pa_close(int fd) {
557 
558 #ifdef OS_IS_WIN32
559     int ret;
560 
561     FD_CLR(fd, &nonblocking_fds);
562 
563     if ((ret = closesocket(fd)) == 0)
564         return 0;
565 
566     if (WSAGetLastError() != WSAENOTSOCK) {
567         errno = WSAGetLastError();
568         return ret;
569     }
570 #endif
571 
572     for (;;) {
573         int r;
574 
575         if ((r = close(fd)) < 0) {
576             if (errno == EINTR)
577                 continue;
578             AUDIO_ERR_LOG("Close fd failed, err code: %{public}d", r);
579         }
580         return r;
581     }
582 }
583 
584 /* Print a warning messages in case that the given signal is not
585  * blocked or trapped */
pa_check_signal_is_blocked(int sig)586 void pa_check_signal_is_blocked(int sig) {
587 #ifdef HAVE_SIGACTION
588     struct sigaction sa;
589     sigset_t set;
590 
591     /* If POSIX threads are supported use thread-aware
592      * pthread_sigmask() function, to check if the signal is
593      * blocked. Otherwise fall back to sigprocmask() */
594 
595 #ifdef HAVE_PTHREAD
596     if (pthread_sigmask(SIG_SETMASK, NULL, &set) < 0) {
597 #endif
598         if (sigprocmask(SIG_SETMASK, NULL, &set) < 0) {
599             pa_log("sigprocmask(): %s", pa_cstrerror(errno));
600             return;
601         }
602 #ifdef HAVE_PTHREAD
603     }
604 #endif
605 
606     if (sigismember(&set, sig))
607         return;
608 
609     /* Check whether the signal is trapped */
610 
611     if (sigaction(sig, NULL, &sa) < 0) {
612         pa_log("sigaction(): %s", pa_cstrerror(errno));
613         return;
614     }
615 
616     if (sa.sa_handler != SIG_DFL)
617         return;
618 
619     pa_log_warn("%s is not trapped. This might cause malfunction!", pa_sig2str(sig));
620 #else /* HAVE_SIGACTION */
621     pa_log_warn("%s might not be trapped. This might cause malfunction!", pa_sig2str(sig));
622 #endif
623 }
624 
625 /* The following function is based on an example from the GNU libc
626  * documentation. This function is similar to GNU's asprintf(). */
pa_sprintf_malloc(const char * format,...)627 char *pa_sprintf_malloc(const char *format, ...) {
628     size_t size = 100;
629     char *c = NULL;
630 
631     pa_assert(format);
632 
633     for(;;) {
634         int r;
635         va_list ap;
636 
637         c = pa_xrealloc(c, size);
638 
639         va_start(ap, format);
640         r = vsnprintf(c, size, format, ap);
641         va_end(ap);
642 
643         c[size-1] = 0;
644 
645         if (r > -1 && (size_t) r < size)
646             return c;
647 
648         if (r > -1)    /* glibc 2.1 */
649             size = (size_t) r+1;
650         else           /* glibc 2.0 */
651             size *= 2;
652     }
653 }
654 
655 /* Same as the previous function, but use a va_list instead of an
656  * ellipsis */
pa_vsprintf_malloc(const char * format,va_list ap)657 char *pa_vsprintf_malloc(const char *format, va_list ap) {
658     size_t size = 100;
659     char *c = NULL;
660 
661     pa_assert(format);
662 
663     for(;;) {
664         int r;
665         va_list aq;
666 
667         c = pa_xrealloc(c, size);
668 
669         va_copy(aq, ap);
670         r = vsnprintf(c, size, format, aq);
671         va_end(aq);
672 
673         c[size-1] = 0;
674 
675         if (r > -1 && (size_t) r < size)
676             return c;
677 
678         if (r > -1)    /* glibc 2.1 */
679             size = (size_t) r+1;
680         else           /* glibc 2.0 */
681             size *= 2;
682     }
683 }
684 
685 /* Similar to OpenBSD's strlcpy() function */
pa_strlcpy(char * b,const char * s,size_t l)686 char *pa_strlcpy(char *b, const char *s, size_t l) {
687     size_t k;
688 
689     pa_assert(b);
690     pa_assert(s);
691     pa_assert(l > 0);
692 
693     k = strlen(s);
694 
695     if (k > l-1)
696         k = l-1;
697 
698     memcpy(b, s, k);
699     b[k] = 0;
700 
701     return b;
702 }
703 
704 #ifdef HAVE_SYS_RESOURCE_H
set_nice(int nice_level)705 static int set_nice(int nice_level) {
706 #ifdef HAVE_DBUS
707     DBusError error;
708     DBusConnection *bus;
709     int r;
710 
711     dbus_error_init(&error);
712 #endif
713 
714 #ifdef HAVE_SYS_RESOURCE_H
715     if (setpriority(PRIO_PROCESS, 0, nice_level) >= 0) {
716         pa_log_debug("setpriority() worked.");
717         return 0;
718     }
719 #endif
720 
721 #ifdef HAVE_DBUS
722     /* Try to talk to RealtimeKit */
723 
724     if (!(bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error))) {
725         pa_log("Failed to connect to system bus: %s", error.message);
726         dbus_error_free(&error);
727         errno = -EIO;
728         return -1;
729     }
730 
731     /* We need to disable exit on disconnect because otherwise
732      * dbus_shutdown will kill us. See
733      * https://bugs.freedesktop.org/show_bug.cgi?id=16924 */
734     dbus_connection_set_exit_on_disconnect(bus, FALSE);
735 
736     r = rtkit_make_high_priority(bus, 0, nice_level);
737     dbus_connection_close(bus);
738     dbus_connection_unref(bus);
739 
740     if (r >= 0) {
741         pa_log_debug("RealtimeKit worked.");
742         return 0;
743     }
744 
745     errno = -r;
746 #endif
747 
748     return -1;
749 }
750 #endif
751 
752 /* Raise the priority of the current process as much as possible that
753  * is <= the specified nice level..*/
pa_raise_priority(int nice_level)754 int pa_raise_priority(int nice_level) {
755 
756 #ifdef HAVE_SYS_RESOURCE_H
757     int n;
758 
759     if (set_nice(nice_level) >= 0) {
760         pa_log_info("Successfully gained nice level %i.", nice_level);
761         return 0;
762     }
763 
764     for (n = nice_level+1; n < 0; n++)
765         if (set_nice(n) >= 0) {
766             pa_log_info("Successfully acquired nice level %i, which is lower than the requested %i.", n, nice_level);
767             return 0;
768         }
769 
770     pa_log_info("Failed to acquire high-priority scheduling: %s", pa_cstrerror(errno));
771     return -1;
772 #endif
773 
774 #ifdef OS_IS_WIN32
775     if (nice_level < 0) {
776         if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS)) {
777             pa_log_warn("SetPriorityClass() failed: 0x%08lX", GetLastError());
778             errno = EPERM;
779             return -1;
780         }
781 
782         pa_log_info("Successfully gained high priority class.");
783     }
784 #endif
785 
786     return 0;
787 }
788 
789 /* Reset the priority to normal, inverting the changes made by
790  * pa_raise_priority() and pa_thread_make_realtime()*/
pa_reset_priority(void)791 void pa_reset_priority(void) {
792 #ifdef HAVE_SYS_RESOURCE_H
793     struct sched_param sp;
794 
795     setpriority(PRIO_PROCESS, 0, 0);
796 
797     pa_zero(sp);
798     pthread_setschedparam(pthread_self(), SCHED_OTHER, &sp);
799 #endif
800 
801 #ifdef OS_IS_WIN32
802     SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS);
803 #endif
804 }
805 
806 /* Check whenever any substring in v matches the provided regex. */
pa_match(const char * expr,const char * v)807 int pa_match(const char *expr, const char *v) {
808 #if defined(HAVE_REGEX_H) || defined(HAVE_PCREPOSIX_H)
809     int k;
810     regex_t re;
811     int r;
812 
813     pa_assert(expr);
814     pa_assert(v);
815 
816     if (regcomp(&re, expr, REG_NOSUB|REG_EXTENDED) != 0) {
817         errno = EINVAL;
818         return -1;
819     }
820 
821     if ((k = regexec(&re, v, 0, NULL, 0)) == 0)
822         r = 1;
823     else if (k == REG_NOMATCH)
824         r = 0;
825     else
826         r = -1;
827 
828     regfree(&re);
829 
830     if (r < 0)
831         errno = EINVAL;
832 
833     return r;
834 #else
835     errno = ENOSYS;
836     return -1;
837 #endif
838 }
839 
840 /* Check whenever the provided regex pattern is valid. */
pa_is_regex_valid(const char * expr)841 bool pa_is_regex_valid(const char *expr) {
842 #if defined(HAVE_REGEX_H) || defined(HAVE_PCREPOSIX_H)
843     regex_t re;
844 
845     if (expr == NULL || regcomp(&re, expr, REG_NOSUB|REG_EXTENDED) != 0) {
846         return false;
847     }
848 
849     regfree(&re);
850     return true;
851 #else
852     return false;
853 #endif
854 }
855 
856 /* Try to parse a boolean string value.*/
pa_parse_boolean(const char * v)857 int pa_parse_boolean(const char *v) {
858     pa_assert(v);
859 
860     /* First we check language independent */
861     if (pa_streq(v, "1") || !strcasecmp(v, "y") || !strcasecmp(v, "t")
862             || !strcasecmp(v, "yes") || !strcasecmp(v, "true") || !strcasecmp(v, "on"))
863         return 1;
864     else if (pa_streq(v, "0") || !strcasecmp(v, "n") || !strcasecmp(v, "f")
865                  || !strcasecmp(v, "no") || !strcasecmp(v, "false") || !strcasecmp(v, "off"))
866         return 0;
867 
868 #ifdef HAVE_LANGINFO_H
869 {
870     const char *expr;
871     /* And then we check language dependent */
872     if ((expr = nl_langinfo(YESEXPR)))
873         if (expr[0])
874             if (pa_match(expr, v) > 0)
875                 return 1;
876 
877     if ((expr = nl_langinfo(NOEXPR)))
878         if (expr[0])
879             if (pa_match(expr, v) > 0)
880                 return 0;
881 }
882 #endif
883 
884     errno = EINVAL;
885     return -1;
886 }
887 
888 /* Try to parse a volume string to pa_volume_t. The allowed formats are:
889  * db, % and unsigned integer */
pa_parse_volume(const char * v,pa_volume_t * volume)890 int pa_parse_volume(const char *v, pa_volume_t *volume) {
891     int len;
892     uint32_t i;
893     double d;
894     char str[64];
895 
896     pa_assert(v);
897     pa_assert(volume);
898 
899     len = strlen(v);
900 
901     if (len <= 0 || len >= 64)
902         return -1;
903 
904     memcpy(str, v, len + 1);
905 
906     if (str[len - 1] == '%') {
907         str[len - 1] = '\0';
908         if (pa_atod(str, &d) < 0)
909             return -1;
910 
911         d = d / 100 * PA_VOLUME_NORM;
912 
913         if (d < 0 || d > PA_VOLUME_MAX)
914             return -1;
915 
916         *volume = d;
917         return 0;
918     }
919 
920     if (len > 2 && (str[len - 1] == 'b' || str[len - 1] == 'B') &&
921                (str[len - 2] == 'd' || str[len - 2] == 'D')) {
922         str[len - 2] = '\0';
923         if (pa_atod(str, &d) < 0)
924             return -1;
925 
926         if (d > pa_sw_volume_to_dB(PA_VOLUME_MAX))
927             return -1;
928 
929         *volume = pa_sw_volume_from_dB(d);
930         return 0;
931     }
932 
933     if (pa_atou(v, &i) < 0 || !PA_VOLUME_IS_VALID(i))
934         return -1;
935 
936     *volume = i;
937     return 0;
938 }
939 
940 /* Split the specified string wherever one of the characters in delimiter
941  * occurs. Each time it is called returns a newly allocated string
942  * with pa_xmalloc(). The variable state points to, should be
943  * initialized to NULL before the first call. */
pa_split(const char * c,const char * delimiter,const char ** state)944 char *pa_split(const char *c, const char *delimiter, const char**state) {
945     const char *current = *state ? *state : c;
946     size_t l;
947 
948     if (!*current)
949         return NULL;
950 
951     l = strcspn(current, delimiter);
952     *state = current+l;
953 
954     if (**state)
955         (*state)++;
956 
957     return pa_xstrndup(current, l);
958 }
959 
960 /* Split the specified string wherever one of the characters in delimiter
961  * occurs. Each time it is called returns a pointer to the substring within the
962  * string and the length in 'n'. Note that the resultant string cannot be used
963  * as-is without the length parameter, since it is merely pointing to a point
964  * within the original string. The variable state points to, should be
965  * initialized to NULL before the first call. */
pa_split_in_place(const char * c,const char * delimiter,size_t * n,const char ** state)966 const char *pa_split_in_place(const char *c, const char *delimiter, size_t *n, const char**state) {
967     const char *current = *state ? *state : c;
968     size_t l;
969 
970     if (!*current)
971         return NULL;
972 
973     l = strcspn(current, delimiter);
974     *state = current+l;
975 
976     if (**state)
977         (*state)++;
978 
979     *n = l;
980     return current;
981 }
982 
983 /* Split a string into words. Otherwise similar to pa_split(). */
pa_split_spaces(const char * c,const char ** state)984 char *pa_split_spaces(const char *c, const char **state) {
985     const char *current = *state ? *state : c;
986     size_t l;
987 
988     if (!*current || *c == 0)
989         return NULL;
990 
991     current += strspn(current, WHITESPACE);
992     l = strcspn(current, WHITESPACE);
993 
994     *state = current+l;
995 
996     return pa_xstrndup(current, l);
997 }
998 
999 /* Similar to pa_split_spaces, except this returns a string in-place.
1000    Returned string is generally not NULL-terminated.
1001    See pa_split_in_place(). */
pa_split_spaces_in_place(const char * c,size_t * n,const char ** state)1002 const char *pa_split_spaces_in_place(const char *c, size_t *n, const char **state) {
1003     const char *current = *state ? *state : c;
1004     size_t l;
1005 
1006     if (!*current || *c == 0)
1007         return NULL;
1008 
1009     current += strspn(current, WHITESPACE);
1010     l = strcspn(current, WHITESPACE);
1011 
1012     *state = current+l;
1013 
1014     *n = l;
1015     return current;
1016 }
1017 
1018 PA_STATIC_TLS_DECLARE(signame, pa_xfree);
1019 
1020 /* Return the name of an UNIX signal. Similar to Solaris sig2str() */
pa_sig2str(int sig)1021 const char *pa_sig2str(int sig) {
1022     char *t;
1023 
1024     if (sig <= 0)
1025         goto fail;
1026 
1027 #ifdef NSIG
1028     if (sig >= NSIG)
1029         goto fail;
1030 #endif
1031 
1032 #ifdef HAVE_SIG2STR
1033     {
1034         char buf[SIG2STR_MAX];
1035 
1036         if (sig2str(sig, buf) == 0) {
1037             pa_xfree(PA_STATIC_TLS_GET(signame));
1038             t = pa_sprintf_malloc("SIG%s", buf);
1039             PA_STATIC_TLS_SET(signame, t);
1040             return t;
1041         }
1042     }
1043 #else
1044 
1045     switch (sig) {
1046 #ifdef SIGHUP
1047         case SIGHUP:    return "SIGHUP";
1048 #endif
1049         case SIGINT:    return "SIGINT";
1050 #ifdef SIGQUIT
1051         case SIGQUIT:   return "SIGQUIT";
1052 #endif
1053         case SIGILL:    return "SIGULL";
1054 #ifdef SIGTRAP
1055         case SIGTRAP:   return "SIGTRAP";
1056 #endif
1057         case SIGABRT:   return "SIGABRT";
1058 #ifdef SIGBUS
1059         case SIGBUS:    return "SIGBUS";
1060 #endif
1061         case SIGFPE:    return "SIGFPE";
1062 #ifdef SIGKILL
1063         case SIGKILL:   return "SIGKILL";
1064 #endif
1065 #ifdef SIGUSR1
1066         case SIGUSR1:   return "SIGUSR1";
1067 #endif
1068         case SIGSEGV:   return "SIGSEGV";
1069 #ifdef SIGUSR2
1070         case SIGUSR2:   return "SIGUSR2";
1071 #endif
1072 #ifdef SIGPIPE
1073         case SIGPIPE:   return "SIGPIPE";
1074 #endif
1075 #ifdef SIGALRM
1076         case SIGALRM:   return "SIGALRM";
1077 #endif
1078         case SIGTERM:   return "SIGTERM";
1079 #ifdef SIGSTKFLT
1080         case SIGSTKFLT: return "SIGSTKFLT";
1081 #endif
1082 #ifdef SIGCHLD
1083         case SIGCHLD:   return "SIGCHLD";
1084 #endif
1085 #ifdef SIGCONT
1086         case SIGCONT:   return "SIGCONT";
1087 #endif
1088 #ifdef SIGSTOP
1089         case SIGSTOP:   return "SIGSTOP";
1090 #endif
1091 #ifdef SIGTSTP
1092         case SIGTSTP:   return "SIGTSTP";
1093 #endif
1094 #ifdef SIGTTIN
1095         case SIGTTIN:   return "SIGTTIN";
1096 #endif
1097 #ifdef SIGTTOU
1098         case SIGTTOU:   return "SIGTTOU";
1099 #endif
1100 #ifdef SIGURG
1101         case SIGURG:    return "SIGURG";
1102 #endif
1103 #ifdef SIGXCPU
1104         case SIGXCPU:   return "SIGXCPU";
1105 #endif
1106 #ifdef SIGXFSZ
1107         case SIGXFSZ:   return "SIGXFSZ";
1108 #endif
1109 #ifdef SIGVTALRM
1110         case SIGVTALRM: return "SIGVTALRM";
1111 #endif
1112 #ifdef SIGPROF
1113         case SIGPROF:   return "SIGPROF";
1114 #endif
1115 #ifdef SIGWINCH
1116         case SIGWINCH:  return "SIGWINCH";
1117 #endif
1118 #ifdef SIGIO
1119         case SIGIO:     return "SIGIO";
1120 #endif
1121 #ifdef SIGPWR
1122         case SIGPWR:    return "SIGPWR";
1123 #endif
1124 #ifdef SIGSYS
1125         case SIGSYS:    return "SIGSYS";
1126 #endif
1127     }
1128 
1129 #ifdef SIGRTMIN
1130     if (sig >= SIGRTMIN && sig <= SIGRTMAX) {
1131         pa_xfree(PA_STATIC_TLS_GET(signame));
1132         t = pa_sprintf_malloc("SIGRTMIN+%i", sig - SIGRTMIN);
1133         PA_STATIC_TLS_SET(signame, t);
1134         return t;
1135     }
1136 #endif
1137 
1138 #endif
1139 
1140 fail:
1141 
1142     pa_xfree(PA_STATIC_TLS_GET(signame));
1143     t = pa_sprintf_malloc("SIG%i", sig);
1144     PA_STATIC_TLS_SET(signame, t);
1145     return t;
1146 }
1147 
1148 #ifdef HAVE_GRP_H
1149 
1150 /* Check whether the specified GID and the group name match */
is_group(gid_t gid,const char * name)1151 static int is_group(gid_t gid, const char *name) {
1152     struct group *group = NULL;
1153     int r = -1;
1154 
1155     errno = 0;
1156     if (!(group = pa_getgrgid_malloc(gid))) {
1157         if (!errno)
1158             errno = ENOENT;
1159 
1160         pa_log("pa_getgrgid_malloc(%u): %s", gid, pa_cstrerror(errno));
1161 
1162         goto finish;
1163     }
1164 
1165     r = pa_streq(name, group->gr_name);
1166 
1167 finish:
1168     pa_getgrgid_free(group);
1169 
1170     return r;
1171 }
1172 
1173 /* Check the current user is member of the specified group */
pa_own_uid_in_group(const char * name,gid_t * gid)1174 int pa_own_uid_in_group(const char *name, gid_t *gid) {
1175     GETGROUPS_T *gids, tgid;
1176     long n = sysconf(_SC_NGROUPS_MAX);
1177     int r = -1, i, k;
1178 
1179     pa_assert(n > 0);
1180 
1181     gids = pa_xmalloc(sizeof(GETGROUPS_T) * (size_t) n);
1182 
1183     if ((n = getgroups((int) n, gids)) < 0) {
1184         pa_log("getgroups(): %s", pa_cstrerror(errno));
1185         goto finish;
1186     }
1187 
1188     for (i = 0; i < n; i++) {
1189 
1190         if ((k = is_group(gids[i], name)) < 0)
1191             goto finish;
1192         else if (k > 0) {
1193             *gid = gids[i];
1194             r = 1;
1195             goto finish;
1196         }
1197     }
1198 
1199     if ((k = is_group(tgid = getgid(), name)) < 0)
1200         goto finish;
1201     else if (k > 0) {
1202         *gid = tgid;
1203         r = 1;
1204         goto finish;
1205     }
1206 
1207     r = 0;
1208 
1209 finish:
1210 
1211     pa_xfree(gids);
1212     return r;
1213 }
1214 
1215 /* Check whether the specific user id is a member of the specified group */
pa_uid_in_group(uid_t uid,const char * name)1216 int pa_uid_in_group(uid_t uid, const char *name) {
1217     struct group *group = NULL;
1218     char **i;
1219     int r = -1;
1220 
1221     errno = 0;
1222     if (!(group = pa_getgrnam_malloc(name))) {
1223         if (!errno)
1224             errno = ENOENT;
1225         goto finish;
1226     }
1227 
1228     r = 0;
1229     for (i = group->gr_mem; *i; i++) {
1230         struct passwd *pw = NULL;
1231 
1232         errno = 0;
1233         if (!(pw = pa_getpwnam_malloc(*i)))
1234             continue;
1235 
1236         if (pw->pw_uid == uid)
1237             r = 1;
1238 
1239         pa_getpwnam_free(pw);
1240 
1241         if (r == 1)
1242             break;
1243     }
1244 
1245 finish:
1246     pa_getgrnam_free(group);
1247 
1248     return r;
1249 }
1250 
1251 /* Get the GID of a given group, return (gid_t) -1 on failure. */
pa_get_gid_of_group(const char * name)1252 gid_t pa_get_gid_of_group(const char *name) {
1253     gid_t ret = (gid_t) -1;
1254     struct group *gr = NULL;
1255 
1256     errno = 0;
1257     if (!(gr = pa_getgrnam_malloc(name))) {
1258         if (!errno)
1259             errno = ENOENT;
1260         goto finish;
1261     }
1262 
1263     ret = gr->gr_gid;
1264 
1265 finish:
1266     pa_getgrnam_free(gr);
1267     return ret;
1268 }
1269 
pa_check_in_group(gid_t g)1270 int pa_check_in_group(gid_t g) {
1271     gid_t gids[NGROUPS_MAX];
1272     int r;
1273 
1274     if ((r = getgroups(NGROUPS_MAX, gids)) < 0)
1275         return -1;
1276 
1277     for (; r > 0; r--)
1278         if (gids[r-1] == g)
1279             return 1;
1280 
1281     return 0;
1282 }
1283 
1284 #else /* HAVE_GRP_H */
1285 
pa_own_uid_in_group(const char * name,gid_t * gid)1286 int pa_own_uid_in_group(const char *name, gid_t *gid) {
1287     errno = ENOTSUP;
1288     return -1;
1289 
1290 }
1291 
pa_uid_in_group(uid_t uid,const char * name)1292 int pa_uid_in_group(uid_t uid, const char *name) {
1293     errno = ENOTSUP;
1294     return -1;
1295 }
1296 
pa_get_gid_of_group(const char * name)1297 gid_t pa_get_gid_of_group(const char *name) {
1298     errno = ENOTSUP;
1299     return (gid_t) -1;
1300 }
1301 
pa_check_in_group(gid_t g)1302 int pa_check_in_group(gid_t g) {
1303     errno = ENOTSUP;
1304     return -1;
1305 }
1306 
1307 #endif
1308 
1309 /* Lock or unlock a file entirely.
1310   (advisory on UNIX, mandatory on Windows) */
pa_lock_fd(int fd,int b)1311 int pa_lock_fd(int fd, int b) {
1312 #ifdef F_SETLKW
1313     struct flock f_lock;
1314 
1315     /* Try a R/W lock first */
1316 
1317     f_lock.l_type = (short) (b ? F_WRLCK : F_UNLCK);
1318     f_lock.l_whence = SEEK_SET;
1319     f_lock.l_start = 0;
1320     f_lock.l_len = 0;
1321 
1322     if (fcntl(fd, F_SETLKW, &f_lock) >= 0)
1323         return 0;
1324 
1325     /* Perhaps the file descriptor was opened for read only, than try again with a read lock. */
1326     if (b && errno == EBADF) {
1327         f_lock.l_type = F_RDLCK;
1328         if (fcntl(fd, F_SETLKW, &f_lock) >= 0)
1329             return 0;
1330     }
1331 
1332     pa_log("%slock: %s", !b ? "un" : "", pa_cstrerror(errno));
1333 #endif
1334 
1335 #ifdef OS_IS_WIN32
1336     HANDLE h = (HANDLE) _get_osfhandle(fd);
1337 
1338     if (b && LockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF))
1339         return 0;
1340     if (!b && UnlockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF))
1341         return 0;
1342 
1343     pa_log("%slock failed: 0x%08lX", !b ? "un" : "", GetLastError());
1344 
1345     /* FIXME: Needs to set errno! */
1346 #endif
1347 
1348     return -1;
1349 }
1350 
1351 /* Remove trailing newlines from a string */
pa_strip_nl(char * s)1352 char* pa_strip_nl(char *s) {
1353     pa_assert(s);
1354 
1355     s[strcspn(s, NEWLINE)] = 0;
1356     return s;
1357 }
1358 
pa_strip(char * s)1359 char *pa_strip(char *s) {
1360     char *e, *l = NULL;
1361 
1362     /* Drops trailing whitespace. Modifies the string in
1363      * place. Returns pointer to first non-space character */
1364 
1365     s += strspn(s, WHITESPACE);
1366 
1367     for (e = s; *e; e++)
1368         if (!strchr(WHITESPACE, *e))
1369             l = e;
1370 
1371     if (l)
1372         *(l+1) = 0;
1373     else
1374         *s = 0;
1375 
1376     return s;
1377 }
1378 
1379 /* Create a temporary lock file and lock it. */
pa_lock_lockfile(const char * fn)1380 int pa_lock_lockfile(const char *fn) {
1381     int fd;
1382     pa_assert(fn);
1383 
1384     for (;;) {
1385         struct stat st;
1386 
1387         if ((fd = pa_open_cloexec(fn, O_CREAT|O_RDWR
1388 #ifdef O_NOFOLLOW
1389                        |O_NOFOLLOW
1390 #endif
1391                        , S_IRUSR|S_IWUSR)) < 0) {
1392             pa_log_warn("Failed to create lock file '%s': %s", fn, pa_cstrerror(errno));
1393             goto fail;
1394         }
1395 
1396         if (pa_lock_fd(fd, 1) < 0) {
1397             pa_log_warn("Failed to lock file '%s'.", fn);
1398             goto fail;
1399         }
1400 
1401         if (fstat(fd, &st) < 0) {
1402             pa_log_warn("Failed to fstat() file '%s': %s", fn, pa_cstrerror(errno));
1403             goto fail;
1404         }
1405 
1406         /* Check whether the file has been removed meanwhile. When yes,
1407          * restart this loop, otherwise, we're done */
1408         if (st.st_nlink >= 1)
1409             break;
1410 
1411         if (pa_lock_fd(fd, 0) < 0) {
1412             pa_log_warn("Failed to unlock file '%s'.", fn);
1413             goto fail;
1414         }
1415 
1416         if (pa_close(fd) < 0) {
1417             pa_log_warn("Failed to close file '%s': %s", fn, pa_cstrerror(errno));
1418             fd = -1;
1419             goto fail;
1420         }
1421     }
1422 
1423     return fd;
1424 
1425 fail:
1426 
1427     if (fd >= 0) {
1428         int saved_errno = errno;
1429         pa_close(fd);
1430         errno = saved_errno;
1431     }
1432 
1433     return -1;
1434 }
1435 
1436 /* Unlock a temporary lock file */
pa_unlock_lockfile(const char * fn,int fd)1437 int pa_unlock_lockfile(const char *fn, int fd) {
1438     int r = 0;
1439     pa_assert(fd >= 0);
1440 
1441     if (fn) {
1442         if (unlink(fn) < 0) {
1443             pa_log_warn("Unable to remove lock file '%s': %s", fn, pa_cstrerror(errno));
1444             r = -1;
1445         }
1446     }
1447 
1448     if (pa_lock_fd(fd, 0) < 0) {
1449         pa_log_warn("Failed to unlock file '%s'.", fn);
1450         r = -1;
1451     }
1452 
1453     if (pa_close(fd) < 0) {
1454         pa_log_warn("Failed to close '%s': %s", fn, pa_cstrerror(errno));
1455         r = -1;
1456     }
1457 
1458     return r;
1459 }
1460 
check_ours(const char * p)1461 static int check_ours(const char *p) {
1462     struct stat st;
1463 
1464     pa_assert(p);
1465 
1466     if (stat(p, &st) < 0)
1467         return -errno;
1468 
1469 #ifdef HAVE_GETUID
1470     if (st.st_uid != getuid() && st.st_uid != 0)
1471         return -EACCES;
1472 #endif
1473 
1474     return 0;
1475 }
1476 
get_pulse_home(void)1477 static char *get_pulse_home(void) {
1478     char *h, *ret;
1479     int t;
1480 
1481     h = pa_get_home_dir_malloc();
1482     if (!h) {
1483         pa_log_error("Failed to get home directory.");
1484         return NULL;
1485     }
1486 
1487     t = check_ours(h);
1488     if (t < 0 && t != -ENOENT) {
1489         pa_log_error("Home directory not accessible: %s", pa_cstrerror(-t));
1490         pa_xfree(h);
1491         return NULL;
1492     }
1493 
1494     /* If the old directory exists, use it. */
1495     ret = pa_sprintf_malloc("%s" PA_PATH_SEP ".pulse", h);
1496     pa_xfree(h);
1497     if (access(ret, F_OK) >= 0)
1498         return ret;
1499     free(ret);
1500 
1501     /* Otherwise go for the XDG compliant directory. */
1502     if (pa_get_config_home_dir(&ret) < 0)
1503         return NULL;
1504 
1505     return ret;
1506 }
1507 
pa_get_state_dir(void)1508 char *pa_get_state_dir(void) {
1509     char *d;
1510 
1511     /* The state directory shall contain dynamic data that should be
1512      * kept across reboots, and is private to this user */
1513 
1514     if (!(d = pa_xstrdup(getenv("PULSE_STATE_PATH"))))
1515         if (!(d = get_pulse_home()))
1516             return NULL;
1517 
1518     /* If PULSE_STATE_PATH and PULSE_RUNTIME_PATH point to the same
1519      * dir then this will break. */
1520 
1521     if (pa_make_secure_dir(d, 0700U, (uid_t) -1, (gid_t) -1, true) < 0) {
1522         pa_log_error("Failed to create secure directory (%s): %s", d, pa_cstrerror(errno));
1523         pa_xfree(d);
1524         return NULL;
1525     }
1526 
1527     return d;
1528 }
1529 
pa_get_home_dir_malloc(void)1530 char *pa_get_home_dir_malloc(void) {
1531     char *homedir;
1532     size_t allocated = 128;
1533 
1534     for (;;) {
1535         homedir = pa_xmalloc(allocated);
1536 
1537         if (!pa_get_home_dir(homedir, allocated)) {
1538             pa_xfree(homedir);
1539             return NULL;
1540         }
1541 
1542         if (strlen(homedir) < allocated - 1)
1543             break;
1544 
1545         pa_xfree(homedir);
1546         allocated *= 2;
1547     }
1548 
1549     return homedir;
1550 }
1551 
pa_append_to_home_dir(const char * path,char ** _r)1552 int pa_append_to_home_dir(const char *path, char **_r) {
1553     char *home_dir;
1554 
1555     pa_assert(path);
1556     pa_assert(_r);
1557 
1558     home_dir = pa_get_home_dir_malloc();
1559     if (!home_dir) {
1560         pa_log("Failed to get home directory.");
1561         return -PA_ERR_NOENTITY;
1562     }
1563 
1564     *_r = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", home_dir, path);
1565     pa_xfree(home_dir);
1566     return 0;
1567 }
1568 
pa_get_config_home_dir(char ** _r)1569 int pa_get_config_home_dir(char **_r) {
1570     const char *e;
1571     char *home_dir;
1572 
1573     pa_assert(_r);
1574 
1575     e = getenv("XDG_CONFIG_HOME");
1576     if (e && *e) {
1577         *_r = pa_sprintf_malloc("%s" PA_PATH_SEP "pulse", e);
1578         return 0;
1579     }
1580 
1581     home_dir = pa_get_home_dir_malloc();
1582     if (!home_dir)
1583         return -PA_ERR_NOENTITY;
1584 
1585     *_r = pa_sprintf_malloc("%s" PA_PATH_SEP ".config" PA_PATH_SEP "pulse", home_dir);
1586     pa_xfree(home_dir);
1587     return 0;
1588 }
1589 
pa_get_data_home_dir(char ** _r)1590 int pa_get_data_home_dir(char **_r) {
1591     const char *e;
1592     char *home_dir;
1593 
1594     pa_assert(_r);
1595 
1596     e = getenv("XDG_DATA_HOME");
1597     if (e && *e) {
1598         if (pa_is_path_absolute(e)) {
1599             *_r = pa_sprintf_malloc("%s" PA_PATH_SEP "pulseaudio", e);
1600             return 0;
1601         }
1602         else
1603             pa_log_warn("Ignored non-absolute XDG_DATA_HOME value '%s'", e);
1604     }
1605 
1606     home_dir = pa_get_home_dir_malloc();
1607     if (!home_dir)
1608         return -PA_ERR_NOENTITY;
1609 
1610     *_r = pa_sprintf_malloc("%s" PA_PATH_SEP ".local" PA_PATH_SEP "share" PA_PATH_SEP "pulseaudio", home_dir);
1611     pa_xfree(home_dir);
1612     return 0;
1613 }
1614 
pa_get_data_dirs(pa_dynarray ** _r)1615 int pa_get_data_dirs(pa_dynarray **_r) {
1616     const char *e;
1617     const char *def = "/usr/local/share/:/usr/share/";
1618     const char *p;
1619     const char *split_state = NULL;
1620     char *n;
1621     pa_dynarray *paths;
1622 
1623     pa_assert(_r);
1624 
1625     e = getenv("XDG_DATA_DIRS");
1626     p = e && *e ? e : def;
1627 
1628     paths = pa_dynarray_new((pa_free_cb_t) pa_xfree);
1629 
1630     while ((n = pa_split(p, ":", &split_state))) {
1631         char *path;
1632 
1633         if (!pa_is_path_absolute(n)) {
1634             pa_log_warn("Ignored non-absolute path '%s' in XDG_DATA_DIRS", n);
1635             pa_xfree(n);
1636             continue;
1637         }
1638 
1639         path = pa_sprintf_malloc("%s" PA_PATH_SEP "pulseaudio", n);
1640         pa_xfree(n);
1641         pa_dynarray_append(paths, path);
1642     }
1643 
1644     if (pa_dynarray_size(paths) == 0) {
1645         pa_log_warn("XDG_DATA_DIRS contains no valid paths");
1646         pa_dynarray_free(paths);
1647         return -PA_ERR_INVALID;
1648     }
1649 
1650     *_r = paths;
1651     return 0;
1652 }
1653 
pa_append_to_config_home_dir(const char * path,char ** _r)1654 int pa_append_to_config_home_dir(const char *path, char **_r) {
1655     int r;
1656     char *config_home_dir;
1657 
1658     pa_assert(path);
1659     pa_assert(_r);
1660 
1661     r = pa_get_config_home_dir(&config_home_dir);
1662     if (r < 0)
1663         return r;
1664 
1665     *_r = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", config_home_dir, path);
1666     pa_xfree(config_home_dir);
1667     return 0;
1668 }
1669 
pa_get_binary_name_malloc(void)1670 char *pa_get_binary_name_malloc(void) {
1671     char *t;
1672     size_t allocated = 128;
1673 
1674     for (;;) {
1675         t = pa_xmalloc(allocated);
1676 
1677         if (!pa_get_binary_name(t, allocated)) {
1678             pa_xfree(t);
1679             return NULL;
1680         }
1681 
1682         if (strlen(t) < allocated - 1)
1683             break;
1684 
1685         pa_xfree(t);
1686         allocated *= 2;
1687     }
1688 
1689     return t;
1690 }
1691 
make_random_dir(mode_t m)1692 static char* make_random_dir(mode_t m) {
1693     static const char table[] =
1694         "abcdefghijklmnopqrstuvwxyz"
1695         "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1696         "0123456789";
1697 
1698     char *fn;
1699     size_t pathlen;
1700 
1701     fn = pa_sprintf_malloc("%s" PA_PATH_SEP "pulse-XXXXXXXXXXXX", pa_get_temp_dir());
1702     pathlen = strlen(fn);
1703 
1704     for (;;) {
1705         size_t i;
1706         int r;
1707         mode_t u;
1708         int saved_errno;
1709 
1710         for (i = pathlen - 12; i < pathlen; i++)
1711             fn[i] = table[rand() % (sizeof(table)-1)];
1712 
1713         u = umask((~m) & 0777);
1714 #ifndef OS_IS_WIN32
1715         r = mkdir(fn, m);
1716 #else
1717         r = mkdir(fn);
1718 #endif
1719 
1720         saved_errno = errno;
1721         umask(u);
1722         errno = saved_errno;
1723 
1724         if (r >= 0)
1725             return fn;
1726 
1727         if (errno != EEXIST) {
1728             pa_log_error("Failed to create random directory %s: %s", fn, pa_cstrerror(errno));
1729             pa_xfree(fn);
1730             return NULL;
1731         }
1732     }
1733 }
1734 
make_random_dir_and_link(mode_t m,const char * k)1735 static int make_random_dir_and_link(mode_t m, const char *k) {
1736     char *p;
1737 
1738     if (!(p = make_random_dir(m)))
1739         return -1;
1740 
1741 #ifdef HAVE_SYMLINK
1742     if (symlink(p, k) < 0) {
1743         int saved_errno = errno;
1744 
1745         if (errno != EEXIST)
1746             pa_log_error("Failed to symlink %s to %s: %s", k, p, pa_cstrerror(errno));
1747 
1748         rmdir(p);
1749         pa_xfree(p);
1750 
1751         errno = saved_errno;
1752         return -1;
1753     }
1754 #else
1755     pa_xfree(p);
1756     return -1;
1757 #endif
1758 
1759     pa_xfree(p);
1760     return 0;
1761 }
1762 
pa_get_runtime_dir(void)1763 char *pa_get_runtime_dir(void) {
1764     char *d, *k = NULL, *p = NULL, *t = NULL, *mid;
1765     mode_t m;
1766 
1767     /* The runtime directory shall contain dynamic data that needs NOT
1768      * to be kept across reboots and is usually private to the user,
1769      * except in system mode, where it might be accessible by other
1770      * users, too. Since we need POSIX locking and UNIX sockets in
1771      * this directory, we try XDG_RUNTIME_DIR first, and if that isn't
1772      * set create a directory in $HOME and link it to a random subdir
1773      * in /tmp, if it was not explicitly configured. */
1774 
1775     m = pa_in_system_mode() ? 0755U : 0755U;
1776 
1777     /* Use the explicitly configured value if it is set */
1778     d = getenv("PULSE_RUNTIME_PATH");
1779     if (d) {
1780 
1781         if (pa_make_secure_dir(d, m, (uid_t) -1, (gid_t) -1, true) < 0) {
1782             pa_log_error("Failed to create secure directory (%s): %s", d, pa_cstrerror(errno));
1783             goto fail;
1784         }
1785 
1786         return pa_xstrdup(d);
1787     }
1788 
1789     /* Use the XDG standard for the runtime directory. */
1790     d = getenv("XDG_RUNTIME_DIR");
1791     if (d) {
1792 #ifdef HAVE_GETUID
1793         struct stat st;
1794         if (stat(d, &st) == 0 && st.st_uid != getuid()) {
1795             pa_log(_("XDG_RUNTIME_DIR (%s) is not owned by us (uid %d), but by uid %d! "
1796                    "(This could e.g. happen if you try to connect to a non-root PulseAudio as a root user, over the native protocol. Don't do that.)"),
1797                    d, getuid(), st.st_uid);
1798             goto fail;
1799         }
1800 #endif
1801 
1802         k = pa_sprintf_malloc("%s" PA_PATH_SEP "pulse", d);
1803 
1804         if (pa_make_secure_dir(k, m, (uid_t) -1, (gid_t) -1, true) < 0) {
1805             pa_log_error("Failed to create secure directory (%s): %s", k, pa_cstrerror(errno));
1806             goto fail;
1807         }
1808 
1809         return k;
1810     }
1811 
1812     /* XDG_RUNTIME_DIR wasn't set, use the old legacy fallback */
1813     d = get_pulse_home();
1814     if (!d)
1815         goto fail;
1816 
1817     if (pa_make_secure_dir(d, m, (uid_t) -1, (gid_t) -1, true) < 0) {
1818         pa_log_error("Failed to create secure directory (%s): %s", d, pa_cstrerror(errno));
1819         pa_xfree(d);
1820         goto fail;
1821     }
1822 
1823     mid = pa_machine_id();
1824     if (!mid) {
1825         pa_xfree(d);
1826         goto fail;
1827     }
1828 
1829     k = pa_sprintf_malloc("%s" PA_PATH_SEP "%s-runtime", d, mid);
1830     pa_xfree(d);
1831     pa_xfree(mid);
1832 
1833     for (;;) {
1834         /* OK, first let's check if the "runtime" symlink already exists */
1835 
1836         p = pa_readlink(k);
1837         if (!p) {
1838 
1839             if (errno != ENOENT) {
1840                 pa_log_error("Failed to stat runtime directory %s: %s", k, pa_cstrerror(errno));
1841                 goto fail;
1842             }
1843 
1844 #ifdef HAVE_SYMLINK
1845             /* Hmm, so the runtime directory didn't exist yet, so let's
1846              * create one in /tmp and symlink that to it */
1847 
1848             if (make_random_dir_and_link(0700, k) < 0) {
1849 
1850                 /* Mhmm, maybe another process was quicker than us,
1851                  * let's check if that was valid */
1852                 if (errno == EEXIST)
1853                     continue;
1854 
1855                 goto fail;
1856             }
1857 #else
1858             /* No symlink possible, so let's just create the runtime directly
1859              * Do not check again if it exists since it cannot be a symlink */
1860             if (mkdir(k) < 0 && errno != EEXIST)
1861                 goto fail;
1862 #endif
1863 
1864             return k;
1865         }
1866 
1867         /* Make sure that this actually makes sense */
1868         if (!pa_is_path_absolute(p)) {
1869             pa_log_error("Path %s in link %s is not absolute.", p, k);
1870             errno = ENOENT;
1871             goto fail;
1872         }
1873 
1874         /* Hmm, so this symlink is still around, make sure nobody fools us */
1875 #ifdef HAVE_LSTAT
1876 {
1877         struct stat st;
1878         if (lstat(p, &st) < 0) {
1879 
1880             if (errno != ENOENT) {
1881                 pa_log_error("Failed to stat runtime directory %s: %s", p, pa_cstrerror(errno));
1882                 goto fail;
1883             }
1884 
1885         } else {
1886 
1887             if (S_ISDIR(st.st_mode) &&
1888                 (st.st_uid == getuid()) &&
1889                 ((st.st_mode & 0777) == 0700)) {
1890 
1891                 pa_xfree(p);
1892                 return k;
1893             }
1894 
1895             pa_log_info("Hmm, runtime path exists, but points to an invalid directory. Changing runtime directory.");
1896         }
1897 }
1898 #endif
1899 
1900         pa_xfree(p);
1901         p = NULL;
1902 
1903         /* Hmm, so the link points to some nonexisting or invalid
1904          * dir. Let's replace it by a new link. We first create a
1905          * temporary link and then rename that to allow concurrent
1906          * execution of this function. */
1907 
1908         t = pa_sprintf_malloc("%s.tmp", k);
1909 
1910         if (make_random_dir_and_link(0700, t) < 0) {
1911 
1912             if (errno != EEXIST) {
1913                 pa_log_error("Failed to symlink %s: %s", t, pa_cstrerror(errno));
1914                 goto fail;
1915             }
1916 
1917             pa_xfree(t);
1918             t = NULL;
1919 
1920             /* Hmm, someone else was quicker then us. Let's give
1921              * him some time to finish, and retry. */
1922             pa_msleep(10);
1923             continue;
1924         }
1925 
1926         /* OK, we succeeded in creating the temporary symlink, so
1927          * let's rename it */
1928         if (rename(t, k) < 0) {
1929             pa_log_error("Failed to rename %s to %s: %s", t, k, pa_cstrerror(errno));
1930             goto fail;
1931         }
1932 
1933         pa_xfree(t);
1934         return k;
1935     }
1936 
1937 fail:
1938     pa_xfree(p);
1939     pa_xfree(k);
1940     pa_xfree(t);
1941 
1942     return NULL;
1943 }
1944 
1945 /* Try to open a configuration file. If "env" is specified, open the
1946  * value of the specified environment variable. Otherwise look for a
1947  * file "local" in the home directory or a file "global" in global
1948  * file system. If "result" is non-NULL, a pointer to a newly
1949  * allocated buffer containing the used configuration file is
1950  * stored there.*/
pa_open_config_file(const char * global,const char * local,const char * env,char ** result)1951 FILE *pa_open_config_file(const char *global, const char *local, const char *env, char **result) {
1952     const char *fn;
1953     FILE *f;
1954 
1955     if (env && (fn = getenv(env))) {
1956         if ((f = pa_fopen_cloexec(fn, "r"))) {
1957             if (result)
1958                 *result = pa_xstrdup(fn);
1959 
1960             return f;
1961         }
1962 
1963         pa_log_warn("Failed to open configuration file '%s': %s", fn, pa_cstrerror(errno));
1964         return NULL;
1965     }
1966 
1967     if (local) {
1968         const char *e;
1969         char *lfn;
1970         char *h;
1971 
1972         if ((e = getenv("PULSE_CONFIG_PATH"))) {
1973             fn = lfn = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", e, local);
1974             f = pa_fopen_cloexec(fn, "r");
1975         } else if ((h = pa_get_home_dir_malloc())) {
1976             fn = lfn = pa_sprintf_malloc("%s" PA_PATH_SEP ".pulse" PA_PATH_SEP "%s", h, local);
1977             f = pa_fopen_cloexec(fn, "r");
1978             if (!f) {
1979                 free(lfn);
1980                 fn = lfn = pa_sprintf_malloc("%s" PA_PATH_SEP ".config/pulse" PA_PATH_SEP "%s", h, local);
1981                 f = pa_fopen_cloexec(fn, "r");
1982             }
1983             pa_xfree(h);
1984         } else
1985             return NULL;
1986 
1987         if (f) {
1988             if (result)
1989                 *result = pa_xstrdup(fn);
1990 
1991             pa_xfree(lfn);
1992             return f;
1993         }
1994 
1995         if (errno != ENOENT) {
1996             pa_log_warn("Failed to open configuration file '%s': %s", fn, pa_cstrerror(errno));
1997             pa_xfree(lfn);
1998             return NULL;
1999         }
2000 
2001         pa_xfree(lfn);
2002     }
2003 
2004     if (global) {
2005         char *gfn;
2006 
2007 #ifdef OS_IS_WIN32
2008         if (strncmp(global, PA_DEFAULT_CONFIG_DIR, strlen(PA_DEFAULT_CONFIG_DIR)) == 0)
2009             gfn = pa_sprintf_malloc("%s" PA_PATH_SEP "etc" PA_PATH_SEP "pulse%s",
2010                                     pa_win32_get_toplevel(NULL),
2011                                     global + strlen(PA_DEFAULT_CONFIG_DIR));
2012         else
2013 #endif
2014         gfn = pa_xstrdup(global);
2015 
2016         if ((f = pa_fopen_cloexec(gfn, "r"))) {
2017             if (result)
2018                 *result = gfn;
2019             else
2020                 pa_xfree(gfn);
2021 
2022             return f;
2023         }
2024         pa_xfree(gfn);
2025     }
2026 
2027     errno = ENOENT;
2028     return NULL;
2029 }
2030 
pa_find_config_file(const char * global,const char * local,const char * env)2031 char *pa_find_config_file(const char *global, const char *local, const char *env) {
2032     const char *fn;
2033 
2034     if (env && (fn = getenv(env))) {
2035         if (access(fn, R_OK) == 0)
2036             return pa_xstrdup(fn);
2037 
2038         pa_log_warn("Failed to access configuration file '%s': %s", fn, pa_cstrerror(errno));
2039         return NULL;
2040     }
2041 
2042     if (local) {
2043         const char *e;
2044         char *lfn;
2045         char *h;
2046 
2047         if ((e = getenv("PULSE_CONFIG_PATH")))
2048             fn = lfn = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", e, local);
2049         else if ((h = pa_get_home_dir_malloc())) {
2050             fn = lfn = pa_sprintf_malloc("%s" PA_PATH_SEP ".pulse" PA_PATH_SEP "%s", h, local);
2051             pa_xfree(h);
2052         } else
2053             return NULL;
2054 
2055         if (access(fn, R_OK) == 0) {
2056             char *r = pa_xstrdup(fn);
2057             pa_xfree(lfn);
2058             return r;
2059         }
2060 
2061         if (errno != ENOENT) {
2062             pa_log_warn("Failed to access configuration file '%s': %s", fn, pa_cstrerror(errno));
2063             pa_xfree(lfn);
2064             return NULL;
2065         }
2066 
2067         pa_xfree(lfn);
2068     }
2069 
2070     if (global) {
2071         char *gfn;
2072 
2073 #ifdef OS_IS_WIN32
2074         if (strncmp(global, PA_DEFAULT_CONFIG_DIR, strlen(PA_DEFAULT_CONFIG_DIR)) == 0)
2075             gfn = pa_sprintf_malloc("%s" PA_PATH_SEP "etc" PA_PATH_SEP "pulse%s",
2076                                     pa_win32_get_toplevel(NULL),
2077                                     global + strlen(PA_DEFAULT_CONFIG_DIR));
2078         else
2079 #endif
2080         gfn = pa_xstrdup(global);
2081 
2082         if (access(gfn, R_OK) == 0)
2083             return gfn;
2084         pa_xfree(gfn);
2085     }
2086 
2087     errno = ENOENT;
2088 
2089     return NULL;
2090 }
2091 
2092 /* Format the specified data as a hexademical string */
pa_hexstr(const uint8_t * d,size_t dlength,char * s,size_t slength)2093 char *pa_hexstr(const uint8_t* d, size_t dlength, char *s, size_t slength) {
2094     size_t i = 0, j = 0;
2095     const char hex[] = "0123456789abcdef";
2096 
2097     pa_assert(d);
2098     pa_assert(s);
2099     pa_assert(slength > 0);
2100 
2101     while (j+2 < slength && i < dlength) {
2102         s[j++] = hex[*d >> 4];
2103         s[j++] = hex[*d & 0xF];
2104 
2105         d++;
2106         i++;
2107     }
2108 
2109     s[j < slength ? j : slength] = 0;
2110     return s;
2111 }
2112 
2113 /* Convert a hexadecimal digit to a number or -1 if invalid */
hexc(char c)2114 static int hexc(char c) {
2115     if (c >= '0' && c <= '9')
2116         return c - '0';
2117 
2118     if (c >= 'A' && c <= 'F')
2119         return c - 'A' + 10;
2120 
2121     if (c >= 'a' && c <= 'f')
2122         return c - 'a' + 10;
2123 
2124     errno = EINVAL;
2125     return -1;
2126 }
2127 
2128 /* Parse a hexadecimal string as created by pa_hexstr() to a BLOB */
pa_parsehex(const char * p,uint8_t * d,size_t dlength)2129 size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength) {
2130     size_t j = 0;
2131 
2132     pa_assert(p);
2133     pa_assert(d);
2134 
2135     while (j < dlength && *p) {
2136         int b;
2137 
2138         if ((b = hexc(*(p++))) < 0)
2139             return (size_t) -1;
2140 
2141         d[j] = (uint8_t) (b << 4);
2142 
2143         if (!*p)
2144             return (size_t) -1;
2145 
2146         if ((b = hexc(*(p++))) < 0)
2147             return (size_t) -1;
2148 
2149         d[j] |= (uint8_t) b;
2150         j++;
2151     }
2152 
2153     return j;
2154 }
2155 
2156 /* Returns nonzero when *s starts with *pfx */
pa_startswith(const char * s,const char * pfx)2157 bool pa_startswith(const char *s, const char *pfx) {
2158     size_t l;
2159 
2160     pa_assert(s);
2161     pa_assert(pfx);
2162 
2163     l = strlen(pfx);
2164 
2165     return strlen(s) >= l && strncmp(s, pfx, l) == 0;
2166 }
2167 
2168 /* Returns nonzero when *s ends with *sfx */
pa_endswith(const char * s,const char * sfx)2169 bool pa_endswith(const char *s, const char *sfx) {
2170     size_t l1, l2;
2171 
2172     pa_assert(s);
2173     pa_assert(sfx);
2174 
2175     l1 = strlen(s);
2176     l2 = strlen(sfx);
2177 
2178     return l1 >= l2 && pa_streq(s + l1 - l2, sfx);
2179 }
2180 
pa_is_path_absolute(const char * fn)2181 bool pa_is_path_absolute(const char *fn) {
2182     pa_assert(fn);
2183 
2184 #ifndef OS_IS_WIN32
2185     return *fn == '/';
2186 #else
2187     return strlen(fn) >= 3 && isalpha(fn[0]) && fn[1] == ':' && fn[2] == '\\';
2188 #endif
2189 }
2190 
pa_make_path_absolute(const char * p)2191 char *pa_make_path_absolute(const char *p) {
2192     char *r;
2193     char *cwd;
2194 
2195     pa_assert(p);
2196 
2197     if (pa_is_path_absolute(p))
2198         return pa_xstrdup(p);
2199 
2200     if (!(cwd = pa_getcwd()))
2201         return pa_xstrdup(p);
2202 
2203     r = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", cwd, p);
2204     pa_xfree(cwd);
2205     return r;
2206 }
2207 
2208 /* If fn is NULL, return the PulseAudio runtime or state dir (depending on the
2209  * rt parameter). If fn is non-NULL and starts with /, return fn. Otherwise,
2210  * append fn to the runtime/state dir and return it. */
get_path(const char * fn,bool prependmid,bool rt)2211 static char *get_path(const char *fn, bool prependmid, bool rt) {
2212     char *rtp;
2213 
2214     rtp = rt ? pa_get_runtime_dir() : pa_get_state_dir();
2215 
2216     if (fn) {
2217         char *r, *canonical_rtp;
2218 
2219         if (pa_is_path_absolute(fn)) {
2220             pa_xfree(rtp);
2221             return pa_xstrdup(fn);
2222         }
2223 
2224         if (!rtp)
2225             return NULL;
2226 
2227         /* Hopefully make the path smaller to avoid 108 char limit (fdo#44680) */
2228         if ((canonical_rtp = pa_realpath(rtp))) {
2229             if (strlen(rtp) >= strlen(canonical_rtp))
2230                 pa_xfree(rtp);
2231             else {
2232                 pa_xfree(canonical_rtp);
2233                 canonical_rtp = rtp;
2234             }
2235         } else
2236             canonical_rtp = rtp;
2237 
2238         if (prependmid) {
2239             char *mid;
2240 
2241             if (!(mid = pa_machine_id())) {
2242                 pa_xfree(canonical_rtp);
2243                 return NULL;
2244             }
2245 
2246             r = pa_sprintf_malloc("%s" PA_PATH_SEP "%s-%s", canonical_rtp, mid, fn);
2247             pa_xfree(mid);
2248         } else
2249             r = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", canonical_rtp, fn);
2250 
2251         pa_xfree(canonical_rtp);
2252         return r;
2253     } else
2254         return rtp;
2255 }
2256 
pa_runtime_path(const char * fn)2257 char *pa_runtime_path(const char *fn) {
2258     return get_path(fn, false, true);
2259 }
2260 
pa_state_path(const char * fn,bool appendmid)2261 char *pa_state_path(const char *fn, bool appendmid) {
2262     return get_path(fn, appendmid, false);
2263 }
2264 
2265 /* Convert the string s to a signed integer in *ret_i */
pa_atoi(const char * s,int32_t * ret_i)2266 int pa_atoi(const char *s, int32_t *ret_i) {
2267     long l;
2268 
2269     pa_assert(s);
2270     pa_assert(ret_i);
2271 
2272     if (pa_atol(s, &l) < 0)
2273         return -1;
2274 
2275     if (l < INT32_MIN || l > INT32_MAX) {
2276         errno = ERANGE;
2277         return -1;
2278     }
2279 
2280     *ret_i = (int32_t) l;
2281 
2282     return 0;
2283 }
2284 
2285 enum numtype {
2286     NUMTYPE_UINT,
2287     NUMTYPE_INT,
2288     NUMTYPE_DOUBLE,
2289 };
2290 
2291 /* A helper function for pa_atou() and friends. This does some common checks,
2292  * because our number parsing is more strict than the strtoX functions.
2293  *
2294  * Leading zeros are stripped from integers so that they don't get parsed as
2295  * octal (but "0x" is preserved for hexadecimal numbers). For NUMTYPE_INT the
2296  * zero stripping may involve allocating a new string, in which case it's
2297  * stored in tmp. Otherwise tmp is set to NULL. The caller needs to free tmp
2298  * after they're done with ret. When parsing other types than NUMTYPE_INT the
2299  * caller can pass NULL as tmp.
2300  *
2301  * The final string to parse is returned in ret. ret will point either inside
2302  * s or to tmp. */
prepare_number_string(const char * s,enum numtype type,char ** tmp,const char ** ret)2303 static int prepare_number_string(const char *s, enum numtype type, char **tmp, const char **ret) {
2304     const char *original = s;
2305     bool negative = false;
2306 
2307     pa_assert(s);
2308     pa_assert(type != NUMTYPE_INT || tmp);
2309     pa_assert(ret);
2310 
2311     if (tmp)
2312         *tmp = NULL;
2313 
2314     /* The strtoX functions accept leading spaces, we don't. */
2315     if (isspace((unsigned char) s[0]))
2316         return -1;
2317 
2318     /* The strtoX functions accept a plus sign, we don't. */
2319     if (s[0] == '+')
2320         return -1;
2321 
2322     /* The strtoul and strtoull functions allow a minus sign even though they
2323      * parse an unsigned number. In case of a minus sign the original negative
2324      * number gets negated. We don't want that kind of behviour. */
2325     if (type == NUMTYPE_UINT && s[0] == '-')
2326         return -1;
2327 
2328     /* The strtoX functions interpret the number as octal if it starts with
2329      * a zero. We prefer to use base 10, so we strip all leading zeros (if the
2330      * string starts with "0x", strtoul() interprets it as hexadecimal, which
2331      * is fine, because it's unambiguous unlike octal).
2332      *
2333      * While stripping the leading zeros, we have to remember to also handle
2334      * the case where the number is negative, which makes the zero skipping
2335      * code somewhat complex. */
2336 
2337     /* Doubles don't need zero stripping, we can finish now. */
2338     if (type == NUMTYPE_DOUBLE)
2339         goto finish;
2340 
2341     if (s[0] == '-') {
2342         negative = true;
2343         s++; /* Skip the minus sign. */
2344     }
2345 
2346     /* Don't skip zeros if the string starts with "0x". */
2347     if (s[0] == '0' && s[1] != 'x') {
2348         while (s[0] == '0' && s[1])
2349             s++; /* Skip zeros. */
2350     }
2351 
2352     if (negative) {
2353         s--; /* Go back one step, we need the minus sign back. */
2354 
2355         /* If s != original, then we have skipped some zeros and we need to replace
2356          * the last skipped zero with a minus sign. */
2357         if (s != original) {
2358             *tmp = pa_xstrdup(s);
2359             *tmp[0] = '-';
2360             s = *tmp;
2361         }
2362     }
2363 
2364 finish:
2365     *ret = s;
2366     return 0;
2367 }
2368 
2369 /* Convert the string s to an unsigned integer in *ret_u */
pa_atou(const char * s,uint32_t * ret_u)2370 int pa_atou(const char *s, uint32_t *ret_u) {
2371     char *x = NULL;
2372     unsigned long l;
2373 
2374     pa_assert(s);
2375     pa_assert(ret_u);
2376 
2377     if (prepare_number_string(s, NUMTYPE_UINT, NULL, &s) < 0) {
2378         errno = EINVAL;
2379         return -1;
2380     }
2381 
2382     errno = 0;
2383     l = strtoul(s, &x, 0);
2384 
2385     /* If x doesn't point to the end of s, there was some trailing garbage in
2386      * the string. If x points to s, no conversion was done (empty string). */
2387     if (!x || *x || x == s || errno) {
2388         if (!errno)
2389             errno = EINVAL;
2390         return -1;
2391     }
2392 
2393     if (l > UINT32_MAX) {
2394         errno = ERANGE;
2395         return -1;
2396     }
2397 
2398     *ret_u = (uint32_t) l;
2399 
2400     return 0;
2401 }
2402 
2403 /* Convert the string s to an unsigned 64 bit integer in *ret_u */
pa_atou64(const char * s,uint64_t * ret_u)2404 int pa_atou64(const char *s, uint64_t *ret_u) {
2405     char *x = NULL;
2406     unsigned long long l;
2407 
2408     pa_assert(s);
2409     pa_assert(ret_u);
2410 
2411     if (prepare_number_string(s, NUMTYPE_UINT, NULL, &s) < 0) {
2412         errno = EINVAL;
2413         return -1;
2414     }
2415 
2416     errno = 0;
2417     l = strtoull(s, &x, 0);
2418 
2419     /* If x doesn't point to the end of s, there was some trailing garbage in
2420      * the string. If x points to s, no conversion was done (empty string). */
2421     if (!x || *x || x == s || errno) {
2422         if (!errno)
2423             errno = EINVAL;
2424         return -1;
2425     }
2426 
2427     if (l > UINT64_MAX) {
2428         errno = ERANGE;
2429         return -1;
2430     }
2431 
2432     *ret_u = (uint64_t) l;
2433 
2434     return 0;
2435 }
2436 
2437 /* Convert the string s to a signed long integer in *ret_l. */
pa_atol(const char * s,long * ret_l)2438 int pa_atol(const char *s, long *ret_l) {
2439     char *tmp;
2440     char *x = NULL;
2441     long l;
2442 
2443     pa_assert(s);
2444     pa_assert(ret_l);
2445 
2446     if (prepare_number_string(s, NUMTYPE_INT, &tmp, &s) < 0) {
2447         errno = EINVAL;
2448         return -1;
2449     }
2450 
2451     errno = 0;
2452     l = strtol(s, &x, 0);
2453 
2454     /* If x doesn't point to the end of s, there was some trailing garbage in
2455      * the string. If x points to s, no conversion was done (at least an empty
2456      * string can trigger this). */
2457     if (!x || *x || x == s || errno) {
2458         if (!errno)
2459             errno = EINVAL;
2460         pa_xfree(tmp);
2461         return -1;
2462     }
2463 
2464     pa_xfree(tmp);
2465 
2466     *ret_l = l;
2467 
2468     return 0;
2469 }
2470 
2471 /* Convert the string s to a signed 64 bit integer in *ret_l. */
pa_atoi64(const char * s,int64_t * ret_l)2472 int pa_atoi64(const char *s, int64_t *ret_l) {
2473     char *tmp;
2474     char *x = NULL;
2475     long long l;
2476 
2477     pa_assert(s);
2478     pa_assert(ret_l);
2479 
2480     if (prepare_number_string(s, NUMTYPE_INT, &tmp, &s) < 0) {
2481         errno = EINVAL;
2482         return -1;
2483     }
2484 
2485     errno = 0;
2486     l = strtoll(s, &x, 0);
2487 
2488     /* If x doesn't point to the end of s, there was some trailing garbage in
2489      * the string. If x points to s, no conversion was done (at least an empty
2490      * string can trigger this). */
2491     if (!x || *x || x == s || errno) {
2492         if (!errno)
2493             errno = EINVAL;
2494         pa_xfree(tmp);
2495         return -1;
2496     }
2497 
2498     pa_xfree(tmp);
2499 
2500     *ret_l = l;
2501 
2502     if (l < INT64_MIN || l > INT64_MAX) {
2503         errno = ERANGE;
2504         return -1;
2505     }
2506 
2507     return 0;
2508 }
2509 
2510 #ifdef HAVE_STRTOD_L
2511 static locale_t c_locale = NULL;
2512 
c_locale_destroy(void)2513 static void c_locale_destroy(void) {
2514     freelocale(c_locale);
2515 }
2516 #endif
2517 
pa_atod(const char * s,double * ret_d)2518 int pa_atod(const char *s, double *ret_d) {
2519     char *x = NULL;
2520     double f;
2521 
2522     pa_assert(s);
2523     pa_assert(ret_d);
2524 
2525     if (prepare_number_string(s, NUMTYPE_DOUBLE, NULL, &s) < 0) {
2526         errno = EINVAL;
2527         return -1;
2528     }
2529 
2530     /* This should be locale independent */
2531 
2532 #ifdef HAVE_STRTOD_L
2533 
2534     PA_ONCE_BEGIN {
2535 
2536         if ((c_locale = newlocale(LC_ALL_MASK, "C", NULL)))
2537             atexit(c_locale_destroy);
2538 
2539     } PA_ONCE_END;
2540 
2541     if (c_locale) {
2542         errno = 0;
2543         f = strtod_l(s, &x, c_locale);
2544     } else
2545 #endif
2546     {
2547         errno = 0;
2548         f = strtod(s, &x);
2549     }
2550 
2551     /* If x doesn't point to the end of s, there was some trailing garbage in
2552      * the string. If x points to s, no conversion was done (at least an empty
2553      * string can trigger this). */
2554     if (!x || *x || x == s || errno) {
2555         if (!errno)
2556             errno = EINVAL;
2557         return -1;
2558     }
2559 
2560     if (isnan(f)) {
2561         errno = EINVAL;
2562         return -1;
2563     }
2564 
2565     *ret_d = f;
2566 
2567     return 0;
2568 }
2569 
2570 /* Same as snprintf, but guarantees NUL-termination on every platform */
pa_snprintf(char * str,size_t size,const char * format,...)2571 size_t pa_snprintf(char *str, size_t size, const char *format, ...) {
2572     size_t ret;
2573     va_list ap;
2574 
2575     pa_assert(str);
2576     pa_assert(size > 0);
2577     pa_assert(format);
2578 
2579     va_start(ap, format);
2580     ret = pa_vsnprintf(str, size, format, ap);
2581     va_end(ap);
2582 
2583     return ret;
2584 }
2585 
2586 /* Same as vsnprintf, but guarantees NUL-termination on every platform */
pa_vsnprintf(char * str,size_t size,const char * format,va_list ap)2587 size_t pa_vsnprintf(char *str, size_t size, const char *format, va_list ap) {
2588     int ret;
2589 
2590     pa_assert(str);
2591     pa_assert(size > 0);
2592     pa_assert(format);
2593 
2594     ret = vsnprintf(str, size, format, ap);
2595 
2596     str[size-1] = 0;
2597 
2598     if (ret < 0)
2599         return strlen(str);
2600 
2601     if ((size_t) ret > size-1)
2602         return size-1;
2603 
2604     return (size_t) ret;
2605 }
2606 
2607 /* Truncate the specified string, but guarantee that the string
2608  * returned still validates as UTF8 */
pa_truncate_utf8(char * c,size_t l)2609 char *pa_truncate_utf8(char *c, size_t l) {
2610     pa_assert(c);
2611     pa_assert(pa_utf8_valid(c));
2612 
2613     if (strlen(c) <= l)
2614         return c;
2615 
2616     c[l] = 0;
2617 
2618     while (l > 0 && !pa_utf8_valid(c))
2619         c[--l] = 0;
2620 
2621     return c;
2622 }
2623 
pa_getcwd(void)2624 char *pa_getcwd(void) {
2625     size_t l = 128;
2626 
2627     for (;;) {
2628         char *p = pa_xmalloc(l);
2629         if (getcwd(p, l))
2630             return p;
2631 
2632         if (errno != ERANGE) {
2633             pa_xfree(p);
2634             return NULL;
2635         }
2636 
2637         pa_xfree(p);
2638         l *= 2;
2639     }
2640 }
2641 
pa_will_need(const void * p,size_t l)2642 void *pa_will_need(const void *p, size_t l) {
2643 #ifdef RLIMIT_MEMLOCK
2644     struct rlimit rlim;
2645 #endif
2646     const void *a;
2647     size_t size;
2648     int r = ENOTSUP;
2649     size_t bs;
2650     const size_t page_size = pa_page_size();
2651 
2652     pa_assert(p);
2653     pa_assert(l > 0);
2654 
2655     a = PA_PAGE_ALIGN_PTR(p);
2656     size = (size_t) ((const uint8_t*) p + l - (const uint8_t*) a);
2657 
2658 #ifdef HAVE_POSIX_MADVISE
2659     if ((r = posix_madvise((void*) a, size, POSIX_MADV_WILLNEED)) == 0) {
2660         pa_log_debug("posix_madvise() worked fine!");
2661         return (void*) p;
2662     }
2663 #endif
2664 
2665     /* Most likely the memory was not mmap()ed from a file and thus
2666      * madvise() didn't work, so let's misuse mlock() do page this
2667      * stuff back into RAM. Yeah, let's fuck with the MM!  It's so
2668      * inviting, the man page of mlock() tells us: "All pages that
2669      * contain a part of the specified address range are guaranteed to
2670      * be resident in RAM when the call returns successfully." */
2671 
2672 #ifdef RLIMIT_MEMLOCK
2673     pa_assert_se(getrlimit(RLIMIT_MEMLOCK, &rlim) == 0);
2674 
2675     if (rlim.rlim_cur < page_size) {
2676         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));
2677         errno = EPERM;
2678         return (void*) p;
2679     }
2680 
2681     bs = PA_PAGE_ALIGN((size_t) rlim.rlim_cur);
2682 #else
2683     bs = page_size*4;
2684 #endif
2685 
2686     pa_log_debug("posix_madvise() failed (or doesn't exist), trying mlock(): %s", pa_cstrerror(r));
2687 
2688 #ifdef HAVE_MLOCK
2689     while (size > 0 && bs > 0) {
2690 
2691         if (bs > size)
2692             bs = size;
2693 
2694         if (mlock(a, bs) < 0) {
2695             bs = PA_PAGE_ALIGN(bs / 2);
2696             continue;
2697         }
2698 
2699         pa_assert_se(munlock(a, bs) == 0);
2700 
2701         a = (const uint8_t*) a + bs;
2702         size -= bs;
2703     }
2704 #endif
2705 
2706     if (bs <= 0)
2707         pa_log_debug("mlock() failed too (or doesn't exist), giving up: %s", pa_cstrerror(errno));
2708     else
2709         pa_log_debug("mlock() worked fine!");
2710 
2711     return (void*) p;
2712 }
2713 
pa_close_pipe(int fds[2])2714 void pa_close_pipe(int fds[2]) {
2715     pa_assert(fds);
2716 
2717     if (fds[0] >= 0)
2718         pa_assert_se(pa_close(fds[0]) == 0);
2719 
2720     if (fds[1] >= 0)
2721         pa_assert_se(pa_close(fds[1]) == 0);
2722 
2723     fds[0] = fds[1] = -1;
2724 }
2725 
pa_readlink(const char * p)2726 char *pa_readlink(const char *p) {
2727 #ifdef HAVE_READLINK
2728     size_t l = 100;
2729 
2730     for (;;) {
2731         char *c;
2732         ssize_t n;
2733 
2734         c = pa_xmalloc(l);
2735 
2736         if ((n = readlink(p, c, l-1)) < 0) {
2737             pa_xfree(c);
2738             return NULL;
2739         }
2740 
2741         if ((size_t) n < l-1) {
2742             c[n] = 0;
2743             return c;
2744         }
2745 
2746         pa_xfree(c);
2747         l *= 2;
2748     }
2749 #else
2750     return NULL;
2751 #endif
2752 }
2753 
pa_close_all(int except_fd,...)2754 int pa_close_all(int except_fd, ...) {
2755     va_list ap;
2756     unsigned n = 0, i;
2757     int r, *p;
2758 
2759     va_start(ap, except_fd);
2760 
2761     if (except_fd >= 0)
2762         for (n = 1; va_arg(ap, int) >= 0; n++)
2763             ;
2764 
2765     va_end(ap);
2766 
2767     p = pa_xnew(int, n+1);
2768 
2769     va_start(ap, except_fd);
2770 
2771     i = 0;
2772     if (except_fd >= 0) {
2773         int fd;
2774         p[i++] = except_fd;
2775 
2776         while ((fd = va_arg(ap, int)) >= 0)
2777             p[i++] = fd;
2778     }
2779     p[i] = -1;
2780 
2781     va_end(ap);
2782 
2783     r = pa_close_allv(p);
2784     pa_xfree(p);
2785 
2786     return r;
2787 }
2788 
pa_close_allv(const int except_fds[])2789 int pa_close_allv(const int except_fds[]) {
2790 #ifndef OS_IS_WIN32
2791     struct rlimit rl;
2792     int maxfd, fd;
2793 
2794 #if defined(__linux__) || defined(__sun)
2795     int saved_errno;
2796     DIR *d;
2797 
2798     if ((d = opendir("/proc/self/fd"))) {
2799 
2800         struct dirent *de;
2801 
2802         while ((de = readdir(d))) {
2803             bool found;
2804             long l;
2805             char *e = NULL;
2806             int i;
2807 
2808             if (de->d_name[0] == '.')
2809                 continue;
2810 
2811             errno = 0;
2812             l = strtol(de->d_name, &e, 10);
2813             if (errno != 0 || !e || *e) {
2814                 closedir(d);
2815                 errno = EINVAL;
2816                 return -1;
2817             }
2818 
2819             fd = (int) l;
2820 
2821             if ((long) fd != l) {
2822                 closedir(d);
2823                 errno = EINVAL;
2824                 return -1;
2825             }
2826 
2827             if (fd < 3)
2828                 continue;
2829 
2830             if (fd == dirfd(d))
2831                 continue;
2832 
2833             found = false;
2834             for (i = 0; except_fds[i] >= 0; i++)
2835                 if (except_fds[i] == fd) {
2836                     found = true;
2837                     break;
2838                 }
2839 
2840             if (found)
2841                 continue;
2842 
2843             if (pa_close(fd) < 0) {
2844                 saved_errno = errno;
2845                 closedir(d);
2846                 errno = saved_errno;
2847 
2848                 return -1;
2849             }
2850         }
2851 
2852         closedir(d);
2853         return 0;
2854     }
2855 
2856 #endif
2857 
2858     if (getrlimit(RLIMIT_NOFILE, &rl) >= 0)
2859         maxfd = (int) rl.rlim_max;
2860     else
2861         maxfd = sysconf(_SC_OPEN_MAX);
2862 
2863     for (fd = 3; fd < maxfd; fd++) {
2864         int i;
2865         bool found;
2866 
2867         found = false;
2868         for (i = 0; except_fds[i] >= 0; i++)
2869             if (except_fds[i] == fd) {
2870                 found = true;
2871                 break;
2872             }
2873 
2874         if (found)
2875             continue;
2876 
2877         if (pa_close(fd) < 0 && errno != EBADF)
2878             return -1;
2879     }
2880 #endif  /* !OS_IS_WIN32 */
2881 
2882     return 0;
2883 }
2884 
pa_unblock_sigs(int except,...)2885 int pa_unblock_sigs(int except, ...) {
2886     va_list ap;
2887     unsigned n = 0, i;
2888     int r, *p;
2889 
2890     va_start(ap, except);
2891 
2892     if (except >= 1)
2893         for (n = 1; va_arg(ap, int) >= 0; n++)
2894             ;
2895 
2896     va_end(ap);
2897 
2898     p = pa_xnew(int, n+1);
2899 
2900     va_start(ap, except);
2901 
2902     i = 0;
2903     if (except >= 1) {
2904         int sig;
2905         p[i++] = except;
2906 
2907         while ((sig = va_arg(ap, int)) >= 0)
2908             p[i++] = sig;
2909     }
2910     p[i] = -1;
2911 
2912     va_end(ap);
2913 
2914     r = pa_unblock_sigsv(p);
2915     pa_xfree(p);
2916 
2917     return r;
2918 }
2919 
pa_unblock_sigsv(const int except[])2920 int pa_unblock_sigsv(const int except[]) {
2921 #ifndef OS_IS_WIN32
2922     int i;
2923     sigset_t ss;
2924 
2925     if (sigemptyset(&ss) < 0)
2926         return -1;
2927 
2928     for (i = 0; except[i] > 0; i++)
2929         if (sigaddset(&ss, except[i]) < 0)
2930             return -1;
2931 
2932     return sigprocmask(SIG_SETMASK, &ss, NULL);
2933 #else
2934     return 0;
2935 #endif
2936 }
2937 
pa_reset_sigs(int except,...)2938 int pa_reset_sigs(int except, ...) {
2939     va_list ap;
2940     unsigned n = 0, i;
2941     int *p, r;
2942 
2943     va_start(ap, except);
2944 
2945     if (except >= 1)
2946         for (n = 1; va_arg(ap, int) >= 0; n++)
2947             ;
2948 
2949     va_end(ap);
2950 
2951     p = pa_xnew(int, n+1);
2952 
2953     va_start(ap, except);
2954 
2955     i = 0;
2956     if (except >= 1) {
2957         int sig;
2958         p[i++] = except;
2959 
2960         while ((sig = va_arg(ap, int)) >= 0)
2961             p[i++] = sig;
2962     }
2963     p[i] = -1;
2964 
2965     va_end(ap);
2966 
2967     r = pa_reset_sigsv(p);
2968     pa_xfree(p);
2969 
2970     return r;
2971 }
2972 
pa_reset_sigsv(const int except[])2973 int pa_reset_sigsv(const int except[]) {
2974 #ifndef OS_IS_WIN32
2975     int sig;
2976 
2977     for (sig = 1; sig < NSIG; sig++) {
2978         bool reset = true;
2979 
2980         switch (sig) {
2981             case SIGKILL:
2982             case SIGSTOP:
2983                 reset = false;
2984                 break;
2985 
2986             default: {
2987                 int i;
2988 
2989                 for (i = 0; except[i] > 0; i++) {
2990                     if (sig == except[i]) {
2991                         reset = false;
2992                         break;
2993                     }
2994                 }
2995             }
2996         }
2997 
2998         if (reset) {
2999             struct sigaction sa;
3000 
3001             memset(&sa, 0, sizeof(sa));
3002             sa.sa_handler = SIG_DFL;
3003 
3004             /* On Linux the first two RT signals are reserved by
3005              * glibc, and sigaction() will return EINVAL for them. */
3006             if ((sigaction(sig, &sa, NULL) < 0))
3007                 if (errno != EINVAL)
3008                     return -1;
3009         }
3010     }
3011 #endif
3012 
3013     return 0;
3014 }
3015 
pa_set_env(const char * key,const char * value)3016 void pa_set_env(const char *key, const char *value) {
3017     pa_assert(key);
3018     pa_assert(value);
3019 
3020     /* This is not thread-safe */
3021 
3022 #ifdef OS_IS_WIN32
3023     int kl = strlen(key);
3024     int vl = strlen(value);
3025     char *tmp = pa_xmalloc(kl+vl+2);
3026     memcpy(tmp, key, kl);
3027     memcpy(tmp+kl+1, value, vl);
3028     tmp[kl] = '=';
3029     tmp[kl+1+vl] = '\0';
3030     putenv(tmp);
3031     /* Even though it should be safe to free it on Windows, we don't want to
3032      * rely on undocumented behaviour. */
3033 #else
3034     setenv(key, value, 1);
3035 #endif
3036 }
3037 
pa_unset_env(const char * key)3038 void pa_unset_env(const char *key) {
3039     pa_assert(key);
3040 
3041     /* This is not thread-safe */
3042 
3043 #ifdef OS_IS_WIN32
3044     int kl = strlen(key);
3045     char *tmp = pa_xmalloc(kl+2);
3046     memcpy(tmp, key, kl);
3047     tmp[kl] = '=';
3048     tmp[kl+1] = '\0';
3049     putenv(tmp);
3050     /* Even though it should be safe to free it on Windows, we don't want to
3051      * rely on undocumented behaviour. */
3052 #else
3053     unsetenv(key);
3054 #endif
3055 }
3056 
pa_set_env_and_record(const char * key,const char * value)3057 void pa_set_env_and_record(const char *key, const char *value) {
3058     pa_assert(key);
3059     pa_assert(value);
3060 
3061     /* This is not thread-safe */
3062 
3063     pa_set_env(key, value);
3064     recorded_env = pa_strlist_prepend(recorded_env, key);
3065 }
3066 
pa_unset_env_recorded(void)3067 void pa_unset_env_recorded(void) {
3068 
3069     /* This is not thread-safe */
3070 
3071     for (;;) {
3072         char *s;
3073 
3074         recorded_env = pa_strlist_pop(recorded_env, &s);
3075 
3076         if (!s)
3077             break;
3078 
3079         pa_unset_env(s);
3080         pa_xfree(s);
3081     }
3082 }
3083 
pa_in_system_mode(void)3084 bool pa_in_system_mode(void) {
3085     const char *e;
3086 
3087     if (!(e = getenv("PULSE_SYSTEM")))
3088         return false;
3089 
3090     return !!atoi(e);
3091 }
3092 
3093 /* Checks a delimiters-separated list of words in haystack for needle */
pa_str_in_list(const char * haystack,const char * delimiters,const char * needle)3094 bool pa_str_in_list(const char *haystack, const char *delimiters, const char *needle) {
3095     char *s;
3096     const char *state = NULL;
3097 
3098     if (!haystack || !needle)
3099         return false;
3100 
3101     while ((s = pa_split(haystack, delimiters, &state))) {
3102         if (pa_streq(needle, s)) {
3103             pa_xfree(s);
3104             return true;
3105         }
3106 
3107         pa_xfree(s);
3108     }
3109 
3110     return false;
3111 }
3112 
3113 /* Checks a whitespace-separated list of words in haystack for needle */
pa_str_in_list_spaces(const char * haystack,const char * needle)3114 bool pa_str_in_list_spaces(const char *haystack, const char *needle) {
3115     const char *s;
3116     size_t n;
3117     const char *state = NULL;
3118 
3119     if (!haystack || !needle)
3120         return false;
3121 
3122     while ((s = pa_split_spaces_in_place(haystack, &n, &state))) {
3123         if (pa_strneq(needle, s, n))
3124             return true;
3125     }
3126 
3127     return false;
3128 }
3129 
pa_str_strip_suffix(const char * str,const char * suffix)3130 char* pa_str_strip_suffix(const char *str, const char *suffix) {
3131     size_t str_l, suf_l, prefix;
3132     char *ret;
3133 
3134     pa_assert(str);
3135     pa_assert(suffix);
3136 
3137     str_l = strlen(str);
3138     suf_l = strlen(suffix);
3139 
3140     if (str_l < suf_l)
3141         return NULL;
3142 
3143     prefix = str_l - suf_l;
3144 
3145     if (!pa_streq(&str[prefix], suffix))
3146         return NULL;
3147 
3148     ret = pa_xmalloc(prefix + 1);
3149 
3150     strncpy(ret, str, prefix);
3151     ret[prefix] = '\0';
3152 
3153     return ret;
3154 }
3155 
pa_get_user_name_malloc(void)3156 char *pa_get_user_name_malloc(void) {
3157     ssize_t k;
3158     char *u;
3159 
3160 #ifdef _SC_LOGIN_NAME_MAX
3161     k = (ssize_t) sysconf(_SC_LOGIN_NAME_MAX);
3162 
3163     if (k <= 0)
3164 #endif
3165         k = 32;
3166 
3167     u = pa_xnew(char, k+1);
3168 
3169     if (!(pa_get_user_name(u, k))) {
3170         pa_xfree(u);
3171         return NULL;
3172     }
3173 
3174     return u;
3175 }
3176 
pa_get_host_name_malloc(void)3177 char *pa_get_host_name_malloc(void) {
3178     size_t l;
3179 
3180     l = 100;
3181     for (;;) {
3182         char *c;
3183 
3184         c = pa_xmalloc(l);
3185 
3186         if (!pa_get_host_name(c, l)) {
3187 
3188             if (errno != EINVAL && errno != ENAMETOOLONG)
3189                 break;
3190 
3191         } else if (strlen(c) < l-1) {
3192             char *u;
3193 
3194             if (*c == 0) {
3195                 pa_xfree(c);
3196                 break;
3197             }
3198 
3199             u = pa_utf8_filter(c);
3200             pa_xfree(c);
3201             return u;
3202         }
3203 
3204         /* Hmm, the hostname is as long the space we offered the
3205          * function, we cannot know if it fully fit in, so let's play
3206          * safe and retry. */
3207 
3208         pa_xfree(c);
3209         l *= 2;
3210     }
3211 
3212     return NULL;
3213 }
3214 
pa_machine_id(void)3215 char *pa_machine_id(void) {
3216     FILE *f;
3217     char *h;
3218 
3219     /* The returned value is supposed be some kind of ascii identifier
3220      * that is unique and stable across reboots. First we try if the machine-id
3221      * file is available. If it's available, that's great, since it provides an
3222      * identifier that suits our needs perfectly. If it's not, we fall back to
3223      * the hostname, which is not as good, since it can change over time. */
3224 
3225     /* We search for the machine-id file from four locations. The first two are
3226      * relative to the configured installation prefix, but if we're installed
3227      * under /usr/local, for example, it's likely that the machine-id won't be
3228      * found there, so we also try the hardcoded paths.
3229      *
3230      * PA_MACHINE_ID or PA_MACHINE_ID_FALLBACK might exist on a Windows system,
3231      * but the last two hardcoded paths certainly don't, hence we don't try
3232      * them on Windows. */
3233     if ((f = pa_fopen_cloexec(PA_MACHINE_ID, "r")) ||
3234         (f = pa_fopen_cloexec(PA_MACHINE_ID_FALLBACK, "r")) ||
3235 #if !defined(OS_IS_WIN32)
3236         (f = pa_fopen_cloexec("/etc/machine-id", "r")) ||
3237         (f = pa_fopen_cloexec("/var/lib/dbus/machine-id", "r"))
3238 #else
3239         false
3240 #endif
3241         ) {
3242         char ln[34] = "", *r;
3243 
3244         r = fgets(ln, sizeof(ln)-1, f);
3245         fclose(f);
3246 
3247         pa_strip_nl(ln);
3248 
3249         if (r && ln[0])
3250             return pa_utf8_filter(ln);
3251     }
3252 
3253     if ((h = pa_get_host_name_malloc()))
3254         return h;
3255 
3256 #if !defined(OS_IS_WIN32) && !defined(__ANDROID__)
3257     /* If no hostname was set we use the POSIX hostid. It's usually
3258      * the IPv4 address.  Might not be that stable. */
3259     return pa_sprintf_malloc("%08lx", (unsigned long) gethostid());
3260 #else
3261     return NULL;
3262 #endif
3263 }
3264 
pa_session_id(void)3265 char *pa_session_id(void) {
3266     const char *e;
3267 
3268     e = getenv("XDG_SESSION_ID");
3269     if (!e)
3270         return NULL;
3271 
3272     return pa_utf8_filter(e);
3273 }
3274 
pa_uname_string(void)3275 char *pa_uname_string(void) {
3276 #ifdef HAVE_UNAME
3277     struct utsname u;
3278 
3279     pa_assert_se(uname(&u) >= 0);
3280 
3281     return pa_sprintf_malloc("%s %s %s %s", u.sysname, u.machine, u.release, u.version);
3282 #endif
3283 #ifdef OS_IS_WIN32
3284     OSVERSIONINFO i;
3285 
3286     pa_zero(i);
3287     i.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
3288     pa_assert_se(GetVersionEx(&i));
3289 
3290     return pa_sprintf_malloc("Windows %lu.%lu (%lu) %s", i.dwMajorVersion, i.dwMinorVersion, i.dwBuildNumber, i.szCSDVersion);
3291 #endif
3292 }
3293 
3294 #ifdef HAVE_VALGRIND_MEMCHECK_H
pa_in_valgrind(void)3295 bool pa_in_valgrind(void) {
3296     static int b = 0;
3297 
3298     /* To make heisenbugs a bit simpler to find we check for $VALGRIND
3299      * here instead of really checking whether we run in valgrind or
3300      * not. */
3301 
3302     if (b < 1)
3303         b = getenv("VALGRIND") ? 2 : 1;
3304 
3305     return b > 1;
3306 }
3307 #endif
3308 
pa_gcd(unsigned a,unsigned b)3309 unsigned pa_gcd(unsigned a, unsigned b) {
3310 
3311     while (b > 0) {
3312         unsigned t = b;
3313         b = a % b;
3314         a = t;
3315     }
3316 
3317     return a;
3318 }
3319 
pa_reduce(unsigned * num,unsigned * den)3320 void pa_reduce(unsigned *num, unsigned *den) {
3321 
3322     unsigned gcd = pa_gcd(*num, *den);
3323 
3324     if (gcd <= 0)
3325         return;
3326 
3327     *num /= gcd;
3328     *den /= gcd;
3329 
3330     pa_assert(pa_gcd(*num, *den) == 1);
3331 }
3332 
pa_ncpus(void)3333 unsigned pa_ncpus(void) {
3334     long ncpus;
3335 
3336 #ifdef _SC_NPROCESSORS_ONLN
3337     ncpus = sysconf(_SC_NPROCESSORS_ONLN);
3338 #else
3339     ncpus = 1;
3340 #endif
3341 
3342     return ncpus <= 0 ? 1 : (unsigned) ncpus;
3343 }
3344 
pa_replace(const char * s,const char * a,const char * b)3345 char *pa_replace(const char*s, const char*a, const char *b) {
3346     pa_strbuf *sb;
3347     size_t an;
3348 
3349     pa_assert(s);
3350     pa_assert(a);
3351     pa_assert(*a);
3352     pa_assert(b);
3353 
3354     an = strlen(a);
3355     sb = pa_strbuf_new();
3356 
3357     for (;;) {
3358         const char *p;
3359 
3360         if (!(p = strstr(s, a)))
3361             break;
3362 
3363         pa_strbuf_putsn(sb, s, p-s);
3364         pa_strbuf_puts(sb, b);
3365         s = p + an;
3366     }
3367 
3368     pa_strbuf_puts(sb, s);
3369 
3370     return pa_strbuf_to_string_free(sb);
3371 }
3372 
pa_escape(const char * p,const char * chars)3373 char *pa_escape(const char *p, const char *chars) {
3374     const char *s;
3375     const char *c;
3376     char *out_string, *output;
3377     int char_count = strlen(p);
3378 
3379     /* Maximum number of characters in output string
3380      * including trailing 0. */
3381     char_count = 2 * char_count + 1;
3382 
3383     /* allocate output string */
3384     out_string = pa_xmalloc(char_count);
3385     output = out_string;
3386 
3387     /* write output string */
3388     for (s = p; *s; ++s) {
3389         if (*s == '\\')
3390             *output++ = '\\';
3391         else if (chars) {
3392             for (c = chars; *c; ++c) {
3393                 if (*s == *c) {
3394                     *output++ = '\\';
3395                     break;
3396                 }
3397             }
3398         }
3399         *output++ = *s;
3400     }
3401 
3402     *output = 0;
3403 
3404     /* Remove trailing garbage */
3405     output = pa_xstrdup(out_string);
3406 
3407     pa_xfree(out_string);
3408     return output;
3409 }
3410 
pa_unescape(char * p)3411 char *pa_unescape(char *p) {
3412     char *s, *d;
3413     bool escaped = false;
3414 
3415     for (s = p, d = p; *s; s++) {
3416         if (!escaped && *s == '\\') {
3417             escaped = true;
3418             continue;
3419         }
3420 
3421         *(d++) = *s;
3422         escaped = false;
3423     }
3424 
3425     *d = 0;
3426 
3427     return p;
3428 }
3429 
pa_realpath(const char * path)3430 char *pa_realpath(const char *path) {
3431     char *t;
3432     pa_assert(path);
3433 
3434     /* We want only absolute paths */
3435     if (path[0] != '/') {
3436         errno = EINVAL;
3437         return NULL;
3438     }
3439 
3440 #if defined(__GLIBC__)
3441     {
3442         char *r;
3443 
3444         if (!(r = realpath(path, NULL)))
3445             return NULL;
3446 
3447         /* We copy this here in case our pa_xmalloc() is not
3448          * implemented on top of libc malloc() */
3449         t = pa_xstrdup(r);
3450         pa_xfree(r);
3451     }
3452 #elif defined(PATH_MAX)
3453     {
3454         char *path_buf;
3455         path_buf = pa_xmalloc(PATH_MAX);
3456 
3457 #if defined(OS_IS_WIN32)
3458         if (!(t = _fullpath(path_buf, path, _MAX_PATH))) {
3459             pa_xfree(path_buf);
3460             return NULL;
3461         }
3462 #else
3463         if (!(t = realpath(path, path_buf))) {
3464             pa_xfree(path_buf);
3465             return NULL;
3466         }
3467 #endif
3468     }
3469 #else
3470 #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."
3471 #endif
3472 
3473     return t;
3474 }
3475 
pa_disable_sigpipe(void)3476 void pa_disable_sigpipe(void) {
3477 
3478 #ifdef SIGPIPE
3479     struct sigaction sa;
3480 
3481     pa_zero(sa);
3482 
3483     if (sigaction(SIGPIPE, NULL, &sa) < 0) {
3484         pa_log("sigaction(): %s", pa_cstrerror(errno));
3485         return;
3486     }
3487 
3488     sa.sa_handler = SIG_IGN;
3489 
3490     if (sigaction(SIGPIPE, &sa, NULL) < 0) {
3491         pa_log("sigaction(): %s", pa_cstrerror(errno));
3492         return;
3493     }
3494 #endif
3495 }
3496 
pa_xfreev(void ** a)3497 void pa_xfreev(void**a) {
3498     void **p;
3499 
3500     if (!a)
3501         return;
3502 
3503     for (p = a; *p; p++)
3504         pa_xfree(*p);
3505 
3506     pa_xfree(a);
3507 }
3508 
pa_split_spaces_strv(const char * s)3509 char **pa_split_spaces_strv(const char *s) {
3510     char **t, *e;
3511     unsigned i = 0, n = 8;
3512     const char *state = NULL;
3513 
3514     t = pa_xnew(char*, n);
3515     while ((e = pa_split_spaces(s, &state))) {
3516         t[i++] = e;
3517 
3518         if (i >= n) {
3519             n *= 2;
3520             t = pa_xrenew(char*, t, n);
3521         }
3522     }
3523 
3524     if (i <= 0) {
3525         pa_xfree(t);
3526         return NULL;
3527     }
3528 
3529     t[i] = NULL;
3530     return t;
3531 }
3532 
pa_maybe_prefix_path(const char * path,const char * prefix)3533 char* pa_maybe_prefix_path(const char *path, const char *prefix) {
3534     pa_assert(path);
3535 
3536     if (pa_is_path_absolute(path))
3537         return pa_xstrdup(path);
3538 
3539     return pa_sprintf_malloc("%s" PA_PATH_SEP "%s", prefix, path);
3540 }
3541 
pa_pipe_buf(int fd)3542 size_t pa_pipe_buf(int fd) {
3543 
3544 #ifdef _PC_PIPE_BUF
3545     long n;
3546 
3547     if ((n = fpathconf(fd, _PC_PIPE_BUF)) >= 0)
3548         return (size_t) n;
3549 #endif
3550 
3551 #ifdef PIPE_BUF
3552     return PIPE_BUF;
3553 #else
3554     return 4096;
3555 #endif
3556 }
3557 
pa_reset_personality(void)3558 void pa_reset_personality(void) {
3559 
3560 #if defined(__linux__) && !defined(__ANDROID__)
3561     if (personality(PER_LINUX) < 0)
3562         pa_log_warn("Uh, personality() failed: %s", pa_cstrerror(errno));
3563 #endif
3564 
3565 }
3566 
pa_run_from_build_tree(void)3567 bool pa_run_from_build_tree(void) {
3568     static bool b = false;
3569 
3570 #ifdef HAVE_RUNNING_FROM_BUILD_TREE
3571     char *rp;
3572     PA_ONCE_BEGIN {
3573         if ((rp = pa_readlink("/proc/self/exe"))) {
3574             b = pa_startswith(rp, PA_BUILDDIR);
3575             pa_xfree(rp);
3576         }
3577     } PA_ONCE_END;
3578 #endif
3579 
3580     return b;
3581 }
3582 
pa_get_temp_dir(void)3583 const char *pa_get_temp_dir(void) {
3584     const char *t;
3585 
3586     if ((t = getenv("TMPDIR")) &&
3587         pa_is_path_absolute(t))
3588         return t;
3589 
3590     if ((t = getenv("TMP")) &&
3591         pa_is_path_absolute(t))
3592         return t;
3593 
3594     if ((t = getenv("TEMP")) &&
3595         pa_is_path_absolute(t))
3596         return t;
3597 
3598     if ((t = getenv("TEMPDIR")) &&
3599         pa_is_path_absolute(t))
3600         return t;
3601 
3602     return "/tmp";
3603 }
3604 
pa_open_cloexec(const char * fn,int flags,mode_t mode)3605 int pa_open_cloexec(const char *fn, int flags, mode_t mode) {
3606     int fd;
3607 
3608 #ifdef O_NOCTTY
3609     flags |= O_NOCTTY;
3610 #endif
3611 
3612 #ifdef O_CLOEXEC
3613     if ((fd = open(fn, flags|O_CLOEXEC, mode)) >= 0)
3614         goto finish;
3615 
3616     if (errno != EINVAL)
3617         return fd;
3618 #endif
3619 
3620     if ((fd = open(fn, flags, mode)) >= 0)
3621         goto finish;
3622 
3623     /* return error */
3624     return fd;
3625 
3626 finish:
3627     /* Some implementations might simply ignore O_CLOEXEC if it is not
3628      * understood, make sure FD_CLOEXEC is enabled anyway */
3629 
3630     pa_make_fd_cloexec(fd);
3631     return fd;
3632 }
3633 
pa_socket_cloexec(int domain,int type,int protocol)3634 int pa_socket_cloexec(int domain, int type, int protocol) {
3635     int fd;
3636 
3637 #ifdef SOCK_CLOEXEC
3638     if ((fd = socket(domain, type | SOCK_CLOEXEC, protocol)) >= 0)
3639         goto finish;
3640 
3641     if (errno != EINVAL)
3642         return fd;
3643 #endif
3644 
3645     if ((fd = socket(domain, type, protocol)) >= 0)
3646         goto finish;
3647 
3648     /* return error */
3649     return fd;
3650 
3651 finish:
3652     /* Some implementations might simply ignore SOCK_CLOEXEC if it is
3653      * not understood, make sure FD_CLOEXEC is enabled anyway */
3654 
3655     pa_make_fd_cloexec(fd);
3656     return fd;
3657 }
3658 
pa_pipe_cloexec(int pipefd[2])3659 int pa_pipe_cloexec(int pipefd[2]) {
3660     int r;
3661 
3662 #ifdef HAVE_PIPE2
3663     if ((r = pipe2(pipefd, O_CLOEXEC)) >= 0)
3664         goto finish;
3665 
3666     if (errno == EMFILE) {
3667         pa_log_error("The per-process limit on the number of open file descriptors has been reached.");
3668         return r;
3669     }
3670 
3671     if (errno == ENFILE) {
3672         pa_log_error("The system-wide limit on the total number of open files has been reached.");
3673         return r;
3674     }
3675 
3676     if (errno != EINVAL && errno != ENOSYS)
3677         return r;
3678 
3679 #endif
3680 
3681     if ((r = pipe(pipefd)) >= 0)
3682         goto finish;
3683 
3684     if (errno == EMFILE) {
3685         pa_log_error("The per-process limit on the number of open file descriptors has been reached.");
3686         return r;
3687     }
3688 
3689     if (errno == ENFILE) {
3690         pa_log_error("The system-wide limit on the total number of open files has been reached.");
3691         return r;
3692     }
3693 
3694     /* return error */
3695     return r;
3696 
3697 finish:
3698     pa_make_fd_cloexec(pipefd[0]);
3699     pa_make_fd_cloexec(pipefd[1]);
3700 
3701     return 0;
3702 }
3703 
pa_accept_cloexec(int sockfd,struct sockaddr * addr,socklen_t * addrlen)3704 int pa_accept_cloexec(int sockfd, struct sockaddr *addr, socklen_t *addrlen) {
3705     int fd;
3706 
3707     errno = 0;
3708 
3709 #ifdef HAVE_ACCEPT4
3710     if ((fd = accept4(sockfd, addr, addrlen, SOCK_CLOEXEC)) >= 0)
3711         goto finish;
3712 
3713     if (errno != EINVAL && errno != ENOSYS)
3714         return fd;
3715 
3716 #endif
3717 
3718 #ifdef HAVE_PACCEPT
3719     if ((fd = paccept(sockfd, addr, addrlen, NULL, SOCK_CLOEXEC)) >= 0)
3720         goto finish;
3721 #endif
3722 
3723     if ((fd = accept(sockfd, addr, addrlen)) >= 0)
3724         goto finish;
3725 
3726     /* return error */
3727     return fd;
3728 
3729 finish:
3730     pa_make_fd_cloexec(fd);
3731     return fd;
3732 }
3733 
pa_fopen_cloexec(const char * path,const char * mode)3734 FILE* pa_fopen_cloexec(const char *path, const char *mode) {
3735     FILE *f;
3736     char *m;
3737 
3738     m = pa_sprintf_malloc("%se", mode);
3739 
3740     errno = 0;
3741     if ((f = fopen(path, m))) {
3742         pa_xfree(m);
3743         goto finish;
3744     }
3745 
3746     pa_xfree(m);
3747 
3748     if (errno != EINVAL)
3749         return NULL;
3750 
3751     if (!(f = fopen(path, mode)))
3752         return NULL;
3753 
3754 finish:
3755     pa_make_fd_cloexec(fileno(f));
3756     return f;
3757 }
3758 
pa_nullify_stdfds(void)3759 void pa_nullify_stdfds(void) {
3760 
3761 #ifndef OS_IS_WIN32
3762         pa_close(STDIN_FILENO);
3763         pa_close(STDOUT_FILENO);
3764         pa_close(STDERR_FILENO);
3765 
3766         pa_assert_se(open("/dev/null", O_RDONLY) == STDIN_FILENO);
3767         pa_assert_se(open("/dev/null", O_WRONLY) == STDOUT_FILENO);
3768         pa_assert_se(open("/dev/null", O_WRONLY) == STDERR_FILENO);
3769 #else
3770         FreeConsole();
3771 #endif
3772 
3773 }
3774 
pa_read_line_from_file(const char * fn)3775 char *pa_read_line_from_file(const char *fn) {
3776     FILE *f;
3777     char ln[256] = "", *r;
3778 
3779     if (!(f = pa_fopen_cloexec(fn, "r")))
3780         return NULL;
3781 
3782     r = fgets(ln, sizeof(ln)-1, f);
3783     fclose(f);
3784 
3785     if (!r) {
3786         errno = EIO;
3787         return NULL;
3788     }
3789 
3790     pa_strip_nl(ln);
3791     return pa_xstrdup(ln);
3792 }
3793 
pa_running_in_vm(void)3794 bool pa_running_in_vm(void) {
3795 
3796 #if defined(__i386__) || defined(__x86_64__)
3797 
3798     /* Both CPUID and DMI are x86 specific interfaces... */
3799 
3800 #ifdef HAVE_CPUID_H
3801     unsigned int eax, ebx, ecx, edx;
3802 #endif
3803 
3804 #ifdef __linux__
3805     const char *const dmi_vendors[] = {
3806         "/sys/class/dmi/id/sys_vendor",
3807         "/sys/class/dmi/id/board_vendor",
3808         "/sys/class/dmi/id/bios_vendor"
3809     };
3810 
3811     unsigned i;
3812 
3813     for (i = 0; i < PA_ELEMENTSOF(dmi_vendors); i++) {
3814         char *s;
3815 
3816         if ((s = pa_read_line_from_file(dmi_vendors[i]))) {
3817 
3818             if (pa_startswith(s, "QEMU") ||
3819                 /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
3820                 pa_startswith(s, "VMware") ||
3821                 pa_startswith(s, "VMW") ||
3822                 pa_startswith(s, "Microsoft Corporation") ||
3823                 pa_startswith(s, "innotek GmbH") ||
3824                 pa_startswith(s, "Xen")) {
3825 
3826                 pa_xfree(s);
3827                 return true;
3828             }
3829 
3830             pa_xfree(s);
3831         }
3832     }
3833 
3834 #endif
3835 
3836 #ifdef HAVE_CPUID_H
3837 
3838     /* Hypervisors provide presence on 0x1 cpuid leaf.
3839      * http://lwn.net/Articles/301888/ */
3840     if (__get_cpuid(1, &eax, &ebx, &ecx, &edx) == 0)
3841         return false;
3842 
3843     if (ecx & 0x80000000)
3844         return true;
3845 
3846 #endif /* HAVE_CPUID_H */
3847 
3848 #endif /* defined(__i386__) || defined(__x86_64__) */
3849 
3850     return false;
3851 }
3852 
pa_page_size(void)3853 size_t pa_page_size(void) {
3854 #if defined(PAGE_SIZE)
3855     return PAGE_SIZE;
3856 #elif defined(PAGESIZE)
3857     return PAGESIZE;
3858 #elif defined(HAVE_SYSCONF)
3859     static size_t page_size = 4096; /* Let's hope it's like x86. */
3860 
3861     PA_ONCE_BEGIN {
3862         long ret = sysconf(_SC_PAGE_SIZE);
3863         if (ret > 0)
3864             page_size = ret;
3865     } PA_ONCE_END;
3866 
3867     return page_size;
3868 #else
3869     return 4096;
3870 #endif
3871 }
3872