2 * ossp-slave - OSS Proxy: Common codes for slaves
4 * Copyright (C) 2008-2010 SUSE Linux Products GmbH
5 * Copyright (C) 2008-2010 Tejun Heo <tj@kernel.org>
7 * This file is released under the GPLv2.
12 #include <sys/types.h>
14 #include <sys/socket.h>
22 #include "ossp-slave.h"
24 static const char *usage =
25 "usage: ossp-SLAVE [options]\n"
27 "proxies commands from osspd to pulseaudio\n"
30 " -u UID uid to use\n"
31 " -g GID gid to use\n"
32 " -c CMD_FD fd to receive commands from osspd\n"
33 " -n NOTIFY_FD fd to send async notifications to osspd\n"
34 " -m MMAP_FD fd to use for mmap\n"
35 " -o MMAP_OFFSET mmap offset\n"
36 " -s MMAP_SIZE mmap size\n"
37 " -l LOG_LEVEL set log level\n"
38 " -t enable log timestamps\n";
40 char ossp_user_name[OSSP_USER_NAME_LEN];
41 int ossp_cmd_fd = -1, ossp_notify_fd = -1;
42 void *ossp_mmap_addr[2];
44 void ossp_slave_init(int argc, char **argv)
46 int have_uid = 0, have_gid = 0;
53 struct passwd *pw, pw_buf;
55 char pw_sbuf[sysconf(_SC_GETPW_R_SIZE_MAX)];
57 while ((opt = getopt(argc, argv, "u:g:c:n:m:o:s:l:t")) != -1) {
61 uid = strtol(optarg, NULL, 0);
65 gid = strtol(optarg, NULL, 0);
68 ossp_cmd_fd = strtol(optarg, NULL, 0);
71 ossp_notify_fd = strtol(optarg, NULL, 0);
74 mmap_fd = strtol(optarg, NULL, 0);
77 mmap_off = strtoull(optarg, NULL, 0);
80 mmap_size = strtoul(optarg, NULL, 0);
83 ossp_log_level = strtol(optarg, NULL, 0);
86 ossp_log_timestamp = 1;
91 if (!have_uid || !have_gid || ossp_cmd_fd < 0 || ossp_notify_fd < 0) {
92 fprintf(stderr, usage);
96 snprintf(ossp_user_name, sizeof(ossp_user_name), "uid%d", uid);
97 if (getpwuid_r(uid, &pw_buf, pw_sbuf, sizeof(pw_sbuf), &pw) == 0)
98 snprintf(ossp_user_name, sizeof(ossp_user_name), "%s",
101 snprintf(ossp_log_name, sizeof(ossp_log_name), "ossp-padsp[%s:%d]",
102 ossp_user_name, getpid());
107 if (!mmap_off || !mmap_size) {
108 fprintf(stderr, usage);
112 p = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED,
115 fatal_e(-errno, "mmap failed");
117 ossp_mmap_addr[PLAY] = p;
118 ossp_mmap_addr[REC] = p + mmap_size / 2;
122 /* mmap done, drop privileges */
123 if (setresgid(gid, gid, gid) || setresuid(uid, uid, uid))
124 fatal_e(-errno, "failed to drop privileges");
127 memset(&sa, 0, sizeof(sa));
128 sa.sa_handler = SIG_IGN;
129 if (sigaction(SIGPIPE, &sa, NULL))
130 fatal_e(-errno, "failed to ignore SIGPIPE");
133 int ossp_slave_process_command(int cmd_fd,
134 ossp_action_fn_t const *action_fn_tbl,
135 int (*action_pre_fn)(void),
136 void (*action_post_fn)(void))
138 static struct sized_buf carg_sbuf = { }, rarg_sbuf = { };
139 static struct sized_buf din_sbuf = { }, dout_sbuf = { };
142 char cmsg_buf[CMSG_SPACE(sizeof(fd))];
143 struct iovec iov = { &cmd, sizeof(cmd) };
144 struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1,
145 .msg_control = cmsg_buf,
146 .msg_controllen = sizeof(cmsg_buf) };
147 struct cmsghdr *cmsg;
148 size_t carg_size, din_size, rarg_size, dout_size;
149 char *carg = NULL, *din = NULL, *rarg = NULL, *dout = NULL;
150 struct ossp_reply reply = { .magic = OSSP_REPLY_MAGIC };
153 ret = recvmsg(cmd_fd, &msg, 0);
158 err_e(ret, "failed to read command channel");
162 if (ret != sizeof(cmd)) {
163 err("command struct size mismatch (%zu, should be %zu)",
168 if (cmd.magic != OSSP_CMD_MAGIC) {
169 err("illegal command magic 0x%x", cmd.magic);
173 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg;
174 cmsg = CMSG_NXTHDR(&msg, cmsg)) {
175 if (cmsg->cmsg_level == SOL_SOCKET &&
176 cmsg->cmsg_type == SCM_RIGHTS)
177 fd = *(int *)CMSG_DATA(cmsg);
179 err("unknown cmsg %d:%d received (opcode %d)",
180 cmsg->cmsg_level, cmsg->cmsg_type, cmd.opcode);
185 if (cmd.opcode >= OSSP_NR_OPCODES) {
186 err("unknown opcode %d", cmd.opcode);
190 carg_size = ossp_arg_sizes[cmd.opcode].carg_size;
191 din_size = cmd.din_size;
192 rarg_size = ossp_arg_sizes[cmd.opcode].rarg_size;
193 dout_size = cmd.dout_size;
195 if ((fd >= 0) != ossp_arg_sizes[cmd.opcode].has_fd) {
196 err("fd=%d unexpected for opcode %d", fd, cmd.opcode);
200 if (ensure_sbuf_size(&carg_sbuf, carg_size) ||
201 ensure_sbuf_size(&din_sbuf, din_size) ||
202 ensure_sbuf_size(&rarg_sbuf, rarg_size) ||
203 ensure_sbuf_size(&dout_sbuf, dout_size)) {
204 err("failed to allocate command buffers");
209 carg = carg_sbuf.buf;
210 ret = read_fill(cmd_fd, carg, carg_size);
216 ret = read_fill(cmd_fd, din, din_size);
221 rarg = rarg_sbuf.buf;
223 dout = dout_sbuf.buf;
226 if (action_fn_tbl[cmd.opcode]) {
227 ret = action_pre_fn();
229 ret = action_fn_tbl[cmd.opcode](cmd.opcode, carg,
231 dout, &dout_size, fd);
238 reply.dout_size = dout_size;
244 if (write_fill(cmd_fd, &reply, sizeof(reply)) < 0 ||
245 write_fill(cmd_fd, rarg, rarg_size) < 0 ||
246 write_fill(cmd_fd, dout, dout_size) < 0)