]> code.delx.au - pulseaudio/blob - src/pulsecore/core-util.c
Fix a DoS with allocating overly large silence buffers. (Identified by Luigi Auriemma...
[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 <assert.h>
35 #include <string.h>
36 #include <stdio.h>
37 #include <fcntl.h>
38 #include <unistd.h>
39 #include <limits.h>
40 #include <time.h>
41 #include <ctype.h>
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <sys/time.h>
45
46 #ifdef HAVE_SCHED_H
47 #include <sched.h>
48 #endif
49
50 #ifdef HAVE_SYS_RESOURCE_H
51 #include <sys/resource.h>
52 #endif
53
54 #ifdef HAVE_PTHREAD
55 #include <pthread.h>
56 #endif
57
58 #ifdef HAVE_NETDB_H
59 #include <netdb.h>
60 #endif
61
62 #ifdef HAVE_WINDOWS_H
63 #include <windows.h>
64 #endif
65
66 #ifdef HAVE_PWD_H
67 #include <pwd.h>
68 #endif
69
70 #ifdef HAVE_GRP_H
71 #include <grp.h>
72 #endif
73
74 #include <samplerate.h>
75
76 #include <pulse/xmalloc.h>
77 #include <pulse/util.h>
78
79 #include <pulsecore/core-error.h>
80 #include <pulsecore/winsock.h>
81 #include <pulsecore/log.h>
82
83 #include "core-util.h"
84
85 /* Not all platforms have this */
86 #ifndef MSG_NOSIGNAL
87 #define MSG_NOSIGNAL 0
88 #endif
89
90 #ifndef OS_IS_WIN32
91 #define PA_USER_RUNTIME_PATH_PREFIX "/tmp/pulse-"
92 #define PATH_SEP '/'
93 #else
94 #define PA_USER_RUNTIME_PATH_PREFIX "%TEMP%\\pulse-"
95 #define PATH_SEP '\\'
96 #endif
97
98 #ifdef OS_IS_WIN32
99
100 #define PULSE_ROOTENV "PULSE_ROOT"
101
102 int pa_set_root(HANDLE handle) {
103 char library_path[MAX_PATH + sizeof(PULSE_ROOTENV) + 1], *sep;
104
105 strcpy(library_path, PULSE_ROOTENV "=");
106
107 if (!GetModuleFileName(handle, library_path + sizeof(PULSE_ROOTENV), MAX_PATH))
108 return 0;
109
110 sep = strrchr(library_path, '\\');
111 if (sep)
112 *sep = '\0';
113
114 if (_putenv(library_path) < 0)
115 return 0;
116
117 return 1;
118 }
119
120 #endif
121
122 /** Make a file descriptor nonblock. Doesn't do any error checking */
123 void pa_make_nonblock_fd(int fd) {
124 #ifdef O_NONBLOCK
125 int v;
126 assert(fd >= 0);
127
128 if ((v = fcntl(fd, F_GETFL)) >= 0)
129 if (!(v & O_NONBLOCK))
130 fcntl(fd, F_SETFL, v|O_NONBLOCK);
131 #elif defined(OS_IS_WIN32)
132 u_long arg = 1;
133 if (ioctlsocket(fd, FIONBIO, &arg) < 0) {
134 if (WSAGetLastError() == WSAENOTSOCK)
135 pa_log_warn("WARNING: Only sockets can be made non-blocking!");
136 }
137 #else
138 pa_log_warn("WARNING: Non-blocking I/O not supported.!");
139 #endif
140 }
141
142 /** Creates a directory securely */
143 int pa_make_secure_dir(const char* dir, mode_t m, uid_t uid, gid_t gid) {
144 struct stat st;
145 int r;
146
147 assert(dir);
148
149 #ifdef OS_IS_WIN32
150 r = mkdir(dir);
151 #else
152 {
153 mode_t u;
154 u = umask(~m);
155 r = mkdir(dir, m);
156 umask(u);
157 }
158 #endif
159
160 if (r < 0 && errno != EEXIST)
161 return -1;
162
163 #ifdef HAVE_CHOWN
164 if (uid == (uid_t)-1)
165 uid = getuid();
166 if (gid == (gid_t)-1)
167 gid = getgid();
168 chown(dir, uid, gid);
169 #endif
170
171 #ifdef HAVE_CHMOD
172 chmod(dir, m);
173 #endif
174
175 #ifdef HAVE_LSTAT
176 if (lstat(dir, &st) < 0)
177 #else
178 if (stat(dir, &st) < 0)
179 #endif
180 goto fail;
181
182 #ifndef OS_IS_WIN32
183 if (!S_ISDIR(st.st_mode) ||
184 (st.st_uid != uid) ||
185 (st.st_gid != gid) ||
186 ((st.st_mode & 0777) != m)) {
187 errno = EACCES;
188 goto fail;
189 }
190 #else
191 pa_log_warn("secure directory creation not supported on Win32.");
192 #endif
193
194 return 0;
195
196 fail:
197 rmdir(dir);
198 return -1;
199 }
200
201 /* Return a newly allocated sting containing the parent directory of the specified file */
202 char *pa_parent_dir(const char *fn) {
203 char *slash, *dir = pa_xstrdup(fn);
204
205 if ((slash = (char*) pa_path_get_filename(dir)) == dir) {
206 pa_xfree(dir);
207 return NULL;
208 }
209
210 *(slash-1) = 0;
211 return dir;
212 }
213
214 /* Creates a the parent directory of the specified path securely */
215 int pa_make_secure_parent_dir(const char *fn, mode_t m, uid_t uid, gid_t gid) {
216 int ret = -1;
217 char *dir;
218
219 if (!(dir = pa_parent_dir(fn)))
220 goto finish;
221
222 if (pa_make_secure_dir(dir, m, uid, gid) < 0)
223 goto finish;
224
225 ret = 0;
226
227 finish:
228 pa_xfree(dir);
229 return ret;
230 }
231
232 /** Platform independent read function. Necessary since not all
233 * systems treat all file descriptors equal. If type is
234 * non-NULL it is used to cache the type of the fd. This is
235 * useful for making sure that only a single syscall is executed per
236 * function call. The variable pointed to should be initialized to 0
237 * by the caller. */
238 ssize_t pa_read(int fd, void *buf, size_t count, int *type) {
239
240 #ifdef OS_IS_WIN32
241
242 if (!type || *type == 0) {
243 ssize_t r;
244
245 if ((r = recv(fd, buf, count, 0)) >= 0)
246 return r;
247
248 if (WSAGetLastError() != WSAENOTSOCK) {
249 errno = WSAGetLastError();
250 return r;
251 }
252
253 if (type)
254 *type = 1;
255 }
256
257 #endif
258
259 return read(fd, buf, count);
260 }
261
262 /** Similar to pa_read(), but handles writes */
263 ssize_t pa_write(int fd, const void *buf, size_t count, int *type) {
264
265 if (!type || *type == 0) {
266 ssize_t r;
267
268 if ((r = send(fd, buf, count, MSG_NOSIGNAL)) >= 0)
269 return r;
270
271 #ifdef OS_IS_WIN32
272 if (WSAGetLastError() != WSAENOTSOCK) {
273 errno = WSAGetLastError();
274 return r;
275 }
276 #else
277 if (errno != ENOTSOCK)
278 return r;
279 #endif
280
281 if (type)
282 *type = 1;
283 }
284
285 return write(fd, buf, count);
286 }
287
288 /** Calls read() in a loop. Makes sure that as much as 'size' bytes,
289 * unless EOF is reached or an error occured */
290 ssize_t pa_loop_read(int fd, void*data, size_t size, int *type) {
291 ssize_t ret = 0;
292 int _type;
293
294 assert(fd >= 0);
295 assert(data);
296 assert(size);
297
298 if (!type) {
299 _type = 0;
300 type = &_type;
301 }
302
303 while (size > 0) {
304 ssize_t r;
305
306 if ((r = pa_read(fd, data, size, type)) < 0)
307 return r;
308
309 if (r == 0)
310 break;
311
312 ret += r;
313 data = (uint8_t*) data + r;
314 size -= r;
315 }
316
317 return ret;
318 }
319
320 /** Similar to pa_loop_read(), but wraps write() */
321 ssize_t pa_loop_write(int fd, const void*data, size_t size, int *type) {
322 ssize_t ret = 0;
323 int _type;
324
325 assert(fd >= 0);
326 assert(data);
327 assert(size);
328
329 if (!type) {
330 _type = 0;
331 type = &_type;
332 }
333
334 while (size > 0) {
335 ssize_t r;
336
337 if ((r = pa_write(fd, data, size, type)) < 0)
338 return r;
339
340 if (r == 0)
341 break;
342
343 ret += r;
344 data = (const uint8_t*) data + r;
345 size -= r;
346 }
347
348 return ret;
349 }
350
351 /** Platform independent read function. Necessary since not all
352 * systems treat all file descriptors equal. */
353 int pa_close(int fd)
354 {
355 #ifdef OS_IS_WIN32
356 int ret;
357
358 ret = closesocket(fd);
359 if (ret == 0)
360 return 0;
361
362 if (WSAGetLastError() != WSAENOTSOCK) {
363 errno = WSAGetLastError();
364 return ret;
365 }
366 #endif
367
368 return close(fd);
369 }
370
371 /* Print a warning messages in case that the given signal is not
372 * blocked or trapped */
373 void pa_check_signal_is_blocked(int sig) {
374 #ifdef HAVE_SIGACTION
375 struct sigaction sa;
376 sigset_t set;
377
378 /* If POSIX threads are supported use thread-aware
379 * pthread_sigmask() function, to check if the signal is
380 * blocked. Otherwise fall back to sigprocmask() */
381
382 #ifdef HAVE_PTHREAD
383 if (pthread_sigmask(SIG_SETMASK, NULL, &set) < 0) {
384 #endif
385 if (sigprocmask(SIG_SETMASK, NULL, &set) < 0) {
386 pa_log("sigprocmask(): %s", pa_cstrerror(errno));
387 return;
388 }
389 #ifdef HAVE_PTHREAD
390 }
391 #endif
392
393 if (sigismember(&set, sig))
394 return;
395
396 /* Check whether the signal is trapped */
397
398 if (sigaction(sig, NULL, &sa) < 0) {
399 pa_log("sigaction(): %s", pa_cstrerror(errno));
400 return;
401 }
402
403 if (sa.sa_handler != SIG_DFL)
404 return;
405
406 pa_log("WARNING: %s is not trapped. This might cause malfunction!", pa_strsignal(sig));
407 #else /* HAVE_SIGACTION */
408 pa_log("WARNING: %s might not be trapped. This might cause malfunction!", pa_strsignal(sig));
409 #endif
410 }
411
412 /* The following function is based on an example from the GNU libc
413 * documentation. This function is similar to GNU's asprintf(). */
414 char *pa_sprintf_malloc(const char *format, ...) {
415 int size = 100;
416 char *c = NULL;
417
418 assert(format);
419
420 for(;;) {
421 int r;
422 va_list ap;
423
424 c = pa_xrealloc(c, size);
425
426 va_start(ap, format);
427 r = vsnprintf(c, size, format, ap);
428 va_end(ap);
429
430 if (r > -1 && r < size)
431 return c;
432
433 if (r > -1) /* glibc 2.1 */
434 size = r+1;
435 else /* glibc 2.0 */
436 size *= 2;
437 }
438 }
439
440 /* Same as the previous function, but use a va_list instead of an
441 * ellipsis */
442 char *pa_vsprintf_malloc(const char *format, va_list ap) {
443 int size = 100;
444 char *c = NULL;
445
446 assert(format);
447
448 for(;;) {
449 int r;
450 va_list aq;
451
452 va_copy(aq, ap);
453
454 c = pa_xrealloc(c, size);
455 r = vsnprintf(c, size, format, aq);
456
457 va_end(aq);
458
459 if (r > -1 && r < size)
460 return c;
461
462 if (r > -1) /* glibc 2.1 */
463 size = r+1;
464 else /* glibc 2.0 */
465 size *= 2;
466 }
467 }
468
469 /* Similar to OpenBSD's strlcpy() function */
470 char *pa_strlcpy(char *b, const char *s, size_t l) {
471 assert(b && s && l > 0);
472
473 strncpy(b, s, l);
474 b[l-1] = 0;
475 return b;
476 }
477
478 #define NICE_LEVEL (-15)
479
480 /* Raise the priority of the current process as much as possible and
481 sensible: set the nice level to -15 and enable realtime scheduling if
482 supported.*/
483 void pa_raise_priority(void) {
484
485 #ifdef HAVE_SYS_RESOURCE_H
486 if (setpriority(PRIO_PROCESS, 0, NICE_LEVEL) < 0)
487 pa_log_warn("setpriority(): %s", pa_cstrerror(errno));
488 else
489 pa_log_info("Successfully gained nice level %i.", NICE_LEVEL);
490 #endif
491
492 #ifdef _POSIX_PRIORITY_SCHEDULING
493 {
494 struct sched_param sp;
495
496 if (sched_getparam(0, &sp) < 0) {
497 pa_log("sched_getparam(): %s", pa_cstrerror(errno));
498 return;
499 }
500
501 sp.sched_priority = 1;
502 if (sched_setscheduler(0, SCHED_FIFO, &sp) < 0) {
503 pa_log_warn("sched_setscheduler(): %s", pa_cstrerror(errno));
504 return;
505 }
506
507 pa_log_info("Successfully enabled SCHED_FIFO scheduling.");
508 }
509 #endif
510
511 #ifdef OS_IS_WIN32
512 if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS))
513 pa_log_warn("SetPriorityClass() failed: 0x%08X", GetLastError());
514 else
515 pa_log_info("Successfully gained high priority class.");
516 #endif
517 }
518
519 /* Reset the priority to normal, inverting the changes made by pa_raise_priority() */
520 void pa_reset_priority(void) {
521 #ifdef OS_IS_WIN32
522 SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS);
523 #endif
524
525 #ifdef _POSIX_PRIORITY_SCHEDULING
526 {
527 struct sched_param sp;
528 sched_getparam(0, &sp);
529 sp.sched_priority = 0;
530 sched_setscheduler(0, SCHED_OTHER, &sp);
531 }
532 #endif
533
534 #ifdef HAVE_SYS_RESOURCE_H
535 setpriority(PRIO_PROCESS, 0, 0);
536 #endif
537 }
538
539 /* Set the FD_CLOEXEC flag for a fd */
540 int pa_fd_set_cloexec(int fd, int b) {
541
542 #ifdef FD_CLOEXEC
543 int v;
544 assert(fd >= 0);
545
546 if ((v = fcntl(fd, F_GETFD, 0)) < 0)
547 return -1;
548
549 v = (v & ~FD_CLOEXEC) | (b ? FD_CLOEXEC : 0);
550
551 if (fcntl(fd, F_SETFD, v) < 0)
552 return -1;
553 #endif
554
555 return 0;
556 }
557
558 /* Try to parse a boolean string value.*/
559 int pa_parse_boolean(const char *v) {
560
561 if (!strcmp(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || !strcasecmp(v, "on"))
562 return 1;
563 else if (!strcmp(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || !strcasecmp(v, "off"))
564 return 0;
565
566 return -1;
567 }
568
569 /* Split the specified string wherever one of the strings in delimiter
570 * occurs. Each time it is called returns a newly allocated string
571 * with pa_xmalloc(). The variable state points to, should be
572 * initiallized to NULL before the first call. */
573 char *pa_split(const char *c, const char *delimiter, const char**state) {
574 const char *current = *state ? *state : c;
575 size_t l;
576
577 if (!*current)
578 return NULL;
579
580 l = strcspn(current, delimiter);
581 *state = current+l;
582
583 if (**state)
584 (*state)++;
585
586 return pa_xstrndup(current, l);
587 }
588
589 /* What is interpreted as whitespace? */
590 #define WHITESPACE " \t\n"
591
592 /* Split a string into words. Otherwise similar to pa_split(). */
593 char *pa_split_spaces(const char *c, const char **state) {
594 const char *current = *state ? *state : c;
595 size_t l;
596
597 if (!*current || *c == 0)
598 return NULL;
599
600 current += strspn(current, WHITESPACE);
601 l = strcspn(current, WHITESPACE);
602
603 *state = current+l;
604
605 return pa_xstrndup(current, l);
606 }
607
608 /* Return the name of an UNIX signal. Similar to GNU's strsignal() */
609 const char *pa_strsignal(int sig) {
610 switch(sig) {
611 case SIGINT: return "SIGINT";
612 case SIGTERM: return "SIGTERM";
613 #ifdef SIGUSR1
614 case SIGUSR1: return "SIGUSR1";
615 #endif
616 #ifdef SIGUSR2
617 case SIGUSR2: return "SIGUSR2";
618 #endif
619 #ifdef SIGXCPU
620 case SIGXCPU: return "SIGXCPU";
621 #endif
622 #ifdef SIGPIPE
623 case SIGPIPE: return "SIGPIPE";
624 #endif
625 #ifdef SIGCHLD
626 case SIGCHLD: return "SIGCHLD";
627 #endif
628 #ifdef SIGHUP
629 case SIGHUP: return "SIGHUP";
630 #endif
631 default: return "UNKNOWN SIGNAL";
632 }
633 }
634
635 #ifdef HAVE_GRP_H
636
637 /* Check whether the specified GID and the group name match */
638 static int is_group(gid_t gid, const char *name) {
639 struct group group, *result = NULL;
640 long n;
641 void *data;
642 int r = -1;
643
644 #ifdef HAVE_GETGRGID_R
645 #ifdef _SC_GETGR_R_SIZE_MAX
646 n = sysconf(_SC_GETGR_R_SIZE_MAX);
647 #else
648 n = -1;
649 #endif
650 if (n < 0) n = 512;
651 data = pa_xmalloc(n);
652
653 if (getgrgid_r(gid, &group, data, n, &result) < 0 || !result) {
654 pa_log("getgrgid_r(%u): %s", (unsigned)gid, pa_cstrerror(errno));
655 goto finish;
656 }
657
658 r = strcmp(name, result->gr_name) == 0;
659
660 finish:
661 pa_xfree(data);
662 #else
663 /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) that do not
664 * support getgrgid_r. */
665 if ((result = getgrgid(gid)) == NULL) {
666 pa_log("getgrgid(%u): %s", gid, pa_cstrerror(errno));
667 goto finish;
668 }
669
670 r = strcmp(name, result->gr_name) == 0;
671
672 finish:
673 #endif
674
675 return r;
676 }
677
678 /* Check the current user is member of the specified group */
679 int pa_own_uid_in_group(const char *name, gid_t *gid) {
680 GETGROUPS_T *gids, tgid;
681 int n = sysconf(_SC_NGROUPS_MAX);
682 int r = -1, i;
683
684 assert(n > 0);
685
686 gids = pa_xmalloc(sizeof(GETGROUPS_T)*n);
687
688 if ((n = getgroups(n, gids)) < 0) {
689 pa_log("getgroups(): %s", pa_cstrerror(errno));
690 goto finish;
691 }
692
693 for (i = 0; i < n; i++) {
694 if (is_group(gids[i], name) > 0) {
695 *gid = gids[i];
696 r = 1;
697 goto finish;
698 }
699 }
700
701 if (is_group(tgid = getgid(), name) > 0) {
702 *gid = tgid;
703 r = 1;
704 goto finish;
705 }
706
707 r = 0;
708
709 finish:
710
711 pa_xfree(gids);
712 return r;
713 }
714
715 /* Check whether the specifc user id is a member of the specified group */
716 int pa_uid_in_group(uid_t uid, const char *name) {
717 char *g_buf, *p_buf;
718 long g_n, p_n;
719 struct group grbuf, *gr;
720 char **i;
721 int r = -1;
722
723 g_n = sysconf(_SC_GETGR_R_SIZE_MAX);
724 g_buf = pa_xmalloc(g_n);
725
726 p_n = sysconf(_SC_GETPW_R_SIZE_MAX);
727 p_buf = pa_xmalloc(p_n);
728
729 if (getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr) != 0 || !gr)
730 goto finish;
731
732 r = 0;
733 for (i = gr->gr_mem; *i; i++) {
734 struct passwd pwbuf, *pw;
735
736 if (getpwnam_r(*i, &pwbuf, p_buf, (size_t) p_n, &pw) != 0 || !pw)
737 continue;
738
739 if (pw->pw_uid == uid) {
740 r = 1;
741 break;
742 }
743 }
744
745 finish:
746 pa_xfree(g_buf);
747 pa_xfree(p_buf);
748
749 return r;
750 }
751
752 /* Get the GID of a gfiven group, return (gid_t) -1 on failure. */
753 gid_t pa_get_gid_of_group(const char *name) {
754 gid_t ret = (gid_t) -1;
755 char *g_buf;
756 long g_n;
757 struct group grbuf, *gr;
758
759 g_n = sysconf(_SC_GETGR_R_SIZE_MAX);
760 g_buf = pa_xmalloc(g_n);
761
762 if (getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr) != 0 || !gr)
763 goto finish;
764
765 ret = gr->gr_gid;
766
767 finish:
768 pa_xfree(g_buf);
769 return ret;
770 }
771
772 int pa_check_in_group(gid_t g) {
773 gid_t gids[NGROUPS_MAX];
774 int r;
775
776 if ((r = getgroups(NGROUPS_MAX, gids)) < 0)
777 return -1;
778
779 for (; r > 0; r--)
780 if (gids[r-1] == g)
781 return 1;
782
783 return 0;
784 }
785
786 #else /* HAVE_GRP_H */
787
788 int pa_own_uid_in_group(const char *name, gid_t *gid) {
789 return -1;
790
791 }
792
793 int pa_uid_in_group(uid_t uid, const char *name) {
794 return -1;
795 }
796
797 gid_t pa_get_gid_of_group(const char *name) {
798 return (gid_t) -1;
799 }
800
801 int pa_check_in_group(gid_t g) {
802 return -1;
803 }
804
805 #endif
806
807 /* Lock or unlock a file entirely.
808 (advisory on UNIX, mandatory on Windows) */
809 int pa_lock_fd(int fd, int b) {
810 #ifdef F_SETLKW
811 struct flock flock;
812
813 /* Try a R/W lock first */
814
815 flock.l_type = b ? F_WRLCK : F_UNLCK;
816 flock.l_whence = SEEK_SET;
817 flock.l_start = 0;
818 flock.l_len = 0;
819
820 if (fcntl(fd, F_SETLKW, &flock) >= 0)
821 return 0;
822
823 /* Perhaps the file descriptor qas opened for read only, than try again with a read lock. */
824 if (b && errno == EBADF) {
825 flock.l_type = F_RDLCK;
826 if (fcntl(fd, F_SETLKW, &flock) >= 0)
827 return 0;
828 }
829
830 pa_log("%slock: %s", !b? "un" : "",
831 pa_cstrerror(errno));
832 #endif
833
834 #ifdef OS_IS_WIN32
835 HANDLE h = (HANDLE)_get_osfhandle(fd);
836
837 if (b && LockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF))
838 return 0;
839 if (!b && UnlockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF))
840 return 0;
841
842 pa_log("%slock failed: 0x%08X", !b ? "un" : "", GetLastError());
843 #endif
844
845 return -1;
846 }
847
848 /* Remove trailing newlines from a string */
849 char* pa_strip_nl(char *s) {
850 assert(s);
851
852 s[strcspn(s, "\r\n")] = 0;
853 return s;
854 }
855
856 /* Create a temporary lock file and lock it. */
857 int pa_lock_lockfile(const char *fn) {
858 int fd = -1;
859 assert(fn);
860
861 for (;;) {
862 struct stat st;
863
864 if ((fd = open(fn, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR)) < 0) {
865 pa_log("failed to create lock file '%s': %s", fn,
866 pa_cstrerror(errno));
867 goto fail;
868 }
869
870 if (pa_lock_fd(fd, 1) < 0) {
871 pa_log("failed to lock file '%s'.", fn);
872 goto fail;
873 }
874
875 if (fstat(fd, &st) < 0) {
876 pa_log("failed to fstat() file '%s'.", fn);
877 goto fail;
878 }
879
880 /* Check wheter the file has been removed meanwhile. When yes, restart this loop, otherwise, we're done */
881 if (st.st_nlink >= 1)
882 break;
883
884 if (pa_lock_fd(fd, 0) < 0) {
885 pa_log("failed to unlock file '%s'.", fn);
886 goto fail;
887 }
888
889 if (close(fd) < 0) {
890 pa_log("failed to close file '%s'.", fn);
891 goto fail;
892 }
893
894 fd = -1;
895 }
896
897 return fd;
898
899 fail:
900
901 if (fd >= 0)
902 close(fd);
903
904 return -1;
905 }
906
907 /* Unlock a temporary lcok file */
908 int pa_unlock_lockfile(const char *fn, int fd) {
909 int r = 0;
910 assert(fn && fd >= 0);
911
912 if (unlink(fn) < 0) {
913 pa_log_warn("WARNING: unable to remove lock file '%s': %s",
914 fn, pa_cstrerror(errno));
915 r = -1;
916 }
917
918 if (pa_lock_fd(fd, 0) < 0) {
919 pa_log_warn("WARNING: failed to unlock file '%s'.", fn);
920 r = -1;
921 }
922
923 if (close(fd) < 0) {
924 pa_log_warn("WARNING: failed to close lock file '%s': %s",
925 fn, pa_cstrerror(errno));
926 r = -1;
927 }
928
929 return r;
930 }
931
932 /* Try to open a configuration file. If "env" is specified, open the
933 * value of the specified environment variable. Otherwise look for a
934 * file "local" in the home directory or a file "global" in global
935 * file system. If "result" is non-NULL, a pointer to a newly
936 * allocated buffer containing the used configuration file is
937 * stored there.*/
938 FILE *pa_open_config_file(const char *global, const char *local, const char *env, char **result, const char *mode) {
939 const char *fn;
940 char h[PATH_MAX];
941
942 #ifdef OS_IS_WIN32
943 char buf[PATH_MAX];
944
945 if (!getenv(PULSE_ROOTENV))
946 pa_set_root(NULL);
947 #endif
948
949 if (env && (fn = getenv(env))) {
950 #ifdef OS_IS_WIN32
951 if (!ExpandEnvironmentStrings(fn, buf, PATH_MAX))
952 return NULL;
953 fn = buf;
954 #endif
955
956 if (result)
957 *result = pa_xstrdup(fn);
958
959 return fopen(fn, mode);
960 }
961
962 if (local) {
963 const char *e;
964 char *lfn = NULL;
965
966 if ((e = getenv("PULSE_CONFIG_PATH")))
967 fn = lfn = pa_sprintf_malloc("%s/%s", e, local);
968 else if (pa_get_home_dir(h, sizeof(h)))
969 fn = lfn = pa_sprintf_malloc("%s/.pulse/%s", h, local);
970
971 if (lfn) {
972 FILE *f;
973
974 #ifdef OS_IS_WIN32
975 if (!ExpandEnvironmentStrings(lfn, buf, PATH_MAX))
976 return NULL;
977 fn = buf;
978 #endif
979
980 f = fopen(fn, mode);
981 if (f != NULL) {
982 if (result)
983 *result = pa_xstrdup(fn);
984 pa_xfree(lfn);
985 return f;
986 }
987
988 if (errno != ENOENT) {
989 pa_log_warn("WARNING: failed to open configuration file '%s': %s",
990 lfn, pa_cstrerror(errno));
991 }
992
993 pa_xfree(lfn);
994 }
995 }
996
997 if (!global) {
998 if (result)
999 *result = NULL;
1000 errno = ENOENT;
1001 return NULL;
1002 }
1003
1004 #ifdef OS_IS_WIN32
1005 if (!ExpandEnvironmentStrings(global, buf, PATH_MAX))
1006 return NULL;
1007 global = buf;
1008 #endif
1009
1010 if (result)
1011 *result = pa_xstrdup(global);
1012
1013 return fopen(global, mode);
1014 }
1015
1016 /* Format the specified data as a hexademical string */
1017 char *pa_hexstr(const uint8_t* d, size_t dlength, char *s, size_t slength) {
1018 size_t i = 0, j = 0;
1019 const char hex[] = "0123456789abcdef";
1020 assert(d && s && slength > 0);
1021
1022 while (i < dlength && j+3 <= slength) {
1023 s[j++] = hex[*d >> 4];
1024 s[j++] = hex[*d & 0xF];
1025
1026 d++;
1027 i++;
1028 }
1029
1030 s[j < slength ? j : slength] = 0;
1031 return s;
1032 }
1033
1034 /* Convert a hexadecimal digit to a number or -1 if invalid */
1035 static int hexc(char c) {
1036 if (c >= '0' && c <= '9')
1037 return c - '0';
1038
1039 if (c >= 'A' && c <= 'F')
1040 return c - 'A' + 10;
1041
1042 if (c >= 'a' && c <= 'f')
1043 return c - 'a' + 10;
1044
1045 return -1;
1046 }
1047
1048 /* Parse a hexadecimal string as created by pa_hexstr() to a BLOB */
1049 size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength) {
1050 size_t j = 0;
1051 assert(p && d);
1052
1053 while (j < dlength && *p) {
1054 int b;
1055
1056 if ((b = hexc(*(p++))) < 0)
1057 return (size_t) -1;
1058
1059 d[j] = (uint8_t) (b << 4);
1060
1061 if (!*p)
1062 return (size_t) -1;
1063
1064 if ((b = hexc(*(p++))) < 0)
1065 return (size_t) -1;
1066
1067 d[j] |= (uint8_t) b;
1068 j++;
1069 }
1070
1071 return j;
1072 }
1073
1074 /* Returns nonzero when *s starts with *pfx */
1075 int pa_startswith(const char *s, const char *pfx) {
1076 size_t l;
1077
1078 assert(s);
1079 assert(pfx);
1080
1081 l = strlen(pfx);
1082
1083 return strlen(s) >= l && strncmp(s, pfx, l) == 0;
1084 }
1085
1086 /* Returns nonzero when *s ends with *sfx */
1087 int pa_endswith(const char *s, const char *sfx) {
1088 size_t l1, l2;
1089
1090 assert(s);
1091 assert(sfx);
1092
1093 l1 = strlen(s);
1094 l2 = strlen(sfx);
1095
1096 return l1 >= l2 && strcmp(s+l1-l2, sfx) == 0;
1097 }
1098
1099 /* if fn is null return the PulseAudio run time path in s (/tmp/pulse)
1100 * if fn is non-null and starts with / return fn in s
1101 * otherwise append fn to the run time path and return it in s */
1102 char *pa_runtime_path(const char *fn, char *s, size_t l) {
1103 const char *e;
1104
1105 #ifndef OS_IS_WIN32
1106 if (fn && *fn == '/')
1107 #else
1108 if (fn && strlen(fn) >= 3 && isalpha(fn[0]) && fn[1] == ':' && fn[2] == '\\')
1109 #endif
1110 return pa_strlcpy(s, fn, l);
1111
1112 if ((e = getenv("PULSE_RUNTIME_PATH"))) {
1113
1114 if (fn)
1115 snprintf(s, l, "%s%c%s", e, PATH_SEP, fn);
1116 else
1117 snprintf(s, l, "%s", e);
1118
1119 } else {
1120 char u[256];
1121
1122 if (fn)
1123 snprintf(s, l, "%s%s%c%s", PA_USER_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u)), PATH_SEP, fn);
1124 else
1125 snprintf(s, l, "%s%s", PA_USER_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u)));
1126 }
1127
1128
1129 #ifdef OS_IS_WIN32
1130 {
1131 char buf[l];
1132 strcpy(buf, s);
1133 ExpandEnvironmentStrings(buf, s, l);
1134 }
1135 #endif
1136
1137 return s;
1138 }
1139
1140 /* Convert the string s to a signed integer in *ret_i */
1141 int pa_atoi(const char *s, int32_t *ret_i) {
1142 char *x = NULL;
1143 long l;
1144 assert(s && ret_i);
1145
1146 l = strtol(s, &x, 0);
1147
1148 if (!x || *x)
1149 return -1;
1150
1151 *ret_i = (int32_t) l;
1152
1153 return 0;
1154 }
1155
1156 /* Convert the string s to an unsigned integer in *ret_u */
1157 int pa_atou(const char *s, uint32_t *ret_u) {
1158 char *x = NULL;
1159 unsigned long l;
1160 assert(s && ret_u);
1161
1162 l = strtoul(s, &x, 0);
1163
1164 if (!x || *x)
1165 return -1;
1166
1167 *ret_u = (uint32_t) l;
1168
1169 return 0;
1170 }