[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.103

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