xref: /openbsd/usr.bin/sndiod/sndiod.c (revision d415bd75)
1 /*	$OpenBSD: sndiod.c,v 1.48 2022/03/07 08:58:33 ratchov Exp $	*/
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>
20 #include <sys/socket.h>
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"
38 #include "fdpass.h"
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 /*
54  * privileged user name
55  */
56 #ifndef SNDIO_PRIV_USER
57 #define SNDIO_PRIV_USER	"_sndiop"
58 #endif
59 
60 /*
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	480
79 #endif
80 
81 /*
82  * buffer size if neither ``-z'' nor ``-b'' is used
83  */
84 #ifndef DEFAULT_BUFSZ
85 #define DEFAULT_BUFSZ	7680
86 #endif
87 
88 /*
89  * default device precision
90  */
91 #ifndef DEFAULT_BITS
92 #define DEFAULT_BITS	16
93 #endif
94 
95 void sigint(int);
96 void sighup(int);
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);
103 void getbasepath(char *);
104 void setsig(void);
105 void unsetsig(void);
106 struct dev *mkdev(char *, struct aparams *,
107     int, int, int, int, int, int);
108 struct port *mkport(char *, int);
109 struct opt *mkopt(char *, struct dev *,
110     int, int, int, int, int, int, int, int);
111 
112 unsigned int log_level = 0;
113 volatile sig_atomic_t quit_flag = 0, reopen_flag = 0;
114 
115 char usagestr[] = "usage: sndiod [-d] [-a flag] [-b nframes] "
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";
120 
121 /*
122  * default audio devices
123  */
124 static char *default_devs[] = {
125 	"rsnd/0", "rsnd/1", "rsnd/2", "rsnd/3",
126 	NULL
127 };
128 
129 /*
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 /*
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 
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 
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 
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 
231 unsigned int
232 opt_mode(void)
233 {
234 	unsigned int mode = 0;
235 	char *p = optarg;
236 
237 	for (;;) {
238 		if (getword("play", &p)) {
239 			mode |= MODE_PLAY;
240 		} else if (getword("rec", &p)) {
241 			mode |= MODE_REC;
242 		} else if (getword("mon", &p)) {
243 			mode |= MODE_MON;
244 		} else if (getword("midi", &p)) {
245 			mode |= MODE_MIDIMASK;
246 		} else
247 			errx(1, "%s: bad mode", optarg);
248 		if (*p == '\0')
249 			break;
250 		p++;
251 	}
252 	if (mode == 0)
253 		errx(1, "empty mode");
254 	return mode;
255 }
256 
257 void
258 setsig(void)
259 {
260 	struct sigaction sa;
261 
262 	quit_flag = 0;
263 	reopen_flag = 0;
264 	sigfillset(&sa.sa_mask);
265 	sa.sa_flags = SA_RESTART;
266 	sa.sa_handler = sigint;
267 	if (sigaction(SIGINT, &sa, NULL) == -1)
268 		err(1, "sigaction(int) failed");
269 	if (sigaction(SIGTERM, &sa, NULL) == -1)
270 		err(1, "sigaction(term) failed");
271 	sa.sa_handler = sighup;
272 	if (sigaction(SIGHUP, &sa, NULL) == -1)
273 		err(1, "sigaction(hup) failed");
274 }
275 
276 void
277 unsetsig(void)
278 {
279 	struct sigaction sa;
280 
281 	sigfillset(&sa.sa_mask);
282 	sa.sa_flags = SA_RESTART;
283 	sa.sa_handler = SIG_DFL;
284 	if (sigaction(SIGHUP, &sa, NULL) == -1)
285 		err(1, "unsetsig(hup): sigaction failed");
286 	if (sigaction(SIGTERM, &sa, NULL) == -1)
287 		err(1, "unsetsig(term): sigaction failed");
288 	if (sigaction(SIGINT, &sa, NULL) == -1)
289 		err(1, "unsetsig(int): sigaction failed");
290 }
291 
292 void
293 getbasepath(char *base)
294 {
295 	uid_t uid;
296 	struct stat sb;
297 	mode_t mask, omask;
298 
299 	uid = geteuid();
300 	if (uid == 0) {
301 		mask = 022;
302 		snprintf(base, SOCKPATH_MAX, SOCKPATH_DIR);
303 	} else {
304 		mask = 077;
305 		snprintf(base, SOCKPATH_MAX, SOCKPATH_DIR "-%u", uid);
306 	}
307 	omask = umask(mask);
308 	if (mkdir(base, 0777) == -1) {
309 		if (errno != EEXIST)
310 			err(1, "mkdir(\"%s\")", base);
311 	}
312 	umask(omask);
313 	if (stat(base, &sb) == -1)
314 		err(1, "stat(\"%s\")", base);
315 	if (!S_ISDIR(sb.st_mode))
316 		errx(1, "%s is not a directory", base);
317 	if (sb.st_uid != uid || (sb.st_mode & mask) != 0)
318 		errx(1, "%s has wrong permissions", base);
319 }
320 
321 struct dev *
322 mkdev(char *path, struct aparams *par,
323     int mode, int bufsz, int round, int rate, int hold, int autovol)
324 {
325 	struct dev *d;
326 
327 	for (d = dev_list; d != NULL; d = d->next) {
328 		if (strcmp(d->path, path) == 0)
329 			return d;
330 	}
331 	if (!bufsz && !round) {
332 		round = DEFAULT_ROUND;
333 		bufsz = DEFAULT_BUFSZ;
334 	} else if (!bufsz) {
335 		bufsz = round * 2;
336 	} else if (!round)
337 		round = bufsz / 2;
338 	d = dev_new(path, par, mode, bufsz, round, rate, hold, autovol);
339 	if (d == NULL)
340 		exit(1);
341 	return d;
342 }
343 
344 struct port *
345 mkport(char *path, int hold)
346 {
347 	struct port *c;
348 
349 	for (c = port_list; c != NULL; c = c->next) {
350 		if (strcmp(c->path, path) == 0)
351 			return c;
352 	}
353 	c = port_new(path, MODE_MIDIMASK, hold);
354 	if (c == NULL)
355 		exit(1);
356 	return c;
357 }
358 
359 struct opt *
360 mkopt(char *path, struct dev *d,
361     int pmin, int pmax, int rmin, int rmax,
362     int mode, int vol, int mmc, int dup)
363 {
364 	struct opt *o;
365 
366 	o = opt_new(d, path, pmin, pmax, rmin, rmax,
367 	    MIDI_TO_ADATA(vol), mmc, dup, mode);
368 	if (o == NULL)
369 		return NULL;
370 	dev_adjpar(d, o->mode, o->pmax, o->rmax);
371 	return o;
372 }
373 
374 static void
375 dounveil(char *name, char *prefix, char *path_prefix)
376 {
377 	size_t prefix_len;
378 	char path[PATH_MAX];
379 
380 	prefix_len = strlen(prefix);
381 
382 	if (strncmp(name, prefix, prefix_len) != 0)
383 		errx(1, "%s: unsupported device or port format", name);
384 	snprintf(path, sizeof(path), "%s%s", path_prefix, name + prefix_len);
385 	if (unveil(path, "rw") == -1)
386 		err(1, "unveil %s", path);
387 }
388 
389 static int
390 start_helper(int background)
391 {
392 	struct dev *d;
393 	struct port *p;
394 	struct passwd *pw;
395 	int s[2];
396 	pid_t pid;
397 
398 	if (geteuid() == 0) {
399 		if ((pw = getpwnam(SNDIO_PRIV_USER)) == NULL)
400 			errx(1, "unknown user %s", SNDIO_PRIV_USER);
401 	} else
402 		pw = NULL;
403 	if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == -1) {
404 		perror("socketpair");
405 		return 0;
406 	}
407 	pid = fork();
408 	if (pid	== -1) {
409 		log_puts("can't fork\n");
410 		return 0;
411 	}
412 	if (pid == 0) {
413 		setproctitle("helper");
414 		close(s[0]);
415 		if (fdpass_new(s[1], &helper_fileops) == NULL)
416 			return 0;
417 		if (background) {
418 			log_flush();
419 			log_level = 0;
420 			if (daemon(0, 0) == -1)
421 				err(1, "daemon");
422 		}
423 		if (pw != NULL) {
424 			if (setgroups(1, &pw->pw_gid) ||
425 			    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
426 			    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
427 				err(1, "cannot drop privileges");
428 		}
429 		for (d = dev_list; d != NULL; d = d->next) {
430 			dounveil(d->path, "rsnd/", "/dev/audio");
431 			dounveil(d->path, "rsnd/", "/dev/audioctl");
432 		}
433 		for (p = port_list; p != NULL; p = p->next) {
434 			dounveil(p->path, "rmidi/", "/dev/rmidi");
435 		}
436 		if (pledge("stdio sendfd rpath wpath", NULL) == -1)
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 
456 int
457 main(int argc, char **argv)
458 {
459 	int c, i, background, unit;
460 	int pmin, pmax, rmin, rmax;
461 	char base[SOCKPATH_MAX], path[SOCKPATH_MAX];
462 	unsigned int mode, dup, mmc, vol;
463 	unsigned int hold, autovol, bufsz, round, rate;
464 	unsigned int reopen_list;
465 	const char *str;
466 	struct aparams par;
467 	struct opt *o;
468 	struct dev *d, *dev_first, *dev_next;
469 	struct port *p, *port_first, *port_next;
470 	struct listen *l;
471 	struct passwd *pw;
472 	struct tcpaddr {
473 		char *host;
474 		struct tcpaddr *next;
475 	} *tcpaddr_list, *ta;
476 
477 	atexit(log_flush);
478 
479 	/*
480 	 * global options defaults
481 	 */
482 	vol = 127;
483 	dup = 1;
484 	mmc = 0;
485 	hold = 0;
486 	autovol = 0;
487 	bufsz = 0;
488 	round = 0;
489 	rate = DEFAULT_RATE;
490 	unit = 0;
491 	background = 1;
492 	pmin = 0;
493 	pmax = 1;
494 	rmin = 0;
495 	rmax = 1;
496 	par.bits = DEFAULT_BITS;
497 	par.bps = APARAMS_BPS(par.bits);
498 	par.le = ADATA_LE;
499 	par.sig = 1;
500 	par.msb = 0;
501 	mode = MODE_PLAY | MODE_REC;
502 	dev_first = dev_next = NULL;
503 	port_first = port_next = NULL;
504 	tcpaddr_list = NULL;
505 	d = NULL;
506 	p = NULL;
507 
508 	slot_array_init();
509 
510 	while ((c = getopt(argc, argv,
511 	    "a:b:c:C:de:F:f:j:L:m:Q:q:r:s:t:U:v:w:x:z:")) != -1) {
512 		switch (c) {
513 		case 'd':
514 			log_level++;
515 			background = 0;
516 			break;
517 		case 'U':
518 			unit = strtonum(optarg, 0, 15, &str);
519 			if (str)
520 				errx(1, "%s: unit number is %s", optarg, str);
521 			break;
522 		case 'L':
523 			ta = xmalloc(sizeof(struct tcpaddr));
524 			ta->host = optarg;
525 			ta->next = tcpaddr_list;
526 			tcpaddr_list = ta;
527 			break;
528 		case 'm':
529 			mode = opt_mode();
530 			break;
531 		case 'j':
532 			dup = opt_onoff();
533 			break;
534 		case 't':
535 			mmc = opt_mmc();
536 			break;
537 		case 'c':
538 			opt_ch(&pmin, &pmax);
539 			break;
540 		case 'C':
541 			opt_ch(&rmin, &rmax);
542 			break;
543 		case 'e':
544 			opt_enc(&par);
545 			break;
546 		case 'r':
547 			rate = strtonum(optarg, RATE_MIN, RATE_MAX, &str);
548 			if (str)
549 				errx(1, "%s: rate is %s", optarg, str);
550 			break;
551 		case 'v':
552 			vol = strtonum(optarg, 0, MIDI_MAXCTL, &str);
553 			if (str)
554 				errx(1, "%s: volume is %s", optarg, str);
555 			break;
556 		case 's':
557 			if (d == NULL) {
558 				for (i = 0; default_devs[i] != NULL; i++) {
559 					mkdev(default_devs[i], &par, 0,
560 					    bufsz, round, rate, 0, autovol);
561 				}
562 				d = dev_list;
563 			}
564 			if (mkopt(optarg, d, pmin, pmax, rmin, rmax,
565 				mode, vol, mmc, dup) == NULL)
566 				return 1;
567 			break;
568 		case 'q':
569 			p = mkport(optarg, hold);
570 			/* create new circulate list */
571 			port_first = port_next = p;
572 			break;
573 		case 'Q':
574 			if (p == NULL)
575 				errx(1, "-Q %s: no ports defined", optarg);
576 			p = mkport(optarg, hold);
577 			/* add to circulate list */
578 			p->alt_next = port_next;
579 			port_first->alt_next = p;
580 			port_next = p;
581 			break;
582 		case 'a':
583 			hold = opt_onoff();
584 			break;
585 		case 'w':
586 			autovol = opt_onoff();
587 			break;
588 		case 'b':
589 			bufsz = strtonum(optarg, 1, RATE_MAX, &str);
590 			if (str)
591 				errx(1, "%s: buffer size is %s", optarg, str);
592 			break;
593 		case 'z':
594 			round = strtonum(optarg, 1, SHRT_MAX, &str);
595 			if (str)
596 				errx(1, "%s: block size is %s", optarg, str);
597 			break;
598 		case 'f':
599 			d = mkdev(optarg, &par, 0, bufsz, round,
600 			    rate, hold, autovol);
601 			/* create new circulate list */
602 			dev_first = dev_next = d;
603 			break;
604 		case 'F':
605 			if (d == NULL)
606 				errx(1, "-F %s: no devices defined", optarg);
607 			d = mkdev(optarg, &par, 0, bufsz, round,
608 			    rate, hold, autovol);
609 			/* add to circulate list */
610 			d->alt_next = dev_next;
611 			dev_first->alt_next = d;
612 			dev_next = d;
613 			break;
614 		default:
615 			fputs(usagestr, stderr);
616 			return 1;
617 		}
618 	}
619 	argc -= optind;
620 	argv += optind;
621 	if (argc > 0) {
622 		fputs(usagestr, stderr);
623 		return 1;
624 	}
625 	if (port_list == NULL) {
626 		for (i = 0; default_ports[i] != NULL; i++)
627 			mkport(default_ports[i], 0);
628 	}
629 	if (dev_list == NULL) {
630 		for (i = 0; default_devs[i] != NULL; i++) {
631 			mkdev(default_devs[i], &par, 0,
632 			    bufsz, round, rate, 0, autovol);
633 		}
634 	}
635 
636 	/*
637 	 * Add default sub-device (if none) backed by the last device
638 	 */
639 	o = opt_byname("default");
640 	if (o == NULL) {
641 		o = mkopt("default", dev_list, pmin, pmax, rmin, rmax,
642 		    mode, vol, 0, dup);
643 		if (o == NULL)
644 			return 1;
645 	}
646 
647 	/*
648 	 * For each device create an anonymous sub-device using
649 	 * the "default" sub-device as template
650 	 */
651 	for (d = dev_list; d != NULL; d = d->next) {
652 		if (opt_new(d, NULL, o->pmin, o->pmax, o->rmin, o->rmax,
653 			o->maxweight, o->mtc != NULL, o->dup, o->mode) == NULL)
654 			return 1;
655 		dev_adjpar(d, o->mode, o->pmax, o->rmax);
656 	}
657 
658 	setsig();
659 	filelist_init();
660 
661 	if (!start_helper(background))
662 		return 1;
663 
664 	if (geteuid() == 0) {
665 		if ((pw = getpwnam(SNDIO_USER)) == NULL)
666 			errx(1, "unknown user %s", SNDIO_USER);
667 	} else
668 		pw = NULL;
669 	getbasepath(base);
670 	snprintf(path, SOCKPATH_MAX, "%s/" SOCKPATH_FILE "%u", base, unit);
671 	if (!listen_new_un(path))
672 		return 1;
673 	for (ta = tcpaddr_list; ta != NULL; ta = ta->next) {
674 		if (!listen_new_tcp(ta->host, AUCAT_PORT + unit))
675 			return 1;
676 	}
677 	for (l = listen_list; l != NULL; l = l->next) {
678 		if (!listen_init(l))
679 			return 1;
680 	}
681 	midi_init();
682 	for (p = port_list; p != NULL; p = p->next) {
683 		if (!port_init(p))
684 			return 1;
685 	}
686 	for (d = dev_list; d != NULL; d = d->next) {
687 		if (!dev_init(d))
688 			return 1;
689 	}
690 	for (o = opt_list; o != NULL; o = o->next)
691 		opt_init(o);
692 	if (background) {
693 		log_flush();
694 		log_level = 0;
695 		if (daemon(0, 0) == -1)
696 			err(1, "daemon");
697 	}
698 	if (pw != NULL) {
699 		if (setpriority(PRIO_PROCESS, 0, SNDIO_PRIO) == -1)
700 			err(1, "setpriority");
701 		if (chroot(pw->pw_dir) == -1 || chdir("/") == -1)
702 			err(1, "cannot chroot to %s", pw->pw_dir);
703 		if (setgroups(1, &pw->pw_gid) == -1 ||
704 		    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1 ||
705 		    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1 )
706 			err(1, "cannot drop privileges");
707 	}
708 	if (tcpaddr_list) {
709 		if (pledge("stdio audio recvfd unix inet", NULL) == -1)
710 			err(1, "pledge");
711 	} else {
712 		if (pledge("stdio audio recvfd unix", NULL) == -1)
713 			err(1, "pledge");
714 	}
715 	for (;;) {
716 		if (quit_flag)
717 			break;
718 		if (reopen_flag) {
719 			reopen_flag = 0;
720 
721 			reopen_list = 0;
722 			for (d = dev_list; d != NULL; d = d->next) {
723 				if (d->pstate != DEV_CFG)
724 					reopen_list |= (1 << d->num);
725 			}
726 			for (d = dev_list; d != NULL; d = d->next) {
727 				if (reopen_list & (1 << d->num))
728 					dev_migrate(d);
729 			}
730 
731 			reopen_list = 0;
732 			for (p = port_list; p != NULL; p = p->next) {
733 				if (p->state != PORT_CFG)
734 					reopen_list |= (1 << p->num);
735 			}
736 			for (p = port_list; p != NULL; p = p->next) {
737 				if (reopen_list & (1 << p->num)) {
738 					if (port_migrate(p) != p)
739 						port_close(p);
740 				}
741 			}
742 		}
743 		if (!fdpass_peer)
744 			break;
745 		if (!file_poll())
746 			break;
747 	}
748 	stop_helper();
749 	while (listen_list != NULL)
750 		listen_close(listen_list);
751 	while (sock_list != NULL)
752 		sock_close(sock_list);
753 	for (o = opt_list; o != NULL; o = o->next)
754 		opt_done(o);
755 	for (d = dev_list; d != NULL; d = d->next)
756 		dev_done(d);
757 	for (p = port_list; p != NULL; p = p->next)
758 		port_done(p);
759 	while (file_poll())
760 		; /* nothing */
761 	midi_done();
762 
763 	while (opt_list)
764 		opt_del(opt_list);
765 	while (dev_list)
766 		dev_del(dev_list);
767 	while (port_list)
768 		port_del(port_list);
769 	while (tcpaddr_list) {
770 		ta = tcpaddr_list;
771 		tcpaddr_list = ta->next;
772 		xfree(ta);
773 	}
774 	filelist_done();
775 	unsetsig();
776 	return 0;
777 }
778