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

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