]> code.delx.au - pulseaudio/blob - polyp/util.c
add module-combine
[pulseaudio] / 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 }