bail out if no sink is defined
[profile/ivi/pulseaudio.git] / 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 Lesser 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 Lesser 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 #include <limits.h>
37 #include <fcntl.h>
38 #include <sys/ioctl.h>
39
40 #ifdef HAVE_LIBWRAP
41 #include <syslog.h>
42 #include <tcpd.h>
43 #endif
44
45 #include "core.h"
46 #include "mainloop.h"
47 #include "module.h"
48 #include "mainloop-signal.h"
49 #include "cmdline.h"
50 #include "cli-command.h"
51 #include "util.h"
52 #include "sioman.h"
53 #include "xmalloc.h"
54 #include "cpulimit.h"
55 #include "log.h"
56 #include "daemon-conf.h"
57 #include "dumpmodules.h"
58 #include "caps.h"
59 #include "cli-text.h"
60 #include "pid.h"
61 #include "namereg.h"
62
63 #ifdef HAVE_LIBWRAP
64 /* Only one instance of these variables */
65 int allow_severity = LOG_INFO;
66 int deny_severity = LOG_WARNING;
67 #endif
68
69 static void signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, int sig, void *userdata) {
70     pa_log_info(__FILE__": Got signal %s.\n", pa_strsignal(sig));
71
72     switch (sig) {
73         case SIGUSR1:
74             pa_module_load(userdata, "module-cli", NULL);
75             break;
76             
77         case SIGUSR2:
78             pa_module_load(userdata, "module-cli-protocol-unix", NULL);
79             break;
80
81         case SIGHUP: {
82             char *c = pa_full_status_string(userdata);
83             pa_log_notice(c);
84             pa_xfree(c);
85             return;
86         }
87
88         case SIGINT:
89         case SIGTERM:
90         default:
91             pa_log_info(__FILE__": Exiting.\n");
92             m->quit(m, 1);
93             break;
94     }
95 }
96
97 static void close_pipe(int p[2]) {
98     if (p[0] != -1)
99         close(p[0]);
100     if (p[1] != -1)
101         close(p[1]);
102     p[0] = p[1] = -1;
103 }
104
105 int main(int argc, char *argv[]) {
106     struct pa_core *c;
107     struct pa_strbuf *buf = NULL;
108     struct pa_daemon_conf *conf;
109     struct pa_mainloop *mainloop;
110
111     char *s;
112     int r, retval = 1, d = 0;
113     int daemon_pipe[2] = { -1, -1 };
114     gid_t gid = (gid_t) -1;
115     int suid_root;
116     int valid_pid_file = 0;
117
118     pa_limit_caps();
119
120     suid_root = getuid() != 0 && geteuid() == 0;
121     
122     if (suid_root && (pa_uid_in_group("realtime", &gid) <= 0 || gid >= 1000)) {
123         pa_log_warn(__FILE__": WARNING: called SUID root, but not in group 'realtime'.\n");
124         pa_drop_root();
125     }
126     
127     LTDL_SET_PRELOADED_SYMBOLS();
128     
129     r = lt_dlinit();
130     assert(r == 0);
131
132     pa_log_set_ident("polypaudio");
133     
134     conf = pa_daemon_conf_new();
135     
136     if (pa_daemon_conf_load(conf, NULL) < 0)
137         goto finish;
138
139     if (pa_daemon_conf_env(conf) < 0)
140         goto finish;
141
142     if (pa_cmdline_parse(conf, argc, argv, &d) < 0) {
143         pa_log(__FILE__": failed to parse command line.\n");
144         goto finish;
145     }
146
147     pa_log_set_maximal_level(conf->log_level);
148     pa_log_set_target(conf->auto_log_target ? PA_LOG_STDERR : conf->log_target, NULL);
149
150     if (conf->high_priority && conf->cmd == PA_CMD_DAEMON)
151         pa_raise_priority();
152
153     pa_drop_caps();
154
155     if (suid_root)
156         pa_drop_root();
157     
158     if (conf->dl_search_path)
159         lt_dlsetsearchpath(conf->dl_search_path);
160
161     switch (conf->cmd) {
162         case PA_CMD_DUMP_MODULES:
163             pa_dump_modules(conf, argc-d, argv+d);
164             retval = 0;
165             goto finish;
166
167         case PA_CMD_DUMP_CONF: {
168             char *s = pa_daemon_conf_dump(conf);
169             fputs(s, stdout);
170             pa_xfree(s);
171             retval = 0;
172             goto finish;
173         }
174
175         case PA_CMD_HELP :
176             pa_cmdline_help(argv[0]);
177             retval = 0;
178             goto finish;
179
180         case PA_CMD_VERSION :
181             printf(PACKAGE_NAME" "PACKAGE_VERSION"\n");
182             retval = 0;
183             goto finish;
184
185         case PA_CMD_CHECK: {
186             pid_t pid;
187
188             if (pa_pid_file_check_running(&pid) < 0) {
189                 pa_log_info(__FILE__": daemon not running\n");
190             } else {
191                 pa_log_info(__FILE__": daemon running as PID %u\n", pid);
192                 retval = 0;
193             }
194
195             goto finish;
196
197         }
198         case PA_CMD_KILL:
199
200             if (pa_pid_file_kill(SIGINT, NULL) < 0)
201                 pa_log(__FILE__": failed to kill daemon.\n");
202             else
203                 retval = 0;
204             
205             goto finish;
206             
207         default:
208             assert(conf->cmd == PA_CMD_DAEMON);
209     }
210
211     if (conf->daemonize) {
212         pid_t child;
213         int tty_fd;
214
215         if (pa_stdio_acquire() < 0) {
216             pa_log(__FILE__": failed to acquire stdio.\n");
217             goto finish;
218         }
219
220         if (pipe(daemon_pipe) < 0) {
221             pa_log(__FILE__": failed to create pipe.\n");
222             goto finish;
223         }
224         
225         if ((child = fork()) < 0) {
226             pa_log(__FILE__": fork() failed: %s\n", strerror(errno));
227             goto finish;
228         }
229
230         if (child != 0) {
231             /* Father */
232
233             close(daemon_pipe[1]);
234             daemon_pipe[1] = -1;
235
236             if (pa_loop_read(daemon_pipe[0], &retval, sizeof(retval)) != sizeof(retval)) {
237                 pa_log(__FILE__": read() failed: %s\n", strerror(errno));
238                 retval = 1;
239             }
240
241             if (retval)
242                 pa_log(__FILE__": daemon startup failed.\n");
243             else
244                 pa_log_info(__FILE__": daemon startup successful.\n");
245             
246             goto finish;
247         }
248
249         close(daemon_pipe[0]);
250         daemon_pipe[0] = -1;
251
252         if (conf->auto_log_target)
253             pa_log_set_target(PA_LOG_SYSLOG, NULL);
254
255         setsid();
256         setpgid(0,0);
257         
258         close(0);
259         close(1);
260         close(2);
261
262         open("/dev/null", O_RDONLY);
263         open("/dev/null", O_WRONLY);
264         open("/dev/null", O_WRONLY);
265         
266         signal(SIGTTOU, SIG_IGN);
267         signal(SIGTTIN, SIG_IGN);
268         signal(SIGTSTP, SIG_IGN);
269         
270         if ((tty_fd = open("/dev/tty", O_RDWR)) >= 0) {
271             ioctl(tty_fd, TIOCNOTTY, (char*) 0);
272             close(tty_fd);
273         }
274     }
275
276     chdir("/");
277     
278     if (conf->use_pid_file) {
279         if (pa_pid_file_create() < 0) {
280             if (conf->daemonize)
281                 pa_loop_write(daemon_pipe[1], &retval, sizeof(retval));
282             goto finish;
283         }
284
285         valid_pid_file = 1;
286     }
287
288     mainloop = pa_mainloop_new();
289     assert(mainloop);
290
291     r = pa_signal_init(pa_mainloop_get_api(mainloop));
292     assert(r == 0);
293     pa_signal_new(SIGINT, signal_callback, c);
294     pa_signal_new(SIGTERM, signal_callback, c);
295     signal(SIGPIPE, SIG_IGN);
296
297     c = pa_core_new(pa_mainloop_get_api(mainloop));
298     assert(c);
299     
300     pa_signal_new(SIGUSR1, signal_callback, c);
301     pa_signal_new(SIGUSR2, signal_callback, c);
302     pa_signal_new(SIGHUP, signal_callback, c);
303
304     r = pa_cpu_limit_init(pa_mainloop_get_api(mainloop));
305     assert(r == 0);
306     
307     buf = pa_strbuf_new();
308     assert(buf);
309     if (conf->default_script_file)
310         r = pa_cli_command_execute_file(c, conf->default_script_file, buf, &conf->fail);
311
312     if (r >= 0)
313         r = pa_cli_command_execute(c, conf->script_commands, buf, &conf->fail);
314     pa_log(s = pa_strbuf_tostring_free(buf));
315     pa_xfree(s);
316     
317     if (r < 0 && conf->fail) {
318         pa_log(__FILE__": failed to initialize daemon.\n");
319         if (conf->daemonize)
320             pa_loop_write(daemon_pipe[1], &retval, sizeof(retval));
321     } else if (!c->modules || pa_idxset_ncontents(c->modules) == 0) {
322         pa_log(__FILE__": daemon startup without any loaded modules, refusing to work.\n");
323         if (conf->daemonize)
324             pa_loop_write(daemon_pipe[1], &retval, sizeof(retval));
325     } else {
326
327         retval = 0;
328         if (conf->daemonize)
329             pa_loop_write(daemon_pipe[1], &retval, sizeof(retval));
330
331         c->disallow_module_loading = conf->disallow_module_loading;
332         c->exit_idle_time = conf->exit_idle_time;
333         c->module_idle_time = conf->module_idle_time;
334         c->scache_idle_time = conf->scache_idle_time;
335         c->resample_method = conf->resample_method;
336
337         if (pa_namereg_get(c, c->default_sink_name, PA_NAMEREG_SINK, 1) == NULL) {
338             pa_log_error("%s : Fatal error. Default sink name (%s) does not exist in name register.\n", __FILE__, c->default_sink_name);
339             retval = 1;
340         } else {
341             pa_log_info(__FILE__": Daemon startup complete.\n");
342             if (pa_mainloop_run(mainloop, &retval) < 0)
343                 retval = 1;
344             pa_log_info(__FILE__": Daemon shutdown initiated.\n");
345         }
346     }
347         
348     pa_core_free(c);
349
350     pa_cpu_limit_done();
351     pa_signal_done();
352     pa_mainloop_free(mainloop);
353     
354     pa_log_info(__FILE__": Daemon terminated.\n");
355     
356 finish:
357
358     if (conf)
359         pa_daemon_conf_free(conf);
360
361     if (valid_pid_file)
362         pa_pid_file_remove();
363     
364     close_pipe(daemon_pipe);
365
366     lt_dlexit();
367     
368     return retval;
369 }