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