]> code.delx.au - pulseaudio/blob - src/pulsecore/core-util.c
add new pa_pipe_close() API to close two fds at the same time
[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 pa_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 pa_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 pa_assert(fd >= 0);
304 pa_assert(data);
305 pa_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 pa_assert(fd >= 0);
335 pa_assert(data);
336 pa_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
364 #ifdef OS_IS_WIN32
365 int ret;
366
367 if ((ret = closesocket(fd)) == 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 pa_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 pa_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 pa_assert(b);
483 pa_assert(s);
484 pa_assert(l > 0);
485
486 strncpy(b, s, l);
487 b[l-1] = 0;
488 return b;
489 }
490
491 /* Make the current thread a realtime thread*/
492 void pa_make_realtime(void) {
493
494 #ifdef _POSIX_PRIORITY_SCHEDULING
495 struct sched_param sp;
496 int r, policy;
497
498 memset(&sp, 0, sizeof(sp));
499 policy = 0;
500
501 if ((r = pthread_getschedparam(pthread_self(), &policy, &sp)) != 0) {
502 pa_log("pthread_getschedgetparam(): %s", pa_cstrerror(r));
503 return;
504 }
505
506 sp.sched_priority = 1;
507 if ((r = pthread_setschedparam(pthread_self(), SCHED_FIFO, &sp)) != 0) {
508 pa_log_warn("pthread_setschedparam(): %s", pa_cstrerror(r));
509 return;
510 }
511
512 pa_log_info("Successfully enabled SCHED_FIFO scheduling for thread.");
513 #endif
514
515 }
516
517 #define NICE_LEVEL (-11)
518
519 /* Raise the priority of the current process as much as possible and
520 sensible: set the nice level to -15.*/
521 void pa_raise_priority(void) {
522
523 #ifdef HAVE_SYS_RESOURCE_H
524 if (setpriority(PRIO_PROCESS, 0, NICE_LEVEL) < 0)
525 pa_log_warn("setpriority(): %s", pa_cstrerror(errno));
526 else
527 pa_log_info("Successfully gained nice level %i.", NICE_LEVEL);
528 #endif
529
530 #ifdef OS_IS_WIN32
531 if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS))
532 pa_log_warn("SetPriorityClass() failed: 0x%08X", GetLastError());
533 else
534 pa_log_info("Successfully gained high priority class.");
535 #endif
536 }
537
538 /* Reset the priority to normal, inverting the changes made by
539 * pa_raise_priority() */
540 void pa_reset_priority(void) {
541 #ifdef OS_IS_WIN32
542 SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS);
543 #endif
544
545 #ifdef HAVE_SYS_RESOURCE_H
546 setpriority(PRIO_PROCESS, 0, 0);
547 #endif
548 }
549
550 /* Set the FD_CLOEXEC flag for a fd */
551 int pa_fd_set_cloexec(int fd, int b) {
552
553 #ifdef FD_CLOEXEC
554 int v;
555 pa_assert(fd >= 0);
556
557 if ((v = fcntl(fd, F_GETFD, 0)) < 0)
558 return -1;
559
560 v = (v & ~FD_CLOEXEC) | (b ? FD_CLOEXEC : 0);
561
562 if (fcntl(fd, F_SETFD, v) < 0)
563 return -1;
564 #endif
565
566 return 0;
567 }
568
569 /* Try to parse a boolean string value.*/
570 int pa_parse_boolean(const char *v) {
571
572 if (!strcmp(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || !strcasecmp(v, "on"))
573 return 1;
574 else if (!strcmp(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || !strcasecmp(v, "off"))
575 return 0;
576
577 return -1;
578 }
579
580 /* Split the specified string wherever one of the strings in delimiter
581 * occurs. Each time it is called returns a newly allocated string
582 * with pa_xmalloc(). The variable state points to, should be
583 * initiallized to NULL before the first call. */
584 char *pa_split(const char *c, const char *delimiter, const char**state) {
585 const char *current = *state ? *state : c;
586 size_t l;
587
588 if (!*current)
589 return NULL;
590
591 l = strcspn(current, delimiter);
592 *state = current+l;
593
594 if (**state)
595 (*state)++;
596
597 return pa_xstrndup(current, l);
598 }
599
600 /* What is interpreted as whitespace? */
601 #define WHITESPACE " \t\n"
602
603 /* Split a string into words. Otherwise similar to pa_split(). */
604 char *pa_split_spaces(const char *c, const char **state) {
605 const char *current = *state ? *state : c;
606 size_t l;
607
608 if (!*current || *c == 0)
609 return NULL;
610
611 current += strspn(current, WHITESPACE);
612 l = strcspn(current, WHITESPACE);
613
614 *state = current+l;
615
616 return pa_xstrndup(current, l);
617 }
618
619 /* Return the name of an UNIX signal. Similar to GNU's strsignal() */
620 const char *pa_strsignal(int sig) {
621 switch(sig) {
622 case SIGINT: return "SIGINT";
623 case SIGTERM: return "SIGTERM";
624 #ifdef SIGUSR1
625 case SIGUSR1: return "SIGUSR1";
626 #endif
627 #ifdef SIGUSR2
628 case SIGUSR2: return "SIGUSR2";
629 #endif
630 #ifdef SIGXCPU
631 case SIGXCPU: return "SIGXCPU";
632 #endif
633 #ifdef SIGPIPE
634 case SIGPIPE: return "SIGPIPE";
635 #endif
636 #ifdef SIGCHLD
637 case SIGCHLD: return "SIGCHLD";
638 #endif
639 #ifdef SIGHUP
640 case SIGHUP: return "SIGHUP";
641 #endif
642 default: return "UNKNOWN SIGNAL";
643 }
644 }
645
646 #ifdef HAVE_GRP_H
647
648 /* Check whether the specified GID and the group name match */
649 static int is_group(gid_t gid, const char *name) {
650 struct group group, *result = NULL;
651 long n;
652 void *data;
653 int r = -1;
654
655 #ifdef HAVE_GETGRGID_R
656 #ifdef _SC_GETGR_R_SIZE_MAX
657 n = sysconf(_SC_GETGR_R_SIZE_MAX);
658 #else
659 n = -1;
660 #endif
661 if (n < 0) n = 512;
662 data = pa_xmalloc(n);
663
664 if (getgrgid_r(gid, &group, data, n, &result) < 0 || !result) {
665 pa_log("getgrgid_r(%u): %s", (unsigned)gid, pa_cstrerror(errno));
666 goto finish;
667 }
668
669 r = strcmp(name, result->gr_name) == 0;
670
671 finish:
672 pa_xfree(data);
673 #else
674 /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) that do not
675 * support getgrgid_r. */
676 if ((result = getgrgid(gid)) == NULL) {
677 pa_log("getgrgid(%u): %s", gid, pa_cstrerror(errno));
678 goto finish;
679 }
680
681 r = strcmp(name, result->gr_name) == 0;
682
683 finish:
684 #endif
685
686 return r;
687 }
688
689 /* Check the current user is member of the specified group */
690 int pa_own_uid_in_group(const char *name, gid_t *gid) {
691 GETGROUPS_T *gids, tgid;
692 int n = sysconf(_SC_NGROUPS_MAX);
693 int r = -1, i;
694
695 pa_assert(n > 0);
696
697 gids = pa_xmalloc(sizeof(GETGROUPS_T)*n);
698
699 if ((n = getgroups(n, gids)) < 0) {
700 pa_log("getgroups(): %s", pa_cstrerror(errno));
701 goto finish;
702 }
703
704 for (i = 0; i < n; i++) {
705 if (is_group(gids[i], name) > 0) {
706 *gid = gids[i];
707 r = 1;
708 goto finish;
709 }
710 }
711
712 if (is_group(tgid = getgid(), name) > 0) {
713 *gid = tgid;
714 r = 1;
715 goto finish;
716 }
717
718 r = 0;
719
720 finish:
721
722 pa_xfree(gids);
723 return r;
724 }
725
726 /* Check whether the specifc user id is a member of the specified group */
727 int pa_uid_in_group(uid_t uid, const char *name) {
728 char *g_buf, *p_buf;
729 long g_n, p_n;
730 struct group grbuf, *gr;
731 char **i;
732 int r = -1;
733
734 g_n = sysconf(_SC_GETGR_R_SIZE_MAX);
735 g_buf = pa_xmalloc(g_n);
736
737 p_n = sysconf(_SC_GETPW_R_SIZE_MAX);
738 p_buf = pa_xmalloc(p_n);
739
740 if (getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr) != 0 || !gr)
741 goto finish;
742
743 r = 0;
744 for (i = gr->gr_mem; *i; i++) {
745 struct passwd pwbuf, *pw;
746
747 if (getpwnam_r(*i, &pwbuf, p_buf, (size_t) p_n, &pw) != 0 || !pw)
748 continue;
749
750 if (pw->pw_uid == uid) {
751 r = 1;
752 break;
753 }
754 }
755
756 finish:
757 pa_xfree(g_buf);
758 pa_xfree(p_buf);
759
760 return r;
761 }
762
763 /* Get the GID of a gfiven group, return (gid_t) -1 on failure. */
764 gid_t pa_get_gid_of_group(const char *name) {
765 gid_t ret = (gid_t) -1;
766 char *g_buf;
767 long g_n;
768 struct group grbuf, *gr;
769
770 g_n = sysconf(_SC_GETGR_R_SIZE_MAX);
771 g_buf = pa_xmalloc(g_n);
772
773 if (getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr) != 0 || !gr)
774 goto finish;
775
776 ret = gr->gr_gid;
777
778 finish:
779 pa_xfree(g_buf);
780 return ret;
781 }
782
783 int pa_check_in_group(gid_t g) {
784 gid_t gids[NGROUPS_MAX];
785 int r;
786
787 if ((r = getgroups(NGROUPS_MAX, gids)) < 0)
788 return -1;
789
790 for (; r > 0; r--)
791 if (gids[r-1] == g)
792 return 1;
793
794 return 0;
795 }
796
797 #else /* HAVE_GRP_H */
798
799 int pa_own_uid_in_group(const char *name, gid_t *gid) {
800 return -1;
801
802 }
803
804 int pa_uid_in_group(uid_t uid, const char *name) {
805 return -1;
806 }
807
808 gid_t pa_get_gid_of_group(const char *name) {
809 return (gid_t) -1;
810 }
811
812 int pa_check_in_group(gid_t g) {
813 return -1;
814 }
815
816 #endif
817
818 /* Lock or unlock a file entirely.
819 (advisory on UNIX, mandatory on Windows) */
820 int pa_lock_fd(int fd, int b) {
821 #ifdef F_SETLKW
822 struct flock flock;
823
824 /* Try a R/W lock first */
825
826 flock.l_type = b ? F_WRLCK : F_UNLCK;
827 flock.l_whence = SEEK_SET;
828 flock.l_start = 0;
829 flock.l_len = 0;
830
831 if (fcntl(fd, F_SETLKW, &flock) >= 0)
832 return 0;
833
834 /* Perhaps the file descriptor qas opened for read only, than try again with a read lock. */
835 if (b && errno == EBADF) {
836 flock.l_type = F_RDLCK;
837 if (fcntl(fd, F_SETLKW, &flock) >= 0)
838 return 0;
839 }
840
841 pa_log("%slock: %s", !b? "un" : "", pa_cstrerror(errno));
842 #endif
843
844 #ifdef OS_IS_WIN32
845 HANDLE h = (HANDLE)_get_osfhandle(fd);
846
847 if (b && LockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF))
848 return 0;
849 if (!b && UnlockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF))
850 return 0;
851
852 pa_log("%slock failed: 0x%08X", !b ? "un" : "", GetLastError());
853 #endif
854
855 return -1;
856 }
857
858 /* Remove trailing newlines from a string */
859 char* pa_strip_nl(char *s) {
860 pa_assert(s);
861
862 s[strcspn(s, "\r\n")] = 0;
863 return s;
864 }
865
866 /* Create a temporary lock file and lock it. */
867 int pa_lock_lockfile(const char *fn) {
868 int fd = -1;
869 pa_assert(fn);
870
871 for (;;) {
872 struct stat st;
873
874 if ((fd = open(fn, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR)) < 0) {
875 pa_log_warn("Failed to create lock file '%s': %s", fn, pa_cstrerror(errno));
876 goto fail;
877 }
878
879 if (pa_lock_fd(fd, 1) < 0) {
880 pa_log_warn("Failed to lock file '%s'.", fn);
881 goto fail;
882 }
883
884 if (fstat(fd, &st) < 0) {
885 pa_log_warn("Failed to fstat() file '%s': %s", fn, pa_cstrerror(errno));
886 goto fail;
887 }
888
889 /* Check wheter the file has been removed meanwhile. When yes,
890 * restart this loop, otherwise, we're done */
891 if (st.st_nlink >= 1)
892 break;
893
894 if (pa_lock_fd(fd, 0) < 0) {
895 pa_log_warn("Failed to unlock file '%s'.", fn);
896 goto fail;
897 }
898
899 if (pa_close(fd) < 0) {
900 pa_log_warn("Failed to close file '%s': %s", fn, pa_cstrerror(errno));
901 fd = -1;
902 goto fail;
903 }
904
905 fd = -1;
906 }
907
908 return fd;
909
910 fail:
911
912 if (fd >= 0)
913 pa_close(fd);
914
915 return -1;
916 }
917
918 /* Unlock a temporary lcok file */
919 int pa_unlock_lockfile(const char *fn, int fd) {
920 int r = 0;
921 pa_assert(fn);
922 pa_assert(fd >= 0);
923
924 if (unlink(fn) < 0) {
925 pa_log_warn("Unable to remove lock file '%s': %s", fn, pa_cstrerror(errno));
926 r = -1;
927 }
928
929 if (pa_lock_fd(fd, 0) < 0) {
930 pa_log_warn("Failed to unlock file '%s'.", fn);
931 r = -1;
932 }
933
934 if (pa_close(fd) < 0) {
935 pa_log_warn("Failed to close '%s': %s", fn, pa_cstrerror(errno));
936 r = -1;
937 }
938
939 return r;
940 }
941
942 /* Try to open a configuration file. If "env" is specified, open the
943 * value of the specified environment variable. Otherwise look for a
944 * file "local" in the home directory or a file "global" in global
945 * file system. If "result" is non-NULL, a pointer to a newly
946 * allocated buffer containing the used configuration file is
947 * stored there.*/
948 FILE *pa_open_config_file(const char *global, const char *local, const char *env, char **result, const char *mode) {
949 const char *fn;
950 char h[PATH_MAX];
951
952 #ifdef OS_IS_WIN32
953 char buf[PATH_MAX];
954
955 if (!getenv(PULSE_ROOTENV))
956 pa_set_root(NULL);
957 #endif
958
959 if (env && (fn = getenv(env))) {
960 #ifdef OS_IS_WIN32
961 if (!ExpandEnvironmentStrings(fn, buf, PATH_MAX))
962 return NULL;
963 fn = buf;
964 #endif
965
966 if (result)
967 *result = pa_xstrdup(fn);
968
969 return fopen(fn, mode);
970 }
971
972 if (local) {
973 const char *e;
974 char *lfn = NULL;
975
976 if ((e = getenv("PULSE_CONFIG_PATH")))
977 fn = lfn = pa_sprintf_malloc("%s/%s", e, local);
978 else if (pa_get_home_dir(h, sizeof(h)))
979 fn = lfn = pa_sprintf_malloc("%s/.pulse/%s", h, local);
980
981 if (lfn) {
982 FILE *f;
983
984 #ifdef OS_IS_WIN32
985 if (!ExpandEnvironmentStrings(lfn, buf, PATH_MAX))
986 return NULL;
987 fn = buf;
988 #endif
989
990 f = fopen(fn, mode);
991 if (f != NULL) {
992 if (result)
993 *result = pa_xstrdup(fn);
994 pa_xfree(lfn);
995 return f;
996 }
997
998 if (errno != ENOENT) {
999 pa_log_warn("WARNING: failed to open configuration file '%s': %s",
1000 lfn, pa_cstrerror(errno));
1001 }
1002
1003 pa_xfree(lfn);
1004 }
1005 }
1006
1007 if (!global) {
1008 if (result)
1009 *result = NULL;
1010 errno = ENOENT;
1011 return NULL;
1012 }
1013
1014 #ifdef OS_IS_WIN32
1015 if (!ExpandEnvironmentStrings(global, buf, PATH_MAX))
1016 return NULL;
1017 global = buf;
1018 #endif
1019
1020 if (result)
1021 *result = pa_xstrdup(global);
1022
1023 return fopen(global, mode);
1024 }
1025
1026 /* Format the specified data as a hexademical string */
1027 char *pa_hexstr(const uint8_t* d, size_t dlength, char *s, size_t slength) {
1028 size_t i = 0, j = 0;
1029 const char hex[] = "0123456789abcdef";
1030
1031 pa_assert(d);
1032 pa_assert(s);
1033 pa_assert(slength > 0);
1034
1035 while (i < dlength && j+3 <= slength) {
1036 s[j++] = hex[*d >> 4];
1037 s[j++] = hex[*d & 0xF];
1038
1039 d++;
1040 i++;
1041 }
1042
1043 s[j < slength ? j : slength] = 0;
1044 return s;
1045 }
1046
1047 /* Convert a hexadecimal digit to a number or -1 if invalid */
1048 static int hexc(char c) {
1049 if (c >= '0' && c <= '9')
1050 return c - '0';
1051
1052 if (c >= 'A' && c <= 'F')
1053 return c - 'A' + 10;
1054
1055 if (c >= 'a' && c <= 'f')
1056 return c - 'a' + 10;
1057
1058 return -1;
1059 }
1060
1061 /* Parse a hexadecimal string as created by pa_hexstr() to a BLOB */
1062 size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength) {
1063 size_t j = 0;
1064
1065 pa_assert(p);
1066 pa_assert(d);
1067
1068 while (j < dlength && *p) {
1069 int b;
1070
1071 if ((b = hexc(*(p++))) < 0)
1072 return (size_t) -1;
1073
1074 d[j] = (uint8_t) (b << 4);
1075
1076 if (!*p)
1077 return (size_t) -1;
1078
1079 if ((b = hexc(*(p++))) < 0)
1080 return (size_t) -1;
1081
1082 d[j] |= (uint8_t) b;
1083 j++;
1084 }
1085
1086 return j;
1087 }
1088
1089 /* Returns nonzero when *s starts with *pfx */
1090 int pa_startswith(const char *s, const char *pfx) {
1091 size_t l;
1092
1093 pa_assert(s);
1094 pa_assert(pfx);
1095
1096 l = strlen(pfx);
1097
1098 return strlen(s) >= l && strncmp(s, pfx, l) == 0;
1099 }
1100
1101 /* Returns nonzero when *s ends with *sfx */
1102 int pa_endswith(const char *s, const char *sfx) {
1103 size_t l1, l2;
1104
1105 pa_assert(s);
1106 pa_assert(sfx);
1107
1108 l1 = strlen(s);
1109 l2 = strlen(sfx);
1110
1111 return l1 >= l2 && strcmp(s+l1-l2, sfx) == 0;
1112 }
1113
1114 /* if fn is null return the PulseAudio run time path in s (/tmp/pulse)
1115 * if fn is non-null and starts with / return fn in s
1116 * otherwise append fn to the run time path and return it in s */
1117 char *pa_runtime_path(const char *fn, char *s, size_t l) {
1118 const char *e;
1119
1120 #ifndef OS_IS_WIN32
1121 if (fn && *fn == '/')
1122 #else
1123 if (fn && strlen(fn) >= 3 && isalpha(fn[0]) && fn[1] == ':' && fn[2] == '\\')
1124 #endif
1125 return pa_strlcpy(s, fn, l);
1126
1127 if ((e = getenv("PULSE_RUNTIME_PATH"))) {
1128
1129 if (fn)
1130 pa_snprintf(s, l, "%s%c%s", e, PA_PATH_SEP_CHAR, fn);
1131 else
1132 pa_snprintf(s, l, "%s", e);
1133
1134 } else {
1135 char u[256];
1136
1137 if (fn)
1138 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);
1139 else
1140 pa_snprintf(s, l, "%s%s", PA_USER_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u)));
1141 }
1142
1143
1144 #ifdef OS_IS_WIN32
1145 {
1146 char buf[l];
1147 strcpy(buf, s);
1148 ExpandEnvironmentStrings(buf, s, l);
1149 }
1150 #endif
1151
1152 return s;
1153 }
1154
1155 /* Convert the string s to a signed integer in *ret_i */
1156 int pa_atoi(const char *s, int32_t *ret_i) {
1157 char *x = NULL;
1158 long l;
1159
1160 pa_assert(s);
1161 pa_assert(ret_i);
1162
1163 l = strtol(s, &x, 0);
1164
1165 if (!x || *x)
1166 return -1;
1167
1168 *ret_i = (int32_t) l;
1169
1170 return 0;
1171 }
1172
1173 /* Convert the string s to an unsigned integer in *ret_u */
1174 int pa_atou(const char *s, uint32_t *ret_u) {
1175 char *x = NULL;
1176 unsigned long l;
1177
1178 pa_assert(s);
1179 pa_assert(ret_u);
1180
1181 l = strtoul(s, &x, 0);
1182
1183 if (!x || *x)
1184 return -1;
1185
1186 *ret_u = (uint32_t) l;
1187
1188 return 0;
1189 }
1190
1191 /* Same as snprintf, but guarantees NUL-termination on every platform */
1192 int pa_snprintf(char *str, size_t size, const char *format, ...) {
1193 int ret;
1194 va_list ap;
1195
1196 pa_assert(str);
1197 pa_assert(size > 0);
1198 pa_assert(format);
1199
1200 va_start(ap, format);
1201 ret = vsnprintf(str, size, format, ap);
1202 va_end(ap);
1203
1204 str[size-1] = 0;
1205
1206 return ret;
1207 }
1208
1209 /* Truncate the specified string, but guarantee that the string
1210 * returned still validates as UTF8 */
1211 char *pa_truncate_utf8(char *c, size_t l) {
1212 pa_assert(c);
1213 pa_assert(pa_utf8_valid(c));
1214
1215 if (strlen(c) <= l)
1216 return c;
1217
1218 c[l] = 0;
1219
1220 while (l > 0 && !pa_utf8_valid(c))
1221 c[--l] = 0;
1222
1223 return c;
1224 }
1225
1226 char *pa_getcwd(void) {
1227 size_t l = 128;
1228
1229 for (;;) {
1230 char *p = pa_xnew(char, l);
1231 if (getcwd(p, l))
1232 return p;
1233
1234 if (errno != ERANGE)
1235 return NULL;
1236
1237 pa_xfree(p);
1238 l *= 2;
1239 }
1240 }
1241
1242 char *pa_make_path_absolute(const char *p) {
1243 char *r;
1244 char *cwd;
1245
1246 pa_assert(p);
1247
1248 if (p[0] == '/')
1249 return pa_xstrdup(p);
1250
1251 if (!(cwd = pa_getcwd()))
1252 return pa_xstrdup(p);
1253
1254 r = pa_sprintf_malloc("%s/%s", cwd, p);
1255 pa_xfree(cwd);
1256 return r;
1257 }
1258
1259 void *pa_will_need(const void *p, size_t l) {
1260 #ifdef RLIMIT_MEMLOCK
1261 struct rlimit rlim;
1262 #endif
1263 const void *a;
1264 size_t size;
1265 int r;
1266 size_t bs;
1267
1268 pa_assert(p);
1269 pa_assert(l > 0);
1270
1271 a = PA_PAGE_ALIGN_PTR(p);
1272 size = (const uint8_t*) p + l - (const uint8_t*) a;
1273
1274 #ifdef HAVE_POSIX_MADVISE
1275 if ((r = posix_madvise((void*) a, size, POSIX_MADV_WILLNEED)) == 0) {
1276 pa_log_debug("posix_madvise() worked fine!");
1277 return (void*) p;
1278 }
1279 #endif
1280
1281 /* Most likely the memory was not mmap()ed from a file and thus
1282 * madvise() didn't work, so let's misuse mlock() do page this
1283 * stuff back into RAM. Yeah, let's fuck with the MM! It's so
1284 * inviting, the man page of mlock() tells us: "All pages that
1285 * contain a part of the specified address range are guaranteed to
1286 * be resident in RAM when the call returns successfully." */
1287
1288 #ifdef RLIMIT_MEMLOCK
1289 pa_assert_se(getrlimit(RLIMIT_MEMLOCK, &rlim) == 0);
1290
1291 if (rlim.rlim_cur < PA_PAGE_SIZE) {
1292 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));
1293 return (void*) p;
1294 }
1295
1296 bs = PA_PAGE_ALIGN(rlim.rlim_cur);
1297 #else
1298 bs = PA_PAGE_SIZE*4;
1299 #endif
1300
1301 pa_log_debug("posix_madvise() failed (or doesn't exist), trying mlock(): %s", pa_cstrerror(r));
1302
1303 while (size > 0 && bs > 0) {
1304
1305 if (bs > size)
1306 bs = size;
1307
1308 if (mlock(a, bs) < 0) {
1309 bs = PA_PAGE_ALIGN(bs / 2);
1310 continue;
1311 }
1312
1313 pa_assert_se(munlock(a, bs) == 0);
1314
1315 a = (const uint8_t*) a + bs;
1316 size -= bs;
1317 }
1318
1319 if (bs <= 0)
1320 pa_log_debug("mlock() failed too, giving up: %s", pa_cstrerror(errno));
1321 else
1322 pa_log_debug("mlock() worked fine!");
1323
1324 return (void*) p;
1325 }
1326
1327 void pa_close_pipe(int fds[2]) {
1328 pa_assert(fds);
1329
1330 if (fds[0] >= 0)
1331 pa_assert_se(pa_close(fds[0]) == 0);
1332
1333 if (fds[1] >= 0)
1334 pa_assert_se(pa_close(fds[1]) == 0);
1335
1336 fds[0] = fds[1] = -1;
1337 }
1338