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

1.45    ! ratchov     1: /*     $OpenBSD: sndiod.c,v 1.44 2021/02/05 17:59:33 jcs 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.5       ratchov    88: void sigint(int);
1.36      ratchov    89: void sighup(int);
1.5       ratchov    90: void opt_ch(int *, int *);
                     91: void opt_enc(struct aparams *);
                     92: int opt_mmc(void);
                     93: int opt_onoff(void);
                     94: int getword(char *, char **);
                     95: unsigned int opt_mode(void);
1.31      ratchov    96: void getbasepath(char *);
1.5       ratchov    97: void setsig(void);
                     98: void unsetsig(void);
                     99: struct dev *mkdev(char *, struct aparams *,
                    100:     int, int, int, int, int, int);
1.27      ratchov   101: struct port *mkport(char *, int);
1.5       ratchov   102: struct opt *mkopt(char *, struct dev *,
                    103:     int, int, int, int, int, int, int, int);
1.1       ratchov   104:
                    105: unsigned int log_level = 0;
1.36      ratchov   106: volatile sig_atomic_t quit_flag = 0, reopen_flag = 0;
1.1       ratchov   107:
                    108: char usagestr[] = "usage: sndiod [-d] [-a flag] [-b nframes] "
1.36      ratchov   109:     "[-C min:max] [-c min:max]\n\t"
                    110:     "[-e enc] [-F device] [-f device] [-j flag] [-L addr] [-m mode]\n\t"
                    111:     "[-Q port] [-q port] [-r rate] [-s name] [-t mode] [-U unit]\n\t"
                    112:     "[-v volume] [-w flag] [-z nframes]\n";
1.1       ratchov   113:
                    114: /*
1.40      ratchov   115:  * default audio devices
                    116:  */
                    117: static char *default_devs[] = {
                    118:        "rsnd/0", "rsnd/1", "rsnd/2", "rsnd/3",
                    119:        NULL
                    120: };
                    121:
                    122: /*
1.39      ratchov   123:  * default MIDI ports
                    124:  */
                    125: static char *default_ports[] = {
                    126:        "rmidi/0", "rmidi/1", "rmidi/2", "rmidi/3",
                    127:        "rmidi/4", "rmidi/5", "rmidi/6", "rmidi/7",
                    128:        NULL
                    129: };
                    130:
                    131: /*
1.1       ratchov   132:  * SIGINT handler, it raises the quit flag. If the flag is already set,
                    133:  * that means that the last SIGINT was not handled, because the process
                    134:  * is blocked somewhere, so exit.
                    135:  */
                    136: void
                    137: sigint(int s)
                    138: {
                    139:        if (quit_flag)
                    140:                _exit(1);
                    141:        quit_flag = 1;
                    142: }
                    143:
1.36      ratchov   144: /*
                    145:  * SIGHUP handler, it raises the reopen flag, which requests devices
                    146:  * to be reopened.
                    147:  */
                    148: void
                    149: sighup(int s)
                    150: {
                    151:        reopen_flag = 1;
                    152: }
                    153:
1.1       ratchov   154: void
                    155: opt_ch(int *rcmin, int *rcmax)
                    156: {
                    157:        char *next, *end;
                    158:        long cmin, cmax;
                    159:
                    160:        errno = 0;
                    161:        cmin = strtol(optarg, &next, 10);
                    162:        if (next == optarg || *next != ':')
                    163:                goto failed;
                    164:        cmax = strtol(++next, &end, 10);
                    165:        if (end == next || *end != '\0')
                    166:                goto failed;
                    167:        if (cmin < 0 || cmax < cmin || cmax >= NCHAN_MAX)
                    168:                goto failed;
                    169:        *rcmin = cmin;
                    170:        *rcmax = cmax;
                    171:        return;
                    172: failed:
                    173:        errx(1, "%s: bad channel range", optarg);
                    174: }
                    175:
                    176: void
                    177: opt_enc(struct aparams *par)
                    178: {
                    179:        int len;
                    180:
                    181:        len = aparams_strtoenc(par, optarg);
                    182:        if (len == 0 || optarg[len] != '\0')
                    183:                errx(1, "%s: bad encoding", optarg);
                    184: }
                    185:
                    186: int
                    187: opt_mmc(void)
                    188: {
                    189:        if (strcmp("off", optarg) == 0)
                    190:                return 0;
                    191:        if (strcmp("slave", optarg) == 0)
                    192:                return 1;
                    193:        errx(1, "%s: off/slave expected", optarg);
                    194: }
                    195:
                    196: int
                    197: opt_onoff(void)
                    198: {
                    199:        if (strcmp("off", optarg) == 0)
                    200:                return 0;
                    201:        if (strcmp("on", optarg) == 0)
                    202:                return 1;
                    203:        errx(1, "%s: on/off expected", optarg);
                    204: }
                    205:
1.4       ratchov   206: int
                    207: getword(char *word, char **str)
                    208: {
                    209:        char *p = *str;
                    210:
                    211:        for (;;) {
                    212:                if (*word == '\0')
                    213:                        break;
                    214:                if (*word++ != *p++)
                    215:                        return 0;
                    216:        }
                    217:        if (*p == ',' || *p == '\0') {
                    218:                *str = p;
                    219:                return 1;
                    220:        }
                    221:        return 0;
                    222: }
                    223:
1.1       ratchov   224: unsigned int
                    225: opt_mode(void)
                    226: {
                    227:        unsigned int mode = 0;
                    228:        char *p = optarg;
                    229:
1.4       ratchov   230:        for (;;) {
                    231:                if (getword("play", &p)) {
1.1       ratchov   232:                        mode |= MODE_PLAY;
1.4       ratchov   233:                } else if (getword("rec", &p)) {
1.1       ratchov   234:                        mode |= MODE_REC;
1.4       ratchov   235:                } else if (getword("mon", &p)) {
1.1       ratchov   236:                        mode |= MODE_MON;
1.4       ratchov   237:                } else if (getword("midi", &p)) {
1.1       ratchov   238:                        mode |= MODE_MIDIMASK;
1.4       ratchov   239:                } else
1.1       ratchov   240:                        errx(1, "%s: bad mode", optarg);
                    241:                if (*p == '\0')
                    242:                        break;
1.4       ratchov   243:                p++;
1.1       ratchov   244:        }
                    245:        if (mode == 0)
                    246:                errx(1, "empty mode");
                    247:        return mode;
                    248: }
                    249:
                    250: void
                    251: setsig(void)
                    252: {
                    253:        struct sigaction sa;
                    254:
                    255:        quit_flag = 0;
1.36      ratchov   256:        reopen_flag = 0;
1.1       ratchov   257:        sigfillset(&sa.sa_mask);
                    258:        sa.sa_flags = SA_RESTART;
                    259:        sa.sa_handler = sigint;
1.35      ratchov   260:        if (sigaction(SIGINT, &sa, NULL) == -1)
1.1       ratchov   261:                err(1, "sigaction(int) failed");
1.35      ratchov   262:        if (sigaction(SIGTERM, &sa, NULL) == -1)
1.1       ratchov   263:                err(1, "sigaction(term) failed");
1.36      ratchov   264:        sa.sa_handler = sighup;
1.35      ratchov   265:        if (sigaction(SIGHUP, &sa, NULL) == -1)
1.1       ratchov   266:                err(1, "sigaction(hup) failed");
                    267: }
                    268:
                    269: void
                    270: unsetsig(void)
                    271: {
                    272:        struct sigaction sa;
                    273:
                    274:        sigfillset(&sa.sa_mask);
                    275:        sa.sa_flags = SA_RESTART;
                    276:        sa.sa_handler = SIG_DFL;
1.35      ratchov   277:        if (sigaction(SIGHUP, &sa, NULL) == -1)
1.29      ratchov   278:                err(1, "unsetsig(hup): sigaction failed");
1.35      ratchov   279:        if (sigaction(SIGTERM, &sa, NULL) == -1)
1.29      ratchov   280:                err(1, "unsetsig(term): sigaction failed");
1.35      ratchov   281:        if (sigaction(SIGINT, &sa, NULL) == -1)
1.29      ratchov   282:                err(1, "unsetsig(int): sigaction failed");
1.1       ratchov   283: }
                    284:
                    285: void
1.31      ratchov   286: getbasepath(char *base)
1.1       ratchov   287: {
                    288:        uid_t uid;
                    289:        struct stat sb;
1.14      ratchov   290:        mode_t mask, omask;
1.1       ratchov   291:
                    292:        uid = geteuid();
                    293:        if (uid == 0) {
                    294:                mask = 022;
1.10      ratchov   295:                snprintf(base, SOCKPATH_MAX, SOCKPATH_DIR);
1.1       ratchov   296:        } else {
                    297:                mask = 077;
1.10      ratchov   298:                snprintf(base, SOCKPATH_MAX, SOCKPATH_DIR "-%u", uid);
1.1       ratchov   299:        }
1.14      ratchov   300:        omask = umask(mask);
1.35      ratchov   301:        if (mkdir(base, 0777) == -1) {
1.1       ratchov   302:                if (errno != EEXIST)
                    303:                        err(1, "mkdir(\"%s\")", base);
                    304:        }
1.28      ratchov   305:        umask(omask);
1.35      ratchov   306:        if (stat(base, &sb) == -1)
1.1       ratchov   307:                err(1, "stat(\"%s\")", base);
1.30      ratchov   308:        if (!S_ISDIR(sb.st_mode))
                    309:                errx(1, "%s is not a directory", base);
1.1       ratchov   310:        if (sb.st_uid != uid || (sb.st_mode & mask) != 0)
                    311:                errx(1, "%s has wrong permissions", base);
                    312: }
                    313:
                    314: struct dev *
                    315: mkdev(char *path, struct aparams *par,
                    316:     int mode, int bufsz, int round, int rate, int hold, int autovol)
                    317: {
                    318:        struct dev *d;
                    319:
                    320:        for (d = dev_list; d != NULL; d = d->next) {
1.41      ratchov   321:                if (d->alt_list->next == NULL &&
                    322:                    strcmp(d->alt_list->name, path) == 0)
1.1       ratchov   323:                        return d;
                    324:        }
                    325:        if (!bufsz && !round) {
                    326:                round = DEFAULT_ROUND;
                    327:                bufsz = DEFAULT_BUFSZ;
                    328:        } else if (!bufsz) {
                    329:                bufsz = round * 2;
                    330:        } else if (!round)
                    331:                round = bufsz / 2;
                    332:        d = dev_new(path, par, mode, bufsz, round, rate, hold, autovol);
                    333:        if (d == NULL)
                    334:                exit(1);
                    335:        return d;
                    336: }
                    337:
1.27      ratchov   338: struct port *
                    339: mkport(char *path, int hold)
                    340: {
                    341:        struct port *c;
                    342:
                    343:        for (c = port_list; c != NULL; c = c->next) {
1.36      ratchov   344:                if (c->path_list->next == NULL &&
                    345:                    strcmp(c->path_list->str, path) == 0)
1.27      ratchov   346:                        return c;
                    347:        }
                    348:        c = port_new(path, MODE_MIDIMASK, hold);
                    349:        if (c == NULL)
                    350:                exit(1);
                    351:        return c;
                    352: }
                    353:
1.1       ratchov   354: struct opt *
                    355: mkopt(char *path, struct dev *d,
                    356:     int pmin, int pmax, int rmin, int rmax,
                    357:     int mode, int vol, int mmc, int dup)
                    358: {
                    359:        struct opt *o;
                    360:
1.33      ratchov   361:        o = opt_new(d, path, pmin, pmax, rmin, rmax,
1.1       ratchov   362:            MIDI_TO_ADATA(vol), mmc, dup, mode);
                    363:        if (o == NULL)
1.26      ratchov   364:                return NULL;
1.31      ratchov   365:        dev_adjpar(d, o->mode, o->pmax, o->rmax);
1.1       ratchov   366:        return o;
                    367: }
                    368:
1.34      ratchov   369: static void
                    370: dounveil(char *name, char *prefix, char *path_prefix)
                    371: {
                    372:        size_t prefix_len;
                    373:        char path[PATH_MAX];
                    374:
                    375:        prefix_len = strlen(prefix);
                    376:
                    377:        if (strncmp(name, prefix, prefix_len) != 0)
                    378:                errx(1, "%s: unsupported device or port format", name);
                    379:        snprintf(path, sizeof(path), "%s%s", path_prefix, name + prefix_len);
1.35      ratchov   380:        if (unveil(path, "rw") == -1)
1.34      ratchov   381:                err(1, "unveil");
                    382: }
                    383:
1.32      ratchov   384: static int
                    385: start_helper(int background)
                    386: {
1.34      ratchov   387:        struct dev *d;
1.41      ratchov   388:        struct dev_alt *da;
1.34      ratchov   389:        struct port *p;
1.32      ratchov   390:        struct passwd *pw;
1.36      ratchov   391:        struct name *n;
1.32      ratchov   392:        int s[2];
                    393:        pid_t pid;
                    394:
                    395:        if (geteuid() == 0) {
                    396:                if ((pw = getpwnam(SNDIO_PRIV_USER)) == NULL)
                    397:                        errx(1, "unknown user %s", SNDIO_PRIV_USER);
                    398:        } else
                    399:                pw = NULL;
1.35      ratchov   400:        if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == -1) {
1.32      ratchov   401:                perror("socketpair");
                    402:                return 0;
                    403:        }
                    404:        pid = fork();
                    405:        if (pid == -1) {
                    406:                log_puts("can't fork\n");
                    407:                return 0;
                    408:        }
                    409:        if (pid == 0) {
                    410:                setproctitle("helper");
                    411:                close(s[0]);
                    412:                if (fdpass_new(s[1], &helper_fileops) == NULL)
                    413:                        return 0;
                    414:                if (background) {
                    415:                        log_flush();
                    416:                        log_level = 0;
1.35      ratchov   417:                        if (daemon(0, 0) == -1)
1.32      ratchov   418:                                err(1, "daemon");
                    419:                }
                    420:                if (pw != NULL) {
                    421:                        if (setgroups(1, &pw->pw_gid) ||
                    422:                            setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
                    423:                            setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
                    424:                                err(1, "cannot drop privileges");
                    425:                }
1.36      ratchov   426:                for (d = dev_list; d != NULL; d = d->next) {
1.41      ratchov   427:                        for (da = d->alt_list; da != NULL; da = da->next) {
                    428:                                dounveil(da->name, "rsnd/", "/dev/audio");
                    429:                                dounveil(da->name, "rsnd/", "/dev/audioctl");
1.38      ratchov   430:                        }
1.36      ratchov   431:                }
                    432:                for (p = port_list; p != NULL; p = p->next) {
                    433:                        for (n = p->path_list; n != NULL; n = n->next)
                    434:                                dounveil(n->str, "rmidi/", "/dev/rmidi");
                    435:                }
1.35      ratchov   436:                if (pledge("stdio sendfd rpath wpath", NULL) == -1)
1.32      ratchov   437:                        err(1, "pledge");
                    438:                while (file_poll())
                    439:                        ; /* nothing */
                    440:                exit(0);
                    441:        } else {
                    442:                close(s[1]);
                    443:                if (fdpass_new(s[0], &worker_fileops) == NULL)
                    444:                        return 0;
                    445:        }
                    446:        return 1;
                    447: }
                    448:
                    449: static void
                    450: stop_helper(void)
                    451: {
                    452:        if (fdpass_peer)
                    453:                fdpass_close(fdpass_peer);
                    454: }
                    455:
1.1       ratchov   456: int
                    457: main(int argc, char **argv)
                    458: {
1.45    ! ratchov   459:        int c, i, background, unit;
1.1       ratchov   460:        int pmin, pmax, rmin, rmax;
1.25      ratchov   461:        char base[SOCKPATH_MAX], path[SOCKPATH_MAX];
1.1       ratchov   462:        unsigned int mode, dup, mmc, vol;
                    463:        unsigned int hold, autovol, bufsz, round, rate;
                    464:        const char *str;
                    465:        struct aparams par;
                    466:        struct dev *d;
                    467:        struct port *p;
                    468:        struct listen *l;
1.17      ratchov   469:        struct passwd *pw;
1.25      ratchov   470:        struct tcpaddr {
                    471:                char *host;
                    472:                struct tcpaddr *next;
                    473:        } *tcpaddr_list, *ta;
1.1       ratchov   474:
                    475:        atexit(log_flush);
                    476:
                    477:        /*
                    478:         * global options defaults
                    479:         */
1.44      jcs       480:        vol = 127;
1.1       ratchov   481:        dup = 1;
                    482:        mmc = 0;
                    483:        hold = 0;
1.44      jcs       484:        autovol = 0;
1.1       ratchov   485:        bufsz = 0;
                    486:        round = 0;
                    487:        rate = DEFAULT_RATE;
                    488:        unit = 0;
                    489:        background = 1;
                    490:        pmin = 0;
                    491:        pmax = 1;
                    492:        rmin = 0;
                    493:        rmax = 1;
                    494:        aparams_init(&par);
                    495:        mode = MODE_PLAY | MODE_REC;
1.25      ratchov   496:        tcpaddr_list = NULL;
1.45    ! ratchov   497:        d = NULL;
        !           498:        p = NULL;
1.42      ratchov   499:
                    500:        slot_array_init();
1.1       ratchov   501:
1.36      ratchov   502:        while ((c = getopt(argc, argv,
                    503:            "a:b:c:C:de:F:f:j:L:m:Q:q:r:s:t:U:v:w:x:z:")) != -1) {
1.1       ratchov   504:                switch (c) {
                    505:                case 'd':
                    506:                        log_level++;
                    507:                        background = 0;
                    508:                        break;
                    509:                case 'U':
                    510:                        unit = strtonum(optarg, 0, 15, &str);
                    511:                        if (str)
                    512:                                errx(1, "%s: unit number is %s", optarg, str);
                    513:                        break;
                    514:                case 'L':
1.25      ratchov   515:                        ta = xmalloc(sizeof(struct tcpaddr));
                    516:                        ta->host = optarg;
                    517:                        ta->next = tcpaddr_list;
                    518:                        tcpaddr_list = ta;
1.1       ratchov   519:                        break;
                    520:                case 'm':
                    521:                        mode = opt_mode();
                    522:                        break;
                    523:                case 'j':
                    524:                        dup = opt_onoff();
                    525:                        break;
                    526:                case 't':
                    527:                        mmc = opt_mmc();
                    528:                        break;
                    529:                case 'c':
                    530:                        opt_ch(&pmin, &pmax);
                    531:                        break;
                    532:                case 'C':
                    533:                        opt_ch(&rmin, &rmax);
                    534:                        break;
                    535:                case 'e':
                    536:                        opt_enc(&par);
                    537:                        break;
                    538:                case 'r':
                    539:                        rate = strtonum(optarg, RATE_MIN, RATE_MAX, &str);
                    540:                        if (str)
                    541:                                errx(1, "%s: rate is %s", optarg, str);
                    542:                        break;
                    543:                case 'v':
                    544:                        vol = strtonum(optarg, 0, MIDI_MAXCTL, &str);
                    545:                        if (str)
                    546:                                errx(1, "%s: volume is %s", optarg, str);
                    547:                        break;
                    548:                case 's':
1.45    ! ratchov   549:                        if (d == NULL) {
        !           550:                                for (i = 0; default_devs[i] != NULL; i++) {
        !           551:                                        mkdev(default_devs[i], &par, 0,
        !           552:                                            bufsz, round, rate, 0, autovol);
        !           553:                                }
        !           554:                                d = dev_list;
1.1       ratchov   555:                        }
1.26      ratchov   556:                        if (mkopt(optarg, d, pmin, pmax, rmin, rmax,
                    557:                                mode, vol, mmc, dup) == NULL)
                    558:                                return 1;
1.1       ratchov   559:                        break;
                    560:                case 'q':
1.45    ! ratchov   561:                        p = mkport(optarg, hold);
1.1       ratchov   562:                        break;
1.36      ratchov   563:                case 'Q':
1.45    ! ratchov   564:                        if (p == NULL)
1.36      ratchov   565:                                errx(1, "-Q %s: no ports defined", optarg);
1.45    ! ratchov   566:                        namelist_add(&p->path_list, optarg);
1.36      ratchov   567:                        break;
1.1       ratchov   568:                case 'a':
                    569:                        hold = opt_onoff();
                    570:                        break;
                    571:                case 'w':
                    572:                        autovol = opt_onoff();
                    573:                        break;
                    574:                case 'b':
                    575:                        bufsz = strtonum(optarg, 1, RATE_MAX, &str);
                    576:                        if (str)
                    577:                                errx(1, "%s: buffer size is %s", optarg, str);
                    578:                        break;
                    579:                case 'z':
                    580:                        round = strtonum(optarg, 1, SHRT_MAX, &str);
                    581:                        if (str)
                    582:                                errx(1, "%s: block size is %s", optarg, str);
                    583:                        break;
                    584:                case 'f':
1.45    ! ratchov   585:                        d = mkdev(optarg, &par, 0, bufsz, round,
1.28      ratchov   586:                            rate, hold, autovol);
1.1       ratchov   587:                        break;
1.36      ratchov   588:                case 'F':
1.45    ! ratchov   589:                        if (d == NULL)
1.36      ratchov   590:                                errx(1, "-F %s: no devices defined", optarg);
1.41      ratchov   591:                        if (!dev_addname(d, optarg))
                    592:                                exit(1);
1.36      ratchov   593:                        break;
1.1       ratchov   594:                default:
                    595:                        fputs(usagestr, stderr);
                    596:                        return 1;
                    597:                }
                    598:        }
                    599:        argc -= optind;
                    600:        argv += optind;
                    601:        if (argc > 0) {
                    602:                fputs(usagestr, stderr);
                    603:                return 1;
1.39      ratchov   604:        }
                    605:        if (port_list == NULL) {
                    606:                for (i = 0; default_ports[i] != NULL; i++)
                    607:                        mkport(default_ports[i], 0);
1.1       ratchov   608:        }
1.45    ! ratchov   609:        if (dev_list == NULL) {
        !           610:                for (i = 0; default_devs[i] != NULL; i++) {
1.40      ratchov   611:                        mkdev(default_devs[i], &par, 0,
                    612:                            bufsz, round, rate, 0, autovol);
                    613:                }
                    614:        }
1.1       ratchov   615:        for (d = dev_list; d != NULL; d = d->next) {
1.33      ratchov   616:                if (opt_byname(d, "default"))
1.1       ratchov   617:                        continue;
1.26      ratchov   618:                if (mkopt("default", d, pmin, pmax, rmin, rmax,
                    619:                        mode, vol, mmc, dup) == NULL)
                    620:                        return 1;
1.1       ratchov   621:        }
1.17      ratchov   622:
                    623:        setsig();
                    624:        filelist_init();
                    625:
1.32      ratchov   626:        if (!start_helper(background))
                    627:                return 1;
                    628:
                    629:        if (geteuid() == 0) {
1.20      ratchov   630:                if ((pw = getpwnam(SNDIO_USER)) == NULL)
                    631:                        errx(1, "unknown user %s", SNDIO_USER);
1.32      ratchov   632:        } else
                    633:                pw = NULL;
                    634:        getbasepath(base);
                    635:        snprintf(path, SOCKPATH_MAX, "%s/" SOCKPATH_FILE "%u", base, unit);
                    636:        if (!listen_new_un(path))
                    637:                return 1;
                    638:        for (ta = tcpaddr_list; ta != NULL; ta = ta->next) {
                    639:                if (!listen_new_tcp(ta->host, AUCAT_PORT + unit))
                    640:                        return 1;
1.20      ratchov   641:        }
1.32      ratchov   642:        for (l = listen_list; l != NULL; l = l->next) {
                    643:                if (!listen_init(l))
                    644:                        return 1;
1.13      ratchov   645:        }
1.32      ratchov   646:        midi_init();
                    647:        for (p = port_list; p != NULL; p = p->next) {
                    648:                if (!port_init(p))
                    649:                        return 1;
1.1       ratchov   650:        }
1.32      ratchov   651:        for (d = dev_list; d != NULL; d = d->next) {
                    652:                if (!dev_init(d))
1.1       ratchov   653:                        return 1;
1.32      ratchov   654:        }
                    655:        if (background) {
                    656:                log_flush();
                    657:                log_level = 0;
1.35      ratchov   658:                if (daemon(0, 0) == -1)
1.32      ratchov   659:                        err(1, "daemon");
                    660:        }
                    661:        if (pw != NULL) {
1.35      ratchov   662:                if (setpriority(PRIO_PROCESS, 0, SNDIO_PRIO) == -1)
1.32      ratchov   663:                        err(1, "setpriority");
1.35      ratchov   664:                if (chroot(pw->pw_dir) == -1 || chdir("/") == -1)
1.32      ratchov   665:                        err(1, "cannot chroot to %s", pw->pw_dir);
1.35      ratchov   666:                if (setgroups(1, &pw->pw_gid) == -1 ||
                    667:                    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1 ||
                    668:                    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1 )
1.32      ratchov   669:                        err(1, "cannot drop privileges");
                    670:        }
                    671:        if (tcpaddr_list) {
                    672:                if (pledge("stdio audio recvfd unix inet", NULL) == -1)
1.22      ratchov   673:                        err(1, "pledge");
1.18      ratchov   674:        } else {
1.32      ratchov   675:                if (pledge("stdio audio recvfd unix", NULL) == -1)
                    676:                        err(1, "pledge");
                    677:        }
                    678:        for (;;) {
                    679:                if (quit_flag)
                    680:                        break;
1.36      ratchov   681:                if (reopen_flag) {
                    682:                        reopen_flag = 0;
                    683:                        for (d = dev_list; d != NULL; d = d->next)
                    684:                                dev_reopen(d);
                    685:                        for (p = port_list; p != NULL; p = p->next)
                    686:                                port_reopen(p);
                    687:                }
1.32      ratchov   688:                if (!fdpass_peer)
                    689:                        break;
                    690:                if (!file_poll())
                    691:                        break;
                    692:        }
                    693:        stop_helper();
                    694:        while (listen_list != NULL)
                    695:                listen_close(listen_list);
                    696:        while (sock_list != NULL)
                    697:                sock_close(sock_list);
                    698:        for (d = dev_list; d != NULL; d = d->next)
                    699:                dev_done(d);
                    700:        for (p = port_list; p != NULL; p = p->next)
                    701:                port_done(p);
                    702:        while (file_poll())
                    703:                ; /* nothing */
                    704:        midi_done();
1.18      ratchov   705:
1.43      ratchov   706:        while (opt_list)
                    707:                opt_del(opt_list);
1.1       ratchov   708:        while (dev_list)
                    709:                dev_del(dev_list);
                    710:        while (port_list)
                    711:                port_del(port_list);
1.25      ratchov   712:        while (tcpaddr_list) {
                    713:                ta = tcpaddr_list;
                    714:                tcpaddr_list = ta->next;
                    715:                xfree(ta);
                    716:        }
1.1       ratchov   717:        filelist_done();
                    718:        unsetsig();
                    719:        return 0;
                    720: }