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 34static BusContext *context; 35 36static int reload_pipe[2]; 37#define RELOAD_READ_END 0 38#define RELOAD_WRITE_END 1 39 40 41static void 42signal_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 67static void 68usage (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 74static void 75version (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 85static void 86introspect (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} 109static void 110check_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 121static void 122check_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 133static void 134check_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 145static dbus_bool_t 146handle_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 171static dbus_bool_t 172reload_watch_callback (DBusWatch *watch, 173 unsigned int condition, 174 void *data) 175{ 176 return dbus_watch_handle (watch, condition); 177} 178 179static void 180setup_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 222int 223main (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