2003-04-06 Havoc Pennington <hp@pobox.com>
authorHavoc Pennington <hp@redhat.com>
Sun, 6 Apr 2003 23:15:41 +0000 (23:15 +0000)
committerHavoc Pennington <hp@redhat.com>
Sun, 6 Apr 2003 23:15:41 +0000 (23:15 +0000)
* 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.

ChangeLog
bus/bus.c
bus/config-parser.c
bus/config-parser.h
bus/messagebus.in
bus/system.conf.in
configure.in
dbus/Makefile.am
dbus/dbus-sysdeps.c
dbus/dbus-sysdeps.h

index ede733b3dd4412649e4d0147f43f71c9d162b899..75eed1b471c78b2d2b1cf3231453b55acbd6de4c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,41 @@
+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
index 880f35d1589adeeda18d8a24e523f4704cc6d53f..09a0b5bbf25dd0d0737065b330822ea87e20340c 100644 (file)
--- a/bus/bus.c
+++ b/bus/bus.c
@@ -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);
index f9473ff9ab3677ac1e9f14c189a294020e8f3f2e..1052dc2dddc927d888b135b3438aa1f7443fd815 100644 (file)
@@ -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,
@@ -497,6 +510,19 @@ start_busconfig_child (BusConfigParser   *parser,
 
       parser->fork = TRUE;
       
+      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)
@@ -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>
 
index af5c8260aa0a3f421934eb5d85bbc026147ce39e..93d4100332419ad6e8af9110e3f93f5845b707b1 100644 (file)
@@ -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
index 60c70777c9deee696ef88850bd233e0b30635cf6..45388a5ed9b22374537643ef04ee754b82588fc7 100755 (executable)
@@ -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=$?
         ;;
     *)
index 15a4972eda3bb53923f1eab00f6c6369529d2f78..0e570575acc1b32df8e6995bcede0fed35dec687 100644 (file)
   <!-- 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 -->
index d37a7c4b9757bdd17753c9fbaa451fbfe2f64649..e908d3ee7963ea91f649a7b65a834bdbb9a96029 100644 (file)
@@ -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}
 "
index 2065e75e8832294f53a2b5efbbdfe885bd76f76b..7d5ed501a3b99d52645890de99c6dbeea47c3045 100644 (file)
@@ -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
 
index 7a3899566d91d327709a0d07a5976ce9bd5f7d7f..df921b1739186e5387afa13d1b7c6439f5b040a4 100644 (file)
@@ -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;
     }
@@ -2992,6 +3010,62 @@ _dbus_become_daemon (DBusError *error)
   return TRUE;
 }
 
+/**
+ * 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.
  *
index 933e277559fa78402e3f49fac9212275bb4b4642..0a4a34dde069476df42f591d830aba7309b85c2b 100644 (file)
@@ -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);