bus: signal_handler: ignore failure to write, and explain why
[platform/upstream/dbus.git] / bus / main.c
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /* main.c  main() for message bus
3  *
4  * Copyright (C) 2003 Red Hat, Inc.
5  *
6  * Licensed under the Academic Free License version 2.1
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21  *
22  */
23
24 #include <config.h>
25 #include "bus.h"
26 #include "driver.h"
27 #include <dbus/dbus-internals.h>
28 #include <dbus/dbus-watch.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #ifdef HAVE_SIGNAL_H
33 #include <signal.h>
34 #endif
35 #ifdef HAVE_ERRNO_H
36 #include <errno.h>
37 #endif
38 #include "selinux.h"
39
40 static BusContext *context;
41
42 static int reload_pipe[2];
43 #define RELOAD_READ_END 0
44 #define RELOAD_WRITE_END 1
45
46 static void close_reload_pipe (DBusWatch **);
47
48 static void
49 signal_handler (int sig)
50 {
51
52   switch (sig)
53     {
54 #ifdef DBUS_BUS_ENABLE_DNOTIFY_ON_LINUX
55     case SIGIO:
56       /* explicit fall-through */
57 #endif /* DBUS_BUS_ENABLE_DNOTIFY_ON_LINUX  */
58 #ifdef SIGHUP
59     case SIGHUP:
60       {
61         DBusString str;
62         _dbus_string_init_const (&str, "foo");
63         if ((reload_pipe[RELOAD_WRITE_END] > 0) &&
64             !_dbus_write_socket (reload_pipe[RELOAD_WRITE_END], &str, 0, 1))
65           {
66             /* If we receive SIGHUP often enough to fill the pipe buffer (4096
67              * times on old Linux, 65536 on modern Linux) before it can be
68              * drained, let's just warn and ignore. The configuration will be
69              * reloaded while draining the pipe buffer, which is what we
70              * wanted. It's harmless that it will be reloaded fewer times than
71              * we asked for, since the reload is delayed anyway, so new changes
72              * will be picked up. */
73             _dbus_warn ("Unable to write to reload pipe.\n");
74           }
75       }
76       break;
77 #endif
78     }
79 }
80
81 static void
82 usage (void)
83 {
84   fprintf (stderr, DBUS_DAEMON_NAME " [--version] [--session] [--system] [--config-file=FILE] [--print-address[=DESCRIPTOR]] [--print-pid[=DESCRIPTOR]] [--fork] [--nofork] [--introspect] [--address=ADDRESS] [--systemd-activation]\n");
85   exit (1);
86 }
87
88 static void
89 version (void)
90 {
91   printf ("D-Bus Message Bus Daemon %s\n"
92           "Copyright (C) 2002, 2003 Red Hat, Inc., CodeFactory AB, and others\n"
93           "This is free software; see the source for copying conditions.\n"
94           "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
95           DBUS_VERSION_STRING);
96   exit (0);
97 }
98
99 static void
100 introspect (void)
101 {
102   DBusString xml;
103   const char *v_STRING;
104
105   if (!_dbus_string_init (&xml))
106     goto oom;
107
108   if (!bus_driver_generate_introspect_string (&xml))
109     {
110       _dbus_string_free (&xml);
111       goto oom;
112     }
113
114   v_STRING = _dbus_string_get_const_data (&xml);
115   printf ("%s\n", v_STRING);
116
117   exit (0);
118
119  oom:
120   _dbus_warn ("Can not introspect - Out of memory\n");
121   exit (1);
122 }
123
124 static void
125 check_two_config_files (const DBusString *config_file,
126                         const char       *extra_arg)
127 {
128   if (_dbus_string_get_length (config_file) > 0)
129     {
130       fprintf (stderr, "--%s specified but configuration file %s already requested\n",
131                extra_arg, _dbus_string_get_const_data (config_file));
132       exit (1);
133     }
134 }
135
136 static void
137 check_two_addresses (const DBusString *address,
138                      const char       *extra_arg)
139 {
140   if (_dbus_string_get_length (address) > 0)
141     {
142       fprintf (stderr, "--%s specified but address %s already requested\n",
143                extra_arg, _dbus_string_get_const_data (address));
144       exit (1);
145     }
146 }
147
148 static void
149 check_two_addr_descriptors (const DBusString *addr_fd,
150                             const char       *extra_arg)
151 {
152   if (_dbus_string_get_length (addr_fd) > 0)
153     {
154       fprintf (stderr, "--%s specified but printing address to %s already requested\n",
155                extra_arg, _dbus_string_get_const_data (addr_fd));
156       exit (1);
157     }
158 }
159
160 static void
161 check_two_pid_descriptors (const DBusString *pid_fd,
162                            const char       *extra_arg)
163 {
164   if (_dbus_string_get_length (pid_fd) > 0)
165     {
166       fprintf (stderr, "--%s specified but printing pid to %s already requested\n",
167                extra_arg, _dbus_string_get_const_data (pid_fd));
168       exit (1);
169     }
170 }
171
172 static dbus_bool_t
173 handle_reload_watch (DBusWatch    *watch,
174                      unsigned int  flags,
175                      void         *data)
176 {
177   DBusError error;
178   DBusString str;
179
180   while (!_dbus_string_init (&str))
181     _dbus_wait_for_memory ();
182
183   if ((reload_pipe[RELOAD_READ_END] > 0) &&
184       _dbus_read_socket (reload_pipe[RELOAD_READ_END], &str, 1) != 1)
185     {
186       _dbus_warn ("Couldn't read from reload pipe.\n");
187       close_reload_pipe (&watch);
188       return TRUE;
189     }
190   _dbus_string_free (&str);
191
192   /* this can only fail if we don't understand the config file
193    * or OOM.  Either way we should just stick with the currently
194    * loaded config.
195    */
196   dbus_error_init (&error);
197   if (! bus_context_reload_config (context, &error))
198     {
199       _DBUS_ASSERT_ERROR_IS_SET (&error);
200       _dbus_assert (dbus_error_has_name (&error, DBUS_ERROR_FAILED) ||
201                     dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY));
202       _dbus_warn ("Unable to reload configuration: %s\n",
203                   error.message);
204       dbus_error_free (&error);
205     }
206   return TRUE;
207 }
208
209 static dbus_bool_t
210 reload_watch_callback (DBusWatch    *watch,
211                        unsigned int  condition,
212                        void         *data)
213 {
214   return dbus_watch_handle (watch, condition);
215 }
216
217 static void
218 setup_reload_pipe (DBusLoop *loop)
219 {
220   DBusError error;
221   DBusWatch *watch;
222
223   dbus_error_init (&error);
224
225   if (!_dbus_full_duplex_pipe (&reload_pipe[0], &reload_pipe[1],
226                                TRUE, &error))
227     {
228       _dbus_warn ("Unable to create reload pipe: %s\n",
229                   error.message);
230       dbus_error_free (&error);
231       exit (1);
232     }
233
234   watch = _dbus_watch_new (reload_pipe[RELOAD_READ_END],
235                            DBUS_WATCH_READABLE, TRUE,
236                            handle_reload_watch, NULL, NULL);
237
238   if (watch == NULL)
239     {
240       _dbus_warn ("Unable to create reload watch: %s\n",
241                   error.message);
242       dbus_error_free (&error);
243       exit (1);
244     }
245
246   if (!_dbus_loop_add_watch (loop, watch, reload_watch_callback,
247                              NULL, NULL))
248     {
249       _dbus_warn ("Unable to add reload watch to main loop: %s\n",
250                   error.message);
251       dbus_error_free (&error);
252       exit (1);
253     }
254
255 }
256
257 static void
258 close_reload_pipe (DBusWatch **watch)
259 {
260     _dbus_loop_remove_watch (bus_context_get_loop (context),
261         *watch, reload_watch_callback, NULL);
262     _dbus_watch_invalidate (*watch);
263     _dbus_watch_unref (*watch);
264     *watch = NULL;
265
266     _dbus_close_socket (reload_pipe[RELOAD_READ_END], NULL);
267     reload_pipe[RELOAD_READ_END] = -1;
268
269     _dbus_close_socket (reload_pipe[RELOAD_WRITE_END], NULL);
270     reload_pipe[RELOAD_WRITE_END] = -1;
271 }
272
273 int
274 main (int argc, char **argv)
275 {
276   DBusError error;
277   DBusString config_file;
278   DBusString address;
279   DBusString addr_fd;
280   DBusString pid_fd;
281   const char *prev_arg;
282   DBusPipe print_addr_pipe;
283   DBusPipe print_pid_pipe;
284   int i;
285   dbus_bool_t print_address;
286   dbus_bool_t print_pid;
287   dbus_bool_t is_session_bus;
288   int force_fork;
289   dbus_bool_t systemd_activation;
290
291   if (!_dbus_string_init (&config_file))
292     return 1;
293
294   if (!_dbus_string_init (&address))
295     return 1;
296
297   if (!_dbus_string_init (&addr_fd))
298     return 1;
299
300   if (!_dbus_string_init (&pid_fd))
301     return 1;
302
303   print_address = FALSE;
304   print_pid = FALSE;
305   is_session_bus = FALSE;
306   force_fork = FORK_FOLLOW_CONFIG_FILE;
307   systemd_activation = FALSE;
308
309   prev_arg = NULL;
310   i = 1;
311   while (i < argc)
312     {
313       const char *arg = argv[i];
314
315       if (strcmp (arg, "--help") == 0 ||
316           strcmp (arg, "-h") == 0 ||
317           strcmp (arg, "-?") == 0)
318         usage ();
319       else if (strcmp (arg, "--version") == 0)
320         version ();
321       else if (strcmp (arg, "--introspect") == 0)
322         introspect ();
323       else if (strcmp (arg, "--nofork") == 0)
324         force_fork = FORK_NEVER;
325       else if (strcmp (arg, "--fork") == 0)
326         force_fork = FORK_ALWAYS;
327       else if (strcmp (arg, "--systemd-activation") == 0)
328         systemd_activation = TRUE;
329       else if (strcmp (arg, "--system") == 0)
330         {
331           check_two_config_files (&config_file, "system");
332
333           if (!_dbus_append_system_config_file (&config_file))
334             exit (1);
335         }
336       else if (strcmp (arg, "--session") == 0)
337         {
338           check_two_config_files (&config_file, "session");
339
340           if (!_dbus_append_session_config_file (&config_file))
341             exit (1);
342         }
343       else if (strstr (arg, "--config-file=") == arg)
344         {
345           const char *file;
346
347           check_two_config_files (&config_file, "config-file");
348
349           file = strchr (arg, '=');
350           ++file;
351
352           if (!_dbus_string_append (&config_file, file))
353             exit (1);
354         }
355       else if (prev_arg &&
356                strcmp (prev_arg, "--config-file") == 0)
357         {
358           check_two_config_files (&config_file, "config-file");
359
360           if (!_dbus_string_append (&config_file, arg))
361             exit (1);
362         }
363       else if (strcmp (arg, "--config-file") == 0)
364         ; /* wait for next arg */
365       else if (strstr (arg, "--address=") == arg)
366         {
367           const char *file;
368
369           check_two_addresses (&address, "address");
370
371           file = strchr (arg, '=');
372           ++file;
373
374           if (!_dbus_string_append (&address, file))
375             exit (1);
376         }
377       else if (prev_arg &&
378                strcmp (prev_arg, "--address") == 0)
379         {
380           check_two_addresses (&address, "address");
381
382           if (!_dbus_string_append (&address, arg))
383             exit (1);
384         }
385       else if (strcmp (arg, "--address") == 0)
386         ; /* wait for next arg */
387       else if (strstr (arg, "--print-address=") == arg)
388         {
389           const char *desc;
390
391           check_two_addr_descriptors (&addr_fd, "print-address");
392
393           desc = strchr (arg, '=');
394           ++desc;
395
396           if (!_dbus_string_append (&addr_fd, desc))
397             exit (1);
398
399           print_address = TRUE;
400         }
401       else if (prev_arg &&
402                strcmp (prev_arg, "--print-address") == 0)
403         {
404           check_two_addr_descriptors (&addr_fd, "print-address");
405
406           if (!_dbus_string_append (&addr_fd, arg))
407             exit (1);
408
409           print_address = TRUE;
410         }
411       else if (strcmp (arg, "--print-address") == 0)
412         print_address = TRUE; /* and we'll get the next arg if appropriate */
413       else if (strstr (arg, "--print-pid=") == arg)
414         {
415           const char *desc;
416
417           check_two_pid_descriptors (&pid_fd, "print-pid");
418
419           desc = strchr (arg, '=');
420           ++desc;
421
422           if (!_dbus_string_append (&pid_fd, desc))
423             exit (1);
424
425           print_pid = TRUE;
426         }
427       else if (prev_arg &&
428                strcmp (prev_arg, "--print-pid") == 0)
429         {
430           check_two_pid_descriptors (&pid_fd, "print-pid");
431
432           if (!_dbus_string_append (&pid_fd, arg))
433             exit (1);
434
435           print_pid = TRUE;
436         }
437       else if (strcmp (arg, "--print-pid") == 0)
438         print_pid = TRUE; /* and we'll get the next arg if appropriate */
439       else
440         usage ();
441
442       prev_arg = arg;
443
444       ++i;
445     }
446
447   if (_dbus_string_get_length (&config_file) == 0)
448     {
449       fprintf (stderr, "No configuration file specified.\n");
450       usage ();
451     }
452
453   _dbus_pipe_invalidate (&print_addr_pipe);
454   if (print_address)
455     {
456       _dbus_pipe_init_stdout (&print_addr_pipe);
457       if (_dbus_string_get_length (&addr_fd) > 0)
458         {
459           long val;
460           int end;
461           if (!_dbus_string_parse_int (&addr_fd, 0, &val, &end) ||
462               end != _dbus_string_get_length (&addr_fd) ||
463               val < 0 || val > _DBUS_INT_MAX)
464             {
465               fprintf (stderr, "Invalid file descriptor: \"%s\"\n",
466                        _dbus_string_get_const_data (&addr_fd));
467               exit (1);
468             }
469
470           _dbus_pipe_init (&print_addr_pipe, val);
471         }
472     }
473   _dbus_string_free (&addr_fd);
474
475   _dbus_pipe_invalidate (&print_pid_pipe);
476   if (print_pid)
477     {
478       _dbus_pipe_init_stdout (&print_pid_pipe);
479       if (_dbus_string_get_length (&pid_fd) > 0)
480         {
481           long val;
482           int end;
483           if (!_dbus_string_parse_int (&pid_fd, 0, &val, &end) ||
484               end != _dbus_string_get_length (&pid_fd) ||
485               val < 0 || val > _DBUS_INT_MAX)
486             {
487               fprintf (stderr, "Invalid file descriptor: \"%s\"\n",
488                        _dbus_string_get_const_data (&pid_fd));
489               exit (1);
490             }
491
492           _dbus_pipe_init (&print_pid_pipe, val);
493         }
494     }
495   _dbus_string_free (&pid_fd);
496
497   if (!bus_selinux_pre_init ())
498     {
499       _dbus_warn ("SELinux pre-initialization failed\n");
500       exit (1);
501     }
502
503   dbus_error_init (&error);
504   context = bus_context_new (&config_file, force_fork,
505                              &print_addr_pipe, &print_pid_pipe,
506                              _dbus_string_get_length(&address) > 0 ? &address : NULL,
507                              systemd_activation,
508                              &error);
509   _dbus_string_free (&config_file);
510   if (context == NULL)
511     {
512       _dbus_warn ("Failed to start message bus: %s\n",
513                   error.message);
514       dbus_error_free (&error);
515       exit (1);
516     }
517
518   /* bus_context_new() closes the print_addr_pipe and
519    * print_pid_pipe
520    */
521
522   setup_reload_pipe (bus_context_get_loop (context));
523
524 #ifdef SIGHUP
525   _dbus_set_signal_handler (SIGHUP, signal_handler);
526 #endif
527 #ifdef DBUS_BUS_ENABLE_DNOTIFY_ON_LINUX
528   _dbus_set_signal_handler (SIGIO, signal_handler);
529 #endif /* DBUS_BUS_ENABLE_DNOTIFY_ON_LINUX */
530
531   _dbus_verbose ("We are on D-Bus...\n");
532   _dbus_loop_run (bus_context_get_loop (context));
533
534   bus_context_shutdown (context);
535   bus_context_unref (context);
536   bus_selinux_shutdown ();
537
538   return 0;
539 }