File: | src/usr.bin/sndiod/sndiod.c |
Warning: | line 609, column 2 Value stored to 'argv' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: sndiod.c,v 1.47 2021/11/01 14:43:25 ratchov Exp $ */ |
2 | /* |
3 | * Copyright (c) 2008-2012 Alexandre Ratchov <alex@caoua.org> |
4 | * |
5 | * Permission to use, copy, modify, and distribute this software for any |
6 | * purpose with or without fee is hereby granted, provided that the above |
7 | * copyright notice and this permission notice appear in all copies. |
8 | * |
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
16 | */ |
17 | #include <sys/stat.h> |
18 | #include <sys/types.h> |
19 | #include <sys/resource.h> |
20 | #include <sys/socket.h> |
21 | |
22 | #include <err.h> |
23 | #include <errno(*__errno()).h> |
24 | #include <fcntl.h> |
25 | #include <grp.h> |
26 | #include <limits.h> |
27 | #include <pwd.h> |
28 | #include <signal.h> |
29 | #include <sndio.h> |
30 | #include <stdio.h> |
31 | #include <stdlib.h> |
32 | #include <string.h> |
33 | #include <unistd.h> |
34 | |
35 | #include "amsg.h" |
36 | #include "defs.h" |
37 | #include "dev.h" |
38 | #include "fdpass.h" |
39 | #include "file.h" |
40 | #include "listen.h" |
41 | #include "midi.h" |
42 | #include "opt.h" |
43 | #include "sock.h" |
44 | #include "utils.h" |
45 | |
46 | /* |
47 | * unprivileged user name |
48 | */ |
49 | #ifndef SNDIO_USER"_sndio" |
50 | #define SNDIO_USER"_sndio" "_sndio" |
51 | #endif |
52 | |
53 | /* |
54 | * privileged user name |
55 | */ |
56 | #ifndef SNDIO_PRIV_USER"_sndiop" |
57 | #define SNDIO_PRIV_USER"_sndiop" "_sndiop" |
58 | #endif |
59 | |
60 | /* |
61 | * priority when run as root |
62 | */ |
63 | #ifndef SNDIO_PRIO(-20) |
64 | #define SNDIO_PRIO(-20) (-20) |
65 | #endif |
66 | |
67 | /* |
68 | * sample rate if no ``-r'' is used |
69 | */ |
70 | #ifndef DEFAULT_RATE48000 |
71 | #define DEFAULT_RATE48000 48000 |
72 | #endif |
73 | |
74 | /* |
75 | * block size if neither ``-z'' nor ``-b'' is used |
76 | */ |
77 | #ifndef DEFAULT_ROUND480 |
78 | #define DEFAULT_ROUND480 480 |
79 | #endif |
80 | |
81 | /* |
82 | * buffer size if neither ``-z'' nor ``-b'' is used |
83 | */ |
84 | #ifndef DEFAULT_BUFSZ7680 |
85 | #define DEFAULT_BUFSZ7680 7680 |
86 | #endif |
87 | |
88 | void sigint(int); |
89 | void sighup(int); |
90 | void opt_ch(int *, int *); |
91 | void opt_enc(struct aparams *); |
92 | int opt_mmc(void); |
93 | int opt_onoff(void); |
94 | int getword(char *, char **); |
95 | unsigned int opt_mode(void); |
96 | void getbasepath(char *); |
97 | void setsig(void); |
98 | void unsetsig(void); |
99 | struct dev *mkdev(char *, struct aparams *, |
100 | int, int, int, int, int, int); |
101 | struct port *mkport(char *, int); |
102 | struct opt *mkopt(char *, struct dev *, |
103 | int, int, int, int, int, int, int, int); |
104 | |
105 | unsigned int log_level = 0; |
106 | volatile sig_atomic_t quit_flag = 0, reopen_flag = 0; |
107 | |
108 | char usagestr[] = "usage: sndiod [-d] [-a flag] [-b nframes] " |
109 | "[-C min:max] [-c min:max]\n\t" |
110 | "[-e enc] [-F device] [-f device] [-j flag] [-L addr] [-m mode]\n\t" |
111 | "[-Q port] [-q port] [-r rate] [-s name] [-t mode] [-U unit]\n\t" |
112 | "[-v volume] [-w flag] [-z nframes]\n"; |
113 | |
114 | /* |
115 | * default audio devices |
116 | */ |
117 | static char *default_devs[] = { |
118 | "rsnd/0", "rsnd/1", "rsnd/2", "rsnd/3", |
119 | NULL((void*)0) |
120 | }; |
121 | |
122 | /* |
123 | * default MIDI ports |
124 | */ |
125 | static char *default_ports[] = { |
126 | "rmidi/0", "rmidi/1", "rmidi/2", "rmidi/3", |
127 | "rmidi/4", "rmidi/5", "rmidi/6", "rmidi/7", |
128 | NULL((void*)0) |
129 | }; |
130 | |
131 | /* |
132 | * SIGINT handler, it raises the quit flag. If the flag is already set, |
133 | * that means that the last SIGINT was not handled, because the process |
134 | * is blocked somewhere, so exit. |
135 | */ |
136 | void |
137 | sigint(int s) |
138 | { |
139 | if (quit_flag) |
140 | _exit(1); |
141 | quit_flag = 1; |
142 | } |
143 | |
144 | /* |
145 | * SIGHUP handler, it raises the reopen flag, which requests devices |
146 | * to be reopened. |
147 | */ |
148 | void |
149 | sighup(int s) |
150 | { |
151 | reopen_flag = 1; |
152 | } |
153 | |
154 | void |
155 | opt_ch(int *rcmin, int *rcmax) |
156 | { |
157 | char *next, *end; |
158 | long cmin, cmax; |
159 | |
160 | errno(*__errno()) = 0; |
161 | cmin = strtol(optarg, &next, 10); |
162 | if (next == optarg || *next != ':') |
163 | goto failed; |
164 | cmax = strtol(++next, &end, 10); |
165 | if (end == next || *end != '\0') |
166 | goto failed; |
167 | if (cmin < 0 || cmax < cmin || cmax >= NCHAN_MAX64) |
168 | goto failed; |
169 | *rcmin = cmin; |
170 | *rcmax = cmax; |
171 | return; |
172 | failed: |
173 | errx(1, "%s: bad channel range", optarg); |
174 | } |
175 | |
176 | void |
177 | opt_enc(struct aparams *par) |
178 | { |
179 | int len; |
180 | |
181 | len = aparams_strtoenc(par, optarg); |
182 | if (len == 0 || optarg[len] != '\0') |
183 | errx(1, "%s: bad encoding", optarg); |
184 | } |
185 | |
186 | int |
187 | opt_mmc(void) |
188 | { |
189 | if (strcmp("off", optarg) == 0) |
190 | return 0; |
191 | if (strcmp("slave", optarg) == 0) |
192 | return 1; |
193 | errx(1, "%s: off/slave expected", optarg); |
194 | } |
195 | |
196 | int |
197 | opt_onoff(void) |
198 | { |
199 | if (strcmp("off", optarg) == 0) |
200 | return 0; |
201 | if (strcmp("on", optarg) == 0) |
202 | return 1; |
203 | errx(1, "%s: on/off expected", optarg); |
204 | } |
205 | |
206 | int |
207 | getword(char *word, char **str) |
208 | { |
209 | char *p = *str; |
210 | |
211 | for (;;) { |
212 | if (*word == '\0') |
213 | break; |
214 | if (*word++ != *p++) |
215 | return 0; |
216 | } |
217 | if (*p == ',' || *p == '\0') { |
218 | *str = p; |
219 | return 1; |
220 | } |
221 | return 0; |
222 | } |
223 | |
224 | unsigned int |
225 | opt_mode(void) |
226 | { |
227 | unsigned int mode = 0; |
228 | char *p = optarg; |
229 | |
230 | for (;;) { |
231 | if (getword("play", &p)) { |
232 | mode |= MODE_PLAY0x01; |
233 | } else if (getword("rec", &p)) { |
234 | mode |= MODE_REC0x02; |
235 | } else if (getword("mon", &p)) { |
236 | mode |= MODE_MON0x10; |
237 | } else if (getword("midi", &p)) { |
238 | mode |= MODE_MIDIMASK(0x08 | 0x04); |
239 | } else |
240 | errx(1, "%s: bad mode", optarg); |
241 | if (*p == '\0') |
242 | break; |
243 | p++; |
244 | } |
245 | if (mode == 0) |
246 | errx(1, "empty mode"); |
247 | return mode; |
248 | } |
249 | |
250 | void |
251 | setsig(void) |
252 | { |
253 | struct sigaction sa; |
254 | |
255 | quit_flag = 0; |
256 | reopen_flag = 0; |
257 | sigfillset(&sa.sa_mask); |
258 | sa.sa_flags = SA_RESTART0x0002; |
259 | sa.sa_handler__sigaction_u.__sa_handler = sigint; |
260 | if (sigaction(SIGINT2, &sa, NULL((void*)0)) == -1) |
261 | err(1, "sigaction(int) failed"); |
262 | if (sigaction(SIGTERM15, &sa, NULL((void*)0)) == -1) |
263 | err(1, "sigaction(term) failed"); |
264 | sa.sa_handler__sigaction_u.__sa_handler = sighup; |
265 | if (sigaction(SIGHUP1, &sa, NULL((void*)0)) == -1) |
266 | err(1, "sigaction(hup) failed"); |
267 | } |
268 | |
269 | void |
270 | unsetsig(void) |
271 | { |
272 | struct sigaction sa; |
273 | |
274 | sigfillset(&sa.sa_mask); |
275 | sa.sa_flags = SA_RESTART0x0002; |
276 | sa.sa_handler__sigaction_u.__sa_handler = SIG_DFL(void (*)(int))0; |
277 | if (sigaction(SIGHUP1, &sa, NULL((void*)0)) == -1) |
278 | err(1, "unsetsig(hup): sigaction failed"); |
279 | if (sigaction(SIGTERM15, &sa, NULL((void*)0)) == -1) |
280 | err(1, "unsetsig(term): sigaction failed"); |
281 | if (sigaction(SIGINT2, &sa, NULL((void*)0)) == -1) |
282 | err(1, "unsetsig(int): sigaction failed"); |
283 | } |
284 | |
285 | void |
286 | getbasepath(char *base) |
287 | { |
288 | uid_t uid; |
289 | struct stat sb; |
290 | mode_t mask, omask; |
291 | |
292 | uid = geteuid(); |
293 | if (uid == 0) { |
294 | mask = 022; |
295 | snprintf(base, SOCKPATH_MAX(1 + sizeof("/tmp/sndio") - 1 + sizeof(char) + sizeof(int) * 3 + sizeof(char) + sizeof("sock") - 1 + sizeof(int) * 3), SOCKPATH_DIR"/tmp/sndio"); |
296 | } else { |
297 | mask = 077; |
298 | snprintf(base, SOCKPATH_MAX(1 + sizeof("/tmp/sndio") - 1 + sizeof(char) + sizeof(int) * 3 + sizeof(char) + sizeof("sock") - 1 + sizeof(int) * 3), SOCKPATH_DIR"/tmp/sndio" "-%u", uid); |
299 | } |
300 | omask = umask(mask); |
301 | if (mkdir(base, 0777) == -1) { |
302 | if (errno(*__errno()) != EEXIST17) |
303 | err(1, "mkdir(\"%s\")", base); |
304 | } |
305 | umask(omask); |
306 | if (stat(base, &sb) == -1) |
307 | err(1, "stat(\"%s\")", base); |
308 | if (!S_ISDIR(sb.st_mode)((sb.st_mode & 0170000) == 0040000)) |
309 | errx(1, "%s is not a directory", base); |
310 | if (sb.st_uid != uid || (sb.st_mode & mask) != 0) |
311 | errx(1, "%s has wrong permissions", base); |
312 | } |
313 | |
314 | struct dev * |
315 | mkdev(char *path, struct aparams *par, |
316 | int mode, int bufsz, int round, int rate, int hold, int autovol) |
317 | { |
318 | struct dev *d; |
319 | |
320 | for (d = dev_list; d != NULL((void*)0); d = d->next) { |
321 | if (strcmp(d->path, path) == 0) |
322 | return d; |
323 | } |
324 | if (!bufsz && !round) { |
325 | round = DEFAULT_ROUND480; |
326 | bufsz = DEFAULT_BUFSZ7680; |
327 | } else if (!bufsz) { |
328 | bufsz = round * 2; |
329 | } else if (!round) |
330 | round = bufsz / 2; |
331 | d = dev_new(path, par, mode, bufsz, round, rate, hold, autovol); |
332 | if (d == NULL((void*)0)) |
333 | exit(1); |
334 | return d; |
335 | } |
336 | |
337 | struct port * |
338 | mkport(char *path, int hold) |
339 | { |
340 | struct port *c; |
341 | |
342 | for (c = port_list; c != NULL((void*)0); c = c->next) { |
343 | if (strcmp(c->path, path) == 0) |
344 | return c; |
345 | } |
346 | c = port_new(path, MODE_MIDIMASK(0x08 | 0x04), hold); |
347 | if (c == NULL((void*)0)) |
348 | exit(1); |
349 | return c; |
350 | } |
351 | |
352 | struct opt * |
353 | mkopt(char *path, struct dev *d, |
354 | int pmin, int pmax, int rmin, int rmax, |
355 | int mode, int vol, int mmc, int dup) |
356 | { |
357 | struct opt *o; |
358 | |
359 | o = opt_new(d, path, pmin, pmax, rmin, rmax, |
360 | MIDI_TO_ADATA(vol)(aparams_ctltovol[vol] << (16 - 16)), mmc, dup, mode); |
361 | if (o == NULL((void*)0)) |
362 | return NULL((void*)0); |
363 | dev_adjpar(d, o->mode, o->pmax, o->rmax); |
364 | return o; |
365 | } |
366 | |
367 | static void |
368 | dounveil(char *name, char *prefix, char *path_prefix) |
369 | { |
370 | size_t prefix_len; |
371 | char path[PATH_MAX1024]; |
372 | |
373 | prefix_len = strlen(prefix); |
374 | |
375 | if (strncmp(name, prefix, prefix_len) != 0) |
376 | errx(1, "%s: unsupported device or port format", name); |
377 | snprintf(path, sizeof(path), "%s%s", path_prefix, name + prefix_len); |
378 | if (unveil(path, "rw") == -1) |
379 | err(1, "unveil %s", path); |
380 | } |
381 | |
382 | static int |
383 | start_helper(int background) |
384 | { |
385 | struct dev *d; |
386 | struct port *p; |
387 | struct passwd *pw; |
388 | int s[2]; |
389 | pid_t pid; |
390 | |
391 | if (geteuid() == 0) { |
392 | if ((pw = getpwnam(SNDIO_PRIV_USER"_sndiop")) == NULL((void*)0)) |
393 | errx(1, "unknown user %s", SNDIO_PRIV_USER"_sndiop"); |
394 | } else |
395 | pw = NULL((void*)0); |
396 | if (socketpair(AF_UNIX1, SOCK_STREAM1, 0, s) == -1) { |
397 | perror("socketpair"); |
398 | return 0; |
399 | } |
400 | pid = fork(); |
401 | if (pid == -1) { |
402 | log_puts("can't fork\n"); |
403 | return 0; |
404 | } |
405 | if (pid == 0) { |
406 | setproctitle("helper"); |
407 | close(s[0]); |
408 | if (fdpass_new(s[1], &helper_fileops) == NULL((void*)0)) |
409 | return 0; |
410 | if (background) { |
411 | log_flush(); |
412 | log_level = 0; |
413 | if (daemon(0, 0) == -1) |
414 | err(1, "daemon"); |
415 | } |
416 | if (pw != NULL((void*)0)) { |
417 | if (setgroups(1, &pw->pw_gid) || |
418 | setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || |
419 | setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) |
420 | err(1, "cannot drop privileges"); |
421 | } |
422 | for (d = dev_list; d != NULL((void*)0); d = d->next) { |
423 | dounveil(d->path, "rsnd/", "/dev/audio"); |
424 | dounveil(d->path, "rsnd/", "/dev/audioctl"); |
425 | } |
426 | for (p = port_list; p != NULL((void*)0); p = p->next) { |
427 | dounveil(p->path, "rmidi/", "/dev/rmidi"); |
428 | } |
429 | if (pledge("stdio sendfd rpath wpath", NULL((void*)0)) == -1) |
430 | err(1, "pledge"); |
431 | while (file_poll()) |
432 | ; /* nothing */ |
433 | exit(0); |
434 | } else { |
435 | close(s[1]); |
436 | if (fdpass_new(s[0], &worker_fileops) == NULL((void*)0)) |
437 | return 0; |
438 | } |
439 | return 1; |
440 | } |
441 | |
442 | static void |
443 | stop_helper(void) |
444 | { |
445 | if (fdpass_peer) |
446 | fdpass_close(fdpass_peer); |
447 | } |
448 | |
449 | int |
450 | main(int argc, char **argv) |
451 | { |
452 | int c, i, background, unit; |
453 | int pmin, pmax, rmin, rmax; |
454 | char base[SOCKPATH_MAX(1 + sizeof("/tmp/sndio") - 1 + sizeof(char) + sizeof(int) * 3 + sizeof(char) + sizeof("sock") - 1 + sizeof(int) * 3)], path[SOCKPATH_MAX(1 + sizeof("/tmp/sndio") - 1 + sizeof(char) + sizeof(int) * 3 + sizeof(char) + sizeof("sock") - 1 + sizeof(int) * 3)]; |
455 | unsigned int mode, dup, mmc, vol; |
456 | unsigned int hold, autovol, bufsz, round, rate; |
457 | unsigned int reopen_list; |
458 | const char *str; |
459 | struct aparams par; |
460 | struct opt *o; |
461 | struct dev *d, *dev_first, *dev_next; |
462 | struct port *p, *port_first, *port_next; |
463 | struct listen *l; |
464 | struct passwd *pw; |
465 | struct tcpaddr { |
466 | char *host; |
467 | struct tcpaddr *next; |
468 | } *tcpaddr_list, *ta; |
469 | |
470 | atexit(log_flush); |
471 | |
472 | /* |
473 | * global options defaults |
474 | */ |
475 | vol = 127; |
476 | dup = 1; |
477 | mmc = 0; |
478 | hold = 0; |
479 | autovol = 0; |
480 | bufsz = 0; |
481 | round = 0; |
482 | rate = DEFAULT_RATE48000; |
483 | unit = 0; |
484 | background = 1; |
485 | pmin = 0; |
486 | pmax = 1; |
487 | rmin = 0; |
488 | rmax = 1; |
489 | aparams_init(&par); |
490 | mode = MODE_PLAY0x01 | MODE_REC0x02; |
491 | dev_first = dev_next = NULL((void*)0); |
492 | port_first = port_next = NULL((void*)0); |
493 | tcpaddr_list = NULL((void*)0); |
494 | d = NULL((void*)0); |
495 | p = NULL((void*)0); |
496 | |
497 | slot_array_init(); |
498 | |
499 | while ((c = getopt(argc, argv, |
500 | "a:b:c:C:de:F:f:j:L:m:Q:q:r:s:t:U:v:w:x:z:")) != -1) { |
501 | switch (c) { |
502 | case 'd': |
503 | log_level++; |
504 | background = 0; |
505 | break; |
506 | case 'U': |
507 | unit = strtonum(optarg, 0, 15, &str); |
508 | if (str) |
509 | errx(1, "%s: unit number is %s", optarg, str); |
510 | break; |
511 | case 'L': |
512 | ta = xmalloc(sizeof(struct tcpaddr)); |
513 | ta->host = optarg; |
514 | ta->next = tcpaddr_list; |
515 | tcpaddr_list = ta; |
516 | break; |
517 | case 'm': |
518 | mode = opt_mode(); |
519 | break; |
520 | case 'j': |
521 | dup = opt_onoff(); |
522 | break; |
523 | case 't': |
524 | mmc = opt_mmc(); |
525 | break; |
526 | case 'c': |
527 | opt_ch(&pmin, &pmax); |
528 | break; |
529 | case 'C': |
530 | opt_ch(&rmin, &rmax); |
531 | break; |
532 | case 'e': |
533 | opt_enc(&par); |
534 | break; |
535 | case 'r': |
536 | rate = strtonum(optarg, RATE_MIN4000, RATE_MAX192000, &str); |
537 | if (str) |
538 | errx(1, "%s: rate is %s", optarg, str); |
539 | break; |
540 | case 'v': |
541 | vol = strtonum(optarg, 0, MIDI_MAXCTL127, &str); |
542 | if (str) |
543 | errx(1, "%s: volume is %s", optarg, str); |
544 | break; |
545 | case 's': |
546 | if (d == NULL((void*)0)) { |
547 | for (i = 0; default_devs[i] != NULL((void*)0); i++) { |
548 | mkdev(default_devs[i], &par, 0, |
549 | bufsz, round, rate, 0, autovol); |
550 | } |
551 | d = dev_list; |
552 | } |
553 | if (mkopt(optarg, d, pmin, pmax, rmin, rmax, |
554 | mode, vol, mmc, dup) == NULL((void*)0)) |
555 | return 1; |
556 | break; |
557 | case 'q': |
558 | p = mkport(optarg, hold); |
559 | /* create new circulate list */ |
560 | port_first = port_next = p; |
561 | break; |
562 | case 'Q': |
563 | if (p == NULL((void*)0)) |
564 | errx(1, "-Q %s: no ports defined", optarg); |
565 | p = mkport(optarg, hold); |
566 | /* add to circulate list */ |
567 | p->alt_next = port_next; |
568 | port_first->alt_next = p; |
569 | port_next = p; |
570 | break; |
571 | case 'a': |
572 | hold = opt_onoff(); |
573 | break; |
574 | case 'w': |
575 | autovol = opt_onoff(); |
576 | break; |
577 | case 'b': |
578 | bufsz = strtonum(optarg, 1, RATE_MAX192000, &str); |
579 | if (str) |
580 | errx(1, "%s: buffer size is %s", optarg, str); |
581 | break; |
582 | case 'z': |
583 | round = strtonum(optarg, 1, SHRT_MAX32767, &str); |
584 | if (str) |
585 | errx(1, "%s: block size is %s", optarg, str); |
586 | break; |
587 | case 'f': |
588 | d = mkdev(optarg, &par, 0, bufsz, round, |
589 | rate, hold, autovol); |
590 | /* create new circulate list */ |
591 | dev_first = dev_next = d; |
592 | break; |
593 | case 'F': |
594 | if (d == NULL((void*)0)) |
595 | errx(1, "-F %s: no devices defined", optarg); |
596 | d = mkdev(optarg, &par, 0, bufsz, round, |
597 | rate, hold, autovol); |
598 | /* add to circulate list */ |
599 | d->alt_next = dev_next; |
600 | dev_first->alt_next = d; |
601 | dev_next = d; |
602 | break; |
603 | default: |
604 | fputs(usagestr, stderr(&__sF[2])); |
605 | return 1; |
606 | } |
607 | } |
608 | argc -= optind; |
609 | argv += optind; |
Value stored to 'argv' is never read | |
610 | if (argc > 0) { |
611 | fputs(usagestr, stderr(&__sF[2])); |
612 | return 1; |
613 | } |
614 | if (port_list == NULL((void*)0)) { |
615 | for (i = 0; default_ports[i] != NULL((void*)0); i++) |
616 | mkport(default_ports[i], 0); |
617 | } |
618 | if (dev_list == NULL((void*)0)) { |
619 | for (i = 0; default_devs[i] != NULL((void*)0); i++) { |
620 | mkdev(default_devs[i], &par, 0, |
621 | bufsz, round, rate, 0, autovol); |
622 | } |
623 | } |
624 | |
625 | /* |
626 | * Add default sub-device (if none) backed by the last device |
627 | */ |
628 | o = opt_byname("default"); |
629 | if (o == NULL((void*)0)) { |
630 | o = mkopt("default", dev_list, pmin, pmax, rmin, rmax, |
631 | mode, vol, 0, dup); |
632 | if (o == NULL((void*)0)) |
633 | return 1; |
634 | } |
635 | |
636 | /* |
637 | * For each device create an anonymous sub-device using |
638 | * the "default" sub-device as template |
639 | */ |
640 | for (d = dev_list; d != NULL((void*)0); d = d->next) { |
641 | if (opt_new(d, NULL((void*)0), o->pmin, o->pmax, o->rmin, o->rmax, |
642 | o->maxweight, o->mtc != NULL((void*)0), o->dup, o->mode) == NULL((void*)0)) |
643 | return 1; |
644 | dev_adjpar(d, o->mode, o->pmax, o->rmax); |
645 | } |
646 | |
647 | setsig(); |
648 | filelist_init(); |
649 | |
650 | if (!start_helper(background)) |
651 | return 1; |
652 | |
653 | if (geteuid() == 0) { |
654 | if ((pw = getpwnam(SNDIO_USER"_sndio")) == NULL((void*)0)) |
655 | errx(1, "unknown user %s", SNDIO_USER"_sndio"); |
656 | } else |
657 | pw = NULL((void*)0); |
658 | getbasepath(base); |
659 | snprintf(path, SOCKPATH_MAX(1 + sizeof("/tmp/sndio") - 1 + sizeof(char) + sizeof(int) * 3 + sizeof(char) + sizeof("sock") - 1 + sizeof(int) * 3), "%s/" SOCKPATH_FILE"sock" "%u", base, unit); |
660 | if (!listen_new_un(path)) |
661 | return 1; |
662 | for (ta = tcpaddr_list; ta != NULL((void*)0); ta = ta->next) { |
663 | if (!listen_new_tcp(ta->host, AUCAT_PORT11025 + unit)) |
664 | return 1; |
665 | } |
666 | for (l = listen_list; l != NULL((void*)0); l = l->next) { |
667 | if (!listen_init(l)) |
668 | return 1; |
669 | } |
670 | midi_init(); |
671 | for (p = port_list; p != NULL((void*)0); p = p->next) { |
672 | if (!port_init(p)) |
673 | return 1; |
674 | } |
675 | for (d = dev_list; d != NULL((void*)0); d = d->next) { |
676 | if (!dev_init(d)) |
677 | return 1; |
678 | } |
679 | for (o = opt_list; o != NULL((void*)0); o = o->next) |
680 | opt_init(o); |
681 | if (background) { |
682 | log_flush(); |
683 | log_level = 0; |
684 | if (daemon(0, 0) == -1) |
685 | err(1, "daemon"); |
686 | } |
687 | if (pw != NULL((void*)0)) { |
688 | if (setpriority(PRIO_PROCESS0, 0, SNDIO_PRIO(-20)) == -1) |
689 | err(1, "setpriority"); |
690 | if (chroot(pw->pw_dir) == -1 || chdir("/") == -1) |
691 | err(1, "cannot chroot to %s", pw->pw_dir); |
692 | if (setgroups(1, &pw->pw_gid) == -1 || |
693 | setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1 || |
694 | setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1 ) |
695 | err(1, "cannot drop privileges"); |
696 | } |
697 | if (tcpaddr_list) { |
698 | if (pledge("stdio audio recvfd unix inet", NULL((void*)0)) == -1) |
699 | err(1, "pledge"); |
700 | } else { |
701 | if (pledge("stdio audio recvfd unix", NULL((void*)0)) == -1) |
702 | err(1, "pledge"); |
703 | } |
704 | for (;;) { |
705 | if (quit_flag) |
706 | break; |
707 | if (reopen_flag) { |
708 | reopen_flag = 0; |
709 | |
710 | reopen_list = 0; |
711 | for (d = dev_list; d != NULL((void*)0); d = d->next) { |
712 | if (d->pstate != DEV_CFG0) |
713 | reopen_list |= (1 << d->num); |
714 | } |
715 | for (d = dev_list; d != NULL((void*)0); d = d->next) { |
716 | if (reopen_list & (1 << d->num)) |
717 | dev_migrate(d); |
718 | } |
719 | |
720 | reopen_list = 0; |
721 | for (p = port_list; p != NULL((void*)0); p = p->next) { |
722 | if (p->state != PORT_CFG0) |
723 | reopen_list |= (1 << p->num); |
724 | } |
725 | for (p = port_list; p != NULL((void*)0); p = p->next) { |
726 | if (reopen_list & (1 << p->num)) { |
727 | if (port_migrate(p) != p) |
728 | port_close(p); |
729 | } |
730 | } |
731 | } |
732 | if (!fdpass_peer) |
733 | break; |
734 | if (!file_poll()) |
735 | break; |
736 | } |
737 | stop_helper(); |
738 | while (listen_list != NULL((void*)0)) |
739 | listen_close(listen_list); |
740 | while (sock_list != NULL((void*)0)) |
741 | sock_close(sock_list); |
742 | for (o = opt_list; o != NULL((void*)0); o = o->next) |
743 | opt_done(o); |
744 | for (d = dev_list; d != NULL((void*)0); d = d->next) |
745 | dev_done(d); |
746 | for (p = port_list; p != NULL((void*)0); p = p->next) |
747 | port_done(p); |
748 | while (file_poll()) |
749 | ; /* nothing */ |
750 | midi_done(); |
751 | |
752 | while (opt_list) |
753 | opt_del(opt_list); |
754 | while (dev_list) |
755 | dev_del(dev_list); |
756 | while (port_list) |
757 | port_del(port_list); |
758 | while (tcpaddr_list) { |
759 | ta = tcpaddr_list; |
760 | tcpaddr_list = ta->next; |
761 | xfree(ta); |
762 | } |
763 | filelist_done(); |
764 | unsetsig(); |
765 | return 0; |
766 | } |