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