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