Annotation of src/usr.bin/aucat/aucat.c, Revision 1.52
1.52 ! ratchov 1: /* $OpenBSD: aucat.c,v 1.51 2009/01/10 20:02:28 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: /*
18: * TODO:
19: *
20: * (hard) use parsable encoding names instead of the lookup
21: * table. For instance, [s|u]bits[le|be][/bytes{msb|lsb}], example
22: * s8, s16le, s24le/3msb. This would give names that correspond to
23: * what use most linux-centric apps, but for which we have an
24: * algorithm to convert the name to a aparams structure.
25: *
26: * (easy) uses {chmin-chmax} instead of chmin:chmax notation for
27: * channels specification to match the notation used in rmix.
28: *
29: * (easy) use comma-separated parameters syntax, example:
30: * s24le/3msb,{3-6},48000 so we don't have to use three -e, -r, -c
31: * flags, but only one -p flag that specify one or more parameters.
32: *
33: * (hard) if all inputs are over, the mixer terminates and closes
34: * the write end of the device. It should continue writing zeros
35: * until the recording is over (or be able to stop write end of
36: * the device)
37: *
38: * (hard) implement -n flag (no device) to connect all inputs to
39: * the outputs.
40: *
41: * (hard) ignore input files that are not audible (because channels
42: * they provide are not used on the output). Similarly ignore
43: * outputs that are zero filled (because channels they consume are
44: * not provided).
1.1 kstailey 45: */
46:
1.15 ratchov 47: #include <sys/param.h>
1.1 kstailey 48: #include <sys/types.h>
1.15 ratchov 49: #include <sys/queue.h>
1.13 uwe 50:
1.28 ratchov 51: #include <signal.h>
1.15 ratchov 52: #include <err.h>
1.1 kstailey 53: #include <fcntl.h>
1.15 ratchov 54: #include <signal.h>
1.1 kstailey 55: #include <stdio.h>
1.4 millert 56: #include <stdlib.h>
1.8 david 57: #include <string.h>
1.1 kstailey 58: #include <unistd.h>
1.15 ratchov 59: #include <varargs.h>
1.1 kstailey 60:
1.15 ratchov 61: #include "conf.h"
62: #include "aparams.h"
63: #include "aproc.h"
64: #include "abuf.h"
1.28 ratchov 65: #include "wav.h"
66: #include "listen.h"
1.15 ratchov 67: #include "dev.h"
1.11 jaredy 68:
1.43 ratchov 69: #define MODE_PLAY 1
70: #define MODE_REC 2
71:
1.28 ratchov 72: int debug_level = 0;
73: volatile int quit_flag = 0;
1.7 deraadt 74:
1.28 ratchov 75: /*
76: * SIGINT handler, it raises the quit flag. If the flag is already set,
77: * that means that the last SIGINT was not handled, because the process
78: * is blocked somewhere, so exit
79: */
80: void
81: sigint(int s)
82: {
83: if (quit_flag)
84: _exit(1);
85: quit_flag = 1;
86: }
1.22 ratchov 87:
1.15 ratchov 88: /*
1.28 ratchov 89: * increase debug level on SIGUSR1
1.15 ratchov 90: */
1.28 ratchov 91: void
92: sigusr1(int s)
93: {
94: if (debug_level < 4)
95: debug_level++;
96: }
1.13 uwe 97:
1.11 jaredy 98: /*
1.28 ratchov 99: * decrease debug level on SIGUSR2
1.1 kstailey 100: */
1.28 ratchov 101: void
102: sigusr2(int s)
1.15 ratchov 103: {
1.28 ratchov 104: if (debug_level > 0)
105: debug_level--;
1.15 ratchov 106: }
107:
108: void
109: usage(void)
1.1 kstailey 110: {
1.15 ratchov 111: extern char *__progname;
1.4 millert 112:
1.15 ratchov 113: fprintf(stderr,
1.51 ratchov 114: "usage: %s [-lnu] [-b nsamples] [-C min:max] [-c min:max] [-e enc] "
1.29 jmc 115: "[-f device]\n"
1.45 jmc 116: "\t[-h fmt] [-i file] [-m mode] [-o file] [-r rate] [-s socket]\n"
1.44 jmc 117: "\t[-v volume] [-x policy]\n",
1.15 ratchov 118: __progname);
119: }
120:
121: void
122: opt_ch(struct aparams *par)
123: {
124: if (sscanf(optarg, "%u:%u", &par->cmin, &par->cmax) != 2 ||
1.28 ratchov 125: par->cmax < par->cmin || par->cmax > NCHAN_MAX - 1)
1.35 ratchov 126: errx(1, "%s: bad channel range", optarg);
1.15 ratchov 127: }
1.13 uwe 128:
1.15 ratchov 129: void
130: opt_rate(struct aparams *par)
131: {
132: if (sscanf(optarg, "%u", &par->rate) != 1 ||
133: par->rate < RATE_MIN || par->rate > RATE_MAX)
1.35 ratchov 134: errx(1, "%s: bad sample rate", optarg);
135: }
136:
137: void
138: opt_vol(unsigned *vol)
139: {
140: if (sscanf(optarg, "%u", vol) != 1 ||
141: *vol > MIDI_MAXCTL)
142: errx(1, "%s: bad volume", optarg);
1.15 ratchov 143: }
1.13 uwe 144:
1.15 ratchov 145: void
146: opt_enc(struct aparams *par)
147: {
1.28 ratchov 148: int len;
149:
150: len = aparams_strtoenc(par, optarg);
151: if (len == 0 || optarg[len] != '\0')
152: errx(1, "%s: bad encoding", optarg);
1.15 ratchov 153: }
1.4 millert 154:
1.15 ratchov 155: int
156: opt_hdr(void)
157: {
158: if (strcmp("auto", optarg) == 0)
159: return HDR_AUTO;
160: if (strcmp("raw", optarg) == 0)
161: return HDR_RAW;
162: if (strcmp("wav", optarg) == 0)
163: return HDR_WAV;
1.35 ratchov 164: errx(1, "%s: bad header specification", optarg);
1.1 kstailey 165: }
166:
1.22 ratchov 167: int
168: opt_xrun(void)
169: {
170: if (strcmp("ignore", optarg) == 0)
171: return XRUN_IGNORE;
172: if (strcmp("sync", optarg) == 0)
173: return XRUN_SYNC;
174: if (strcmp("error", optarg) == 0)
175: return XRUN_ERROR;
176: errx(1, "%s: onderrun/overrun policy", optarg);
177: }
178:
1.43 ratchov 179: int
180: opt_mode(void)
181: {
182: if (strcmp("play", optarg) == 0)
183: return MODE_PLAY;
184: if (strcmp("rec", optarg) == 0)
185: return MODE_REC;
186: if (strcmp("duplex", optarg) == 0)
187: return MODE_PLAY | MODE_REC;
188: errx(1, "%s: bad mode", optarg);
189: }
190:
1.13 uwe 191: /*
1.42 ratchov 192: * Arguments of -i, -o and -s options are stored in a list.
1.13 uwe 193: */
1.15 ratchov 194: struct farg {
195: SLIST_ENTRY(farg) entry;
1.42 ratchov 196: struct aparams ipar; /* input (read) parameters */
197: struct aparams opar; /* output (write) parameters */
1.15 ratchov 198: unsigned vol; /* last requested volume */
199: char *name; /* optarg pointer (no need to copy it */
200: int hdr; /* header format */
1.22 ratchov 201: int xrun; /* overrun/underrun policy */
1.15 ratchov 202: };
1.13 uwe 203:
1.15 ratchov 204: SLIST_HEAD(farglist, farg);
1.13 uwe 205:
1.15 ratchov 206: /*
207: * Add a farg entry to the given list, corresponding
208: * to the given file name.
209: */
210: void
1.52 ! ratchov 211: farg_add(struct farglist *list,
1.42 ratchov 212: struct aparams *ipar, struct aparams *opar, unsigned vol,
213: int hdr, int xrun, char *optarg)
1.15 ratchov 214: {
215: struct farg *fa;
216: size_t namelen;
1.52 ! ratchov 217:
1.15 ratchov 218: fa = malloc(sizeof(struct farg));
219: if (fa == NULL)
220: err(1, "%s", optarg);
221:
222: if (hdr == HDR_AUTO) {
223: namelen = strlen(optarg);
1.52 ! ratchov 224: if (namelen >= 4 &&
1.15 ratchov 225: strcasecmp(optarg + namelen - 4, ".wav") == 0) {
226: fa->hdr = HDR_WAV;
227: DPRINTF("%s: assuming wav file format\n", optarg);
228: } else {
229: fa->hdr = HDR_RAW;
230: DPRINTF("%s: assuming headerless file\n", optarg);
1.13 uwe 231: }
1.52 ! ratchov 232: } else
1.15 ratchov 233: fa->hdr = hdr;
1.22 ratchov 234: fa->xrun = xrun;
1.42 ratchov 235: fa->ipar = *ipar;
236: fa->opar = *opar;
1.15 ratchov 237: fa->vol = vol;
238: fa->name = optarg;
239: SLIST_INSERT_HEAD(list, fa, entry);
240: }
1.13 uwe 241:
1.15 ratchov 242: /*
243: * Open an input file and setup converter if necessary.
244: */
245: void
1.26 ratchov 246: newinput(struct farg *fa)
1.15 ratchov 247: {
248: int fd;
1.28 ratchov 249: struct wav *f;
1.26 ratchov 250: struct aproc *proc;
251: struct abuf *buf;
252: unsigned nfr;
1.15 ratchov 253:
254: if (strcmp(fa->name, "-") == 0) {
255: fd = STDIN_FILENO;
256: if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
257: warn("stdin");
258: fa->name = "stdin";
259: } else {
260: fd = open(fa->name, O_RDONLY | O_NONBLOCK, 0666);
261: if (fd < 0)
262: err(1, "%s", fa->name);
1.13 uwe 263: }
1.28 ratchov 264: /*
265: * XXX : we should round rate, right ?
266: */
1.42 ratchov 267: f = wav_new_in(&wav_ops, fd, fa->name, &fa->ipar, fa->hdr);
268: nfr = dev_bufsz * fa->ipar.rate / dev_rate;
269: buf = abuf_new(nfr, &fa->ipar);
1.28 ratchov 270: proc = rpipe_new((struct file *)f);
1.26 ratchov 271: aproc_setout(proc, buf);
1.28 ratchov 272: abuf_fill(buf); /* XXX: move this in dev_attach() ? */
1.42 ratchov 273: dev_attach(fa->name, buf, &fa->ipar, fa->xrun,
1.40 ratchov 274: NULL, NULL, 0, ADATA_UNIT);
1.35 ratchov 275: dev_setvol(buf, MIDI_TO_ADATA(fa->vol));
1.15 ratchov 276: }
1.13 uwe 277:
1.15 ratchov 278: /*
279: * Open an output file and setup converter if necessary.
280: */
281: void
1.26 ratchov 282: newoutput(struct farg *fa)
1.15 ratchov 283: {
284: int fd;
1.28 ratchov 285: struct wav *f;
1.26 ratchov 286: struct aproc *proc;
287: struct abuf *buf;
288: unsigned nfr;
1.15 ratchov 289:
290: if (strcmp(fa->name, "-") == 0) {
291: fd = STDOUT_FILENO;
292: if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
293: warn("stdout");
294: fa->name = "stdout";
295: } else {
296: fd = open(fa->name,
297: O_WRONLY | O_TRUNC | O_CREAT | O_NONBLOCK, 0666);
298: if (fd < 0)
299: err(1, "%s", fa->name);
300: }
1.28 ratchov 301: /*
302: * XXX : we should round rate, right ?
303: */
1.42 ratchov 304: f = wav_new_out(&wav_ops, fd, fa->name, &fa->opar, fa->hdr);
305: nfr = dev_bufsz * fa->opar.rate / dev_rate;
1.28 ratchov 306: proc = wpipe_new((struct file *)f);
1.42 ratchov 307: buf = abuf_new(nfr, &fa->opar);
1.26 ratchov 308: aproc_setin(proc, buf);
1.42 ratchov 309: dev_attach(fa->name, NULL, NULL, 0, buf, &fa->opar, fa->xrun, 0);
1.13 uwe 310: }
311:
1.1 kstailey 312: int
1.15 ratchov 313: main(int argc, char **argv)
1.1 kstailey 314: {
1.51 ratchov 315: int c, u_flag, l_flag, n_flag, hdr, xrun, suspend = 0;
1.15 ratchov 316: struct farg *fa;
1.42 ratchov 317: struct farglist ifiles, ofiles, sfiles;
1.26 ratchov 318: struct aparams ipar, opar, dipar, dopar;
1.28 ratchov 319: struct sigaction sa;
1.43 ratchov 320: unsigned bufsz, mode;
1.42 ratchov 321: char *devpath, *dbgenv;
1.21 ratchov 322: const char *errstr;
1.28 ratchov 323: extern char *malloc_options;
1.40 ratchov 324: unsigned volctl;
1.28 ratchov 325:
326: malloc_options = "FGJ";
1.15 ratchov 327:
1.19 ratchov 328: dbgenv = getenv("AUCAT_DEBUG");
329: if (dbgenv) {
1.21 ratchov 330: debug_level = strtonum(dbgenv, 0, 4, &errstr);
331: if (errstr)
332: errx(1, "AUCAT_DEBUG is %s: %s", errstr, dbgenv);
1.19 ratchov 333: }
334:
1.15 ratchov 335: aparams_init(&ipar, 0, 1, 44100);
336: aparams_init(&opar, 0, 1, 44100);
1.26 ratchov 337: u_flag = 0;
1.28 ratchov 338: l_flag = 0;
1.51 ratchov 339: n_flag = 0;
1.15 ratchov 340: devpath = NULL;
341: SLIST_INIT(&ifiles);
342: SLIST_INIT(&ofiles);
1.42 ratchov 343: SLIST_INIT(&sfiles);
1.28 ratchov 344: hdr = HDR_AUTO;
345: xrun = XRUN_IGNORE;
1.40 ratchov 346: volctl = MIDI_MAXCTL;
1.32 ratchov 347: bufsz = 44100 * 4 / 15; /* XXX: use milliseconds, not frames */
1.43 ratchov 348: mode = 0;
1.15 ratchov 349:
1.51 ratchov 350: while ((c = getopt(argc, argv, "nb:c:C:e:r:h:x:v:i:o:f:m:lus:")) != -1) {
1.15 ratchov 351: switch (c) {
1.51 ratchov 352: case 'n':
353: n_flag = 1;
354: break;
1.43 ratchov 355: case 'm':
356: mode = opt_mode();
357: break;
1.15 ratchov 358: case 'h':
1.28 ratchov 359: hdr = opt_hdr();
1.15 ratchov 360: break;
1.22 ratchov 361: case 'x':
1.28 ratchov 362: xrun = opt_xrun();
1.22 ratchov 363: break;
1.15 ratchov 364: case 'c':
365: opt_ch(&ipar);
366: break;
367: case 'C':
368: opt_ch(&opar);
369: break;
370: case 'e':
371: opt_enc(&ipar);
1.28 ratchov 372: aparams_copyenc(&opar, &ipar);
1.15 ratchov 373: break;
374: case 'r':
375: opt_rate(&ipar);
1.28 ratchov 376: opar.rate = ipar.rate;
1.15 ratchov 377: break;
1.35 ratchov 378: case 'v':
1.40 ratchov 379: opt_vol(&volctl);
1.35 ratchov 380: break;
1.15 ratchov 381: case 'i':
1.42 ratchov 382: farg_add(&ifiles, &ipar, &opar, volctl,
383: hdr, xrun, optarg);
1.15 ratchov 384: break;
385: case 'o':
1.42 ratchov 386: farg_add(&ofiles, &ipar, &opar, volctl,
387: hdr, xrun, optarg);
388: break;
389: case 's':
390: farg_add(&sfiles, &ipar, &opar, volctl,
391: hdr, xrun, optarg);
1.15 ratchov 392: break;
1.4 millert 393: case 'f':
1.15 ratchov 394: if (devpath)
395: err(1, "only one -f allowed");
396: devpath = optarg;
1.28 ratchov 397: dipar = opar;
398: dopar = ipar;
1.15 ratchov 399: break;
1.28 ratchov 400: case 'l':
401: l_flag = 1;
1.17 jakemsr 402: break;
1.15 ratchov 403: case 'u':
404: u_flag = 1;
1.4 millert 405: break;
1.28 ratchov 406: case 'b':
1.32 ratchov 407: if (sscanf(optarg, "%u", &bufsz) != 1 || bufsz == 0) {
1.28 ratchov 408: fprintf(stderr, "%s: bad buf size\n", optarg);
409: exit(1);
410: }
411: break;
1.11 jaredy 412: default:
413: usage();
1.15 ratchov 414: exit(1);
1.4 millert 415: }
416: }
417: argc -= optind;
418: argv += optind;
419:
1.15 ratchov 420: if (!devpath) {
1.47 ratchov 421: dopar = ipar;
422: dipar = opar;
1.15 ratchov 423: }
424:
1.28 ratchov 425: if (!l_flag && SLIST_EMPTY(&ifiles) &&
426: SLIST_EMPTY(&ofiles) && argc > 0) {
1.15 ratchov 427: /*
428: * Legacy mode: if no -i or -o options are provided, and
429: * there are arguments then assume the arguments are files
430: * to play.
431: */
432: for (c = 0; c < argc; c++)
433: if (legacy_play(devpath, argv[c]) != 0) {
1.17 jakemsr 434: errx(1, "%s: could not play\n", argv[c]);
1.15 ratchov 435: }
436: exit(0);
437: } else if (argc > 0) {
1.11 jaredy 438: usage();
1.15 ratchov 439: exit(1);
440: }
441:
1.42 ratchov 442: if (!l_flag && !SLIST_EMPTY(&sfiles))
443: errx(1, "can't use -s without -l");
1.43 ratchov 444: if ((l_flag || mode != 0) &&
445: (!SLIST_EMPTY(&ofiles) || !SLIST_EMPTY(&ifiles)))
446: errx(1, "can't use -l, -m and -s with -o or -i");
447: if (!mode) {
448: if (l_flag || !SLIST_EMPTY(&ifiles))
449: mode |= MODE_PLAY;
450: if (l_flag || !SLIST_EMPTY(&ofiles))
451: mode |= MODE_REC;
452: }
1.51 ratchov 453: if (n_flag) {
454: if (devpath != NULL || l_flag)
455: errx(1, "can't use -n with -f or -l");
456: if (SLIST_EMPTY(&ifiles) || SLIST_EMPTY(&ofiles))
457: errx(1, "both -i and -o are required with -n");
458: }
1.15 ratchov 459:
1.46 ratchov 460: /*
461: * if there are no sockets paths provided use the default
462: */
463: if (l_flag && SLIST_EMPTY(&sfiles)) {
464: farg_add(&sfiles, &dopar, &dipar,
465: MIDI_MAXCTL, HDR_RAW, XRUN_IGNORE, DEFAULT_SOCKET);
466: }
467:
468: if (!u_flag) {
1.26 ratchov 469: /*
470: * Calculate "best" device parameters. Iterate over all
471: * inputs and outputs and find the maximum sample rate
472: * and channel number.
473: */
1.49 ratchov 474: aparams_init(&dipar, dipar.cmin, dipar.cmax, dipar.rate);
475: aparams_init(&dopar, dopar.cmin, dopar.cmax, dopar.rate);
1.26 ratchov 476: SLIST_FOREACH(fa, &ifiles, entry) {
1.46 ratchov 477: aparams_grow(&dopar, &fa->ipar);
1.26 ratchov 478: }
479: SLIST_FOREACH(fa, &ofiles, entry) {
1.46 ratchov 480: aparams_grow(&dipar, &fa->opar);
481: }
482: SLIST_FOREACH(fa, &sfiles, entry) {
483: aparams_grow(&dopar, &fa->ipar);
484: aparams_grow(&dipar, &fa->opar);
1.17 jakemsr 485: }
1.42 ratchov 486: }
487:
1.28 ratchov 488: quit_flag = 0;
489: sigfillset(&sa.sa_mask);
490: sa.sa_flags = SA_RESTART;
491: sa.sa_handler = sigint;
492: if (sigaction(SIGINT, &sa, NULL) < 0)
493: DPRINTF("sigaction(int) failed\n");
494: #ifdef DEBUG
495: sa.sa_handler = sigusr1;
496: if (sigaction(SIGUSR1, &sa, NULL) < 0)
497: DPRINTF("sigaction(usr1) failed\n");
498: sa.sa_handler = sigusr2;
499: if (sigaction(SIGUSR2, &sa, NULL) < 0)
500: DPRINTF("sigaction(usr2) failed1n");
501: #endif
502: filelist_init();
1.51 ratchov 503:
1.15 ratchov 504: /*
1.32 ratchov 505: * Open the device. Give half of the buffer to the device,
506: * the other half is for the socket/files
1.15 ratchov 507: */
1.51 ratchov 508: if (n_flag) {
509: dev_loopinit(&dipar, &dopar, bufsz);
510: } else {
1.52 ! ratchov 511: dev_init(devpath,
1.51 ratchov 512: (mode & MODE_REC) ? &dipar : NULL,
513: (mode & MODE_PLAY) ? &dopar : NULL,
514: bufsz);
515: }
1.52 ! ratchov 516:
1.15 ratchov 517: /*
518: * Create buffers for all input and output pipes.
519: */
1.26 ratchov 520: while (!SLIST_EMPTY(&ifiles)) {
521: fa = SLIST_FIRST(&ifiles);
522: SLIST_REMOVE_HEAD(&ifiles, entry);
523: newinput(fa);
524: free(fa);
525: }
526: while (!SLIST_EMPTY(&ofiles)) {
527: fa = SLIST_FIRST(&ofiles);
528: SLIST_REMOVE_HEAD(&ofiles, entry);
529: newoutput(fa);
1.42 ratchov 530: free(fa);
531: }
532: while (!SLIST_EMPTY(&sfiles)) {
533: fa = SLIST_FIRST(&sfiles);
534: SLIST_REMOVE_HEAD(&sfiles, entry);
535: (void)listen_new(&listen_ops, fa->name,
536: &fa->opar, &fa->ipar, MIDI_TO_ADATA(fa->vol));
1.26 ratchov 537: free(fa);
1.15 ratchov 538: }
1.13 uwe 539:
1.15 ratchov 540: /*
1.28 ratchov 541: * loop, start audio
1.15 ratchov 542: */
1.28 ratchov 543: for (;;) {
544: if (quit_flag) {
545: break;
546: }
1.50 ratchov 547: if ((!dev_rec || dev_rec->u.io.file == NULL) &&
1.51 ratchov 548: (!dev_play || dev_play->u.io.file == NULL) && !n_flag) {
1.50 ratchov 549: fprintf(stderr, "device desappeared, terminating\n");
550: break;
1.38 ratchov 551: }
1.50 ratchov 552: if (!file_poll())
553: break;
1.34 ratchov 554: if ((!dev_mix || dev_mix->u.mix.idle > 2 * dev_bufsz) &&
555: (!dev_sub || dev_sub->u.sub.idle > 2 * dev_bufsz)) {
1.37 ratchov 556: if (!l_flag)
557: break;
1.34 ratchov 558: if (!suspend) {
559: DPRINTF("suspending\n");
560: suspend = 1;
561: dev_stop();
562: dev_clear();
563: }
564: }
565: if ((dev_mix && dev_mix->u.mix.idle == 0) ||
566: (dev_sub && dev_sub->u.sub.idle == 0)) {
567: if (suspend) {
568: DPRINTF("resuming\n");
569: suspend = 0;
570: dev_start();
571: }
572: }
573: }
1.50 ratchov 574: if (l_flag)
575: filelist_unlisten();
1.34 ratchov 576: if (suspend) {
577: DPRINTF("resuming to drain\n");
578: suspend = 0;
579: dev_start();
1.28 ratchov 580: }
1.51 ratchov 581: if (n_flag) {
582: dev_loopdone();
583: } else
584: dev_done();
1.28 ratchov 585: filelist_done();
1.11 jaredy 586:
1.28 ratchov 587: sigfillset(&sa.sa_mask);
588: sa.sa_flags = SA_RESTART;
589: sa.sa_handler = SIG_DFL;
590: if (sigaction(SIGINT, &sa, NULL) < 0)
591: DPRINTF("dev_done: sigaction failed\n");
1.15 ratchov 592: return 0;
1.1 kstailey 593: }