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