$NetBSD: patch-ab,v 1.20 2012/08/14 19:18:08 abs Exp $

_dbus_poll: Set the timeout value argument to poll to -1 whenever
it is less than -1 to avoid kde4 session start hang

--- dbus/dbus-sysdeps-unix.c.orig	2012-07-03 18:02:45.000000000 +0000
+++ dbus/dbus-sysdeps-unix.c
@@ -22,6 +22,8 @@
  *
  */
 
+#define _NETBSD_SOURCE
+
 #include <config.h>
 
 #include "dbus-internals.h"
@@ -72,6 +74,10 @@
 #include <ucred.h>
 #endif
 
+#ifdef __NetBSD__
+#include <sys/un.h>
+#endif
+
 #ifdef HAVE_ADT
 #include <bsm/adt.h>
 #endif
@@ -122,6 +128,32 @@
 
 #endif /* Solaris */
 
+#ifdef LOCAL_PEEREID
+static dbus_bool_t
+dbus_nb_getpeereid(int fd, pid_t *pid, uid_t *uid, gid_t *gid)
+{
+  struct unpcbid cred;
+  socklen_t len = sizeof(cred);
+
+  _dbus_verbose ("dbus_nb_getpeereid: enter, fd=%d\n");
+  if (getsockopt (fd, 0, LOCAL_PEEREID, &cred, &len) < 0)
+    {
+      _dbus_verbose ("dbus_nb_getpeereid: getsockopt LOCAL_PEEREID failed: %s\n", strerror(errno));
+      return FALSE;
+    }
+  if (pid)
+    *pid = cred.unp_pid;
+  if (uid)
+    *uid = cred.unp_euid;
+  if (gid)
+    *gid = cred.unp_egid;
+
+  _dbus_verbose ("dbus_nb_getpeereid: returning TRUE, pid=%d uid=%d gid=%d\n",
+                cred.unp_pid, cred.unp_euid, cred.unp_egid);
+  return TRUE;
+}
+#endif
+
 static dbus_bool_t
 _dbus_open_socket (int              *fd_p,
                    int               domain,
@@ -969,7 +1001,7 @@ _dbus_set_local_creds (int fd, dbus_bool
 {
   dbus_bool_t retval = TRUE;
 
-#if defined(HAVE_CMSGCRED)
+#if defined(HAVE_CMSGCRED) || defined(LOCAL_PEEREID)
   /* NOOP just to make sure only one codepath is used
    *      and to prefer CMSGCRED
    */
@@ -1674,6 +1706,11 @@ _dbus_read_credentials_socket  (int     
     char cred[CMSG_SPACE (sizeof (struct cmsgcred))];
   } cmsg;
 
+#elif defined(LOCAL_PEEREID)
+  pid_t sockpid;
+  uid_t sockuid;
+  gid_t sockgid;
+
 #elif defined(LOCAL_CREDS)
   struct {
     struct cmsghdr hdr;
@@ -1709,10 +1746,15 @@ _dbus_read_credentials_socket  (int     
   msg.msg_iov = &iov;
   msg.msg_iovlen = 1;
 
-#if defined(HAVE_CMSGCRED) || defined(LOCAL_CREDS)
+#if (defined(HAVE_CMSGCRED) || defined(LOCAL_CREDS)) && !defined(LOCAL_PEEREID)
   _DBUS_ZERO(cmsg);
+#ifdef HAVE_CMSGCRED
   msg.msg_control = (caddr_t) &cmsg;
   msg.msg_controllen = CMSG_SPACE (sizeof (struct cmsgcred));
+#else /* defined(LOCAL_CREDS) */
+  msg.msg_control = &cmsg;
+  msg.msg_controllen = sizeof (cmsg);
+#endif
 #endif
 
  again:
@@ -1749,9 +1791,13 @@ _dbus_read_credentials_socket  (int     
       return FALSE;
     }
 
-#if defined(HAVE_CMSGCRED) || defined(LOCAL_CREDS)
+#if (defined(HAVE_CMSGCRED) || defined(LOCAL_CREDS)) && !defined(LOCAL_PEEREID)
+#ifdef HAVE_CMSGCRED
   if (cmsg.hdr.cmsg_len < CMSG_LEN (sizeof (struct cmsgcred))
 		  || cmsg.hdr.cmsg_type != SCM_CREDS)
+#else /* defined(LOCAL_CREDS) */
+  if (cmsg.hdr.cmsg_len < sizeof (cmsg) || cmsg.hdr.cmsg_type != SCM_CREDS)
+#endif
     {
       dbus_set_error (error, DBUS_ERROR_FAILED,
                       "Message from recvmsg() was not SCM_CREDS");
@@ -1787,6 +1833,16 @@ _dbus_read_credentials_socket  (int     
     cred = (struct cmsgcred *) CMSG_DATA (&cmsg.hdr);
     pid_read = cred->cmcred_pid;
     uid_read = cred->cmcred_euid;
+#elif defined(LOCAL_PEEREID)
+    if (dbus_nb_getpeereid(client_fd, &sockpid, &sockuid, &sockgid) == TRUE)
+      {
+       pid_read = sockpid;
+       uid_read = sockuid;
+      }
+    else
+      {
+        _dbus_verbose ("Failed to dbus_nb_getpeereid() credentials: %s\n", _dbus_strerror (errno));
+      }
 #elif defined(LOCAL_CREDS)
     pid_read = DBUS_PID_UNSET;
     uid_read = cmsg.cred.sc_uid;
@@ -1848,7 +1904,7 @@ _dbus_read_credentials_socket  (int     
       }
     if (ucred != NULL)
       ucred_free (ucred);
-#else /* !SO_PEERCRED && !HAVE_CMSGCRED && !HAVE_GETPEEREID && !HAVE_GETPEERUCRED */
+#else /* !SO_PEERCRED && !HAVE_CMSGCRED && !HAVE_GETPEEREID && !HAVE_GETPEERUCRED && !LOCAL_PEEREID */
     _dbus_verbose ("Socket credentials not supported on this OS\n");
 #endif
   }
@@ -2525,6 +2581,10 @@ _dbus_poll (DBusPollFD *fds,
       _DBUS_STRUCT_OFFSET (DBusPollFD, revents) ==
       _DBUS_STRUCT_OFFSET (struct pollfd, revents))
     {
+      if (timeout_milliseconds < -1) {
+        _dbus_warn("_dbus_poll: timeout = %d (fixed)\n", timeout_milliseconds);
+        timeout_milliseconds = -1;
+      }
       return poll ((struct pollfd*) fds,
                    n_fds,
                    timeout_milliseconds);
