Annotation of src/usr.bin/aucat/aucat.c, Revision 1.122
1.122 ! ratchov 1: /* $OpenBSD: aucat.c,v 1.121 2011/10/12 12:16:10 jmc 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;
382: hold = join = autovol = 1;
383: mmc = 0;
384: bufsz = 0;
385: round = 0;
386: unit = 0;
387: background = 0;
388: aparams_init(&ppar, 0, 1, DEFAULT_RATE);
389: aparams_init(&rpar, 0, 1, DEFAULT_RATE);
390: server = 0;
391:
392: #ifdef DEBUG
393: atexit(dbg_flush);
394: #endif
395: setsig();
396: filelist_init();
397:
398: prog = strrchr(argv[0], '/');
399: if (prog == NULL)
400: prog = argv[0];
401: else
402: prog++;
403: if (strcmp(prog, PROG_AUCAT) == 0) {
404: mode = MODE_MIDIMASK | MODE_PLAY | MODE_REC;
405: 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:";
406: usagestr = aucat_usage;
407: } else {
408: fprintf(stderr, "%s: can't determine program to run\n", prog);
409: return 1;
410: }
1.92 ratchov 411:
1.120 ratchov 412: while ((c = getopt(argc, argv, optstr)) != -1) {
1.15 ratchov 413: switch (c) {
1.69 ratchov 414: case 'd':
1.78 ratchov 415: #ifdef DEBUG
1.120 ratchov 416: if (debug_level < 4)
1.78 ratchov 417: debug_level++;
418: #endif
1.51 ratchov 419: break;
1.92 ratchov 420: case 'U':
1.120 ratchov 421: if (server)
422: errx(1, "-U must come before server options");
1.92 ratchov 423: unit = strtonum(optarg, 0, MIDI_MAXCTL, &str);
424: if (str)
425: errx(1, "%s: unit number is %s", optarg, str);
1.120 ratchov 426: server = 1;
1.92 ratchov 427: break;
1.113 ratchov 428: case 'L':
1.122 ! ratchov 429: listen_new_tcp(optarg, AUCAT_PORT + unit);
1.120 ratchov 430: server = 1;
1.113 ratchov 431: break;
1.43 ratchov 432: case 'm':
1.120 ratchov 433: mode = opt_mode();
1.43 ratchov 434: break;
1.15 ratchov 435: case 'h':
1.120 ratchov 436: hdr = opt_hdr();
1.15 ratchov 437: break;
1.22 ratchov 438: case 'x':
1.120 ratchov 439: xrun = opt_xrun();
1.22 ratchov 440: break;
1.84 ratchov 441: case 'j':
1.120 ratchov 442: join = opt_onoff();
1.84 ratchov 443: break;
1.74 ratchov 444: case 't':
1.120 ratchov 445: mmc = opt_mmc();
1.74 ratchov 446: break;
1.15 ratchov 447: case 'c':
1.120 ratchov 448: opt_ch(&ppar);
1.15 ratchov 449: break;
450: case 'C':
1.120 ratchov 451: opt_ch(&rpar);
1.15 ratchov 452: break;
453: case 'e':
1.120 ratchov 454: opt_enc(&ppar);
455: aparams_copyenc(&rpar, &ppar);
1.15 ratchov 456: break;
457: case 'r':
1.92 ratchov 458: rate = strtonum(optarg, RATE_MIN, RATE_MAX, &str);
1.76 ratchov 459: if (str)
460: errx(1, "%s: rate is %s", optarg, str);
1.120 ratchov 461: ppar.rate = rpar.rate = rate;
1.15 ratchov 462: break;
1.35 ratchov 463: case 'v':
1.120 ratchov 464: vol = strtonum(optarg, 0, MIDI_MAXCTL, &str);
1.76 ratchov 465: if (str)
466: errx(1, "%s: volume is %s", optarg, str);
1.35 ratchov 467: break;
1.15 ratchov 468: case 'i':
1.120 ratchov 469: d = mkdev(NULL, 0, bufsz, round, 1, autovol);
470: w = wav_new_in(&wav_ops, d,
471: mode & (MODE_PLAY | MODE_MIDIOUT), optarg,
472: hdr, &ppar, xrun, vol, mmc, join);
473: if (w == NULL)
474: errx(1, "%s: couldn't create stream", optarg);
475: dev_adjpar(d, w->mode, NULL, &w->hpar);
476: break;
477: case 'o':
478: d = mkdev(NULL, 0, bufsz, round, 1, autovol);
479: w = wav_new_out(&wav_ops, d,
480: mode & (MODE_RECMASK | MODE_MIDIIN), optarg,
481: hdr, &rpar, xrun, mmc, join);
482: if (w == NULL)
483: errx(1, "%s: couldn't create stream", optarg);
484: dev_adjpar(d, w->mode, &w->hpar, NULL);
1.15 ratchov 485: break;
1.120 ratchov 486: case 's':
487: d = mkdev(NULL, 0, bufsz, round, 1, autovol);
488: mkopt(optarg, d, &rpar, &ppar,
489: mode, vol, mmc, join);
490: /* XXX: set device rate, if never set */
491: server = 1;
1.42 ratchov 492: break;
1.120 ratchov 493: case 'q':
494: d = mkdev(NULL, mode, bufsz, round, 1, autovol);
495: if (!devctl_add(d, optarg, MODE_MIDIMASK))
496: errx(1, "%s: can't open port", optarg);
497: d->reqmode |= MODE_MIDIMASK;
1.92 ratchov 498: break;
499: case 'a':
1.120 ratchov 500: hold = opt_onoff();
1.83 ratchov 501: break;
1.115 ratchov 502: case 'w':
1.120 ratchov 503: autovol = opt_onoff();
1.4 millert 504: break;
1.28 ratchov 505: case 'b':
1.120 ratchov 506: bufsz = strtonum(optarg, 1, RATE_MAX * 5, &str);
1.76 ratchov 507: if (str)
508: errx(1, "%s: buffer size is %s", optarg, str);
1.28 ratchov 509: break;
1.74 ratchov 510: case 'z':
1.120 ratchov 511: round = strtonum(optarg, 1, SHRT_MAX, &str);
1.76 ratchov 512: if (str)
513: errx(1, "%s: block size is %s", optarg, str);
1.74 ratchov 514: break;
1.92 ratchov 515: case 'f':
1.120 ratchov 516: mkdev(optarg, 0, bufsz, round, hold, autovol);
517: break;
518: case 'n':
519: mkdev("loopback", MODE_LOOP, bufsz, round, 1, autovol);
520: break;
521: case 'M':
522: mkdev("midithru", MODE_THRU, 0, 0, 1, 0);
1.92 ratchov 523: break;
524: case 'l':
1.120 ratchov 525: background = 1;
1.92 ratchov 526: break;
1.11 jaredy 527: default:
1.120 ratchov 528: fputs(usagestr, stderr);
1.15 ratchov 529: exit(1);
1.4 millert 530: }
531: }
532: argc -= optind;
533: argv += optind;
1.92 ratchov 534: if (argc > 0) {
1.120 ratchov 535: fputs(usagestr, stderr);
1.102 ratchov 536: exit(1);
1.15 ratchov 537: }
1.120 ratchov 538: if (wav_list == NULL) {
539: if (opt_list == NULL) {
540: d = mkdev(NULL, 0, bufsz, round, 1, autovol);
541: mkopt("default", d, &rpar, &ppar,
542: mode, vol, mmc, join);
543: server = 1;
544: }
1.116 ratchov 545: } else {
1.120 ratchov 546: d = mkdev(NULL, 0, bufsz, round, 1, autovol);
547: if ((d->reqmode & MODE_THRU) && !d->ctl_list) {
548: if (!devctl_add(d, "default", MODE_MIDIMASK))
549: errx(1, "%s: can't open port", optarg);
550: d->reqmode |= MODE_MIDIMASK;
1.92 ratchov 551: }
1.42 ratchov 552: }
1.120 ratchov 553: if (server) {
1.61 ratchov 554: getbasepath(base, sizeof(base));
1.122 ! ratchov 555: snprintf(path, PATH_MAX, "%s/%s%u", base, AUCAT_PATH, unit);
1.120 ratchov 556: listen_new_un(path);
557: if (geteuid() == 0)
558: privdrop();
559: }
560: for (w = wav_list; w != NULL; w = w->next) {
561: if (!wav_init(w))
562: exit(1);
1.55 ratchov 563: }
1.120 ratchov 564: for (d = dev_list; d != NULL; d = d->next) {
565: if (!dev_init(d))
566: exit(1);
567: if (d->autostart && (d->mode & MODE_AUDIOMASK))
1.92 ratchov 568: ctl_start(d->midi);
1.56 ratchov 569: }
1.120 ratchov 570: for (l = listen_list; l != NULL; l = l->next) {
571: if (!listen_init(l))
572: exit(1);
1.98 ratchov 573: }
1.120 ratchov 574: if (background) {
1.107 ratchov 575: #ifdef DEBUG
1.98 ratchov 576: debug_level = 0;
577: dbg_flush();
1.107 ratchov 578: #endif
1.98 ratchov 579: if (daemon(0, 0) < 0)
1.56 ratchov 580: err(1, "daemon");
1.15 ratchov 581: }
1.13 uwe 582:
1.15 ratchov 583: /*
1.62 ratchov 584: * Loop, start audio.
1.15 ratchov 585: */
1.28 ratchov 586: for (;;) {
1.90 ratchov 587: if (quit_flag)
1.28 ratchov 588: break;
1.92 ratchov 589: active = 0;
590: for (d = dev_list; d != NULL; d = dnext) {
591: dnext = d->next;
592: if (!dev_run(d))
593: goto fatal;
1.120 ratchov 594: if ((d->mode & MODE_THRU) ||
595: (d->pstate != DEV_CLOSED && !ctl_idle(d->midi)))
1.92 ratchov 596: active = 1;
597: }
598: if (dev_list == NULL)
1.50 ratchov 599: break;
1.120 ratchov 600: if (!server && !active)
1.83 ratchov 601: break;
1.50 ratchov 602: if (!file_poll())
603: break;
1.34 ratchov 604: }
1.92 ratchov 605: fatal:
1.120 ratchov 606: while (listen_list != NULL)
607: file_close(&listen_list->file);
1.110 ratchov 608:
1.90 ratchov 609: /*
610: * give a chance to drain
611: */
1.96 ratchov 612: for (d = dev_list; d != NULL; d = d->next)
613: dev_drain(d);
1.90 ratchov 614: while (file_poll())
615: ; /* nothing */
1.96 ratchov 616:
617: while (dev_list)
618: dev_del(dev_list);
1.83 ratchov 619: filelist_done();
1.120 ratchov 620: if (server) {
1.86 ratchov 621: if (rmdir(base) < 0 && errno != ENOTEMPTY && errno != EPERM)
1.55 ratchov 622: warn("rmdir(\"%s\")", base);
623: }
1.61 ratchov 624: unsetsig();
625: return 0;
1.1 kstailey 626: }