Patch from Jon Trowbridge <trow@ximian.com>:
[platform/upstream/dbus.git] / bus / main.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
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.0
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23 #include "bus.h"
24 #include <dbus/dbus-internals.h>
25 #include <dbus/dbus-watch.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <signal.h>
30 #include <errno.h>
31
32 static BusContext *context;
33
34 static int reload_pipe[2];
35 #define RELOAD_READ_END 0
36 #define RELOAD_WRITE_END 1
37
38
39 static void
40 signal_handler (int sig)
41 {
42   DBusString str;
43
44   switch (sig)
45     {
46     case SIGHUP:
47       _dbus_string_init_const (&str, "foo");
48       if (!_dbus_write (reload_pipe[RELOAD_WRITE_END], &str, 0, 1))
49         {
50           _dbus_warn ("Unable to write to reload pipe.\n");
51           exit (1);
52         }
53       break;
54
55     case SIGTERM:
56       _dbus_loop_quit (bus_context_get_loop (context));
57       break;
58     }
59 }
60
61 static void
62 usage (void)
63 {
64   fprintf (stderr, "dbus-daemon-1 [--version] [--session] [--system] [--config-file=FILE] [--print-address[=DESCRIPTOR]] [--print-pid[=DESCRIPTOR]] [--fork]\n");
65   exit (1);
66 }
67
68 static void
69 version (void)
70 {
71   printf ("D-BUS Message Bus Daemon %s\n"
72           "Copyright (C) 2002, 2003 Red Hat, Inc., CodeFactory AB, and others\n"
73           "This is free software; see the source for copying conditions.\n"
74           "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
75           VERSION);
76   exit (0);
77 }
78
79 static void
80 check_two_config_files (const DBusString *config_file,
81                         const char       *extra_arg)
82 {
83   if (_dbus_string_get_length (config_file) > 0)
84     {
85       fprintf (stderr, "--%s specified but configuration file %s already requested\n",
86                extra_arg, _dbus_string_get_const_data (config_file));
87       exit (1);
88     }
89 }
90
91 static void
92 check_two_addr_descriptors (const DBusString *addr_fd,
93                             const char       *extra_arg)
94 {
95   if (_dbus_string_get_length (addr_fd) > 0)
96     {
97       fprintf (stderr, "--%s specified but printing address to %s already requested\n",
98                extra_arg, _dbus_string_get_const_data (addr_fd));
99       exit (1);
100     }
101 }
102
103 static void
104 check_two_pid_descriptors (const DBusString *pid_fd,
105                            const char       *extra_arg)
106 {
107   if (_dbus_string_get_length (pid_fd) > 0)
108     {
109       fprintf (stderr, "--%s specified but printing pid to %s already requested\n",
110                extra_arg, _dbus_string_get_const_data (pid_fd));
111       exit (1);
112     }
113 }
114
115 static dbus_bool_t
116 handle_reload_watch (DBusWatch    *watch,
117                      unsigned int  flags,
118                      void         *data)
119 {
120   DBusError error;
121   DBusString str;
122   _dbus_string_init (&str);
123   if (_dbus_read (reload_pipe[RELOAD_READ_END], &str, 1) != 1)
124     {
125       _dbus_warn ("Couldn't read from reload pipe.\n");
126       exit (1);
127     }
128   _dbus_string_free (&str);
129
130   dbus_error_init (&error);
131   if (! bus_context_reload_config (context, &error))
132     {
133       _dbus_warn ("Unable to reload configuration: %s\n",
134                   error.message);
135       dbus_error_free (&error);
136       exit (1);
137     }
138   return TRUE;
139 }
140
141 static dbus_bool_t
142 reload_watch_callback (DBusWatch    *watch,
143                        unsigned int  condition,
144                        void         *data)
145 {
146   return dbus_watch_handle (watch, condition);
147 }
148
149 static void
150 setup_reload_pipe (DBusLoop *loop)
151 {
152   DBusError error;
153   DBusWatch *watch;
154
155   dbus_error_init (&error);
156
157   if (!_dbus_full_duplex_pipe (&reload_pipe[0], &reload_pipe[1],
158                                TRUE, &error))
159     {
160       _dbus_warn ("Unable to create reload pipe: %s\n",
161                   error.message);
162       dbus_error_free (&error);
163       exit (1);
164     }
165
166   watch = _dbus_watch_new (reload_pipe[RELOAD_READ_END],
167                            DBUS_WATCH_READABLE, TRUE,
168                            handle_reload_watch, NULL, NULL);
169
170   if (watch == NULL)
171     {
172       _dbus_warn ("Unable to create reload watch: %s\n",
173                   error.message);
174       dbus_error_free (&error);
175       exit (1);
176     }
177
178   if (!_dbus_loop_add_watch (loop, watch, reload_watch_callback,
179                              NULL, NULL))
180     {
181       _dbus_warn ("Unable to add reload watch to main loop: %s\n",
182                   error.message);
183       dbus_error_free (&error);
184       exit (1);
185     }
186
187 }
188
189 int
190 main (int argc, char **argv)
191 {
192   DBusError error;
193   DBusString config_file;
194   DBusString addr_fd;
195   DBusString pid_fd;
196   const char *prev_arg;
197   int print_addr_fd;
198   int print_pid_fd;
199   int i;
200   dbus_bool_t print_address;
201   dbus_bool_t print_pid;
202   dbus_bool_t force_fork;
203   
204   if (!_dbus_string_init (&config_file))
205     return 1;
206
207   if (!_dbus_string_init (&addr_fd))
208     return 1;
209
210   if (!_dbus_string_init (&pid_fd))
211     return 1;
212   
213   print_address = FALSE;
214   print_pid = FALSE;
215   force_fork = FALSE;
216   
217   prev_arg = NULL;
218   i = 1;
219   while (i < argc)
220     {
221       const char *arg = argv[i];
222       
223       if (strcmp (arg, "--help") == 0 ||
224           strcmp (arg, "-h") == 0 ||
225           strcmp (arg, "-?") == 0)
226         usage ();
227       else if (strcmp (arg, "--version") == 0)
228         version ();
229       else if (strcmp (arg, "--fork") == 0)
230         force_fork = TRUE;
231       else if (strcmp (arg, "--system") == 0)
232         {
233           check_two_config_files (&config_file, "system");
234
235           if (!_dbus_string_append (&config_file, DBUS_SYSTEM_CONFIG_FILE))
236             exit (1);
237         }
238       else if (strcmp (arg, "--session") == 0)
239         {
240           check_two_config_files (&config_file, "session");
241
242           if (!_dbus_string_append (&config_file, DBUS_SESSION_CONFIG_FILE))
243             exit (1);
244         }
245       else if (strstr (arg, "--config-file=") == arg)
246         {
247           const char *file;
248
249           check_two_config_files (&config_file, "config-file");
250           
251           file = strchr (arg, '=');
252           ++file;
253
254           if (!_dbus_string_append (&config_file, file))
255             exit (1);
256         }
257       else if (prev_arg &&
258                strcmp (prev_arg, "--config-file") == 0)
259         {
260           check_two_config_files (&config_file, "config-file");
261           
262           if (!_dbus_string_append (&config_file, arg))
263             exit (1);
264         }
265       else if (strcmp (arg, "--config-file") == 0)
266         ; /* wait for next arg */
267       else if (strstr (arg, "--print-address=") == arg)
268         {
269           const char *desc;
270
271           check_two_addr_descriptors (&addr_fd, "print-address");
272           
273           desc = strchr (arg, '=');
274           ++desc;
275
276           if (!_dbus_string_append (&addr_fd, desc))
277             exit (1);
278
279           print_address = TRUE;
280         }
281       else if (prev_arg &&
282                strcmp (prev_arg, "--print-address") == 0)
283         {
284           check_two_addr_descriptors (&addr_fd, "print-address");
285           
286           if (!_dbus_string_append (&addr_fd, arg))
287             exit (1);
288
289           print_address = TRUE;
290         }
291       else if (strcmp (arg, "--print-address") == 0)
292         print_address = TRUE; /* and we'll get the next arg if appropriate */
293       else if (strstr (arg, "--print-pid=") == arg)
294         {
295           const char *desc;
296
297           check_two_pid_descriptors (&pid_fd, "print-pid");
298           
299           desc = strchr (arg, '=');
300           ++desc;
301
302           if (!_dbus_string_append (&pid_fd, desc))
303             exit (1);
304
305           print_pid = TRUE;
306         }
307       else if (prev_arg &&
308                strcmp (prev_arg, "--print-pid") == 0)
309         {
310           check_two_pid_descriptors (&pid_fd, "print-pid");
311           
312           if (!_dbus_string_append (&pid_fd, arg))
313             exit (1);
314           
315           print_pid = TRUE;
316         }
317       else if (strcmp (arg, "--print-pid") == 0)
318         print_pid = TRUE; /* and we'll get the next arg if appropriate */
319       else
320         usage ();
321       
322       prev_arg = arg;
323       
324       ++i;
325     }
326
327   if (_dbus_string_get_length (&config_file) == 0)
328     {
329       fprintf (stderr, "No configuration file specified.\n");
330       usage ();
331     }
332
333   print_addr_fd = -1;
334   if (print_address)
335     {
336       print_addr_fd = 1; /* stdout */
337       if (_dbus_string_get_length (&addr_fd) > 0)
338         {
339           long val;
340           int end;
341           if (!_dbus_string_parse_int (&addr_fd, 0, &val, &end) ||
342               end != _dbus_string_get_length (&addr_fd) ||
343               val < 0 || val > _DBUS_INT_MAX)
344             {
345               fprintf (stderr, "Invalid file descriptor: \"%s\"\n",
346                        _dbus_string_get_const_data (&addr_fd));
347               exit (1);
348             }
349
350           print_addr_fd = val;
351         }
352     }
353
354   print_pid_fd = -1;
355   if (print_pid)
356     {
357       print_pid_fd = 1; /* stdout */
358       if (_dbus_string_get_length (&pid_fd) > 0)
359         {
360           long val;
361           int end;
362           if (!_dbus_string_parse_int (&pid_fd, 0, &val, &end) ||
363               end != _dbus_string_get_length (&pid_fd) ||
364               val < 0 || val > _DBUS_INT_MAX)
365             {
366               fprintf (stderr, "Invalid file descriptor: \"%s\"\n",
367                        _dbus_string_get_const_data (&pid_fd));
368               exit (1);
369             }
370
371           print_pid_fd = val;
372         }
373     }
374   
375   dbus_error_init (&error);
376   context = bus_context_new (&config_file, force_fork,
377                              print_addr_fd, print_pid_fd,
378                              &error);
379   _dbus_string_free (&config_file);
380   if (context == NULL)
381     {
382       _dbus_warn ("Failed to start message bus: %s\n",
383                   error.message);
384       dbus_error_free (&error);
385       exit (1);
386     }
387
388   setup_reload_pipe (bus_context_get_loop (context));
389  
390   _dbus_set_signal_handler (SIGHUP, signal_handler);
391   _dbus_set_signal_handler (SIGTERM, signal_handler);
392   
393   _dbus_verbose ("We are on D-Bus...\n");
394   _dbus_loop_run (bus_context_get_loop (context));
395   
396   bus_context_shutdown (context);
397   bus_context_unref (context);
398
399   return 0;
400 }