1 |
|
|
/* $OpenBSD: sndiod.c,v 1.32 2016/10/20 05:48:50 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 960 |
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 in server mode |
90 |
|
|
*/ |
91 |
|
|
#ifndef DEFAULT_DEV |
92 |
|
|
#define DEFAULT_DEV "rsnd/0" |
93 |
|
|
#endif |
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 *); |
103 |
|
|
void setsig(void); |
104 |
|
|
void unsetsig(void); |
105 |
|
|
struct dev *mkdev(char *, struct aparams *, |
106 |
|
|
int, int, int, int, int, int); |
107 |
|
|
struct port *mkport(char *, int); |
108 |
|
|
struct opt *mkopt(char *, struct dev *, |
109 |
|
|
int, int, int, int, int, int, int, int); |
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 |
|
|
|
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 |
|
|
|
202 |
|
|
unsigned int |
203 |
|
|
opt_mode(void) |
204 |
|
|
{ |
205 |
|
|
unsigned int mode = 0; |
206 |
|
|
char *p = optarg; |
207 |
|
|
|
208 |
|
|
for (;;) { |
209 |
|
|
if (getword("play", &p)) { |
210 |
|
|
mode |= MODE_PLAY; |
211 |
|
|
} else if (getword("rec", &p)) { |
212 |
|
|
mode |= MODE_REC; |
213 |
|
|
} else if (getword("mon", &p)) { |
214 |
|
|
mode |= MODE_MON; |
215 |
|
|
} else if (getword("midi", &p)) { |
216 |
|
|
mode |= MODE_MIDIMASK; |
217 |
|
|
} else |
218 |
|
|
errx(1, "%s: bad mode", optarg); |
219 |
|
|
if (*p == '\0') |
220 |
|
|
break; |
221 |
|
|
p++; |
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"); |
255 |
|
|
if (sigaction(SIGTERM, &sa, NULL) < 0) |
256 |
|
|
err(1, "unsetsig(term): sigaction failed"); |
257 |
|
|
if (sigaction(SIGINT, &sa, NULL) < 0) |
258 |
|
|
err(1, "unsetsig(int): sigaction failed"); |
259 |
|
|
} |
260 |
|
|
|
261 |
|
|
void |
262 |
|
|
getbasepath(char *base) |
263 |
|
|
{ |
264 |
|
|
uid_t uid; |
265 |
|
|
struct stat sb; |
266 |
|
|
mode_t mask, omask; |
267 |
|
|
|
268 |
|
|
uid = geteuid(); |
269 |
|
|
if (uid == 0) { |
270 |
|
|
mask = 022; |
271 |
|
|
snprintf(base, SOCKPATH_MAX, SOCKPATH_DIR); |
272 |
|
|
} else { |
273 |
|
|
mask = 077; |
274 |
|
|
snprintf(base, SOCKPATH_MAX, SOCKPATH_DIR "-%u", uid); |
275 |
|
|
} |
276 |
|
|
omask = umask(mask); |
277 |
|
|
if (mkdir(base, 0777) < 0) { |
278 |
|
|
if (errno != EEXIST) |
279 |
|
|
err(1, "mkdir(\"%s\")", base); |
280 |
|
|
} |
281 |
|
|
umask(omask); |
282 |
|
|
if (stat(base, &sb) < 0) |
283 |
|
|
err(1, "stat(\"%s\")", base); |
284 |
|
|
if (!S_ISDIR(sb.st_mode)) |
285 |
|
|
errx(1, "%s is not a directory", base); |
286 |
|
|
if (sb.st_uid != uid || (sb.st_mode & mask) != 0) |
287 |
|
|
errx(1, "%s has wrong permissions", base); |
288 |
|
|
} |
289 |
|
|
|
290 |
|
|
struct dev * |
291 |
|
|
mkdev(char *path, struct aparams *par, |
292 |
|
|
int mode, int bufsz, int round, int rate, int hold, int autovol) |
293 |
|
|
{ |
294 |
|
|
struct dev *d; |
295 |
|
|
|
296 |
|
|
for (d = dev_list; d != NULL; d = d->next) { |
297 |
|
|
if (strcmp(d->path, path) == 0) |
298 |
|
|
return d; |
299 |
|
|
} |
300 |
|
|
if (!bufsz && !round) { |
301 |
|
|
round = DEFAULT_ROUND; |
302 |
|
|
bufsz = DEFAULT_BUFSZ; |
303 |
|
|
} else if (!bufsz) { |
304 |
|
|
bufsz = round * 2; |
305 |
|
|
} else if (!round) |
306 |
|
|
round = bufsz / 2; |
307 |
|
|
d = dev_new(path, par, mode, bufsz, round, rate, hold, autovol); |
308 |
|
|
if (d == NULL) |
309 |
|
|
exit(1); |
310 |
|
|
return d; |
311 |
|
|
} |
312 |
|
|
|
313 |
|
|
struct port * |
314 |
|
|
mkport(char *path, int hold) |
315 |
|
|
{ |
316 |
|
|
struct port *c; |
317 |
|
|
|
318 |
|
|
for (c = port_list; c != NULL; c = c->next) { |
319 |
|
|
if (strcmp(c->path, path) == 0) |
320 |
|
|
return c; |
321 |
|
|
} |
322 |
|
|
c = port_new(path, MODE_MIDIMASK, hold); |
323 |
|
|
if (c == NULL) |
324 |
|
|
exit(1); |
325 |
|
|
return c; |
326 |
|
|
} |
327 |
|
|
|
328 |
|
|
struct opt * |
329 |
|
|
mkopt(char *path, struct dev *d, |
330 |
|
|
int pmin, int pmax, int rmin, int rmax, |
331 |
|
|
int mode, int vol, int mmc, int dup) |
332 |
|
|
{ |
333 |
|
|
struct opt *o; |
334 |
|
|
|
335 |
|
|
o = opt_new(path, d, pmin, pmax, rmin, rmax, |
336 |
|
|
MIDI_TO_ADATA(vol), mmc, dup, mode); |
337 |
|
|
if (o == NULL) |
338 |
|
|
return NULL; |
339 |
|
|
dev_adjpar(d, o->mode, o->pmax, o->rmax); |
340 |
|
|
return o; |
341 |
|
|
} |
342 |
|
|
|
343 |
|
|
static int |
344 |
|
|
start_helper(int background) |
345 |
|
|
{ |
346 |
|
|
struct passwd *pw; |
347 |
|
|
int s[2]; |
348 |
|
|
pid_t pid; |
349 |
|
|
|
350 |
|
|
if (geteuid() == 0) { |
351 |
|
|
if ((pw = getpwnam(SNDIO_PRIV_USER)) == NULL) |
352 |
|
|
errx(1, "unknown user %s", SNDIO_PRIV_USER); |
353 |
|
|
} else |
354 |
|
|
pw = NULL; |
355 |
|
|
if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) < 0) { |
356 |
|
|
perror("socketpair"); |
357 |
|
|
return 0; |
358 |
|
|
} |
359 |
|
|
pid = fork(); |
360 |
|
|
if (pid == -1) { |
361 |
|
|
log_puts("can't fork\n"); |
362 |
|
|
return 0; |
363 |
|
|
} |
364 |
|
|
if (pid == 0) { |
365 |
|
|
setproctitle("helper"); |
366 |
|
|
close(s[0]); |
367 |
|
|
if (fdpass_new(s[1], &helper_fileops) == NULL) |
368 |
|
|
return 0; |
369 |
|
|
if (background) { |
370 |
|
|
log_flush(); |
371 |
|
|
log_level = 0; |
372 |
|
|
if (daemon(0, 0) < 0) |
373 |
|
|
err(1, "daemon"); |
374 |
|
|
} |
375 |
|
|
if (pw != NULL) { |
376 |
|
|
if (setgroups(1, &pw->pw_gid) || |
377 |
|
|
setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || |
378 |
|
|
setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) |
379 |
|
|
err(1, "cannot drop privileges"); |
380 |
|
|
} |
381 |
|
|
if (pledge("stdio sendfd rpath wpath flock cpath", NULL) < 0) |
382 |
|
|
err(1, "pledge"); |
383 |
|
|
while (file_poll()) |
384 |
|
|
; /* nothing */ |
385 |
|
|
exit(0); |
386 |
|
|
} else { |
387 |
|
|
close(s[1]); |
388 |
|
|
if (fdpass_new(s[0], &worker_fileops) == NULL) |
389 |
|
|
return 0; |
390 |
|
|
} |
391 |
|
|
return 1; |
392 |
|
|
} |
393 |
|
|
|
394 |
|
|
static void |
395 |
|
|
stop_helper(void) |
396 |
|
|
{ |
397 |
|
|
if (fdpass_peer) |
398 |
|
|
fdpass_close(fdpass_peer); |
399 |
|
|
} |
400 |
|
|
|
401 |
|
|
int |
402 |
|
|
main(int argc, char **argv) |
403 |
|
|
{ |
404 |
|
|
int c, background, unit; |
405 |
|
|
int pmin, pmax, rmin, rmax; |
406 |
|
|
char base[SOCKPATH_MAX], path[SOCKPATH_MAX]; |
407 |
|
|
unsigned int mode, dup, mmc, vol; |
408 |
|
|
unsigned int hold, autovol, bufsz, round, rate; |
409 |
|
|
const char *str; |
410 |
|
|
struct aparams par; |
411 |
|
|
struct dev *d; |
412 |
|
|
struct port *p; |
413 |
|
|
struct listen *l; |
414 |
|
|
struct passwd *pw; |
415 |
|
|
struct tcpaddr { |
416 |
|
|
char *host; |
417 |
|
|
struct tcpaddr *next; |
418 |
|
|
} *tcpaddr_list, *ta; |
419 |
|
|
|
420 |
|
|
atexit(log_flush); |
421 |
|
|
|
422 |
|
|
/* |
423 |
|
|
* global options defaults |
424 |
|
|
*/ |
425 |
|
|
vol = 118; |
426 |
|
|
dup = 1; |
427 |
|
|
mmc = 0; |
428 |
|
|
hold = 0; |
429 |
|
|
autovol = 1; |
430 |
|
|
bufsz = 0; |
431 |
|
|
round = 0; |
432 |
|
|
rate = DEFAULT_RATE; |
433 |
|
|
unit = 0; |
434 |
|
|
background = 1; |
435 |
|
|
pmin = 0; |
436 |
|
|
pmax = 1; |
437 |
|
|
rmin = 0; |
438 |
|
|
rmax = 1; |
439 |
|
|
aparams_init(&par); |
440 |
|
|
mode = MODE_PLAY | MODE_REC; |
441 |
|
|
tcpaddr_list = NULL; |
442 |
|
|
|
443 |
|
|
while ((c = getopt(argc, argv, "a:b:c:C:de:f:j:L:m:q:r:s:t:U:v:w:x:z:")) != -1) { |
444 |
|
|
switch (c) { |
445 |
|
|
case 'd': |
446 |
|
|
log_level++; |
447 |
|
|
background = 0; |
448 |
|
|
break; |
449 |
|
|
case 'U': |
450 |
|
|
unit = strtonum(optarg, 0, 15, &str); |
451 |
|
|
if (str) |
452 |
|
|
errx(1, "%s: unit number is %s", optarg, str); |
453 |
|
|
break; |
454 |
|
|
case 'L': |
455 |
|
|
ta = xmalloc(sizeof(struct tcpaddr)); |
456 |
|
|
ta->host = optarg; |
457 |
|
|
ta->next = tcpaddr_list; |
458 |
|
|
tcpaddr_list = ta; |
459 |
|
|
break; |
460 |
|
|
case 'm': |
461 |
|
|
mode = opt_mode(); |
462 |
|
|
break; |
463 |
|
|
case 'j': |
464 |
|
|
dup = opt_onoff(); |
465 |
|
|
break; |
466 |
|
|
case 't': |
467 |
|
|
mmc = opt_mmc(); |
468 |
|
|
break; |
469 |
|
|
case 'c': |
470 |
|
|
opt_ch(&pmin, &pmax); |
471 |
|
|
break; |
472 |
|
|
case 'C': |
473 |
|
|
opt_ch(&rmin, &rmax); |
474 |
|
|
break; |
475 |
|
|
case 'e': |
476 |
|
|
opt_enc(&par); |
477 |
|
|
break; |
478 |
|
|
case 'r': |
479 |
|
|
rate = strtonum(optarg, RATE_MIN, RATE_MAX, &str); |
480 |
|
|
if (str) |
481 |
|
|
errx(1, "%s: rate is %s", optarg, str); |
482 |
|
|
break; |
483 |
|
|
case 'v': |
484 |
|
|
vol = strtonum(optarg, 0, MIDI_MAXCTL, &str); |
485 |
|
|
if (str) |
486 |
|
|
errx(1, "%s: volume is %s", optarg, str); |
487 |
|
|
break; |
488 |
|
|
case 's': |
489 |
|
|
if ((d = dev_list) == NULL) { |
490 |
|
|
d = mkdev(DEFAULT_DEV, &par, 0, bufsz, round, |
491 |
|
|
rate, hold, autovol); |
492 |
|
|
} |
493 |
|
|
if (mkopt(optarg, d, pmin, pmax, rmin, rmax, |
494 |
|
|
mode, vol, mmc, dup) == NULL) |
495 |
|
|
return 1; |
496 |
|
|
break; |
497 |
|
|
case 'q': |
498 |
|
|
mkport(optarg, hold); |
499 |
|
|
break; |
500 |
|
|
case 'a': |
501 |
|
|
hold = opt_onoff(); |
502 |
|
|
break; |
503 |
|
|
case 'w': |
504 |
|
|
autovol = opt_onoff(); |
505 |
|
|
break; |
506 |
|
|
case 'b': |
507 |
|
|
bufsz = strtonum(optarg, 1, RATE_MAX, &str); |
508 |
|
|
if (str) |
509 |
|
|
errx(1, "%s: buffer size is %s", optarg, str); |
510 |
|
|
break; |
511 |
|
|
case 'z': |
512 |
|
|
round = strtonum(optarg, 1, SHRT_MAX, &str); |
513 |
|
|
if (str) |
514 |
|
|
errx(1, "%s: block size is %s", optarg, str); |
515 |
|
|
break; |
516 |
|
|
case 'f': |
517 |
|
|
mkdev(optarg, &par, 0, bufsz, round, |
518 |
|
|
rate, hold, autovol); |
519 |
|
|
break; |
520 |
|
|
default: |
521 |
|
|
fputs(usagestr, stderr); |
522 |
|
|
return 1; |
523 |
|
|
} |
524 |
|
|
} |
525 |
|
|
argc -= optind; |
526 |
|
|
argv += optind; |
527 |
|
|
if (argc > 0) { |
528 |
|
|
fputs(usagestr, stderr); |
529 |
|
|
return 1; |
530 |
|
|
} |
531 |
|
|
if (dev_list == NULL) |
532 |
|
|
mkdev(DEFAULT_DEV, &par, 0, bufsz, round, rate, hold, autovol); |
533 |
|
|
for (d = dev_list; d != NULL; d = d->next) { |
534 |
|
|
if (opt_byname("default", d->num)) |
535 |
|
|
continue; |
536 |
|
|
if (mkopt("default", d, pmin, pmax, rmin, rmax, |
537 |
|
|
mode, vol, mmc, dup) == NULL) |
538 |
|
|
return 1; |
539 |
|
|
} |
540 |
|
|
|
541 |
|
|
setsig(); |
542 |
|
|
filelist_init(); |
543 |
|
|
|
544 |
|
|
if (!start_helper(background)) |
545 |
|
|
return 1; |
546 |
|
|
|
547 |
|
|
if (geteuid() == 0) { |
548 |
|
|
if ((pw = getpwnam(SNDIO_USER)) == NULL) |
549 |
|
|
errx(1, "unknown user %s", SNDIO_USER); |
550 |
|
|
} else |
551 |
|
|
pw = NULL; |
552 |
|
|
getbasepath(base); |
553 |
|
|
snprintf(path, SOCKPATH_MAX, "%s/" SOCKPATH_FILE "%u", base, unit); |
554 |
|
|
if (!listen_new_un(path)) |
555 |
|
|
return 1; |
556 |
|
|
for (ta = tcpaddr_list; ta != NULL; ta = ta->next) { |
557 |
|
|
if (!listen_new_tcp(ta->host, AUCAT_PORT + unit)) |
558 |
|
|
return 1; |
559 |
|
|
} |
560 |
|
|
for (l = listen_list; l != NULL; l = l->next) { |
561 |
|
|
if (!listen_init(l)) |
562 |
|
|
return 1; |
563 |
|
|
} |
564 |
|
|
midi_init(); |
565 |
|
|
for (p = port_list; p != NULL; p = p->next) { |
566 |
|
|
if (!port_init(p)) |
567 |
|
|
return 1; |
568 |
|
|
} |
569 |
|
|
for (d = dev_list; d != NULL; d = d->next) { |
570 |
|
|
if (!dev_init(d)) |
571 |
|
|
return 1; |
572 |
|
|
} |
573 |
|
|
if (background) { |
574 |
|
|
log_flush(); |
575 |
|
|
log_level = 0; |
576 |
|
|
if (daemon(0, 0) < 0) |
577 |
|
|
err(1, "daemon"); |
578 |
|
|
} |
579 |
|
|
if (pw != NULL) { |
580 |
|
|
if (setpriority(PRIO_PROCESS, 0, SNDIO_PRIO) < 0) |
581 |
|
|
err(1, "setpriority"); |
582 |
|
|
if (chroot(pw->pw_dir) != 0 || chdir("/") != 0) |
583 |
|
|
err(1, "cannot chroot to %s", pw->pw_dir); |
584 |
|
|
if (setgroups(1, &pw->pw_gid) || |
585 |
|
|
setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || |
586 |
|
|
setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) |
587 |
|
|
err(1, "cannot drop privileges"); |
588 |
|
|
} |
589 |
|
|
if (tcpaddr_list) { |
590 |
|
|
if (pledge("stdio audio recvfd unix inet flock rpath cpath wpath", NULL) == -1) |
591 |
|
|
err(1, "pledge"); |
592 |
|
|
} else { |
593 |
|
|
if (pledge("stdio audio recvfd unix flock rpath cpath wpath", NULL) == -1) |
594 |
|
|
err(1, "pledge"); |
595 |
|
|
} |
596 |
|
|
for (;;) { |
597 |
|
|
if (quit_flag) |
598 |
|
|
break; |
599 |
|
|
if (!fdpass_peer) |
600 |
|
|
break; |
601 |
|
|
if (!file_poll()) |
602 |
|
|
break; |
603 |
|
|
} |
604 |
|
|
stop_helper(); |
605 |
|
|
while (listen_list != NULL) |
606 |
|
|
listen_close(listen_list); |
607 |
|
|
while (sock_list != NULL) |
608 |
|
|
sock_close(sock_list); |
609 |
|
|
for (d = dev_list; d != NULL; d = d->next) |
610 |
|
|
dev_done(d); |
611 |
|
|
for (p = port_list; p != NULL; p = p->next) |
612 |
|
|
port_done(p); |
613 |
|
|
while (file_poll()) |
614 |
|
|
; /* nothing */ |
615 |
|
|
midi_done(); |
616 |
|
|
|
617 |
|
|
while (opt_list != NULL) |
618 |
|
|
opt_del(opt_list); |
619 |
|
|
while (dev_list) |
620 |
|
|
dev_del(dev_list); |
621 |
|
|
while (port_list) |
622 |
|
|
port_del(port_list); |
623 |
|
|
while (tcpaddr_list) { |
624 |
|
|
ta = tcpaddr_list; |
625 |
|
|
tcpaddr_list = ta->next; |
626 |
|
|
xfree(ta); |
627 |
|
|
} |
628 |
|
|
filelist_done(); |
629 |
|
|
unsetsig(); |
630 |
|
|
return 0; |
631 |
|
|
} |