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