_dbus_get_is_errno_eagain_or_ewouldblock: Avoid warning
[platform/upstream/dbus.git] / dbus / dbus-sysdeps-unix.c
index 377e9e2..e8cd5b3 100644 (file)
@@ -913,6 +913,7 @@ _dbus_connect_unix_socket (const char     *path,
   int fd;
   size_t path_len;
   struct sockaddr_un addr;
+  _DBUS_STATIC_ASSERT (sizeof (addr.sun_path) > _DBUS_MAX_SUN_PATH_LENGTH);
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
@@ -933,7 +934,7 @@ _dbus_connect_unix_socket (const char     *path,
 
   if (abstract)
     {
-#ifdef HAVE_ABSTRACT_SOCKETS
+#ifdef __linux__
       addr.sun_path[0] = '\0'; /* this is what says "use abstract" */
       path_len++; /* Account for the extra nul byte added to the start of sun_path */
 
@@ -945,14 +946,14 @@ _dbus_connect_unix_socket (const char     *path,
           return -1;
        }
 
-      strncpy (&addr.sun_path[1], path, path_len);
+      strncpy (&addr.sun_path[1], path, sizeof (addr.sun_path) - 2);
       /* _dbus_verbose_bytes (addr.sun_path, sizeof (addr.sun_path)); */
-#else /* HAVE_ABSTRACT_SOCKETS */
+#else /* !__linux__ */
       dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED,
                       "Operating system does not support abstract socket namespace\n");
       _dbus_close (fd, NULL);
       return -1;
-#endif /* ! HAVE_ABSTRACT_SOCKETS */
+#endif /* !__linux__ */
     }
   else
     {
@@ -964,7 +965,7 @@ _dbus_connect_unix_socket (const char     *path,
           return -1;
        }
 
-      strncpy (addr.sun_path, path, path_len);
+      strncpy (addr.sun_path, path, sizeof (addr.sun_path) - 1);
     }
 
   if (connect (fd, (struct sockaddr*) &addr, _DBUS_STRUCT_OFFSET (struct sockaddr_un, sun_path) + path_len) < 0)
@@ -1115,6 +1116,7 @@ _dbus_listen_unix_socket (const char     *path,
   int listen_fd;
   struct sockaddr_un addr;
   size_t path_len;
+  _DBUS_STATIC_ASSERT (sizeof (addr.sun_path) > _DBUS_MAX_SUN_PATH_LENGTH);
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
@@ -1134,7 +1136,7 @@ _dbus_listen_unix_socket (const char     *path,
 
   if (abstract)
     {
-#ifdef HAVE_ABSTRACT_SOCKETS
+#ifdef __linux__
       /* remember that abstract names aren't nul-terminated so we rely
        * on sun_path being filled in with zeroes above.
        */
@@ -1149,14 +1151,14 @@ _dbus_listen_unix_socket (const char     *path,
           return -1;
        }
 
-      strncpy (&addr.sun_path[1], path, path_len);
+      strncpy (&addr.sun_path[1], path, sizeof (addr.sun_path) - 2);
       /* _dbus_verbose_bytes (addr.sun_path, sizeof (addr.sun_path)); */
-#else /* HAVE_ABSTRACT_SOCKETS */
+#else /* !__linux__ */
       dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED,
                       "Operating system does not support abstract socket namespace\n");
       _dbus_close (listen_fd, NULL);
       return -1;
-#endif /* ! HAVE_ABSTRACT_SOCKETS */
+#endif /* !__linux__ */
     }
   else
     {
@@ -1186,7 +1188,7 @@ _dbus_listen_unix_socket (const char     *path,
           return -1;
        }
 
-      strncpy (addr.sun_path, path, path_len);
+      strncpy (addr.sun_path, path, sizeof (addr.sun_path) - 1);
     }
 
   if (bind (listen_fd, (struct sockaddr*) &addr, _DBUS_STRUCT_OFFSET (struct sockaddr_un, sun_path) + path_len) < 0)
@@ -1320,6 +1322,56 @@ _dbus_listen_systemd_sockets (DBusSocket **fds,
 #endif
 }
 
+/* Convert an error code from getaddrinfo() or getnameinfo() into
+ * a D-Bus error name. */
+static const char *
+_dbus_error_from_gai (int gai_res,
+                      int saved_errno)
+{
+  switch (gai_res)
+    {
+#ifdef EAI_FAMILY
+      case EAI_FAMILY:
+        /* ai_family not supported (at all) */
+        return DBUS_ERROR_NOT_SUPPORTED;
+#endif
+
+#ifdef EAI_SOCKTYPE
+      case EAI_SOCKTYPE:
+        /* ai_socktype not supported (at all) */
+        return DBUS_ERROR_NOT_SUPPORTED;
+#endif
+
+#ifdef EAI_MEMORY
+      case EAI_MEMORY:
+        /* Out of memory */
+        return DBUS_ERROR_NO_MEMORY;
+#endif
+
+#ifdef EAI_SYSTEM
+      case EAI_SYSTEM:
+        /* Unspecified system error, details in errno */
+        return _dbus_error_from_errno (saved_errno);
+#endif
+
+      case 0:
+        /* It succeeded, but we didn't get any addresses? */
+        return DBUS_ERROR_FAILED;
+
+      /* EAI_AGAIN: Transient failure */
+      /* EAI_BADFLAGS: invalid ai_flags (programming error) */
+      /* EAI_FAIL: Non-recoverable failure */
+      /* EAI_NODATA: host exists but has no addresses */
+      /* EAI_NONAME: host does not exist */
+      /* EAI_OVERFLOW: argument buffer overflow */
+      /* EAI_SERVICE: service not available for specified socket
+       * type (we should never see this because we use numeric
+       * ports) */
+      default:
+        return DBUS_ERROR_FAILED;
+    }
+}
+
 /**
  * Creates a socket and connects to a socket at the given host
  * and port. The connection fd is returned, and is set up as
@@ -1379,7 +1431,7 @@ _dbus_connect_tcp_socket_with_nonce (const char     *host,
   if ((res = getaddrinfo(host, port, &hints, &ai)) != 0)
     {
       dbus_set_error (error,
-                      _dbus_error_from_errno (errno),
+                      _dbus_error_from_gai (res, errno),
                       "Failed to lookup host/port: \"%s:%s\": %s (%d)",
                       host, port, gai_strerror(res), res);
       return _dbus_socket_get_invalid ();
@@ -1501,7 +1553,7 @@ _dbus_listen_tcp_socket (const char     *host,
   if ((res = getaddrinfo(host, port, &hints, &ai)) != 0 || !ai)
     {
       dbus_set_error (error,
-                      _dbus_error_from_errno (errno),
+                      _dbus_error_from_gai (res, errno),
                       "Failed to lookup host/port: \"%s:%s\": %s (%d)",
                       host ? host : "*", port, gai_strerror(res), res);
       goto failed;
@@ -1576,11 +1628,9 @@ _dbus_listen_tcp_socket (const char     *host,
       newlisten_fd = dbus_realloc(listen_fd, sizeof(DBusSocket)*(nlisten_fd+1));
       if (!newlisten_fd)
         {
-          saved_errno = errno;
           _dbus_close (fd, NULL);
-          dbus_set_error (error, _dbus_error_from_errno (saved_errno),
-                          "Failed to allocate file handle array: %s",
-                          _dbus_strerror (saved_errno));
+          dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
+                          "Failed to allocate file handle array");
           goto failed;
         }
       listen_fd = newlisten_fd;
@@ -1603,16 +1653,26 @@ _dbus_listen_tcp_socket (const char     *host,
               addrlen = sizeof(addr);
               result = getsockname(fd, (struct sockaddr*) &addr, &addrlen);
 
-              if (result == -1 ||
-                  (res = getnameinfo ((struct sockaddr*)&addr, addrlen, NULL, 0,
+              if (result == -1)
+                {
+                  saved_errno = errno;
+                  dbus_set_error (error, _dbus_error_from_errno (saved_errno),
+                                  "Failed to retrieve socket name for \"%s:%s\": %s",
+                                  host ? host : "*", port, _dbus_strerror (saved_errno));
+                  goto failed;
+                }
+
+              if ((res = getnameinfo ((struct sockaddr*)&addr, addrlen, NULL, 0,
                                       portbuf, sizeof(portbuf),
                                       NI_NUMERICHOST | NI_NUMERICSERV)) != 0)
                 {
-                  dbus_set_error (error, _dbus_error_from_errno (errno),
+                  saved_errno = errno;
+                  dbus_set_error (error, _dbus_error_from_gai (res, saved_errno),
                                   "Failed to resolve port \"%s:%s\": %s (%d)",
                                   host ? host : "*", port, gai_strerror(res), res);
                   goto failed;
                 }
+
               if (!_dbus_string_append(retport, portbuf))
                 {
                   dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
@@ -2054,13 +2114,13 @@ _dbus_read_credentials_socket  (DBusSocket       client_fd,
     ucred_t * ucred = NULL;
     if (getpeerucred (client_fd.fd, &ucred) == 0)
       {
+#ifdef HAVE_ADT
+        adt_session_data_t *adth = NULL;
+#endif
         pid_read = ucred_getpid (ucred);
         uid_read = ucred_geteuid (ucred);
 #ifdef HAVE_ADT
         /* generate audit session data based on socket ucred */
-        adt_session_data_t *adth = NULL;
-        adt_export_data_t *data = NULL;
-        size_t size = 0;
         if (adt_start_session (&adth, NULL, 0) || (adth == NULL))
           {
             _dbus_verbose ("Failed to adt_start_session(): %s\n", _dbus_strerror (errno));
@@ -2073,7 +2133,8 @@ _dbus_read_credentials_socket  (DBusSocket       client_fd,
               }
             else
               {
-                size = adt_export_session_data (adth, &data);
+                adt_export_data_t *data = NULL;
+                size_t size = adt_export_session_data (adth, &data);
                 if (size <= 0)
                   {
                     _dbus_verbose ("Failed to adt_export_session_data(): %s\n", _dbus_strerror (errno));
@@ -2955,7 +3016,7 @@ _dbus_get_real_time (long *tv_sec,
  * @returns #TRUE on success
  */
 dbus_bool_t
-_dbus_create_directory (const DBusString *filename,
+_dbus_ensure_directory (const DBusString *filename,
                         DBusError        *error)
 {
   const char *filename_c;
@@ -2979,6 +3040,35 @@ _dbus_create_directory (const DBusString *filename,
 }
 
 /**
+ * Creates a directory. Unlike _dbus_ensure_directory(), this only succeeds
+ * if the directory is genuinely newly-created.
+ *
+ * @param filename directory filename
+ * @param error initialized error object
+ * @returns #TRUE on success
+ */
+dbus_bool_t
+_dbus_create_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 (mkdir (filename_c, 0700) < 0)
+    {
+      dbus_set_error (error, DBUS_ERROR_FAILED,
+                      "Failed to create directory %s: %s\n",
+                      filename_c, _dbus_strerror (errno));
+      return FALSE;
+    }
+  else
+    return TRUE;
+}
+
+/**
  * Appends the given filename to the given directory.
  *
  * @todo it might be cute to collapse multiple '/' such as "foo//"
@@ -3876,36 +3966,51 @@ _dbus_read_local_machine_uuid (DBusGUID   *machine_id,
                                dbus_bool_t create_if_not_found,
                                DBusError  *error)
 {
+  DBusError our_error = DBUS_ERROR_INIT;
+  DBusError etc_error = DBUS_ERROR_INIT;
   DBusString filename;
   dbus_bool_t b;
 
   _dbus_string_init_const (&filename, DBUS_MACHINE_UUID_FILE);
 
-  b = _dbus_read_uuid_file (&filename, machine_id, FALSE, error);
+  b = _dbus_read_uuid_file (&filename, machine_id, FALSE, &our_error);
   if (b)
     return TRUE;
 
-  dbus_error_free (error);
-
   /* Fallback to the system machine ID */
   _dbus_string_init_const (&filename, "/etc/machine-id");
-  b = _dbus_read_uuid_file (&filename, machine_id, FALSE, error);
+  b = _dbus_read_uuid_file (&filename, machine_id, FALSE, &etc_error);
 
   if (b)
     {
-      /* try to copy it to the DBUS_MACHINE_UUID_FILE, but do not
-       * complain if that isn't possible for whatever reason */
-      _dbus_string_init_const (&filename, DBUS_MACHINE_UUID_FILE);
-      _dbus_write_uuid_file (&filename, machine_id, NULL);
+      if (create_if_not_found)
+        {
+          /* try to copy it to the DBUS_MACHINE_UUID_FILE, but do not
+           * complain if that isn't possible for whatever reason */
+          _dbus_string_init_const (&filename, DBUS_MACHINE_UUID_FILE);
+          _dbus_write_uuid_file (&filename, machine_id, NULL);
+        }
 
+      dbus_error_free (&our_error);
       return TRUE;
     }
 
   if (!create_if_not_found)
-    return FALSE;
+    {
+      dbus_set_error (error, etc_error.name,
+                      "D-Bus library appears to be incorrectly set up: "
+                      "see the manual page for dbus-uuidgen to correct "
+                      "this issue. (%s; %s)",
+                      our_error.message, etc_error.message);
+      dbus_error_free (&our_error);
+      dbus_error_free (&etc_error);
+      return FALSE;
+    }
+
+  dbus_error_free (&our_error);
+  dbus_error_free (&etc_error);
 
   /* if none found, try to make a new one */
-  dbus_error_free (error);
   _dbus_string_init_const (&filename, DBUS_MACHINE_UUID_FILE);
 
   if (!_dbus_generate_uuid (machine_id, error))
@@ -4209,7 +4314,8 @@ _dbus_append_keyring_directory_for_credentials (DBusString      *directory,
         static dbus_bool_t already_warned = FALSE;
         if (!already_warned)
           {
-            _dbus_warn ("Using your real home directory for testing, set DBUS_TEST_HOMEDIR to avoid");
+            _dbus_warn ("Using %s for testing, set DBUS_TEST_HOMEDIR to avoid",
+                _dbus_string_get_const_data (&homedir));
             already_warned = TRUE;
           }
       }
@@ -4258,7 +4364,15 @@ _dbus_daemon_unpublish_session_bus_address (void)
 dbus_bool_t
 _dbus_get_is_errno_eagain_or_ewouldblock (int e)
 {
+  /* Avoid the -Wlogical-op GCC warning, which can be triggered when EAGAIN and
+   * EWOULDBLOCK are numerically equal, which is permitted as described by
+   * errno(3).
+   */
+#if EAGAIN == EWOULDBLOCK
+  return e == EAGAIN;
+#else
   return e == EAGAIN || e == EWOULDBLOCK;
+#endif
 }
 
 /**
@@ -4570,9 +4684,6 @@ _dbus_init_system_log (const char   *tag,
  * @param severity a severity value
  * @param msg a printf-style format string
  * @param args arguments for the format string
- *
- * If the FATAL severity is given, this function will terminate the program
- * with an error code.
  */
 void
 _dbus_logv (DBusSystemLogSeverity  severity,
@@ -4587,7 +4698,7 @@ _dbus_logv (DBusSystemLogSeverity  severity,
       switch (severity)
         {
           case DBUS_SYSTEM_LOG_INFO:
-            flags =  LOG_DAEMON | LOG_NOTICE;
+            flags =  LOG_DAEMON | LOG_INFO;
             break;
           case DBUS_SYSTEM_LOG_WARNING:
             flags =  LOG_DAEMON | LOG_WARNING;
@@ -4595,11 +4706,11 @@ _dbus_logv (DBusSystemLogSeverity  severity,
           case DBUS_SYSTEM_LOG_SECURITY:
             flags = LOG_AUTH | LOG_NOTICE;
             break;
-          case DBUS_SYSTEM_LOG_FATAL:
+          case DBUS_SYSTEM_LOG_ERROR:
             flags = LOG_DAEMON|LOG_CRIT;
             break;
           default:
-            return;
+            _dbus_assert_not_reached ("invalid log severity");
         }
 
       DBUS_VA_COPY (tmp, args);
@@ -4618,9 +4729,6 @@ _dbus_logv (DBusSystemLogSeverity  severity,
       fputc ('\n', stderr);
       va_end (tmp);
     }
-
-  if (severity == DBUS_SYSTEM_LOG_FATAL)
-    exit (1);
 }
 
 /* tests in dbus-sysdeps-util.c */