[daemon-fix] Changed the way of make bus address when the address is not given
[platform/upstream/dbus.git] / dbus / dbus-sysdeps-unix.c
index 42aa967..1cb4a58 100644 (file)
@@ -1,11 +1,11 @@
 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 /* dbus-sysdeps-unix.c Wrappers around UNIX system/libc features (internal to D-Bus implementation)
- * 
+ *
  * Copyright (C) 2002, 2003, 2006  Red Hat, Inc.
  * Copyright (C) 2003 CodeFactory AB
  *
  * Licensed under the Academic Free License version 2.1
- * 
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  *
  */
 
@@ -34,6 +34,7 @@
 #include "dbus-userdb.h"
 #include "dbus-list.h"
 #include "dbus-credentials.h"
+#include "dbus-nonce.h"
 
 #include <sys/types.h>
 #include <stdlib.h>
@@ -54,6 +55,7 @@
 #include <netinet/in.h>
 #include <netdb.h>
 #include <grp.h>
+#include <arpa/inet.h>
 
 #ifdef HAVE_ERRNO_H
 #include <errno.h>
 #ifdef HAVE_GETPEERUCRED
 #include <ucred.h>
 #endif
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#endif
 
 #ifdef HAVE_ADT
 #include <bsm/adt.h>
 #endif
 
+#include "sd-daemon.h"
+
+#if !DBUS_USE_SYNC
+#include <pthread.h>
+#endif
+
 #ifndef O_BINARY
 #define O_BINARY 0
 #endif
 #define socklen_t int
 #endif
 
+#if defined (__sun) || defined (__sun__)
+/*
+ * CMS_SPACE etc. definitions for Solaris < 10, based on
+ *   http://mailman.videolan.org/pipermail/vlc-devel/2006-May/024402.html
+ * via
+ *   http://wiki.opencsw.org/porting-faq#toc10
+ *
+ * These are only redefined for Solaris, for now: if your OS needs these too,
+ * please file a bug. (Or preferably, improve your OS so they're not needed.)
+ */
+
+# ifndef CMSG_ALIGN
+#   ifdef __sun__
+#     define CMSG_ALIGN(len) _CMSG_DATA_ALIGN (len)
+#   else
+      /* aligning to sizeof (long) is assumed to be portable (fd.o#40235) */
+#     define CMSG_ALIGN(len) (((len) + sizeof (long) - 1) & \
+                              ~(sizeof (long) - 1))
+#   endif
+# endif
+
+# ifndef CMSG_SPACE
+#   define CMSG_SPACE(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + \
+                            CMSG_ALIGN (len))
+# endif
+
+# ifndef CMSG_LEN
+#   define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len))
+# endif
+
+#endif /* Solaris */
+
 static dbus_bool_t
 _dbus_open_socket (int              *fd_p,
                    int               domain,
@@ -129,13 +172,6 @@ _dbus_open_socket (int              *fd_p,
     }
 }
 
-dbus_bool_t
-_dbus_open_tcp_socket (int              *fd,
-                       DBusError        *error)
-{
-  return _dbus_open_socket(fd, AF_INET, SOCK_STREAM, 0, error);
-}
-
 /**
  * Opens a UNIX domain socket (as in the socket() call).
  * Does not bind the socket.
@@ -146,7 +182,7 @@ _dbus_open_tcp_socket (int              *fd,
  * @param error return location for an error
  * @returns #FALSE if error is set
  */
-dbus_bool_t
+static dbus_bool_t
 _dbus_open_unix_socket (int              *fd,
                         DBusError        *error)
 {
@@ -161,7 +197,7 @@ _dbus_open_unix_socket (int              *fd,
  * @param error return location for an error
  * @returns #FALSE if error is set
  */
-dbus_bool_t 
+dbus_bool_t
 _dbus_close_socket (int               fd,
                     DBusError        *error)
 {
@@ -201,7 +237,7 @@ _dbus_write_socket (int               fd,
                     int               start,
                     int               len)
 {
-#ifdef MSG_NOSIGNAL
+#if HAVE_DECL_MSG_NOSIGNAL
   const char *data;
   int bytes_written;
 
@@ -439,7 +475,7 @@ _dbus_write_socket_with_unix_fds_two(int               fd,
  again:
 
   bytes_written = sendmsg (fd, &m, 0
-#ifdef MSG_NOSIGNAL
+#if HAVE_DECL_MSG_NOSIGNAL
                            |MSG_NOSIGNAL
 #endif
                            );
@@ -457,60 +493,9 @@ _dbus_write_socket_with_unix_fds_two(int               fd,
 }
 
 /**
- * write data to a pipe.
- *
- * @param pipe the pipe instance
- * @param buffer the buffer to write data from
- * @param start the first byte in the buffer to write
- * @param len the number of bytes to try to write
- * @param error error return
- * @returns the number of bytes written or -1 on error
- */
-int
-_dbus_pipe_write (DBusPipe         *pipe,
-                  const DBusString *buffer,
-                  int               start,
-                  int               len,
-                  DBusError        *error)
-{
-  int written;
-  
-  written = _dbus_write (pipe->fd_or_handle, buffer, start, len);
-  if (written < 0)
-    {
-      dbus_set_error (error, DBUS_ERROR_FAILED,
-                      "Writing to pipe: %s\n",
-                      _dbus_strerror (errno));
-    }
-  return written;
-}
-
-/**
- * close a pipe.
- *
- * @param pipe the pipe instance
- * @param error return location for an error
- * @returns #FALSE if error is set
- */
-int
-_dbus_pipe_close  (DBusPipe         *pipe,
-                   DBusError        *error)
-{
-  if (_dbus_close (pipe->fd_or_handle, error) < 0)
-    {
-      return -1;
-    }
-  else
-    {
-      _dbus_pipe_invalidate (pipe);
-      return 0;
-    }
-}
-
-/**
  * Like _dbus_write_two() but only works on sockets and is thus
  * available on Windows.
- * 
+ *
  * @param fd the file descriptor
  * @param buffer1 first buffer
  * @param start1 first byte to write in first buffer
@@ -529,7 +514,7 @@ _dbus_write_socket_two (int               fd,
                         int               start2,
                         int               len2)
 {
-#ifdef MSG_NOSIGNAL
+#if HAVE_DECL_MSG_NOSIGNAL
   struct iovec vectors[2];
   const char *data1;
   const char *data2;
@@ -577,6 +562,11 @@ _dbus_write_socket_two (int               fd,
 #endif
 }
 
+dbus_bool_t
+_dbus_socket_is_invalid (int fd)
+{
+    return fd < 0 ? TRUE : FALSE;
+}
 
 /**
  * Thin wrapper around the read() system call that appends
@@ -588,7 +578,7 @@ _dbus_write_socket_two (int               fd,
  *
  * Unlike _dbus_read_socket(), _dbus_read() is not available
  * on Windows.
- * 
+ *
  * @param fd the file descriptor to read from
  * @param buffer the buffer to append data to
  * @param count the amount of data to read
@@ -604,7 +594,7 @@ _dbus_read (int               fd,
   char *data;
 
   _dbus_assert (count >= 0);
-  
+
   start = _dbus_string_get_length (buffer);
 
   if (!_dbus_string_lengthen (buffer, count))
@@ -616,7 +606,7 @@ _dbus_read (int               fd,
   data = _dbus_string_get_data_len (buffer, start, count);
 
  again:
-  
+
   bytes_read = read (fd, data, count);
 
   if (bytes_read < 0)
@@ -639,7 +629,7 @@ _dbus_read (int               fd,
       if (bytes_read > 0)
         _dbus_verbose_bytes_of_string (buffer, start, bytes_read);
 #endif
-      
+
       return bytes_read;
     }
 }
@@ -647,7 +637,7 @@ _dbus_read (int               fd,
 /**
  * Thin wrapper around the write() system call that writes a part of a
  * DBusString and handles EINTR for you.
- * 
+ *
  * @param fd the file descriptor to write
  * @param buffer the buffer to write data from
  * @param start the first byte in the buffer to write
@@ -662,9 +652,9 @@ _dbus_write (int               fd,
 {
   const char *data;
   int bytes_written;
-  
+
   data = _dbus_string_get_const_data_len (buffer, start, len);
-  
+
  again:
 
   bytes_written = write (fd, data, len);
@@ -676,7 +666,7 @@ _dbus_write (int               fd,
   if (bytes_written > 0)
     _dbus_verbose_bytes_of_string (buffer, start, bytes_written);
 #endif
-  
+
   return bytes_written;
 }
 
@@ -714,7 +704,7 @@ _dbus_write_two (int               fd,
   _dbus_assert (start2 >= 0);
   _dbus_assert (len1 >= 0);
   _dbus_assert (len2 >= 0);
-  
+
 #ifdef HAVE_WRITEV
   {
     struct iovec vectors[2];
@@ -732,40 +722,40 @@ _dbus_write_two (int               fd,
         start2 = 0;
         len2 = 0;
       }
-   
+
     vectors[0].iov_base = (char*) data1;
     vectors[0].iov_len = len1;
     vectors[1].iov_base = (char*) data2;
     vectors[1].iov_len = len2;
 
   again:
-   
+
     bytes_written = writev (fd,
                             vectors,
                             data2 ? 2 : 1);
 
     if (bytes_written < 0 && errno == EINTR)
       goto again;
-   
+
     return bytes_written;
   }
 #else /* HAVE_WRITEV */
   {
     int ret1;
-    
+
     ret1 = _dbus_write (fd, buffer1, start1, len1);
     if (ret1 == len1 && buffer2 != NULL)
       {
         ret2 = _dbus_write (fd, buffer2, start2, len2);
         if (ret2 < 0)
           ret2 = 0; /* we can't report an error as the first write was OK */
-       
+
         return ret1 + ret2;
       }
     else
       return ret1;
   }
-#endif /* !HAVE_WRITEV */   
+#endif /* !HAVE_WRITEV */
 }
 
 #define _DBUS_MAX_SUN_PATH_LENGTH 99
@@ -787,7 +777,7 @@ _dbus_write_two (int               fd,
  * Creates a socket and connects it to the UNIX domain socket at the
  * given path.  The connection fd is returned, and is set up as
  * nonblocking.
- * 
+ *
  * Uses abstract sockets instead of filesystem-linked sockets if
  * requested (it's possible only on Linux; see "man 7 unix" on Linux).
  * On non-Linux abstract socket usage always fails.
@@ -806,14 +796,14 @@ _dbus_connect_unix_socket (const char     *path,
 {
   int fd;
   size_t path_len;
-  struct sockaddr_un addr;  
+  struct sockaddr_un addr;
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
   _dbus_verbose ("connecting to unix socket %s abstract=%d\n",
                  path, abstract);
-  
-  
+
+
   if (!_dbus_open_unix_socket (&fd, error))
     {
       _DBUS_ASSERT_ERROR_IS_SET(error);
@@ -838,7 +828,7 @@ _dbus_connect_unix_socket (const char     *path,
           _dbus_close (fd, NULL);
           return -1;
        }
-       
+
       strncpy (&addr.sun_path[1], path, path_len);
       /* _dbus_verbose_bytes (addr.sun_path, sizeof (addr.sun_path)); */
 #else /* HAVE_ABSTRACT_SOCKETS */
@@ -860,27 +850,23 @@ _dbus_connect_unix_socket (const char     *path,
 
       strncpy (addr.sun_path, path, path_len);
     }
-  
+
   if (connect (fd, (struct sockaddr*) &addr, _DBUS_STRUCT_OFFSET (struct sockaddr_un, sun_path) + path_len) < 0)
-    {      
+    {
       dbus_set_error (error,
                       _dbus_error_from_errno (errno),
                       "Failed to connect to socket %s: %s",
                       path, _dbus_strerror (errno));
 
       _dbus_close (fd, NULL);
-      fd = -1;
-      
       return -1;
     }
 
   if (!_dbus_set_fd_nonblocking (fd, error))
     {
       _DBUS_ASSERT_ERROR_IS_SET (error);
-      
-      _dbus_close (fd, NULL);
-      fd = -1;
 
+      _dbus_close (fd, NULL);
       return -1;
     }
 
@@ -888,6 +874,96 @@ _dbus_connect_unix_socket (const char     *path,
 }
 
 /**
+ * Creates a UNIX domain socket and connects it to the specified
+ * process to execute.
+ *
+ * This will set FD_CLOEXEC for the socket returned.
+ *
+ * @param path the path to the executable
+ * @param argv the argument list for the process to execute.
+ * argv[0] typically is identical to the path of the executable
+ * @param error return location for error code
+ * @returns connection file descriptor or -1 on error
+ */
+int
+_dbus_connect_exec (const char     *path,
+                    char *const    argv[],
+                    DBusError      *error)
+{
+  int fds[2];
+  pid_t pid;
+
+  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+  _dbus_verbose ("connecting to process %s\n", path);
+
+  if (socketpair (AF_UNIX, SOCK_STREAM
+#ifdef SOCK_CLOEXEC
+                  |SOCK_CLOEXEC
+#endif
+                  , 0, fds) < 0)
+    {
+      dbus_set_error (error,
+                      _dbus_error_from_errno (errno),
+                      "Failed to create socket pair: %s",
+                      _dbus_strerror (errno));
+      return -1;
+    }
+
+  _dbus_fd_set_close_on_exec (fds[0]);
+  _dbus_fd_set_close_on_exec (fds[1]);
+
+  pid = fork ();
+  if (pid < 0)
+    {
+      dbus_set_error (error,
+                      _dbus_error_from_errno (errno),
+                      "Failed to fork() to call %s: %s",
+                      path, _dbus_strerror (errno));
+      close (fds[0]);
+      close (fds[1]);
+      return -1;
+    }
+
+  if (pid == 0)
+    {
+      /* child */
+      close (fds[0]);
+
+      dup2 (fds[1], STDIN_FILENO);
+      dup2 (fds[1], STDOUT_FILENO);
+
+      if (fds[1] != STDIN_FILENO &&
+          fds[1] != STDOUT_FILENO)
+        close (fds[1]);
+
+      /* Inherit STDERR and the controlling terminal from the
+         parent */
+
+      _dbus_close_all ();
+
+      execvp (path, argv);
+
+      fprintf (stderr, "Failed to execute process %s: %s\n", path, _dbus_strerror (errno));
+
+      _exit(1);
+    }
+
+  /* parent */
+  close (fds[1]);
+
+  if (!_dbus_set_fd_nonblocking (fds[0], error))
+    {
+      _DBUS_ASSERT_ERROR_IS_SET (error);
+
+      close (fds[0]);
+      return -1;
+    }
+
+  return fds[0];
+}
+
+/**
  * Enables or disables the reception of credentials on the given socket during
  * the next message transmission.  This is only effective if the #LOCAL_CREDS
  * system feature exists, in which case the other side of the connection does
@@ -902,10 +978,10 @@ _dbus_set_local_creds (int fd, dbus_bool_t on)
   dbus_bool_t retval = TRUE;
 
 #if defined(HAVE_CMSGCRED)
-  /* NOOP just to make sure only one codepath is used 
+  /* NOOP just to make sure only one codepath is used
    *      and to prefer CMSGCRED
    */
-#elif defined(LOCAL_CREDS) 
+#elif defined(LOCAL_CREDS)
   int val = on ? 1 : 0;
   if (setsockopt (fd, 0, LOCAL_CREDS, &val, sizeof (val)) < 0)
     {
@@ -945,12 +1021,13 @@ _dbus_listen_unix_socket (const char     *path,
   int listen_fd;
   struct sockaddr_un addr;
   size_t path_len;
+  unsigned int reuseaddr;
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
   _dbus_verbose ("listening on unix socket %s abstract=%d\n",
                  path, abstract);
-  
+
   if (!_dbus_open_unix_socket (&listen_fd, error))
     {
       _DBUS_ASSERT_ERROR_IS_SET(error);
@@ -961,7 +1038,7 @@ _dbus_listen_unix_socket (const char     *path,
   _DBUS_ZERO (addr);
   addr.sun_family = AF_UNIX;
   path_len = strlen (path);
-  
+
   if (abstract)
     {
 #ifdef HAVE_ABSTRACT_SOCKETS
@@ -978,7 +1055,7 @@ _dbus_listen_unix_socket (const char     *path,
           _dbus_close (listen_fd, NULL);
           return -1;
        }
-      
+
       strncpy (&addr.sun_path[1], path, path_len);
       /* _dbus_verbose_bytes (addr.sun_path, sizeof (addr.sun_path)); */
 #else /* HAVE_ABSTRACT_SOCKETS */
@@ -1015,10 +1092,17 @@ _dbus_listen_unix_socket (const char     *path,
           _dbus_close (listen_fd, NULL);
           return -1;
        }
-       
+
       strncpy (addr.sun_path, path, path_len);
     }
-  
+
+  reuseaddr = 1;
+  if (setsockopt  (listen_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(reuseaddr))==-1)
+    {
+      _dbus_warn ("Failed to set socket option\"%s\": %s",
+                  path, _dbus_strerror (errno));
+    }
+
   if (bind (listen_fd, (struct sockaddr*) &addr, _DBUS_STRUCT_OFFSET (struct sockaddr_un, sun_path) + path_len) < 0)
     {
       dbus_set_error (error, _dbus_error_from_errno (errno),
@@ -1052,19 +1136,118 @@ _dbus_listen_unix_socket (const char     *path,
       _dbus_close (listen_fd, NULL);
       return -1;
     }
-  
+
   /* Try opening up the permissions, but if we can't, just go ahead
    * and continue, maybe it will be good enough.
    */
   if (!abstract && chmod (path, 0777) < 0)
     _dbus_warn ("Could not set mode 0777 on socket %s\n",
                 path);
-  
+
   return listen_fd;
 }
 
 /**
- * Creates a socket and connects to a socket at the given host 
+ * Acquires one or more sockets passed in from systemd. The sockets
+ * are set to be nonblocking.
+ *
+ * This will set FD_CLOEXEC for the sockets returned.
+ *
+ * @param fds the file descriptors
+ * @param error return location for errors
+ * @returns the number of file descriptors
+ */
+int
+_dbus_listen_systemd_sockets (int       **fds,
+                              DBusError *error)
+{
+  int r, n;
+  unsigned fd;
+  int *new_fds;
+
+  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+  n = sd_listen_fds (TRUE);
+  if (n < 0)
+    {
+      dbus_set_error (error, _dbus_error_from_errno (-n),
+                      "Failed to acquire systemd socket: %s",
+                      _dbus_strerror (-n));
+      return -1;
+    }
+
+  if (n <= 0)
+    {
+      dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
+                      "No socket received.");
+      return -1;
+    }
+
+  for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++)
+    {
+      r = sd_is_socket (fd, AF_UNSPEC, SOCK_STREAM, 1);
+      if (r < 0)
+        {
+          dbus_set_error (error, _dbus_error_from_errno (-r),
+                          "Failed to verify systemd socket type: %s",
+                          _dbus_strerror (-r));
+          return -1;
+        }
+
+      if (!r)
+        {
+          dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
+                          "Passed socket has wrong type.");
+          return -1;
+        }
+    }
+
+  /* OK, the file descriptors are all good, so let's take posession of
+     them then. */
+
+  new_fds = dbus_new (int, n);
+  if (!new_fds)
+    {
+      dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
+                      "Failed to allocate file handle array.");
+      goto fail;
+    }
+
+  for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++)
+    {
+      if (!_dbus_set_local_creds (fd, TRUE))
+        {
+          dbus_set_error (error, _dbus_error_from_errno (errno),
+                          "Failed to enable LOCAL_CREDS on systemd socket: %s",
+                          _dbus_strerror (errno));
+          goto fail;
+        }
+
+      if (!_dbus_set_fd_nonblocking (fd, error))
+        {
+          _DBUS_ASSERT_ERROR_IS_SET (error);
+          goto fail;
+        }
+
+      new_fds[fd - SD_LISTEN_FDS_START] = fd;
+    }
+
+  *fds = new_fds;
+  return n;
+
+ fail:
+
+  for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++)
+    {
+      _dbus_close (fd, NULL);
+    }
+
+  dbus_free (new_fds);
+  return -1;
+}
+
+/**
+ * Creates a socket and connects to a socket at the given host
  * and port. The connection fd is returned, and is set up as
  * nonblocking.
  *
@@ -1082,19 +1265,21 @@ _dbus_connect_tcp_socket (const char     *host,
                           const char     *family,
                           DBusError      *error)
 {
+    return _dbus_connect_tcp_socket_with_nonce (host, port, family, (const char*)NULL, error);
+}
+
+int
+_dbus_connect_tcp_socket_with_nonce (const char     *host,
+                                     const char     *port,
+                                     const char     *family,
+                                     const char     *noncefile,
+                                     DBusError      *error)
+{
   int saved_errno = 0;
   int fd = -1, res;
   struct addrinfo hints;
   struct addrinfo *ai, *tmp;
 
-  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-
-  if (!_dbus_open_tcp_socket (&fd, error))
-    {
-      _DBUS_ASSERT_ERROR_IS_SET(error);
-      return -1;
-    }
-
   _DBUS_ASSERT_ERROR_IS_CLEAR(error);
 
   _DBUS_ZERO (hints);
@@ -1122,7 +1307,6 @@ _dbus_connect_tcp_socket (const char     *host,
                       _dbus_error_from_errno (errno),
                       "Failed to lookup host/port: \"%s:%s\": %s (%d)",
                       host, port, gai_strerror(res), res);
-      _dbus_close (fd, NULL);
       return -1;
     }
 
@@ -1159,12 +1343,24 @@ _dbus_connect_tcp_socket (const char     *host,
       return -1;
     }
 
+  if (noncefile != NULL)
+    {
+      DBusString noncefileStr;
+      dbus_bool_t ret;
+      _dbus_string_init_const (&noncefileStr, noncefile);
+      ret = _dbus_send_nonce (fd, &noncefileStr, error);
+      _dbus_string_free (&noncefileStr);
 
-  if (!_dbus_set_fd_nonblocking (fd, error))
+      if (!ret)
     {
       _dbus_close (fd, NULL);
-      fd = -1;
+          return -1;
+        }
+    }
 
+  if (!_dbus_set_fd_nonblocking (fd, error))
+    {
+      _dbus_close (fd, NULL);
       return -1;
     }
 
@@ -1199,6 +1395,7 @@ _dbus_listen_tcp_socket (const char     *host,
   int nlisten_fd = 0, *listen_fd = NULL, res, i;
   struct addrinfo hints;
   struct addrinfo *ai, *tmp;
+  unsigned int reuseaddr;
 
   *fds_p = NULL;
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
@@ -1224,13 +1421,14 @@ _dbus_listen_tcp_socket (const char     *host,
   hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE;
 
  redo_lookup_with_port:
+  ai = NULL;
   if ((res = getaddrinfo(host, port, &hints, &ai)) != 0 || !ai)
     {
       dbus_set_error (error,
                       _dbus_error_from_errno (errno),
                       "Failed to lookup host/port: \"%s:%s\": %s (%d)",
                       host ? host : "*", port, gai_strerror(res), res);
-      return -1;
+      goto failed;
     }
 
   tmp = ai;
@@ -1244,6 +1442,13 @@ _dbus_listen_tcp_socket (const char     *host,
         }
       _DBUS_ASSERT_ERROR_IS_CLEAR(error);
 
+      reuseaddr = 1;
+      if (setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(reuseaddr))==-1)
+        {
+          _dbus_warn ("Failed to set socket option \"%s:%s\": %s",
+                      host ? host : "*", port, _dbus_strerror (errno));
+        }
+
       if (bind (fd, (struct sockaddr*) tmp->ai_addr, tmp->ai_addrlen) < 0)
         {
           saved_errno = errno;
@@ -1294,16 +1499,18 @@ _dbus_listen_tcp_socket (const char     *host,
              to use the same port */
           if (!port || !strcmp(port, "0"))
             {
+              int result;
               struct sockaddr_storage addr;
               socklen_t addrlen;
               char portbuf[50];
 
               addrlen = sizeof(addr);
-              getsockname(fd, (struct sockaddr*) &addr, &addrlen);
+              result = getsockname(fd, (struct sockaddr*) &addr, &addrlen);
 
-              if ((res = getnameinfo((struct sockaddr*)&addr, addrlen, NULL, 0,
-                                     portbuf, sizeof(portbuf),
-                                     NI_NUMERICHOST)) != 0)
+              if (result == -1 ||
+                  (res = getnameinfo ((struct sockaddr*)&addr, addrlen, NULL, 0,
+                                      portbuf, sizeof(portbuf),
+                                      NI_NUMERICHOST)) != 0)
                 {
                   dbus_set_error (error, _dbus_error_from_errno (errno),
                                   "Failed to resolve port \"%s:%s\": %s (%s)",
@@ -1342,7 +1549,7 @@ _dbus_listen_tcp_socket (const char     *host,
       dbus_set_error (error, _dbus_error_from_errno (errno),
                       "Failed to bind socket \"%s:%s\": %s",
                       host ? host : "*", port, _dbus_strerror (errno));
-      return -1;
+      goto failed;
     }
 
   for (i = 0 ; i < nlisten_fd ; i++)
@@ -1372,10 +1579,10 @@ write_credentials_byte (int             server_fd,
 {
   int bytes_written;
   char buf[1] = { '\0' };
-#if defined(HAVE_CMSGCRED) 
-  struct {
+#if defined(HAVE_CMSGCRED)
+  union {
          struct cmsghdr hdr;
-         struct cmsgcred cred;
+         char cred[CMSG_SPACE (sizeof (struct cmsgcred))];
   } cmsg;
   struct iovec iov;
   struct msghdr msg;
@@ -1386,22 +1593,30 @@ write_credentials_byte (int             server_fd,
   msg.msg_iov = &iov;
   msg.msg_iovlen = 1;
 
-  msg.msg_control = &cmsg;
-  msg.msg_controllen = sizeof (cmsg);
+  msg.msg_control = (caddr_t) &cmsg;
+  msg.msg_controllen = CMSG_SPACE (sizeof (struct cmsgcred));
   _DBUS_ZERO(cmsg);
-  cmsg.hdr.cmsg_len = sizeof (cmsg);
+  cmsg.hdr.cmsg_len = CMSG_LEN (sizeof (struct cmsgcred));
   cmsg.hdr.cmsg_level = SOL_SOCKET;
   cmsg.hdr.cmsg_type = SCM_CREDS;
 #endif
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-  
+
  again:
 
-#if defined(HAVE_CMSGCRED) 
-  bytes_written = sendmsg (server_fd, &msg, 0);
+#if defined(HAVE_CMSGCRED)
+  bytes_written = sendmsg (server_fd, &msg, 0
+#if HAVE_DECL_MSG_NOSIGNAL
+                           |MSG_NOSIGNAL
+#endif
+                           );
 #else
-  bytes_written = write (server_fd, buf, 1);
+  bytes_written = send (server_fd, buf, 1, 0
+#if HAVE_DECL_MSG_NOSIGNAL
+                        |MSG_NOSIGNAL
+#endif
+                        );
 #endif
 
   if (bytes_written < 0 && errno == EINTR)
@@ -1438,7 +1653,7 @@ write_credentials_byte (int             server_fd,
  * we got valid credentials. On some systems, such as Linux,
  * reading/writing the byte isn't actually required, but we do it
  * anyway just to avoid multiple codepaths.
- * 
+ *
  * Fails if no byte is available, so you must select() first.
  *
  * The point of the byte is that on some systems we have to
@@ -1460,14 +1675,11 @@ _dbus_read_credentials_socket  (int              client_fd,
   dbus_uid_t uid_read;
   dbus_pid_t pid_read;
   int bytes_read;
-  
-  uid_read = DBUS_UID_UNSET;
-  pid_read = DBUS_PID_UNSET;
-  
-#ifdef HAVE_CMSGCRED 
-  struct {
+
+#ifdef HAVE_CMSGCRED
+  union {
     struct cmsghdr hdr;
-    struct cmsgcred cred;
+    char cred[CMSG_SPACE (sizeof (struct cmsgcred))];
   } cmsg;
 
 #elif defined(LOCAL_CREDS)
@@ -1477,8 +1689,11 @@ _dbus_read_credentials_socket  (int              client_fd,
   } cmsg;
 #endif
 
+  uid_read = DBUS_UID_UNSET;
+  pid_read = DBUS_PID_UNSET;
+
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-  
+
   /* The POSIX spec certainly doesn't promise this, but
    * we need these assertions to fail as soon as we're wrong about
    * it so we can do the porting fixups
@@ -1504,8 +1719,8 @@ _dbus_read_credentials_socket  (int              client_fd,
 
 #if defined(HAVE_CMSGCRED) || defined(LOCAL_CREDS)
   _DBUS_ZERO(cmsg);
-  msg.msg_control = &cmsg;
-  msg.msg_controllen = sizeof (cmsg);
+  msg.msg_control = (caddr_t) &cmsg;
+  msg.msg_controllen = CMSG_SPACE (sizeof (struct cmsgcred));
 #endif
 
  again:
@@ -1520,7 +1735,7 @@ _dbus_read_credentials_socket  (int              client_fd,
        * normally only call read_credentials if the socket was ready
        * for reading
        */
-      
+
       dbus_set_error (error, _dbus_error_from_errno (errno),
                       "Failed to read credentials byte: %s",
                       _dbus_strerror (errno));
@@ -1543,7 +1758,8 @@ _dbus_read_credentials_socket  (int              client_fd,
     }
 
 #if defined(HAVE_CMSGCRED) || defined(LOCAL_CREDS)
-  if (cmsg.hdr.cmsg_len < sizeof (cmsg) || cmsg.hdr.cmsg_type != SCM_CREDS)
+  if (cmsg.hdr.cmsg_len < CMSG_LEN (sizeof (struct cmsgcred))
+                 || cmsg.hdr.cmsg_type != SCM_CREDS)
     {
       dbus_set_error (error, DBUS_ERROR_FAILED,
                       "Message from recvmsg() was not SCM_CREDS");
@@ -1555,9 +1771,13 @@ _dbus_read_credentials_socket  (int              client_fd,
 
   {
 #ifdef SO_PEERCRED
-    struct ucred cr;   
+#ifdef __OpenBSD__
+    struct sockpeercred cr;
+#else
+    struct ucred cr;
+#endif
     int cr_len = sizeof (cr);
-    
+
     if (getsockopt (client_fd, SOL_SOCKET, SO_PEERCRED, &cr, &cr_len) == 0 &&
        cr_len == sizeof (cr))
       {
@@ -1570,8 +1790,11 @@ _dbus_read_credentials_socket  (int              client_fd,
                       cr_len, (int) sizeof (cr), _dbus_strerror (errno));
       }
 #elif defined(HAVE_CMSGCRED)
-    pid_read = cmsg.cred.cmcred_pid;
-    uid_read = cmsg.cred.cmcred_euid;
+    struct cmsgcred *cred;
+
+    cred = (struct cmsgcred *) CMSG_DATA (&cmsg.hdr);
+    pid_read = cred->cmcred_pid;
+    uid_read = cred->cmcred_euid;
 #elif defined(LOCAL_CREDS)
     pid_read = DBUS_PID_UNSET;
     uid_read = cmsg.cred.sc_uid;
@@ -1604,9 +1827,9 @@ _dbus_read_credentials_socket  (int              client_fd,
           {
             _dbus_verbose ("Failed to adt_start_session(): %s\n", _dbus_strerror (errno));
           }
-        else 
+        else
           {
-            if (adt_set_from_ucred (adth, ucred, ADT_NEW)) 
+            if (adt_set_from_ucred (adth, ucred, ADT_NEW))
               {
                 _dbus_verbose ("Failed to adt_set_from_ucred(): %s\n", _dbus_strerror (errno));
               }
@@ -1647,7 +1870,7 @@ _dbus_read_credentials_socket  (int              client_fd,
 
   if (pid_read != DBUS_PID_UNSET)
     {
-      if (!_dbus_credentials_add_unix_pid (credentials, pid_read))
+      if (!_dbus_credentials_add_pid (credentials, pid_read))
         {
           _DBUS_SET_OOM (error);
           return FALSE;
@@ -1662,7 +1885,7 @@ _dbus_read_credentials_socket  (int              client_fd,
           return FALSE;
         }
     }
-  
+
   return TRUE;
 }
 
@@ -1688,7 +1911,7 @@ _dbus_send_credentials_socket  (int              server_fd,
                                 DBusError       *error)
 {
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-  
+
   if (write_credentials_byte (server_fd, error))
     return TRUE;
   else
@@ -1748,8 +1971,8 @@ _dbus_accept  (int listen_fd)
 }
 
 /**
- * Checks to make sure the given directory is 
- * private to the user 
+ * Checks to make sure the given directory is
+ * private to the user
  *
  * @param dir the name of the directory
  * @param error error return
@@ -1760,19 +1983,19 @@ _dbus_check_dir_is_private_to_user (DBusString *dir, DBusError *error)
 {
   const char *directory;
   struct stat sb;
-       
+
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-    
+
   directory = _dbus_string_get_const_data (dir);
-       
+
   if (stat (directory, &sb) < 0)
     {
       dbus_set_error (error, _dbus_error_from_errno (errno),
                       "%s", _dbus_strerror (errno));
-   
+
       return FALSE;
     }
-    
+
   if ((S_IROTH & sb.st_mode) || (S_IWOTH & sb.st_mode) ||
       (S_IRGRP & sb.st_mode) || (S_IWGRP & sb.st_mode))
     {
@@ -1780,7 +2003,7 @@ _dbus_check_dir_is_private_to_user (DBusString *dir, DBusError *error)
                      "%s directory is not private to the user", directory);
       return FALSE;
     }
-    
+
   return TRUE;
 }
 
@@ -1791,12 +2014,12 @@ fill_user_info_from_passwd (struct passwd *p,
 {
   _dbus_assert (p->pw_name != NULL);
   _dbus_assert (p->pw_dir != NULL);
-  
+
   info->uid = p->pw_uid;
   info->primary_gid = p->pw_gid;
   info->username = _dbus_strdup (p->pw_name);
   info->homedir = _dbus_strdup (p->pw_dir);
-  
+
   if (info->username == NULL ||
       info->homedir == NULL)
     {
@@ -1814,7 +2037,7 @@ fill_user_info (DBusUserInfo       *info,
                 DBusError          *error)
 {
   const char *username_c;
-  
+
   /* exactly one of username/uid provided */
   _dbus_assert (username != NULL || uid != DBUS_UID_UNSET);
   _dbus_assert (username == NULL || uid == DBUS_UID_UNSET);
@@ -1825,7 +2048,7 @@ fill_user_info (DBusUserInfo       *info,
   info->n_group_ids = 0;
   info->username = NULL;
   info->homedir = NULL;
-  
+
   if (username != NULL)
     username_c = _dbus_string_get_const_data (username);
   else
@@ -1835,7 +2058,7 @@ fill_user_info (DBusUserInfo       *info,
    * are always symmetrical, if not we have to add more configure
    * checks
    */
-  
+
 #if defined (HAVE_POSIX_GETPWNAM_R) || defined (HAVE_NONPOSIX_GETPWNAM_R)
   {
     struct passwd *p;
@@ -1939,46 +2162,74 @@ fill_user_info (DBusUserInfo       *info,
 
   /* Fill this in so we can use it to get groups */
   username_c = info->username;
-  
+
 #ifdef HAVE_GETGROUPLIST
   {
     gid_t *buf;
     int buf_count;
     int i;
-    
-    buf_count = 17;
+    int initial_buf_count;
+
+    initial_buf_count = 17;
+    buf_count = initial_buf_count;
     buf = dbus_new (gid_t, buf_count);
     if (buf == NULL)
       {
         dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
         goto failed;
       }
-    
+
     if (getgrouplist (username_c,
                       info->primary_gid,
                       buf, &buf_count) < 0)
       {
-        gid_t *new = dbus_realloc (buf, buf_count * sizeof (buf[0]));
+        gid_t *new;
+        /* Presumed cause of negative return code: buf has insufficient
+           entries to hold the entire group list. The Linux behavior in this
+           case is to pass back the actual number of groups in buf_count, but
+           on Mac OS X 10.5, buf_count is unhelpfully left alone.
+           So as a hack, try to help out a bit by guessing a larger
+           number of groups, within reason.. might still fail, of course,
+           but we can at least print a more informative message.  I looked up
+           the "right way" to do this by downloading Apple's own source code
+           for the "id" command, and it turns out that they use an
+           undocumented library function getgrouplist_2 (!) which is not
+           declared in any header in /usr/include (!!). That did not seem
+           like the way to go here.
+        */
+        if (buf_count == initial_buf_count)
+          {
+            buf_count *= 16; /* Retry with an arbitrarily scaled-up array */
+          }
+        new = dbus_realloc (buf, buf_count * sizeof (buf[0]));
         if (new == NULL)
           {
             dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
             dbus_free (buf);
             goto failed;
           }
-        
+
         buf = new;
 
         errno = 0;
         if (getgrouplist (username_c, info->primary_gid, buf, &buf_count) < 0)
           {
-            dbus_set_error (error,
-                            _dbus_error_from_errno (errno),
-                            "Failed to get groups for username \"%s\" primary GID "
-                            DBUS_GID_FORMAT ": %s\n",
-                            username_c, info->primary_gid,
-                            _dbus_strerror (errno));
-            dbus_free (buf);
-            goto failed;
+            if (errno == 0)
+              {
+                _dbus_warn ("It appears that username \"%s\" is in more than %d groups.\nProceeding with just the first %d groups.",
+                            username_c, buf_count, buf_count);
+              }
+            else
+              {
+                dbus_set_error (error,
+                                _dbus_error_from_errno (errno),
+                                "Failed to get groups for username \"%s\" primary GID "
+                                DBUS_GID_FORMAT ": %s\n",
+                                username_c, info->primary_gid,
+                                _dbus_strerror (errno));
+                dbus_free (buf);
+                goto failed;
+              }
           }
       }
 
@@ -1989,12 +2240,12 @@ fill_user_info (DBusUserInfo       *info,
         dbus_free (buf);
         goto failed;
       }
-    
+
     for (i = 0; i < buf_count; ++i)
       info->group_ids[i] = buf[i];
 
     info->n_group_ids = buf_count;
-    
+
     dbus_free (buf);
   }
 #else  /* HAVE_GETGROUPLIST */
@@ -2014,9 +2265,9 @@ fill_user_info (DBusUserInfo       *info,
 #endif /* HAVE_GETGROUPLIST */
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-  
+
   return TRUE;
-  
+
  failed:
   _DBUS_ASSERT_ERROR_IS_SET (error);
   return FALSE;
@@ -2074,7 +2325,7 @@ _dbus_credentials_add_from_current_process (DBusCredentials *credentials)
   _dbus_assert (sizeof (uid_t) <= sizeof (dbus_uid_t));
   _dbus_assert (sizeof (gid_t) <= sizeof (dbus_gid_t));
 
-  if (!_dbus_credentials_add_unix_pid(credentials, _dbus_getpid()))
+  if (!_dbus_credentials_add_pid(credentials, _dbus_getpid()))
     return FALSE;
   if (!_dbus_credentials_add_unix_uid(credentials, _dbus_geteuid()))
     return FALSE;
@@ -2089,7 +2340,7 @@ _dbus_credentials_add_from_current_process (DBusCredentials *credentials)
  * is required, that is done in dbus-auth.c. The username here
  * need not be anything human-readable, it can be the machine-readable
  * form i.e. a user id.
- * 
+ *
  * @param str the string to append to
  * @returns #FALSE on no memory
  */
@@ -2131,7 +2382,7 @@ _dbus_geteuid (void)
 /**
  * The only reason this is separate from _dbus_getpid() is to allow it
  * on Windows for logging but not for other purposes.
- * 
+ *
  * @returns process ID to put in log messages
  */
 unsigned long
@@ -2153,7 +2404,7 @@ _dbus_parse_uid (const DBusString      *uid_str,
 {
   int end;
   long val;
-  
+
   if (_dbus_string_get_length (uid_str) == 0)
     {
       _dbus_verbose ("UID string was zero length\n");
@@ -2168,7 +2419,7 @@ _dbus_parse_uid (const DBusString      *uid_str,
       _dbus_verbose ("could not parse string as a UID\n");
       return FALSE;
     }
-  
+
   if (end != _dbus_string_get_length (uid_str))
     {
       _dbus_verbose ("string contained trailing stuff after UID\n");
@@ -2181,7 +2432,12 @@ _dbus_parse_uid (const DBusString      *uid_str,
 }
 
 #if !DBUS_USE_SYNC
-_DBUS_DEFINE_GLOBAL_LOCK (atomic);
+/* To be thread-safe by default on platforms that don't necessarily have
+ * atomic operations (notably Debian armel, which is armv4t), we must
+ * use a mutex that can be initialized statically, like this.
+ * GLib >= 2.32 uses a similar system.
+ */
+static pthread_mutex_t atomic_mutex = PTHREAD_MUTEX_INITIALIZER;
 #endif
 
 /**
@@ -2197,10 +2453,12 @@ _dbus_atomic_inc (DBusAtomic *atomic)
   return __sync_add_and_fetch(&atomic->value, 1)-1;
 #else
   dbus_int32_t res;
-  _DBUS_LOCK (atomic);
+
+  pthread_mutex_lock (&atomic_mutex);
   res = atomic->value;
   atomic->value += 1;
-  _DBUS_UNLOCK (atomic);
+  pthread_mutex_unlock (&atomic_mutex);
+
   return res;
 #endif
 }
@@ -2218,25 +2476,39 @@ _dbus_atomic_dec (DBusAtomic *atomic)
   return __sync_sub_and_fetch(&atomic->value, 1)+1;
 #else
   dbus_int32_t res;
-  
-  _DBUS_LOCK (atomic);
+
+  pthread_mutex_lock (&atomic_mutex);
   res = atomic->value;
   atomic->value -= 1;
-  _DBUS_UNLOCK (atomic);
+  pthread_mutex_unlock (&atomic_mutex);
+
   return res;
 #endif
 }
 
-#ifdef DBUS_BUILD_TESTS
-/** Gets our GID
- * @returns process GID
+/**
+ * Atomically get the value of an integer. It may change at any time
+ * thereafter, so this is mostly only useful for assertions.
+ *
+ * @param atomic pointer to the integer to get
+ * @returns the value at this moment
  */
-dbus_gid_t
-_dbus_getgid (void)
+dbus_int32_t
+_dbus_atomic_get (DBusAtomic *atomic)
 {
-  return getgid ();
-}
+#if DBUS_USE_SYNC
+  __sync_synchronize ();
+  return atomic->value;
+#else
+  dbus_int32_t res;
+
+  pthread_mutex_lock (&atomic_mutex);
+  res = atomic->value;
+  pthread_mutex_unlock (&atomic_mutex);
+
+  return res;
 #endif
+}
 
 /**
  * Wrapper for poll().
@@ -2271,7 +2543,7 @@ _dbus_poll (DBusPollFD *fds,
       _DBUS_STRUCT_OFFSET (struct pollfd, revents))
     {
       return poll ((struct pollfd*) fds,
-                   n_fds, 
+                   n_fds,
                    timeout_milliseconds);
     }
   else
@@ -2289,7 +2561,7 @@ _dbus_poll (DBusPollFD *fds,
   int i;
   struct timeval tv;
   int ready;
-  
+
   FD_ZERO (&read_set);
   FD_ZERO (&write_set);
   FD_ZERO (&err_set);
@@ -2308,7 +2580,7 @@ _dbus_poll (DBusPollFD *fds,
 
       max_fd = MAX (max_fd, fdp->fd);
     }
-    
+
   tv.tv_sec = timeout_milliseconds / 1000;
   tv.tv_usec = (timeout_milliseconds % 1000) * 1000;
 
@@ -2339,15 +2611,25 @@ _dbus_poll (DBusPollFD *fds,
 }
 
 /**
- * Get current time, as in gettimeofday().
+ * Get current time, as in gettimeofday(). Use the monotonic clock if
+ * available, to avoid problems when the system time changes.
  *
  * @param tv_sec return location for number of seconds
- * @param tv_usec return location for number of microseconds (thousandths)
+ * @param tv_usec return location for number of microseconds
  */
 void
-_dbus_get_current_time (long *tv_sec,
-                        long *tv_usec)
+_dbus_get_monotonic_time (long *tv_sec,
+                          long *tv_usec)
 {
+#ifdef HAVE_MONOTONIC_CLOCK
+  struct timespec ts;
+  clock_gettime (CLOCK_MONOTONIC, &ts);
+
+  if (tv_sec)
+    *tv_sec = ts.tv_sec;
+  if (tv_usec)
+    *tv_usec = ts.tv_nsec / 1000;
+#else
   struct timeval t;
 
   gettimeofday (&t, NULL);
@@ -2356,365 +2638,28 @@ _dbus_get_current_time (long *tv_sec,
     *tv_sec = t.tv_sec;
   if (tv_usec)
     *tv_usec = t.tv_usec;
+#endif
 }
 
 /**
- * Appends the contents of the given file to the string,
- * returning error code. At the moment, won't open a file
- * more than a megabyte in size.
- *
- * @param str the string to append to
- * @param filename filename to load
- * @param error place to set an error
- * @returns #FALSE if error was set
- */
-dbus_bool_t
-_dbus_file_get_contents (DBusString       *str,
-                         const DBusString *filename,
-                         DBusError        *error)
-{
-  int fd;
-  struct stat sb;
-  int orig_len;
-  int total;
-  const char *filename_c;
-
-  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-  
-  filename_c = _dbus_string_get_const_data (filename);
-  
-  /* O_BINARY useful on Cygwin */
-  fd = open (filename_c, O_RDONLY | O_BINARY);
-  if (fd < 0)
-    {
-      dbus_set_error (error, _dbus_error_from_errno (errno),
-                      "Failed to open \"%s\": %s",
-                      filename_c,
-                      _dbus_strerror (errno));
-      return FALSE;
-    }
-
-  _dbus_verbose ("file fd %d opened\n", fd);
-  
-  if (fstat (fd, &sb) < 0)
-    {
-      dbus_set_error (error, _dbus_error_from_errno (errno),
-                      "Failed to stat \"%s\": %s",
-                      filename_c,
-                      _dbus_strerror (errno));
-
-      _dbus_verbose ("fstat() failed: %s",
-                     _dbus_strerror (errno));
-      
-      _dbus_close (fd, NULL);
-      
-      return FALSE;
-    }
-
-  if (sb.st_size > _DBUS_ONE_MEGABYTE)
-    {
-      dbus_set_error (error, DBUS_ERROR_FAILED,
-                      "File size %lu of \"%s\" is too large.",
-                      (unsigned long) sb.st_size, filename_c);
-      _dbus_close (fd, NULL);
-      return FALSE;
-    }
-  
-  total = 0;
-  orig_len = _dbus_string_get_length (str);
-  if (sb.st_size > 0 && S_ISREG (sb.st_mode))
-    {
-      int bytes_read;
-
-      while (total < (int) sb.st_size)
-        {
-          bytes_read = _dbus_read (fd, str,
-                                   sb.st_size - total);
-          if (bytes_read <= 0)
-            {
-              dbus_set_error (error, _dbus_error_from_errno (errno),
-                              "Error reading \"%s\": %s",
-                              filename_c,
-                              _dbus_strerror (errno));
-
-              _dbus_verbose ("read() failed: %s",
-                             _dbus_strerror (errno));
-              
-              _dbus_close (fd, NULL);
-              _dbus_string_set_length (str, orig_len);
-              return FALSE;
-            }
-          else
-            total += bytes_read;
-        }
-
-      _dbus_close (fd, NULL);
-      return TRUE;
-    }
-  else if (sb.st_size != 0)
-    {
-      _dbus_verbose ("Can only open regular files at the moment.\n");
-      dbus_set_error (error, DBUS_ERROR_FAILED,
-                      "\"%s\" is not a regular file",
-                      filename_c);
-      _dbus_close (fd, NULL);
-      return FALSE;
-    }
-  else
-    {
-      _dbus_close (fd, NULL);
-      return TRUE;
-    }
-}
-
-/**
- * Writes a string out to a file. If the file exists,
- * it will be atomically overwritten by the new data.
- *
- * @param str the string to write out
- * @param filename the file to save string to
- * @param error error to be filled in on failure
- * @returns #FALSE on failure
- */
-dbus_bool_t
-_dbus_string_save_to_file (const DBusString *str,
-                           const DBusString *filename,
-                           DBusError        *error)
-{
-  int fd;
-  int bytes_to_write;
-  const char *filename_c;
-  DBusString tmp_filename;
-  const char *tmp_filename_c;
-  int total;
-  dbus_bool_t need_unlink;
-  dbus_bool_t retval;
-
-  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-  
-  fd = -1;
-  retval = FALSE;
-  need_unlink = FALSE;
-  
-  if (!_dbus_string_init (&tmp_filename))
-    {
-      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
-      return FALSE;
-    }
-
-  if (!_dbus_string_copy (filename, 0, &tmp_filename, 0))
-    {
-      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
-      _dbus_string_free (&tmp_filename);
-      return FALSE;
-    }
-  
-  if (!_dbus_string_append (&tmp_filename, "."))
-    {
-      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
-      _dbus_string_free (&tmp_filename);
-      return FALSE;
-    }
-
-#define N_TMP_FILENAME_RANDOM_BYTES 8
-  if (!_dbus_generate_random_ascii (&tmp_filename, N_TMP_FILENAME_RANDOM_BYTES))
-    {
-      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
-      _dbus_string_free (&tmp_filename);
-      return FALSE;
-    }
-    
-  filename_c = _dbus_string_get_const_data (filename);
-  tmp_filename_c = _dbus_string_get_const_data (&tmp_filename);
-
-  fd = open (tmp_filename_c, O_WRONLY | O_BINARY | O_EXCL | O_CREAT,
-             0600);
-  if (fd < 0)
-    {
-      dbus_set_error (error, _dbus_error_from_errno (errno),
-                      "Could not create %s: %s", tmp_filename_c,
-                      _dbus_strerror (errno));
-      goto out;
-    }
-
-  _dbus_verbose ("tmp file fd %d opened\n", fd);
-  
-  need_unlink = TRUE;
-  
-  total = 0;
-  bytes_to_write = _dbus_string_get_length (str);
-
-  while (total < bytes_to_write)
-    {
-      int bytes_written;
-
-      bytes_written = _dbus_write (fd, str, total,
-                                   bytes_to_write - total);
-
-      if (bytes_written <= 0)
-        {
-          dbus_set_error (error, _dbus_error_from_errno (errno),
-                          "Could not write to %s: %s", tmp_filename_c,
-                          _dbus_strerror (errno));
-          
-          goto out;
-        }
-
-      total += bytes_written;
-    }
-
-  if (fsync(fd))
-    {
-      dbus_set_error (error, _dbus_error_from_errno (errno),
-                      "Could not synchronize file %s: %s",
-                      tmp_filename_c, _dbus_strerror (errno));
-
-      goto out;
-  }
-
-  if (!_dbus_close (fd, NULL))
-    {
-      dbus_set_error (error, _dbus_error_from_errno (errno),
-                      "Could not close file %s: %s",
-                      tmp_filename_c, _dbus_strerror (errno));
-
-      goto out;
-    }
-
-  fd = -1;
-  
-  if (rename (tmp_filename_c, filename_c) < 0)
-    {
-      dbus_set_error (error, _dbus_error_from_errno (errno),
-                      "Could not rename %s to %s: %s",
-                      tmp_filename_c, filename_c,
-                      _dbus_strerror (errno));
-
-      goto out;
-    }
-
-  need_unlink = FALSE;
-  
-  retval = TRUE;
-  
- out:
-  /* close first, then unlink, to prevent ".nfs34234235" garbage
-   * files
-   */
-
-  if (fd >= 0)
-    _dbus_close (fd, NULL);
-        
-  if (need_unlink && unlink (tmp_filename_c) < 0)
-    _dbus_verbose ("Failed to unlink temp file %s: %s\n",
-                   tmp_filename_c, _dbus_strerror (errno));
-
-  _dbus_string_free (&tmp_filename);
-
-  if (!retval)
-    _DBUS_ASSERT_ERROR_IS_SET (error);
-  
-  return retval;
-}
-
-/** Makes the file readable by every user in the system.
- *
- * @param filename the filename
- * @param error error location
- * @returns #TRUE if the file's permissions could be changed.
- */
-dbus_bool_t
-_dbus_make_file_world_readable(const DBusString *filename,
-                               DBusError *error)
-{
-  const char *filename_c;
-
-  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-
-  filename_c = _dbus_string_get_const_data (filename);
-  if (chmod (filename_c, 0644) == -1)
-    {
-      dbus_set_error (error,
-                      DBUS_ERROR_FAILED,
-                      "Could not change permissions of file %s: %s\n",
-                      filename_c,
-                      _dbus_strerror (errno));
-      return FALSE;
-    }
-  return TRUE;
-}
-
-/** Creates the given file, failing if the file already exists.
- *
- * @param filename the filename
- * @param error error location
- * @returns #TRUE if we created the file and it didn't exist
- */
-dbus_bool_t
-_dbus_create_file_exclusively (const DBusString *filename,
-                               DBusError        *error)
-{
-  int fd;
-  const char *filename_c;
-
-  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-  
-  filename_c = _dbus_string_get_const_data (filename);
-  
-  fd = open (filename_c, O_WRONLY | O_BINARY | O_EXCL | O_CREAT,
-             0600);
-  if (fd < 0)
-    {
-      dbus_set_error (error,
-                      DBUS_ERROR_FAILED,
-                      "Could not create file %s: %s\n",
-                      filename_c,
-                      _dbus_strerror (errno));
-      return FALSE;
-    }
-
-  _dbus_verbose ("exclusive file fd %d opened\n", fd);
-  
-  if (!_dbus_close (fd, NULL))
-    {
-      dbus_set_error (error,
-                      DBUS_ERROR_FAILED,
-                      "Could not close file %s: %s\n",
-                      filename_c,
-                      _dbus_strerror (errno));
-      return FALSE;
-    }
-  
-  return TRUE;
-}
-
-/**
- * Deletes the given file.
+ * Get current time, as in gettimeofday(). Never uses the monotonic
+ * clock.
  *
- * @param filename the filename
- * @param error error location
- * 
- * @returns #TRUE if unlink() succeeded
+ * @param tv_sec return location for number of seconds
+ * @param tv_usec return location for number of microseconds
  */
-dbus_bool_t
-_dbus_delete_file (const DBusString *filename,
-                   DBusError        *error)
+void
+_dbus_get_real_time (long *tv_sec,
+                     long *tv_usec)
 {
-  const char *filename_c;
+  struct timeval t;
 
-  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-  
-  filename_c = _dbus_string_get_const_data (filename);
+  gettimeofday (&t, NULL);
 
-  if (unlink (filename_c) < 0)
-    {
-      dbus_set_error (error, DBUS_ERROR_FAILED,
-                      "Failed to delete file %s: %s\n",
-                      filename_c, _dbus_strerror (errno));
-      return FALSE;
-    }
-  else
-    return TRUE;
+  if (tv_sec)
+    *tv_sec = t.tv_sec;
+  if (tv_usec)
+    *tv_usec = t.tv_usec;
 }
 
 /**
@@ -2732,14 +2677,14 @@ _dbus_create_directory (const DBusString *filename,
   const char *filename_c;
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-  
+
   filename_c = _dbus_string_get_const_data (filename);
 
   if (mkdir (filename_c, 0700) < 0)
     {
       if (errno == EEXIST)
         return TRUE;
-      
+
       dbus_set_error (error, DBUS_ERROR_FAILED,
                       "Failed to create directory %s: %s\n",
                       filename_c, _dbus_strerror (errno));
@@ -2769,7 +2714,7 @@ _dbus_concat_dir_and_file (DBusString       *dir,
   if (_dbus_string_get_length (dir) == 0 ||
       _dbus_string_get_length (next_component) == 0)
     return TRUE;
-  
+
   dir_ends_in_slash = '/' == _dbus_string_get_byte (dir,
                                                     _dbus_string_get_length (dir) - 1);
 
@@ -2831,7 +2776,7 @@ _dbus_generate_pseudorandom_bytes (DBusString *str,
 {
   int old_len;
   char *p;
-  
+
   old_len = _dbus_string_get_length (str);
 
   if (!_dbus_string_lengthen (str, n_bytes))
@@ -2864,7 +2809,7 @@ _dbus_generate_random_bytes (DBusString *str,
    * a DBusError. So we always fall back to pseudorandom
    * if the I/O fails.
    */
-  
+
   old_len = _dbus_string_get_length (str);
   fd = -1;
 
@@ -2874,7 +2819,7 @@ _dbus_generate_random_bytes (DBusString *str,
     return _dbus_generate_pseudorandom_bytes (str, n_bytes);
 
   _dbus_verbose ("/dev/urandom fd %d opened\n", fd);
-  
+
   if (_dbus_read (fd, str, n_bytes) != n_bytes)
     {
       _dbus_close (fd, NULL);
@@ -2884,9 +2829,9 @@ _dbus_generate_random_bytes (DBusString *str,
 
   _dbus_verbose ("Read %d bytes from /dev/urandom\n",
                  n_bytes);
-  
+
   _dbus_close (fd, NULL);
-  
+
   return TRUE;
 }
 
@@ -2913,7 +2858,7 @@ const char*
 _dbus_strerror (int error_number)
 {
   const char *msg;
-  
+
   msg = strerror (error_number);
   if (msg == NULL)
     msg = "unknown";
@@ -2938,17 +2883,17 @@ _dbus_disable_sigpipe (void)
  * @param fd the file descriptor
  */
 void
-_dbus_fd_set_close_on_exec (int fd)
+_dbus_fd_set_close_on_exec (intptr_t fd)
 {
   int val;
-  
+
   val = fcntl (fd, F_GETFD, 0);
-  
+
   if (val < 0)
     return;
 
   val |= FD_CLOEXEC;
-  
+
   fcntl (fd, F_SETFD, val);
 }
 
@@ -2964,7 +2909,7 @@ _dbus_close (int        fd,
              DBusError *error)
 {
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-  
+
  again:
   if (close (fd) < 0)
     {
@@ -2984,6 +2929,7 @@ _dbus_close (int        fd,
  * (i.e. avoids stdin/stdout/stderr). Sets O_CLOEXEC.
  *
  * @param fd the file descriptor to duplicate
+ * @param error address of error location.
  * @returns duplicated file descriptor
  * */
 int
@@ -3011,7 +2957,7 @@ _dbus_dup(int        fd,
     return -1;
   }
 
-#ifndef F_DUPFD_CLOEXEC
+#ifdef F_DUPFD_CLOEXEC
   if (!cloexec_done)
 #endif
     {
@@ -3035,7 +2981,7 @@ _dbus_set_fd_nonblocking (int             fd,
   int val;
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-  
+
   val = fcntl (fd, F_GETFL, 0);
   if (val < 0)
     {
@@ -3068,17 +3014,17 @@ _dbus_set_fd_nonblocking (int             fd,
  */
 void
 _dbus_print_backtrace (void)
-{  
+{
 #if defined (HAVE_BACKTRACE) && defined (DBUS_BUILT_R_DYNAMIC)
   void *bt[500];
   int bt_size;
   int i;
   char **syms;
-  
+
   bt_size = backtrace (bt, 500);
 
   syms = backtrace_symbols (bt, bt_size);
-  
+
   i = 0;
   while (i < bt_size)
     {
@@ -3102,11 +3048,6 @@ _dbus_print_backtrace (void)
  *
  * Marks both file descriptors as close-on-exec
  *
- * @todo libdbus only uses this for the debug-pipe server, so in
- * principle it could be in dbus-sysdeps-util.c, except that
- * dbus-sysdeps-util.c isn't in libdbus when tests are enabled and the
- * debug-pipe server is used.
- * 
  * @param fd1 return location for one end
  * @param fd2 return location for the other end
  * @param blocking #TRUE if pipe should be blocking
@@ -3158,20 +3099,20 @@ _dbus_full_duplex_pipe (int        *fd1,
     {
       dbus_set_error (error, _dbus_error_from_errno (errno),
                       "Could not set full-duplex pipe nonblocking");
-      
+
       _dbus_close (fds[0], NULL);
       _dbus_close (fds[1], NULL);
-      
+
       return FALSE;
     }
-  
+
   *fd1 = fds[0];
   *fd2 = fds[1];
 
   _dbus_verbose ("full-duplex pipe %d <-> %d\n",
                  *fd1, *fd2);
-  
-  return TRUE;  
+
+  return TRUE;
 #else
   _dbus_warn ("_dbus_full_duplex_pipe() not implemented on this OS\n");
   dbus_set_error (error, DBUS_ERROR_FAILED,
@@ -3186,27 +3127,87 @@ _dbus_full_duplex_pipe (int        *fd1,
  *
  * @param format a printf-style format string
  * @param args arguments for the format string
- * @returns length of the given format string and args
+ * @returns length of the given format string and args, or -1 if no memory
  */
 int
 _dbus_printf_string_upper_bound (const char *format,
                                  va_list     args)
 {
-  char c;
-  return vsnprintf (&c, 1, format, args);
+  char static_buf[1024];
+  int bufsize = sizeof (static_buf);
+  int len;
+  va_list args_copy;
+
+  DBUS_VA_COPY (args_copy, args);
+  len = vsnprintf (static_buf, bufsize, format, args_copy);
+  va_end (args_copy);
+
+  /* If vsnprintf() returned non-negative, then either the string fits in
+   * static_buf, or this OS has the POSIX and C99 behaviour where vsnprintf
+   * returns the number of characters that were needed, or this OS returns the
+   * truncated length.
+   *
+   * We ignore the possibility that snprintf might just ignore the length and
+   * overrun the buffer (64-bit Solaris 7), because that's pathological.
+   * If your libc is really that bad, come back when you have a better one. */
+  if (len == bufsize)
+    {
+      /* This could be the truncated length (Tru64 and IRIX have this bug),
+       * or the real length could be coincidentally the same. Which is it?
+       * If vsnprintf returns the truncated length, we'll go to the slow
+       * path. */
+      DBUS_VA_COPY (args_copy, args);
+
+      if (vsnprintf (static_buf, 1, format, args_copy) == 1)
+        len = -1;
+
+      va_end (args_copy);
+    }
+
+  /* If vsnprintf() returned negative, we have to do more work.
+   * HP-UX returns negative. */
+  while (len < 0)
+    {
+      char *buf;
+
+      bufsize *= 2;
+
+      buf = dbus_malloc (bufsize);
+
+      if (buf == NULL)
+        return -1;
+
+      DBUS_VA_COPY (args_copy, args);
+      len = vsnprintf (buf, bufsize, format, args_copy);
+      va_end (args_copy);
+
+      dbus_free (buf);
+
+      /* If the reported length is exactly the buffer size, round up to the
+       * next size, in case vsnprintf has been returning the truncated
+       * length */
+      if (len == bufsize)
+        len = -1;
+    }
+
+  return len;
 }
 
 /**
- * Gets the temporary files directory by inspecting the environment variables 
+ * Gets the temporary files directory by inspecting the environment variables
  * TMPDIR, TMP, and TEMP in that order. If none of those are set "/tmp" is returned
  *
- * @returns location of temp directory
+ * @returns location of temp directory, or #NULL if no memory for locking
  */
 const char*
 _dbus_get_tmpdir(void)
 {
+  /* Protected by _DBUS_LOCK_sysdeps */
   static const char* tmpdir = NULL;
 
+  if (!_DBUS_LOCK (sysdeps))
+    return NULL;
+
   if (tmpdir == NULL)
     {
       /* TMPDIR is what glibc uses, then
@@ -3228,90 +3229,82 @@ _dbus_get_tmpdir(void)
       if (tmpdir == NULL)
         tmpdir = "/tmp";
     }
-  
+
+  _DBUS_UNLOCK (sysdeps);
+
   _dbus_assert(tmpdir != NULL);
-  
+
   return tmpdir;
 }
 
+#if defined(DBUS_ENABLE_X11_AUTOLAUNCH) || defined(DBUS_ENABLE_LAUNCHD)
 /**
- * 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 (may or may not be absolute)
+ * @param path_fallback if %TRUE, search PATH for executable
+ * @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,
+                            dbus_bool_t path_fallback,
+                            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;
   int status;
   int orig_len;
-  int i;
-  DBusString uuid;
+
   dbus_bool_t retval;
-  
+  sigset_t new_set, old_set;
+
   _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;
+  /* We need to block any existing handlers for SIGCHLD temporarily; they
+   * will cause waitpid() below to fail.
+   * https://bugs.freedesktop.org/show_bug.cgi?id=21347
+   */
+  sigemptyset (&new_set);
+  sigaddset (&new_set, SIGCHLD);
+  sigprocmask (SIG_BLOCK, &new_set, &old_set);
+
+  orig_len = _dbus_string_get_length (result);
 
-  _dbus_assert (i == _DBUS_N_ELEMENTS (argv));
-  
-  orig_len = _dbus_string_get_length (address);
-  
 #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;
     }
 
@@ -3319,17 +3312,16 @@ _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;
     }
 
   if (pid == 0)
     {
       /* child process */
-      int maxfds;
       int fd;
 
       fd = open ("/dev/null", O_RDWR);
@@ -3338,50 +3330,53 @@ _dbus_get_autolaunch_address (DBusString *address,
         _exit (1);
 
       _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 */
-      close (2);                /* close stderr */
 
-      if (dup2 (fd, 0) == -1)
+      if (dup2 (fd, 0) == -1) /* setup stdin */
         _exit (1);
-      if (dup2 (address_pipe[WRITE_END], 1) == -1)
+      if (dup2 (result_pipe[WRITE_END], 1) == -1) /* setup stdout */
         _exit (1);
-      if (dup2 (errors_pipe[WRITE_END], 2) == -1)
+      if (dup2 (errors_pipe[WRITE_END], 2) == -1) /* setup stderr */
         _exit (1);
 
-      maxfds = sysconf (_SC_OPEN_MAX);
-      /* Pick something reasonable if for some reason sysconf
-       * says unlimited.
-       */
-      if (maxfds < 0)
-        maxfds = 1024;
-      /* close all inherited fds */
-      for (i = 3; i < maxfds; i++)
-        close (i);
+      _dbus_close_all ();
 
-      execv (DBUS_BINDIR "/dbus-launch", argv);
+      sigprocmask (SIG_SETMASK, &old_set, NULL);
 
-      /* failed, try searching PATH */
-      execvp ("dbus-launch", argv);
+      /* If it looks fully-qualified, try execv first */
+      if (progpath[0] == '/')
+        {
+          execv (progpath, argv);
+          /* Ok, that failed.  Now if path_fallback is given, let's
+           * try unqualified.  This is mostly a hack to work
+           * around systems which ship dbus-launch in /usr/bin
+           * but everything else in /bin (because dbus-launch
+           * depends on X11).
+           */
+          if (path_fallback)
+            /* We must have a slash, because we checked above */
+            execvp (strrchr (progpath, '/')+1, 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 
+  do
     {
-      ret = _dbus_read (address_pipe[READ_END], address, 1024);
+      ret = _dbus_read (result_pipe[READ_END], result, 1024);
     }
   while (ret > 0);
 
@@ -3394,49 +3389,148 @@ _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);
+      if (!_dbus_string_init (&error_message))
+        {
+          _DBUS_SET_OOM (error);
+          goto out;
+        }
+
       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;
     }
 
   retval = TRUE;
-  
+
  out:
+  sigprocmask (SIG_SETMASK, &old_set, NULL);
+
   if (retval)
     _DBUS_ASSERT_ERROR_IS_CLEAR (error);
   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;
+}
+#endif
+
+/**
+ * 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 scope scope of autolaunch (Windows only)
+ * @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 (const char *scope,
+                              DBusString *address,
+                              DBusError  *error)
+{
+#ifdef DBUS_ENABLE_X11_AUTOLAUNCH
+  /* Perform X11-based autolaunch. (We also support launchd-based autolaunch,
+   * but that's done elsewhere, and if it worked, this function wouldn't
+   * be called.) */
+  const char *display;
+  char *argv[6];
+  int i;
+  DBusString uuid;
+  dbus_bool_t retval;
+
+  if (_dbus_check_setuid ())
+    {
+      dbus_set_error_const (error, DBUS_ERROR_NOT_SUPPORTED,
+                            "Unable to autolaunch when setuid");
+      return FALSE;
+    }
+
+  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+  retval = FALSE;
+
+  /* fd.o #19997: if $DISPLAY isn't set to something useful, then
+   * dbus-launch-x11 is just going to fail. Rather than trying to
+   * run it, we might as well bail out early with a nice error. */
+  display = _dbus_getenv ("DISPLAY");
+
+  if (display == NULL || display[0] == '\0')
+    {
+      dbus_set_error_const (error, DBUS_ERROR_NOT_SUPPORTED,
+          "Unable to autolaunch a dbus-daemon without a $DISPLAY for X11");
+      return 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",
+                                       TRUE,
+                                       argv, address, error);
+
+ out:
   _dbus_string_free (&uuid);
   return retval;
+#else
+  dbus_set_error_const (error, DBUS_ERROR_NOT_SUPPORTED,
+      "Using X11 for dbus-daemon autolaunch was disabled at compile time, "
+      "set your DBUS_SESSION_BUS_ADDRESS instead");
+  return FALSE;
+#endif
 }
 
 /**
@@ -3463,191 +3557,169 @@ _dbus_read_local_machine_uuid (DBusGUID   *machine_id,
                                DBusError  *error)
 {
   DBusString filename;
+  dbus_bool_t b;
+
   _dbus_string_init_const (&filename, DBUS_MACHINE_UUID_FILE);
-  return _dbus_read_uuid_file (&filename, machine_id, create_if_not_found, error);
-}
 
-#define DBUS_UNIX_STANDARD_SESSION_SERVICEDIR "/dbus-1/services"
-#define DBUS_UNIX_STANDARD_SYSTEM_SERVICEDIR "/dbus-1/system-services"
+  b = _dbus_read_uuid_file (&filename, machine_id, create_if_not_found, error);
+  if (b)
+    return TRUE;
+
+  dbus_error_free (error);
 
+  /* Fallback to the system machine ID */
+  _dbus_string_init_const (&filename, "/etc/machine-id");
+  return _dbus_read_uuid_file (&filename, machine_id, FALSE, error);
+}
 
 /**
- * Returns the standard directories for a session bus to look for service 
- * activation files 
- *
- * On UNIX this should be the standard xdg freedesktop.org data directories:
- *
- * XDG_DATA_HOME=${XDG_DATA_HOME-$HOME/.local/share}
- * XDG_DATA_DIRS=${XDG_DATA_DIRS-/usr/local/share:/usr/share}
- *
- * and
- *
- * DBUS_DATADIR
- *
- * @param dirs the directory list we are returning
- * @returns #FALSE on OOM 
+ * quries launchd for a specific env var which holds the socket path.
+ * @param socket_path append the socket path to this DBusString
+ * @param launchd_env_var the env var to look up
+ * @param error a DBusError to store the error in case of failure
+ * @return the value of the env var
  */
-
-dbus_bool_t 
-_dbus_get_standard_session_servicedirs (DBusList **dirs)
+dbus_bool_t
+_dbus_lookup_launchd_socket (DBusString *socket_path,
+                             const char *launchd_env_var,
+                             DBusError  *error)
 {
-  const char *xdg_data_home;
-  const char *xdg_data_dirs;
-  DBusString servicedir_path;
-
-  if (!_dbus_string_init (&servicedir_path))
-    return FALSE;
-
-  xdg_data_home = _dbus_getenv ("XDG_DATA_HOME");
-  xdg_data_dirs = _dbus_getenv ("XDG_DATA_DIRS");
+#ifdef DBUS_ENABLE_LAUNCHD
+  char *argv[4];
+  int i;
 
-  if (xdg_data_dirs != NULL)
-    {
-      if (!_dbus_string_append (&servicedir_path, xdg_data_dirs))
-        goto oom;
+  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
-      if (!_dbus_string_append (&servicedir_path, ":"))
-        goto oom;
-    }
-  else
+  if (_dbus_check_setuid ())
     {
-      if (!_dbus_string_append (&servicedir_path, "/usr/local/share:/usr/share:"))
-        goto oom;
+      dbus_set_error_const (error, DBUS_ERROR_NOT_SUPPORTED,
+                            "Unable to find launchd socket when setuid");
+      return FALSE;
     }
 
-  /* 
-   * add configured datadir to defaults
-   * this may be the same as an xdg dir
-   * however the config parser should take 
-   * care of duplicates 
-   */
-  if (!_dbus_string_append (&servicedir_path, DBUS_DATADIR":"))
-        goto oom;
+  i = 0;
+  argv[i] = "launchctl";
+  ++i;
+  argv[i] = "getenv";
+  ++i;
+  argv[i] = (char*)launchd_env_var;
+  ++i;
+  argv[i] = NULL;
+  ++i;
 
-  if (xdg_data_home != NULL)
+  _dbus_assert (i == _DBUS_N_ELEMENTS (argv));
+
+  if (!_read_subprocess_line_argv(argv[0], TRUE, argv, socket_path, error))
     {
-      if (!_dbus_string_append (&servicedir_path, xdg_data_home))
-        goto oom;
+      return FALSE;
     }
-  else
-    {
-      const DBusString *homedir;
-      DBusString local_share;
-
-      if (!_dbus_homedir_from_current_process (&homedir))
-        goto oom;
-       
-      if (!_dbus_string_append (&servicedir_path, _dbus_string_get_const_data (homedir)))
-        goto oom;
 
-      _dbus_string_init_const (&local_share, "/.local/share");
-      if (!_dbus_concat_dir_and_file (&servicedir_path, &local_share))
-        goto oom;
+  /* no error, but no result either */
+  if (_dbus_string_get_length(socket_path) == 0)
+    {
+      return FALSE;
     }
 
-  if (!_dbus_split_paths_and_append (&servicedir_path, 
-                                     DBUS_UNIX_STANDARD_SESSION_SERVICEDIR, 
-                                     dirs))
-    goto oom;
-
-  _dbus_string_free (&servicedir_path);  
+  /* strip the carriage-return */
+  _dbus_string_shorten(socket_path, 1);
   return TRUE;
-
- oom:
-  _dbus_string_free (&servicedir_path);
+#else /* DBUS_ENABLE_LAUNCHD */
+  dbus_set_error(error, DBUS_ERROR_NOT_SUPPORTED,
+                "can't lookup socket from launchd; launchd support not compiled in");
   return FALSE;
+#endif
 }
 
-
-/**
- * Returns the standard directories for a system bus to look for service 
- * activation files 
- *
- * On UNIX this should be the standard xdg freedesktop.org data directories:
- *
- * XDG_DATA_DIRS=${XDG_DATA_DIRS-/usr/local/share:/usr/share}
- *
- * and
- *
- * DBUS_DATADIR
- *
- * On Windows there is no system bus and this function can return nothing.
- *
- * @param dirs the directory list we are returning
- * @returns #FALSE on OOM 
- */
-
-dbus_bool_t 
-_dbus_get_standard_system_servicedirs (DBusList **dirs)
+#ifdef DBUS_ENABLE_LAUNCHD
+static dbus_bool_t
+_dbus_lookup_session_address_launchd (DBusString *address, DBusError  *error)
 {
-  const char *xdg_data_dirs;
-  DBusString servicedir_path;
+  dbus_bool_t valid_socket;
+  DBusString socket_path;
 
-  if (!_dbus_string_init (&servicedir_path))
-    return FALSE;
+  if (_dbus_check_setuid ())
+    {
+      dbus_set_error_const (error, DBUS_ERROR_NOT_SUPPORTED,
+                            "Unable to find launchd socket when setuid");
+      return FALSE;
+    }
+
+  if (!_dbus_string_init (&socket_path))
+    {
+      _DBUS_SET_OOM (error);
+      return FALSE;
+    }
 
-  xdg_data_dirs = _dbus_getenv ("XDG_DATA_DIRS");
+  valid_socket = _dbus_lookup_launchd_socket (&socket_path, "DBUS_LAUNCHD_SESSION_BUS_SOCKET", error);
 
-  if (xdg_data_dirs != NULL)
+  if (dbus_error_is_set(error))
     {
-      if (!_dbus_string_append (&servicedir_path, xdg_data_dirs))
-        goto oom;
+      _dbus_string_free(&socket_path);
+      return FALSE;
+    }
 
-      if (!_dbus_string_append (&servicedir_path, ":"))
-        goto oom;
+  if (!valid_socket)
+    {
+      dbus_set_error(error, "no socket path",
+                "launchd did not provide a socket path, "
+                "verify that org.freedesktop.dbus-session.plist is loaded!");
+      _dbus_string_free(&socket_path);
+      return FALSE;
     }
-  else
+  if (!_dbus_string_append (address, "unix:path="))
     {
-      if (!_dbus_string_append (&servicedir_path, "/usr/local/share:/usr/share:"))
-        goto oom;
+      _DBUS_SET_OOM (error);
+      _dbus_string_free(&socket_path);
+      return FALSE;
+    }
+  if (!_dbus_string_copy (&socket_path, 0, address,
+                          _dbus_string_get_length (address)))
+    {
+      _DBUS_SET_OOM (error);
+      _dbus_string_free(&socket_path);
+      return FALSE;
     }
 
-  /* 
-   * add configured datadir to defaults
-   * this may be the same as an xdg dir
-   * however the config parser should take 
-   * care of duplicates 
-   */
-  if (!_dbus_string_append (&servicedir_path, DBUS_DATADIR":"))
-        goto oom;
-
-  if (!_dbus_split_paths_and_append (&servicedir_path, 
-                                     DBUS_UNIX_STANDARD_SYSTEM_SERVICEDIR, 
-                                     dirs))
-    goto oom;
-
-  _dbus_string_free (&servicedir_path);  
+  _dbus_string_free(&socket_path);
   return TRUE;
-
- oom:
-  _dbus_string_free (&servicedir_path);
-  return FALSE;
-}
-
-/**
- * Append the absolute path of the system.conf file
- * (there is no system bus on Windows so this can just
- * return FALSE and print a warning or something)
- * 
- * @param str the string to append to
- * @returns #FALSE if no memory
- */
-dbus_bool_t
-_dbus_append_system_config_file (DBusString *str)
-{
-  return _dbus_string_append (str, DBUS_SYSTEM_CONFIG_FILE);
 }
+#endif
 
 /**
- * Append the absolute path of the session.conf file.
- * 
- * @param str the string to append to
- * @returns #FALSE if no memory
+ * Determines the address of the session bus by querying a
+ * platform-specific method.
+ *
+ * The first parameter will be a boolean specifying whether
+ * or not a dynamic session lookup is supported on this platform.
+ *
+ * If supported is TRUE and the return value is #TRUE, the
+ * address will be  appended to @p address.
+ * If a failure happens, returns #FALSE and sets an error in
+ * @p error.
+ *
+ * If supported is FALSE, ignore the return value.
+ *
+ * @param supported returns whether this method is supported
+ * @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_append_session_config_file (DBusString *str)
+_dbus_lookup_session_address (dbus_bool_t *supported,
+                              DBusString  *address,
+                              DBusError   *error)
 {
-  return _dbus_string_append (str, DBUS_SESSION_CONFIG_FILE);
+#ifdef DBUS_ENABLE_LAUNCHD
+  *supported = TRUE;
+  return _dbus_lookup_session_address_launchd (address, error);
+#else
+  /* On non-Mac Unix platforms, if the session address isn't already
+   * set in DBUS_SESSION_BUS_ADDRESS environment variable, we punt and
+   * fall back to the autolaunch: global default; see
+   * init_session_address in dbus/dbus-bus.c. */
+  *supported = FALSE;
+  return TRUE;
+#endif
 }
 
 /**
@@ -3655,7 +3727,7 @@ _dbus_append_session_config_file (DBusString *str)
  * caches should be nuked. Of course any caches that need explicit reload
  * are probably broken, but c'est la vie.
  *
- * 
+ *
  */
 void
 _dbus_flush_caches (void)
@@ -3670,10 +3742,10 @@ _dbus_flush_caches (void)
  *
  * On UNIX the directory is ~/.dbus-keyrings while on Windows it should probably
  * be something else, since the dotfile convention is not normal on Windows.
- * 
+ *
  * @param directory string to append directory to
  * @param credentials credentials the directory should be for
- *  
+ *
  * @returns #FALSE on no memory
  */
 dbus_bool_t
@@ -3683,10 +3755,10 @@ _dbus_append_keyring_directory_for_credentials (DBusString      *directory,
   DBusString homedir;
   DBusString dotdir;
   dbus_uid_t uid;
-  
+
   _dbus_assert (credentials != NULL);
   _dbus_assert (!_dbus_credentials_are_anonymous (credentials));
-  
+
   if (!_dbus_string_init (&homedir))
     return FALSE;
 
@@ -3695,11 +3767,11 @@ _dbus_append_keyring_directory_for_credentials (DBusString      *directory,
 
   if (!_dbus_homedir_from_uid (uid, &homedir))
     goto failed;
-  
-#ifdef DBUS_BUILD_TESTS
+
+#ifdef DBUS_ENABLE_EMBEDDED_TESTS
   {
     const char *override;
-    
+
     override = _dbus_getenv ("DBUS_TEST_HOMEDIR");
     if (override != NULL && *override != '\0')
       {
@@ -3712,6 +3784,8 @@ _dbus_append_keyring_directory_for_credentials (DBusString      *directory,
       }
     else
       {
+        /* Not strictly thread-safe, but if we fail at thread-safety here,
+         * the worst that will happen is some extra warnings. */
         static dbus_bool_t already_warned = FALSE;
         if (!already_warned)
           {
@@ -3726,7 +3800,7 @@ _dbus_append_keyring_directory_for_credentials (DBusString      *directory,
   if (!_dbus_concat_dir_and_file (&homedir,
                                   &dotdir))
     goto failed;
-  
+
   if (!_dbus_string_copy (&homedir, 0,
                           directory, _dbus_string_get_length (directory))) {
     goto failed;
@@ -3734,12 +3808,26 @@ _dbus_append_keyring_directory_for_credentials (DBusString      *directory,
 
   _dbus_string_free (&homedir);
   return TRUE;
-  
- failed: 
+
+ failed:
   _dbus_string_free (&homedir);
   return FALSE;
 }
 
+//PENDING(kdab) docs
+dbus_bool_t
+_dbus_daemon_publish_session_bus_address (const char* addr,
+                                          const char *scope)
+{
+  return TRUE;
+}
+
+//PENDING(kdab) docs
+void
+_dbus_daemon_unpublish_session_bus_address (void)
+{
+
+}
 
 /**
  * See if errno is EAGAIN or EWOULDBLOCK (this has to be done differently
@@ -3754,6 +3842,34 @@ _dbus_get_is_errno_eagain_or_ewouldblock (void)
 }
 
 /**
+ * Removes a directory; Directory must be empty
+ *
+ * @param filename directory filename
+ * @param error initialized error object
+ * @returns #TRUE on success
+ */
+dbus_bool_t
+_dbus_delete_directory (const DBusString *filename,
+                        DBusError        *error)
+{
+  const char *filename_c;
+
+  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+  filename_c = _dbus_string_get_const_data (filename);
+
+  if (rmdir (filename_c) != 0)
+    {
+      dbus_set_error (error, DBUS_ERROR_FAILED,
+                      "Failed to remove directory %s: %s\n",
+                      filename_c, _dbus_strerror (errno));
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+/**
  *  Checks whether file descriptors may be passed via the socket
  *
  *  @param fd the socket
@@ -3785,4 +3901,191 @@ _dbus_socket_can_pass_unix_fd(int fd) {
 #endif
 }
 
+/**
+ * Closes all file descriptors except the first three (i.e. stdin,
+ * stdout, stderr).
+ */
+void
+_dbus_close_all (void)
+{
+  int maxfds, i;
+
+#ifdef __linux__
+  DIR *d;
+
+  /* On Linux we can optimize this a bit if /proc is available. If it
+     isn't available, fall back to the brute force way. */
+
+  d = opendir ("/proc/self/fd");
+  if (d)
+    {
+      for (;;)
+        {
+          struct dirent buf, *de;
+          int k, fd;
+          long l;
+          char *e = NULL;
+
+          k = readdir_r (d, &buf, &de);
+          if (k != 0 || !de)
+            break;
+
+          if (de->d_name[0] == '.')
+            continue;
+
+          errno = 0;
+          l = strtol (de->d_name, &e, 10);
+          if (errno != 0 || e == NULL || *e != '\0')
+            continue;
+
+          fd = (int) l;
+          if (fd < 3)
+            continue;
+
+          if (fd == dirfd (d))
+            continue;
+
+          close (fd);
+        }
+
+      closedir (d);
+      return;
+    }
+#endif
+
+  maxfds = sysconf (_SC_OPEN_MAX);
+
+  /* Pick something reasonable if for some reason sysconf says
+   * unlimited.
+   */
+  if (maxfds < 0)
+    maxfds = 1024;
+
+  /* close all inherited fds */
+  for (i = 3; i < maxfds; i++)
+    close (i);
+}
+
+/**
+ * **NOTE**: If you modify this function, please also consider making
+ * the corresponding change in GLib.  See
+ * glib/gutils.c:g_check_setuid().
+ *
+ * Returns TRUE if the current process was executed as setuid (or an
+ * equivalent __libc_enable_secure is available).  See:
+ * http://osdir.com/ml/linux.lfs.hardened/2007-04/msg00032.html
+ */
+dbus_bool_t
+_dbus_check_setuid (void)
+{
+  /* TODO: get __libc_enable_secure exported from glibc.
+   * See http://www.openwall.com/lists/owl-dev/2012/08/14/1
+   */
+#if 0 && defined(HAVE_LIBC_ENABLE_SECURE)
+  {
+    /* See glibc/include/unistd.h */
+    extern int __libc_enable_secure;
+    return __libc_enable_secure;
+  }
+#elif defined(HAVE_ISSETUGID)
+  /* BSD: http://www.freebsd.org/cgi/man.cgi?query=issetugid&sektion=2 */
+  return issetugid ();
+#else
+  uid_t ruid, euid, suid; /* Real, effective and saved user ID's */
+  gid_t rgid, egid, sgid; /* Real, effective and saved group ID's */
+
+  /* We call into this function from _dbus_threads_init_platform_specific()
+   * to make sure these are initialized before we start threading. */
+  static dbus_bool_t check_setuid_initialised;
+  static dbus_bool_t is_setuid;
+
+  if (_DBUS_UNLIKELY (!check_setuid_initialised))
+    {
+#ifdef HAVE_GETRESUID
+      if (getresuid (&ruid, &euid, &suid) != 0 ||
+          getresgid (&rgid, &egid, &sgid) != 0)
+#endif /* HAVE_GETRESUID */
+        {
+          suid = ruid = getuid ();
+          sgid = rgid = getgid ();
+          euid = geteuid ();
+          egid = getegid ();
+        }
+
+      check_setuid_initialised = TRUE;
+      is_setuid = (ruid != euid || ruid != suid ||
+                   rgid != egid || rgid != sgid);
+
+    }
+  return is_setuid;
+#endif
+}
+
+/**
+ * Read the address from the socket and append it to the string
+ *
+ * @param fd the socket
+ * @param address
+ * @param error return location for error code
+ */
+dbus_bool_t
+_dbus_append_address_from_socket (int         fd,
+                                  DBusString *address,
+                                  DBusError  *error)
+{
+  union {
+      struct sockaddr sa;
+      struct sockaddr_storage storage;
+      struct sockaddr_un un;
+      struct sockaddr_in ipv4;
+      struct sockaddr_in6 ipv6;
+  } socket;
+  char hostip[INET6_ADDRSTRLEN];
+  int size = sizeof (socket);
+
+  if (getsockname (fd, &socket.sa, &size))
+    goto err;
+
+  switch (socket.sa.sa_family)
+    {
+    case AF_UNIX:
+      if (socket.un.sun_path[0]=='\0')
+        {
+          if (_dbus_string_append_printf (address, "unix:abstract=%s", &(socket.un.sun_path[1])))
+            return TRUE;
+        }
+      else
+        {
+          if (_dbus_string_append_printf (address, "unix:path=%s", socket.un.sun_path))
+            return TRUE;
+        }
+      break;
+    case AF_INET:
+      if (inet_ntop (AF_INET, &socket.ipv4.sin_addr, hostip, sizeof (hostip)))
+        if (_dbus_string_append_printf (address, "tcp:family=ipv4,host=%s,port=%u",
+                   hostip, ntohs (socket.ipv4.sin_port)))
+          return TRUE;
+      break;
+#ifdef AF_INET6
+    case AF_INET6:
+      if (inet_ntop (AF_INET6, &socket.ipv6.sin6_addr, hostip, sizeof (hostip)))
+        if (_dbus_string_append_printf (address, "tcp:family=ipv6,host=%s,port=%u",
+                   hostip, ntohs (socket.ipv6.sin6_port)))
+          return TRUE;
+      break;
+#endif
+    default:
+      dbus_set_error (error,
+                      _dbus_error_from_errno (EINVAL),
+                      "Failed to read address from socket: Unknown socket type.");
+      return FALSE;
+    }
+ err:
+  dbus_set_error (error,
+                  _dbus_error_from_errno (errno),
+                  "Failed to open socket: %s",
+                  _dbus_strerror (errno));
+  return FALSE;
+}
+
 /* tests in dbus-sysdeps-util.c */