add module-combine
[profile/ivi/pulseaudio-panda.git] / polyp / 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 General Public License as published
8   by the Free Software Foundation; either version 2 of the License,
9   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   General Public License for more details.
15  
16   You should have received a copy of the GNU General Public License
17   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 <sys/types.h>
36 #include <pwd.h>
37 #include <signal.h>
38 #include <pthread.h>
39 #include <sys/time.h>
40 #include <sched.h>
41 #include <sys/resource.h>
42 #include <limits.h>
43
44 #include "util.h"
45 #include "xmalloc.h"
46 #include "log.h"
47
48 void pa_make_nonblock_fd(int fd) {
49     int v;
50
51     if ((v = fcntl(fd, F_GETFL)) >= 0)
52         if (!(v & O_NONBLOCK))
53             fcntl(fd, F_SETFL, v|O_NONBLOCK);
54 }
55
56 int pa_make_secure_dir(const char* dir) {
57     struct stat st;
58
59     if (mkdir(dir, 0700) < 0) 
60         if (errno != EEXIST)
61             return -1;
62     
63     if (lstat(dir, &st) < 0) 
64         goto fail;
65     
66     if (!S_ISDIR(st.st_mode) || (st.st_uid != getuid()) || ((st.st_mode & 0777) != 0700))
67         goto fail;
68     
69     return 0;
70     
71 fail:
72     rmdir(dir);
73     return -1;
74 }
75
76 ssize_t pa_loop_read(int fd, void*data, size_t size) {
77     ssize_t ret = 0;
78     assert(fd >= 0 && data && size);
79
80     while (size > 0) {
81         ssize_t r;
82
83         if ((r = read(fd, data, size)) < 0)
84             return r;
85
86         if (r == 0)
87             break;
88         
89         ret += r;
90         data = (uint8_t*) data + r;
91         size -= r;
92     }
93
94     return ret;
95 }
96
97 ssize_t pa_loop_write(int fd, const void*data, size_t size) {
98     ssize_t ret = 0;
99     assert(fd >= 0 && data && size);
100
101     while (size > 0) {
102         ssize_t r;
103
104         if ((r = write(fd, data, size)) < 0)
105             return r;
106
107         if (r == 0)
108             break;
109         
110         ret += r;
111         data = (uint8_t*) data + r;
112         size -= r;
113     }
114
115     return ret;
116 }
117
118 void pa_check_for_sigpipe(void) {
119     struct sigaction sa;
120     sigset_t set;
121
122 #ifdef HAVE_PTHREAD    
123     if (pthread_sigmask(SIG_SETMASK, NULL, &set) < 0) {
124 #endif
125         if (sigprocmask(SIG_SETMASK, NULL, &set) < 0) {
126             pa_log(__FILE__": sigprocmask() failed: %s\n", strerror(errno));
127             return;
128         }
129 #ifdef HAVE_PTHREAD
130     }
131 #endif
132
133     if (sigismember(&set, SIGPIPE))
134         return;
135     
136     if (sigaction(SIGPIPE, NULL, &sa) < 0) {
137         pa_log(__FILE__": sigaction() failed: %s\n", strerror(errno));
138         return;
139     }
140         
141     if (sa.sa_handler != SIG_DFL)
142         return;
143     
144     pa_log(__FILE__": WARNING: SIGPIPE is not trapped. This might cause malfunction!\n");
145 }
146
147 /* The following is based on an example from the GNU libc documentation */
148 char *pa_sprintf_malloc(const char *format, ...) {
149     int  size = 100;
150     char *c = NULL;
151     
152     assert(format);
153     
154     for(;;) {
155         int r;
156         va_list ap;
157
158         c = pa_xrealloc(c, size);
159
160         va_start(ap, format);
161         r = vsnprintf(c, size, format, ap);
162         va_end(ap);
163         
164         if (r > -1 && r < size)
165             return c;
166
167         if (r > -1)    /* glibc 2.1 */
168             size = r+1; 
169         else           /* glibc 2.0 */
170             size *= 2;
171     }
172 }
173
174 char *pa_vsprintf_malloc(const char *format, va_list ap) {
175     int  size = 100;
176     char *c = NULL;
177     
178     assert(format);
179     
180     for(;;) {
181         int r;
182         va_list ap;
183
184         c = pa_xrealloc(c, size);
185         r = vsnprintf(c, size, format, ap);
186         
187         if (r > -1 && r < size)
188             return c;
189
190         if (r > -1)    /* glibc 2.1 */
191             size = r+1; 
192         else           /* glibc 2.0 */
193             size *= 2;
194     }
195 }
196
197
198 char *pa_get_user_name(char *s, size_t l) {
199     struct passwd pw, *r;
200     char buf[1024];
201     char *p;
202
203     if (!(p = getenv("USER")))
204         if (!(p = getenv("LOGNAME")))
205             if (!(p = getenv("USERNAME"))) {
206                 
207                 if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) {
208                     snprintf(s, l, "%lu", (unsigned long) getuid());
209                     return s;
210                 }
211                 
212                 p = r->pw_name;
213             }
214     
215     snprintf(s, l, "%s", p);
216     return s;
217 }
218
219 char *pa_get_host_name(char *s, size_t l) {
220     gethostname(s, l);
221     s[l-1] = 0;
222     return s;
223 }
224
225 pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b) {
226     pa_usec_t r;
227     assert(a && b);
228
229     if (pa_timeval_cmp(a, b) < 0) {
230         const struct timeval *c;
231         c = a;
232         a = b;
233         b = c;
234     }
235
236     r = ((pa_usec_t) a->tv_sec - b->tv_sec)* 1000000;
237
238     if (a->tv_usec > b->tv_usec)
239         r += ((pa_usec_t) a->tv_usec - b->tv_usec);
240     else if (a->tv_usec < b->tv_usec)
241         r -= ((pa_usec_t) b->tv_usec - a->tv_usec);
242
243     return r;
244 }
245
246 int pa_timeval_cmp(const struct timeval *a, const struct timeval *b) {
247     assert(a && b);
248
249     if (a->tv_sec < b->tv_sec)
250         return -1;
251
252     if (a->tv_sec > b->tv_sec)
253         return 1;
254
255     if (a->tv_usec < b->tv_usec)
256         return -1;
257
258     if (a->tv_usec > b->tv_usec)
259         return 1;
260
261     return 0;
262 }
263
264 pa_usec_t pa_age(const struct timeval *tv) {
265     struct timeval now;
266     assert(tv);
267     gettimeofday(&now, NULL);
268     return pa_timeval_diff(&now, tv);
269 }
270
271 void pa_timeval_add(struct timeval *tv, pa_usec_t v) {
272     unsigned long secs;
273     assert(tv);
274     
275     secs = (v/1000000);
276     tv->tv_sec += (unsigned long) secs;
277     v -= secs*1000000;
278
279     tv->tv_usec += v;
280
281     while (tv->tv_usec >= 1000000) {
282         tv->tv_sec++;
283         tv->tv_usec -= 1000000;
284     }
285 }
286
287 #define NICE_LEVEL (-15)
288
289 void pa_raise_priority(void) {
290     if (setpriority(PRIO_PROCESS, 0, NICE_LEVEL) < 0)
291         pa_log(__FILE__": setpriority() failed: %s\n", strerror(errno));
292     else
293         pa_log(__FILE__": Successfully gained nice level %i.\n", NICE_LEVEL);
294
295 #ifdef _POSIX_PRIORITY_SCHEDULING
296     {
297         struct sched_param sp;
298
299         if (sched_getparam(0, &sp) < 0) {
300             pa_log(__FILE__": sched_getparam() failed: %s\n", strerror(errno));
301             return;
302         }
303         
304         sp.sched_priority = 1;
305         if (sched_setscheduler(0, SCHED_FIFO, &sp) < 0) {
306             pa_log(__FILE__": sched_setscheduler() failed: %s\n", strerror(errno));
307             return;
308         }
309
310         pa_log(__FILE__": Successfully enabled SCHED_FIFO scheduling.\n");
311     }
312 #endif
313 }
314
315 void pa_reset_priority(void) {
316 #ifdef _POSIX_PRIORITY_SCHEDULING
317     {
318         struct sched_param sp;
319         sched_getparam(0, &sp);
320         sp.sched_priority = 0;
321         sched_setscheduler(0, SCHED_OTHER, &sp);
322     }
323 #endif
324
325     setpriority(PRIO_PROCESS, 0, 0);
326 }
327
328 int pa_fd_set_cloexec(int fd, int b) {
329     int v;
330     assert(fd >= 0);
331
332     if ((v = fcntl(fd, F_GETFD, 0)) < 0)
333         return -1;
334     
335     v = (v & ~FD_CLOEXEC) | (b ? FD_CLOEXEC : 0);
336     
337     if (fcntl(fd, F_SETFD, v) < 0)
338         return -1;
339     
340     return 0;
341 }
342
343 char *pa_get_binary_name(char *s, size_t l) {
344     char path[PATH_MAX];
345     int i;
346     assert(s && l);
347
348     /* This works on Linux only */
349     
350     snprintf(path, sizeof(path), "/proc/%u/exe", (unsigned) getpid());
351     if ((i = readlink(path, s, l-1)) < 0)
352         return NULL;
353
354     s[i] = 0;
355     return s;
356 }
357
358 char *pa_path_get_filename(const char *p) {
359     char *fn;
360
361     if ((fn = strrchr(p, '/')))
362         return fn+1;
363
364     return (char*) p;
365 }
366
367 int pa_parse_boolean(const char *v) {
368     
369     if (!strcmp(v, "1") || !strcasecmp(v, "yes") || !strcasecmp(v, "y") || !strcasecmp(v, "on"))
370         return 1;
371     else if (!strcmp(v, "0") || !strcasecmp(v, "no") || !strcasecmp(v, "n") || !strcasecmp(v, "off"))
372         return 0;
373
374     return -1;
375 }
376
377 char *pa_split(const char *c, const char *delimiter, const char**state) {
378     const char *current = *state ? *state : c;
379     size_t l;
380
381     if (!*current)
382         return NULL;
383     
384     l = strcspn(current, delimiter);
385     *state = current+l;
386
387     if (**state)
388         *state++;
389
390     return pa_xstrndup(current, l);
391 }