Add copyright notices to all relevant files. (based on svn log)
[profile/ivi/pulseaudio.git] / 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 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 /* Print a warning messages in case that the given signal is not
352  * blocked or trapped */
353 void pa_check_signal_is_blocked(int sig) {
354 #ifdef HAVE_SIGACTION
355     struct sigaction sa;
356     sigset_t set;
357
358     /* If POSIX threads are supported use thread-aware
359      * pthread_sigmask() function, to check if the signal is
360      * blocked. Otherwise fall back to sigprocmask() */
361
362 #ifdef HAVE_PTHREAD
363     if (pthread_sigmask(SIG_SETMASK, NULL, &set) < 0) {
364 #endif
365         if (sigprocmask(SIG_SETMASK, NULL, &set) < 0) {
366             pa_log("sigprocmask(): %s", pa_cstrerror(errno));
367             return;
368         }
369 #ifdef HAVE_PTHREAD
370     }
371 #endif
372
373     if (sigismember(&set, sig))
374         return;
375
376     /* Check whether the signal is trapped */
377
378     if (sigaction(sig, NULL, &sa) < 0) {
379         pa_log("sigaction(): %s", pa_cstrerror(errno));
380         return;
381     }
382
383     if (sa.sa_handler != SIG_DFL)
384         return;
385
386     pa_log("WARNING: %s is not trapped. This might cause malfunction!", pa_strsignal(sig));
387 #else /* HAVE_SIGACTION */
388     pa_log("WARNING: %s might not be trapped. This might cause malfunction!", pa_strsignal(sig));
389 #endif
390 }
391
392 /* The following function is based on an example from the GNU libc
393  * documentation. This function is similar to GNU's asprintf(). */
394 char *pa_sprintf_malloc(const char *format, ...) {
395     int  size = 100;
396     char *c = NULL;
397
398     assert(format);
399
400     for(;;) {
401         int r;
402         va_list ap;
403
404         c = pa_xrealloc(c, size);
405
406         va_start(ap, format);
407         r = vsnprintf(c, size, format, ap);
408         va_end(ap);
409
410         if (r > -1 && r < size)
411             return c;
412
413         if (r > -1)    /* glibc 2.1 */
414             size = r+1;
415         else           /* glibc 2.0 */
416             size *= 2;
417     }
418 }
419
420 /* Same as the previous function, but use a va_list instead of an
421  * ellipsis */
422 char *pa_vsprintf_malloc(const char *format, va_list ap) {
423     int  size = 100;
424     char *c = NULL;
425
426     assert(format);
427
428     for(;;) {
429         int r;
430         va_list aq;
431
432         va_copy(aq, ap);
433
434         c = pa_xrealloc(c, size);
435         r = vsnprintf(c, size, format, aq);
436
437         va_end(aq);
438
439         if (r > -1 && r < size)
440             return c;
441
442         if (r > -1)    /* glibc 2.1 */
443             size = r+1;
444         else           /* glibc 2.0 */
445             size *= 2;
446     }
447 }
448
449 /* Similar to OpenBSD's strlcpy() function */
450 char *pa_strlcpy(char *b, const char *s, size_t l) {
451     assert(b && s && l > 0);
452
453     strncpy(b, s, l);
454     b[l-1] = 0;
455     return b;
456 }
457
458 #define NICE_LEVEL (-15)
459
460 /* Raise the priority of the current process as much as possible and
461 sensible: set the nice level to -15 and enable realtime scheduling if
462 supported.*/
463 void pa_raise_priority(void) {
464
465 #ifdef HAVE_SYS_RESOURCE_H
466     if (setpriority(PRIO_PROCESS, 0, NICE_LEVEL) < 0)
467         pa_log_warn("setpriority(): %s", pa_cstrerror(errno));
468     else
469         pa_log_info("Successfully gained nice level %i.", NICE_LEVEL);
470 #endif
471
472 #ifdef _POSIX_PRIORITY_SCHEDULING
473     {
474         struct sched_param sp;
475
476         if (sched_getparam(0, &sp) < 0) {
477             pa_log("sched_getparam(): %s", pa_cstrerror(errno));
478             return;
479         }
480
481         sp.sched_priority = 1;
482         if (sched_setscheduler(0, SCHED_FIFO, &sp) < 0) {
483             pa_log_warn("sched_setscheduler(): %s", pa_cstrerror(errno));
484             return;
485         }
486
487         pa_log_info("Successfully enabled SCHED_FIFO scheduling.");
488     }
489 #endif
490
491 #ifdef OS_IS_WIN32
492     if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS))
493         pa_log_warn("SetPriorityClass() failed: 0x%08X", GetLastError());
494     else
495         pa_log_info("Successfully gained high priority class.");
496 #endif
497 }
498
499 /* Reset the priority to normal, inverting the changes made by pa_raise_priority() */
500 void pa_reset_priority(void) {
501 #ifdef OS_IS_WIN32
502     SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS);
503 #endif
504
505 #ifdef _POSIX_PRIORITY_SCHEDULING
506     {
507         struct sched_param sp;
508         sched_getparam(0, &sp);
509         sp.sched_priority = 0;
510         sched_setscheduler(0, SCHED_OTHER, &sp);
511     }
512 #endif
513
514 #ifdef HAVE_SYS_RESOURCE_H
515     setpriority(PRIO_PROCESS, 0, 0);
516 #endif
517 }
518
519 /* Set the FD_CLOEXEC flag for a fd */
520 int pa_fd_set_cloexec(int fd, int b) {
521
522 #ifdef FD_CLOEXEC
523     int v;
524     assert(fd >= 0);
525
526     if ((v = fcntl(fd, F_GETFD, 0)) < 0)
527         return -1;
528
529     v = (v & ~FD_CLOEXEC) | (b ? FD_CLOEXEC : 0);
530
531     if (fcntl(fd, F_SETFD, v) < 0)
532         return -1;
533 #endif
534
535     return 0;
536 }
537
538 /* Try to parse a boolean string value.*/
539 int pa_parse_boolean(const char *v) {
540
541     if (!strcmp(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || !strcasecmp(v, "on"))
542         return 1;
543     else if (!strcmp(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || !strcasecmp(v, "off"))
544         return 0;
545
546     return -1;
547 }
548
549 /* Split the specified string wherever one of the strings in delimiter
550  * occurs. Each time it is called returns a newly allocated string
551  * with pa_xmalloc(). The variable state points to, should be
552  * initiallized to NULL before the first call. */
553 char *pa_split(const char *c, const char *delimiter, const char**state) {
554     const char *current = *state ? *state : c;
555     size_t l;
556
557     if (!*current)
558         return NULL;
559
560     l = strcspn(current, delimiter);
561     *state = current+l;
562
563     if (**state)
564         (*state)++;
565
566     return pa_xstrndup(current, l);
567 }
568
569 /* What is interpreted as whitespace? */
570 #define WHITESPACE " \t\n"
571
572 /* Split a string into words. Otherwise similar to pa_split(). */
573 char *pa_split_spaces(const char *c, const char **state) {
574     const char *current = *state ? *state : c;
575     size_t l;
576
577     if (!*current || *c == 0)
578         return NULL;
579
580     current += strspn(current, WHITESPACE);
581     l = strcspn(current, WHITESPACE);
582
583     *state = current+l;
584
585     return pa_xstrndup(current, l);
586 }
587
588 /* Return the name of an UNIX signal. Similar to GNU's strsignal() */
589 const char *pa_strsignal(int sig) {
590     switch(sig) {
591         case SIGINT: return "SIGINT";
592         case SIGTERM: return "SIGTERM";
593 #ifdef SIGUSR1
594         case SIGUSR1: return "SIGUSR1";
595 #endif
596 #ifdef SIGUSR2
597         case SIGUSR2: return "SIGUSR2";
598 #endif
599 #ifdef SIGXCPU
600         case SIGXCPU: return "SIGXCPU";
601 #endif
602 #ifdef SIGPIPE
603         case SIGPIPE: return "SIGPIPE";
604 #endif
605 #ifdef SIGCHLD
606         case SIGCHLD: return "SIGCHLD";
607 #endif
608 #ifdef SIGHUP
609         case SIGHUP: return "SIGHUP";
610 #endif
611         default: return "UNKNOWN SIGNAL";
612     }
613 }
614
615 #ifdef HAVE_GRP_H
616
617 /* Check whether the specified GID and the group name match */
618 static int is_group(gid_t gid, const char *name) {
619     struct group group, *result = NULL;
620     long n;
621     void *data;
622     int r = -1;
623
624 #ifdef HAVE_GETGRGID_R
625 #ifdef _SC_GETGR_R_SIZE_MAX
626     n = sysconf(_SC_GETGR_R_SIZE_MAX);
627 #else
628     n = -1;
629 #endif
630     if (n < 0) n = 512;
631     data = pa_xmalloc(n);
632
633     if (getgrgid_r(gid, &group, data, n, &result) < 0 || !result) {
634         pa_log("getgrgid_r(%u): %s", (unsigned)gid, pa_cstrerror(errno));
635         goto finish;
636     }
637
638     r = strcmp(name, result->gr_name) == 0;
639
640 finish:
641     pa_xfree(data);
642 #else
643     /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) that do not
644      * support getgrgid_r. */
645     if ((result = getgrgid(gid)) == NULL) {
646         pa_log("getgrgid(%u): %s", gid, pa_cstrerror(errno));
647         goto finish;
648     }
649
650     r = strcmp(name, result->gr_name) == 0;
651
652 finish:
653 #endif
654
655     return r;
656 }
657
658 /* Check the current user is member of the specified group */
659 int pa_own_uid_in_group(const char *name, gid_t *gid) {
660     GETGROUPS_T *gids, tgid;
661     int n = sysconf(_SC_NGROUPS_MAX);
662     int r = -1, i;
663
664     assert(n > 0);
665
666     gids = pa_xmalloc(sizeof(GETGROUPS_T)*n);
667
668     if ((n = getgroups(n, gids)) < 0) {
669         pa_log("getgroups(): %s", pa_cstrerror(errno));
670         goto finish;
671     }
672
673     for (i = 0; i < n; i++) {
674         if (is_group(gids[i], name) > 0) {
675             *gid = gids[i];
676             r = 1;
677             goto finish;
678         }
679     }
680
681     if (is_group(tgid = getgid(), name) > 0) {
682         *gid = tgid;
683         r = 1;
684         goto finish;
685     }
686
687     r = 0;
688
689 finish:
690
691     pa_xfree(gids);
692     return r;
693 }
694
695 /* Check whether the specifc user id is a member of the specified group */
696 int pa_uid_in_group(uid_t uid, const char *name) {
697     char *g_buf, *p_buf;
698     long g_n, p_n;
699     struct group grbuf, *gr;
700     char **i;
701     int r = -1;
702
703     g_n = sysconf(_SC_GETGR_R_SIZE_MAX);
704     g_buf = pa_xmalloc(g_n);
705
706     p_n = sysconf(_SC_GETPW_R_SIZE_MAX);
707     p_buf = pa_xmalloc(p_n);
708
709     if (getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr) != 0 || !gr)
710         goto finish;
711
712     r = 0;
713     for (i = gr->gr_mem; *i; i++) {
714         struct passwd pwbuf, *pw;
715
716         if (getpwnam_r(*i, &pwbuf, p_buf, (size_t) p_n, &pw) != 0 || !pw)
717             continue;
718
719         if (pw->pw_uid == uid) {
720             r = 1;
721             break;
722         }
723     }
724
725 finish:
726     pa_xfree(g_buf);
727     pa_xfree(p_buf);
728
729     return r;
730 }
731
732 /* Get the GID of a gfiven group, return (gid_t) -1 on failure. */
733 gid_t pa_get_gid_of_group(const char *name) {
734     gid_t ret = (gid_t) -1;
735     char *g_buf;
736     long g_n;
737     struct group grbuf, *gr;
738
739     g_n = sysconf(_SC_GETGR_R_SIZE_MAX);
740     g_buf = pa_xmalloc(g_n);
741
742     if (getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr) != 0 || !gr)
743         goto finish;
744
745     ret = gr->gr_gid;
746
747 finish:
748     pa_xfree(g_buf);
749     return ret;
750 }
751
752 int pa_check_in_group(gid_t g) {
753     gid_t gids[NGROUPS_MAX];
754     int r;
755
756     if ((r = getgroups(NGROUPS_MAX, gids)) < 0)
757         return -1;
758
759     for (; r > 0; r--)
760         if (gids[r-1] == g)
761             return 1;
762
763     return 0;
764 }
765
766 #else /* HAVE_GRP_H */
767
768 int pa_own_uid_in_group(const char *name, gid_t *gid) {
769     return -1;
770
771 }
772
773 int pa_uid_in_group(uid_t uid, const char *name) {
774     return -1;
775 }
776
777 gid_t pa_get_gid_of_group(const char *name) {
778     return (gid_t) -1;
779 }
780
781 int pa_check_in_group(gid_t g) {
782     return -1;
783 }
784
785 #endif
786
787 /* Lock or unlock a file entirely.
788   (advisory on UNIX, mandatory on Windows) */
789 int pa_lock_fd(int fd, int b) {
790 #ifdef F_SETLKW
791     struct flock flock;
792
793     /* Try a R/W lock first */
794
795     flock.l_type = b ? F_WRLCK : F_UNLCK;
796     flock.l_whence = SEEK_SET;
797     flock.l_start = 0;
798     flock.l_len = 0;
799
800     if (fcntl(fd, F_SETLKW, &flock) >= 0)
801         return 0;
802
803     /* Perhaps the file descriptor qas opened for read only, than try again with a read lock. */
804     if (b && errno == EBADF) {
805         flock.l_type = F_RDLCK;
806         if (fcntl(fd, F_SETLKW, &flock) >= 0)
807             return 0;
808     }
809
810     pa_log("%slock: %s", !b? "un" : "",
811         pa_cstrerror(errno));
812 #endif
813
814 #ifdef OS_IS_WIN32
815     HANDLE h = (HANDLE)_get_osfhandle(fd);
816
817     if (b && LockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF))
818         return 0;
819     if (!b && UnlockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF))
820         return 0;
821
822     pa_log("%slock failed: 0x%08X", !b ? "un" : "", GetLastError());
823 #endif
824
825     return -1;
826 }
827
828 /* Remove trailing newlines from a string */
829 char* pa_strip_nl(char *s) {
830     assert(s);
831
832     s[strcspn(s, "\r\n")] = 0;
833     return s;
834 }
835
836 /* Create a temporary lock file and lock it. */
837 int pa_lock_lockfile(const char *fn) {
838     int fd = -1;
839     assert(fn);
840
841     for (;;) {
842         struct stat st;
843
844         if ((fd = open(fn, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR)) < 0) {
845             pa_log("failed to create lock file '%s': %s", fn,
846                 pa_cstrerror(errno));
847             goto fail;
848         }
849
850         if (pa_lock_fd(fd, 1) < 0) {
851             pa_log("failed to lock file '%s'.", fn);
852             goto fail;
853         }
854
855         if (fstat(fd, &st) < 0) {
856             pa_log("failed to fstat() file '%s'.", fn);
857             goto fail;
858         }
859
860         /* Check wheter the file has been removed meanwhile. When yes, restart this loop, otherwise, we're done */
861         if (st.st_nlink >= 1)
862             break;
863
864         if (pa_lock_fd(fd, 0) < 0) {
865             pa_log("failed to unlock file '%s'.", fn);
866             goto fail;
867         }
868
869         if (close(fd) < 0) {
870             pa_log("failed to close file '%s'.", fn);
871             goto fail;
872         }
873
874         fd = -1;
875     }
876
877     return fd;
878
879 fail:
880
881     if (fd >= 0)
882         close(fd);
883
884     return -1;
885 }
886
887 /* Unlock a temporary lcok file */
888 int pa_unlock_lockfile(const char *fn, int fd) {
889     int r = 0;
890     assert(fn && fd >= 0);
891
892     if (unlink(fn) < 0) {
893         pa_log_warn("WARNING: unable to remove lock file '%s': %s",
894             fn, pa_cstrerror(errno));
895         r = -1;
896     }
897
898     if (pa_lock_fd(fd, 0) < 0) {
899         pa_log_warn("WARNING: failed to unlock file '%s'.", fn);
900         r = -1;
901     }
902
903     if (close(fd) < 0) {
904         pa_log_warn("WARNING: failed to close lock file '%s': %s",
905             fn, pa_cstrerror(errno));
906         r = -1;
907     }
908
909     return r;
910 }
911
912 /* Try to open a configuration file. If "env" is specified, open the
913  * value of the specified environment variable. Otherwise look for a
914  * file "local" in the home directory or a file "global" in global
915  * file system. If "result" is non-NULL, a pointer to a newly
916  * allocated buffer containing the used configuration file is
917  * stored there.*/
918 FILE *pa_open_config_file(const char *global, const char *local, const char *env, char **result, const char *mode) {
919     const char *fn;
920     char h[PATH_MAX];
921
922 #ifdef OS_IS_WIN32
923     char buf[PATH_MAX];
924
925     if (!getenv(PULSE_ROOTENV))
926         pa_set_root(NULL);
927 #endif
928
929     if (env && (fn = getenv(env))) {
930 #ifdef OS_IS_WIN32
931         if (!ExpandEnvironmentStrings(fn, buf, PATH_MAX))
932             return NULL;
933         fn = buf;
934 #endif
935
936         if (result)
937             *result = pa_xstrdup(fn);
938
939         return fopen(fn, mode);
940     }
941
942     if (local) {
943         const char *e;
944         char *lfn = NULL;
945
946         if ((e = getenv("PULSE_CONFIG_PATH")))
947             fn = lfn = pa_sprintf_malloc("%s/%s", e, local);
948         else if (pa_get_home_dir(h, sizeof(h)))
949             fn = lfn = pa_sprintf_malloc("%s/.pulse/%s", h, local);
950
951         if (lfn) {
952             FILE *f;
953
954 #ifdef OS_IS_WIN32
955             if (!ExpandEnvironmentStrings(lfn, buf, PATH_MAX))
956                 return NULL;
957             fn = buf;
958 #endif
959
960             f = fopen(fn, mode);
961             if (f != NULL) {
962                 if (result)
963                     *result = pa_xstrdup(fn);
964                 pa_xfree(lfn);
965                 return f;
966             }
967
968             if (errno != ENOENT) {
969                 pa_log_warn("WARNING: failed to open configuration file '%s': %s",
970                     lfn, pa_cstrerror(errno));
971             }
972
973             pa_xfree(lfn);
974         }
975     }
976
977     if (!global) {
978         if (result)
979             *result = NULL;
980         errno = ENOENT;
981         return NULL;
982     }
983
984 #ifdef OS_IS_WIN32
985     if (!ExpandEnvironmentStrings(global, buf, PATH_MAX))
986         return NULL;
987     global = buf;
988 #endif
989
990     if (result)
991         *result = pa_xstrdup(global);
992
993     return fopen(global, mode);
994 }
995
996 /* Format the specified data as a hexademical string */
997 char *pa_hexstr(const uint8_t* d, size_t dlength, char *s, size_t slength) {
998     size_t i = 0, j = 0;
999     const char hex[] = "0123456789abcdef";
1000     assert(d && s && slength > 0);
1001
1002     while (i < dlength && j+3 <= slength) {
1003         s[j++] = hex[*d >> 4];
1004         s[j++] = hex[*d & 0xF];
1005
1006         d++;
1007         i++;
1008     }
1009
1010     s[j < slength ? j : slength] = 0;
1011     return s;
1012 }
1013
1014 /* Convert a hexadecimal digit to a number or -1 if invalid */
1015 static int hexc(char c) {
1016     if (c >= '0' && c <= '9')
1017         return c - '0';
1018
1019     if (c >= 'A' && c <= 'F')
1020         return c - 'A' + 10;
1021
1022     if (c >= 'a' && c <= 'f')
1023         return c - 'a' + 10;
1024
1025     return -1;
1026 }
1027
1028 /* Parse a hexadecimal string as created by pa_hexstr() to a BLOB */
1029 size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength) {
1030     size_t j = 0;
1031     assert(p && d);
1032
1033     while (j < dlength && *p) {
1034         int b;
1035
1036         if ((b = hexc(*(p++))) < 0)
1037             return (size_t) -1;
1038
1039         d[j] = (uint8_t) (b << 4);
1040
1041         if (!*p)
1042             return (size_t) -1;
1043
1044         if ((b = hexc(*(p++))) < 0)
1045             return (size_t) -1;
1046
1047         d[j] |= (uint8_t) b;
1048         j++;
1049     }
1050
1051     return j;
1052 }
1053
1054 /* Returns nonzero when *s starts with *pfx */
1055 int pa_startswith(const char *s, const char *pfx) {
1056     size_t l;
1057
1058     assert(s);
1059     assert(pfx);
1060
1061     l = strlen(pfx);
1062
1063     return strlen(s) >= l && strncmp(s, pfx, l) == 0;
1064 }
1065
1066 /* Returns nonzero when *s ends with *sfx */
1067 int pa_endswith(const char *s, const char *sfx) {
1068     size_t l1, l2;
1069
1070     assert(s);
1071     assert(sfx);
1072
1073     l1 = strlen(s);
1074     l2 = strlen(sfx);
1075
1076     return l1 >= l2 && strcmp(s+l1-l2, sfx) == 0;
1077 }
1078
1079 /* if fn is null return the PulseAudio run time path in s (/tmp/pulse)
1080  * if fn is non-null and starts with / return fn in s
1081  * otherwise append fn to the run time path and return it in s */
1082 char *pa_runtime_path(const char *fn, char *s, size_t l) {
1083     const char *e;
1084
1085 #ifndef OS_IS_WIN32
1086     if (fn && *fn == '/')
1087 #else
1088     if (fn && strlen(fn) >= 3 && isalpha(fn[0]) && fn[1] == ':' && fn[2] == '\\')
1089 #endif
1090         return pa_strlcpy(s, fn, l);
1091
1092     if ((e = getenv("PULSE_RUNTIME_PATH"))) {
1093
1094         if (fn)
1095             snprintf(s, l, "%s%c%s", e, PATH_SEP, fn);
1096         else
1097             snprintf(s, l, "%s", e);
1098
1099     } else {
1100         char u[256];
1101
1102         if (fn)
1103             snprintf(s, l, "%s%s%c%s", PA_USER_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u)), PATH_SEP, fn);
1104         else
1105             snprintf(s, l, "%s%s", PA_USER_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u)));
1106     }
1107
1108
1109 #ifdef OS_IS_WIN32
1110     {
1111         char buf[l];
1112         strcpy(buf, s);
1113         ExpandEnvironmentStrings(buf, s, l);
1114     }
1115 #endif
1116
1117     return s;
1118 }
1119
1120 /* Convert the string s to a signed integer in *ret_i */
1121 int pa_atoi(const char *s, int32_t *ret_i) {
1122     char *x = NULL;
1123     long l;
1124     assert(s && ret_i);
1125
1126     l = strtol(s, &x, 0);
1127
1128     if (!x || *x)
1129         return -1;
1130
1131     *ret_i = (int32_t) l;
1132
1133     return 0;
1134 }
1135
1136 /* Convert the string s to an unsigned integer in *ret_u */
1137 int pa_atou(const char *s, uint32_t *ret_u) {
1138     char *x = NULL;
1139     unsigned long l;
1140     assert(s && ret_u);
1141
1142     l = strtoul(s, &x, 0);
1143
1144     if (!x || *x)
1145         return -1;
1146
1147     *ret_u = (uint32_t) l;
1148
1149     return 0;
1150 }