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