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

Annotation of src/usr.bin/sndiod/sndiod.c, Revision 1.49

1.49    ! ratchov     1: /*     $OpenBSD: sndiod.c,v 1.48 2022/03/07 08:58:33 ratchov Exp $     */
1.1       ratchov     2: /*
                      3:  * Copyright (c) 2008-2012 Alexandre Ratchov <alex@caoua.org>
                      4:  *
                      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/stat.h>
                     18: #include <sys/types.h>
                     19: #include <sys/resource.h>
1.18      ratchov    20: #include <sys/socket.h>
1.1       ratchov    21:
                     22: #include <err.h>
                     23: #include <errno.h>
                     24: #include <fcntl.h>
                     25: #include <grp.h>
                     26: #include <limits.h>
                     27: #include <pwd.h>
                     28: #include <signal.h>
                     29: #include <sndio.h>
                     30: #include <stdio.h>
                     31: #include <stdlib.h>
                     32: #include <string.h>
                     33: #include <unistd.h>
                     34:
                     35: #include "amsg.h"
                     36: #include "defs.h"
                     37: #include "dev.h"
1.18      ratchov    38: #include "fdpass.h"
1.1       ratchov    39: #include "file.h"
                     40: #include "listen.h"
                     41: #include "midi.h"
                     42: #include "opt.h"
                     43: #include "sock.h"
                     44: #include "utils.h"
                     45:
                     46: /*
                     47:  * unprivileged user name
                     48:  */
                     49: #ifndef SNDIO_USER
                     50: #define SNDIO_USER     "_sndio"
                     51: #endif
                     52:
                     53: /*
1.18      ratchov    54:  * privileged user name
                     55:  */
                     56: #ifndef SNDIO_PRIV_USER
                     57: #define SNDIO_PRIV_USER        "_sndiop"
                     58: #endif
                     59:
                     60: /*
1.1       ratchov    61:  * priority when run as root
                     62:  */
                     63: #ifndef SNDIO_PRIO
                     64: #define SNDIO_PRIO     (-20)
                     65: #endif
                     66:
                     67: /*
                     68:  * sample rate if no ``-r'' is used
                     69:  */
                     70: #ifndef DEFAULT_RATE
                     71: #define DEFAULT_RATE   48000
                     72: #endif
                     73:
                     74: /*
                     75:  * block size if neither ``-z'' nor ``-b'' is used
                     76:  */
                     77: #ifndef DEFAULT_ROUND
1.37      ratchov    78: #define DEFAULT_ROUND  480
1.1       ratchov    79: #endif
                     80:
                     81: /*
                     82:  * buffer size if neither ``-z'' nor ``-b'' is used
                     83:  */
                     84: #ifndef DEFAULT_BUFSZ
1.8       dcoppa     85: #define DEFAULT_BUFSZ  7680
1.1       ratchov    86: #endif
                     87:
1.48      ratchov    88: /*
                     89:  * default device precision
                     90:  */
                     91: #ifndef DEFAULT_BITS
                     92: #define DEFAULT_BITS   16
                     93: #endif
                     94:
1.5       ratchov    95: void sigint(int);
1.36      ratchov    96: void sighup(int);
1.5       ratchov    97: void opt_ch(int *, int *);
                     98: void opt_enc(struct aparams *);
                     99: int opt_mmc(void);
                    100: int opt_onoff(void);
                    101: int getword(char *, char **);
                    102: unsigned int opt_mode(void);
1.31      ratchov   103: void getbasepath(char *);
1.5       ratchov   104: void setsig(void);
                    105: void unsetsig(void);
                    106: struct dev *mkdev(char *, struct aparams *,
                    107:     int, int, int, int, int, int);
1.27      ratchov   108: struct port *mkport(char *, int);
1.5       ratchov   109: struct opt *mkopt(char *, struct dev *,
                    110:     int, int, int, int, int, int, int, int);
1.1       ratchov   111:
                    112: unsigned int log_level = 0;
1.36      ratchov   113: volatile sig_atomic_t quit_flag = 0, reopen_flag = 0;
1.1       ratchov   114:
                    115: char usagestr[] = "usage: sndiod [-d] [-a flag] [-b nframes] "
1.36      ratchov   116:     "[-C min:max] [-c min:max]\n\t"
                    117:     "[-e enc] [-F device] [-f device] [-j flag] [-L addr] [-m mode]\n\t"
                    118:     "[-Q port] [-q port] [-r rate] [-s name] [-t mode] [-U unit]\n\t"
                    119:     "[-v volume] [-w flag] [-z nframes]\n";
1.1       ratchov   120:
                    121: /*
1.40      ratchov   122:  * default audio devices
                    123:  */
                    124: static char *default_devs[] = {
                    125:        "rsnd/0", "rsnd/1", "rsnd/2", "rsnd/3",
                    126:        NULL
                    127: };
                    128:
                    129: /*
1.39      ratchov   130:  * default MIDI ports
                    131:  */
                    132: static char *default_ports[] = {
                    133:        "rmidi/0", "rmidi/1", "rmidi/2", "rmidi/3",
                    134:        "rmidi/4", "rmidi/5", "rmidi/6", "rmidi/7",
                    135:        NULL
                    136: };
                    137:
                    138: /*
1.1       ratchov   139:  * SIGINT handler, it raises the quit flag. If the flag is already set,
                    140:  * that means that the last SIGINT was not handled, because the process
                    141:  * is blocked somewhere, so exit.
                    142:  */
                    143: void
                    144: sigint(int s)
                    145: {
                    146:        if (quit_flag)
                    147:                _exit(1);
                    148:        quit_flag = 1;
                    149: }
                    150:
1.36      ratchov   151: /*
                    152:  * SIGHUP handler, it raises the reopen flag, which requests devices
                    153:  * to be reopened.
                    154:  */
                    155: void
                    156: sighup(int s)
                    157: {
                    158:        reopen_flag = 1;
                    159: }
                    160:
1.1       ratchov   161: void
                    162: opt_ch(int *rcmin, int *rcmax)
                    163: {
                    164:        char *next, *end;
                    165:        long cmin, cmax;
                    166:
                    167:        errno = 0;
                    168:        cmin = strtol(optarg, &next, 10);
                    169:        if (next == optarg || *next != ':')
                    170:                goto failed;
                    171:        cmax = strtol(++next, &end, 10);
                    172:        if (end == next || *end != '\0')
                    173:                goto failed;
                    174:        if (cmin < 0 || cmax < cmin || cmax >= NCHAN_MAX)
                    175:                goto failed;
                    176:        *rcmin = cmin;
                    177:        *rcmax = cmax;
                    178:        return;
                    179: failed:
                    180:        errx(1, "%s: bad channel range", optarg);
                    181: }
                    182:
                    183: void
                    184: opt_enc(struct aparams *par)
                    185: {
                    186:        int len;
                    187:
                    188:        len = aparams_strtoenc(par, optarg);
                    189:        if (len == 0 || optarg[len] != '\0')
                    190:                errx(1, "%s: bad encoding", optarg);
                    191: }
                    192:
                    193: int
                    194: opt_mmc(void)
                    195: {
                    196:        if (strcmp("off", optarg) == 0)
                    197:                return 0;
                    198:        if (strcmp("slave", optarg) == 0)
                    199:                return 1;
                    200:        errx(1, "%s: off/slave expected", optarg);
                    201: }
                    202:
                    203: int
                    204: opt_onoff(void)
                    205: {
                    206:        if (strcmp("off", optarg) == 0)
                    207:                return 0;
                    208:        if (strcmp("on", optarg) == 0)
                    209:                return 1;
                    210:        errx(1, "%s: on/off expected", optarg);
                    211: }
                    212:
1.4       ratchov   213: int
                    214: getword(char *word, char **str)
                    215: {
                    216:        char *p = *str;
                    217:
                    218:        for (;;) {
                    219:                if (*word == '\0')
                    220:                        break;
                    221:                if (*word++ != *p++)
                    222:                        return 0;
                    223:        }
                    224:        if (*p == ',' || *p == '\0') {
                    225:                *str = p;
                    226:                return 1;
                    227:        }
                    228:        return 0;
                    229: }
                    230:
1.1       ratchov   231: unsigned int
                    232: opt_mode(void)
                    233: {
                    234:        unsigned int mode = 0;
                    235:        char *p = optarg;
                    236:
1.4       ratchov   237:        for (;;) {
                    238:                if (getword("play", &p)) {
1.1       ratchov   239:                        mode |= MODE_PLAY;
1.4       ratchov   240:                } else if (getword("rec", &p)) {
1.1       ratchov   241:                        mode |= MODE_REC;
1.4       ratchov   242:                } else if (getword("mon", &p)) {
1.1       ratchov   243:                        mode |= MODE_MON;
1.4       ratchov   244:                } else if (getword("midi", &p)) {
1.1       ratchov   245:                        mode |= MODE_MIDIMASK;
1.4       ratchov   246:                } else
1.1       ratchov   247:                        errx(1, "%s: bad mode", optarg);
                    248:                if (*p == '\0')
                    249:                        break;
1.4       ratchov   250:                p++;
1.1       ratchov   251:        }
                    252:        if (mode == 0)
                    253:                errx(1, "empty mode");
                    254:        return mode;
                    255: }
                    256:
1.49    ! ratchov   257: /*
        !           258:  * Open all devices. Possibly switch to the new devices if they have higher
        !           259:  * priorities than the current ones.
        !           260:  */
        !           261: static void
        !           262: reopen_devs(void)
        !           263: {
        !           264:        struct opt *o;
        !           265:        struct dev *d, *a;
        !           266:
        !           267:        for (o = opt_list; o != NULL; o = o->next) {
        !           268:
        !           269:                /* skip unused logical devices and ones with fixed hardware */
        !           270:                if (o->refcnt == 0 || strcmp(o->name, o->dev->name) == 0)
        !           271:                        continue;
        !           272:
        !           273:                /* circulate to the device with the highest prio */
        !           274:                a = o->alt_first;
        !           275:                for (d = a; d->alt_next != a; d = d->alt_next) {
        !           276:                        if (d->num > o->alt_first->num)
        !           277:                                o->alt_first = d;
        !           278:                }
        !           279:
        !           280:                /* switch to the first working one, in pririty order */
        !           281:                d = o->alt_first;
        !           282:                while (d != o->dev) {
        !           283:                        if (opt_setdev(o, d))
        !           284:                                break;
        !           285:                        d = d->alt_next;
        !           286:                }
        !           287:        }
        !           288:
        !           289:        /*
        !           290:         * retry to open the remaining devices that are not used but need
        !           291:         * to stay open (ex. '-a on')
        !           292:         */
        !           293:        for (d = dev_list; d != NULL; d = d->next) {
        !           294:                if (d->refcnt > 0 && d->pstate == DEV_CFG)
        !           295:                        dev_open(d);
        !           296:        }
        !           297: }
        !           298:
        !           299: /*
        !           300:  * For each port, open the alt with the highest priority and switch to it
        !           301:  */
        !           302: static void
        !           303: reopen_ports(void)
        !           304: {
        !           305:        struct port *p, *a, *apri;
        !           306:        int inuse;
        !           307:
        !           308:        for (p = port_list; p != NULL; p = a->next) {
        !           309:
        !           310:                /* skip unused ports */
        !           311:                inuse = 0;
        !           312:                a = p;
        !           313:                while (1) {
        !           314:                        if (midi_rxmask(a->midi) || a->midi->txmask)
        !           315:                                inuse = 1;
        !           316:                        if (a->alt_next == p)
        !           317:                                break;
        !           318:                        a = a->alt_next;
        !           319:                }
        !           320:                if (!inuse)
        !           321:                        continue;
        !           322:
        !           323:                /* open the alt with the highest prio */
        !           324:                apri = port_alt_ref(p->num);
        !           325:
        !           326:                /* switch to it */
        !           327:                a = p;
        !           328:                while (1) {
        !           329:                        if (a != apri) {
        !           330:                                midi_migrate(a->midi, apri->midi);
        !           331:                                port_unref(a);
        !           332:                        }
        !           333:                        if (a->alt_next == p)
        !           334:                                break;
        !           335:                        a = a->alt_next;
        !           336:                }
        !           337:        }
        !           338: }
        !           339:
1.1       ratchov   340: void
                    341: setsig(void)
                    342: {
                    343:        struct sigaction sa;
                    344:
                    345:        quit_flag = 0;
1.36      ratchov   346:        reopen_flag = 0;
1.1       ratchov   347:        sigfillset(&sa.sa_mask);
                    348:        sa.sa_flags = SA_RESTART;
                    349:        sa.sa_handler = sigint;
1.35      ratchov   350:        if (sigaction(SIGINT, &sa, NULL) == -1)
1.1       ratchov   351:                err(1, "sigaction(int) failed");
1.35      ratchov   352:        if (sigaction(SIGTERM, &sa, NULL) == -1)
1.1       ratchov   353:                err(1, "sigaction(term) failed");
1.36      ratchov   354:        sa.sa_handler = sighup;
1.35      ratchov   355:        if (sigaction(SIGHUP, &sa, NULL) == -1)
1.1       ratchov   356:                err(1, "sigaction(hup) failed");
                    357: }
                    358:
                    359: void
                    360: unsetsig(void)
                    361: {
                    362:        struct sigaction sa;
                    363:
                    364:        sigfillset(&sa.sa_mask);
                    365:        sa.sa_flags = SA_RESTART;
                    366:        sa.sa_handler = SIG_DFL;
1.35      ratchov   367:        if (sigaction(SIGHUP, &sa, NULL) == -1)
1.29      ratchov   368:                err(1, "unsetsig(hup): sigaction failed");
1.35      ratchov   369:        if (sigaction(SIGTERM, &sa, NULL) == -1)
1.29      ratchov   370:                err(1, "unsetsig(term): sigaction failed");
1.35      ratchov   371:        if (sigaction(SIGINT, &sa, NULL) == -1)
1.29      ratchov   372:                err(1, "unsetsig(int): sigaction failed");
1.1       ratchov   373: }
                    374:
                    375: void
1.31      ratchov   376: getbasepath(char *base)
1.1       ratchov   377: {
                    378:        uid_t uid;
                    379:        struct stat sb;
1.14      ratchov   380:        mode_t mask, omask;
1.1       ratchov   381:
                    382:        uid = geteuid();
                    383:        if (uid == 0) {
                    384:                mask = 022;
1.10      ratchov   385:                snprintf(base, SOCKPATH_MAX, SOCKPATH_DIR);
1.1       ratchov   386:        } else {
                    387:                mask = 077;
1.10      ratchov   388:                snprintf(base, SOCKPATH_MAX, SOCKPATH_DIR "-%u", uid);
1.1       ratchov   389:        }
1.14      ratchov   390:        omask = umask(mask);
1.35      ratchov   391:        if (mkdir(base, 0777) == -1) {
1.1       ratchov   392:                if (errno != EEXIST)
                    393:                        err(1, "mkdir(\"%s\")", base);
                    394:        }
1.28      ratchov   395:        umask(omask);
1.35      ratchov   396:        if (stat(base, &sb) == -1)
1.1       ratchov   397:                err(1, "stat(\"%s\")", base);
1.30      ratchov   398:        if (!S_ISDIR(sb.st_mode))
                    399:                errx(1, "%s is not a directory", base);
1.1       ratchov   400:        if (sb.st_uid != uid || (sb.st_mode & mask) != 0)
                    401:                errx(1, "%s has wrong permissions", base);
                    402: }
                    403:
                    404: struct dev *
                    405: mkdev(char *path, struct aparams *par,
                    406:     int mode, int bufsz, int round, int rate, int hold, int autovol)
                    407: {
                    408:        struct dev *d;
                    409:
                    410:        for (d = dev_list; d != NULL; d = d->next) {
1.47      ratchov   411:                if (strcmp(d->path, path) == 0)
1.1       ratchov   412:                        return d;
                    413:        }
                    414:        if (!bufsz && !round) {
                    415:                round = DEFAULT_ROUND;
                    416:                bufsz = DEFAULT_BUFSZ;
                    417:        } else if (!bufsz) {
                    418:                bufsz = round * 2;
                    419:        } else if (!round)
                    420:                round = bufsz / 2;
                    421:        d = dev_new(path, par, mode, bufsz, round, rate, hold, autovol);
                    422:        if (d == NULL)
                    423:                exit(1);
                    424:        return d;
                    425: }
                    426:
1.27      ratchov   427: struct port *
                    428: mkport(char *path, int hold)
                    429: {
                    430:        struct port *c;
                    431:
                    432:        for (c = port_list; c != NULL; c = c->next) {
1.47      ratchov   433:                if (strcmp(c->path, path) == 0)
1.27      ratchov   434:                        return c;
                    435:        }
                    436:        c = port_new(path, MODE_MIDIMASK, hold);
                    437:        if (c == NULL)
                    438:                exit(1);
                    439:        return c;
                    440: }
                    441:
1.1       ratchov   442: struct opt *
                    443: mkopt(char *path, struct dev *d,
                    444:     int pmin, int pmax, int rmin, int rmax,
                    445:     int mode, int vol, int mmc, int dup)
                    446: {
                    447:        struct opt *o;
                    448:
1.33      ratchov   449:        o = opt_new(d, path, pmin, pmax, rmin, rmax,
1.1       ratchov   450:            MIDI_TO_ADATA(vol), mmc, dup, mode);
                    451:        if (o == NULL)
1.26      ratchov   452:                return NULL;
1.31      ratchov   453:        dev_adjpar(d, o->mode, o->pmax, o->rmax);
1.1       ratchov   454:        return o;
                    455: }
                    456:
1.34      ratchov   457: static void
                    458: dounveil(char *name, char *prefix, char *path_prefix)
                    459: {
                    460:        size_t prefix_len;
                    461:        char path[PATH_MAX];
                    462:
                    463:        prefix_len = strlen(prefix);
                    464:
                    465:        if (strncmp(name, prefix, prefix_len) != 0)
                    466:                errx(1, "%s: unsupported device or port format", name);
                    467:        snprintf(path, sizeof(path), "%s%s", path_prefix, name + prefix_len);
1.35      ratchov   468:        if (unveil(path, "rw") == -1)
1.46      beck      469:                err(1, "unveil %s", path);
1.34      ratchov   470: }
                    471:
1.32      ratchov   472: static int
                    473: start_helper(int background)
                    474: {
1.34      ratchov   475:        struct dev *d;
                    476:        struct port *p;
1.32      ratchov   477:        struct passwd *pw;
                    478:        int s[2];
                    479:        pid_t pid;
                    480:
                    481:        if (geteuid() == 0) {
                    482:                if ((pw = getpwnam(SNDIO_PRIV_USER)) == NULL)
                    483:                        errx(1, "unknown user %s", SNDIO_PRIV_USER);
                    484:        } else
                    485:                pw = NULL;
1.35      ratchov   486:        if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == -1) {
1.32      ratchov   487:                perror("socketpair");
                    488:                return 0;
                    489:        }
                    490:        pid = fork();
                    491:        if (pid == -1) {
                    492:                log_puts("can't fork\n");
                    493:                return 0;
                    494:        }
                    495:        if (pid == 0) {
                    496:                setproctitle("helper");
                    497:                close(s[0]);
                    498:                if (fdpass_new(s[1], &helper_fileops) == NULL)
                    499:                        return 0;
                    500:                if (background) {
                    501:                        log_flush();
                    502:                        log_level = 0;
1.35      ratchov   503:                        if (daemon(0, 0) == -1)
1.32      ratchov   504:                                err(1, "daemon");
                    505:                }
                    506:                if (pw != NULL) {
                    507:                        if (setgroups(1, &pw->pw_gid) ||
                    508:                            setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
                    509:                            setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
                    510:                                err(1, "cannot drop privileges");
                    511:                }
1.36      ratchov   512:                for (d = dev_list; d != NULL; d = d->next) {
1.47      ratchov   513:                        dounveil(d->path, "rsnd/", "/dev/audio");
                    514:                        dounveil(d->path, "rsnd/", "/dev/audioctl");
1.36      ratchov   515:                }
                    516:                for (p = port_list; p != NULL; p = p->next) {
1.47      ratchov   517:                        dounveil(p->path, "rmidi/", "/dev/rmidi");
1.36      ratchov   518:                }
1.35      ratchov   519:                if (pledge("stdio sendfd rpath wpath", NULL) == -1)
1.32      ratchov   520:                        err(1, "pledge");
                    521:                while (file_poll())
                    522:                        ; /* nothing */
                    523:                exit(0);
                    524:        } else {
                    525:                close(s[1]);
                    526:                if (fdpass_new(s[0], &worker_fileops) == NULL)
                    527:                        return 0;
                    528:        }
                    529:        return 1;
                    530: }
                    531:
                    532: static void
                    533: stop_helper(void)
                    534: {
                    535:        if (fdpass_peer)
                    536:                fdpass_close(fdpass_peer);
                    537: }
                    538:
1.1       ratchov   539: int
                    540: main(int argc, char **argv)
                    541: {
1.45      ratchov   542:        int c, i, background, unit;
1.1       ratchov   543:        int pmin, pmax, rmin, rmax;
1.25      ratchov   544:        char base[SOCKPATH_MAX], path[SOCKPATH_MAX];
1.1       ratchov   545:        unsigned int mode, dup, mmc, vol;
                    546:        unsigned int hold, autovol, bufsz, round, rate;
                    547:        const char *str;
                    548:        struct aparams par;
1.47      ratchov   549:        struct opt *o;
                    550:        struct dev *d, *dev_first, *dev_next;
                    551:        struct port *p, *port_first, *port_next;
1.1       ratchov   552:        struct listen *l;
1.17      ratchov   553:        struct passwd *pw;
1.25      ratchov   554:        struct tcpaddr {
                    555:                char *host;
                    556:                struct tcpaddr *next;
                    557:        } *tcpaddr_list, *ta;
1.1       ratchov   558:
                    559:        atexit(log_flush);
                    560:
                    561:        /*
                    562:         * global options defaults
                    563:         */
1.44      jcs       564:        vol = 127;
1.1       ratchov   565:        dup = 1;
                    566:        mmc = 0;
                    567:        hold = 0;
1.44      jcs       568:        autovol = 0;
1.1       ratchov   569:        bufsz = 0;
                    570:        round = 0;
                    571:        rate = DEFAULT_RATE;
                    572:        unit = 0;
                    573:        background = 1;
                    574:        pmin = 0;
                    575:        pmax = 1;
                    576:        rmin = 0;
                    577:        rmax = 1;
1.48      ratchov   578:        par.bits = DEFAULT_BITS;
                    579:        par.bps = APARAMS_BPS(par.bits);
                    580:        par.le = ADATA_LE;
                    581:        par.sig = 1;
                    582:        par.msb = 0;
1.1       ratchov   583:        mode = MODE_PLAY | MODE_REC;
1.47      ratchov   584:        dev_first = dev_next = NULL;
                    585:        port_first = port_next = NULL;
1.25      ratchov   586:        tcpaddr_list = NULL;
1.45      ratchov   587:        d = NULL;
                    588:        p = NULL;
1.42      ratchov   589:
                    590:        slot_array_init();
1.1       ratchov   591:
1.36      ratchov   592:        while ((c = getopt(argc, argv,
                    593:            "a:b:c:C:de:F:f:j:L:m:Q:q:r:s:t:U:v:w:x:z:")) != -1) {
1.1       ratchov   594:                switch (c) {
                    595:                case 'd':
                    596:                        log_level++;
                    597:                        background = 0;
                    598:                        break;
                    599:                case 'U':
                    600:                        unit = strtonum(optarg, 0, 15, &str);
                    601:                        if (str)
                    602:                                errx(1, "%s: unit number is %s", optarg, str);
                    603:                        break;
                    604:                case 'L':
1.25      ratchov   605:                        ta = xmalloc(sizeof(struct tcpaddr));
                    606:                        ta->host = optarg;
                    607:                        ta->next = tcpaddr_list;
                    608:                        tcpaddr_list = ta;
1.1       ratchov   609:                        break;
                    610:                case 'm':
                    611:                        mode = opt_mode();
                    612:                        break;
                    613:                case 'j':
                    614:                        dup = opt_onoff();
                    615:                        break;
                    616:                case 't':
                    617:                        mmc = opt_mmc();
                    618:                        break;
                    619:                case 'c':
                    620:                        opt_ch(&pmin, &pmax);
                    621:                        break;
                    622:                case 'C':
                    623:                        opt_ch(&rmin, &rmax);
                    624:                        break;
                    625:                case 'e':
                    626:                        opt_enc(&par);
                    627:                        break;
                    628:                case 'r':
                    629:                        rate = strtonum(optarg, RATE_MIN, RATE_MAX, &str);
                    630:                        if (str)
                    631:                                errx(1, "%s: rate is %s", optarg, str);
                    632:                        break;
                    633:                case 'v':
                    634:                        vol = strtonum(optarg, 0, MIDI_MAXCTL, &str);
                    635:                        if (str)
                    636:                                errx(1, "%s: volume is %s", optarg, str);
                    637:                        break;
                    638:                case 's':
1.45      ratchov   639:                        if (d == NULL) {
                    640:                                for (i = 0; default_devs[i] != NULL; i++) {
                    641:                                        mkdev(default_devs[i], &par, 0,
                    642:                                            bufsz, round, rate, 0, autovol);
                    643:                                }
                    644:                                d = dev_list;
1.1       ratchov   645:                        }
1.26      ratchov   646:                        if (mkopt(optarg, d, pmin, pmax, rmin, rmax,
                    647:                                mode, vol, mmc, dup) == NULL)
                    648:                                return 1;
1.1       ratchov   649:                        break;
                    650:                case 'q':
1.45      ratchov   651:                        p = mkport(optarg, hold);
1.47      ratchov   652:                        /* create new circulate list */
                    653:                        port_first = port_next = p;
1.1       ratchov   654:                        break;
1.36      ratchov   655:                case 'Q':
1.45      ratchov   656:                        if (p == NULL)
1.36      ratchov   657:                                errx(1, "-Q %s: no ports defined", optarg);
1.47      ratchov   658:                        p = mkport(optarg, hold);
                    659:                        /* add to circulate list */
                    660:                        p->alt_next = port_next;
                    661:                        port_first->alt_next = p;
                    662:                        port_next = p;
1.36      ratchov   663:                        break;
1.1       ratchov   664:                case 'a':
                    665:                        hold = opt_onoff();
                    666:                        break;
                    667:                case 'w':
                    668:                        autovol = opt_onoff();
                    669:                        break;
                    670:                case 'b':
                    671:                        bufsz = strtonum(optarg, 1, RATE_MAX, &str);
                    672:                        if (str)
                    673:                                errx(1, "%s: buffer size is %s", optarg, str);
                    674:                        break;
                    675:                case 'z':
                    676:                        round = strtonum(optarg, 1, SHRT_MAX, &str);
                    677:                        if (str)
                    678:                                errx(1, "%s: block size is %s", optarg, str);
                    679:                        break;
                    680:                case 'f':
1.45      ratchov   681:                        d = mkdev(optarg, &par, 0, bufsz, round,
1.28      ratchov   682:                            rate, hold, autovol);
1.47      ratchov   683:                        /* create new circulate list */
                    684:                        dev_first = dev_next = d;
1.1       ratchov   685:                        break;
1.36      ratchov   686:                case 'F':
1.45      ratchov   687:                        if (d == NULL)
1.36      ratchov   688:                                errx(1, "-F %s: no devices defined", optarg);
1.47      ratchov   689:                        d = mkdev(optarg, &par, 0, bufsz, round,
                    690:                            rate, hold, autovol);
                    691:                        /* add to circulate list */
                    692:                        d->alt_next = dev_next;
                    693:                        dev_first->alt_next = d;
                    694:                        dev_next = d;
1.36      ratchov   695:                        break;
1.1       ratchov   696:                default:
                    697:                        fputs(usagestr, stderr);
                    698:                        return 1;
                    699:                }
                    700:        }
                    701:        argc -= optind;
                    702:        argv += optind;
                    703:        if (argc > 0) {
                    704:                fputs(usagestr, stderr);
                    705:                return 1;
1.39      ratchov   706:        }
                    707:        if (port_list == NULL) {
                    708:                for (i = 0; default_ports[i] != NULL; i++)
                    709:                        mkport(default_ports[i], 0);
1.1       ratchov   710:        }
1.45      ratchov   711:        if (dev_list == NULL) {
                    712:                for (i = 0; default_devs[i] != NULL; i++) {
1.40      ratchov   713:                        mkdev(default_devs[i], &par, 0,
                    714:                            bufsz, round, rate, 0, autovol);
                    715:                }
                    716:        }
1.47      ratchov   717:
                    718:        /*
                    719:         * Add default sub-device (if none) backed by the last device
                    720:         */
                    721:        o = opt_byname("default");
                    722:        if (o == NULL) {
                    723:                o = mkopt("default", dev_list, pmin, pmax, rmin, rmax,
                    724:                    mode, vol, 0, dup);
                    725:                if (o == NULL)
                    726:                        return 1;
                    727:        }
                    728:
                    729:        /*
                    730:         * For each device create an anonymous sub-device using
                    731:         * the "default" sub-device as template
                    732:         */
1.1       ratchov   733:        for (d = dev_list; d != NULL; d = d->next) {
1.47      ratchov   734:                if (opt_new(d, NULL, o->pmin, o->pmax, o->rmin, o->rmax,
                    735:                        o->maxweight, o->mtc != NULL, o->dup, o->mode) == NULL)
1.26      ratchov   736:                        return 1;
1.47      ratchov   737:                dev_adjpar(d, o->mode, o->pmax, o->rmax);
1.1       ratchov   738:        }
1.17      ratchov   739:
                    740:        setsig();
                    741:        filelist_init();
                    742:
1.32      ratchov   743:        if (!start_helper(background))
                    744:                return 1;
                    745:
                    746:        if (geteuid() == 0) {
1.20      ratchov   747:                if ((pw = getpwnam(SNDIO_USER)) == NULL)
                    748:                        errx(1, "unknown user %s", SNDIO_USER);
1.32      ratchov   749:        } else
                    750:                pw = NULL;
                    751:        getbasepath(base);
                    752:        snprintf(path, SOCKPATH_MAX, "%s/" SOCKPATH_FILE "%u", base, unit);
                    753:        if (!listen_new_un(path))
                    754:                return 1;
                    755:        for (ta = tcpaddr_list; ta != NULL; ta = ta->next) {
                    756:                if (!listen_new_tcp(ta->host, AUCAT_PORT + unit))
                    757:                        return 1;
1.20      ratchov   758:        }
1.32      ratchov   759:        for (l = listen_list; l != NULL; l = l->next) {
                    760:                if (!listen_init(l))
                    761:                        return 1;
1.13      ratchov   762:        }
1.32      ratchov   763:        midi_init();
                    764:        for (p = port_list; p != NULL; p = p->next) {
                    765:                if (!port_init(p))
                    766:                        return 1;
1.1       ratchov   767:        }
1.32      ratchov   768:        for (d = dev_list; d != NULL; d = d->next) {
                    769:                if (!dev_init(d))
1.1       ratchov   770:                        return 1;
1.32      ratchov   771:        }
1.47      ratchov   772:        for (o = opt_list; o != NULL; o = o->next)
                    773:                opt_init(o);
1.32      ratchov   774:        if (background) {
                    775:                log_flush();
                    776:                log_level = 0;
1.35      ratchov   777:                if (daemon(0, 0) == -1)
1.32      ratchov   778:                        err(1, "daemon");
                    779:        }
                    780:        if (pw != NULL) {
1.35      ratchov   781:                if (setpriority(PRIO_PROCESS, 0, SNDIO_PRIO) == -1)
1.32      ratchov   782:                        err(1, "setpriority");
1.35      ratchov   783:                if (chroot(pw->pw_dir) == -1 || chdir("/") == -1)
1.32      ratchov   784:                        err(1, "cannot chroot to %s", pw->pw_dir);
1.35      ratchov   785:                if (setgroups(1, &pw->pw_gid) == -1 ||
                    786:                    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1 ||
                    787:                    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1 )
1.32      ratchov   788:                        err(1, "cannot drop privileges");
                    789:        }
                    790:        if (tcpaddr_list) {
                    791:                if (pledge("stdio audio recvfd unix inet", NULL) == -1)
1.22      ratchov   792:                        err(1, "pledge");
1.18      ratchov   793:        } else {
1.32      ratchov   794:                if (pledge("stdio audio recvfd unix", NULL) == -1)
                    795:                        err(1, "pledge");
                    796:        }
1.49    ! ratchov   797:
1.32      ratchov   798:        for (;;) {
                    799:                if (quit_flag)
                    800:                        break;
1.36      ratchov   801:                if (reopen_flag) {
                    802:                        reopen_flag = 0;
1.49    ! ratchov   803:                        reopen_devs();
        !           804:                        reopen_ports();
1.36      ratchov   805:                }
1.32      ratchov   806:                if (!fdpass_peer)
                    807:                        break;
                    808:                if (!file_poll())
                    809:                        break;
                    810:        }
                    811:        stop_helper();
                    812:        while (listen_list != NULL)
                    813:                listen_close(listen_list);
                    814:        while (sock_list != NULL)
                    815:                sock_close(sock_list);
1.47      ratchov   816:        for (o = opt_list; o != NULL; o = o->next)
                    817:                opt_done(o);
1.32      ratchov   818:        for (d = dev_list; d != NULL; d = d->next)
                    819:                dev_done(d);
                    820:        for (p = port_list; p != NULL; p = p->next)
                    821:                port_done(p);
                    822:        while (file_poll())
                    823:                ; /* nothing */
                    824:        midi_done();
1.18      ratchov   825:
1.43      ratchov   826:        while (opt_list)
                    827:                opt_del(opt_list);
1.1       ratchov   828:        while (dev_list)
                    829:                dev_del(dev_list);
                    830:        while (port_list)
                    831:                port_del(port_list);
1.25      ratchov   832:        while (tcpaddr_list) {
                    833:                ta = tcpaddr_list;
                    834:                tcpaddr_list = ta->next;
                    835:                xfree(ta);
                    836:        }
1.1       ratchov   837:        filelist_done();
                    838:        unsetsig();
                    839:        return 0;
                    840: }