Annotation of src/usr.bin/aucat/aucat.c, Revision 1.121
1.121 ! jmc 1: /* $OpenBSD: aucat.c,v 1.120 2011/10/12 07:20:03 ratchov Exp $ */
1.1 kstailey 2: /*
1.15 ratchov 3: * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
1.1 kstailey 4: *
1.15 ratchov 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/param.h>
18: #include <sys/queue.h>
1.55 ratchov 19: #include <sys/stat.h>
1.62 ratchov 20: #include <sys/types.h>
1.86 ratchov 21: #include <sys/resource.h>
1.13 uwe 22:
1.15 ratchov 23: #include <err.h>
1.55 ratchov 24: #include <errno.h>
1.1 kstailey 25: #include <fcntl.h>
1.55 ratchov 26: #include <limits.h>
1.86 ratchov 27: #include <pwd.h>
1.15 ratchov 28: #include <signal.h>
1.1 kstailey 29: #include <stdio.h>
1.4 millert 30: #include <stdlib.h>
1.8 david 31: #include <string.h>
1.1 kstailey 32: #include <unistd.h>
33:
1.62 ratchov 34: #include "abuf.h"
1.112 ratchov 35: #include "amsg.h"
1.15 ratchov 36: #include "aparams.h"
37: #include "aproc.h"
1.62 ratchov 38: #include "conf.h"
39: #include "dev.h"
1.28 ratchov 40: #include "listen.h"
1.61 ratchov 41: #include "midi.h"
42: #include "opt.h"
1.62 ratchov 43: #include "wav.h"
1.78 ratchov 44: #ifdef DEBUG
45: #include "dbg.h"
46: #endif
1.11 jaredy 47:
1.86 ratchov 48: /*
49: * unprivileged user name
50: */
51: #define SNDIO_USER "_sndio"
52:
53: /*
54: * priority when run as root
55: */
56: #define SNDIO_PRIO (-20)
57:
1.61 ratchov 58: #define PROG_AUCAT "aucat"
59: #define PROG_MIDICAT "midicat"
60:
1.108 ratchov 61: /*
62: * sample rate if no ``-r'' is used
63: */
64: #ifndef DEFAULT_RATE
65: #define DEFAULT_RATE 44100
66: #endif
67:
1.120 ratchov 68: /*
69: * block size if no ``-z'' is used
70: */
71: #ifndef DEFAULT_ROUND
72: #define DEFAULT_ROUND (44100 / 15)
73: #endif
74:
1.78 ratchov 75: #ifdef DEBUG
1.120 ratchov 76: volatile sig_atomic_t debug_level = 1;
1.78 ratchov 77: #endif
1.111 deraadt 78: volatile sig_atomic_t quit_flag = 0;
1.7 deraadt 79:
1.120 ratchov 80: char aucat_usage[] = "usage: " PROG_AUCAT " [-dlMn] [-a flag] [-b nframes] "
81: "[-C min:max] [-c min:max] [-e enc]\n\t"
82: "[-f device] [-h fmt] [-i file] [-j flag] [-L addr] [-m mode] "
83: "[-o file]\n\t"
84: "[-q port] [-r rate] [-s name] [-t mode] [-U unit] [-v volume]\n\t"
85: "[-w flag] [-x policy] [-z nframes]\n";
86:
87: char midicat_usage[] = "usage: " PROG_MIDICAT " [-dlM] [-a flag] "
1.121 ! jmc 88: "[-i file] [-L addr] [-o file] [-q port]\n\t"
! 89: "[-s name] [-U unit]\n";
1.120 ratchov 90:
1.28 ratchov 91: /*
92: * SIGINT handler, it raises the quit flag. If the flag is already set,
93: * that means that the last SIGINT was not handled, because the process
1.62 ratchov 94: * is blocked somewhere, so exit.
1.28 ratchov 95: */
96: void
97: sigint(int s)
98: {
99: if (quit_flag)
100: _exit(1);
101: quit_flag = 1;
102: }
1.22 ratchov 103:
1.78 ratchov 104: #ifdef DEBUG
105: /*
106: * Increase debug level on SIGUSR1.
107: */
108: void
109: sigusr1(int s)
110: {
111: if (debug_level < 4)
112: debug_level++;
113: }
114:
115: /*
116: * Decrease debug level on SIGUSR2.
117: */
118: void
119: sigusr2(int s)
120: {
121: if (debug_level > 0)
122: debug_level--;
123: }
124: #endif
1.15 ratchov 125:
126: void
127: opt_ch(struct aparams *par)
128: {
1.76 ratchov 129: char *next, *end;
130: long cmin, cmax;
1.13 uwe 131:
1.76 ratchov 132: errno = 0;
133: cmin = strtol(optarg, &next, 10);
134: if (next == optarg || *next != ':')
135: goto failed;
136: cmax = strtol(++next, &end, 10);
137: if (end == next || *end != '\0')
138: goto failed;
139: if (cmin < 0 || cmax < cmin || cmax > NCHAN_MAX)
140: goto failed;
141: par->cmin = cmin;
142: par->cmax = cmax;
143: return;
144: failed:
145: errx(1, "%s: bad channel range", optarg);
1.15 ratchov 146: }
1.13 uwe 147:
1.15 ratchov 148: void
149: opt_enc(struct aparams *par)
150: {
1.28 ratchov 151: int len;
152:
153: len = aparams_strtoenc(par, optarg);
154: if (len == 0 || optarg[len] != '\0')
155: errx(1, "%s: bad encoding", optarg);
1.15 ratchov 156: }
1.4 millert 157:
1.15 ratchov 158: int
159: opt_hdr(void)
160: {
161: if (strcmp("auto", optarg) == 0)
162: return HDR_AUTO;
163: if (strcmp("raw", optarg) == 0)
164: return HDR_RAW;
165: if (strcmp("wav", optarg) == 0)
166: return HDR_WAV;
1.35 ratchov 167: errx(1, "%s: bad header specification", optarg);
1.1 kstailey 168: }
169:
1.22 ratchov 170: int
1.74 ratchov 171: opt_mmc(void)
172: {
173: if (strcmp("off", optarg) == 0)
174: return 0;
175: if (strcmp("slave", optarg) == 0)
176: return 1;
177: errx(1, "%s: bad MMC mode", optarg);
178: }
179:
180: int
1.90 ratchov 181: opt_onoff(void)
1.84 ratchov 182: {
183: if (strcmp("off", optarg) == 0)
184: return 0;
185: if (strcmp("on", optarg) == 0)
186: return 1;
187: errx(1, "%s: bad join/expand setting", optarg);
188: }
189:
190: int
1.22 ratchov 191: opt_xrun(void)
192: {
193: if (strcmp("ignore", optarg) == 0)
194: return XRUN_IGNORE;
195: if (strcmp("sync", optarg) == 0)
196: return XRUN_SYNC;
197: if (strcmp("error", optarg) == 0)
198: return XRUN_ERROR;
1.73 ratchov 199: errx(1, "%s: bad underrun/overrun policy", optarg);
1.22 ratchov 200: }
201:
1.83 ratchov 202: unsigned
1.43 ratchov 203: opt_mode(void)
204: {
1.83 ratchov 205: unsigned mode = 0;
206: char *p = optarg;
207: size_t len;
208:
1.104 ratchov 209: for (p = optarg; *p != '\0'; p++) {
1.83 ratchov 210: len = strcspn(p, ",");
211: if (strncmp("play", p, len) == 0) {
212: mode |= MODE_PLAY;
213: } else if (strncmp("rec", p, len) == 0) {
214: mode |= MODE_REC;
215: } else if (strncmp("mon", p, len) == 0) {
216: mode |= MODE_MON;
1.120 ratchov 217: } else if (strncmp("midi", p, len) == 0) {
218: mode |= MODE_MIDIMASK;
1.83 ratchov 219: } else
220: errx(1, "%s: bad mode", optarg);
221: p += len;
222: if (*p == '\0')
223: break;
224: }
225: if (mode == 0)
226: errx(1, "empty mode");
227: return mode;
1.43 ratchov 228: }
229:
1.113 ratchov 230: void
1.61 ratchov 231: setsig(void)
232: {
233: struct sigaction sa;
234:
235: quit_flag = 0;
236: sigfillset(&sa.sa_mask);
237: sa.sa_flags = SA_RESTART;
238: sa.sa_handler = sigint;
239: if (sigaction(SIGINT, &sa, NULL) < 0)
1.68 ratchov 240: err(1, "sigaction(int) failed");
1.61 ratchov 241: if (sigaction(SIGTERM, &sa, NULL) < 0)
1.68 ratchov 242: err(1, "sigaction(term) failed");
1.61 ratchov 243: if (sigaction(SIGHUP, &sa, NULL) < 0)
1.68 ratchov 244: err(1, "sigaction(hup) failed");
1.78 ratchov 245: #ifdef DEBUG
246: sa.sa_handler = sigusr1;
247: if (sigaction(SIGUSR1, &sa, NULL) < 0)
248: err(1, "sigaction(usr1) failed");
249: sa.sa_handler = sigusr2;
250: if (sigaction(SIGUSR2, &sa, NULL) < 0)
251: err(1, "sigaction(usr2) failed1n");
252: #endif
1.61 ratchov 253: }
254:
255: void
256: unsetsig(void)
257: {
258: struct sigaction sa;
259:
260: sigfillset(&sa.sa_mask);
261: sa.sa_flags = SA_RESTART;
262: sa.sa_handler = SIG_DFL;
1.78 ratchov 263: #ifdef DEBUG
264: if (sigaction(SIGUSR2, &sa, NULL) < 0)
265: err(1, "unsetsig(usr2): sigaction failed");
266: if (sigaction(SIGUSR1, &sa, NULL) < 0)
267: err(1, "unsetsig(usr1): sigaction failed");
268: #endif
1.61 ratchov 269: if (sigaction(SIGHUP, &sa, NULL) < 0)
1.68 ratchov 270: err(1, "unsetsig(hup): sigaction failed\n");
1.61 ratchov 271: if (sigaction(SIGTERM, &sa, NULL) < 0)
1.68 ratchov 272: err(1, "unsetsig(term): sigaction failed\n");
1.61 ratchov 273: if (sigaction(SIGINT, &sa, NULL) < 0)
1.68 ratchov 274: err(1, "unsetsig(int): sigaction failed\n");
1.61 ratchov 275: }
276:
277: void
278: getbasepath(char *base, size_t size)
279: {
280: uid_t uid;
281: struct stat sb;
1.86 ratchov 282: mode_t mask;
1.61 ratchov 283:
284: uid = geteuid();
1.86 ratchov 285: if (uid == 0) {
286: mask = 022;
287: snprintf(base, PATH_MAX, "/tmp/aucat");
288: } else {
289: mask = 077;
290: snprintf(base, PATH_MAX, "/tmp/aucat-%u", uid);
291: }
292: if (mkdir(base, 0777 & ~mask) < 0) {
1.61 ratchov 293: if (errno != EEXIST)
294: err(1, "mkdir(\"%s\")", base);
295: }
296: if (stat(base, &sb) < 0)
297: err(1, "stat(\"%s\")", base);
1.86 ratchov 298: if (sb.st_uid != uid || (sb.st_mode & mask) != 0)
1.61 ratchov 299: errx(1, "%s has wrong permissions", base);
300: }
301:
302: void
1.86 ratchov 303: privdrop(void)
304: {
305: struct passwd *pw;
306: struct stat sb;
307:
308: if ((pw = getpwnam(SNDIO_USER)) == NULL)
1.105 deraadt 309: errx(1, "unknown user %s", SNDIO_USER);
1.86 ratchov 310: if (stat(pw->pw_dir, &sb) < 0)
311: err(1, "stat(\"%s\")", pw->pw_dir);
312: if (sb.st_uid != 0 || (sb.st_mode & 022) != 0)
313: errx(1, "%s has wrong permissions", pw->pw_dir);
314: if (setpriority(PRIO_PROCESS, 0, SNDIO_PRIO) < 0)
315: err(1, "setpriority");
316: if (setgroups(1, &pw->pw_gid) ||
317: setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
318: setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
319: err(1, "cannot drop privileges");
320: }
321:
1.120 ratchov 322: struct dev *
323: mkdev(char *path, int mode, int bufsz, int round, int hold, int autovol)
1.61 ratchov 324: {
1.120 ratchov 325: struct dev *d;
326:
327: if (path) {
328: for (d = dev_list; d != NULL; d = d->next) {
329: if (d->reqmode & (MODE_LOOP | MODE_THRU))
330: continue;
331: if (strcmp(d->path, path) == 0)
332: return d;
333: }
334: } else {
335: if (dev_list)
336: return dev_list;
337: path = "default";
338: }
339: if (!bufsz) {
340: if (!round)
341: round = DEFAULT_ROUND;
342: bufsz = round * 4;
343: } else if (!round)
344: round = bufsz / 4;
345: return dev_new(path, mode, bufsz, round, hold, autovol);
346: }
347:
348: struct opt *
349: mkopt(char *path, struct dev *d, struct aparams *rpar, struct aparams *ppar,
350: int mode, int vol, int mmc, int join)
351: {
352: struct opt *o;
353:
354: if (d->reqmode & MODE_LOOP)
355: errx(1, "%s: can't attach to loopback", path);
356: if (d->reqmode & MODE_THRU)
357: mode = MODE_MIDIMASK;
358: if (!rpar->rate)
359: ppar->rate = rpar->rate = DEFAULT_RATE;
360: o = opt_new(path, d, rpar, ppar, MIDI_TO_ADATA(vol), mmc, join, mode);
361: if (o == NULL)
362: errx(1, "%s: couldn't create subdev", path);
363: dev_adjpar(d, o->mode, rpar, ppar);
364: return o;
1.61 ratchov 365: }
366:
1.1 kstailey 367: int
1.120 ratchov 368: main(int argc, char **argv)
1.1 kstailey 369: {
1.120 ratchov 370: char *prog, *un_path, *optstr, *usagestr;
371: int c, background, unit, server, tcp_port, active;
1.92 ratchov 372: char base[PATH_MAX], path[PATH_MAX];
1.120 ratchov 373: unsigned mode, hdr, xrun, rate, join, mmc, vol;
374: unsigned hold, autovol, bufsz, round;
1.76 ratchov 375: const char *str;
1.120 ratchov 376: struct aparams ppar, rpar;
1.92 ratchov 377: struct dev *d, *dnext;
1.120 ratchov 378: struct listen *l;
379: struct wav *w;
1.19 ratchov 380:
1.92 ratchov 381: /*
382: * global options defaults
383: */
1.120 ratchov 384: hdr = HDR_AUTO;
385: xrun = XRUN_IGNORE;
386: vol = MIDI_MAXCTL;
387: hold = join = autovol = 1;
388: mmc = 0;
389: bufsz = 0;
390: round = 0;
391: unit = 0;
392: background = 0;
393: aparams_init(&ppar, 0, 1, DEFAULT_RATE);
394: aparams_init(&rpar, 0, 1, DEFAULT_RATE);
395: server = 0;
396:
397: #ifdef DEBUG
398: atexit(dbg_flush);
399: #endif
400: setsig();
401: filelist_init();
402:
403: prog = strrchr(argv[0], '/');
404: if (prog == NULL)
405: prog = argv[0];
406: else
407: prog++;
408: if (strcmp(prog, PROG_AUCAT) == 0) {
409: mode = MODE_MIDIMASK | MODE_PLAY | MODE_REC;
410: optstr = "a:b:c:C:de:f:h:i:j:lL:m:Mno:q:r:s:t:U:v:w:x:z:t:j:z:";
411: usagestr = aucat_usage;
412: un_path = AUCAT_PATH;
413: tcp_port = AUCAT_PORT;
414: } else if (strcmp(prog, PROG_MIDICAT) == 0) {
415: mode = MODE_MIDIMASK | MODE_THRU;
416: optstr = "a:di:lL:Mo:q:s:U:";
417: usagestr = midicat_usage;
418: un_path = MIDICAT_PATH;
419: tcp_port = MIDICAT_PORT;
420: mkdev("midithru", MODE_THRU, 0, 0, 1, 0);
421: } else {
422: fprintf(stderr, "%s: can't determine program to run\n", prog);
423: return 1;
424: }
1.92 ratchov 425:
1.15 ratchov 426:
1.120 ratchov 427: while ((c = getopt(argc, argv, optstr)) != -1) {
1.15 ratchov 428: switch (c) {
1.69 ratchov 429: case 'd':
1.78 ratchov 430: #ifdef DEBUG
1.120 ratchov 431: if (debug_level < 4)
1.78 ratchov 432: debug_level++;
433: #endif
1.51 ratchov 434: break;
1.92 ratchov 435: case 'U':
1.120 ratchov 436: if (server)
437: errx(1, "-U must come before server options");
1.92 ratchov 438: unit = strtonum(optarg, 0, MIDI_MAXCTL, &str);
439: if (str)
440: errx(1, "%s: unit number is %s", optarg, str);
1.120 ratchov 441: server = 1;
1.92 ratchov 442: break;
1.113 ratchov 443: case 'L':
1.120 ratchov 444: listen_new_tcp(optarg, tcp_port + unit);
445: server = 1;
1.113 ratchov 446: break;
1.43 ratchov 447: case 'm':
1.120 ratchov 448: mode = opt_mode();
1.43 ratchov 449: break;
1.15 ratchov 450: case 'h':
1.120 ratchov 451: hdr = opt_hdr();
1.15 ratchov 452: break;
1.22 ratchov 453: case 'x':
1.120 ratchov 454: xrun = opt_xrun();
1.22 ratchov 455: break;
1.84 ratchov 456: case 'j':
1.120 ratchov 457: join = opt_onoff();
1.84 ratchov 458: break;
1.74 ratchov 459: case 't':
1.120 ratchov 460: mmc = opt_mmc();
1.74 ratchov 461: break;
1.15 ratchov 462: case 'c':
1.120 ratchov 463: opt_ch(&ppar);
1.15 ratchov 464: break;
465: case 'C':
1.120 ratchov 466: opt_ch(&rpar);
1.15 ratchov 467: break;
468: case 'e':
1.120 ratchov 469: opt_enc(&ppar);
470: aparams_copyenc(&rpar, &ppar);
1.15 ratchov 471: break;
472: case 'r':
1.92 ratchov 473: rate = strtonum(optarg, RATE_MIN, RATE_MAX, &str);
1.76 ratchov 474: if (str)
475: errx(1, "%s: rate is %s", optarg, str);
1.120 ratchov 476: ppar.rate = rpar.rate = rate;
1.15 ratchov 477: break;
1.35 ratchov 478: case 'v':
1.120 ratchov 479: vol = strtonum(optarg, 0, MIDI_MAXCTL, &str);
1.76 ratchov 480: if (str)
481: errx(1, "%s: volume is %s", optarg, str);
1.35 ratchov 482: break;
1.15 ratchov 483: case 'i':
1.120 ratchov 484: d = mkdev(NULL, 0, bufsz, round, 1, autovol);
485: w = wav_new_in(&wav_ops, d,
486: mode & (MODE_PLAY | MODE_MIDIOUT), optarg,
487: hdr, &ppar, xrun, vol, mmc, join);
488: if (w == NULL)
489: errx(1, "%s: couldn't create stream", optarg);
490: dev_adjpar(d, w->mode, NULL, &w->hpar);
491: break;
492: case 'o':
493: d = mkdev(NULL, 0, bufsz, round, 1, autovol);
494: w = wav_new_out(&wav_ops, d,
495: mode & (MODE_RECMASK | MODE_MIDIIN), optarg,
496: hdr, &rpar, xrun, mmc, join);
497: if (w == NULL)
498: errx(1, "%s: couldn't create stream", optarg);
499: dev_adjpar(d, w->mode, &w->hpar, NULL);
1.15 ratchov 500: break;
1.120 ratchov 501: case 's':
502: d = mkdev(NULL, 0, bufsz, round, 1, autovol);
503: mkopt(optarg, d, &rpar, &ppar,
504: mode, vol, mmc, join);
505: /* XXX: set device rate, if never set */
506: server = 1;
1.42 ratchov 507: break;
1.120 ratchov 508: case 'q':
509: d = mkdev(NULL, mode, bufsz, round, 1, autovol);
510: if (!devctl_add(d, optarg, MODE_MIDIMASK))
511: errx(1, "%s: can't open port", optarg);
512: d->reqmode |= MODE_MIDIMASK;
1.92 ratchov 513: break;
514: case 'a':
1.120 ratchov 515: hold = opt_onoff();
1.83 ratchov 516: break;
1.115 ratchov 517: case 'w':
1.120 ratchov 518: autovol = opt_onoff();
1.4 millert 519: break;
1.28 ratchov 520: case 'b':
1.120 ratchov 521: bufsz = strtonum(optarg, 1, RATE_MAX * 5, &str);
1.76 ratchov 522: if (str)
523: errx(1, "%s: buffer size is %s", optarg, str);
1.28 ratchov 524: break;
1.74 ratchov 525: case 'z':
1.120 ratchov 526: round = strtonum(optarg, 1, SHRT_MAX, &str);
1.76 ratchov 527: if (str)
528: errx(1, "%s: block size is %s", optarg, str);
1.74 ratchov 529: break;
1.92 ratchov 530: case 'f':
1.120 ratchov 531: mkdev(optarg, 0, bufsz, round, hold, autovol);
532: break;
533: case 'n':
534: mkdev("loopback", MODE_LOOP, bufsz, round, 1, autovol);
535: break;
536: case 'M':
537: mkdev("midithru", MODE_THRU, 0, 0, 1, 0);
1.92 ratchov 538: break;
539: case 'l':
1.120 ratchov 540: background = 1;
1.92 ratchov 541: break;
1.11 jaredy 542: default:
1.120 ratchov 543: fputs(usagestr, stderr);
1.15 ratchov 544: exit(1);
1.4 millert 545: }
546: }
547: argc -= optind;
548: argv += optind;
1.92 ratchov 549: if (argc > 0) {
1.120 ratchov 550: fputs(usagestr, stderr);
1.102 ratchov 551: exit(1);
1.15 ratchov 552: }
1.120 ratchov 553: if (wav_list == NULL) {
554: if (opt_list == NULL) {
555: d = mkdev(NULL, 0, bufsz, round, 1, autovol);
556: mkopt("default", d, &rpar, &ppar,
557: mode, vol, mmc, join);
558: server = 1;
559: }
1.116 ratchov 560: } else {
1.120 ratchov 561: d = mkdev(NULL, 0, bufsz, round, 1, autovol);
562: if ((d->reqmode & MODE_THRU) && !d->ctl_list) {
563: if (!devctl_add(d, "default", MODE_MIDIMASK))
564: errx(1, "%s: can't open port", optarg);
565: d->reqmode |= MODE_MIDIMASK;
1.92 ratchov 566: }
1.42 ratchov 567: }
1.120 ratchov 568: if (server) {
1.61 ratchov 569: getbasepath(base, sizeof(base));
1.120 ratchov 570: snprintf(path, PATH_MAX, "%s/%s%u", base, un_path, unit);
571: listen_new_un(path);
572: if (geteuid() == 0)
573: privdrop();
574: }
575: for (w = wav_list; w != NULL; w = w->next) {
576: if (!wav_init(w))
577: exit(1);
1.55 ratchov 578: }
1.120 ratchov 579: for (d = dev_list; d != NULL; d = d->next) {
580: if (!dev_init(d))
581: exit(1);
582: if (d->autostart && (d->mode & MODE_AUDIOMASK))
1.92 ratchov 583: ctl_start(d->midi);
1.56 ratchov 584: }
1.120 ratchov 585: for (l = listen_list; l != NULL; l = l->next) {
586: if (!listen_init(l))
587: exit(1);
1.98 ratchov 588: }
1.120 ratchov 589: if (background) {
1.107 ratchov 590: #ifdef DEBUG
1.98 ratchov 591: debug_level = 0;
592: dbg_flush();
1.107 ratchov 593: #endif
1.98 ratchov 594: if (daemon(0, 0) < 0)
1.56 ratchov 595: err(1, "daemon");
1.15 ratchov 596: }
1.13 uwe 597:
1.15 ratchov 598: /*
1.62 ratchov 599: * Loop, start audio.
1.15 ratchov 600: */
1.28 ratchov 601: for (;;) {
1.90 ratchov 602: if (quit_flag)
1.28 ratchov 603: break;
1.92 ratchov 604: active = 0;
605: for (d = dev_list; d != NULL; d = dnext) {
606: dnext = d->next;
607: if (!dev_run(d))
608: goto fatal;
1.120 ratchov 609: if ((d->mode & MODE_THRU) ||
610: (d->pstate != DEV_CLOSED && !ctl_idle(d->midi)))
1.92 ratchov 611: active = 1;
612: }
613: if (dev_list == NULL)
1.50 ratchov 614: break;
1.120 ratchov 615: if (!server && !active)
1.83 ratchov 616: break;
1.50 ratchov 617: if (!file_poll())
618: break;
1.34 ratchov 619: }
1.92 ratchov 620: fatal:
1.120 ratchov 621: while (listen_list != NULL)
622: file_close(&listen_list->file);
1.110 ratchov 623:
1.90 ratchov 624: /*
625: * give a chance to drain
626: */
1.96 ratchov 627: for (d = dev_list; d != NULL; d = d->next)
628: dev_drain(d);
1.90 ratchov 629: while (file_poll())
630: ; /* nothing */
1.96 ratchov 631:
632: while (dev_list)
633: dev_del(dev_list);
1.83 ratchov 634: filelist_done();
1.120 ratchov 635: if (server) {
1.86 ratchov 636: if (rmdir(base) < 0 && errno != ENOTEMPTY && errno != EPERM)
1.55 ratchov 637: warn("rmdir(\"%s\")", base);
638: }
1.61 ratchov 639: unsetsig();
640: return 0;
1.1 kstailey 641: }