Bug 14259 - Refactor _dbus_get_autolaunch_address
authorColin Walters <walters@verbum.org>
Mon, 13 Jul 2009 17:02:21 +0000 (13:02 -0400)
committerColin Walters <walters@verbum.org>
Tue, 14 Jul 2009 19:41:48 +0000 (15:41 -0400)
Split out the process-launching code, which can be reused for
other applications; in particular, a forthcoming patch to parse
output from launchd for MacOS X.
(cherry picked from commit 6b163e95e7a2318a98c16c0d0944337e38e62efa)

dbus/dbus-sysdeps-unix.c

index 6396378..a26f02d 100644 (file)
@@ -2863,23 +2863,30 @@ _dbus_get_tmpdir(void)
 }
 
 /**
- * Determines the address of the session bus by querying a
- * platform-specific method.
+ * Execute a subprocess, returning up to 1024 bytes of output
+ * into @p result.
  *
- * If successful, returns #TRUE and appends the address to @p
- * address. If a failure happens, returns #FALSE and
+ * If successful, returns #TRUE and appends the output to @p
+ * result. If a failure happens, returns #FALSE and
  * sets an error in @p error.
  *
- * @param address a DBusString where the address can be stored
+ * @note It's not an error if the subprocess terminates normally
+ * without writing any data to stdout. Verify the @p result length
+ * before and after this function call to cover this case.
+ *
+ * @param progname initial path to exec
+ * @param argv NULL-terminated list of arguments
+ * @param result a DBusString where the output can be append
  * @param error a DBusError to store the error in case of failure
  * @returns #TRUE on success, #FALSE if an error happened
  */
-dbus_bool_t
-_dbus_get_autolaunch_address (DBusString *address,
-                              DBusError  *error)
+static dbus_bool_t
+_read_subprocess_line_argv (const char *progpath,
+                            char       * const *argv,
+                            DBusString *result,
+                            DBusError  *error)
 {
-  static char *argv[6];
-  int address_pipe[2] = { -1, -1 };
+  int result_pipe[2] = { -1, -1 };
   int errors_pipe[2] = { -1, -1 };
   pid_t pid;
   int ret;
@@ -2907,48 +2914,26 @@ _dbus_get_autolaunch_address (DBusString *address,
   sigaddset (&new_set, SIGCHLD);
   sigprocmask (SIG_BLOCK, &new_set, &old_set);
   
-  if (!_dbus_get_local_machine_uuid_encoded (&uuid))
-    {
-      _DBUS_SET_OOM (error);
-      goto out;
-    }
-  
-  i = 0;
-  argv[i] = "dbus-launch";
-  ++i;
-  argv[i] = "--autolaunch";
-  ++i;
-  argv[i] = _dbus_string_get_data (&uuid);
-  ++i;
-  argv[i] = "--binary-syntax";
-  ++i;
-  argv[i] = "--close-stderr";
-  ++i;
-  argv[i] = NULL;
-  ++i;
-
-  _dbus_assert (i == _DBUS_N_ELEMENTS (argv));
-  
-  orig_len = _dbus_string_get_length (address);
+  orig_len = _dbus_string_get_length (result);
   
 #define READ_END        0
 #define WRITE_END       1
-  if (pipe (address_pipe) < 0)
+  if (pipe (result_pipe) < 0)
     {
       dbus_set_error (error, _dbus_error_from_errno (errno),
-                      "Failed to create a pipe: %s",
-                      _dbus_strerror (errno));
-      _dbus_verbose ("Failed to create a pipe to call dbus-launch: %s\n",
-                     _dbus_strerror (errno));
+                      "Failed to create a pipe to call %s: %s",
+                      progpath, _dbus_strerror (errno));
+      _dbus_verbose ("Failed to create a pipe to call %s: %s\n",
+                     progpath, _dbus_strerror (errno));
       goto out;
     }
   if (pipe (errors_pipe) < 0)
     {
       dbus_set_error (error, _dbus_error_from_errno (errno),
-                      "Failed to create a pipe: %s",
-                      _dbus_strerror (errno));
-      _dbus_verbose ("Failed to create a pipe to call dbus-launch: %s\n",
-                     _dbus_strerror (errno));
+                      "Failed to create a pipe to call %s: %s",
+                      progpath, _dbus_strerror (errno));
+      _dbus_verbose ("Failed to create a pipe to call %s: %s\n",
+                     progpath, _dbus_strerror (errno));
       goto out;
     }
 
@@ -2956,10 +2941,10 @@ _dbus_get_autolaunch_address (DBusString *address,
   if (pid < 0)
     {
       dbus_set_error (error, _dbus_error_from_errno (errno),
-                      "Failed to fork(): %s",
-                      _dbus_strerror (errno));
-      _dbus_verbose ("Failed to fork() to call dbus-launch: %s\n",
-                     _dbus_strerror (errno));
+                      "Failed to fork() to call %s: %s",
+                      progpath, _dbus_strerror (errno));
+      _dbus_verbose ("Failed to fork() to call %s: %s\n",
+                     progpath, _dbus_strerror (errno));
       goto out;
     }
 
@@ -2977,7 +2962,7 @@ _dbus_get_autolaunch_address (DBusString *address,
       _dbus_verbose ("/dev/null fd %d opened\n", fd);
       
       /* set-up stdXXX */
-      close (address_pipe[READ_END]);
+      close (result_pipe[READ_END]);
       close (errors_pipe[READ_END]);
       close (0);                /* close stdin */
       close (1);                /* close stdout */
@@ -2985,7 +2970,7 @@ _dbus_get_autolaunch_address (DBusString *address,
 
       if (dup2 (fd, 0) == -1)
         _exit (1);
-      if (dup2 (address_pipe[WRITE_END], 1) == -1)
+      if (dup2 (result_pipe[WRITE_END], 1) == -1)
         _exit (1);
       if (dup2 (errors_pipe[WRITE_END], 2) == -1)
         _exit (1);
@@ -3002,25 +2987,26 @@ _dbus_get_autolaunch_address (DBusString *address,
 
       sigprocmask(SIG_SETMASK, &old_set, NULL);
 
-      execv (DBUS_BINDIR "/dbus-launch", argv);
-
-      /* failed, try searching PATH */
-      execvp ("dbus-launch", argv);
+      /* If it looks fully-qualified, try execv first */
+      if (progpath[0] == '/')
+        execv (progpath, argv);
+      else
+        execvp (progpath, argv);
 
       /* still nothing, we failed */
       _exit (1);
     }
 
   /* parent process */
-  close (address_pipe[WRITE_END]);
+  close (result_pipe[WRITE_END]);
   close (errors_pipe[WRITE_END]);
-  address_pipe[WRITE_END] = -1;
+  result_pipe[WRITE_END] = -1;
   errors_pipe[WRITE_END] = -1;
 
   ret = 0;
   do 
     {
-      ret = _dbus_read (address_pipe[READ_END], address, 1024);
+      ret = _dbus_read (result_pipe[READ_END], result, 1024);
     }
   while (ret > 0);
 
@@ -3033,27 +3019,27 @@ _dbus_get_autolaunch_address (DBusString *address,
 
   /* We succeeded if the process exited with status 0 and
      anything was read */
-  if (!WIFEXITED (status) || WEXITSTATUS (status) != 0 ||
-      _dbus_string_get_length (address) == orig_len)
+  if (!WIFEXITED (status) || WEXITSTATUS (status) != 0 )
     {
       /* The process ended with error */
       DBusString error_message;
       _dbus_string_init (&error_message);
       ret = 0;
       do
-       {
-         ret = _dbus_read (errors_pipe[READ_END], &error_message, 1024);
-       }
+        {
+          ret = _dbus_read (errors_pipe[READ_END], &error_message, 1024);
+        }
       while (ret > 0);
 
-      _dbus_string_set_length (address, orig_len);
+      _dbus_string_set_length (result, orig_len);
       if (_dbus_string_get_length (&error_message) > 0)
-       dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED,
-                       "dbus-launch failed to autolaunch D-Bus session: %s",
-                       _dbus_string_get_data (&error_message));
+        dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED,
+                        "%s terminated abnormally with the following error: %s",
+                        progpath, _dbus_string_get_data (&error_message));
       else
-       dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED,
-                       "Failed to execute dbus-launch to autolaunch D-Bus session");
+        dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED,
+                        "%s terminated abnormally without any error message",
+                        progpath);
       goto out;
     }
 
@@ -3067,15 +3053,73 @@ _dbus_get_autolaunch_address (DBusString *address,
   else
     _DBUS_ASSERT_ERROR_IS_SET (error);
 
-  if (address_pipe[0] != -1)
-    close (address_pipe[0]);
-  if (address_pipe[1] != -1)
-    close (address_pipe[1]);
+  if (result_pipe[0] != -1)
+    close (result_pipe[0]);
+  if (result_pipe[1] != -1)
+    close (result_pipe[1]);
   if (errors_pipe[0] != -1)
     close (errors_pipe[0]);
   if (errors_pipe[1] != -1)
     close (errors_pipe[1]);
 
+  return retval;  
+}
+
+/**
+ * Returns the address of a new session bus.
+ *
+ * If successful, returns #TRUE and appends the address to @p
+ * address. If a failure happens, returns #FALSE and
+ * sets an error in @p error.
+ *
+ * @param address a DBusString where the address can be stored
+ * @param error a DBusError to store the error in case of failure
+ * @returns #TRUE on success, #FALSE if an error happened
+ */
+dbus_bool_t
+_dbus_get_autolaunch_address (DBusString *address,
+                              DBusError  *error)
+{
+  static char *argv[6];
+  int i;
+  DBusString uuid;
+  dbus_bool_t retval;
+  
+  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+  retval = FALSE;
+
+  if (!_dbus_string_init (&uuid))
+    {
+      _DBUS_SET_OOM (error);
+      return FALSE;
+    }
+  
+  if (!_dbus_get_local_machine_uuid_encoded (&uuid))
+    {
+      _DBUS_SET_OOM (error);
+      goto out;
+    }
+  
+  i = 0;
+  argv[i] = "dbus-launch";
+  ++i;
+  argv[i] = "--autolaunch";
+  ++i;
+  argv[i] = _dbus_string_get_data (&uuid);
+  ++i;
+  argv[i] = "--binary-syntax";
+  ++i;
+  argv[i] = "--close-stderr";
+  ++i;
+  argv[i] = NULL;
+  ++i;
+
+  _dbus_assert (i == _DBUS_N_ELEMENTS (argv));
+
+  retval = _read_subprocess_line_argv (DBUS_BINDIR "/dbus-launch", 
+                                       argv, address, error);
+
+ out:
   _dbus_string_free (&uuid);
   return retval;
 }