Annotation of src/usr.bin/sndiod/sndiod.c, Revision 1.49
1.49 ! ratchov 1: /* $OpenBSD: sndiod.c,v 1.48 2022/03/07 08:58:33 ratchov Exp $ */
1.1 ratchov 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>
1.18 ratchov 20: #include <sys/socket.h>
1.1 ratchov 21:
22: #include <err.h>
23: #include <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"
1.18 ratchov 38: #include "fdpass.h"
1.1 ratchov 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
50: #define SNDIO_USER "_sndio"
51: #endif
52:
53: /*
1.18 ratchov 54: * privileged user name
55: */
56: #ifndef SNDIO_PRIV_USER
57: #define SNDIO_PRIV_USER "_sndiop"
58: #endif
59:
60: /*
1.1 ratchov 61: * priority when run as root
62: */
63: #ifndef SNDIO_PRIO
64: #define SNDIO_PRIO (-20)
65: #endif
66:
67: /*
68: * sample rate if no ``-r'' is used
69: */
70: #ifndef DEFAULT_RATE
71: #define DEFAULT_RATE 48000
72: #endif
73:
74: /*
75: * block size if neither ``-z'' nor ``-b'' is used
76: */
77: #ifndef DEFAULT_ROUND
1.37 ratchov 78: #define DEFAULT_ROUND 480
1.1 ratchov 79: #endif
80:
81: /*
82: * buffer size if neither ``-z'' nor ``-b'' is used
83: */
84: #ifndef DEFAULT_BUFSZ
1.8 dcoppa 85: #define DEFAULT_BUFSZ 7680
1.1 ratchov 86: #endif
87:
1.48 ratchov 88: /*
89: * default device precision
90: */
91: #ifndef DEFAULT_BITS
92: #define DEFAULT_BITS 16
93: #endif
94:
1.5 ratchov 95: void sigint(int);
1.36 ratchov 96: void sighup(int);
1.5 ratchov 97: void opt_ch(int *, int *);
98: void opt_enc(struct aparams *);
99: int opt_mmc(void);
100: int opt_onoff(void);
101: int getword(char *, char **);
102: unsigned int opt_mode(void);
1.31 ratchov 103: void getbasepath(char *);
1.5 ratchov 104: void setsig(void);
105: void unsetsig(void);
106: struct dev *mkdev(char *, struct aparams *,
107: int, int, int, int, int, int);
1.27 ratchov 108: struct port *mkport(char *, int);
1.5 ratchov 109: struct opt *mkopt(char *, struct dev *,
110: int, int, int, int, int, int, int, int);
1.1 ratchov 111:
112: unsigned int log_level = 0;
1.36 ratchov 113: volatile sig_atomic_t quit_flag = 0, reopen_flag = 0;
1.1 ratchov 114:
115: char usagestr[] = "usage: sndiod [-d] [-a flag] [-b nframes] "
1.36 ratchov 116: "[-C min:max] [-c min:max]\n\t"
117: "[-e enc] [-F device] [-f device] [-j flag] [-L addr] [-m mode]\n\t"
118: "[-Q port] [-q port] [-r rate] [-s name] [-t mode] [-U unit]\n\t"
119: "[-v volume] [-w flag] [-z nframes]\n";
1.1 ratchov 120:
121: /*
1.40 ratchov 122: * default audio devices
123: */
124: static char *default_devs[] = {
125: "rsnd/0", "rsnd/1", "rsnd/2", "rsnd/3",
126: NULL
127: };
128:
129: /*
1.39 ratchov 130: * default MIDI ports
131: */
132: static char *default_ports[] = {
133: "rmidi/0", "rmidi/1", "rmidi/2", "rmidi/3",
134: "rmidi/4", "rmidi/5", "rmidi/6", "rmidi/7",
135: NULL
136: };
137:
138: /*
1.1 ratchov 139: * SIGINT handler, it raises the quit flag. If the flag is already set,
140: * that means that the last SIGINT was not handled, because the process
141: * is blocked somewhere, so exit.
142: */
143: void
144: sigint(int s)
145: {
146: if (quit_flag)
147: _exit(1);
148: quit_flag = 1;
149: }
150:
1.36 ratchov 151: /*
152: * SIGHUP handler, it raises the reopen flag, which requests devices
153: * to be reopened.
154: */
155: void
156: sighup(int s)
157: {
158: reopen_flag = 1;
159: }
160:
1.1 ratchov 161: void
162: opt_ch(int *rcmin, int *rcmax)
163: {
164: char *next, *end;
165: long cmin, cmax;
166:
167: errno = 0;
168: cmin = strtol(optarg, &next, 10);
169: if (next == optarg || *next != ':')
170: goto failed;
171: cmax = strtol(++next, &end, 10);
172: if (end == next || *end != '\0')
173: goto failed;
174: if (cmin < 0 || cmax < cmin || cmax >= NCHAN_MAX)
175: goto failed;
176: *rcmin = cmin;
177: *rcmax = cmax;
178: return;
179: failed:
180: errx(1, "%s: bad channel range", optarg);
181: }
182:
183: void
184: opt_enc(struct aparams *par)
185: {
186: int len;
187:
188: len = aparams_strtoenc(par, optarg);
189: if (len == 0 || optarg[len] != '\0')
190: errx(1, "%s: bad encoding", optarg);
191: }
192:
193: int
194: opt_mmc(void)
195: {
196: if (strcmp("off", optarg) == 0)
197: return 0;
198: if (strcmp("slave", optarg) == 0)
199: return 1;
200: errx(1, "%s: off/slave expected", optarg);
201: }
202:
203: int
204: opt_onoff(void)
205: {
206: if (strcmp("off", optarg) == 0)
207: return 0;
208: if (strcmp("on", optarg) == 0)
209: return 1;
210: errx(1, "%s: on/off expected", optarg);
211: }
212:
1.4 ratchov 213: int
214: getword(char *word, char **str)
215: {
216: char *p = *str;
217:
218: for (;;) {
219: if (*word == '\0')
220: break;
221: if (*word++ != *p++)
222: return 0;
223: }
224: if (*p == ',' || *p == '\0') {
225: *str = p;
226: return 1;
227: }
228: return 0;
229: }
230:
1.1 ratchov 231: unsigned int
232: opt_mode(void)
233: {
234: unsigned int mode = 0;
235: char *p = optarg;
236:
1.4 ratchov 237: for (;;) {
238: if (getword("play", &p)) {
1.1 ratchov 239: mode |= MODE_PLAY;
1.4 ratchov 240: } else if (getword("rec", &p)) {
1.1 ratchov 241: mode |= MODE_REC;
1.4 ratchov 242: } else if (getword("mon", &p)) {
1.1 ratchov 243: mode |= MODE_MON;
1.4 ratchov 244: } else if (getword("midi", &p)) {
1.1 ratchov 245: mode |= MODE_MIDIMASK;
1.4 ratchov 246: } else
1.1 ratchov 247: errx(1, "%s: bad mode", optarg);
248: if (*p == '\0')
249: break;
1.4 ratchov 250: p++;
1.1 ratchov 251: }
252: if (mode == 0)
253: errx(1, "empty mode");
254: return mode;
255: }
256:
1.49 ! ratchov 257: /*
! 258: * Open all devices. Possibly switch to the new devices if they have higher
! 259: * priorities than the current ones.
! 260: */
! 261: static void
! 262: reopen_devs(void)
! 263: {
! 264: struct opt *o;
! 265: struct dev *d, *a;
! 266:
! 267: for (o = opt_list; o != NULL; o = o->next) {
! 268:
! 269: /* skip unused logical devices and ones with fixed hardware */
! 270: if (o->refcnt == 0 || strcmp(o->name, o->dev->name) == 0)
! 271: continue;
! 272:
! 273: /* circulate to the device with the highest prio */
! 274: a = o->alt_first;
! 275: for (d = a; d->alt_next != a; d = d->alt_next) {
! 276: if (d->num > o->alt_first->num)
! 277: o->alt_first = d;
! 278: }
! 279:
! 280: /* switch to the first working one, in pririty order */
! 281: d = o->alt_first;
! 282: while (d != o->dev) {
! 283: if (opt_setdev(o, d))
! 284: break;
! 285: d = d->alt_next;
! 286: }
! 287: }
! 288:
! 289: /*
! 290: * retry to open the remaining devices that are not used but need
! 291: * to stay open (ex. '-a on')
! 292: */
! 293: for (d = dev_list; d != NULL; d = d->next) {
! 294: if (d->refcnt > 0 && d->pstate == DEV_CFG)
! 295: dev_open(d);
! 296: }
! 297: }
! 298:
! 299: /*
! 300: * For each port, open the alt with the highest priority and switch to it
! 301: */
! 302: static void
! 303: reopen_ports(void)
! 304: {
! 305: struct port *p, *a, *apri;
! 306: int inuse;
! 307:
! 308: for (p = port_list; p != NULL; p = a->next) {
! 309:
! 310: /* skip unused ports */
! 311: inuse = 0;
! 312: a = p;
! 313: while (1) {
! 314: if (midi_rxmask(a->midi) || a->midi->txmask)
! 315: inuse = 1;
! 316: if (a->alt_next == p)
! 317: break;
! 318: a = a->alt_next;
! 319: }
! 320: if (!inuse)
! 321: continue;
! 322:
! 323: /* open the alt with the highest prio */
! 324: apri = port_alt_ref(p->num);
! 325:
! 326: /* switch to it */
! 327: a = p;
! 328: while (1) {
! 329: if (a != apri) {
! 330: midi_migrate(a->midi, apri->midi);
! 331: port_unref(a);
! 332: }
! 333: if (a->alt_next == p)
! 334: break;
! 335: a = a->alt_next;
! 336: }
! 337: }
! 338: }
! 339:
1.1 ratchov 340: void
341: setsig(void)
342: {
343: struct sigaction sa;
344:
345: quit_flag = 0;
1.36 ratchov 346: reopen_flag = 0;
1.1 ratchov 347: sigfillset(&sa.sa_mask);
348: sa.sa_flags = SA_RESTART;
349: sa.sa_handler = sigint;
1.35 ratchov 350: if (sigaction(SIGINT, &sa, NULL) == -1)
1.1 ratchov 351: err(1, "sigaction(int) failed");
1.35 ratchov 352: if (sigaction(SIGTERM, &sa, NULL) == -1)
1.1 ratchov 353: err(1, "sigaction(term) failed");
1.36 ratchov 354: sa.sa_handler = sighup;
1.35 ratchov 355: if (sigaction(SIGHUP, &sa, NULL) == -1)
1.1 ratchov 356: err(1, "sigaction(hup) failed");
357: }
358:
359: void
360: unsetsig(void)
361: {
362: struct sigaction sa;
363:
364: sigfillset(&sa.sa_mask);
365: sa.sa_flags = SA_RESTART;
366: sa.sa_handler = SIG_DFL;
1.35 ratchov 367: if (sigaction(SIGHUP, &sa, NULL) == -1)
1.29 ratchov 368: err(1, "unsetsig(hup): sigaction failed");
1.35 ratchov 369: if (sigaction(SIGTERM, &sa, NULL) == -1)
1.29 ratchov 370: err(1, "unsetsig(term): sigaction failed");
1.35 ratchov 371: if (sigaction(SIGINT, &sa, NULL) == -1)
1.29 ratchov 372: err(1, "unsetsig(int): sigaction failed");
1.1 ratchov 373: }
374:
375: void
1.31 ratchov 376: getbasepath(char *base)
1.1 ratchov 377: {
378: uid_t uid;
379: struct stat sb;
1.14 ratchov 380: mode_t mask, omask;
1.1 ratchov 381:
382: uid = geteuid();
383: if (uid == 0) {
384: mask = 022;
1.10 ratchov 385: snprintf(base, SOCKPATH_MAX, SOCKPATH_DIR);
1.1 ratchov 386: } else {
387: mask = 077;
1.10 ratchov 388: snprintf(base, SOCKPATH_MAX, SOCKPATH_DIR "-%u", uid);
1.1 ratchov 389: }
1.14 ratchov 390: omask = umask(mask);
1.35 ratchov 391: if (mkdir(base, 0777) == -1) {
1.1 ratchov 392: if (errno != EEXIST)
393: err(1, "mkdir(\"%s\")", base);
394: }
1.28 ratchov 395: umask(omask);
1.35 ratchov 396: if (stat(base, &sb) == -1)
1.1 ratchov 397: err(1, "stat(\"%s\")", base);
1.30 ratchov 398: if (!S_ISDIR(sb.st_mode))
399: errx(1, "%s is not a directory", base);
1.1 ratchov 400: if (sb.st_uid != uid || (sb.st_mode & mask) != 0)
401: errx(1, "%s has wrong permissions", base);
402: }
403:
404: struct dev *
405: mkdev(char *path, struct aparams *par,
406: int mode, int bufsz, int round, int rate, int hold, int autovol)
407: {
408: struct dev *d;
409:
410: for (d = dev_list; d != NULL; d = d->next) {
1.47 ratchov 411: if (strcmp(d->path, path) == 0)
1.1 ratchov 412: return d;
413: }
414: if (!bufsz && !round) {
415: round = DEFAULT_ROUND;
416: bufsz = DEFAULT_BUFSZ;
417: } else if (!bufsz) {
418: bufsz = round * 2;
419: } else if (!round)
420: round = bufsz / 2;
421: d = dev_new(path, par, mode, bufsz, round, rate, hold, autovol);
422: if (d == NULL)
423: exit(1);
424: return d;
425: }
426:
1.27 ratchov 427: struct port *
428: mkport(char *path, int hold)
429: {
430: struct port *c;
431:
432: for (c = port_list; c != NULL; c = c->next) {
1.47 ratchov 433: if (strcmp(c->path, path) == 0)
1.27 ratchov 434: return c;
435: }
436: c = port_new(path, MODE_MIDIMASK, hold);
437: if (c == NULL)
438: exit(1);
439: return c;
440: }
441:
1.1 ratchov 442: struct opt *
443: mkopt(char *path, struct dev *d,
444: int pmin, int pmax, int rmin, int rmax,
445: int mode, int vol, int mmc, int dup)
446: {
447: struct opt *o;
448:
1.33 ratchov 449: o = opt_new(d, path, pmin, pmax, rmin, rmax,
1.1 ratchov 450: MIDI_TO_ADATA(vol), mmc, dup, mode);
451: if (o == NULL)
1.26 ratchov 452: return NULL;
1.31 ratchov 453: dev_adjpar(d, o->mode, o->pmax, o->rmax);
1.1 ratchov 454: return o;
455: }
456:
1.34 ratchov 457: static void
458: dounveil(char *name, char *prefix, char *path_prefix)
459: {
460: size_t prefix_len;
461: char path[PATH_MAX];
462:
463: prefix_len = strlen(prefix);
464:
465: if (strncmp(name, prefix, prefix_len) != 0)
466: errx(1, "%s: unsupported device or port format", name);
467: snprintf(path, sizeof(path), "%s%s", path_prefix, name + prefix_len);
1.35 ratchov 468: if (unveil(path, "rw") == -1)
1.46 beck 469: err(1, "unveil %s", path);
1.34 ratchov 470: }
471:
1.32 ratchov 472: static int
473: start_helper(int background)
474: {
1.34 ratchov 475: struct dev *d;
476: struct port *p;
1.32 ratchov 477: struct passwd *pw;
478: int s[2];
479: pid_t pid;
480:
481: if (geteuid() == 0) {
482: if ((pw = getpwnam(SNDIO_PRIV_USER)) == NULL)
483: errx(1, "unknown user %s", SNDIO_PRIV_USER);
484: } else
485: pw = NULL;
1.35 ratchov 486: if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == -1) {
1.32 ratchov 487: perror("socketpair");
488: return 0;
489: }
490: pid = fork();
491: if (pid == -1) {
492: log_puts("can't fork\n");
493: return 0;
494: }
495: if (pid == 0) {
496: setproctitle("helper");
497: close(s[0]);
498: if (fdpass_new(s[1], &helper_fileops) == NULL)
499: return 0;
500: if (background) {
501: log_flush();
502: log_level = 0;
1.35 ratchov 503: if (daemon(0, 0) == -1)
1.32 ratchov 504: err(1, "daemon");
505: }
506: if (pw != NULL) {
507: if (setgroups(1, &pw->pw_gid) ||
508: setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
509: setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
510: err(1, "cannot drop privileges");
511: }
1.36 ratchov 512: for (d = dev_list; d != NULL; d = d->next) {
1.47 ratchov 513: dounveil(d->path, "rsnd/", "/dev/audio");
514: dounveil(d->path, "rsnd/", "/dev/audioctl");
1.36 ratchov 515: }
516: for (p = port_list; p != NULL; p = p->next) {
1.47 ratchov 517: dounveil(p->path, "rmidi/", "/dev/rmidi");
1.36 ratchov 518: }
1.35 ratchov 519: if (pledge("stdio sendfd rpath wpath", NULL) == -1)
1.32 ratchov 520: err(1, "pledge");
521: while (file_poll())
522: ; /* nothing */
523: exit(0);
524: } else {
525: close(s[1]);
526: if (fdpass_new(s[0], &worker_fileops) == NULL)
527: return 0;
528: }
529: return 1;
530: }
531:
532: static void
533: stop_helper(void)
534: {
535: if (fdpass_peer)
536: fdpass_close(fdpass_peer);
537: }
538:
1.1 ratchov 539: int
540: main(int argc, char **argv)
541: {
1.45 ratchov 542: int c, i, background, unit;
1.1 ratchov 543: int pmin, pmax, rmin, rmax;
1.25 ratchov 544: char base[SOCKPATH_MAX], path[SOCKPATH_MAX];
1.1 ratchov 545: unsigned int mode, dup, mmc, vol;
546: unsigned int hold, autovol, bufsz, round, rate;
547: const char *str;
548: struct aparams par;
1.47 ratchov 549: struct opt *o;
550: struct dev *d, *dev_first, *dev_next;
551: struct port *p, *port_first, *port_next;
1.1 ratchov 552: struct listen *l;
1.17 ratchov 553: struct passwd *pw;
1.25 ratchov 554: struct tcpaddr {
555: char *host;
556: struct tcpaddr *next;
557: } *tcpaddr_list, *ta;
1.1 ratchov 558:
559: atexit(log_flush);
560:
561: /*
562: * global options defaults
563: */
1.44 jcs 564: vol = 127;
1.1 ratchov 565: dup = 1;
566: mmc = 0;
567: hold = 0;
1.44 jcs 568: autovol = 0;
1.1 ratchov 569: bufsz = 0;
570: round = 0;
571: rate = DEFAULT_RATE;
572: unit = 0;
573: background = 1;
574: pmin = 0;
575: pmax = 1;
576: rmin = 0;
577: rmax = 1;
1.48 ratchov 578: par.bits = DEFAULT_BITS;
579: par.bps = APARAMS_BPS(par.bits);
580: par.le = ADATA_LE;
581: par.sig = 1;
582: par.msb = 0;
1.1 ratchov 583: mode = MODE_PLAY | MODE_REC;
1.47 ratchov 584: dev_first = dev_next = NULL;
585: port_first = port_next = NULL;
1.25 ratchov 586: tcpaddr_list = NULL;
1.45 ratchov 587: d = NULL;
588: p = NULL;
1.42 ratchov 589:
590: slot_array_init();
1.1 ratchov 591:
1.36 ratchov 592: while ((c = getopt(argc, argv,
593: "a:b:c:C:de:F:f:j:L:m:Q:q:r:s:t:U:v:w:x:z:")) != -1) {
1.1 ratchov 594: switch (c) {
595: case 'd':
596: log_level++;
597: background = 0;
598: break;
599: case 'U':
600: unit = strtonum(optarg, 0, 15, &str);
601: if (str)
602: errx(1, "%s: unit number is %s", optarg, str);
603: break;
604: case 'L':
1.25 ratchov 605: ta = xmalloc(sizeof(struct tcpaddr));
606: ta->host = optarg;
607: ta->next = tcpaddr_list;
608: tcpaddr_list = ta;
1.1 ratchov 609: break;
610: case 'm':
611: mode = opt_mode();
612: break;
613: case 'j':
614: dup = opt_onoff();
615: break;
616: case 't':
617: mmc = opt_mmc();
618: break;
619: case 'c':
620: opt_ch(&pmin, &pmax);
621: break;
622: case 'C':
623: opt_ch(&rmin, &rmax);
624: break;
625: case 'e':
626: opt_enc(&par);
627: break;
628: case 'r':
629: rate = strtonum(optarg, RATE_MIN, RATE_MAX, &str);
630: if (str)
631: errx(1, "%s: rate is %s", optarg, str);
632: break;
633: case 'v':
634: vol = strtonum(optarg, 0, MIDI_MAXCTL, &str);
635: if (str)
636: errx(1, "%s: volume is %s", optarg, str);
637: break;
638: case 's':
1.45 ratchov 639: if (d == NULL) {
640: for (i = 0; default_devs[i] != NULL; i++) {
641: mkdev(default_devs[i], &par, 0,
642: bufsz, round, rate, 0, autovol);
643: }
644: d = dev_list;
1.1 ratchov 645: }
1.26 ratchov 646: if (mkopt(optarg, d, pmin, pmax, rmin, rmax,
647: mode, vol, mmc, dup) == NULL)
648: return 1;
1.1 ratchov 649: break;
650: case 'q':
1.45 ratchov 651: p = mkport(optarg, hold);
1.47 ratchov 652: /* create new circulate list */
653: port_first = port_next = p;
1.1 ratchov 654: break;
1.36 ratchov 655: case 'Q':
1.45 ratchov 656: if (p == NULL)
1.36 ratchov 657: errx(1, "-Q %s: no ports defined", optarg);
1.47 ratchov 658: p = mkport(optarg, hold);
659: /* add to circulate list */
660: p->alt_next = port_next;
661: port_first->alt_next = p;
662: port_next = p;
1.36 ratchov 663: break;
1.1 ratchov 664: case 'a':
665: hold = opt_onoff();
666: break;
667: case 'w':
668: autovol = opt_onoff();
669: break;
670: case 'b':
671: bufsz = strtonum(optarg, 1, RATE_MAX, &str);
672: if (str)
673: errx(1, "%s: buffer size is %s", optarg, str);
674: break;
675: case 'z':
676: round = strtonum(optarg, 1, SHRT_MAX, &str);
677: if (str)
678: errx(1, "%s: block size is %s", optarg, str);
679: break;
680: case 'f':
1.45 ratchov 681: d = mkdev(optarg, &par, 0, bufsz, round,
1.28 ratchov 682: rate, hold, autovol);
1.47 ratchov 683: /* create new circulate list */
684: dev_first = dev_next = d;
1.1 ratchov 685: break;
1.36 ratchov 686: case 'F':
1.45 ratchov 687: if (d == NULL)
1.36 ratchov 688: errx(1, "-F %s: no devices defined", optarg);
1.47 ratchov 689: d = mkdev(optarg, &par, 0, bufsz, round,
690: rate, hold, autovol);
691: /* add to circulate list */
692: d->alt_next = dev_next;
693: dev_first->alt_next = d;
694: dev_next = d;
1.36 ratchov 695: break;
1.1 ratchov 696: default:
697: fputs(usagestr, stderr);
698: return 1;
699: }
700: }
701: argc -= optind;
702: argv += optind;
703: if (argc > 0) {
704: fputs(usagestr, stderr);
705: return 1;
1.39 ratchov 706: }
707: if (port_list == NULL) {
708: for (i = 0; default_ports[i] != NULL; i++)
709: mkport(default_ports[i], 0);
1.1 ratchov 710: }
1.45 ratchov 711: if (dev_list == NULL) {
712: for (i = 0; default_devs[i] != NULL; i++) {
1.40 ratchov 713: mkdev(default_devs[i], &par, 0,
714: bufsz, round, rate, 0, autovol);
715: }
716: }
1.47 ratchov 717:
718: /*
719: * Add default sub-device (if none) backed by the last device
720: */
721: o = opt_byname("default");
722: if (o == NULL) {
723: o = mkopt("default", dev_list, pmin, pmax, rmin, rmax,
724: mode, vol, 0, dup);
725: if (o == NULL)
726: return 1;
727: }
728:
729: /*
730: * For each device create an anonymous sub-device using
731: * the "default" sub-device as template
732: */
1.1 ratchov 733: for (d = dev_list; d != NULL; d = d->next) {
1.47 ratchov 734: if (opt_new(d, NULL, o->pmin, o->pmax, o->rmin, o->rmax,
735: o->maxweight, o->mtc != NULL, o->dup, o->mode) == NULL)
1.26 ratchov 736: return 1;
1.47 ratchov 737: dev_adjpar(d, o->mode, o->pmax, o->rmax);
1.1 ratchov 738: }
1.17 ratchov 739:
740: setsig();
741: filelist_init();
742:
1.32 ratchov 743: if (!start_helper(background))
744: return 1;
745:
746: if (geteuid() == 0) {
1.20 ratchov 747: if ((pw = getpwnam(SNDIO_USER)) == NULL)
748: errx(1, "unknown user %s", SNDIO_USER);
1.32 ratchov 749: } else
750: pw = NULL;
751: getbasepath(base);
752: snprintf(path, SOCKPATH_MAX, "%s/" SOCKPATH_FILE "%u", base, unit);
753: if (!listen_new_un(path))
754: return 1;
755: for (ta = tcpaddr_list; ta != NULL; ta = ta->next) {
756: if (!listen_new_tcp(ta->host, AUCAT_PORT + unit))
757: return 1;
1.20 ratchov 758: }
1.32 ratchov 759: for (l = listen_list; l != NULL; l = l->next) {
760: if (!listen_init(l))
761: return 1;
1.13 ratchov 762: }
1.32 ratchov 763: midi_init();
764: for (p = port_list; p != NULL; p = p->next) {
765: if (!port_init(p))
766: return 1;
1.1 ratchov 767: }
1.32 ratchov 768: for (d = dev_list; d != NULL; d = d->next) {
769: if (!dev_init(d))
1.1 ratchov 770: return 1;
1.32 ratchov 771: }
1.47 ratchov 772: for (o = opt_list; o != NULL; o = o->next)
773: opt_init(o);
1.32 ratchov 774: if (background) {
775: log_flush();
776: log_level = 0;
1.35 ratchov 777: if (daemon(0, 0) == -1)
1.32 ratchov 778: err(1, "daemon");
779: }
780: if (pw != NULL) {
1.35 ratchov 781: if (setpriority(PRIO_PROCESS, 0, SNDIO_PRIO) == -1)
1.32 ratchov 782: err(1, "setpriority");
1.35 ratchov 783: if (chroot(pw->pw_dir) == -1 || chdir("/") == -1)
1.32 ratchov 784: err(1, "cannot chroot to %s", pw->pw_dir);
1.35 ratchov 785: if (setgroups(1, &pw->pw_gid) == -1 ||
786: setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1 ||
787: setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1 )
1.32 ratchov 788: err(1, "cannot drop privileges");
789: }
790: if (tcpaddr_list) {
791: if (pledge("stdio audio recvfd unix inet", NULL) == -1)
1.22 ratchov 792: err(1, "pledge");
1.18 ratchov 793: } else {
1.32 ratchov 794: if (pledge("stdio audio recvfd unix", NULL) == -1)
795: err(1, "pledge");
796: }
1.49 ! ratchov 797:
1.32 ratchov 798: for (;;) {
799: if (quit_flag)
800: break;
1.36 ratchov 801: if (reopen_flag) {
802: reopen_flag = 0;
1.49 ! ratchov 803: reopen_devs();
! 804: reopen_ports();
1.36 ratchov 805: }
1.32 ratchov 806: if (!fdpass_peer)
807: break;
808: if (!file_poll())
809: break;
810: }
811: stop_helper();
812: while (listen_list != NULL)
813: listen_close(listen_list);
814: while (sock_list != NULL)
815: sock_close(sock_list);
1.47 ratchov 816: for (o = opt_list; o != NULL; o = o->next)
817: opt_done(o);
1.32 ratchov 818: for (d = dev_list; d != NULL; d = d->next)
819: dev_done(d);
820: for (p = port_list; p != NULL; p = p->next)
821: port_done(p);
822: while (file_poll())
823: ; /* nothing */
824: midi_done();
1.18 ratchov 825:
1.43 ratchov 826: while (opt_list)
827: opt_del(opt_list);
1.1 ratchov 828: while (dev_list)
829: dev_del(dev_list);
830: while (port_list)
831: port_del(port_list);
1.25 ratchov 832: while (tcpaddr_list) {
833: ta = tcpaddr_list;
834: tcpaddr_list = ta->next;
835: xfree(ta);
836: }
1.1 ratchov 837: filelist_done();
838: unsetsig();
839: return 0;
840: }