Consistently include <config.h> in all C source files and never in header files.
[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 #include <signal.h>
33 #ifdef HAVE_ERRNO_H
34 #include <errno.h>
35 #endif
36 #include "selinux.h"
37
38 static BusContext *context;
39
40 static int reload_pipe[2];
41 #define RELOAD_READ_END 0
42 #define RELOAD_WRITE_END 1
43
44 static void close_reload_pipe (void);
45
46 static void
47 signal_handler (int sig)
48 {
49
50   switch (sig)
51     {
52 #ifdef DBUS_BUS_ENABLE_DNOTIFY_ON_LINUX 
53     case SIGIO: 
54       /* explicit fall-through */
55 #endif /* DBUS_BUS_ENABLE_DNOTIFY_ON_LINUX  */
56 #ifdef SIGHUP
57     case SIGHUP:
58       {
59         DBusString str;
60         _dbus_string_init_const (&str, "foo");
61         if ((reload_pipe[RELOAD_WRITE_END] > 0) && 
62             !_dbus_write_socket (reload_pipe[RELOAD_WRITE_END], &str, 0, 1))
63           {
64             _dbus_warn ("Unable to write to reload pipe.\n");
65             close_reload_pipe ();
66           }
67       }
68       break;
69 #endif
70     case SIGTERM:
71       _dbus_loop_quit (bus_context_get_loop (context));
72       break;
73     }
74 }
75
76 static void
77 usage (void)
78 {
79   fprintf (stderr, DBUS_DAEMON_NAME " [--version] [--session] [--system] [--config-file=FILE] [--print-address[=DESCRIPTOR]] [--print-pid[=DESCRIPTOR]] [--fork] [--nofork] [--introspect]\n");
80   exit (1);
81 }
82
83 static void
84 version (void)
85 {
86   printf ("D-Bus Message Bus Daemon %s\n"
87           "Copyright (C) 2002, 2003 Red Hat, Inc., CodeFactory AB, and others\n"
88           "This is free software; see the source for copying conditions.\n"
89           "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
90           DBUS_VERSION_STRING);
91   exit (0);
92 }
93
94 static void
95 introspect (void)
96 {
97   DBusString xml;
98   const char *v_STRING;  
99
100   if (!_dbus_string_init (&xml))
101     goto oom;
102
103   if (!bus_driver_generate_introspect_string (&xml))
104     {
105       _dbus_string_free (&xml);
106       goto oom;
107     }
108
109   v_STRING = _dbus_string_get_const_data (&xml);
110   printf ("%s\n", v_STRING); 
111
112   exit (0);
113  
114  oom:
115   _dbus_warn ("Can not introspect - Out of memory\n");
116   exit (1);
117 }
118 static void
119 check_two_config_files (const DBusString *config_file,
120                         const char       *extra_arg)
121 {
122   if (_dbus_string_get_length (config_file) > 0)
123     {
124       fprintf (stderr, "--%s specified but configuration file %s already requested\n",
125                extra_arg, _dbus_string_get_const_data (config_file));
126       exit (1);
127     }
128 }
129
130 static void
131 check_two_addr_descriptors (const DBusString *addr_fd,
132                             const char       *extra_arg)
133 {
134   if (_dbus_string_get_length (addr_fd) > 0)
135     {
136       fprintf (stderr, "--%s specified but printing address to %s already requested\n",
137                extra_arg, _dbus_string_get_const_data (addr_fd));
138       exit (1);
139     }
140 }
141
142 static void
143 check_two_pid_descriptors (const DBusString *pid_fd,
144                            const char       *extra_arg)
145 {
146   if (_dbus_string_get_length (pid_fd) > 0)
147     {
148       fprintf (stderr, "--%s specified but printing pid to %s already requested\n",
149                extra_arg, _dbus_string_get_const_data (pid_fd));
150       exit (1);
151     }
152 }
153
154 static dbus_bool_t
155 handle_reload_watch (DBusWatch    *watch,
156                      unsigned int  flags,
157                      void         *data)
158 {
159   DBusError error;
160   DBusString str;
161
162   while (!_dbus_string_init (&str))
163     _dbus_wait_for_memory ();
164
165   if ((reload_pipe[RELOAD_READ_END] > 0) &&
166       _dbus_read_socket (reload_pipe[RELOAD_READ_END], &str, 1) != 1)
167     {
168       _dbus_warn ("Couldn't read from reload pipe.\n");
169       close_reload_pipe ();
170       return TRUE;
171     }
172   _dbus_string_free (&str);
173
174   /* this can only fail if we don't understand the config file
175    * or OOM.  Either way we should just stick with the currently
176    * loaded config.
177    */
178   dbus_error_init (&error);
179   if (! bus_context_reload_config (context, &error))
180     {
181       _DBUS_ASSERT_ERROR_IS_SET (&error);
182       _dbus_assert (dbus_error_has_name (&error, DBUS_ERROR_FAILED) ||
183                     dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY));
184       _dbus_warn ("Unable to reload configuration: %s\n",
185                   error.message);
186       dbus_error_free (&error);
187     }
188   return TRUE;
189 }
190
191 static dbus_bool_t
192 reload_watch_callback (DBusWatch    *watch,
193                        unsigned int  condition,
194                        void         *data)
195 {
196   return dbus_watch_handle (watch, condition);
197 }
198
199 static void
200 setup_reload_pipe (DBusLoop *loop)
201 {
202   DBusError error;
203   DBusWatch *watch;
204
205   dbus_error_init (&error);
206
207   if (!_dbus_full_duplex_pipe (&reload_pipe[0], &reload_pipe[1],
208                                TRUE, &error))
209     {
210       _dbus_warn ("Unable to create reload pipe: %s\n",
211                   error.message);
212       dbus_error_free (&error);
213       exit (1);
214     }
215
216   watch = _dbus_watch_new (reload_pipe[RELOAD_READ_END],
217                            DBUS_WATCH_READABLE, TRUE,
218                            handle_reload_watch, NULL, NULL);
219
220   if (watch == NULL)
221     {
222       _dbus_warn ("Unable to create reload watch: %s\n",
223                   error.message);
224       dbus_error_free (&error);
225       exit (1);
226     }
227
228   if (!_dbus_loop_add_watch (loop, watch, reload_watch_callback,
229                              NULL, NULL))
230     {
231       _dbus_warn ("Unable to add reload watch to main loop: %s\n",
232                   error.message);
233       dbus_error_free (&error);
234       exit (1);
235     }
236
237 }
238
239 static void
240 close_reload_pipe (void)
241 {
242     _dbus_close_socket (reload_pipe[RELOAD_READ_END], NULL);
243     reload_pipe[RELOAD_READ_END] = -1;
244
245     _dbus_close_socket (reload_pipe[RELOAD_WRITE_END], NULL);
246     reload_pipe[RELOAD_WRITE_END] = -1;
247 }
248
249 int
250 main (int argc, char **argv)
251 {
252   DBusError error;
253   DBusString config_file;
254   DBusString addr_fd;
255   DBusString pid_fd;
256   const char *prev_arg;
257   DBusPipe print_addr_pipe;
258   DBusPipe print_pid_pipe;
259   int i;
260   dbus_bool_t print_address;
261   dbus_bool_t print_pid;
262   dbus_bool_t is_session_bus;
263   int force_fork;
264
265   if (!_dbus_string_init (&config_file))
266     return 1;
267
268   if (!_dbus_string_init (&addr_fd))
269     return 1;
270
271   if (!_dbus_string_init (&pid_fd))
272     return 1;
273
274   print_address = FALSE;
275   print_pid = FALSE;
276   is_session_bus = FALSE;
277   force_fork = FORK_FOLLOW_CONFIG_FILE;
278
279   prev_arg = NULL;
280   i = 1;
281   while (i < argc)
282     {
283       const char *arg = argv[i];
284
285       if (strcmp (arg, "--help") == 0 ||
286           strcmp (arg, "-h") == 0 ||
287           strcmp (arg, "-?") == 0)
288         usage ();
289       else if (strcmp (arg, "--version") == 0)
290         version ();
291       else if (strcmp (arg, "--introspect") == 0)
292         introspect ();
293       else if (strcmp (arg, "--nofork") == 0)
294         force_fork = FORK_NEVER;
295       else if (strcmp (arg, "--fork") == 0)
296         force_fork = FORK_ALWAYS;
297       else if (strcmp (arg, "--system") == 0)
298         {
299           check_two_config_files (&config_file, "system");
300
301           if (!_dbus_append_system_config_file (&config_file))
302             exit (1);
303         }
304       else if (strcmp (arg, "--session") == 0)
305         {
306           check_two_config_files (&config_file, "session");
307
308           if (!_dbus_append_session_config_file (&config_file))
309             exit (1);
310         }
311       else if (strstr (arg, "--config-file=") == arg)
312         {
313           const char *file;
314
315           check_two_config_files (&config_file, "config-file");
316           
317           file = strchr (arg, '=');
318           ++file;
319
320           if (!_dbus_string_append (&config_file, file))
321             exit (1);
322         }
323       else if (prev_arg &&
324                strcmp (prev_arg, "--config-file") == 0)
325         {
326           check_two_config_files (&config_file, "config-file");
327           
328           if (!_dbus_string_append (&config_file, arg))
329             exit (1);
330         }
331       else if (strcmp (arg, "--config-file") == 0)
332         ; /* wait for next arg */
333       else if (strstr (arg, "--print-address=") == arg)
334         {
335           const char *desc;
336
337           check_two_addr_descriptors (&addr_fd, "print-address");
338           
339           desc = strchr (arg, '=');
340           ++desc;
341
342           if (!_dbus_string_append (&addr_fd, desc))
343             exit (1);
344
345           print_address = TRUE;
346         }
347       else if (prev_arg &&
348                strcmp (prev_arg, "--print-address") == 0)
349         {
350           check_two_addr_descriptors (&addr_fd, "print-address");
351           
352           if (!_dbus_string_append (&addr_fd, arg))
353             exit (1);
354
355           print_address = TRUE;
356         }
357       else if (strcmp (arg, "--print-address") == 0)
358         print_address = TRUE; /* and we'll get the next arg if appropriate */
359       else if (strstr (arg, "--print-pid=") == arg)
360         {
361           const char *desc;
362
363           check_two_pid_descriptors (&pid_fd, "print-pid");
364           
365           desc = strchr (arg, '=');
366           ++desc;
367
368           if (!_dbus_string_append (&pid_fd, desc))
369             exit (1);
370
371           print_pid = TRUE;
372         }
373       else if (prev_arg &&
374                strcmp (prev_arg, "--print-pid") == 0)
375         {
376           check_two_pid_descriptors (&pid_fd, "print-pid");
377           
378           if (!_dbus_string_append (&pid_fd, arg))
379             exit (1);
380           
381           print_pid = TRUE;
382         }
383       else if (strcmp (arg, "--print-pid") == 0)
384         print_pid = TRUE; /* and we'll get the next arg if appropriate */
385       else
386         usage ();
387       
388       prev_arg = arg;
389       
390       ++i;
391     }
392
393   if (_dbus_string_get_length (&config_file) == 0)
394     {
395       fprintf (stderr, "No configuration file specified.\n");
396       usage ();
397     }
398
399   _dbus_pipe_invalidate (&print_addr_pipe);
400   if (print_address)
401     {
402       _dbus_pipe_init_stdout (&print_addr_pipe);
403       if (_dbus_string_get_length (&addr_fd) > 0)
404         {
405           long val;
406           int end;
407           if (!_dbus_string_parse_int (&addr_fd, 0, &val, &end) ||
408               end != _dbus_string_get_length (&addr_fd) ||
409               val < 0 || val > _DBUS_INT_MAX)
410             {
411               fprintf (stderr, "Invalid file descriptor: \"%s\"\n",
412                        _dbus_string_get_const_data (&addr_fd));
413               exit (1);
414             }
415
416           _dbus_pipe_init (&print_addr_pipe, val);
417         }
418     }
419   _dbus_string_free (&addr_fd);
420
421   _dbus_pipe_invalidate (&print_pid_pipe);
422   if (print_pid)
423     {
424       _dbus_pipe_init_stdout (&print_pid_pipe);
425       if (_dbus_string_get_length (&pid_fd) > 0)
426         {
427           long val;
428           int end;
429           if (!_dbus_string_parse_int (&pid_fd, 0, &val, &end) ||
430               end != _dbus_string_get_length (&pid_fd) ||
431               val < 0 || val > _DBUS_INT_MAX)
432             {
433               fprintf (stderr, "Invalid file descriptor: \"%s\"\n",
434                        _dbus_string_get_const_data (&pid_fd));
435               exit (1);
436             }
437
438           _dbus_pipe_init (&print_pid_pipe, val);
439         }
440     }
441   _dbus_string_free (&pid_fd);
442
443   if (!bus_selinux_pre_init ())
444     {
445       _dbus_warn ("SELinux pre-initialization failed\n");
446       exit (1);
447     }
448
449   dbus_error_init (&error);
450   context = bus_context_new (&config_file, force_fork,
451                              &print_addr_pipe, &print_pid_pipe,
452                              &error);
453   _dbus_string_free (&config_file);
454   if (context == NULL)
455     {
456       _dbus_warn ("Failed to start message bus: %s\n",
457                   error.message);
458       dbus_error_free (&error);
459       exit (1);
460     }
461
462   is_session_bus = bus_context_get_type(context) != NULL
463       && strcmp(bus_context_get_type(context),"session") == 0;
464
465   if (is_session_bus)
466     _dbus_daemon_publish_session_bus_address (bus_context_get_address (context));
467
468   /* bus_context_new() closes the print_addr_pipe and
469    * print_pid_pipe
470    */
471   
472   setup_reload_pipe (bus_context_get_loop (context));
473
474 #ifdef SIGHUP
475   _dbus_set_signal_handler (SIGHUP, signal_handler);
476 #endif
477   _dbus_set_signal_handler (SIGTERM, signal_handler);
478 #ifdef DBUS_BUS_ENABLE_DNOTIFY_ON_LINUX 
479   _dbus_set_signal_handler (SIGIO, signal_handler);
480 #endif /* DBUS_BUS_ENABLE_DNOTIFY_ON_LINUX */
481   
482   _dbus_verbose ("We are on D-Bus...\n");
483   _dbus_loop_run (bus_context_get_loop (context));
484   
485   bus_context_shutdown (context);
486   bus_context_unref (context);
487   bus_selinux_shutdown ();
488
489   if (is_session_bus)
490     _dbus_daemon_unpublish_session_bus_address ();
491
492   return 0;
493 }