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