[BACK]Return to aucat.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / aucat

Annotation of src/usr.bin/aucat/aucat.c, Revision 1.107

1.107   ! ratchov     1: /*     $OpenBSD: aucat.c,v 1.106 2010/10/21 18:57:42 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.15      ratchov    35: #include "aparams.h"
                     36: #include "aproc.h"
1.62      ratchov    37: #include "conf.h"
                     38: #include "dev.h"
1.28      ratchov    39: #include "listen.h"
1.61      ratchov    40: #include "midi.h"
                     41: #include "opt.h"
1.62      ratchov    42: #include "wav.h"
1.78      ratchov    43: #ifdef DEBUG
                     44: #include "dbg.h"
                     45: #endif
1.11      jaredy     46:
1.86      ratchov    47: /*
                     48:  * unprivileged user name
                     49:  */
                     50: #define SNDIO_USER     "_sndio"
                     51:
                     52: /*
                     53:  * priority when run as root
                     54:  */
                     55: #define SNDIO_PRIO     (-20)
                     56:
1.61      ratchov    57: #define PROG_AUCAT     "aucat"
                     58: #define PROG_MIDICAT   "midicat"
                     59:
1.78      ratchov    60: #ifdef DEBUG
                     61: int debug_level = 0;
                     62: #endif
1.28      ratchov    63: volatile int quit_flag = 0;
1.7       deraadt    64:
1.28      ratchov    65: /*
                     66:  * SIGINT handler, it raises the quit flag. If the flag is already set,
                     67:  * that means that the last SIGINT was not handled, because the process
1.62      ratchov    68:  * is blocked somewhere, so exit.
1.28      ratchov    69:  */
                     70: void
                     71: sigint(int s)
                     72: {
                     73:        if (quit_flag)
                     74:                _exit(1);
                     75:        quit_flag = 1;
                     76: }
1.22      ratchov    77:
1.78      ratchov    78: #ifdef DEBUG
                     79: /*
                     80:  * Increase debug level on SIGUSR1.
                     81:  */
                     82: void
                     83: sigusr1(int s)
                     84: {
                     85:        if (debug_level < 4)
                     86:                debug_level++;
                     87: }
                     88:
                     89: /*
                     90:  * Decrease debug level on SIGUSR2.
                     91:  */
                     92: void
                     93: sigusr2(int s)
                     94: {
                     95:        if (debug_level > 0)
                     96:                debug_level--;
                     97: }
                     98: #endif
1.15      ratchov    99:
                    100: void
                    101: opt_ch(struct aparams *par)
                    102: {
1.76      ratchov   103:        char *next, *end;
                    104:        long cmin, cmax;
1.13      uwe       105:
1.76      ratchov   106:        errno = 0;
                    107:        cmin = strtol(optarg, &next, 10);
                    108:        if (next == optarg || *next != ':')
                    109:                goto failed;
                    110:        cmax = strtol(++next, &end, 10);
                    111:        if (end == next || *end != '\0')
                    112:                goto failed;
                    113:        if (cmin < 0 || cmax < cmin || cmax > NCHAN_MAX)
                    114:                goto failed;
                    115:        par->cmin = cmin;
                    116:        par->cmax = cmax;
                    117:        return;
                    118: failed:
                    119:        errx(1, "%s: bad channel range", optarg);
1.15      ratchov   120: }
1.13      uwe       121:
1.15      ratchov   122: void
                    123: opt_enc(struct aparams *par)
                    124: {
1.28      ratchov   125:        int len;
                    126:
                    127:        len = aparams_strtoenc(par, optarg);
                    128:        if (len == 0 || optarg[len] != '\0')
                    129:                errx(1, "%s: bad encoding", optarg);
1.15      ratchov   130: }
1.4       millert   131:
1.15      ratchov   132: int
                    133: opt_hdr(void)
                    134: {
                    135:        if (strcmp("auto", optarg) == 0)
                    136:                return HDR_AUTO;
                    137:        if (strcmp("raw", optarg) == 0)
                    138:                return HDR_RAW;
                    139:        if (strcmp("wav", optarg) == 0)
                    140:                return HDR_WAV;
1.35      ratchov   141:        errx(1, "%s: bad header specification", optarg);
1.1       kstailey  142: }
                    143:
1.22      ratchov   144: int
1.74      ratchov   145: opt_mmc(void)
                    146: {
                    147:        if (strcmp("off", optarg) == 0)
                    148:                return 0;
                    149:        if (strcmp("slave", optarg) == 0)
                    150:                return 1;
                    151:        errx(1, "%s: bad MMC mode", optarg);
                    152: }
                    153:
                    154: int
1.90      ratchov   155: opt_onoff(void)
1.84      ratchov   156: {
                    157:        if (strcmp("off", optarg) == 0)
                    158:                return 0;
                    159:        if (strcmp("on", optarg) == 0)
                    160:                return 1;
                    161:        errx(1, "%s: bad join/expand setting", optarg);
                    162: }
                    163:
                    164: int
1.22      ratchov   165: opt_xrun(void)
                    166: {
                    167:        if (strcmp("ignore", optarg) == 0)
                    168:                return XRUN_IGNORE;
                    169:        if (strcmp("sync", optarg) == 0)
                    170:                return XRUN_SYNC;
                    171:        if (strcmp("error", optarg) == 0)
                    172:                return XRUN_ERROR;
1.73      ratchov   173:        errx(1, "%s: bad underrun/overrun policy", optarg);
1.22      ratchov   174: }
                    175:
1.83      ratchov   176: unsigned
1.43      ratchov   177: opt_mode(void)
                    178: {
1.83      ratchov   179:        unsigned mode = 0;
                    180:        char *p = optarg;
                    181:        size_t len;
                    182:
1.104     ratchov   183:        for (p = optarg; *p != '\0'; p++) {
1.83      ratchov   184:                len = strcspn(p, ",");
                    185:                if (strncmp("play", p, len) == 0) {
                    186:                        mode |= MODE_PLAY;
                    187:                } else if (strncmp("rec", p, len) == 0) {
                    188:                        mode |= MODE_REC;
                    189:                } else if (strncmp("mon", p, len) == 0) {
                    190:                        mode |= MODE_MON;
                    191:                } else if (strncmp("duplex", p, len) == 0) {
                    192:                        /* XXX: backward compat, remove this */
                    193:                        mode |= MODE_REC | MODE_PLAY;
                    194:                } else
                    195:                        errx(1, "%s: bad mode", optarg);
                    196:                p += len;
                    197:                if (*p == '\0')
                    198:                        break;
                    199:        }
                    200:        if (mode == 0)
                    201:                errx(1, "empty mode");
                    202:        return mode;
1.43      ratchov   203: }
                    204:
1.13      uwe       205: /*
1.92      ratchov   206:  * stream configuration
                    207:  */
                    208: struct cfstr {
                    209:        SLIST_ENTRY(cfstr) entry;
                    210:        unsigned mode;                  /* bitmap of MODE_XXX */
                    211:        struct aparams ipar;            /* input (read) parameters */
                    212:        struct aparams opar;            /* output (write) parameters */
                    213:        unsigned vol;                   /* last requested volume */
                    214:        int hdr;                        /* header format */
                    215:        int xrun;                       /* overrun/underrun policy */
                    216:        int mmc;                        /* MMC mode */
                    217:        int join;                       /* join/expand enabled */
                    218:        char *path;                     /* static path (no need to copy it) */
                    219: };
                    220:
                    221: SLIST_HEAD(cfstrlist, cfstr);
                    222:
                    223: /*
                    224:  * midi device (control stream)
1.13      uwe       225:  */
1.92      ratchov   226: struct cfmid {
                    227:        SLIST_ENTRY(cfmid) entry;
                    228:        char *path;                     /* static path (no need to copy it) */
1.15      ratchov   229: };
1.13      uwe       230:
1.92      ratchov   231: SLIST_HEAD(cfmidlist, cfmid);
1.13      uwe       232:
1.15      ratchov   233: /*
1.92      ratchov   234:  * audio device configuration
1.15      ratchov   235:  */
1.92      ratchov   236: struct cfdev {
                    237:        SLIST_ENTRY(cfdev) entry;
                    238:        struct cfstrlist ins;           /* files to play */
                    239:        struct cfstrlist outs;          /* files to record */
                    240:        struct cfstrlist opts;          /* subdevices to expose */
                    241:        struct cfmidlist mids;          /* midi ports to subscribe */
                    242:        struct aparams ipar;            /* input (read) parameters */
                    243:        struct aparams opar;            /* output (write) parameters */
1.93      ratchov   244:        unsigned hold;                  /* open immediately */
1.92      ratchov   245:        unsigned bufsz;                 /* par.bufsz for sio device */
                    246:        unsigned round;                 /* par.round for sio device */
                    247:        unsigned mode;                  /* bitmap of MODE_XXX */
                    248:        char *path;                     /* static path (no need to copy it) */
                    249: };
                    250:
                    251: SLIST_HEAD(cfdevlist, cfdev);
                    252:
1.15      ratchov   253: void
1.92      ratchov   254: cfdev_add(struct cfdevlist *list, struct cfdev *templ, char *path)
                    255: {
                    256:        struct cfdev *cd;
                    257:
                    258:        cd = malloc(sizeof(struct cfdev));
                    259:        if (cd == NULL) {
                    260:                perror("malloc");
                    261:                abort();
                    262:        }
                    263:        *cd = *templ;
                    264:        cd->path = path;
                    265:        SLIST_INSERT_HEAD(list, cd, entry);
                    266:        SLIST_INIT(&templ->ins);
                    267:        SLIST_INIT(&templ->outs);
                    268:        SLIST_INIT(&templ->opts);
                    269:        SLIST_INIT(&templ->mids);
                    270: }
                    271:
                    272: void
                    273: cfstr_add(struct cfstrlist *list, struct cfstr *templ, char *path)
                    274: {
                    275:        size_t len;
                    276:        struct cfstr *cs;
                    277:        unsigned hdr;
                    278:
1.103     ratchov   279:        if (templ->hdr == HDR_AUTO) {
1.92      ratchov   280:                len = strlen(path);
                    281:                if (len >= 4 && strcasecmp(path + len - 4, ".wav") == 0)
                    282:                        hdr = HDR_WAV;
                    283:                else
                    284:                        hdr = HDR_RAW;
1.52      ratchov   285:        } else
1.92      ratchov   286:                hdr = templ->hdr;
                    287:        cs = malloc(sizeof(struct cfstr));
                    288:        if (cs == NULL) {
                    289:                perror("malloc");
                    290:                abort();
                    291:        }
                    292:        *cs = *templ;
                    293:        cs->path = path;
                    294:        cs->hdr = hdr;
                    295:        SLIST_INSERT_HEAD(list, cs, entry);
                    296: }
                    297:
                    298: void
                    299: cfmid_add(struct cfmidlist *list, char *path)
                    300: {
                    301:        struct cfmid *cm;
                    302:
                    303:        cm = malloc(sizeof(struct cfmid));
                    304:        if (cm == NULL) {
                    305:                perror("malloc");
                    306:                abort();
                    307:        }
                    308:        cm->path = path;
                    309:        SLIST_INSERT_HEAD(list, cm, entry);
1.15      ratchov   310: }
1.13      uwe       311:
1.61      ratchov   312: void
                    313: setsig(void)
                    314: {
                    315:        struct sigaction sa;
                    316:
                    317:        quit_flag = 0;
                    318:        sigfillset(&sa.sa_mask);
                    319:        sa.sa_flags = SA_RESTART;
                    320:        sa.sa_handler = sigint;
                    321:        if (sigaction(SIGINT, &sa, NULL) < 0)
1.68      ratchov   322:                err(1, "sigaction(int) failed");
1.61      ratchov   323:        if (sigaction(SIGTERM, &sa, NULL) < 0)
1.68      ratchov   324:                err(1, "sigaction(term) failed");
1.61      ratchov   325:        if (sigaction(SIGHUP, &sa, NULL) < 0)
1.68      ratchov   326:                err(1, "sigaction(hup) failed");
1.78      ratchov   327: #ifdef DEBUG
                    328:        sa.sa_handler = sigusr1;
                    329:        if (sigaction(SIGUSR1, &sa, NULL) < 0)
                    330:                err(1, "sigaction(usr1) failed");
                    331:        sa.sa_handler = sigusr2;
                    332:        if (sigaction(SIGUSR2, &sa, NULL) < 0)
                    333:                err(1, "sigaction(usr2) failed1n");
                    334: #endif
1.61      ratchov   335: }
                    336:
                    337: void
                    338: unsetsig(void)
                    339: {
                    340:        struct sigaction sa;
                    341:
                    342:        sigfillset(&sa.sa_mask);
                    343:        sa.sa_flags = SA_RESTART;
                    344:        sa.sa_handler = SIG_DFL;
1.78      ratchov   345: #ifdef DEBUG
                    346:        if (sigaction(SIGUSR2, &sa, NULL) < 0)
                    347:                err(1, "unsetsig(usr2): sigaction failed");
                    348:        if (sigaction(SIGUSR1, &sa, NULL) < 0)
                    349:                err(1, "unsetsig(usr1): sigaction failed");
                    350: #endif
1.61      ratchov   351:        if (sigaction(SIGHUP, &sa, NULL) < 0)
1.68      ratchov   352:                err(1, "unsetsig(hup): sigaction failed\n");
1.61      ratchov   353:        if (sigaction(SIGTERM, &sa, NULL) < 0)
1.68      ratchov   354:                err(1, "unsetsig(term): sigaction failed\n");
1.61      ratchov   355:        if (sigaction(SIGINT, &sa, NULL) < 0)
1.68      ratchov   356:                err(1, "unsetsig(int): sigaction failed\n");
1.61      ratchov   357: }
                    358:
                    359: void
                    360: getbasepath(char *base, size_t size)
                    361: {
                    362:        uid_t uid;
                    363:        struct stat sb;
1.86      ratchov   364:        mode_t mask;
1.61      ratchov   365:
                    366:        uid = geteuid();
1.86      ratchov   367:        if (uid == 0) {
                    368:                mask = 022;
                    369:                snprintf(base, PATH_MAX, "/tmp/aucat");
                    370:        } else {
                    371:                mask = 077;
                    372:                snprintf(base, PATH_MAX, "/tmp/aucat-%u", uid);
                    373:        }
                    374:        if (mkdir(base, 0777 & ~mask) < 0) {
1.61      ratchov   375:                if (errno != EEXIST)
                    376:                        err(1, "mkdir(\"%s\")", base);
                    377:        }
                    378:        if (stat(base, &sb) < 0)
                    379:                err(1, "stat(\"%s\")", base);
1.86      ratchov   380:        if (sb.st_uid != uid || (sb.st_mode & mask) != 0)
1.61      ratchov   381:                errx(1, "%s has wrong permissions", base);
                    382: }
                    383:
                    384: void
1.86      ratchov   385: privdrop(void)
                    386: {
                    387:        struct passwd *pw;
                    388:        struct stat sb;
                    389:
                    390:        if ((pw = getpwnam(SNDIO_USER)) == NULL)
1.105     deraadt   391:                errx(1, "unknown user %s", SNDIO_USER);
1.86      ratchov   392:        if (stat(pw->pw_dir, &sb) < 0)
                    393:                err(1, "stat(\"%s\")", pw->pw_dir);
                    394:        if (sb.st_uid != 0 || (sb.st_mode & 022) != 0)
                    395:                errx(1, "%s has wrong permissions", pw->pw_dir);
                    396:        if (setpriority(PRIO_PROCESS, 0, SNDIO_PRIO) < 0)
                    397:                err(1, "setpriority");
                    398:        if (setgroups(1, &pw->pw_gid) ||
                    399:            setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
                    400:            setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
                    401:                err(1, "cannot drop privileges");
                    402: }
                    403:
                    404: void
1.61      ratchov   405: aucat_usage(void)
                    406: {
1.92      ratchov   407:        (void)fputs("usage: " PROG_AUCAT " [-dlnu] [-a flag] [-b nframes] "
1.83      ratchov   408:            "[-C min:max] [-c min:max] [-e enc]\n\t"
1.84      ratchov   409:            "[-f device] [-h fmt] [-i file] [-j flag] [-m mode]"
1.83      ratchov   410:            "[-o file] [-q device]\n\t"
                    411:            "[-r rate] [-s name] [-t mode] [-U unit] "
                    412:            "[-v volume] [-x policy]\n\t"
                    413:            "[-z nframes]\n",
1.61      ratchov   414:            stderr);
                    415: }
                    416:
1.1       kstailey  417: int
1.61      ratchov   418: aucat_main(int argc, char **argv)
1.1       kstailey  419: {
1.92      ratchov   420:        struct cfdevlist cfdevs;
                    421:        struct cfmid *cm;
                    422:        struct cfstr *cs;
                    423:        struct cfdev *cd;
                    424:        struct listen *listen = NULL;
                    425:        int c, u_flag, d_flag, l_flag, n_flag, unit;
                    426:        char base[PATH_MAX], path[PATH_MAX];
                    427:        unsigned mode, rate;
1.76      ratchov   428:        const char *str;
1.102     ratchov   429:        int autostart;
1.92      ratchov   430:        struct dev *d, *dnext;
                    431:        unsigned active;
1.98      ratchov   432:        unsigned nsock, nfile;
1.19      ratchov   433:
1.92      ratchov   434:        /*
                    435:         * global options defaults
                    436:         */
                    437:        unit = -1;
1.26      ratchov   438:        u_flag = 0;
1.69      ratchov   439:        d_flag = 0;
1.28      ratchov   440:        l_flag = 0;
1.51      ratchov   441:        n_flag = 0;
1.92      ratchov   442:        SLIST_INIT(&cfdevs);
1.98      ratchov   443:        nfile = nsock = 0;
1.92      ratchov   444:
                    445:        /*
                    446:         * default stream params
                    447:         */
                    448:        cs = malloc(sizeof(struct cfstr));
                    449:        if (cs == NULL) {
                    450:                perror("malloc");
                    451:                exit(1);
                    452:        }
                    453:        aparams_init(&cs->ipar, 0, 1, 44100);
                    454:        aparams_init(&cs->opar, 0, 1, 44100);
                    455:        cs->mmc = 0;
                    456:        cs->hdr = HDR_AUTO;
                    457:        cs->xrun = XRUN_IGNORE;
                    458:        cs->vol = MIDI_MAXCTL;
                    459:        cs->mode = MODE_PLAY | MODE_REC;
                    460:        cs->join = 1;
                    461:
                    462:        /*
                    463:         * default device
                    464:         */
                    465:        cd = malloc(sizeof(struct cfdev));
                    466:        if (cd == NULL) {
                    467:                perror("malloc");
                    468:                exit(1);
                    469:        }
                    470:        aparams_init(&cd->ipar, 0, 1, 44100);
                    471:        aparams_init(&cd->opar, 0, 1, 44100);
                    472:        SLIST_INIT(&cd->ins);
                    473:        SLIST_INIT(&cd->outs);
                    474:        SLIST_INIT(&cd->opts);
                    475:        SLIST_INIT(&cd->mids);
                    476:        cd->path = NULL;
                    477:        cd->bufsz = 0;
                    478:        cd->round = 0;
                    479:        cd->hold = 1;
1.15      ratchov   480:
1.92      ratchov   481:        while ((c = getopt(argc, argv, "a:dnb:c:C:e:r:h:x:v:i:o:f:m:luq:s:U:t:j:z:")) != -1) {
1.15      ratchov   482:                switch (c) {
1.69      ratchov   483:                case 'd':
1.78      ratchov   484: #ifdef DEBUG
                    485:                        if (d_flag)
                    486:                                debug_level++;
                    487: #endif
1.69      ratchov   488:                        d_flag = 1;
                    489:                        break;
1.51      ratchov   490:                case 'n':
                    491:                        n_flag = 1;
                    492:                        break;
1.92      ratchov   493:                case 'u':
                    494:                        u_flag = 1;
                    495:                        break;
                    496:                case 'U':
                    497:                        unit = strtonum(optarg, 0, MIDI_MAXCTL, &str);
                    498:                        if (str)
                    499:                                errx(1, "%s: unit number is %s", optarg, str);
                    500:                        break;
1.43      ratchov   501:                case 'm':
1.92      ratchov   502:                        cs->mode = opt_mode();
                    503:                        cd->mode = cs->mode;
1.43      ratchov   504:                        break;
1.15      ratchov   505:                case 'h':
1.92      ratchov   506:                        cs->hdr = opt_hdr();
1.15      ratchov   507:                        break;
1.22      ratchov   508:                case 'x':
1.92      ratchov   509:                        cs->xrun = opt_xrun();
1.22      ratchov   510:                        break;
1.84      ratchov   511:                case 'j':
1.92      ratchov   512:                        cs->join = opt_onoff();
1.84      ratchov   513:                        break;
1.74      ratchov   514:                case 't':
1.92      ratchov   515:                        cs->mmc = opt_mmc();
1.74      ratchov   516:                        break;
1.15      ratchov   517:                case 'c':
1.92      ratchov   518:                        opt_ch(&cs->ipar);
                    519:                        cd->opar.cmin = cs->ipar.cmin;
                    520:                        cd->opar.cmax = cs->ipar.cmax;
1.15      ratchov   521:                        break;
                    522:                case 'C':
1.92      ratchov   523:                        opt_ch(&cs->opar);
                    524:                        cd->ipar.cmin = cs->opar.cmin;
                    525:                        cd->ipar.cmax = cs->opar.cmax;
1.15      ratchov   526:                        break;
                    527:                case 'e':
1.92      ratchov   528:                        opt_enc(&cs->ipar);
                    529:                        aparams_copyenc(&cs->opar, &cs->ipar);
1.15      ratchov   530:                        break;
                    531:                case 'r':
1.92      ratchov   532:                        rate = strtonum(optarg, RATE_MIN, RATE_MAX, &str);
1.76      ratchov   533:                        if (str)
                    534:                                errx(1, "%s: rate is %s", optarg, str);
1.92      ratchov   535:                        cs->opar.rate = cs->ipar.rate = rate;
                    536:                        cd->ipar.rate = cd->opar.rate = rate;
1.15      ratchov   537:                        break;
1.35      ratchov   538:                case 'v':
1.92      ratchov   539:                        cs->vol = strtonum(optarg, 0, MIDI_MAXCTL, &str);
1.76      ratchov   540:                        if (str)
                    541:                                errx(1, "%s: volume is %s", optarg, str);
1.35      ratchov   542:                        break;
1.15      ratchov   543:                case 'i':
1.92      ratchov   544:                        cfstr_add(&cd->ins, cs, optarg);
1.98      ratchov   545:                        nfile++;
1.15      ratchov   546:                        break;
                    547:                case 'o':
1.92      ratchov   548:                        cfstr_add(&cd->outs, cs, optarg);
1.98      ratchov   549:                        nfile++;
1.42      ratchov   550:                        break;
                    551:                case 's':
1.92      ratchov   552:                        cfstr_add(&cd->opts, cs, optarg);
1.98      ratchov   553:                        nsock++;
1.92      ratchov   554:                        break;
                    555:                case 'a':
                    556:                        cd->hold = opt_onoff();
1.83      ratchov   557:                        break;
                    558:                case 'q':
1.92      ratchov   559:                        cfmid_add(&cd->mids, optarg);
1.4       millert   560:                        break;
1.28      ratchov   561:                case 'b':
1.92      ratchov   562:                        cd->bufsz = strtonum(optarg, 1, RATE_MAX * 5, &str);
1.76      ratchov   563:                        if (str)
                    564:                                errx(1, "%s: buffer size is %s", optarg, str);
1.28      ratchov   565:                        break;
1.74      ratchov   566:                case 'z':
1.92      ratchov   567:                        cd->round = strtonum(optarg, 1, SHRT_MAX, &str);
1.76      ratchov   568:                        if (str)
                    569:                                errx(1, "%s: block size is %s", optarg, str);
1.74      ratchov   570:                        break;
1.92      ratchov   571:                case 'f':
1.98      ratchov   572:                        if (SLIST_EMPTY(&cd->opts) &&
                    573:                            SLIST_EMPTY(&cd->ins) &&
                    574:                            SLIST_EMPTY(&cd->outs)) {
                    575:                                cfstr_add(&cd->opts, cs, DEFAULT_OPT);
                    576:                                nsock++;
                    577:                        }
1.92      ratchov   578:                        cfdev_add(&cfdevs, cd, optarg);
                    579:                        break;
                    580:                case 'l':
                    581:                        l_flag = 1;
                    582:                        autostart = 0;
                    583:                        break;
1.11      jaredy    584:                default:
1.61      ratchov   585:                        aucat_usage();
1.15      ratchov   586:                        exit(1);
1.4       millert   587:                }
                    588:        }
                    589:        argc -= optind;
                    590:        argv += optind;
                    591:
1.92      ratchov   592: #ifdef DEBUG
                    593:        if (debug_level == 0)
                    594:                debug_level = 1;
                    595: #endif
                    596:        if (argc > 0) {
1.102     ratchov   597:                aucat_usage();
                    598:                exit(1);
1.15      ratchov   599:        }
                    600:
1.98      ratchov   601:        /*
                    602:         * Check constraints specific to -n option
                    603:         */
1.51      ratchov   604:        if (n_flag) {
1.98      ratchov   605:                if (!SLIST_EMPTY(&cfdevs) ||
                    606:                    !SLIST_EMPTY(&cd->mids) ||
                    607:                    !SLIST_EMPTY(&cd->opts))
                    608:                        errx(1, "-f, -s, and -q not allowed in loopback mode");
1.92      ratchov   609:                if (SLIST_EMPTY(&cd->ins) || SLIST_EMPTY(&cd->outs))
1.98      ratchov   610:                        errx(1, "-i and -o are required in loopback mode");
1.51      ratchov   611:        }
1.15      ratchov   612:
1.46      ratchov   613:        /*
1.98      ratchov   614:         * If there's no device specified, do as if the default
                    615:         * device is specified as last argument.
1.92      ratchov   616:         */
                    617:        if (SLIST_EMPTY(&cfdevs)) {
1.98      ratchov   618:                if (SLIST_EMPTY(&cd->opts) &&
                    619:                    SLIST_EMPTY(&cd->ins) &&
                    620:                    SLIST_EMPTY(&cd->outs)) {
                    621:                        cfstr_add(&cd->opts, cs, DEFAULT_OPT);
                    622:                        nsock++;
                    623:                }
1.92      ratchov   624:                if (!cd->hold)
1.98      ratchov   625:                        errx(1, "-a off not compatible with default device");
1.92      ratchov   626:                cfdev_add(&cfdevs, cd, "default");
                    627:        }
1.98      ratchov   628:        if ((cs = SLIST_FIRST(&cd->opts)) ||
                    629:            (cs = SLIST_FIRST(&cd->ins)) ||
                    630:            (cs = SLIST_FIRST(&cd->outs)))
                    631:                errx(1, "%s: no device to attach the stream to", cs->path);
1.46      ratchov   632:
1.83      ratchov   633:        /*
                    634:         * Check modes and calculate "best" device parameters. Iterate over all
                    635:         * inputs and outputs and find the maximum sample rate and channel
                    636:         * number.
                    637:         */
1.92      ratchov   638:        SLIST_FOREACH(cd, &cfdevs, entry) {
                    639:                mode = 0;
                    640:                SLIST_FOREACH(cs, &cd->ins, entry) {
                    641:                        if (cs->mode == 0)
                    642:                                errx(1, "%s: not in play mode", cs->path);
                    643:                        mode |= (cs->mode & MODE_PLAY);
                    644:                        if (!u_flag)
                    645:                                aparams_grow(&cd->opar, &cs->ipar);
                    646:                }
                    647:                SLIST_FOREACH(cs, &cd->outs, entry) {
                    648:                        if (cs->mode == 0)
                    649:                                errx(1, "%s: not in rec/mon mode", cs->path);
                    650:                        if ((cs->mode & MODE_REC) && (cs->mode & MODE_MON))
                    651:                                errx(1, "%s: can't rec and mon", cs->path);
                    652:                        mode |= (cs->mode & MODE_RECMASK);
                    653:                        if (!u_flag)
                    654:                                aparams_grow(&cd->ipar, &cs->opar);
                    655:                }
                    656:                SLIST_FOREACH(cs, &cd->opts, entry) {
                    657:                        if ((cs->mode & MODE_REC) && (cs->mode & MODE_MON))
                    658:                                errx(1, "%s: can't rec and mon", cs->path);
                    659:                        mode |= (cs->mode & (MODE_RECMASK | MODE_PLAY));
                    660:                        if (!u_flag) {
                    661:                                aparams_grow(&cd->opar, &cs->ipar);
                    662:                                aparams_grow(&cd->ipar, &cs->opar);
                    663:                        }
                    664:                }
                    665:                if ((mode & MODE_MON) && !(mode & MODE_PLAY))
                    666:                        errx(1, "no playback stream to monitor");
1.98      ratchov   667:                if (n_flag && (mode & MODE_MON))
                    668:                        errx(1, "-m mon not allowed in loopback mode");
1.92      ratchov   669:                rate = (mode & MODE_REC) ? cd->ipar.rate : cd->opar.rate;
                    670:                if (!cd->round)
                    671:                        cd->round = rate / 15;
                    672:                if (!cd->bufsz)
                    673:                        cd->bufsz = rate / 15 * 4;
                    674:                cd->mode = mode;
1.42      ratchov   675:        }
1.98      ratchov   676:        if (nsock > 0) {
1.61      ratchov   677:                getbasepath(base, sizeof(base));
                    678:                if (unit < 0)
                    679:                        unit = 0;
1.55      ratchov   680:        }
1.61      ratchov   681:        setsig();
1.28      ratchov   682:        filelist_init();
1.51      ratchov   683:
1.15      ratchov   684:        /*
1.92      ratchov   685:         * Open devices
1.15      ratchov   686:         */
1.92      ratchov   687:        while (!SLIST_EMPTY(&cfdevs)) {
                    688:                cd = SLIST_FIRST(&cfdevs);
                    689:                SLIST_REMOVE_HEAD(&cfdevs, entry);
                    690:
                    691:                if (n_flag) {
                    692:                        d = dev_new_loop(&cd->ipar, &cd->opar, cd->bufsz);
                    693:                } else {
1.106     ratchov   694:                        d = dev_new_sio(cd->path, cd->mode | MODE_MIDIMASK,
1.92      ratchov   695:                            &cd->ipar, &cd->opar, cd->bufsz, cd->round,
1.94      ratchov   696:                            cd->hold);
1.92      ratchov   697:                }
                    698:                if (d == NULL)
                    699:                        errx(1, "%s: can't open device", cd->path);
                    700:
                    701:                /*
                    702:                 * register midi devices
                    703:                 */
                    704:                while (!SLIST_EMPTY(&cd->mids)) {
                    705:                        cm = SLIST_FIRST(&cd->mids);
                    706:                        SLIST_REMOVE_HEAD(&cd->mids, entry);
                    707:                        if (!dev_thruadd(d, cm->path, 1, 1))
                    708:                                errx(1, "%s: can't open device", cm->path);
                    709:                        free(cm);
                    710:                }
1.52      ratchov   711:
1.92      ratchov   712:                /*
                    713:                 * register files
                    714:                 */
                    715:                autostart = 0;
                    716:                while (!SLIST_EMPTY(&cd->ins)) {
                    717:                        cs = SLIST_FIRST(&cd->ins);
                    718:                        SLIST_REMOVE_HEAD(&cd->ins, entry);
                    719:                        if (!cs->mmc)
                    720:                                autostart = 1;
1.103     ratchov   721:                        if (strcmp(cs->path, "-") == 0)
                    722:                                cs->path = NULL;
1.92      ratchov   723:                        if (!wav_new_in(&wav_ops, d, cs->mode & MODE_PLAY,
                    724:                                cs->path, cs->hdr, &cs->ipar, cs->xrun,
                    725:                                cs->vol, cs->mmc, cs->join))
                    726:                                exit(1);
                    727:                        free(cs);
                    728:                }
                    729:                while (!SLIST_EMPTY(&cd->outs)) {
                    730:                        cs = SLIST_FIRST(&cd->outs);
                    731:                        SLIST_REMOVE_HEAD(&cd->outs, entry);
                    732:                        if (!cs->mmc)
                    733:                                autostart = 1;
1.103     ratchov   734:                        if (strcmp(cs->path, "-") == 0)
                    735:                                cs->path = NULL;
1.92      ratchov   736:                        if (!wav_new_out(&wav_ops, d, cs->mode & MODE_RECMASK,
                    737:                                cs->path, cs->hdr, &cs->opar, cs->xrun,
                    738:                                cs->mmc, cs->join))
                    739:                                exit(1);
                    740:                        free(cs);
                    741:                }
                    742:                while (!SLIST_EMPTY(&cd->opts)) {
                    743:                        cs = SLIST_FIRST(&cd->opts);
                    744:                        SLIST_REMOVE_HEAD(&cd->opts, entry);
                    745:                        opt_new(cs->path, d, &cs->opar, &cs->ipar,
                    746:                            MIDI_TO_ADATA(cs->vol), cs->mmc,
1.106     ratchov   747:                            cs->join, cs->mode | MODE_MIDIMASK);
1.92      ratchov   748:                        free(cs);
                    749:                }
                    750:                free(cd);
                    751:                if (autostart) {
                    752:                        /*
                    753:                         * inject artificial mmc start
                    754:                         */
                    755:                        ctl_start(d->midi);
                    756:                }
1.56      ratchov   757:        }
1.98      ratchov   758:        if (nsock > 0) {
1.61      ratchov   759:                snprintf(path, sizeof(path), "%s/%s%u", base,
                    760:                    DEFAULT_SOFTAUDIO, unit);
1.92      ratchov   761:                listen = listen_new(&listen_ops, path);
1.98      ratchov   762:                if (listen == NULL)
1.92      ratchov   763:                        exit(1);
1.98      ratchov   764:        }
                    765:        if (geteuid() == 0)
                    766:                privdrop();
                    767:        if (l_flag) {
1.107   ! ratchov   768: #ifdef DEBUG
1.98      ratchov   769:                debug_level = 0;
                    770:                dbg_flush();
1.107   ! ratchov   771: #endif
1.98      ratchov   772:                if (daemon(0, 0) < 0)
1.56      ratchov   773:                        err(1, "daemon");
1.15      ratchov   774:        }
1.13      uwe       775:
1.15      ratchov   776:        /*
1.62      ratchov   777:         * Loop, start audio.
1.15      ratchov   778:         */
1.28      ratchov   779:        for (;;) {
1.90      ratchov   780:                if (quit_flag)
1.28      ratchov   781:                        break;
1.92      ratchov   782:                active = 0;
                    783:                for (d = dev_list; d != NULL; d = dnext) {
                    784:                        dnext = d->next;
                    785:                        if (!dev_run(d))
                    786:                                goto fatal;
1.97      jakemsr   787:                        if (d->pstate != DEV_CLOSED && !ctl_idle(d->midi))
1.92      ratchov   788:                                active = 1;
                    789:                }
                    790:                if (dev_list == NULL)
1.50      ratchov   791:                        break;
1.98      ratchov   792:                if (nsock == 0 && !active)
1.83      ratchov   793:                        break;
1.50      ratchov   794:                if (!file_poll())
                    795:                        break;
1.34      ratchov   796:        }
1.92      ratchov   797:   fatal:
1.98      ratchov   798:        if (nsock > 0)
1.92      ratchov   799:                file_close(&listen->file);
1.90      ratchov   800:        /*
                    801:         * give a chance to drain
                    802:         */
1.96      ratchov   803:        for (d = dev_list; d != NULL; d = d->next)
                    804:                dev_drain(d);
1.90      ratchov   805:        while (file_poll())
                    806:                ; /* nothing */
1.96      ratchov   807:
                    808:        while (dev_list)
                    809:                dev_del(dev_list);
1.83      ratchov   810:        filelist_done();
1.98      ratchov   811:        if (nsock > 0) {
1.86      ratchov   812:                if (rmdir(base) < 0 && errno != ENOTEMPTY && errno != EPERM)
1.55      ratchov   813:                        warn("rmdir(\"%s\")", base);
                    814:        }
1.61      ratchov   815:        unsetsig();
                    816:        return 0;
                    817: }
                    818:
                    819: void
                    820: midicat_usage(void)
                    821: {
1.83      ratchov   822:        (void)fputs("usage: " PROG_MIDICAT " [-dl] "
1.99      jmc       823:            "[-i file] [-o file] [-q port] [-s name] [-U unit]\n",
1.61      ratchov   824:            stderr);
                    825: }
1.92      ratchov   826:
1.61      ratchov   827: int
                    828: midicat_main(int argc, char **argv)
                    829: {
1.98      ratchov   830:        struct cfdevlist cfdevs;
1.92      ratchov   831:        struct cfmid *cm;
1.98      ratchov   832:        struct cfstr *cs;
                    833:        struct cfdev *cd;
1.92      ratchov   834:        struct listen *listen = NULL;
1.69      ratchov   835:        int c, d_flag, l_flag, unit, fd;
1.61      ratchov   836:        char base[PATH_MAX], path[PATH_MAX];
1.65      ratchov   837:        struct file *stdx;
1.63      ratchov   838:        struct aproc *p;
1.61      ratchov   839:        struct abuf *buf;
1.76      ratchov   840:        const char *str;
1.98      ratchov   841:        struct dev *d, *dnext;
                    842:        unsigned nsock;
1.61      ratchov   843:
1.92      ratchov   844:        /*
                    845:         * global options defaults
                    846:         */
                    847:        unit = -1;
1.69      ratchov   848:        d_flag = 0;
1.61      ratchov   849:        l_flag = 0;
1.98      ratchov   850:        SLIST_INIT(&cfdevs);
                    851:        nsock = 0;
                    852:
                    853:        /*
                    854:         * default stream params
                    855:         */
                    856:        cs = malloc(sizeof(struct cfstr));
                    857:        if (cs == NULL) {
                    858:                perror("malloc");
                    859:                exit(1);
                    860:        }
                    861:        cs->hdr = HDR_RAW;
                    862:
                    863:        /*
                    864:         * default device
                    865:         */
                    866:        cd = malloc(sizeof(struct cfdev));
                    867:        if (cd == NULL) {
                    868:                perror("malloc");
                    869:                exit(1);
                    870:        }
                    871:        SLIST_INIT(&cd->ins);
                    872:        SLIST_INIT(&cd->outs);
                    873:        SLIST_INIT(&cd->opts);
                    874:        SLIST_INIT(&cd->mids);
                    875:        cd->path = NULL;
                    876:
1.61      ratchov   877:
1.98      ratchov   878:        while ((c = getopt(argc, argv, "di:o:ls:q:U:")) != -1) {
1.61      ratchov   879:                switch (c) {
1.69      ratchov   880:                case 'd':
1.78      ratchov   881: #ifdef DEBUG
                    882:                        if (d_flag)
                    883:                                debug_level++;
                    884: #endif
1.69      ratchov   885:                        d_flag = 1;
                    886:                        break;
1.61      ratchov   887:                case 'i':
1.98      ratchov   888:                        cfstr_add(&cd->ins, cs, optarg);
1.61      ratchov   889:                        break;
                    890:                case 'o':
1.98      ratchov   891:                        cfstr_add(&cd->outs, cs, optarg);
1.61      ratchov   892:                        break;
1.83      ratchov   893:                case 'q':
1.98      ratchov   894:                        cfmid_add(&cd->mids, optarg);
                    895:                        break;
                    896:                case 's':
                    897:                        cfstr_add(&cd->opts, cs, optarg);
                    898:                        cfdev_add(&cfdevs, cd, optarg);
                    899:                        nsock++;
1.61      ratchov   900:                        break;
                    901:                case 'l':
                    902:                        l_flag = 1;
                    903:                        break;
                    904:                case 'U':
1.76      ratchov   905:                        unit = strtonum(optarg, 0, MIDI_MAXCTL, &str);
                    906:                        if (str)
1.92      ratchov   907:                                errx(1, "%s: unit number is %s", optarg, str);
1.61      ratchov   908:                        break;
                    909:                default:
                    910:                        midicat_usage();
                    911:                        exit(1);
                    912:                }
                    913:        }
                    914:        argc -= optind;
                    915:        argv += optind;
                    916:
1.98      ratchov   917: #ifdef DEBUG
                    918:        if (debug_level == 0)
                    919:                debug_level = 1;
                    920: #endif
                    921:        if (argc > 0) {
1.61      ratchov   922:                midicat_usage();
                    923:                exit(1);
                    924:        }
1.98      ratchov   925:
                    926:        /*
                    927:         * If there's no device specified (-s), then create one with
                    928:         * reasonable defaults:
                    929:         *
                    930:         *  - if there are no streams (-ioq) defined, assume server mode
                    931:         *    and expose the "defaut" option
                    932:         *
                    933:         *  - if there are files (-io) but no ports (-q) to send/receive
                    934:         *    from, add the default sndio(7) MIDI port
                    935:         */
                    936:        if (SLIST_EMPTY(&cfdevs)) {
                    937:                if (SLIST_EMPTY(&cd->mids)) {
1.100     ratchov   938:                        if (!SLIST_EMPTY(&cd->ins) || !SLIST_EMPTY(&cd->outs))
1.98      ratchov   939:                                cfmid_add(&cd->mids, "default");
                    940:                        else {
                    941:                                cfstr_add(&cd->opts, cs, DEFAULT_OPT);
                    942:                                nsock++;
                    943:                        }
                    944:                }
                    945:                cfdev_add(&cfdevs, cd, "default");
                    946:        }
                    947:        if (nsock > 0) {
1.61      ratchov   948:                getbasepath(base, sizeof(path));
                    949:                if (unit < 0)
                    950:                        unit = 0;
                    951:        }
                    952:        setsig();
                    953:        filelist_init();
                    954:
1.98      ratchov   955:        while (!SLIST_EMPTY(&cfdevs)) {
                    956:                cd = SLIST_FIRST(&cfdevs);
                    957:                SLIST_REMOVE_HEAD(&cfdevs, entry);
                    958:
                    959:                d = dev_new_thru();
                    960:                if (d == NULL)
                    961:                        errx(1, "%s: can't open device", cd->path);
                    962:                if (!dev_ref(d))
                    963:                        errx(1, "couldn't open midi thru box");
1.101     ratchov   964:                if (SLIST_EMPTY(&cd->opts) && APROC_OK(d->midi))
1.98      ratchov   965:                        d->midi->flags |= APROC_QUIT;
                    966:
                    967:                /*
                    968:                 * register midi ports
                    969:                 */
                    970:                while (!SLIST_EMPTY(&cd->mids)) {
                    971:                        cm = SLIST_FIRST(&cd->mids);
                    972:                        SLIST_REMOVE_HEAD(&cd->mids, entry);
                    973:                        if (!dev_thruadd(d, cm->path, 1, 1))
                    974:                                errx(1, "%s: can't open device", cm->path);
                    975:                        free(cm);
                    976:                }
                    977:
                    978:                /*
                    979:                 * register files
                    980:                 */
                    981:                while (!SLIST_EMPTY(&cd->ins)) {
                    982:                        cs = SLIST_FIRST(&cd->ins);
                    983:                        SLIST_REMOVE_HEAD(&cd->ins, entry);
                    984:                        if (strcmp(cs->path, "-") == 0) {
                    985:                                fd = STDIN_FILENO;
                    986:                                if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
                    987:                                        warn("stdin");
                    988:                        } else {
                    989:                                fd = open(cs->path, O_RDONLY | O_NONBLOCK, 0666);
                    990:                                if (fd < 0)
                    991:                                        err(1, "%s", cs->path);
                    992:                        }
                    993:                        stdx = (struct file *)pipe_new(&pipe_ops, fd, cs->path);
                    994:                        p = rfile_new(stdx);
                    995:                        buf = abuf_new(MIDI_BUFSZ, &aparams_none);
                    996:                        aproc_setout(p, buf);
                    997:                        dev_midiattach(d, buf, NULL);
                    998:                        free(cs);
1.77      ratchov   999:                }
1.98      ratchov  1000:                while (!SLIST_EMPTY(&cd->outs)) {
                   1001:                        cs = SLIST_FIRST(&cd->outs);
                   1002:                        SLIST_REMOVE_HEAD(&cd->outs, entry);
                   1003:                        if (strcmp(cs->path, "-") == 0) {
                   1004:                                fd = STDOUT_FILENO;
                   1005:                                if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
                   1006:                                        warn("stdout");
                   1007:                        } else {
                   1008:                                fd = open(cs->path,
                   1009:                                    O_WRONLY | O_TRUNC | O_CREAT | O_NONBLOCK, 0666);
                   1010:                                if (fd < 0)
                   1011:                                        err(1, "%s", cs->path);
                   1012:                        }
                   1013:                        stdx = (struct file *)pipe_new(&pipe_ops, fd, cs->path);
                   1014:                        p = wfile_new(stdx);
                   1015:                        buf = abuf_new(MIDI_BUFSZ, &aparams_none);
                   1016:                        aproc_setin(p, buf);
                   1017:                        dev_midiattach(d, NULL, buf);
                   1018:                        free(cs);
                   1019:                }
                   1020:                while (!SLIST_EMPTY(&cd->opts)) {
                   1021:                        cs = SLIST_FIRST(&cd->opts);
                   1022:                        SLIST_REMOVE_HEAD(&cd->opts, entry);
1.106     ratchov  1023:                        opt_new(cs->path, d, NULL, NULL, 0, 0, 0, MODE_MIDIMASK);
1.98      ratchov  1024:                        free(cs);
                   1025:                }
                   1026:                free(cd);
1.63      ratchov  1027:        }
1.98      ratchov  1028:        if (nsock > 0) {
1.61      ratchov  1029:                snprintf(path, sizeof(path), "%s/%s%u", base,
                   1030:                    DEFAULT_MIDITHRU, unit);
1.92      ratchov  1031:                listen = listen_new(&listen_ops, path);
1.98      ratchov  1032:                if (listen == NULL)
                   1033:                        exit(1);
                   1034:        }
                   1035:        if (geteuid() == 0)
                   1036:                privdrop();
                   1037:        if (l_flag) {
1.107   ! ratchov  1038: #ifdef DEBUG
1.98      ratchov  1039:                debug_level = 0;
                   1040:                dbg_flush();
1.107   ! ratchov  1041: #endif
1.98      ratchov  1042:                if (daemon(0, 0) < 0)
1.61      ratchov  1043:                        err(1, "daemon");
                   1044:        }
1.98      ratchov  1045:
1.61      ratchov  1046:        /*
                   1047:         * loop, start processing
                   1048:         */
                   1049:        for (;;) {
1.90      ratchov  1050:                if (quit_flag)
                   1051:                        break;
1.98      ratchov  1052:                for (d = dev_list; d != NULL; d = dnext) {
                   1053:                        dnext = d->next;
                   1054:                        if (!dev_run(d))
                   1055:                                goto fatal;
                   1056:                }
1.61      ratchov  1057:                if (!file_poll())
                   1058:                        break;
                   1059:        }
1.98      ratchov  1060:   fatal:
                   1061:        if (nsock > 0)
1.92      ratchov  1062:                file_close(&listen->file);
1.90      ratchov  1063:        /*
1.98      ratchov  1064:         * give a chance to drain
1.90      ratchov  1065:         */
1.98      ratchov  1066:        for (d = dev_list; d != NULL; d = d->next)
                   1067:                dev_drain(d);
1.90      ratchov  1068:        while (file_poll())
                   1069:                ; /* nothing */
1.98      ratchov  1070:
                   1071:        while (dev_list)
                   1072:                dev_del(dev_list);
1.83      ratchov  1073:        filelist_done();
1.98      ratchov  1074:        if (nsock > 0) {
1.86      ratchov  1075:                if (rmdir(base) < 0 && errno != ENOTEMPTY && errno != EPERM)
1.61      ratchov  1076:                        warn("rmdir(\"%s\")", base);
                   1077:        }
                   1078:        unsetsig();
1.15      ratchov  1079:        return 0;
1.61      ratchov  1080: }
                   1081:
                   1082: int
                   1083: main(int argc, char **argv)
                   1084: {
                   1085:        char *prog;
                   1086:
1.90      ratchov  1087: #ifdef DEBUG
                   1088:        atexit(dbg_flush);
                   1089: #endif
1.61      ratchov  1090:        prog = strrchr(argv[0], '/');
                   1091:        if (prog == NULL)
                   1092:                prog = argv[0];
                   1093:        else
                   1094:                prog++;
                   1095:        if (strcmp(prog, PROG_AUCAT) == 0) {
                   1096:                return aucat_main(argc, argv);
                   1097:        } else if (strcmp(prog, PROG_MIDICAT) == 0) {
                   1098:                return midicat_main(argc, argv);
                   1099:        } else {
                   1100:                fprintf(stderr, "%s: can't determine program to run\n", prog);
                   1101:        }
                   1102:        return 1;
1.1       kstailey 1103: }