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