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 " -s MMAP_SIZE mmap size\n"
36 " -l LOG_LEVEL set log level\n"
37 " -t enable log timestamps\n";
39 char ossp_user_name
[OSSP_USER_NAME_LEN
];
40 int ossp_cmd_fd
= -1, ossp_notify_fd
= -1;
41 void *ossp_mmap_addr
[2];
42 struct ossp_transfer
*ossp_mmap_transfer
;
44 void ossp_slave_init(int argc
, char **argv
)
46 int have_uid
= 0, have_gid
= 0;
52 struct passwd
*pw
, pw_buf
;
54 char pw_sbuf
[sysconf(_SC_GETPW_R_SIZE_MAX
)];
56 while ((opt
= getopt(argc
, argv
, "u:g:c:n:m:o:s:l:t")) != -1) {
60 uid
= strtol(optarg
, NULL
, 0);
64 gid
= strtol(optarg
, NULL
, 0);
67 ossp_cmd_fd
= strtol(optarg
, NULL
, 0);
70 ossp_notify_fd
= strtol(optarg
, NULL
, 0);
73 mmap_fd
= strtol(optarg
, NULL
, 0);
76 mmap_size
= strtoul(optarg
, NULL
, 0);
79 ossp_log_level
= strtol(optarg
, NULL
, 0);
82 ossp_log_timestamp
= 1;
87 if (!have_uid
|| !have_gid
|| ossp_cmd_fd
< 0 || ossp_notify_fd
< 0) {
88 fprintf(stderr
, usage
);
92 snprintf(ossp_user_name
, sizeof(ossp_user_name
), "uid%d", uid
);
93 if (getpwuid_r(uid
, &pw_buf
, pw_sbuf
, sizeof(pw_sbuf
), &pw
) == 0)
94 snprintf(ossp_user_name
, sizeof(ossp_user_name
), "%s",
97 snprintf(ossp_log_name
, sizeof(ossp_log_name
), "ossp-padsp[%s:%d]",
98 ossp_user_name
, getpid());
104 fprintf(stderr
, usage
);
108 p
= mmap(NULL
, mmap_size
+ 2 * sizeof(struct ossp_transfer
),
109 PROT_READ
| PROT_WRITE
, MAP_SHARED
, mmap_fd
, 0);
111 fatal_e(-errno
, "mmap failed");
113 ossp_mmap_addr
[PLAY
] = p
;
114 ossp_mmap_addr
[REC
] = p
+ mmap_size
/ 2;
115 ossp_mmap_transfer
= p
+ mmap_size
;
119 /* mmap done, drop privileges */
120 if (setresgid(gid
, gid
, gid
) || setresuid(uid
, uid
, uid
))
121 fatal_e(-errno
, "failed to drop privileges");
124 memset(&sa
, 0, sizeof(sa
));
125 sa
.sa_handler
= SIG_IGN
;
126 if (sigaction(SIGPIPE
, &sa
, NULL
))
127 fatal_e(-errno
, "failed to ignore SIGPIPE");
130 int ossp_slave_process_command(int cmd_fd
,
131 ossp_action_fn_t
const *action_fn_tbl
,
132 int (*action_pre_fn
)(void),
133 void (*action_post_fn
)(void))
135 static struct sized_buf carg_sbuf
= { }, rarg_sbuf
= { };
136 static struct sized_buf din_sbuf
= { }, dout_sbuf
= { };
139 char cmsg_buf
[CMSG_SPACE(sizeof(fd
))];
140 struct iovec iov
= { &cmd
, sizeof(cmd
) };
141 struct msghdr msg
= { .msg_iov
= &iov
, .msg_iovlen
= 1,
142 .msg_control
= cmsg_buf
,
143 .msg_controllen
= sizeof(cmsg_buf
) };
144 struct cmsghdr
*cmsg
;
145 size_t carg_size
, din_size
, rarg_size
, dout_size
;
146 char *carg
= NULL
, *din
= NULL
, *rarg
= NULL
, *dout
= NULL
;
147 struct ossp_reply reply
= { .magic
= OSSP_REPLY_MAGIC
};
150 ret
= recvmsg(cmd_fd
, &msg
, 0);
155 err_e(ret
, "failed to read command channel");
159 if (ret
!= sizeof(cmd
)) {
160 err("command struct size mismatch (%zu, should be %zu)",
165 if (cmd
.magic
!= OSSP_CMD_MAGIC
) {
166 err("illegal command magic 0x%x", cmd
.magic
);
170 for (cmsg
= CMSG_FIRSTHDR(&msg
); cmsg
;
171 cmsg
= CMSG_NXTHDR(&msg
, cmsg
)) {
172 if (cmsg
->cmsg_level
== SOL_SOCKET
&&
173 cmsg
->cmsg_type
== SCM_RIGHTS
)
174 fd
= *(int *)CMSG_DATA(cmsg
);
176 err("unknown cmsg %d:%d received (opcode %d)",
177 cmsg
->cmsg_level
, cmsg
->cmsg_type
, cmd
.opcode
);
182 if (cmd
.opcode
>= OSSP_NR_OPCODES
) {
183 err("unknown opcode %d", cmd
.opcode
);
187 carg_size
= ossp_arg_sizes
[cmd
.opcode
].carg_size
;
188 din_size
= cmd
.din_size
;
189 rarg_size
= ossp_arg_sizes
[cmd
.opcode
].rarg_size
;
190 dout_size
= cmd
.dout_size
;
192 if ((fd
>= 0) != ossp_arg_sizes
[cmd
.opcode
].has_fd
) {
193 err("fd=%d unexpected for opcode %d", fd
, cmd
.opcode
);
197 if (ensure_sbuf_size(&carg_sbuf
, carg_size
) ||
198 ensure_sbuf_size(&din_sbuf
, din_size
) ||
199 ensure_sbuf_size(&rarg_sbuf
, rarg_size
) ||
200 ensure_sbuf_size(&dout_sbuf
, dout_size
)) {
201 err("failed to allocate command buffers");
206 carg
= carg_sbuf
.buf
;
207 ret
= read_fill(cmd_fd
, carg
, carg_size
);
213 ret
= read_fill(cmd_fd
, din
, din_size
);
218 rarg
= rarg_sbuf
.buf
;
220 dout
= dout_sbuf
.buf
;
223 if (action_fn_tbl
[cmd
.opcode
]) {
224 ret
= action_pre_fn();
226 ret
= action_fn_tbl
[cmd
.opcode
](cmd
.opcode
, carg
,
228 dout
, &dout_size
, fd
);
235 reply
.dout_size
= dout_size
;
241 if (write_fill(cmd_fd
, &reply
, sizeof(reply
)) < 0 ||
242 write_fill(cmd_fd
, rarg
, rarg_size
) < 0 ||
243 write_fill(cmd_fd
, dout
, dout_size
) < 0)