diff options
-rw-r--r-- | ChangeLog | 38 | ||||
-rw-r--r-- | bus/bus.c | 47 | ||||
-rw-r--r-- | bus/config-parser.c | 47 | ||||
-rw-r--r-- | bus/config-parser.h | 1 | ||||
-rwxr-xr-x | bus/messagebus.in | 12 | ||||
-rw-r--r-- | bus/system.conf.in | 5 | ||||
-rw-r--r-- | configure.in | 49 | ||||
-rw-r--r-- | dbus/Makefile.am | 2 | ||||
-rw-r--r-- | dbus/dbus-sysdeps.c | 130 | ||||
-rw-r--r-- | dbus/dbus-sysdeps.h | 15 |
10 files changed, 294 insertions, 52 deletions
@@ -1,5 +1,43 @@ 2003-04-06 Havoc Pennington <hp@pobox.com> + * dbus/dbus-sysdeps.c (_dbus_become_daemon): write the pidfile + here in the parent process, so we can return an error if it + fails. Also, move some of the code into the child so the parent + is less hosed if we fail midway through. + + * bus/bus.c (bus_context_new): move pidfile detection further up + in the function, before we start overwriting sockets and such. + + * bus/messagebus.in: adjust this a bit, not sure if it will work. + + * configure.in: add --with-system-pid-file and --with-system-socket + +2003-04-06 Colin Walters <walters@verbum.org> + + * configure.in (DBUS_SYSTEM_PID_FILE): New variable. + + * bus/system.conf.in: Declare a pidfile. + + * bus/bus.c (bus_context_new): Test for an existing pid file, and + create one (if appropriate). + + * bus/config-parser.c (enum ElementType) [ELEMENT_PIDFILE]: New. + (struct BusConfigParser) [pidfile]: New. + (element_type_to_name, merge_included, start_busconfig_child) + (bus_config_parser_end_element, bus_config_parser_content): Handle it. + (bus_config_parser_unref): Free it. + (bus_config_parser_get_pidfile): New function. + + * bus/config-parser.h (_dbus_write_pid_file): Prototype. + + * dbus/dbus-errors.h (DBUS_ERROR_PIDFILE_EXISTS): New error. + + * dbus/dbus-sysdeps.c (_dbus_write_pid_file): New function. + + * dbus/dbus-sysdeps.h: Prototype it. + +2003-04-06 Havoc Pennington <hp@pobox.com> + * bus/bus.c (bus_context_new): print the address in here, rather than in main(), because we need to do it before forking the daemon @@ -306,7 +306,7 @@ bus_context_new (const DBusString *config_file, DBusList **addresses; BusConfigParser *parser; DBusString full_address; - const char *user; + const char *user, *pidfile; char **auth_mechanisms; DBusList **auth_mechanisms_list; int len; @@ -333,6 +333,31 @@ bus_context_new (const DBusString *config_file, parser = bus_config_load (config_file, error); if (parser == NULL) goto failed; + + /* Check for an existing pid file. Of course this is a race; + * we'd have to use fcntl() locks on the pid file to + * avoid that. But we want to check for the pid file + * before overwriting any existing sockets, etc. + */ + pidfile = bus_config_parser_get_pidfile (parser); + if (pidfile != NULL) + { + DBusString u; + DBusStat stbuf; + DBusError tmp_error; + + dbus_error_init (&tmp_error); + _dbus_string_init_const (&u, pidfile); + + if (_dbus_stat (&u, &stbuf, &tmp_error)) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "The pid file \"%s\" exists, if the message bus is not running, remove this file", + pidfile); + dbus_error_free (&tmp_error); + goto failed; + } + } context = dbus_new0 (BusContext, 1); if (context == NULL) @@ -587,9 +612,27 @@ bus_context_new (const DBusString *config_file, /* Now become a daemon if appropriate */ if (bus_config_parser_get_fork (parser)) { - if (!_dbus_become_daemon (error)) + DBusString u; + + if (pidfile) + _dbus_string_init_const (&u, pidfile); + + if (!_dbus_become_daemon (pidfile ? &u : NULL, error)) goto failed; } + else + { + /* Need to write PID file for ourselves, not for the child process */ + if (pidfile != NULL) + { + DBusString u; + + _dbus_string_init_const (&u, pidfile); + + if (!_dbus_write_pid_file (&u, _dbus_getpid (), error)) + goto failed; + } + } bus_config_parser_unref (parser); _dbus_string_free (&full_address); diff --git a/bus/config-parser.c b/bus/config-parser.c index f9473ff9..1052dc2d 100644 --- a/bus/config-parser.c +++ b/bus/config-parser.c @@ -40,6 +40,7 @@ typedef enum ELEMENT_ALLOW, ELEMENT_DENY, ELEMENT_FORK, + ELEMENT_PIDFILE, ELEMENT_SERVICEDIR, ELEMENT_INCLUDEDIR, ELEMENT_TYPE @@ -94,6 +95,8 @@ struct BusConfigParser DBusList *service_dirs; /**< Directories to look for services in */ unsigned int fork : 1; /**< TRUE to fork into daemon mode */ + + char *pidfile; }; static const char* @@ -123,6 +126,8 @@ element_type_to_name (ElementType type) return "deny"; case ELEMENT_FORK: return "fork"; + case ELEMENT_PIDFILE: + return "pidfile"; case ELEMENT_SERVICEDIR: return "servicedir"; case ELEMENT_INCLUDEDIR: @@ -222,6 +227,13 @@ merge_included (BusConfigParser *parser, if (included->fork) parser->fork = TRUE; + + if (included->pidfile != NULL) + { + dbus_free (parser->pidfile); + parser->pidfile = included->pidfile; + included->pidfile = NULL; + } while ((link = _dbus_list_pop_first_link (&included->listen_on))) _dbus_list_append_link (&parser->listen_on, link); @@ -284,6 +296,7 @@ bus_config_parser_unref (BusConfigParser *parser) dbus_free (parser->user); dbus_free (parser->bus_type); + dbus_free (parser->pidfile); _dbus_list_foreach (&parser->listen_on, (DBusForeachFunction) dbus_free, @@ -499,6 +512,19 @@ start_busconfig_child (BusConfigParser *parser, return TRUE; } + else if (strcmp (element_name, "pidfile") == 0) + { + if (!check_no_attributes (parser, "pidfile", attribute_names, attribute_values, error)) + return FALSE; + + if (push_element (parser, ELEMENT_PIDFILE) == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } + + return TRUE; + } else if (strcmp (element_name, "listen") == 0) { if (!check_no_attributes (parser, "listen", attribute_names, attribute_values, error)) @@ -770,6 +796,7 @@ bus_config_parser_end_element (BusConfigParser *parser, case ELEMENT_USER: case ELEMENT_TYPE: case ELEMENT_LISTEN: + case ELEMENT_PIDFILE: case ELEMENT_AUTH: case ELEMENT_SERVICEDIR: case ELEMENT_INCLUDEDIR: @@ -1004,6 +1031,20 @@ bus_config_parser_content (BusConfigParser *parser, return FALSE; } + case ELEMENT_PIDFILE: + { + char *s; + + e->had_content = TRUE; + + if (!_dbus_string_copy_data (content, &s)) + goto nomem; + + dbus_free (parser->pidfile); + parser->pidfile = s; + } + break; + case ELEMENT_INCLUDE: { DBusString full_path; @@ -1222,6 +1263,12 @@ bus_config_parser_get_fork (BusConfigParser *parser) return parser->fork; } +const char * +bus_config_parser_get_pidfile (BusConfigParser *parser) +{ + return parser->pidfile; +} + #ifdef DBUS_BUILD_TESTS #include <stdio.h> diff --git a/bus/config-parser.h b/bus/config-parser.h index af5c8260..93d41003 100644 --- a/bus/config-parser.h +++ b/bus/config-parser.h @@ -60,6 +60,7 @@ const char* bus_config_parser_get_type (BusConfigParser *parser); DBusList** bus_config_parser_get_addresses (BusConfigParser *parser); DBusList** bus_config_parser_get_mechanisms (BusConfigParser *parser); dbus_bool_t bus_config_parser_get_fork (BusConfigParser *parser); +const char* bus_config_parser_get_pidfile (BusConfigParser *parser); DBusList** bus_config_parser_get_service_dirs (BusConfigParser *parser); /* Loader functions (backended off one of the XML parsers). Returns a diff --git a/bus/messagebus.in b/bus/messagebus.in index 60c70777..45388a5e 100755 --- a/bus/messagebus.in +++ b/bus/messagebus.in @@ -7,7 +7,7 @@ # and other messages. See http://www.freedesktop.org/software/dbus/ # # processname: dbus-daemon-1 -# pidfile: @EXPANDED_LOCALSTATEDIR@/messagebus.pid +# pidfile: @DBUS_SYSTEM_PID_FILE@ # # Sanity checks. @@ -20,7 +20,7 @@ RETVAL=0 start() { echo -n $"Starting system message bus: " - daemon dbus-daemon-1 --system + daemon --check messagebus dbus-daemon-1 --system RETVAL=$? echo [ $RETVAL -eq 0 ] && touch @EXPANDED_LOCALSTATEDIR@/lock/subsys/messagebus @@ -28,7 +28,11 @@ start() { stop() { echo -n $"Stopping system message bus: " - killproc messagebus + + ## we don't want to kill all the per-user dbus-daemon-1, we want + ## to use the pid file *only*; because we use the fake nonexistent + ## program name "messagebus" that should be safe-ish + killproc messagebus -TERM RETVAL=$? echo if [ $RETVAL -eq 0 ]; then @@ -59,7 +63,7 @@ case "$1" in fi ;; reload) - killproc messagebus -HUP + echo "Message bus can't reload its configuration, you have to restart it" RETVAL=$? ;; *) diff --git a/bus/system.conf.in b/bus/system.conf.in index 15a4972e..0e570575 100644 --- a/bus/system.conf.in +++ b/bus/system.conf.in @@ -20,11 +20,14 @@ <!-- Fork into daemon mode --> <fork/> + <!-- Write a pid file --> + <pidfile>@DBUS_SYSTEM_PID_FILE@</pidfile> + <!-- Only allow socket-credentials-based authentication --> <auth>EXTERNAL</auth> <!-- Only listen on a local socket --> - <listen>unix:path=@EXPANDED_LOCALSTATEDIR@/@DBUS_SYSTEM_SOCKET@</listen> + <listen>unix:path=@DBUS_SYSTEM_SOCKET@</listen> <policy context="default"> <!-- Deny everything then punch holes --> diff --git a/configure.in b/configure.in index d37a7c4b..e908d3ee 100644 --- a/configure.in +++ b/configure.in @@ -35,6 +35,8 @@ AC_ARG_WITH(xml, [ --with-xml=[libxml/expat] XML library to use] AC_ARG_WITH(init-scripts, [ --with-init-scripts=[redhat] Style of init scripts to install]) AC_ARG_WITH(session-socket-dir, [ --with-session-socket-dir=[dirname] Where to put sockets for the per-login-session message bus]) AC_ARG_WITH(test-socket-dir, [ --with-test-socket-dir=[dirname] Where to put sockets for make check]) +AC_ARG_WITH(system-pid-file, [ --with-system-pid-file=[pidfile] PID file for systemwide daemon]) +AC_ARG_WITH(system-socket, [ --with-system-socket=[filename] UNIX domain socket for systemwide daemon]) dnl DBUS_BUILD_TESTS controls unit tests built in to .c files dnl and also some stuff in the test/ subdir @@ -385,12 +387,9 @@ dnl Qt flags AC_SUBST(DBUS_QT_CXXFLAGS) AC_SUBST(DBUS_QT_LIBS) -##### Set up location for system bus socket -## name of socket relative to localstatedir -DBUS_SYSTEM_SOCKET=run/dbus/system_bus_socket -AC_SUBST(DBUS_SYSTEM_SOCKET) - #### find the actual value for $prefix that we'll end up with +## (I know this is broken and should be done in the Makefile, but +## that's a major pain and almost nobody actually seems to care) REAL_PREFIX= if test "x$prefix" = "xNONE"; then REAL_PREFIX=$ac_default_prefix @@ -421,18 +420,45 @@ EXPANDED_BINDIR=`eval echo $BINDIR_TMP` prefix=$old_prefix AC_SUBST(EXPANDED_BINDIR) +#### Check our operating system +operating_system=unknown +if test -f /etc/redhat-release || test -f $EXPANDED_SYSCONFDIR/redhat-release ; then + operating_system=redhat +fi + #### Sort out init scripts if test x$with_init_scripts = x; then - if test -f /etc/redhat-release || test -f $EXPANDED_SYSCONFDIR/redhat-release ; then - with_init_scripts=redhat - else - with_init_scripts=none - fi + if test xredhat = x$operating_system ; then + with_init_scripts=redhat + else + with_init_scripts=none + fi fi AM_CONDITIONAL(DBUS_INIT_SCRIPTS_RED_HAT, test x$with_init_scripts = xredhat) + +##### Set up location for system bus socket +if ! test -z "$with_system_socket"; then + DBUS_SYSTEM_SOCKET=$with_system_socket +else + DBUS_SYSTEM_SOCKET=${EXPANDED_LOCALSTATEDIR}/run/dbus/system_bus_socket +fi + +AC_SUBST(DBUS_SYSTEM_SOCKET) + +#### Set up the pid file +if ! test -z "$with_system_pid_file"; then + DBUS_SYSTEM_PID_FILE=$with_system_pid_file +elif test x$operating_system = xredhat ; then + DBUS_SYSTEM_PID_FILE=${EXPANDED_LOCALSTATEDIR}/run/messagebus.pid +else + DBUS_SYSTEM_PID_FILE=${EXPANDED_LOCALSTATEDIR}/run/dbus/pid +fi + +AC_SUBST(DBUS_SYSTEM_PID_FILE) + #### Tell tests where to find certain stuff in builddir ABSOLUTE_TOP_BUILDDIR=`cd ${ac_top_builddir}. && pwd` @@ -512,7 +538,8 @@ echo " Building GLib bindings: ${have_glib} Using XML parser: ${with_xml} Init scripts style: ${with_init_scripts} - System bus socket: ${EXPANDED_LOCALSTATEDIR}/${DBUS_SYSTEM_SOCKET} + System bus socket: ${DBUS_SYSTEM_SOCKET} + System bus PID file: ${DBUS_SYSTEM_PID_FILE} Session bus socket dir: ${DBUS_SESSION_SOCKET_DIR} 'make check' socket dir: ${TEST_SOCKET_DIR} " diff --git a/dbus/Makefile.am b/dbus/Makefile.am index 2065e75e..7d5ed501 100644 --- a/dbus/Makefile.am +++ b/dbus/Makefile.am @@ -1,6 +1,6 @@ INCLUDES=-I$(top_srcdir) $(DBUS_CLIENT_CFLAGS) -DDBUS_COMPILATION \ - -DDBUS_SYSTEM_BUS_PATH=\""@EXPANDED_LOCALSTATEDIR@/@DBUS_SYSTEM_SOCKET@"\" + -DDBUS_SYSTEM_BUS_PATH=\""@DBUS_SYSTEM_SOCKET@"\" dbusincludedir=$(includedir)/dbus-1.0/dbus diff --git a/dbus/dbus-sysdeps.c b/dbus/dbus-sysdeps.c index 7a389956..df921b17 100644 --- a/dbus/dbus-sysdeps.c +++ b/dbus/dbus-sysdeps.c @@ -1700,6 +1700,15 @@ _dbus_string_append_our_uid (DBusString *str) return _dbus_string_append_int (str, getuid ()); } +/** + * Gets our process ID + * @returns process ID + */ +unsigned long +_dbus_getpid (void) +{ + return getpid (); +} _DBUS_DEFINE_GLOBAL_LOCK (atomic); @@ -2930,17 +2939,17 @@ _dbus_print_backtrace (void) /** * Does the chdir, fork, setsid, etc. to become a daemon process. * + * @param pidfile #NULL, or pidfile to create * @param error return location for errors * @returns #FALSE on failure */ dbus_bool_t -_dbus_become_daemon (DBusError *error) +_dbus_become_daemon (const DBusString *pidfile, + DBusError *error) { const char *s; + pid_t child_pid; - /* This is so we don't prevent unmounting of devices. We divert - * all messages to syslog - */ if (chdir ("/") < 0) { dbus_set_error (error, DBUS_ERROR_FAILED, @@ -2948,29 +2957,7 @@ _dbus_become_daemon (DBusError *error) return FALSE; } - s = _dbus_getenv ("DBUS_DEBUG_OUTPUT"); - if (s == NULL || *s == '\0') - { - int dev_null_fd; - - /* silently ignore failures here, if someone - * doesn't have /dev/null we may as well try - * to continue anyhow - */ - - dev_null_fd = open ("/dev/null", O_RDWR); - if (dev_null_fd >= 0) - { - dup2 (dev_null_fd, 0); - dup2 (dev_null_fd, 1); - dup2 (dev_null_fd, 2); - } - } - - /* Get a predictable umask */ - umask (022); - - switch (fork ()) + switch ((child_pid = fork ())) { case -1: dbus_set_error (error, _dbus_error_from_errno (errno), @@ -2978,10 +2965,41 @@ _dbus_become_daemon (DBusError *error) return FALSE; break; - case 0: + case 0: + s = _dbus_getenv ("DBUS_DEBUG_OUTPUT"); + if (s == NULL || *s == '\0') + { + int dev_null_fd; + + /* silently ignore failures here, if someone + * doesn't have /dev/null we may as well try + * to continue anyhow + */ + + dev_null_fd = open ("/dev/null", O_RDWR); + if (dev_null_fd >= 0) + { + dup2 (dev_null_fd, 0); + dup2 (dev_null_fd, 1); + dup2 (dev_null_fd, 2); + } + } + + /* Get a predictable umask */ + umask (022); break; default: + if (pidfile) + { + if (!_dbus_write_pid_file (pidfile, + child_pid, + error)) + { + kill (child_pid, SIGTERM); + return FALSE; + } + } _exit (0); break; } @@ -2993,6 +3011,62 @@ _dbus_become_daemon (DBusError *error) } /** + * Creates a file containing the process ID. + * + * @param filename the filename to write to + * @param pid our process ID + * @param error return location for errors + * @returns #FALSE on failure + */ +dbus_bool_t +_dbus_write_pid_file (const DBusString *filename, + unsigned long pid, + DBusError *error) +{ + const char *cfilename; + int fd; + FILE *f; + + cfilename = _dbus_string_get_const_data (filename); + + fd = open (cfilename, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0644); + + if (fd < 0) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to open \"%s\": %s", cfilename, + _dbus_strerror (errno)); + return FALSE; + } + + if ((f = fdopen (fd, "w")) == NULL) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to fdopen fd %d: %s", fd, _dbus_strerror (errno)); + close (fd); + return FALSE; + } + + if (fprintf (f, "%lu\n", pid) < 0) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to write to \"%s\": %s", cfilename, + _dbus_strerror (errno)); + return FALSE; + } + + if (fclose (f) == EOF) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to close \"%s\": %s", cfilename, + _dbus_strerror (errno)); + return FALSE; + } + + return TRUE; +} + +/** * Changes the user and group the bus is running as. * * @param uid the new user ID diff --git a/dbus/dbus-sysdeps.h b/dbus/dbus-sysdeps.h index 933e2775..0a4a34dd 100644 --- a/dbus/dbus-sysdeps.h +++ b/dbus/dbus-sysdeps.h @@ -119,6 +119,8 @@ dbus_bool_t _dbus_get_groups (unsigned long uid, unsigned long **group_ids, int *n_group_ids); +unsigned long _dbus_getpid (void); + typedef int dbus_atomic_t; dbus_atomic_t _dbus_atomic_inc (dbus_atomic_t *atomic); @@ -216,11 +218,14 @@ dbus_bool_t _dbus_close (int fd, void _dbus_print_backtrace (void); -dbus_bool_t _dbus_become_daemon (DBusError *error); - -dbus_bool_t _dbus_change_identity (unsigned long uid, - unsigned long gid, - DBusError *error); +dbus_bool_t _dbus_become_daemon (const DBusString *pidfile, + DBusError *error); +dbus_bool_t _dbus_write_pid_file (const DBusString *filename, + unsigned long pid, + DBusError *error); +dbus_bool_t _dbus_change_identity (unsigned long uid, + unsigned long gid, + DBusError *error); typedef void (* DBusSignalHandler) (int sig); |