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