]> code.delx.au - pulseaudio/blob - polyp/main.c
a2b3d4c70dab817cb5939e81118528b653d9d82b
[pulseaudio] / polyp / main.c
1 /* $Id$ */
2
3 /***
4 This file is part of polypaudio.
5
6 polypaudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published
8 by the Free Software Foundation; either version 2 of the License,
9 or (at your option) any later version.
10
11 polypaudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with polypaudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <unistd.h>
27 #include <errno.h>
28 #include <string.h>
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <signal.h>
32 #include <stddef.h>
33 #include <assert.h>
34 #include <ltdl.h>
35 #include <memblock.h>
36
37 #include "core.h"
38 #include "mainloop.h"
39 #include "module.h"
40 #include "mainloop-signal.h"
41 #include "cmdline.h"
42 #include "cli-command.h"
43 #include "util.h"
44 #include "sioman.h"
45 #include "xmalloc.h"
46 #include "cpulimit.h"
47 #include "log.h"
48
49 static struct pa_mainloop *mainloop;
50
51 static void drop_root(void) {
52 if (getuid() != 0 && geteuid() == 0) {
53 pa_log(__FILE__": Started SUID root, dropping root rights.\n");
54 setuid(getuid());
55 seteuid(getuid());
56 }
57 }
58
59 static const char* signal_name(int s) {
60 switch(s) {
61 case SIGINT: return "SIGINT";
62 case SIGTERM: return "SIGTERM";
63 case SIGUSR1: return "SIGUSR1";
64 case SIGUSR2: return "SIGUSR2";
65 case SIGXCPU: return "SIGXCPU";
66 case SIGPIPE: return "SIGPIPE";
67 default: return "UNKNOWN SIGNAL";
68 }
69 }
70
71 static void signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, int sig, void *userdata) {
72 pa_log(__FILE__": Got signal %s.\n", signal_name(sig));
73
74 switch (sig) {
75 case SIGUSR1:
76 pa_module_load(userdata, "module-cli", NULL);
77 return;
78
79 case SIGUSR2:
80 pa_module_load(userdata, "module-cli-protocol-unix", NULL);
81 return;
82
83 case SIGINT:
84 case SIGTERM:
85 default:
86 pa_log(__FILE__": Exiting.\n");
87 m->quit(m, 1);
88 return;
89 }
90 }
91
92 static void close_pipe(int p[2]) {
93 if (p[0] != -1)
94 close(p[0]);
95 if (p[1] != -1)
96 close(p[1]);
97 p[0] = p[1] = -1;
98 }
99
100 int main(int argc, char *argv[]) {
101 struct pa_core *c;
102 struct pa_cmdline *cmdline = NULL;
103 struct pa_strbuf *buf = NULL;
104 char *s;
105 int r, retval = 1;
106 int daemon_pipe[2] = { -1, -1 };
107
108 pa_log_set_ident("polypaudio");
109
110 if (!(cmdline = pa_cmdline_parse(argc, argv))) {
111 pa_log(__FILE__": failed to parse command line.\n");
112 goto finish;
113 }
114
115 pa_log_set_target(cmdline->auto_log_target ? PA_LOG_STDERR : cmdline->log_target, NULL);
116
117 if (cmdline->help) {
118 pa_cmdline_help(argv[0]);
119 retval = 0;
120 goto finish;
121 }
122
123 if (cmdline->version) {
124 printf(PACKAGE_NAME" "PACKAGE_VERSION"\n");
125 retval = 0;
126 goto finish;
127 }
128
129 if (cmdline->high_priority)
130 pa_raise_priority();
131
132 if (!cmdline->stay_root)
133 drop_root();
134
135 if (cmdline->daemonize) {
136 pid_t child;
137
138 if (pa_stdio_acquire() < 0) {
139 pa_log(__FILE__": failed to acquire stdio.\n");
140 goto finish;
141 }
142
143 if (pipe(daemon_pipe) < 0) {
144 pa_log(__FILE__": failed to create pipe.\n");
145 goto finish;
146 }
147
148 if ((child = fork()) < 0) {
149 pa_log(__FILE__": fork() failed: %s\n", strerror(errno));
150 goto finish;
151 }
152
153 if (child != 0) {
154 /* Father */
155
156 close(daemon_pipe[1]);
157 daemon_pipe[1] = -1;
158
159 if (pa_loop_read(daemon_pipe[0], &retval, sizeof(retval)) != sizeof(retval)) {
160 pa_log(__FILE__": read() failed: %s\n", strerror(errno));
161 retval = 1;
162 }
163
164 goto finish;
165 }
166
167 close(daemon_pipe[0]);
168 daemon_pipe[0] = -1;
169
170
171 if (cmdline->auto_log_target)
172 pa_log_set_target(PA_LOG_SYSLOG, NULL);
173
174 setsid();
175 setpgrp();
176
177 close(0);
178 close(1);
179 }
180
181 r = lt_dlinit();
182 assert(r == 0);
183
184 if (cmdline->dl_search_path)
185 lt_dlsetsearchpath(cmdline->dl_search_path);
186 #ifdef DLSEARCHPATH
187 else
188 lt_dlsetsearchpath(DLSEARCHPATH);
189 #endif
190
191 pa_log(__FILE__": sizeof(pa_usec_t) = %u\n", sizeof(pa_usec_t));
192
193 mainloop = pa_mainloop_new();
194 assert(mainloop);
195
196 r = pa_signal_init(pa_mainloop_get_api(mainloop));
197 assert(r == 0);
198 pa_signal_new(SIGINT, signal_callback, c);
199 pa_signal_new(SIGTERM, signal_callback, c);
200 signal(SIGPIPE, SIG_IGN);
201
202 c = pa_core_new(pa_mainloop_get_api(mainloop));
203 assert(c);
204
205 pa_signal_new(SIGUSR1, signal_callback, c);
206 pa_signal_new(SIGUSR2, signal_callback, c);
207
208 r = pa_cpu_limit_init(pa_mainloop_get_api(mainloop));
209 assert(r == 0);
210
211 buf = pa_strbuf_new();
212 assert(buf);
213 r = pa_cli_command_execute(c, cmdline->cli_commands, buf, &cmdline->fail, &cmdline->verbose);
214 pa_log(s = pa_strbuf_tostring_free(buf));
215 pa_xfree(s);
216
217 if (r < 0 && cmdline->fail) {
218 pa_log(__FILE__": failed to initialize daemon.\n");
219 if (cmdline->daemonize)
220 pa_loop_write(daemon_pipe[1], &retval, sizeof(retval));
221 } else if (!c->modules || pa_idxset_ncontents(c->modules) == 0) {
222 pa_log(__FILE__": daemon startup without any loaded modules, refusing to work.\n");
223 if (cmdline->daemonize)
224 pa_loop_write(daemon_pipe[1], &retval, sizeof(retval));
225 } else {
226 retval = 0;
227 if (cmdline->daemonize)
228 pa_loop_write(daemon_pipe[1], &retval, sizeof(retval));
229
230 c->disallow_module_loading = cmdline->disallow_module_loading;
231 c->quit_after_last_client_time = cmdline->quit_after_last_client_time;
232
233 pa_log(__FILE__": Daemon startup complete.\n");
234 if (pa_mainloop_run(mainloop, &retval) < 0)
235 retval = 1;
236 pa_log(__FILE__": Daemon shutdown initiated.\n");
237 }
238
239 pa_core_free(c);
240
241 pa_cpu_limit_done();
242 pa_signal_done();
243 pa_mainloop_free(mainloop);
244
245 lt_dlexit();
246
247 pa_log(__FILE__": Daemon terminated.\n");
248
249 finish:
250
251 if (cmdline)
252 pa_cmdline_free(cmdline);
253
254 close_pipe(daemon_pipe);
255
256 return retval;
257 }