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