Initial debian packaging
[osspd.git] / osspd.c
1 /*
2  * osspd - OSS Proxy Daemon: emulate OSS device using CUSE
3  *
4  * Copyright (C) 2008-2010  SUSE Linux Products GmbH
5  * Copyright (C) 2008-2010  Tejun Heo <tj@kernel.org>
6  *
7  * This file is released under the GPLv2.
8  */
9
10 #define FUSE_USE_VERSION 28
11 #define _GNU_SOURCE
12
13 #include <assert.h>
14 #include <cuse_lowlevel.h>
15 #include <fcntl.h>
16 #include <fuse_opt.h>
17 #include <libgen.h>
18 #include <limits.h>
19 #include <pthread.h>
20 #include <pwd.h>
21 #include <stdarg.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <signal.h>
25 #include <sys/mman.h>
26 #include <sys/stat.h>
27 #include <sys/epoll.h>
28 #include <sys/socket.h>
29 #include <sys/soundcard.h>
30 #include <sys/time.h>
31 #include <sys/wait.h>
32 #include <unistd.h>
33
34 #include "ossp.h"
35 #include "ossp-util.h"
36
37 /*
38  * MMAP support needs to be updated to the new fuse MMAP API.  Disable
39  * it for the time being.
40  */
41 #warning mmap support disabled for now
42 /* #define OSSP_MMAP */
43
44 #define DFL_MIXER_NAME          "mixer"
45 #define DFL_DSP_NAME            "dsp"
46 #define DFL_ADSP_NAME           "adsp"
47 #define STRFMT                  "S[%u/%d]"
48 #define STRID(os)               os->id, os->pid
49
50 #define dbg1_os(os, fmt, args...)       dbg1(STRFMT" "fmt, STRID(os) , ##args)
51 #define dbg0_os(os, fmt, args...)       dbg0(STRFMT" "fmt, STRID(os) , ##args)
52 #define warn_os(os, fmt, args...)       warn(STRFMT" "fmt, STRID(os) , ##args)
53 #define err_os(os, fmt, args...)        err(STRFMT" "fmt, STRID(os) , ##args)
54 #define warn_ose(os, err, fmt, args...) \
55         warn_e(err, STRFMT" "fmt, STRID(os) , ##args)
56 #define err_ose(os, err, fmt, args...)  \
57         err_e(err, STRFMT" "fmt, STRID(os) , ##args)
58
59 enum {
60         SNDRV_OSS_VERSION       = ((3<<16)|(8<<8)|(1<<4)|(0)),  /* 3.8.1a */
61         DFL_MIXER_MAJOR         = 14,
62         DFL_MIXER_MINOR         = 0,
63         DFL_DSP_MAJOR           = 14,
64         DFL_DSP_MINOR           = 3,
65         DFL_ADSP_MAJOR          = 14,
66         DFL_ADSP_MINOR          = 12,
67         DFL_MAX_STREAMS         = 128,
68         MIXER_PUT_DELAY         = 600,                  /* 10 mins */
69         /* DSPS_MMAP_SIZE / 2 must be multiple of SHMLBA */
70         DSPS_MMAP_SIZE          = 2 * (512 << 10),      /* 512k for each dir */
71 };
72
73 struct ossp_uid_cnt {
74         struct list_head        link;
75         uid_t                   uid;
76         unsigned                nr_os;
77 };
78
79 struct ossp_mixer {
80         pid_t                   pgrp;
81         struct list_head        link;
82         struct list_head        delayed_put_link;
83         unsigned                refcnt;
84         /* the following two fields are protected by mixer_mutex */
85         int                     vol[2][2];
86         int                     modify_counter;
87         time_t                  put_expires;
88 };
89
90 struct ossp_mixer_cmd {
91         struct ossp_mixer       *mixer;
92         struct ossp_mixer_arg   set;
93         int                     out_dir;
94         int                     rvol;
95 };
96
97 #define for_each_vol(i, j)                                              \
98         for (i = 0, j = 0; i < 2; j += i << 1, j++, i = j >> 1, j &= 1)
99
100 struct ossp_stream {
101         unsigned                id;     /* stream ID */
102         struct list_head        link;
103         struct list_head        pgrp_link;
104         struct list_head        notify_link;
105         unsigned                refcnt;
106         pthread_mutex_t         cmd_mutex;
107         pthread_mutex_t         mmap_mutex;
108         struct fuse_pollhandle  *ph;
109
110         /* stream owner info */
111         pid_t                   pid;
112         pid_t                   pgrp;
113         uid_t                   uid;
114         gid_t                   gid;
115
116         /* slave info */
117         pid_t                   slave_pid;
118         int                     cmd_fd;
119         int                     notify_tx;
120         int                     notify_rx;
121
122         /* the following dead flag is set asynchronously, keep it separate. */
123         int                     dead;
124
125         /* stream mixer state, protected by mixer_mutex */
126         int                     mixer_pending;
127         int                     vol[2][2];
128         int                     vol_set[2][2];
129
130         off_t                   mmap_off;
131         size_t                  mmap_size;
132
133         struct ossp_uid_cnt     *ucnt;
134         struct fuse_session     *se;    /* associated fuse session */
135         struct ossp_mixer       *mixer;
136 };
137
138 struct ossp_dsp_stream {
139         struct ossp_stream      os;
140         unsigned                rw;
141         unsigned                mmapped;
142         int                     nonblock;
143 };
144
145 #define os_to_dsps(_os)         container_of(_os, struct ossp_dsp_stream, os)
146
147 static unsigned max_streams;
148 static unsigned umax_streams;
149 static unsigned hashtbl_size;
150 static char dsp_slave_path[PATH_MAX];
151
152 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
153 static pthread_mutex_t mixer_mutex = PTHREAD_MUTEX_INITIALIZER;
154 static unsigned long *os_id_bitmap;
155 static unsigned nr_mixers;
156 static struct list_head *mixer_tbl;     /* indexed by PGRP */
157 static struct list_head *os_tbl;        /* indexed by ID */
158 static struct list_head *os_pgrp_tbl;   /* indexed by PGRP */
159 static struct list_head *os_notify_tbl; /* indexed by notify fd */
160 static LIST_HEAD(uid_cnt_list);
161 static int notify_epfd;                 /* epoll used to monitor notify fds */
162 static pthread_t notify_poller_thread;
163 static pthread_t slave_reaper_thread;
164 static pthread_t mixer_delayed_put_thread;
165 static pthread_t cuse_mixer_thread;
166 static pthread_t cuse_adsp_thread;
167 static pthread_cond_t notify_poller_kill_wait = PTHREAD_COND_INITIALIZER;
168 static pthread_cond_t slave_reaper_wait = PTHREAD_COND_INITIALIZER;
169 static LIST_HEAD(slave_corpse_list);
170 static LIST_HEAD(mixer_delayed_put_head); /* delayed reference */
171 static pthread_cond_t mixer_delayed_put_cond = PTHREAD_COND_INITIALIZER;
172
173 static int init_wait_fd = -1;
174 static int exit_on_idle;
175 static struct fuse_session *mixer_se;
176 static struct fuse_session *dsp_se;
177 static struct fuse_session *adsp_se;
178
179 static void put_os(struct ossp_stream *os);
180
181
182 /***************************************************************************
183  * Accessors
184  */
185
186 static struct list_head *mixer_tbl_head(pid_t pid)
187 {
188         return &mixer_tbl[pid % hashtbl_size];
189 }
190
191 static struct list_head *os_tbl_head(uint64_t id)
192 {
193         return &os_tbl[id % hashtbl_size];
194 }
195
196 static struct list_head *os_pgrp_tbl_head(pid_t pgrp)
197 {
198         return &os_pgrp_tbl[pgrp % hashtbl_size];
199 }
200
201 static struct list_head *os_notify_tbl_head(int notify_rx)
202 {
203         return &os_notify_tbl[notify_rx % hashtbl_size];
204 }
205
206 static struct ossp_mixer *find_mixer_locked(pid_t pgrp)
207 {
208         struct ossp_mixer *mixer;
209
210         list_for_each_entry(mixer, mixer_tbl_head(pgrp), link)
211                 if (mixer->pgrp == pgrp)
212                         return mixer;
213         return NULL;
214 }
215
216 static struct ossp_mixer *find_mixer(pid_t pgrp)
217 {
218         struct ossp_mixer *mixer;
219
220         pthread_mutex_lock(&mutex);
221         mixer = find_mixer_locked(pgrp);
222         pthread_mutex_unlock(&mutex);
223         return mixer;
224 }
225
226 static struct ossp_stream *find_os(unsigned id)
227 {
228         struct ossp_stream *os, *found = NULL;
229
230         pthread_mutex_lock(&mutex);
231         list_for_each_entry(os, os_tbl_head(id), link)
232                 if (os->id == id) {
233                         found = os;
234                         break;
235                 }
236         pthread_mutex_unlock(&mutex);
237         return found;
238 }
239
240 static struct ossp_stream *find_os_by_notify_rx(int notify_rx)
241 {
242         struct ossp_stream *os, *found = NULL;
243
244         pthread_mutex_lock(&mutex);
245         list_for_each_entry(os, os_notify_tbl_head(notify_rx), notify_link)
246                 if (os->notify_rx == notify_rx) {
247                         found = os;
248                         break;
249                 }
250         pthread_mutex_unlock(&mutex);
251         return found;
252 }
253
254
255 /***************************************************************************
256  * Command and ioctl helpers
257  */
258
259 static ssize_t exec_cmd_intern(struct ossp_stream *os, enum ossp_opcode opcode,
260         const void *carg, size_t carg_size, const void *din, size_t din_size,
261         void *rarg, size_t rarg_size, void *dout, size_t *dout_sizep, int fd)
262 {
263         size_t dout_size = dout_sizep ? *dout_sizep : 0;
264         struct ossp_cmd cmd = { .magic = OSSP_CMD_MAGIC, .opcode = opcode,
265                                  .din_size = din_size,
266                                  .dout_size = dout_size };
267         struct iovec iov = { &cmd, sizeof(cmd) };
268         struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1 };
269         struct ossp_reply reply = { };
270         char cmsg_buf[CMSG_SPACE(sizeof(fd))];
271         char reason[512];
272         int rc;
273
274         if (os->dead)
275                 return -EIO;
276
277         dbg1_os(os, "%s carg=%zu din=%zu rarg=%zu dout=%zu",
278                 ossp_cmd_str[opcode], carg_size, din_size, rarg_size,
279                 dout_size);
280
281         if (fd >= 0) {
282                 struct cmsghdr *cmsg;
283
284                 msg.msg_control = cmsg_buf;
285                 msg.msg_controllen = sizeof(cmsg_buf);
286                 cmsg = CMSG_FIRSTHDR(&msg);
287                 cmsg->cmsg_level = SOL_SOCKET;
288                 cmsg->cmsg_type = SCM_RIGHTS;
289                 cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
290                 *(int *)CMSG_DATA(cmsg) = fd;
291                 msg.msg_controllen = cmsg->cmsg_len;
292         }
293
294         if (sendmsg(os->cmd_fd, &msg, 0) <= 0) {
295                 rc = -errno;
296                 snprintf(reason, sizeof(reason), "command sendmsg failed: %s",
297                          strerror(-rc));
298                 goto fail;
299         }
300
301         if ((rc = write_fill(os->cmd_fd, carg, carg_size)) < 0 ||
302             (rc = write_fill(os->cmd_fd, din, din_size)) < 0) {
303                 snprintf(reason, sizeof(reason),
304                          "can't tranfer command argument and/or data: %s",
305                          strerror(-rc));
306                 goto fail;
307         }
308         if ((rc = read_fill(os->cmd_fd, &reply, sizeof(reply))) < 0) {
309                 snprintf(reason, sizeof(reason), "can't read reply: %s",
310                          strerror(-rc));
311                 goto fail;
312         }
313
314         if (reply.magic != OSSP_REPLY_MAGIC) {
315                 snprintf(reason, sizeof(reason),
316                          "reply magic mismatch %x != %x",
317                          reply.magic, OSSP_REPLY_MAGIC);
318                 rc = -EINVAL;
319                 goto fail;
320         }
321
322         if (reply.result < 0)
323                 goto out_unlock;
324
325         if (reply.dout_size > dout_size) {
326                 snprintf(reason, sizeof(reason),
327                          "data out size overflow %zu > %zu",
328                          reply.dout_size, dout_size);
329                 rc = -EINVAL;
330                 goto fail;
331         }
332
333         dout_size = reply.dout_size;
334         if (dout_sizep)
335                 *dout_sizep = dout_size;
336
337         if ((rc = read_fill(os->cmd_fd, rarg, rarg_size)) < 0 ||
338             (rc = read_fill(os->cmd_fd, dout, dout_size)) < 0) {
339                 snprintf(reason, sizeof(reason), "can't read data out: %s",
340                          strerror(-rc));
341                 goto fail;
342         }
343
344 out_unlock:
345         dbg1_os(os, "  completed, result=%d dout=%zu",
346                 reply.result, dout_size);
347         return reply.result;
348
349 fail:
350         warn_os(os, "communication with slave failed (%s)", reason);
351         os->dead = 1;
352         return rc;
353 }
354
355 static ssize_t exec_cmd(struct ossp_stream *os, enum ossp_opcode opcode,
356         const void *carg, size_t carg_size, const void *din, size_t din_size,
357         void *rarg, size_t rarg_size, void *dout, size_t *dout_sizep, int fd)
358 {
359         int is_mixer;
360         int i, j;
361         ssize_t ret, mret;
362
363         /* mixer command is handled exlicitly below */
364         is_mixer = opcode == OSSP_MIXER;
365         if (is_mixer) {
366                 ret = -pthread_mutex_trylock(&os->cmd_mutex);
367                 if (ret)
368                         return ret;
369         } else {
370                 pthread_mutex_lock(&os->cmd_mutex);
371
372                 ret = exec_cmd_intern(os, opcode, carg, carg_size,
373                                       din, din_size, rarg, rarg_size,
374                                       dout, dout_sizep, fd);
375         }
376
377         /* lazy mixer handling */
378         pthread_mutex_lock(&mixer_mutex);
379
380         if (os->mixer_pending) {
381                 struct ossp_mixer_arg marg;
382         repeat_mixer:
383                 /* we have mixer command pending */
384                 memcpy(marg.vol, os->vol_set, sizeof(os->vol_set));
385                 memset(os->vol_set, -1, sizeof(os->vol_set));
386
387                 pthread_mutex_unlock(&mixer_mutex);
388                 mret = exec_cmd_intern(os, OSSP_MIXER, &marg, sizeof(marg),
389                                        NULL, 0, &marg, sizeof(marg), NULL, NULL,
390                                        -1);
391                 pthread_mutex_lock(&mixer_mutex);
392
393                 /* was there mixer set request while executing mixer command? */
394                 for_each_vol(i, j)
395                         if (os->vol_set[i][j] >= 0)
396                                 goto repeat_mixer;
397
398                 /* update internal mixer state */
399                 if (mret == 0) {
400                         for_each_vol(i, j) {
401                                 if (marg.vol[i][j] >= 0) {
402                                         if (os->vol[i][j] != marg.vol[i][j])
403                                                 os->mixer->modify_counter++;
404                                         os->vol[i][j] = marg.vol[i][j];
405                                 }
406                         }
407                 }
408                 os->mixer_pending = 0;
409         }
410
411         pthread_mutex_unlock(&os->cmd_mutex);
412
413         /*
414          * mixer mutex must be released after cmd_mutex so that
415          * exec_mixer_cmd() can guarantee that mixer_pending flags
416          * will be handled immediately or when the currently
417          * in-progress command completes.
418          */
419         pthread_mutex_unlock(&mixer_mutex);
420
421         return is_mixer ? mret : ret;
422 }
423
424 static ssize_t exec_simple_cmd(struct ossp_stream *os,
425                                enum ossp_opcode opcode, void *carg, void *rarg)
426 {
427         return exec_cmd(os, opcode,
428                         carg, ossp_arg_sizes[opcode].carg_size, NULL, 0,
429                         rarg, ossp_arg_sizes[opcode].rarg_size, NULL, NULL, -1);
430 }
431
432 static int ioctl_prep_uarg(fuse_req_t req, void *in, size_t in_sz, void *out,
433                            size_t out_sz, void *uarg, const void *in_buf,
434                            size_t in_bufsz, size_t out_bufsz)
435 {
436         struct iovec in_iov = { }, out_iov = { };
437         int retry = 0;
438
439         if (in) {
440                 if (!in_bufsz) {
441                         in_iov.iov_base = uarg;
442                         in_iov.iov_len = in_sz;
443                         retry = 1;
444                 } else {
445                         assert(in_bufsz == in_sz);
446                         memcpy(in, in_buf, in_sz);
447                 }
448         }
449
450         if (out) {
451                 if (!out_bufsz) {
452                         out_iov.iov_base = uarg;
453                         out_iov.iov_len = out_sz;
454                         retry = 1;
455                 } else
456                         assert(out_bufsz == out_sz);
457         }
458
459         if (retry)
460                 fuse_reply_ioctl_retry(req, &in_iov, 1, &out_iov, 1);
461
462         return retry;
463 }
464
465 #define PREP_UARG(inp, outp) do {                                       \
466         if (ioctl_prep_uarg(req, (inp), sizeof(*(inp)),                 \
467                             (outp), sizeof(*(outp)), uarg,              \
468                             in_buf, in_bufsz, out_bufsz))               \
469                 return;                                                 \
470 } while (0)
471
472 #define IOCTL_RETURN(result, outp) do {                                 \
473         if ((outp) != NULL)                                             \
474                 fuse_reply_ioctl(req, result, (outp), sizeof(*(outp))); \
475         else                                                            \
476                 fuse_reply_ioctl(req, result, NULL, 0);                 \
477         return;                                                         \
478 } while (0)
479
480
481 /***************************************************************************
482  * Mixer implementation
483  */
484
485 static void put_mixer_real(struct ossp_mixer *mixer)
486 {
487         if (!--mixer->refcnt) {
488                 dbg0("DESTROY mixer(%d)", mixer->pgrp);
489                 list_del_init(&mixer->link);
490                 list_del_init(&mixer->delayed_put_link);
491                 free(mixer);
492                 nr_mixers--;
493
494                 /*
495                  * If exit_on_idle, mixer for pgrp0 is touched during
496                  * init and each stream has mixer attached.  As mixers
497                  * are destroyed after they have been idle for
498                  * MIXER_PUT_DELAY seconds, we can use it for idle
499                  * detection.  Note that this might race with
500                  * concurrent open.  The race is inherent.
501                  */
502                 if (exit_on_idle && !nr_mixers) {
503                         info("idle, exiting");
504                         exit(0);
505                 }
506         }
507 }
508
509 static struct ossp_mixer *get_mixer(pid_t pgrp)
510 {
511         struct ossp_mixer *mixer;
512
513         pthread_mutex_lock(&mutex);
514
515         /* is there a matching one? */
516         mixer = find_mixer_locked(pgrp);
517         if (mixer) {
518                 if (list_empty(&mixer->delayed_put_link))
519                         mixer->refcnt++;
520                 else
521                         list_del_init(&mixer->delayed_put_link);
522                 goto out_unlock;
523         }
524
525         /* reap delayed put list if there are too many mixers */
526         while (nr_mixers > 2 * max_streams &&
527                !list_empty(&mixer_delayed_put_head)) {
528                 struct ossp_mixer *mixer =
529                         list_first_entry(&mixer_delayed_put_head,
530                                          struct ossp_mixer, delayed_put_link);
531
532                 assert(mixer->refcnt == 1);
533                 put_mixer_real(mixer);
534         }
535
536         /* create a new one */
537         mixer = calloc(1, sizeof(*mixer));
538         if (!mixer) {
539                 warn("failed to allocate mixer for %d", pgrp);
540                 mixer = NULL;
541                 goto out_unlock;
542         }
543
544         mixer->pgrp = pgrp;
545         INIT_LIST_HEAD(&mixer->link);
546         INIT_LIST_HEAD(&mixer->delayed_put_link);
547         mixer->refcnt = 1;
548         memset(mixer->vol, -1, sizeof(mixer->vol));
549
550         list_add(&mixer->link, mixer_tbl_head(pgrp));
551         nr_mixers++;
552         dbg0("CREATE mixer(%d)", pgrp);
553
554 out_unlock:
555         pthread_mutex_unlock(&mutex);
556         return mixer;
557 }
558
559 static void put_mixer(struct ossp_mixer *mixer)
560 {
561         pthread_mutex_lock(&mutex);
562
563         if (mixer) {
564                 if (mixer->refcnt == 1) {
565                         struct timespec ts;
566
567                         clock_gettime(CLOCK_REALTIME, &ts);
568                         mixer->put_expires = ts.tv_sec + MIXER_PUT_DELAY;
569                         list_add_tail(&mixer->delayed_put_link,
570                                       &mixer_delayed_put_head);
571                         pthread_cond_signal(&mixer_delayed_put_cond);
572                 } else
573                         put_mixer_real(mixer);
574         }
575
576         pthread_mutex_unlock(&mutex);
577 }
578
579 static void *mixer_delayed_put_worker(void *arg)
580 {
581         struct ossp_mixer *mixer;
582         struct timespec ts;
583         time_t now;
584
585         pthread_mutex_lock(&mutex);
586 again:
587         clock_gettime(CLOCK_REALTIME, &ts);
588         now = ts.tv_sec;
589
590         mixer = NULL;
591         while (!list_empty(&mixer_delayed_put_head)) {
592                 mixer = list_first_entry(&mixer_delayed_put_head,
593                                          struct ossp_mixer, delayed_put_link);
594
595                 if (now <= mixer->put_expires)
596                         break;
597
598                 assert(mixer->refcnt == 1);
599                 put_mixer_real(mixer);
600                 mixer = NULL;
601         }
602
603         if (mixer) {
604                 ts.tv_sec = mixer->put_expires + 1;
605                 pthread_cond_timedwait(&mixer_delayed_put_cond, &mutex, &ts);
606         } else
607                 pthread_cond_wait(&mixer_delayed_put_cond, &mutex);
608
609         goto again;
610 }
611
612 static void init_mixer_cmd(struct ossp_mixer_cmd *mxcmd,
613                            struct ossp_mixer *mixer)
614 {
615         memset(mxcmd, 0, sizeof(*mxcmd));
616         memset(&mxcmd->set.vol, -1, sizeof(mxcmd->set.vol));
617         mxcmd->mixer = mixer;
618         mxcmd->out_dir = -1;
619 }
620
621 static int exec_mixer_cmd(struct ossp_mixer_cmd *mxcmd, struct ossp_stream *os)
622 {
623         int i, j, rc;
624
625         /*
626          * Set pending flags before trying to execute mixer command.
627          * Combined with lock release order in exec_cmd(), this
628          * guarantees that the mixer command will be executed
629          * immediately or when the current command completes.
630          */
631         pthread_mutex_lock(&mixer_mutex);
632         os->mixer_pending = 1;
633         for_each_vol(i, j)
634                 if (mxcmd->set.vol[i][j] >= 0)
635                         os->vol_set[i][j] = mxcmd->set.vol[i][j];
636         pthread_mutex_unlock(&mixer_mutex);
637
638         rc = exec_simple_cmd(os, OSSP_MIXER, NULL, NULL);
639         if (rc >= 0) {
640                 dbg0_os(os, "volume set=%d/%d:%d/%d get=%d/%d:%d/%d",
641                         mxcmd->set.vol[PLAY][LEFT], mxcmd->set.vol[PLAY][RIGHT],
642                         mxcmd->set.vol[REC][LEFT], mxcmd->set.vol[REC][RIGHT],
643                         os->vol[PLAY][LEFT], os->vol[PLAY][RIGHT],
644                         os->vol[REC][LEFT], os->vol[REC][RIGHT]);
645         } else if (rc != -EBUSY)
646                 warn_ose(os, rc, "mixer command failed");
647
648         return rc;
649 }
650
651 static void finish_mixer_cmd(struct ossp_mixer_cmd *mxcmd)
652 {
653         struct ossp_mixer *mixer = mxcmd->mixer;
654         struct ossp_stream *os;
655         int dir = mxcmd->out_dir;
656         int vol[2][2] = { };
657         int cnt[2][2] = { };
658         int i, j;
659
660         pthread_mutex_lock(&mixer_mutex);
661
662         /* get volume of all streams attached to this mixer */
663         pthread_mutex_lock(&mutex);
664         list_for_each_entry(os, os_pgrp_tbl_head(mixer->pgrp), pgrp_link) {
665                 if (os->pgrp != mixer->pgrp)
666                         continue;
667                 for_each_vol(i, j) {
668                         if (os->vol[i][j] < 0)
669                                 continue;
670                         vol[i][j] += os->vol[i][j];
671                         cnt[i][j]++;
672                 }
673         }
674         pthread_mutex_unlock(&mutex);
675
676         /* calculate the summary volume values */
677         for_each_vol(i, j) {
678                 if (mxcmd->set.vol[i][j] >= 0)
679                         vol[i][j] = mxcmd->set.vol[i][j];
680                 else if (cnt[i][j])
681                         vol[i][j] = vol[i][j] / cnt[i][j];
682                 else if (mixer->vol[i][j] >= 0)
683                         vol[i][j] = mixer->vol[i][j];
684                 else
685                         vol[i][j] = 100;
686
687                 vol[i][j] = min(max(0, vol[i][j]), 100);
688         }
689
690         if (dir >= 0)
691                 mxcmd->rvol = vol[dir][LEFT] | (vol[dir][RIGHT] << 8);
692
693         pthread_mutex_unlock(&mixer_mutex);
694 }
695
696 static void mixer_simple_ioctl(fuse_req_t req, struct ossp_mixer *mixer,
697                                unsigned cmd, void *uarg, const void *in_buf,
698                                size_t in_bufsz, size_t out_bufsz,
699                                int *not_minep)
700 {
701         const char *id = "OSS Proxy", *name = "Mixer";
702         int i;
703
704         switch (cmd) {
705         case SOUND_MIXER_INFO: {
706                 struct mixer_info info = { };
707
708                 PREP_UARG(NULL, &info);
709                 strncpy(info.id, id, sizeof(info.id) - 1);
710                 strncpy(info.name, name, sizeof(info.name) - 1);
711                 info.modify_counter = mixer->modify_counter;
712                 IOCTL_RETURN(0, &info);
713         }
714
715         case SOUND_OLD_MIXER_INFO: {
716                 struct _old_mixer_info info = { };
717
718                 PREP_UARG(NULL, &info);
719                 strncpy(info.id, id, sizeof(info.id) - 1);
720                 strncpy(info.name, name, sizeof(info.name) - 1);
721                 IOCTL_RETURN(0, &info);
722         }
723
724         case OSS_GETVERSION:
725                 i = SNDRV_OSS_VERSION;
726                 goto puti;
727         case SOUND_MIXER_READ_DEVMASK:
728         case SOUND_MIXER_READ_STEREODEVS:
729                 i = SOUND_MASK_PCM | SOUND_MASK_IGAIN;
730                 goto puti;
731         case SOUND_MIXER_READ_CAPS:
732                 i = SOUND_CAP_EXCL_INPUT;
733                 goto puti;
734         case SOUND_MIXER_READ_RECMASK:
735         case SOUND_MIXER_READ_RECSRC:
736                 i = SOUND_MASK_IGAIN;
737                 goto puti;
738         puti:
739                 PREP_UARG(NULL, &i);
740                 IOCTL_RETURN(0, &i);
741
742         case SOUND_MIXER_WRITE_RECSRC:
743                 IOCTL_RETURN(0, NULL);
744
745         default:
746                 *not_minep = 1;
747                 return;
748         }
749         assert(0);
750 }
751
752 static void mixer_do_ioctl(fuse_req_t req, struct ossp_mixer *mixer,
753                            unsigned cmd, void *uarg, const void *in_buf,
754                            size_t in_bufsz, size_t out_bufsz)
755 {
756         struct ossp_mixer_cmd mxcmd;
757         struct ossp_stream *os, **osa;
758         int not_mine = 0;
759         int slot = cmd & 0xff, dir;
760         int nr_os;
761         int i, rc;
762
763         mixer_simple_ioctl(req, mixer, cmd, uarg, in_buf, in_bufsz, out_bufsz,
764                            &not_mine);
765         if (!not_mine)
766                 return;
767
768         rc = -ENXIO;
769         if (!(cmd & (SIOC_IN | SIOC_OUT)))
770                 goto err;
771
772         /*
773          * Okay, it's not one of the easy ones.  Build mxcmd for
774          * actual volume control.
775          */
776         if (cmd & SIOC_IN)
777                 PREP_UARG(&i, &i);
778         else
779                 PREP_UARG(NULL, &i);
780
781         switch (slot) {
782         case SOUND_MIXER_PCM:
783                 dir = PLAY;
784                 break;
785         case SOUND_MIXER_IGAIN:
786                 dir = REC;
787                 break;
788         default:
789                 i = 0;
790                 IOCTL_RETURN(0, &i);
791         }
792
793         init_mixer_cmd(&mxcmd, mixer);
794
795         if (cmd & SIOC_IN) {
796                 unsigned l, r;
797
798                 rc = -EINVAL;
799                 l = i & 0xff;
800                 r = (i >> 8) & 0xff;
801                 if (l > 100 || r > 100)
802                         goto err;
803
804                 mixer->vol[dir][LEFT] = mxcmd.set.vol[dir][LEFT] = l;
805                 mixer->vol[dir][RIGHT] = mxcmd.set.vol[dir][RIGHT] = r;
806         }
807         mxcmd.out_dir = dir;
808
809         /*
810          * Apply volume conrol
811          */
812         /* acquire target streams */
813         pthread_mutex_lock(&mutex);
814         osa = calloc(max_streams, sizeof(osa[0]));
815         if (!osa) {
816                 pthread_mutex_unlock(&mutex);
817                 rc = -ENOMEM;
818                 goto err;
819         }
820
821         nr_os = 0;
822         list_for_each_entry(os, os_pgrp_tbl_head(mixer->pgrp), pgrp_link) {
823                 if (os->pgrp == mixer->pgrp) {
824                         osa[nr_os++] = os;
825                         os->refcnt++;
826                 }
827         }
828
829         pthread_mutex_unlock(&mutex);
830
831         /* execute mxcmd for each stream and put it */
832         for (i = 0; i < nr_os; i++) {
833                 exec_mixer_cmd(&mxcmd, osa[i]);
834                 put_os(osa[i]);
835         }
836
837         finish_mixer_cmd(&mxcmd);
838         free(osa);
839
840         IOCTL_RETURN(0, out_bufsz ? &mxcmd.rvol : NULL);
841
842 err:
843         fuse_reply_err(req, -rc);
844 }
845
846 static void mixer_open(fuse_req_t req, struct fuse_file_info *fi)
847 {
848         pid_t pid = fuse_req_ctx(req)->pid, pgrp;
849         struct ossp_mixer *mixer;
850         int rc;
851
852         rc = get_proc_self_info(pid, &pgrp, NULL, 0);
853         if (rc) {
854                 err_e(rc, "get_proc_self_info(%d) failed", pid);
855                 fuse_reply_err(req, -rc);
856                 return;
857         }
858
859         mixer = get_mixer(pgrp);
860         fi->fh = pgrp;
861
862         if (mixer)
863                 fuse_reply_open(req, fi);
864         else
865                 fuse_reply_err(req, ENOMEM);
866 }
867
868 static void mixer_ioctl(fuse_req_t req, int signed_cmd, void *uarg,
869                         struct fuse_file_info *fi, unsigned int flags,
870                         const void *in_buf, size_t in_bufsz, size_t out_bufsz)
871 {
872         struct ossp_mixer *mixer;
873
874         mixer = find_mixer(fi->fh);
875         if (!mixer) {
876                 fuse_reply_err(req, EBADF);
877                 return;
878         }
879
880         mixer_do_ioctl(req, mixer, signed_cmd, uarg, in_buf, in_bufsz,
881                        out_bufsz);
882 }
883
884 static void mixer_release(fuse_req_t req, struct fuse_file_info *fi)
885 {
886         struct ossp_mixer *mixer;
887
888         mixer = find_mixer(fi->fh);
889         if (mixer) {
890                 put_mixer(mixer);
891                 fuse_reply_err(req, 0);
892         } else
893                 fuse_reply_err(req, EBADF);
894 }
895
896
897 /***************************************************************************
898  * Stream implementation
899  */
900
901 static int alloc_os(size_t stream_size, size_t mmap_size, pid_t pid, uid_t pgrp,
902                     uid_t uid, gid_t gid, int cmd_sock,
903                     const int *notify, struct fuse_session *se,
904                     struct ossp_stream **osp)
905 {
906         struct ossp_uid_cnt *tmp_ucnt, *ucnt = NULL;
907         struct ossp_stream *os;
908         int rc;
909
910         assert(stream_size >= sizeof(struct ossp_stream));
911         os = calloc(1, stream_size);
912         if (!os)
913                 return -ENOMEM;
914
915         INIT_LIST_HEAD(&os->link);
916         INIT_LIST_HEAD(&os->pgrp_link);
917         INIT_LIST_HEAD(&os->notify_link);
918         os->refcnt = 1;
919
920         rc = -pthread_mutex_init(&os->cmd_mutex, NULL);
921         if (rc)
922                 goto err_free;
923
924         rc = -pthread_mutex_init(&os->mmap_mutex, NULL);
925         if (rc)
926                 goto err_destroy_cmd_mutex;
927
928         pthread_mutex_lock(&mutex);
929
930         list_for_each_entry(tmp_ucnt, &uid_cnt_list, link)
931                 if (tmp_ucnt->uid == uid) {
932                         ucnt = tmp_ucnt;
933                         break;
934                 }
935         if (!ucnt) {
936                 rc = -ENOMEM;
937                 ucnt = calloc(1, sizeof(*ucnt));
938                 if (!ucnt)
939                         goto err_unlock;
940                 ucnt->uid = uid;
941                 list_add(&ucnt->link, &uid_cnt_list);
942         }
943
944         rc = -EBUSY;
945         if (ucnt->nr_os + 1 > umax_streams)
946                 goto err_unlock;
947
948         /* everything looks fine, allocate id and init stream */
949         rc = -EBUSY;
950         os->id = find_next_zero_bit(os_id_bitmap, max_streams, 0);
951         if (os->id >= max_streams)
952                 goto err_unlock;
953         __set_bit(os->id, os_id_bitmap);
954
955         os->cmd_fd = cmd_sock;
956         os->notify_tx = notify[1];
957         os->notify_rx = notify[0];
958         os->pid = pid;
959         os->pgrp = pgrp;
960         os->uid = uid;
961         os->gid = gid;
962         if (mmap_size) {
963                 os->mmap_off = os->id * mmap_size;
964                 os->mmap_size = mmap_size;
965         }
966         os->ucnt = ucnt;
967         os->se = se;
968
969         memset(os->vol, -1, sizeof(os->vol));
970         memset(os->vol_set, -1, sizeof(os->vol));
971
972         list_add(&os->link, os_tbl_head(os->id));
973         list_add(&os->pgrp_link, os_pgrp_tbl_head(os->pgrp));
974
975         ucnt->nr_os++;
976         *osp = os;
977         pthread_mutex_unlock(&mutex);
978         return 0;
979
980 err_unlock:
981         pthread_mutex_unlock(&mutex);
982         pthread_mutex_destroy(&os->mmap_mutex);
983 err_destroy_cmd_mutex:
984         pthread_mutex_destroy(&os->cmd_mutex);
985 err_free:
986         free(os);
987         return rc;
988 }
989
990 static void shutdown_notification(struct ossp_stream *os)
991 {
992         struct ossp_notify obituary = { .magic = OSSP_NOTIFY_MAGIC,
993                                         .opcode = OSSP_NOTIFY_OBITUARY };
994         ssize_t ret;
995
996         /*
997          * Shutdown notification for this stream.  We politely ask
998          * notify_poller to shut the receive side down to avoid racing
999          * with it.
1000          */
1001         while (os->notify_rx >= 0) {
1002                 ret = write(os->notify_tx, &obituary, sizeof(obituary));
1003                 if (ret <= 0) {
1004                         if (ret == 0)
1005                                 warn_os(os, "unexpected EOF on notify_tx");
1006                         else if (errno != EPIPE)
1007                                 warn_ose(os, -errno,
1008                                          "unexpected error on notify_tx");
1009                         close(os->notify_rx);
1010                         os->notify_rx = -1;
1011                         break;
1012                 }
1013
1014                 if (ret != sizeof(obituary))
1015                         warn_os(os, "short transfer on notify_tx");
1016                 pthread_cond_wait(&notify_poller_kill_wait, &mutex);
1017         }
1018 }
1019
1020 static void put_os(struct ossp_stream *os)
1021 {
1022         if (!os)
1023                 return;
1024
1025         pthread_mutex_lock(&mutex);
1026
1027         assert(os->refcnt);
1028         if (--os->refcnt) {
1029                 pthread_mutex_unlock(&mutex);
1030                 return;
1031         }
1032
1033         os->dead = 1;
1034         shutdown_notification(os);
1035
1036         dbg0_os(os, "DESTROY");
1037
1038         list_del_init(&os->link);
1039         list_del_init(&os->pgrp_link);
1040         list_del_init(&os->notify_link);
1041         os->ucnt->nr_os--;
1042
1043         pthread_mutex_unlock(&mutex);
1044
1045         close(os->cmd_fd);
1046         close(os->notify_tx);
1047         put_mixer(os->mixer);
1048         pthread_mutex_destroy(&os->cmd_mutex);
1049         pthread_mutex_destroy(&os->mmap_mutex);
1050
1051         pthread_mutex_lock(&mutex);
1052         dbg1_os(os, "stream dead, requesting reaping");
1053         list_add_tail(&os->link, &slave_corpse_list);
1054         pthread_cond_signal(&slave_reaper_wait);
1055         pthread_mutex_unlock(&mutex);
1056 }
1057
1058 static void set_extra_env(pid_t pid)
1059 {
1060         char procenviron[32];
1061         const int step = 1024;
1062         char *data = malloc(step + 1);
1063         int ofs = 0;
1064         int fd;
1065         int ret;
1066
1067         if (!data)
1068                 return;
1069
1070         sprintf(procenviron, "/proc/%d/environ", pid);
1071         fd = open(procenviron, O_RDONLY);
1072         if (fd < 0)
1073                 return;
1074
1075         /*
1076          * There should really be a 'read whole file to a newly allocated
1077          * buffer' function.
1078          */
1079         while ((ret = read(fd, data + ofs, step)) > 0) {
1080                 char *newdata;
1081                 ofs += ret;
1082                 newdata = realloc(data, ofs + step + 1);
1083                 if (!newdata) {
1084                         ret = -1;
1085                         break;
1086                 }
1087                 data = newdata;
1088         }
1089         if (ret == 0) {
1090                 char *ptr = data;
1091                 /* Append the extra 0 for end condition */
1092                 data[ofs] = 0;
1093
1094                 while ((ret = strlen(ptr)) > 0) {
1095                         /*
1096                          * Copy all PULSE variables and DISPLAY so that
1097                          * ssh -X remotehost 'mplayer -ao oss' will work
1098                          */
1099                         if (!strncmp(ptr, "DISPLAY=", 8) ||
1100                             !strncmp(ptr, "PULSE_", 6))
1101                                 putenv(ptr);
1102                         ptr += ret + 1;
1103                 }
1104         }
1105
1106         free(data);
1107         close(fd);
1108 }
1109
1110 static int create_os(const char *slave_path,
1111                      size_t stream_size, size_t mmap_size,
1112                      pid_t pid, pid_t pgrp, uid_t uid, gid_t gid,
1113                      struct fuse_session *se, struct ossp_stream **osp)
1114 {
1115         static pthread_mutex_t create_mutex = PTHREAD_MUTEX_INITIALIZER;
1116         int cmd_sock[2] = { -1, -1 };
1117         int notify_sock[2] = { -1, -1 };
1118         struct ossp_stream *os = NULL;
1119         struct epoll_event ev = { };
1120         int i, rc;
1121
1122         /*
1123          * Only one thread can be creating a stream.  This is to avoid
1124          * leaking unwanted fds into slaves.
1125          */
1126         pthread_mutex_lock(&create_mutex);
1127
1128         /* prepare communication channels */
1129         if (socketpair(AF_UNIX, SOCK_STREAM, 0, cmd_sock) ||
1130             socketpair(AF_UNIX, SOCK_STREAM, 0, notify_sock)) {
1131                 rc = -errno;
1132                 warn_e(rc, "failed to create slave command channel");
1133                 goto close_all;
1134         }
1135
1136         if (fcntl(notify_sock[0], F_SETFL, O_NONBLOCK) < 0) {
1137                 rc = -errno;
1138                 warn_e(rc, "failed to set NONBLOCK on notify sock");
1139                 goto close_all;
1140         }
1141
1142         /*
1143          * Alloc stream which will be responsible for all server side
1144          * resources from now on.
1145          */
1146         rc = alloc_os(stream_size, mmap_size, pid, pgrp, uid, gid, cmd_sock[0],
1147                       notify_sock, se, &os);
1148         if (rc) {
1149                 warn_e(rc, "failed to allocate stream for %d", pid);
1150                 goto close_all;
1151         }
1152
1153         rc = -ENOMEM;
1154         os->mixer = get_mixer(pgrp);
1155         if (!os->mixer)
1156                 goto put_os;
1157
1158         /*
1159          * Register notification.  If successful, notify_poller has
1160          * custody of notify_rx fd.
1161          */
1162         pthread_mutex_lock(&mutex);
1163         list_add(&os->notify_link, os_notify_tbl_head(os->notify_rx));
1164         pthread_mutex_unlock(&mutex);
1165
1166         ev.events = EPOLLIN;
1167         ev.data.fd = notify_sock[0];
1168         if (epoll_ctl(notify_epfd, EPOLL_CTL_ADD, notify_sock[0], &ev)) {
1169                 /*
1170                  * Without poller watching this notify sock, poller
1171                  * shutdown sequence in shutdown_notification() can't
1172                  * be used.  Kill notification rx manually.
1173                  */
1174                 rc = -errno;
1175                 warn_ose(os, rc, "failed to add notify epoll");
1176                 close(os->notify_rx);
1177                 os->notify_rx = -1;
1178                 goto put_os;
1179         }
1180
1181         /* start slave */
1182         os->slave_pid = fork();
1183         if (os->slave_pid < 0) {
1184                 rc = -errno;
1185                 warn_ose(os, rc, "failed to fork slave");
1186                 goto put_os;
1187         }
1188
1189         if (os->slave_pid == 0) {
1190                 /* child */
1191                 char id_str[2][16], fd_str[3][16];
1192                 char mmap_off_str[32], mmap_size_str[32];
1193                 char log_str[16], slave_path_copy[PATH_MAX];
1194                 char *argv[] = { slave_path_copy, "-u", id_str[0],
1195                                  "-g", id_str[1], "-c", fd_str[0],
1196                                  "-n", fd_str[1], "-m", fd_str[2],
1197                                  "-o", mmap_off_str, "-s", mmap_size_str,
1198                                  "-l", log_str, NULL, NULL };
1199                 struct passwd *pwd;
1200
1201                 /* drop stuff we don't need */
1202                 if (close(cmd_sock[0]) || close(notify_sock[0]))
1203                         fatal_e(-errno, "failed to close server pipe fds");
1204
1205 #ifdef OSSP_MMAP
1206                 if (!mmap_size)
1207                         close(fuse_mmap_fd(se));
1208 #endif
1209
1210                 clearenv();
1211                 pwd = getpwuid(os->uid);
1212                 if (pwd) {
1213                         setenv("LOGNAME", pwd->pw_name, 1);
1214                         setenv("USER", pwd->pw_name, 1);
1215                         setenv("HOME", pwd->pw_dir, 1);
1216                 }
1217                 /* Set extra environment variables from the caller */
1218                 set_extra_env(pid);
1219
1220                 /* prep and exec */
1221                 slave_path_copy[sizeof(slave_path_copy) - 1] = '\0';
1222                 strncpy(slave_path_copy, slave_path, sizeof(slave_path_copy) - 1);
1223                 if (slave_path_copy[sizeof(slave_path_copy) - 1] != '\0') {
1224                         rc = -errno;
1225                         err_ose(os, rc, "slave path too long");
1226                         goto child_fail;
1227                 }
1228
1229                 snprintf(id_str[0], sizeof(id_str[0]), "%d", os->uid);
1230                 snprintf(id_str[1], sizeof(id_str[0]), "%d", os->gid);
1231                 snprintf(fd_str[0], sizeof(fd_str[0]), "%d", cmd_sock[1]);
1232                 snprintf(fd_str[1], sizeof(fd_str[1]), "%d", notify_sock[1]);
1233                 snprintf(fd_str[2], sizeof(fd_str[2]), "%d",
1234 #ifdef OSSP_MMAP
1235                          mmap_size ? fuse_mmap_fd(se) :
1236 #endif
1237                          -1);
1238                 snprintf(mmap_off_str, sizeof(mmap_off_str), "0x%llx",
1239                          (unsigned long long)os->mmap_off);
1240                 snprintf(mmap_size_str, sizeof(mmap_size_str), "0x%zx",
1241                          mmap_size);
1242                 snprintf(log_str, sizeof(log_str), "%d", ossp_log_level);
1243                 if (ossp_log_timestamp)
1244                         argv[ARRAY_SIZE(argv) - 2] = "-t";
1245
1246                 execv(slave_path, argv);
1247                 rc = -errno;
1248                 err_ose(os, rc, "execv failed for <%d>", pid);
1249         child_fail:
1250                 _exit(1);
1251         }
1252
1253         /* turn on CLOEXEC on all server side fds */
1254         if (fcntl(os->cmd_fd, F_SETFD, FD_CLOEXEC) < 0 ||
1255             fcntl(os->notify_tx, F_SETFD, FD_CLOEXEC) < 0 ||
1256             fcntl(os->notify_rx, F_SETFD, FD_CLOEXEC) < 0) {
1257                 rc = -errno;
1258                 err_ose(os, rc, "failed to set CLOEXEC on server side fds");
1259                 goto put_os;
1260         }
1261
1262         dbg0_os(os, "CREATE slave=%d %s", os->slave_pid, slave_path);
1263         dbg0_os(os, "  client=%d cmd=%d:%d notify=%d:%d mmap=%d:0x%llx:%zu",
1264                 pid, cmd_sock[0], cmd_sock[1], notify_sock[0], notify_sock[1],
1265 #ifdef OSSP_MMAP
1266                 os->mmap_size ? fuse_mmap_fd(se) :
1267 #endif
1268                 -1,
1269                 (unsigned long long)os->mmap_off, os->mmap_size);
1270
1271         *osp = os;
1272         rc = 0;
1273         goto close_client_fds;
1274
1275 put_os:
1276         put_os(os);
1277 close_client_fds:
1278         close(cmd_sock[1]);
1279         pthread_mutex_unlock(&create_mutex);
1280         return rc;
1281
1282 close_all:
1283         for (i = 0; i < 2; i++) {
1284                 close(cmd_sock[i]);
1285                 close(notify_sock[i]);
1286         }
1287         pthread_mutex_unlock(&create_mutex);
1288         return rc;
1289 }
1290
1291 static void dsp_open_common(fuse_req_t req, struct fuse_file_info *fi,
1292                             struct fuse_session *se)
1293 {
1294         const struct fuse_ctx *fuse_ctx = fuse_req_ctx(req);
1295         struct ossp_dsp_open_arg arg = { };
1296         struct ossp_stream *os = NULL;
1297         struct ossp_mixer *mixer;
1298         struct ossp_dsp_stream *dsps;
1299         struct ossp_mixer_cmd mxcmd;
1300         pid_t pgrp;
1301         ssize_t ret;
1302
1303         ret = get_proc_self_info(fuse_ctx->pid, &pgrp, NULL, 0);
1304         if (ret) {
1305                 err_e(ret, "get_proc_self_info(%d) failed", fuse_ctx->pid);
1306                 goto err;
1307         }
1308
1309         ret = create_os(dsp_slave_path, sizeof(*dsps), DSPS_MMAP_SIZE,
1310                         fuse_ctx->pid, pgrp, fuse_ctx->uid, fuse_ctx->gid,
1311                         se, &os);
1312         if (ret)
1313                 goto err;
1314         dsps = os_to_dsps(os);
1315         mixer = os->mixer;
1316
1317         switch (fi->flags & O_ACCMODE) {
1318         case O_WRONLY:
1319                 dsps->rw |= 1 << PLAY;
1320                 break;
1321         case O_RDONLY:
1322                 dsps->rw |= 1 << REC;
1323                 break;
1324         case O_RDWR:
1325                 dsps->rw |= (1 << PLAY) | (1 << REC);
1326                 break;
1327         default:
1328                 assert(0);
1329         }
1330
1331         arg.flags = fi->flags;
1332         arg.opener_pid = os->pid;
1333         ret = exec_simple_cmd(&dsps->os, OSSP_DSP_OPEN, &arg, NULL);
1334         if (ret < 0) {
1335                 put_os(os);
1336                 goto err;
1337         }
1338
1339         memcpy(os->vol, mixer->vol, sizeof(os->vol));
1340         if (os->vol[PLAY][0] >= 0 || os->vol[REC][0] >= 0) {
1341                 init_mixer_cmd(&mxcmd, mixer);
1342                 memcpy(mxcmd.set.vol, os->vol, sizeof(os->vol));
1343                 exec_mixer_cmd(&mxcmd, os);
1344                 finish_mixer_cmd(&mxcmd);
1345         }
1346
1347         fi->direct_io = 1;
1348         fi->nonseekable = 1;
1349         fi->fh = os->id;
1350
1351         fuse_reply_open(req, fi);
1352         return;
1353
1354 err:
1355         fuse_reply_err(req, -ret);
1356 }
1357
1358 static void dsp_open(fuse_req_t req, struct fuse_file_info *fi)
1359 {
1360         dsp_open_common(req, fi, dsp_se);
1361 }
1362
1363 static void adsp_open(fuse_req_t req, struct fuse_file_info *fi)
1364 {
1365         dsp_open_common(req, fi, adsp_se);
1366 }
1367
1368 static void dsp_release(fuse_req_t req, struct fuse_file_info *fi)
1369 {
1370         struct ossp_stream *os;
1371
1372         os = find_os(fi->fh);
1373         if (os) {
1374                 put_os(os);
1375                 fuse_reply_err(req, 0);
1376         } else
1377                 fuse_reply_err(req, EBADF);
1378 }
1379
1380 static void dsp_read(fuse_req_t req, size_t size, off_t off,
1381                      struct fuse_file_info *fi)
1382 {
1383         struct ossp_dsp_rw_arg arg = { };
1384         struct ossp_stream *os;
1385         struct ossp_dsp_stream *dsps;
1386         void *buf = NULL;
1387         ssize_t ret;
1388
1389         ret = -EBADF;
1390         os = find_os(fi->fh);
1391         if (!os)
1392                 goto out;
1393         dsps = os_to_dsps(os);
1394
1395         ret = -EINVAL;
1396         if (!(dsps->rw & (1 << REC)))
1397                 goto out;
1398
1399         ret = -ENXIO;
1400         if (dsps->mmapped)
1401                 goto out;
1402
1403         ret = -ENOMEM;
1404         buf = malloc(size);
1405         if (!buf)
1406                 goto out;
1407
1408         arg.nonblock = (fi->flags & O_NONBLOCK) || dsps->nonblock;
1409
1410         ret = exec_cmd(os, OSSP_DSP_READ, &arg, sizeof(arg),
1411                        NULL, 0, NULL, 0, buf, &size, -1);
1412 out:
1413         if (ret >= 0)
1414                 fuse_reply_buf(req, buf, size);
1415         else
1416                 fuse_reply_err(req, -ret);
1417
1418         free(buf);
1419 }
1420
1421 static void dsp_write(fuse_req_t req, const char *buf, size_t size, off_t off,
1422                       struct fuse_file_info *fi)
1423 {
1424         struct ossp_dsp_rw_arg arg = { };
1425         struct ossp_stream *os;
1426         struct ossp_dsp_stream *dsps;
1427         ssize_t ret;
1428
1429         ret = -EBADF;
1430         os = find_os(fi->fh);
1431         if (!os)
1432                 goto out;
1433         dsps = os_to_dsps(os);
1434
1435         ret = -EINVAL;
1436         if (!(dsps->rw & (1 << PLAY)))
1437                 goto out;
1438
1439         ret = -ENXIO;
1440         if (dsps->mmapped)
1441                 goto out;
1442
1443         arg.nonblock = (fi->flags & O_NONBLOCK) || dsps->nonblock;
1444
1445         ret = exec_cmd(os, OSSP_DSP_WRITE, &arg, sizeof(arg),
1446                        buf, size, NULL, 0, NULL, NULL, -1);
1447 out:
1448         if (ret >= 0)
1449                 fuse_reply_write(req, ret);
1450         else
1451                 fuse_reply_err(req, -ret);
1452 }
1453
1454 static void dsp_poll(fuse_req_t req, struct fuse_file_info *fi,
1455                      struct fuse_pollhandle *ph)
1456 {
1457         int notify = ph != NULL;
1458         unsigned revents = 0;
1459         struct ossp_stream *os;
1460         ssize_t ret;
1461
1462         ret = -EBADF;
1463         os = find_os(fi->fh);
1464         if (!os)
1465                 goto out;
1466
1467         if (ph) {
1468                 pthread_mutex_lock(&mutex);
1469                 if (os->ph)
1470                         fuse_pollhandle_destroy(os->ph);
1471                 os->ph = ph;
1472                 pthread_mutex_unlock(&mutex);
1473         }
1474
1475         ret = exec_simple_cmd(os, OSSP_DSP_POLL, &notify, &revents);
1476 out:
1477         if (ret >= 0)
1478                 fuse_reply_poll(req, revents);
1479         else
1480                 fuse_reply_err(req, -ret);
1481 }
1482
1483 static void dsp_ioctl(fuse_req_t req, int signed_cmd, void *uarg,
1484                       struct fuse_file_info *fi, unsigned int flags,
1485                       const void *in_buf, size_t in_bufsz, size_t out_bufsz)
1486 {
1487         /* some ioctl constants are long and has the highest bit set */
1488         unsigned cmd = signed_cmd;
1489         struct ossp_stream *os;
1490         struct ossp_dsp_stream *dsps;
1491         enum ossp_opcode op;
1492         ssize_t ret;
1493         int i;
1494
1495         ret = -EBADF;
1496         os = find_os(fi->fh);
1497         if (!os)
1498                 goto err;
1499         dsps = os_to_dsps(os);
1500
1501         /* mixer commands are allowed on DSP devices */
1502         if (((cmd >> 8) & 0xff) == 'M') {
1503                 mixer_do_ioctl(req, os->mixer, cmd, uarg, in_buf, in_bufsz,
1504                                out_bufsz);
1505                 return;
1506         }
1507
1508         /* and the rest */
1509         switch (cmd) {
1510         case OSS_GETVERSION:
1511                 i = SNDRV_OSS_VERSION;
1512                 PREP_UARG(NULL, &i);
1513                 IOCTL_RETURN(0, &i);
1514
1515         case SNDCTL_DSP_GETCAPS:
1516                 i = DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER |
1517 #ifdef OSSP_MMAP
1518                         DSP_CAP_MMAP |
1519 #endif
1520                         DSP_CAP_MULTI;
1521                 PREP_UARG(NULL, &i);
1522                 IOCTL_RETURN(0, &i);
1523
1524         case SNDCTL_DSP_NONBLOCK:
1525                 dsps->nonblock = 1;
1526                 ret = 0;
1527                 IOCTL_RETURN(0, NULL);
1528
1529         case SNDCTL_DSP_RESET:          op = OSSP_DSP_RESET;            goto nd;
1530         case SNDCTL_DSP_SYNC:           op = OSSP_DSP_SYNC;             goto nd;
1531         case SNDCTL_DSP_POST:           op = OSSP_DSP_POST;             goto nd;
1532         nd:
1533                 ret = exec_simple_cmd(&dsps->os, op, NULL, NULL);
1534                 if (ret)
1535                         goto err;
1536                 IOCTL_RETURN(0, NULL);
1537
1538         case SOUND_PCM_READ_RATE:       op = OSSP_DSP_GET_RATE;         goto ri;
1539         case SOUND_PCM_READ_BITS:       op = OSSP_DSP_GET_FORMAT;       goto ri;
1540         case SOUND_PCM_READ_CHANNELS:   op = OSSP_DSP_GET_CHANNELS;     goto ri;
1541         case SNDCTL_DSP_GETBLKSIZE:     op = OSSP_DSP_GET_BLKSIZE;      goto ri;
1542         case SNDCTL_DSP_GETFMTS:        op = OSSP_DSP_GET_FORMATS;      goto ri;
1543         case SNDCTL_DSP_GETTRIGGER:     op = OSSP_DSP_GET_TRIGGER;      goto ri;
1544         ri:
1545                 PREP_UARG(NULL, &i);
1546                 ret = exec_simple_cmd(&dsps->os, op, NULL, &i);
1547                 if (ret)
1548                         goto err;
1549                 IOCTL_RETURN(0, &i);
1550
1551         case SNDCTL_DSP_SPEED:          op = OSSP_DSP_SET_RATE;         goto wi;
1552         case SNDCTL_DSP_SETFMT:         op = OSSP_DSP_SET_FORMAT;       goto wi;
1553         case SNDCTL_DSP_CHANNELS:       op = OSSP_DSP_SET_CHANNELS;     goto wi;
1554         case SNDCTL_DSP_SUBDIVIDE:      op = OSSP_DSP_SET_SUBDIVISION;  goto wi;
1555         wi:
1556                 PREP_UARG(&i, &i);
1557                 ret = exec_simple_cmd(&dsps->os, op, &i, &i);
1558                 if (ret)
1559                         goto err;
1560                 IOCTL_RETURN(0, &i);
1561
1562         case SNDCTL_DSP_STEREO:
1563                 PREP_UARG(NULL, &i);
1564                 i = 2;
1565                 ret = exec_simple_cmd(&dsps->os, OSSP_DSP_SET_CHANNELS, &i, &i);
1566                 i--;
1567                 if (ret)
1568                         goto err;
1569                 IOCTL_RETURN(0, &i);
1570
1571         case SNDCTL_DSP_SETFRAGMENT:
1572                 PREP_UARG(&i, NULL);
1573                 ret = exec_simple_cmd(&dsps->os,
1574                                       OSSP_DSP_SET_FRAGMENT, &i, NULL);
1575                 if (ret)
1576                         goto err;
1577                 IOCTL_RETURN(0, NULL);
1578
1579         case SNDCTL_DSP_SETTRIGGER:
1580                 PREP_UARG(&i, NULL);
1581                 ret = exec_simple_cmd(&dsps->os,
1582                                       OSSP_DSP_SET_TRIGGER, &i, NULL);
1583                 if (ret)
1584                         goto err;
1585                 IOCTL_RETURN(0, NULL);
1586
1587         case SNDCTL_DSP_GETOSPACE:
1588         case SNDCTL_DSP_GETISPACE: {
1589                 struct audio_buf_info info;
1590
1591                 ret = -EINVAL;
1592                 if (cmd == SNDCTL_DSP_GETOSPACE) {
1593                         if (!(dsps->rw & (1 << PLAY)))
1594                                 goto err;
1595                         op = OSSP_DSP_GET_OSPACE;
1596                 } else {
1597                         if (!(dsps->rw & (1 << REC)))
1598                                 goto err;
1599                         op = OSSP_DSP_GET_ISPACE;
1600                 }
1601
1602                 PREP_UARG(NULL, &info);
1603                 ret = exec_simple_cmd(&dsps->os, op, NULL, &info);
1604                 if (ret)
1605                         goto err;
1606                 IOCTL_RETURN(0, &info);
1607         }
1608
1609         case SNDCTL_DSP_GETOPTR:
1610         case SNDCTL_DSP_GETIPTR: {
1611                 struct count_info info;
1612
1613                 op = cmd == SNDCTL_DSP_GETOPTR ? OSSP_DSP_GET_OPTR
1614                                                : OSSP_DSP_GET_IPTR;
1615                 PREP_UARG(NULL, &info);
1616                 ret = exec_simple_cmd(&dsps->os, op, NULL, &info);
1617                 if (ret)
1618                         goto err;
1619                 IOCTL_RETURN(0, &info);
1620         }
1621
1622         case SNDCTL_DSP_GETODELAY:
1623                 PREP_UARG(NULL, &i);
1624                 i = 0;
1625                 ret = exec_simple_cmd(&dsps->os, OSSP_DSP_GET_ODELAY, NULL, &i);
1626                 IOCTL_RETURN(ret, &i);  /* always copy out result, 0 on err */
1627
1628         case SOUND_PCM_WRITE_FILTER:
1629         case SOUND_PCM_READ_FILTER:
1630                 ret = -EIO;
1631                 goto err;
1632
1633         case SNDCTL_DSP_MAPINBUF:
1634         case SNDCTL_DSP_MAPOUTBUF:
1635                 ret = -EINVAL;
1636                 goto err;
1637
1638         case SNDCTL_DSP_SETSYNCRO:
1639         case SNDCTL_DSP_SETDUPLEX:
1640         case SNDCTL_DSP_PROFILE:
1641                 IOCTL_RETURN(0, NULL);
1642
1643         default:
1644                 warn_os(os, "unknown ioctl 0x%x", cmd);
1645                 ret = -EINVAL;
1646                 goto err;
1647         }
1648         assert(0);      /* control shouldn't reach here */
1649 err:
1650         fuse_reply_err(req, -ret);
1651 }
1652
1653 #ifdef OSSP_MMAP
1654 static int dsp_mmap_dir(int prot)
1655 {
1656         if (!(prot & PROT_WRITE))
1657                 return REC;
1658         return PLAY;
1659 }
1660
1661 static void dsp_mmap(fuse_req_t req, void *addr, size_t len, int prot,
1662                      int flags, off_t offset, struct fuse_file_info *fi,
1663                      uint64_t mh)
1664 {
1665         int dir = dsp_mmap_dir(prot);
1666         struct ossp_dsp_mmap_arg arg = { };
1667         struct ossp_stream *os;
1668         struct ossp_dsp_stream *dsps;
1669         ssize_t ret;
1670
1671         os = find_os(fi->fh);
1672         if (!os) {
1673                 fuse_reply_err(req, EBADF);
1674                 return;
1675         }
1676         dsps = os_to_dsps(os);
1677
1678         if (!os->mmap_off || len > os->mmap_size / 2) {
1679                 fuse_reply_err(req, EINVAL);
1680                 return;
1681         }
1682
1683         pthread_mutex_lock(&os->mmap_mutex);
1684
1685         ret = -EBUSY;
1686         if (dsps->mmapped & (1 << dir))
1687                 goto out_unlock;
1688
1689         arg.dir = dir;
1690         arg.size = len;
1691
1692         ret = exec_simple_cmd(os, OSSP_DSP_MMAP, &arg, NULL);
1693         if (ret == 0)
1694                 dsps->mmapped |= 1 << dir;
1695
1696 out_unlock:
1697         pthread_mutex_unlock(&os->mmap_mutex);
1698
1699         if (ret == 0)
1700                 fuse_reply_mmap(req, os->mmap_off + dir * os->mmap_size / 2, 0);
1701         else
1702                 fuse_reply_err(req, -ret);
1703 }
1704
1705 static void dsp_munmap(fuse_req_t req, size_t len, struct fuse_file_info *fi,
1706                        off_t offset, uint64_t mh)
1707 {
1708         struct ossp_stream *os;
1709         struct ossp_dsp_stream *dsps;
1710         int dir, rc;
1711
1712         os = find_os(fi->fh);
1713         if (!os)
1714                 goto out;
1715         dsps = os_to_dsps(os);
1716
1717         pthread_mutex_lock(&os->mmap_mutex);
1718
1719         for (dir = 0; dir < 2; dir++)
1720                 if (offset == os->mmap_off + dir * os->mmap_size / 2)
1721                         break;
1722         if (dir == 2 || len > os->mmap_size / 2) {
1723                 warn_os(os, "invalid munmap request "
1724                         "offset=%llu len=%zu mmapped=0x%x",
1725                         (unsigned long long)offset, len, dsps->mmapped);
1726                 goto out_unlock;
1727         }
1728
1729         rc = exec_simple_cmd(os, OSSP_DSP_MUNMAP, &dir, NULL);
1730         if (rc)
1731                 warn_ose(os, rc, "MUNMAP failed for dir=%d", dir);
1732
1733         dsps->mmapped &= ~(1 << dir);
1734
1735 out_unlock:
1736         pthread_mutex_unlock(&os->mmap_mutex);
1737 out:
1738         fuse_reply_none(req);
1739 }
1740 #endif
1741
1742
1743 /***************************************************************************
1744  * Notify poller
1745  */
1746
1747 static void *notify_poller(void *arg)
1748 {
1749         struct epoll_event events[1024];
1750         int i, nfds;
1751
1752 repeat:
1753         nfds = epoll_wait(notify_epfd, events, ARRAY_SIZE(events), -1);
1754         for (i = 0; i < nfds; i++) {
1755                 int do_notify = 0;
1756                 struct ossp_stream *os;
1757                 struct ossp_notify notify;
1758                 ssize_t ret;
1759
1760                 os = find_os_by_notify_rx(events[i].data.fd);
1761                 if (!os) {
1762                         err("can't find stream for notify_rx fd %d",
1763                             events[i].data.fd);
1764                         epoll_ctl(notify_epfd, EPOLL_CTL_DEL, events[i].data.fd,
1765                                   NULL);
1766                         /* we don't know what's going on, don't close the fd */
1767                         continue;
1768                 }
1769
1770                 while ((ret = read(os->notify_rx,
1771                                    &notify, sizeof(notify))) > 0) {
1772                         if (os->dead)
1773                                 continue;
1774                         if (ret != sizeof(notify)) {
1775                                 warn_os(os, "short read on notify_rx (%zu, "
1776                                         "expected %zu), killing the stream",
1777                                         ret, sizeof(notify));
1778                                 os->dead = 1;
1779                                 break;
1780                         }
1781                         if (notify.magic != OSSP_NOTIFY_MAGIC) {
1782                                 warn_os(os, "invalid magic on notification, "
1783                                         "killing the stream");
1784                                 os->dead = 1;
1785                                 break;
1786                         }
1787
1788                         if (notify.opcode >= OSSP_NR_NOTIFY_OPCODES)
1789                                 goto unknown;
1790
1791                         dbg1_os(os, "NOTIFY %s", ossp_notify_str[notify.opcode]);
1792
1793                         switch (notify.opcode) {
1794                         case OSSP_NOTIFY_POLL:
1795                                 do_notify = 1;
1796                                 break;
1797                         case OSSP_NOTIFY_OBITUARY:
1798                                 os->dead = 1;
1799                                 break;
1800                         case OSSP_NOTIFY_VOLCHG:
1801                                 pthread_mutex_lock(&mixer_mutex);
1802                                 os->mixer->modify_counter++;
1803                                 pthread_mutex_unlock(&mixer_mutex);
1804                                 break;
1805                         default:
1806                         unknown:
1807                                 warn_os(os, "unknown notification %d",
1808                                         notify.opcode);
1809                         }
1810                 }
1811                 if (ret == 0)
1812                         os->dead = 1;
1813                 else if (ret < 0 && errno != EAGAIN) {
1814                         warn_ose(os, -errno, "read fail on notify fd");
1815                         os->dead = 1;
1816                 }
1817
1818                 if (!do_notify && !os->dead)
1819                         continue;
1820
1821                 pthread_mutex_lock(&mutex);
1822
1823                 if (os->ph) {
1824                         fuse_lowlevel_notify_poll(os->ph);
1825                         fuse_pollhandle_destroy(os->ph);
1826                         os->ph = NULL;
1827                 }
1828
1829                 if (os->dead) {
1830                         dbg0_os(os, "removing %d from notify poll list",
1831                                 os->notify_rx);
1832                         epoll_ctl(notify_epfd, EPOLL_CTL_DEL, os->notify_rx,
1833                                   NULL);
1834                         close(os->notify_rx);
1835                         os->notify_rx = -1;
1836                         pthread_cond_broadcast(&notify_poller_kill_wait);
1837                 }
1838
1839                 pthread_mutex_unlock(&mutex);
1840         }
1841         goto repeat;
1842 }
1843
1844
1845 /***************************************************************************
1846  * Slave corpse reaper
1847  */
1848
1849 static void *slave_reaper(void *arg)
1850 {
1851         struct ossp_stream *os;
1852         int status;
1853         pid_t pid;
1854
1855         pthread_mutex_lock(&mutex);
1856 repeat:
1857         while (list_empty(&slave_corpse_list))
1858                 pthread_cond_wait(&slave_reaper_wait, &mutex);
1859
1860         os = list_first_entry(&slave_corpse_list, struct ossp_stream, link);
1861         list_del_init(&os->link);
1862
1863         pthread_mutex_unlock(&mutex);
1864
1865         do {
1866                 pid = waitpid(os->slave_pid, &status, 0);
1867         } while (pid < 0 && errno == EINTR);
1868
1869         if (pid < 0) {
1870                 if (errno == ECHILD)
1871                         warn_ose(os, -errno, "slave %d already gone?",
1872                                  os->slave_pid);
1873                 else
1874                         fatal_e(-errno, "waitpid(%d) failed", os->slave_pid);
1875         }
1876
1877         pthread_mutex_lock(&mutex);
1878
1879         dbg1_os(os, "slave %d reaped", os->slave_pid);
1880         __clear_bit(os->id, os_id_bitmap);
1881         free(os);
1882
1883         goto repeat;
1884 }
1885
1886
1887 /***************************************************************************
1888  * Stuff to bind and start everything
1889  */
1890
1891 static void ossp_daemonize(void)
1892 {
1893         int fd, pfd[2];
1894         pid_t pid;
1895         ssize_t ret;
1896         int err;
1897
1898         fd = open("/dev/null", O_RDWR);
1899         if (fd >= 0) {
1900                 dup2(fd, 0);
1901                 dup2(fd, 1);
1902                 dup2(fd, 2);
1903                 if (fd > 2)
1904                         close(fd);
1905         }
1906
1907         if (pipe(pfd))
1908                 fatal_e(-errno, "failed to create pipe for init wait");
1909
1910         if (fcntl(pfd[0], F_SETFD, FD_CLOEXEC) < 0 ||
1911             fcntl(pfd[1], F_SETFD, FD_CLOEXEC) < 0)
1912                 fatal_e(-errno, "failed to set CLOEXEC on init wait pipe");
1913
1914         pid = fork();
1915         if (pid < 0)
1916                 fatal_e(-errno, "failed to fork for daemon");
1917
1918         if (pid == 0) {
1919                 close(pfd[0]);
1920                 init_wait_fd = pfd[1];
1921
1922                 /* be evil, my child */
1923                 chdir("/");
1924                 setsid();
1925                 return;
1926         }
1927
1928         /* wait for init completion and pass over success indication */
1929         close(pfd[1]);
1930
1931         do {
1932                 ret = read(pfd[0], &err, sizeof(err));
1933         } while (ret < 0 && errno == EINTR);
1934
1935         if (ret == sizeof(err) && err == 0)
1936                 exit(0);
1937
1938         fatal("daemon init failed ret=%zd err=%d", ret, err);
1939         exit(1);
1940 }
1941
1942 static void ossp_init_done(void *userdata)
1943 {
1944         /* init complete, notify parent if it's waiting */
1945         if (init_wait_fd >= 0) {
1946                 ssize_t ret;
1947                 int err = 0;
1948
1949                 ret = write(init_wait_fd, &err, sizeof(err));
1950                 if (ret != sizeof(err))
1951                         fatal_e(-errno, "failed to notify init completion, "
1952                                 "ret=%zd", ret);
1953                 close(init_wait_fd);
1954                 init_wait_fd = -1;
1955         }
1956 }
1957
1958 static const struct cuse_lowlevel_ops mixer_ops = {
1959         .open                   = mixer_open,
1960         .release                = mixer_release,
1961         .ioctl                  = mixer_ioctl,
1962 };
1963
1964 static const struct cuse_lowlevel_ops dsp_ops = {
1965         .init_done              = ossp_init_done,
1966         .open                   = dsp_open,
1967         .release                = dsp_release,
1968         .read                   = dsp_read,
1969         .write                  = dsp_write,
1970         .poll                   = dsp_poll,
1971         .ioctl                  = dsp_ioctl,
1972 #ifdef OSSP_MMAP
1973         .mmap                   = dsp_mmap,
1974         .munmap                 = dsp_munmap,
1975 #endif
1976 };
1977
1978 static const struct cuse_lowlevel_ops adsp_ops = {
1979         .open                   = adsp_open,
1980         .release                = dsp_release,
1981         .read                   = dsp_read,
1982         .write                  = dsp_write,
1983         .poll                   = dsp_poll,
1984         .ioctl                  = dsp_ioctl,
1985 #ifdef OSSP_MMAP
1986         .mmap                   = dsp_mmap,
1987         .munmap                 = dsp_munmap,
1988 #endif
1989 };
1990
1991 static const char *usage =
1992 "usage: osspd [options]\n"
1993 "\n"
1994 "options:\n"
1995 "    --help            print this help message\n"
1996 "    --dsp=NAME        DSP device name (default dsp)\n"
1997 "    --dsp-maj=MAJ     DSP device major number (default 14)\n"
1998 "    --dsp-min=MIN     DSP device minor number (default 3)\n"
1999 "    --adsp=NAME       Aux DSP device name (default adsp, blank to disable)\n"
2000 "    --adsp-maj=MAJ    Aux DSP device major number (default 14)\n"
2001 "    --adsp-min=MIN    Aux DSP device minor number (default 12)\n"
2002 "    --mixer=NAME      mixer device name (default mixer, blank to disable)\n"
2003 "    --mixer-maj=MAJ   mixer device major number (default 14)\n"
2004 "    --mixer-min=MIN   mixer device minor number (default 0)\n"
2005 "    --max=MAX         maximum number of open streams (default 256)\n"
2006 "    --umax=MAX        maximum number of open streams per UID (default --max)\n"
2007 "    --exit-on-idle    exit if idle\n"
2008 "    --dsp-slave=PATH  DSP slave (default ossp-padsp in the same dir)\n"
2009 "    --log=LEVEL       log level (0..6)\n"
2010 "    --timestamp       timestamp log messages\n"
2011 "    -v                increase verbosity, can be specified multiple times\n"
2012 "    -f                Run in foreground (don't daemonize)\n"
2013 "\n";
2014
2015 struct ossp_param {
2016         char                    *dsp_name;
2017         unsigned                dsp_major;
2018         unsigned                dsp_minor;
2019         char                    *adsp_name;
2020         unsigned                adsp_major;
2021         unsigned                adsp_minor;
2022         char                    *mixer_name;
2023         unsigned                mixer_major;
2024         unsigned                mixer_minor;
2025         unsigned                max_streams;
2026         unsigned                umax_streams;
2027         char                    *dsp_slave_path;
2028         unsigned                log_level;
2029         int                     exit_on_idle;
2030         int                     timestamp;
2031         int                     fg;
2032         int                     help;
2033 };
2034
2035 #define OSSP_OPT(t, p) { t, offsetof(struct ossp_param, p), 1 }
2036
2037 static const struct fuse_opt ossp_opts[] = {
2038         OSSP_OPT("--dsp=%s",            dsp_name),
2039         OSSP_OPT("--dsp-maj=%u",        dsp_major),
2040         OSSP_OPT("--dsp-min=%u",        dsp_minor),
2041         OSSP_OPT("--adsp=%s",           adsp_name),
2042         OSSP_OPT("--adsp-maj=%u",       adsp_major),
2043         OSSP_OPT("--adsp-min=%u",       adsp_minor),
2044         OSSP_OPT("--mixer=%s",          mixer_name),
2045         OSSP_OPT("--mixer-maj=%u",      mixer_major),
2046         OSSP_OPT("--mixer-min=%u",      mixer_minor),
2047         OSSP_OPT("--max=%u",            max_streams),
2048         OSSP_OPT("--umax=%u",           umax_streams),
2049         OSSP_OPT("--exit-on-idle",      exit_on_idle),
2050         OSSP_OPT("--dsp-slave=%s",      dsp_slave_path),
2051         OSSP_OPT("--timestamp",         timestamp),
2052         OSSP_OPT("--log=%u",            log_level),
2053         OSSP_OPT("-f",                  fg),
2054         FUSE_OPT_KEY("-h",              0),
2055         FUSE_OPT_KEY("--help",          0),
2056         FUSE_OPT_KEY("-v",              1),
2057         FUSE_OPT_END
2058 };
2059
2060 static struct fuse_session *setup_ossp_cuse(const struct cuse_lowlevel_ops *ops,
2061                                             const char *name, int major,
2062                                             int minor, int argc, char **argv)
2063 {
2064         char name_buf[128];
2065         const char *bufp = name_buf;
2066         struct cuse_info ci = { .dev_major = major, .dev_minor = minor,
2067                                 .dev_info_argc = 1, .dev_info_argv = &bufp,
2068                                 .flags = CUSE_UNRESTRICTED_IOCTL };
2069         struct fuse_session *se;
2070         int fd;
2071
2072         snprintf(name_buf, sizeof(name_buf), "DEVNAME=%s", name);
2073
2074         se = cuse_lowlevel_setup(argc, argv, &ci, ops, NULL, NULL);
2075         if (!se) {
2076                 err("failed to setup %s CUSE", name);
2077                 return NULL;
2078         }
2079
2080         fd = fuse_chan_fd(fuse_session_next_chan(se, NULL));
2081         if (
2082 #ifdef OSSP_MMAP
2083                 fd != fuse_mmap_fd(se) &&
2084 #endif
2085                 fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) {
2086                 err_e(-errno, "failed to set CLOEXEC on %s CUSE fd", name);
2087                 cuse_lowlevel_teardown(se);
2088                 return NULL;
2089         }
2090
2091         return se;
2092 }
2093
2094 static void *cuse_worker(void *arg)
2095 {
2096         struct fuse_session *se = arg;
2097         int rc;
2098
2099         rc = fuse_session_loop_mt(se);
2100         cuse_lowlevel_teardown(se);
2101
2102         return (void *)(unsigned long)rc;
2103 }
2104
2105 static int process_arg(void *data, const char *arg, int key,
2106                        struct fuse_args *outargs)
2107 {
2108         struct ossp_param *param = data;
2109
2110         switch (key) {
2111         case 0:
2112                 fprintf(stderr, usage);
2113                 param->help = 1;
2114                 return 0;
2115         case 1:
2116                 param->log_level++;
2117                 return 0;
2118         }
2119         return 1;
2120 }
2121
2122 int main(int argc, char **argv)
2123 {
2124         static struct ossp_param param = {
2125                 .dsp_name = DFL_DSP_NAME,
2126                 .dsp_major = DFL_DSP_MAJOR, .dsp_minor = DFL_DSP_MINOR,
2127                 .adsp_name = DFL_ADSP_NAME,
2128                 .adsp_major = DFL_ADSP_MAJOR, .adsp_minor = DFL_ADSP_MINOR,
2129                 .mixer_name = DFL_MIXER_NAME,
2130                 .mixer_major = DFL_MIXER_MAJOR, .mixer_minor = DFL_MIXER_MINOR,
2131                 .max_streams = DFL_MAX_STREAMS,
2132         };
2133         struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
2134         char path_buf[PATH_MAX], *dir;
2135         char adsp_buf[64] = "", mixer_buf[64] = "";
2136         struct sigaction sa;
2137         struct stat stat_buf;
2138         ssize_t ret;
2139         unsigned u;
2140
2141         snprintf(ossp_log_name, sizeof(ossp_log_name), "osspd");
2142         param.log_level = ossp_log_level;
2143
2144         if (fuse_opt_parse(&args, &param, ossp_opts, process_arg))
2145                 fatal("failed to parse arguments");
2146
2147         if (param.help)
2148                 return 0;
2149
2150         max_streams = param.max_streams;
2151         hashtbl_size = max_streams / 2 + 13;
2152
2153         umax_streams = max_streams;
2154         if (param.umax_streams)
2155                 umax_streams = param.umax_streams;
2156         if (param.log_level > OSSP_LOG_MAX)
2157                 param.log_level = OSSP_LOG_MAX;
2158         if (!param.fg)
2159                 param.log_level = -param.log_level;
2160         ossp_log_level = param.log_level;
2161         ossp_log_timestamp = param.timestamp;
2162
2163         if (!param.fg)
2164                 ossp_daemonize();
2165
2166         /* daemonization already handled, prevent forking inside FUSE */
2167         fuse_opt_add_arg(&args, "-f");
2168
2169         info("OSS Proxy v%s (C) 2008-2010 by Tejun Heo <teheo@suse.de>",
2170              OSSP_VERSION);
2171
2172         /* ignore stupid SIGPIPEs */
2173         memset(&sa, 0, sizeof(sa));
2174         sa.sa_handler = SIG_IGN;
2175         if (sigaction(SIGPIPE, &sa, NULL))
2176                 fatal_e(-errno, "failed to ignore SIGPIPE");
2177
2178         /* determine slave path and check for availability */
2179         ret = readlink("/proc/self/exe", path_buf, PATH_MAX - 1);
2180         if (ret < 0)
2181                 fatal_e(-errno, "failed to determine executable path");
2182         path_buf[ret] = '\0';
2183         dir = dirname(path_buf);
2184
2185         if (param.dsp_slave_path) {
2186                 strncpy(dsp_slave_path, param.dsp_slave_path, PATH_MAX - 1);
2187                 dsp_slave_path[PATH_MAX - 1] = '\0';
2188         } else {
2189                 ret = snprintf(dsp_slave_path, PATH_MAX, "%s/%s",
2190                                dir, "ossp-padsp");
2191                 if (ret >= PATH_MAX)
2192                         fatal("dsp slave pathname too long");
2193         }
2194
2195         if (stat(dsp_slave_path, &stat_buf))
2196                 fatal_e(-errno, "failed to stat %s", dsp_slave_path);
2197         if (!S_ISREG(stat_buf.st_mode) || !(stat_buf.st_mode & 0444))
2198                 fatal("%s is not executable", dsp_slave_path);
2199
2200         /* allocate tables */
2201         os_id_bitmap = calloc(BITS_TO_LONGS(max_streams), sizeof(long));
2202         mixer_tbl = calloc(hashtbl_size, sizeof(mixer_tbl[0]));
2203         os_tbl = calloc(hashtbl_size, sizeof(os_tbl[0]));
2204         os_pgrp_tbl = calloc(hashtbl_size, sizeof(os_pgrp_tbl[0]));
2205         os_notify_tbl = calloc(hashtbl_size, sizeof(os_notify_tbl[0]));
2206         if (!os_id_bitmap || !mixer_tbl || !os_tbl || !os_pgrp_tbl ||
2207             !os_notify_tbl)
2208                 fatal("failed to allocate stream hash tables");
2209         for (u = 0; u < hashtbl_size; u++) {
2210                 INIT_LIST_HEAD(&mixer_tbl[u]);
2211                 INIT_LIST_HEAD(&os_tbl[u]);
2212                 INIT_LIST_HEAD(&os_pgrp_tbl[u]);
2213                 INIT_LIST_HEAD(&os_notify_tbl[u]);
2214         }
2215         __set_bit(0, os_id_bitmap);     /* don't use id 0 */
2216
2217         /* create mixer delayed reference worker */
2218         ret = -pthread_create(&mixer_delayed_put_thread, NULL,
2219                               mixer_delayed_put_worker, NULL);
2220         if (ret)
2221                 fatal_e(ret, "failed to create mixer delayed put worker");
2222
2223         /* if exit_on_idle, touch mixer for pgrp0 */
2224         exit_on_idle = param.exit_on_idle;
2225         if (exit_on_idle) {
2226                 struct ossp_mixer *mixer;
2227
2228                 mixer = get_mixer(0);
2229                 if (!mixer)
2230                         fatal("failed to touch idle mixer");
2231                 put_mixer(mixer);
2232         }
2233
2234         /* create notify epoll and kick off watcher thread */
2235         notify_epfd = epoll_create(max_streams);
2236         if (notify_epfd < 0)
2237                 fatal_e(-errno, "failed to create notify epoll");
2238         if (fcntl(notify_epfd, F_SETFD, FD_CLOEXEC) < 0)
2239                 fatal_e(-errno, "failed to set CLOEXEC on notify epfd");
2240
2241         ret = -pthread_create(&notify_poller_thread, NULL, notify_poller, NULL);
2242         if (ret)
2243                 fatal_e(ret, "failed to create notify poller thread");
2244
2245         /* create reaper for slave corpses */
2246         ret = -pthread_create(&slave_reaper_thread, NULL, slave_reaper, NULL);
2247         if (ret)
2248                 fatal_e(ret, "failed to create slave reaper thread");
2249
2250         /* we're set, let's setup fuse structures */
2251         if (strlen(param.mixer_name))
2252                 mixer_se = setup_ossp_cuse(&mixer_ops, param.mixer_name,
2253                                            param.mixer_major, param.mixer_minor,
2254                                            args.argc, args.argv);
2255         if (strlen(param.adsp_name))
2256                 adsp_se = setup_ossp_cuse(&dsp_ops, param.adsp_name,
2257                                           param.adsp_major, param.adsp_minor,
2258                                           args.argc, args.argv);
2259
2260         dsp_se = setup_ossp_cuse(&dsp_ops, param.dsp_name,
2261                                  param.dsp_major, param.dsp_minor,
2262                                  args.argc, args.argv);
2263         if (!dsp_se)
2264                 fatal("can't create dsp, giving up");
2265
2266         if (mixer_se)
2267                 snprintf(mixer_buf, sizeof(mixer_buf), ", %s (%d:%d)",
2268                          param.mixer_name, param.mixer_major, param.mixer_minor);
2269         if (adsp_se)
2270                 snprintf(adsp_buf, sizeof(adsp_buf), ", %s (%d:%d)",
2271                          param.adsp_name, param.adsp_major, param.adsp_minor);
2272
2273         info("Creating %s (%d:%d)%s%s", param.dsp_name, param.dsp_major,
2274              param.dsp_minor, adsp_buf, mixer_buf);
2275
2276         /* start threads for mixer and adsp */
2277         if (mixer_se) {
2278                 ret = -pthread_create(&cuse_mixer_thread, NULL,
2279                                       cuse_worker, mixer_se);
2280                 if (ret)
2281                         err_e(ret, "failed to create mixer worker");
2282         }
2283         if (adsp_se) {
2284                 ret = -pthread_create(&cuse_adsp_thread, NULL,
2285                                       cuse_worker, adsp_se);
2286                 if (ret)
2287                         err_e(ret, "failed to create adsp worker");
2288         }
2289
2290         /* run CUSE for /dev/dsp in the main thread */
2291         ret = (ssize_t)cuse_worker(dsp_se);
2292         if (ret < 0)
2293                 fatal("dsp worker failed");
2294         return 0;
2295 }