]> code.delx.au - pulseaudio/blob - src/pulsecore/core-util.c
merge 'lennart' branch back into trunk.
[pulseaudio] / src / pulsecore / core-util.c
1 /* $Id$ */
2
3 /***
4 This file is part of PulseAudio.
5
6 Copyright 2004-2006 Lennart Poettering
7 Copyright 2004 Joe Marcus Clarke
8 Copyright 2006-2007 Pierre Ossman <ossman@cendio.se> for Cendio AB
9
10 PulseAudio is free software; you can redistribute it and/or modify
11 it under the terms of the GNU Lesser General Public License as
12 published by the Free Software Foundation; either version 2.1 of the
13 License, or (at your option) any later version.
14
15 PulseAudio is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Lesser General Public License for more details.
19
20 You should have received a copy of the GNU Lesser General Public
21 License along with PulseAudio; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23 USA.
24 ***/
25
26 #ifdef HAVE_CONFIG_H
27 #include <config.h>
28 #endif
29
30 #include <stdarg.h>
31 #include <stdlib.h>
32 #include <signal.h>
33 #include <errno.h>
34 #include <string.h>
35 #include <stdio.h>
36 #include <fcntl.h>
37 #include <unistd.h>
38 #include <limits.h>
39 #include <time.h>
40 #include <ctype.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <sys/time.h>
44
45 #ifdef HAVE_STRTOF_L
46 #include <locale.h>
47 #endif
48
49 #ifdef HAVE_SCHED_H
50 #include <sched.h>
51 #endif
52
53 #ifdef HAVE_SYS_RESOURCE_H
54 #include <sys/resource.h>
55 #endif
56
57 #ifdef HAVE_SYS_CAPABILITY_H
58 #include <sys/capability.h>
59 #endif
60
61 #ifdef HAVE_SYS_MMAN_H
62 #include <sys/mman.h>
63 #endif
64
65 #ifdef HAVE_PTHREAD
66 #include <pthread.h>
67 #endif
68
69 #ifdef HAVE_NETDB_H
70 #include <netdb.h>
71 #endif
72
73 #ifdef HAVE_WINDOWS_H
74 #include <windows.h>
75 #endif
76
77 #ifdef HAVE_PWD_H
78 #include <pwd.h>
79 #endif
80
81 #ifdef HAVE_GRP_H
82 #include <grp.h>
83 #endif
84
85 #ifdef HAVE_LIBSAMPLERATE
86 #include <samplerate.h>
87 #endif
88
89 #include <pulse/xmalloc.h>
90 #include <pulse/util.h>
91 #include <pulse/utf8.h>
92
93 #include <pulsecore/core-error.h>
94 #include <pulsecore/winsock.h>
95 #include <pulsecore/log.h>
96 #include <pulsecore/macro.h>
97 #include <pulsecore/thread.h>
98
99 #include "core-util.h"
100
101 /* Not all platforms have this */
102 #ifndef MSG_NOSIGNAL
103 #define MSG_NOSIGNAL 0
104 #endif
105
106 #ifndef OS_IS_WIN32
107 #define PA_USER_RUNTIME_PATH_PREFIX "/tmp/pulse-"
108 #else
109 #define PA_USER_RUNTIME_PATH_PREFIX "%TEMP%\\pulse-"
110 #endif
111
112 #ifdef OS_IS_WIN32
113
114 #define PULSE_ROOTENV "PULSE_ROOT"
115
116 int pa_set_root(HANDLE handle) {
117 char library_path[MAX_PATH + sizeof(PULSE_ROOTENV) + 1], *sep;
118
119 strcpy(library_path, PULSE_ROOTENV "=");
120
121 if (!GetModuleFileName(handle, library_path + sizeof(PULSE_ROOTENV), MAX_PATH))
122 return 0;
123
124 sep = strrchr(library_path, PA_PATH_SEP_CHAR);
125 if (sep)
126 *sep = '\0';
127
128 if (_putenv(library_path) < 0)
129 return 0;
130
131 return 1;
132 }
133
134 #endif
135
136 /** Make a file descriptor nonblock. Doesn't do any error checking */
137 void pa_make_fd_nonblock(int fd) {
138
139 #ifdef O_NONBLOCK
140 int v;
141 pa_assert(fd >= 0);
142
143 pa_assert_se((v = fcntl(fd, F_GETFL)) >= 0);
144
145 if (!(v & O_NONBLOCK))
146 pa_assert_se(fcntl(fd, F_SETFL, v|O_NONBLOCK) >= 0);
147
148 #elif defined(OS_IS_WIN32)
149 u_long arg = 1;
150 if (ioctlsocket(fd, FIONBIO, &arg) < 0) {
151 pa_assert_se(WSAGetLastError() == WSAENOTSOCK);
152 pa_log_warn("Only sockets can be made non-blocking!");
153 }
154 #else
155 pa_log_warn("Non-blocking I/O not supported.!");
156 #endif
157
158 }
159
160 /* Set the FD_CLOEXEC flag for a fd */
161 void pa_make_fd_cloexec(int fd) {
162
163 #ifdef FD_CLOEXEC
164 int v;
165 pa_assert(fd >= 0);
166
167 pa_assert_se((v = fcntl(fd, F_GETFD, 0)) >= 0);
168
169 if (!(v & FD_CLOEXEC))
170 pa_assert_se(fcntl(fd, F_SETFD, v|FD_CLOEXEC) >= 0);
171 #endif
172
173 }
174
175 /** Creates a directory securely */
176 int pa_make_secure_dir(const char* dir, mode_t m, uid_t uid, gid_t gid) {
177 struct stat st;
178 int r;
179
180 pa_assert(dir);
181
182 #ifdef OS_IS_WIN32
183 r = mkdir(dir);
184 #else
185 {
186 mode_t u;
187 u = umask(~m);
188 r = mkdir(dir, m);
189 umask(u);
190 }
191 #endif
192
193 if (r < 0 && errno != EEXIST)
194 return -1;
195
196 #ifdef HAVE_CHOWN
197 if (uid == (uid_t)-1)
198 uid = getuid();
199 if (gid == (gid_t)-1)
200 gid = getgid();
201 (void) chown(dir, uid, gid);
202 #endif
203
204 #ifdef HAVE_CHMOD
205 chmod(dir, m);
206 #endif
207
208 #ifdef HAVE_LSTAT
209 if (lstat(dir, &st) < 0)
210 #else
211 if (stat(dir, &st) < 0)
212 #endif
213 goto fail;
214
215 #ifndef OS_IS_WIN32
216 if (!S_ISDIR(st.st_mode) ||
217 (st.st_uid != uid) ||
218 (st.st_gid != gid) ||
219 ((st.st_mode & 0777) != m)) {
220 errno = EACCES;
221 goto fail;
222 }
223 #else
224 pa_log_warn("secure directory creation not supported on Win32.");
225 #endif
226
227 return 0;
228
229 fail:
230 rmdir(dir);
231 return -1;
232 }
233
234 /* Return a newly allocated sting containing the parent directory of the specified file */
235 char *pa_parent_dir(const char *fn) {
236 char *slash, *dir = pa_xstrdup(fn);
237
238 if ((slash = (char*) pa_path_get_filename(dir)) == dir) {
239 pa_xfree(dir);
240 return NULL;
241 }
242
243 *(slash-1) = 0;
244 return dir;
245 }
246
247 /* Creates a the parent directory of the specified path securely */
248 int pa_make_secure_parent_dir(const char *fn, mode_t m, uid_t uid, gid_t gid) {
249 int ret = -1;
250 char *dir;
251
252 if (!(dir = pa_parent_dir(fn)))
253 goto finish;
254
255 if (pa_make_secure_dir(dir, m, uid, gid) < 0)
256 goto finish;
257
258 ret = 0;
259
260 finish:
261 pa_xfree(dir);
262 return ret;
263 }
264
265 /** Platform independent read function. Necessary since not all
266 * systems treat all file descriptors equal. If type is
267 * non-NULL it is used to cache the type of the fd. This is
268 * useful for making sure that only a single syscall is executed per
269 * function call. The variable pointed to should be initialized to 0
270 * by the caller. */
271 ssize_t pa_read(int fd, void *buf, size_t count, int *type) {
272
273 #ifdef OS_IS_WIN32
274
275 if (!type || *type == 0) {
276 ssize_t r;
277
278 if ((r = recv(fd, buf, count, 0)) >= 0)
279 return r;
280
281 if (WSAGetLastError() != WSAENOTSOCK) {
282 errno = WSAGetLastError();
283 return r;
284 }
285
286 if (type)
287 *type = 1;
288 }
289
290 #endif
291
292 return read(fd, buf, count);
293 }
294
295 /** Similar to pa_read(), but handles writes */
296 ssize_t pa_write(int fd, const void *buf, size_t count, int *type) {
297
298 if (!type || *type == 0) {
299 ssize_t r;
300
301 if ((r = send(fd, buf, count, MSG_NOSIGNAL)) >= 0)
302 return r;
303
304 #ifdef OS_IS_WIN32
305 if (WSAGetLastError() != WSAENOTSOCK) {
306 errno = WSAGetLastError();
307 return r;
308 }
309 #else
310 if (errno != ENOTSOCK)
311 return r;
312 #endif
313
314 if (type)
315 *type = 1;
316 }
317
318 return write(fd, buf, count);
319 }
320
321 /** Calls read() in a loop. Makes sure that as much as 'size' bytes,
322 * unless EOF is reached or an error occured */
323 ssize_t pa_loop_read(int fd, void*data, size_t size, int *type) {
324 ssize_t ret = 0;
325 int _type;
326
327 pa_assert(fd >= 0);
328 pa_assert(data);
329 pa_assert(size);
330
331 if (!type) {
332 _type = 0;
333 type = &_type;
334 }
335
336 while (size > 0) {
337 ssize_t r;
338
339 if ((r = pa_read(fd, data, size, type)) < 0)
340 return r;
341
342 if (r == 0)
343 break;
344
345 ret += r;
346 data = (uint8_t*) data + r;
347 size -= r;
348 }
349
350 return ret;
351 }
352
353 /** Similar to pa_loop_read(), but wraps write() */
354 ssize_t pa_loop_write(int fd, const void*data, size_t size, int *type) {
355 ssize_t ret = 0;
356 int _type;
357
358 pa_assert(fd >= 0);
359 pa_assert(data);
360 pa_assert(size);
361
362 if (!type) {
363 _type = 0;
364 type = &_type;
365 }
366
367 while (size > 0) {
368 ssize_t r;
369
370 if ((r = pa_write(fd, data, size, type)) < 0)
371 return r;
372
373 if (r == 0)
374 break;
375
376 ret += r;
377 data = (const uint8_t*) data + r;
378 size -= r;
379 }
380
381 return ret;
382 }
383
384 /** Platform independent read function. Necessary since not all
385 * systems treat all file descriptors equal. */
386 int pa_close(int fd) {
387
388 #ifdef OS_IS_WIN32
389 int ret;
390
391 if ((ret = closesocket(fd)) == 0)
392 return 0;
393
394 if (WSAGetLastError() != WSAENOTSOCK) {
395 errno = WSAGetLastError();
396 return ret;
397 }
398 #endif
399
400 return close(fd);
401 }
402
403 /* Print a warning messages in case that the given signal is not
404 * blocked or trapped */
405 void pa_check_signal_is_blocked(int sig) {
406 #ifdef HAVE_SIGACTION
407 struct sigaction sa;
408 sigset_t set;
409
410 /* If POSIX threads are supported use thread-aware
411 * pthread_sigmask() function, to check if the signal is
412 * blocked. Otherwise fall back to sigprocmask() */
413
414 #ifdef HAVE_PTHREAD
415 if (pthread_sigmask(SIG_SETMASK, NULL, &set) < 0) {
416 #endif
417 if (sigprocmask(SIG_SETMASK, NULL, &set) < 0) {
418 pa_log("sigprocmask(): %s", pa_cstrerror(errno));
419 return;
420 }
421 #ifdef HAVE_PTHREAD
422 }
423 #endif
424
425 if (sigismember(&set, sig))
426 return;
427
428 /* Check whether the signal is trapped */
429
430 if (sigaction(sig, NULL, &sa) < 0) {
431 pa_log("sigaction(): %s", pa_cstrerror(errno));
432 return;
433 }
434
435 if (sa.sa_handler != SIG_DFL)
436 return;
437
438 pa_log_warn("%s is not trapped. This might cause malfunction!", pa_sig2str(sig));
439 #else /* HAVE_SIGACTION */
440 pa_log_warn("%s might not be trapped. This might cause malfunction!", pa_sig2str(sig));
441 #endif
442 }
443
444 /* The following function is based on an example from the GNU libc
445 * documentation. This function is similar to GNU's asprintf(). */
446 char *pa_sprintf_malloc(const char *format, ...) {
447 int size = 100;
448 char *c = NULL;
449
450 pa_assert(format);
451
452 for(;;) {
453 int r;
454 va_list ap;
455
456 c = pa_xrealloc(c, size);
457
458 va_start(ap, format);
459 r = vsnprintf(c, size, format, ap);
460 va_end(ap);
461
462 c[size-1] = 0;
463
464 if (r > -1 && r < size)
465 return c;
466
467 if (r > -1) /* glibc 2.1 */
468 size = r+1;
469 else /* glibc 2.0 */
470 size *= 2;
471 }
472 }
473
474 /* Same as the previous function, but use a va_list instead of an
475 * ellipsis */
476 char *pa_vsprintf_malloc(const char *format, va_list ap) {
477 int size = 100;
478 char *c = NULL;
479
480 pa_assert(format);
481
482 for(;;) {
483 int r;
484 va_list aq;
485
486 c = pa_xrealloc(c, size);
487
488 va_copy(aq, ap);
489 r = vsnprintf(c, size, format, aq);
490 va_end(aq);
491
492 c[size-1] = 0;
493
494 if (r > -1 && r < size)
495 return c;
496
497 if (r > -1) /* glibc 2.1 */
498 size = r+1;
499 else /* glibc 2.0 */
500 size *= 2;
501 }
502 }
503
504 /* Similar to OpenBSD's strlcpy() function */
505 char *pa_strlcpy(char *b, const char *s, size_t l) {
506 pa_assert(b);
507 pa_assert(s);
508 pa_assert(l > 0);
509
510 strncpy(b, s, l);
511 b[l-1] = 0;
512 return b;
513 }
514
515 /* Make the current thread a realtime thread*/
516 void pa_make_realtime(void) {
517
518 #ifdef _POSIX_PRIORITY_SCHEDULING
519 struct sched_param sp;
520 int r, policy;
521
522 memset(&sp, 0, sizeof(sp));
523 policy = 0;
524
525 if ((r = pthread_getschedparam(pthread_self(), &policy, &sp)) != 0) {
526 pa_log("pthread_getschedgetparam(): %s", pa_cstrerror(r));
527 return;
528 }
529
530 sp.sched_priority = 1;
531 if ((r = pthread_setschedparam(pthread_self(), SCHED_FIFO, &sp)) != 0) {
532 pa_log_warn("pthread_setschedparam(): %s", pa_cstrerror(r));
533 return;
534 }
535
536 pa_log_info("Successfully enabled SCHED_FIFO scheduling for thread.");
537 #endif
538
539 }
540
541 #define NICE_LEVEL (-11)
542
543 /* Raise the priority of the current process as much as possible and
544 sensible: set the nice level to -15.*/
545 void pa_raise_priority(void) {
546
547 #ifdef HAVE_SYS_RESOURCE_H
548 if (setpriority(PRIO_PROCESS, 0, NICE_LEVEL) < 0)
549 pa_log_warn("setpriority(): %s", pa_cstrerror(errno));
550 else
551 pa_log_info("Successfully gained nice level %i.", NICE_LEVEL);
552 #endif
553
554 #ifdef OS_IS_WIN32
555 if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS))
556 pa_log_warn("SetPriorityClass() failed: 0x%08X", GetLastError());
557 else
558 pa_log_info("Successfully gained high priority class.");
559 #endif
560 }
561
562 /* Reset the priority to normal, inverting the changes made by
563 * pa_raise_priority() */
564 void pa_reset_priority(void) {
565 #ifdef OS_IS_WIN32
566 SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS);
567 #endif
568
569 #ifdef HAVE_SYS_RESOURCE_H
570 setpriority(PRIO_PROCESS, 0, 0);
571 #endif
572 }
573
574 /* Try to parse a boolean string value.*/
575 int pa_parse_boolean(const char *v) {
576
577 if (!strcmp(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || !strcasecmp(v, "on"))
578 return 1;
579 else if (!strcmp(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || !strcasecmp(v, "off"))
580 return 0;
581
582 return -1;
583 }
584
585 /* Split the specified string wherever one of the strings in delimiter
586 * occurs. Each time it is called returns a newly allocated string
587 * with pa_xmalloc(). The variable state points to, should be
588 * initiallized to NULL before the first call. */
589 char *pa_split(const char *c, const char *delimiter, const char**state) {
590 const char *current = *state ? *state : c;
591 size_t l;
592
593 if (!*current)
594 return NULL;
595
596 l = strcspn(current, delimiter);
597 *state = current+l;
598
599 if (**state)
600 (*state)++;
601
602 return pa_xstrndup(current, l);
603 }
604
605 /* What is interpreted as whitespace? */
606 #define WHITESPACE " \t\n"
607
608 /* Split a string into words. Otherwise similar to pa_split(). */
609 char *pa_split_spaces(const char *c, const char **state) {
610 const char *current = *state ? *state : c;
611 size_t l;
612
613 if (!*current || *c == 0)
614 return NULL;
615
616 current += strspn(current, WHITESPACE);
617 l = strcspn(current, WHITESPACE);
618
619 *state = current+l;
620
621 return pa_xstrndup(current, l);
622 }
623
624 PA_STATIC_TLS_DECLARE(signame, pa_xfree);
625
626 /* Return the name of an UNIX signal. Similar to Solaris sig2str() */
627 const char *pa_sig2str(int sig) {
628 char *t;
629
630 if (sig <= 0)
631 goto fail;
632
633 #ifdef NSIG
634 if (sig >= NSIG)
635 goto fail;
636 #endif
637
638 #ifdef HAVE_SIG2STR
639 {
640 char buf[SIG2STR_MAX];
641
642 if (sig2str(sig, buf) == 0) {
643 pa_xfree(PA_STATIC_TLS_GET(signame));
644 t = pa_sprintf_malloc("SIG%s", buf);
645 PA_STATIC_TLS_SET(signame, t);
646 return t;
647 }
648 }
649 #else
650
651 switch(sig) {
652 #ifdef SIGHUP
653 case SIGHUP: return "SIGHUP";
654 #endif
655 case SIGINT: return "SIGINT";
656 #ifdef SIGQUIT
657 case SIGQUIT: return "SIGQUIT";
658 #endif
659 case SIGILL: return "SIGULL";
660 #ifdef SIGTRAP
661 case SIGTRAP: return "SIGTRAP";
662 #endif
663 case SIGABRT: return "SIGABRT";
664 #ifdef SIGBUS
665 case SIGBUS: return "SIGBUS";
666 #endif
667 case SIGFPE: return "SIGFPE";
668 #ifdef SIGKILL
669 case SIGKILL: return "SIGKILL";
670 #endif
671 #ifdef SIGUSR1
672 case SIGUSR1: return "SIGUSR1";
673 #endif
674 case SIGSEGV: return "SIGSEGV";
675 #ifdef SIGUSR2
676 case SIGUSR2: return "SIGUSR2";
677 #endif
678 #ifdef SIGPIPE
679 case SIGPIPE: return "SIGPIPE";
680 #endif
681 #ifdef SIGALRM
682 case SIGALRM: return "SIGALRM";
683 #endif
684 case SIGTERM: return "SIGTERM";
685 #ifdef SIGSTKFLT
686 case SIGSTKFLT: return "SIGSTKFLT";
687 #endif
688 #ifdef SIGCHLD
689 case SIGCHLD: return "SIGCHLD";
690 #endif
691 #ifdef SIGCONT
692 case SIGCONT: return "SIGCONT";
693 #endif
694 #ifdef SIGSTOP
695 case SIGSTOP: return "SIGSTOP";
696 #endif
697 #ifdef SIGTSTP
698 case SIGTSTP: return "SIGTSTP";
699 #endif
700 #ifdef SIGTTIN
701 case SIGTTIN: return "SIGTTIN";
702 #endif
703 #ifdef SIGTTOU
704 case SIGTTOU: return "SIGTTOU";
705 #endif
706 #ifdef SIGURG
707 case SIGURG: return "SIGURG";
708 #endif
709 #ifdef SIGXCPU
710 case SIGXCPU: return "SIGXCPU";
711 #endif
712 #ifdef SIGXFSZ
713 case SIGXFSZ: return "SIGXFSZ";
714 #endif
715 #ifdef SIGVTALRM
716 case SIGVTALRM: return "SIGVTALRM";
717 #endif
718 #ifdef SIGPROF
719 case SIGPROF: return "SIGPROF";
720 #endif
721 #ifdef SIGWINCH
722 case SIGWINCH: return "SIGWINCH";
723 #endif
724 #ifdef SIGIO
725 case SIGIO: return "SIGIO";
726 #endif
727 #ifdef SIGPWR
728 case SIGPWR: return "SIGPWR";
729 #endif
730 #ifdef SIGSYS
731 case SIGSYS: return "SIGSYS";
732 #endif
733 }
734
735 #ifdef SIGRTMIN
736 if (sig >= SIGRTMIN && sig <= SIGRTMAX) {
737 pa_xfree(PA_STATIC_TLS_GET(signame));
738 t = pa_sprintf_malloc("SIGRTMIN+%i", sig - SIGRTMIN);
739 PA_STATIC_TLS_SET(signame, t);
740 return t;
741 }
742 #endif
743
744 #endif
745
746 fail:
747
748 pa_xfree(PA_STATIC_TLS_GET(signame));
749 t = pa_sprintf_malloc("SIG%i", sig);
750 PA_STATIC_TLS_SET(signame, t);
751 return t;
752 }
753
754 #ifdef HAVE_GRP_H
755
756 /* Check whether the specified GID and the group name match */
757 static int is_group(gid_t gid, const char *name) {
758 struct group group, *result = NULL;
759 long n;
760 void *data;
761 int r = -1;
762
763 #ifdef HAVE_GETGRGID_R
764 #ifdef _SC_GETGR_R_SIZE_MAX
765 n = sysconf(_SC_GETGR_R_SIZE_MAX);
766 #else
767 n = -1;
768 #endif
769 if (n < 0) n = 512;
770 data = pa_xmalloc(n);
771
772 if (getgrgid_r(gid, &group, data, n, &result) < 0 || !result) {
773 pa_log("getgrgid_r(%u): %s", (unsigned)gid, pa_cstrerror(errno));
774 goto finish;
775 }
776
777 r = strcmp(name, result->gr_name) == 0;
778
779 finish:
780 pa_xfree(data);
781 #else
782 /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) that do not
783 * support getgrgid_r. */
784 if ((result = getgrgid(gid)) == NULL) {
785 pa_log("getgrgid(%u): %s", gid, pa_cstrerror(errno));
786 goto finish;
787 }
788
789 r = strcmp(name, result->gr_name) == 0;
790
791 finish:
792 #endif
793
794 return r;
795 }
796
797 /* Check the current user is member of the specified group */
798 int pa_own_uid_in_group(const char *name, gid_t *gid) {
799 GETGROUPS_T *gids, tgid;
800 int n = sysconf(_SC_NGROUPS_MAX);
801 int r = -1, i;
802
803 pa_assert(n > 0);
804
805 gids = pa_xmalloc(sizeof(GETGROUPS_T)*n);
806
807 if ((n = getgroups(n, gids)) < 0) {
808 pa_log("getgroups(): %s", pa_cstrerror(errno));
809 goto finish;
810 }
811
812 for (i = 0; i < n; i++) {
813 if (is_group(gids[i], name) > 0) {
814 *gid = gids[i];
815 r = 1;
816 goto finish;
817 }
818 }
819
820 if (is_group(tgid = getgid(), name) > 0) {
821 *gid = tgid;
822 r = 1;
823 goto finish;
824 }
825
826 r = 0;
827
828 finish:
829
830 pa_xfree(gids);
831 return r;
832 }
833
834 /* Check whether the specifc user id is a member of the specified group */
835 int pa_uid_in_group(uid_t uid, const char *name) {
836 char *g_buf, *p_buf;
837 long g_n, p_n;
838 struct group grbuf, *gr;
839 char **i;
840 int r = -1;
841
842 g_n = sysconf(_SC_GETGR_R_SIZE_MAX);
843 g_buf = pa_xmalloc(g_n);
844
845 p_n = sysconf(_SC_GETPW_R_SIZE_MAX);
846 p_buf = pa_xmalloc(p_n);
847
848 if (getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr) != 0 || !gr)
849 goto finish;
850
851 r = 0;
852 for (i = gr->gr_mem; *i; i++) {
853 struct passwd pwbuf, *pw;
854
855 if (getpwnam_r(*i, &pwbuf, p_buf, (size_t) p_n, &pw) != 0 || !pw)
856 continue;
857
858 if (pw->pw_uid == uid) {
859 r = 1;
860 break;
861 }
862 }
863
864 finish:
865 pa_xfree(g_buf);
866 pa_xfree(p_buf);
867
868 return r;
869 }
870
871 /* Get the GID of a gfiven group, return (gid_t) -1 on failure. */
872 gid_t pa_get_gid_of_group(const char *name) {
873 gid_t ret = (gid_t) -1;
874 char *g_buf;
875 long g_n;
876 struct group grbuf, *gr;
877
878 g_n = sysconf(_SC_GETGR_R_SIZE_MAX);
879 g_buf = pa_xmalloc(g_n);
880
881 if (getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr) != 0 || !gr)
882 goto finish;
883
884 ret = gr->gr_gid;
885
886 finish:
887 pa_xfree(g_buf);
888 return ret;
889 }
890
891 int pa_check_in_group(gid_t g) {
892 gid_t gids[NGROUPS_MAX];
893 int r;
894
895 if ((r = getgroups(NGROUPS_MAX, gids)) < 0)
896 return -1;
897
898 for (; r > 0; r--)
899 if (gids[r-1] == g)
900 return 1;
901
902 return 0;
903 }
904
905 #else /* HAVE_GRP_H */
906
907 int pa_own_uid_in_group(const char *name, gid_t *gid) {
908 return -1;
909
910 }
911
912 int pa_uid_in_group(uid_t uid, const char *name) {
913 return -1;
914 }
915
916 gid_t pa_get_gid_of_group(const char *name) {
917 return (gid_t) -1;
918 }
919
920 int pa_check_in_group(gid_t g) {
921 return -1;
922 }
923
924 #endif
925
926 /* Lock or unlock a file entirely.
927 (advisory on UNIX, mandatory on Windows) */
928 int pa_lock_fd(int fd, int b) {
929 #ifdef F_SETLKW
930 struct flock flock;
931
932 /* Try a R/W lock first */
933
934 flock.l_type = b ? F_WRLCK : F_UNLCK;
935 flock.l_whence = SEEK_SET;
936 flock.l_start = 0;
937 flock.l_len = 0;
938
939 if (fcntl(fd, F_SETLKW, &flock) >= 0)
940 return 0;
941
942 /* Perhaps the file descriptor qas opened for read only, than try again with a read lock. */
943 if (b && errno == EBADF) {
944 flock.l_type = F_RDLCK;
945 if (fcntl(fd, F_SETLKW, &flock) >= 0)
946 return 0;
947 }
948
949 pa_log("%slock: %s", !b? "un" : "", pa_cstrerror(errno));
950 #endif
951
952 #ifdef OS_IS_WIN32
953 HANDLE h = (HANDLE)_get_osfhandle(fd);
954
955 if (b && LockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF))
956 return 0;
957 if (!b && UnlockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF))
958 return 0;
959
960 pa_log("%slock failed: 0x%08X", !b ? "un" : "", GetLastError());
961 #endif
962
963 return -1;
964 }
965
966 /* Remove trailing newlines from a string */
967 char* pa_strip_nl(char *s) {
968 pa_assert(s);
969
970 s[strcspn(s, "\r\n")] = 0;
971 return s;
972 }
973
974 /* Create a temporary lock file and lock it. */
975 int pa_lock_lockfile(const char *fn) {
976 int fd = -1;
977 pa_assert(fn);
978
979 for (;;) {
980 struct stat st;
981
982 if ((fd = open(fn, O_CREAT|O_RDWR
983 #ifdef O_NOCTTY
984 |O_NOCTTY
985 #endif
986 #ifdef O_NOFOLLOW
987 |O_NOFOLLOW
988 #endif
989 , S_IRUSR|S_IWUSR)) < 0) {
990 pa_log_warn("Failed to create lock file '%s': %s", fn, pa_cstrerror(errno));
991 goto fail;
992 }
993
994 if (pa_lock_fd(fd, 1) < 0) {
995 pa_log_warn("Failed to lock file '%s'.", fn);
996 goto fail;
997 }
998
999 if (fstat(fd, &st) < 0) {
1000 pa_log_warn("Failed to fstat() file '%s': %s", fn, pa_cstrerror(errno));
1001 goto fail;
1002 }
1003
1004 /* Check wheter the file has been removed meanwhile. When yes,
1005 * restart this loop, otherwise, we're done */
1006 if (st.st_nlink >= 1)
1007 break;
1008
1009 if (pa_lock_fd(fd, 0) < 0) {
1010 pa_log_warn("Failed to unlock file '%s'.", fn);
1011 goto fail;
1012 }
1013
1014 if (pa_close(fd) < 0) {
1015 pa_log_warn("Failed to close file '%s': %s", fn, pa_cstrerror(errno));
1016 fd = -1;
1017 goto fail;
1018 }
1019
1020 fd = -1;
1021 }
1022
1023 return fd;
1024
1025 fail:
1026
1027 if (fd >= 0)
1028 pa_close(fd);
1029
1030 return -1;
1031 }
1032
1033 /* Unlock a temporary lcok file */
1034 int pa_unlock_lockfile(const char *fn, int fd) {
1035 int r = 0;
1036 pa_assert(fn);
1037 pa_assert(fd >= 0);
1038
1039 if (unlink(fn) < 0) {
1040 pa_log_warn("Unable to remove lock file '%s': %s", fn, pa_cstrerror(errno));
1041 r = -1;
1042 }
1043
1044 if (pa_lock_fd(fd, 0) < 0) {
1045 pa_log_warn("Failed to unlock file '%s'.", fn);
1046 r = -1;
1047 }
1048
1049 if (pa_close(fd) < 0) {
1050 pa_log_warn("Failed to close '%s': %s", fn, pa_cstrerror(errno));
1051 r = -1;
1052 }
1053
1054 return r;
1055 }
1056
1057 /* Try to open a configuration file. If "env" is specified, open the
1058 * value of the specified environment variable. Otherwise look for a
1059 * file "local" in the home directory or a file "global" in global
1060 * file system. If "result" is non-NULL, a pointer to a newly
1061 * allocated buffer containing the used configuration file is
1062 * stored there.*/
1063 FILE *pa_open_config_file(const char *global, const char *local, const char *env, char **result, const char *mode) {
1064 const char *fn;
1065 char h[PATH_MAX];
1066
1067 #ifdef OS_IS_WIN32
1068 char buf[PATH_MAX];
1069
1070 if (!getenv(PULSE_ROOTENV))
1071 pa_set_root(NULL);
1072 #endif
1073
1074 if (env && (fn = getenv(env))) {
1075 #ifdef OS_IS_WIN32
1076 if (!ExpandEnvironmentStrings(fn, buf, PATH_MAX))
1077 return NULL;
1078 fn = buf;
1079 #endif
1080
1081 if (result)
1082 *result = pa_xstrdup(fn);
1083
1084 return fopen(fn, mode);
1085 }
1086
1087 if (local) {
1088 const char *e;
1089 char *lfn = NULL;
1090
1091 if ((e = getenv("PULSE_CONFIG_PATH")))
1092 fn = lfn = pa_sprintf_malloc("%s/%s", e, local);
1093 else if (pa_get_home_dir(h, sizeof(h)))
1094 fn = lfn = pa_sprintf_malloc("%s/.pulse/%s", h, local);
1095
1096 if (lfn) {
1097 FILE *f;
1098
1099 #ifdef OS_IS_WIN32
1100 if (!ExpandEnvironmentStrings(lfn, buf, PATH_MAX))
1101 return NULL;
1102 fn = buf;
1103 #endif
1104
1105 f = fopen(fn, mode);
1106 if (f != NULL) {
1107 if (result)
1108 *result = pa_xstrdup(fn);
1109 pa_xfree(lfn);
1110 return f;
1111 }
1112
1113 if (errno != ENOENT)
1114 pa_log_warn("Failed to open configuration file '%s': %s", lfn, pa_cstrerror(errno));
1115
1116 pa_xfree(lfn);
1117 }
1118 }
1119
1120 if (!global) {
1121 if (result)
1122 *result = NULL;
1123 errno = ENOENT;
1124 return NULL;
1125 }
1126
1127 #ifdef OS_IS_WIN32
1128 if (!ExpandEnvironmentStrings(global, buf, PATH_MAX))
1129 return NULL;
1130 global = buf;
1131 #endif
1132
1133 if (result)
1134 *result = pa_xstrdup(global);
1135
1136 return fopen(global, mode);
1137 }
1138
1139 /* Format the specified data as a hexademical string */
1140 char *pa_hexstr(const uint8_t* d, size_t dlength, char *s, size_t slength) {
1141 size_t i = 0, j = 0;
1142 const char hex[] = "0123456789abcdef";
1143
1144 pa_assert(d);
1145 pa_assert(s);
1146 pa_assert(slength > 0);
1147
1148 while (i < dlength && j+3 <= slength) {
1149 s[j++] = hex[*d >> 4];
1150 s[j++] = hex[*d & 0xF];
1151
1152 d++;
1153 i++;
1154 }
1155
1156 s[j < slength ? j : slength] = 0;
1157 return s;
1158 }
1159
1160 /* Convert a hexadecimal digit to a number or -1 if invalid */
1161 static int hexc(char c) {
1162 if (c >= '0' && c <= '9')
1163 return c - '0';
1164
1165 if (c >= 'A' && c <= 'F')
1166 return c - 'A' + 10;
1167
1168 if (c >= 'a' && c <= 'f')
1169 return c - 'a' + 10;
1170
1171 return -1;
1172 }
1173
1174 /* Parse a hexadecimal string as created by pa_hexstr() to a BLOB */
1175 size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength) {
1176 size_t j = 0;
1177
1178 pa_assert(p);
1179 pa_assert(d);
1180
1181 while (j < dlength && *p) {
1182 int b;
1183
1184 if ((b = hexc(*(p++))) < 0)
1185 return (size_t) -1;
1186
1187 d[j] = (uint8_t) (b << 4);
1188
1189 if (!*p)
1190 return (size_t) -1;
1191
1192 if ((b = hexc(*(p++))) < 0)
1193 return (size_t) -1;
1194
1195 d[j] |= (uint8_t) b;
1196 j++;
1197 }
1198
1199 return j;
1200 }
1201
1202 /* Returns nonzero when *s starts with *pfx */
1203 int pa_startswith(const char *s, const char *pfx) {
1204 size_t l;
1205
1206 pa_assert(s);
1207 pa_assert(pfx);
1208
1209 l = strlen(pfx);
1210
1211 return strlen(s) >= l && strncmp(s, pfx, l) == 0;
1212 }
1213
1214 /* Returns nonzero when *s ends with *sfx */
1215 int pa_endswith(const char *s, const char *sfx) {
1216 size_t l1, l2;
1217
1218 pa_assert(s);
1219 pa_assert(sfx);
1220
1221 l1 = strlen(s);
1222 l2 = strlen(sfx);
1223
1224 return l1 >= l2 && strcmp(s+l1-l2, sfx) == 0;
1225 }
1226
1227 /* if fn is null return the PulseAudio run time path in s (/tmp/pulse)
1228 * if fn is non-null and starts with / return fn in s
1229 * otherwise append fn to the run time path and return it in s */
1230 char *pa_runtime_path(const char *fn, char *s, size_t l) {
1231 const char *e;
1232
1233 #ifndef OS_IS_WIN32
1234 if (fn && *fn == '/')
1235 #else
1236 if (fn && strlen(fn) >= 3 && isalpha(fn[0]) && fn[1] == ':' && fn[2] == '\\')
1237 #endif
1238 return pa_strlcpy(s, fn, l);
1239
1240 if ((e = getenv("PULSE_RUNTIME_PATH"))) {
1241
1242 if (fn)
1243 pa_snprintf(s, l, "%s%c%s", e, PA_PATH_SEP_CHAR, fn);
1244 else
1245 pa_snprintf(s, l, "%s", e);
1246
1247 } else {
1248 char u[256];
1249
1250 if (fn)
1251 pa_snprintf(s, l, "%s%s%c%s", PA_USER_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u)), PA_PATH_SEP_CHAR, fn);
1252 else
1253 pa_snprintf(s, l, "%s%s", PA_USER_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u)));
1254 }
1255
1256
1257 #ifdef OS_IS_WIN32
1258 {
1259 char buf[l];
1260 strcpy(buf, s);
1261 ExpandEnvironmentStrings(buf, s, l);
1262 }
1263 #endif
1264
1265 return s;
1266 }
1267
1268 /* Convert the string s to a signed integer in *ret_i */
1269 int pa_atoi(const char *s, int32_t *ret_i) {
1270 char *x = NULL;
1271 long l;
1272
1273 pa_assert(s);
1274 pa_assert(ret_i);
1275
1276 errno = 0;
1277 l = strtol(s, &x, 0);
1278
1279 if (!x || *x || errno != 0)
1280 return -1;
1281
1282 if ((int32_t) l != l)
1283 return -1;
1284
1285 *ret_i = (int32_t) l;
1286
1287 return 0;
1288 }
1289
1290 /* Convert the string s to an unsigned integer in *ret_u */
1291 int pa_atou(const char *s, uint32_t *ret_u) {
1292 char *x = NULL;
1293 unsigned long l;
1294
1295 pa_assert(s);
1296 pa_assert(ret_u);
1297
1298 errno = 0;
1299 l = strtoul(s, &x, 0);
1300
1301 if (!x || *x || errno != 0)
1302 return -1;
1303
1304 if ((uint32_t) l != l)
1305 return -1;
1306
1307 *ret_u = (uint32_t) l;
1308
1309 return 0;
1310 }
1311
1312 #ifdef HAVE_STRTOF_L
1313 static locale_t c_locale = NULL;
1314
1315 static void c_locale_destroy(void) {
1316 freelocale(c_locale);
1317 }
1318 #endif
1319
1320 int pa_atof(const char *s, float *ret_f) {
1321 char *x = NULL;
1322 float f;
1323 int r = 0;
1324
1325 pa_assert(s);
1326 pa_assert(ret_f);
1327
1328 /* This should be locale independent */
1329
1330 #ifdef HAVE_STRTOF_L
1331
1332 PA_ONCE_BEGIN {
1333
1334 if ((c_locale = newlocale(LC_ALL_MASK, "C", NULL)))
1335 atexit(c_locale_destroy);
1336
1337 } PA_ONCE_END;
1338
1339 if (c_locale) {
1340 errno = 0;
1341 f = strtof_l(s, &x, c_locale);
1342 } else
1343 #endif
1344 {
1345 errno = 0;
1346 #ifdef HAVE_STRTOF
1347 f = strtof(s, &x);
1348 #else
1349 f = strtod(s, &x);
1350 #endif
1351 }
1352
1353 if (!x || *x || errno != 0)
1354 r = -1;
1355 else
1356 *ret_f = f;
1357
1358 return r;
1359 }
1360
1361 /* Same as snprintf, but guarantees NUL-termination on every platform */
1362 int pa_snprintf(char *str, size_t size, const char *format, ...) {
1363 int ret;
1364 va_list ap;
1365
1366 pa_assert(str);
1367 pa_assert(size > 0);
1368 pa_assert(format);
1369
1370 va_start(ap, format);
1371 ret = vsnprintf(str, size, format, ap);
1372 va_end(ap);
1373
1374 str[size-1] = 0;
1375
1376 return ret;
1377 }
1378
1379 /* Truncate the specified string, but guarantee that the string
1380 * returned still validates as UTF8 */
1381 char *pa_truncate_utf8(char *c, size_t l) {
1382 pa_assert(c);
1383 pa_assert(pa_utf8_valid(c));
1384
1385 if (strlen(c) <= l)
1386 return c;
1387
1388 c[l] = 0;
1389
1390 while (l > 0 && !pa_utf8_valid(c))
1391 c[--l] = 0;
1392
1393 return c;
1394 }
1395
1396 char *pa_getcwd(void) {
1397 size_t l = 128;
1398
1399 for (;;) {
1400 char *p = pa_xnew(char, l);
1401 if (getcwd(p, l))
1402 return p;
1403
1404 if (errno != ERANGE)
1405 return NULL;
1406
1407 pa_xfree(p);
1408 l *= 2;
1409 }
1410 }
1411
1412 char *pa_make_path_absolute(const char *p) {
1413 char *r;
1414 char *cwd;
1415
1416 pa_assert(p);
1417
1418 if (p[0] == '/')
1419 return pa_xstrdup(p);
1420
1421 if (!(cwd = pa_getcwd()))
1422 return pa_xstrdup(p);
1423
1424 r = pa_sprintf_malloc("%s/%s", cwd, p);
1425 pa_xfree(cwd);
1426 return r;
1427 }
1428
1429 void *pa_will_need(const void *p, size_t l) {
1430 #ifdef RLIMIT_MEMLOCK
1431 struct rlimit rlim;
1432 #endif
1433 const void *a;
1434 size_t size;
1435 int r;
1436 size_t bs;
1437
1438 pa_assert(p);
1439 pa_assert(l > 0);
1440
1441 a = PA_PAGE_ALIGN_PTR(p);
1442 size = (const uint8_t*) p + l - (const uint8_t*) a;
1443
1444 #ifdef HAVE_POSIX_MADVISE
1445 if ((r = posix_madvise((void*) a, size, POSIX_MADV_WILLNEED)) == 0) {
1446 pa_log_debug("posix_madvise() worked fine!");
1447 return (void*) p;
1448 }
1449 #endif
1450
1451 /* Most likely the memory was not mmap()ed from a file and thus
1452 * madvise() didn't work, so let's misuse mlock() do page this
1453 * stuff back into RAM. Yeah, let's fuck with the MM! It's so
1454 * inviting, the man page of mlock() tells us: "All pages that
1455 * contain a part of the specified address range are guaranteed to
1456 * be resident in RAM when the call returns successfully." */
1457
1458 #ifdef RLIMIT_MEMLOCK
1459 pa_assert_se(getrlimit(RLIMIT_MEMLOCK, &rlim) == 0);
1460
1461 if (rlim.rlim_cur < PA_PAGE_SIZE) {
1462 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));
1463 return (void*) p;
1464 }
1465
1466 bs = PA_PAGE_ALIGN(rlim.rlim_cur);
1467 #else
1468 bs = PA_PAGE_SIZE*4;
1469 #endif
1470
1471 pa_log_debug("posix_madvise() failed (or doesn't exist), trying mlock(): %s", pa_cstrerror(r));
1472
1473 #ifdef HAVE_MLOCK
1474 while (size > 0 && bs > 0) {
1475
1476 if (bs > size)
1477 bs = size;
1478
1479 if (mlock(a, bs) < 0) {
1480 bs = PA_PAGE_ALIGN(bs / 2);
1481 continue;
1482 }
1483
1484 pa_assert_se(munlock(a, bs) == 0);
1485
1486 a = (const uint8_t*) a + bs;
1487 size -= bs;
1488 }
1489 #endif
1490
1491 if (bs <= 0)
1492 pa_log_debug("mlock() failed too (or doesn't exist), giving up: %s", pa_cstrerror(errno));
1493 else
1494 pa_log_debug("mlock() worked fine!");
1495
1496 return (void*) p;
1497 }
1498
1499 void pa_close_pipe(int fds[2]) {
1500 pa_assert(fds);
1501
1502 if (fds[0] >= 0)
1503 pa_assert_se(pa_close(fds[0]) == 0);
1504
1505 if (fds[1] >= 0)
1506 pa_assert_se(pa_close(fds[1]) == 0);
1507
1508 fds[0] = fds[1] = -1;
1509 }