bus: Raise file descriptor limit to match configuration
[platform/upstream/dbus.git] / dbus / dbus-sysdeps-util-unix.c
index 4269381..02954d5 100644 (file)
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  *
  */
+
+#include <config.h>
 #include "dbus-sysdeps.h"
 #include "dbus-sysdeps-unix.h"
 #include "dbus-internals.h"
+#include "dbus-pipe.h"
 #include "dbus-protocol.h"
 #include "dbus-string.h"
 #define DBUS_USERDB_INCLUDES_PRIVATE 1
@@ -39,6 +42,9 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <sys/stat.h>
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
 #include <grp.h>
 #include <sys/socket.h>
 #include <dirent.h>
@@ -248,7 +254,8 @@ _dbus_write_pid_to_file_and_pipe (const DBusString *pidfile,
       DBusString pid;
       int bytes;
 
-      _dbus_verbose ("writing our pid to pipe %d\n", print_pid_pipe->fd_or_handle);
+      _dbus_verbose ("writing our pid to pipe %"PRIuPTR"\n",
+                     print_pid_pipe->fd_or_handle);
       
       if (!_dbus_string_init (&pid))
         {
@@ -365,6 +372,56 @@ _dbus_change_to_daemon_user  (const char    *user,
 }
 #endif /* !HAVE_LIBAUDIT */
 
+
+/**
+ * Attempt to ensure that the current process can open
+ * at least @limit file descriptors.
+ *
+ * If @limit is lower than the current, it will not be
+ * lowered.  No error is returned if the request can
+ * not be satisfied.
+ *
+ * @limit Number of file descriptors
+ */
+void
+_dbus_request_file_descriptor_limit (unsigned int limit)
+{
+#ifdef HAVE_SETRLIMIT
+  struct rlimit lim;
+  struct rlimit target_lim;
+  unsigned int current_limit;
+
+  /* No point to doing this practically speaking
+   * if we're not uid 0.  We expect the system
+   * bus to use this before we change UID, and
+   * the session bus takes the Linux default
+   * of 1024 for both cur and max.
+   */
+  if (getuid () != 0)
+    return;
+
+  if (getrlimit (RLIMIT_NOFILE, &lim) < 0)
+    return;
+
+  if (lim.rlim_cur >= limit)
+    return;
+
+  /* Ignore "maximum limit", assume we have the "superuser"
+   * privileges.  On Linux this is CAP_SYS_RESOURCE.
+   */
+  target_lim.rlim_cur = target_lim.rlim_max = limit;
+  /* Also ignore errors; if we fail, we will at least work
+   * up to whatever limit we had, which seems better than
+   * just outright aborting.
+   *
+   * However, in the future we should probably log this so OS builders
+   * have a chance to notice any misconfiguration like dbus-daemon
+   * being started without CAP_SYS_RESOURCE.
+   */
+  setrlimit (RLIMIT_NOFILE, &target_lim);
+#endif
+}
+
 void 
 _dbus_init_system_log (void)
 {
@@ -397,6 +454,8 @@ _dbus_system_log (DBusSystemLogSeverity severity, const char *msg, ...)
  * @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_system_logv (DBusSystemLogSeverity severity, const char *msg, va_list args)
@@ -410,10 +469,17 @@ _dbus_system_logv (DBusSystemLogSeverity severity, const char *msg, va_list args
       case DBUS_SYSTEM_LOG_SECURITY:
         flags = LOG_AUTH | LOG_NOTICE;
         break;
+      case DBUS_SYSTEM_LOG_FATAL:
+        flags = LOG_DAEMON|LOG_CRIT;
+        break;
       default:
         return;
     }
+
   vsyslog (flags, msg, args);
+
+  if (severity == DBUS_SYSTEM_LOG_FATAL)
+    exit (1);
 }
 
 /** Installs a UNIX signal handler
@@ -435,35 +501,6 @@ _dbus_set_signal_handler (int               sig,
   sigaction (sig,  &act, NULL);
 }
 
-
-/**
- * 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 if a file exists
 *
 * @param file full path to the file
@@ -624,54 +661,14 @@ _dbus_directory_open (const DBusString *filename,
   return iter;
 }
 
-/* Calculate the required buffer size (in bytes) for directory
- * entries read from the given directory handle.  Return -1 if this
- * this cannot be done. 
- *
- * If you use autoconf, include fpathconf and dirfd in your
- * AC_CHECK_FUNCS list.  Otherwise use some other method to detect
- * and use them where available.
- */
-static dbus_bool_t
-dirent_buf_size(DIR * dirp, size_t *size)
-{
- long name_max;
-#   if defined(HAVE_FPATHCONF) && defined(_PC_NAME_MAX)
-#      if defined(HAVE_DIRFD)
-          name_max = fpathconf(dirfd(dirp), _PC_NAME_MAX);
-#      elif defined(HAVE_DDFD)
-          name_max = fpathconf(dirp->dd_fd, _PC_NAME_MAX);
-#      else
-          name_max = fpathconf(dirp->__dd_fd, _PC_NAME_MAX);
-#      endif /* HAVE_DIRFD */
-     if (name_max == -1)
-#           if defined(NAME_MAX)
-            name_max = NAME_MAX;
-#           else
-            return FALSE;
-#           endif
-#   elif defined(MAXNAMELEN)
-     name_max = MAXNAMELEN;
-#   else
-#       if defined(NAME_MAX)
-        name_max = NAME_MAX;
-#       else
-#           error "buffer size for readdir_r cannot be determined"
-#       endif
-#   endif
-  if (size)
-    *size = (size_t)offsetof(struct dirent, d_name) + name_max + 1;
-  else
-    return FALSE;
-
-  return TRUE;
-}
-
 /**
  * Get next file in the directory. Will not return "." or ".."  on
  * UNIX. If an error occurs, the contents of "filename" are
  * undefined. The error is never set if the function succeeds.
  *
+ * This function is not re-entrant, and not necessarily thread-safe.
+ * Only use it for test code or single-threaded utilities.
+ *
  * @param iter the iterator
  * @param filename string to be set to the next file in the dir
  * @param error return location for error
@@ -682,37 +679,24 @@ _dbus_directory_get_next_file (DBusDirIter      *iter,
                                DBusString       *filename,
                                DBusError        *error)
 {
-  struct dirent *d, *ent;
-  size_t buf_size;
+  struct dirent *ent;
   int err;
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-  if (!dirent_buf_size (iter->d, &buf_size))
-    {
-      dbus_set_error (error, DBUS_ERROR_FAILED,
-                      "Can't calculate buffer size when reading directory");
-      return FALSE;
-    }
-
-  d = (struct dirent *)dbus_malloc (buf_size);
-  if (!d)
-    {
-      dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
-                      "No memory to read directory entry");
-      return FALSE;
-    }
 
  again:
-  err = readdir_r (iter->d, d, &ent);
-  if (err || !ent)
+  errno = 0;
+  ent = readdir (iter->d);
+
+  if (!ent)
     {
+      err = errno;
+
       if (err != 0)
         dbus_set_error (error,
                         _dbus_error_from_errno (err),
                         "%s", _dbus_strerror (err));
 
-      dbus_free (d);
       return FALSE;
     }
   else if (ent->d_name[0] == '.' &&
@@ -726,12 +710,10 @@ _dbus_directory_get_next_file (DBusDirIter      *iter,
         {
           dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
                           "No memory to read directory entry");
-          dbus_free (d);
           return FALSE;
         }
       else
         {
-          dbus_free (d);
           return TRUE;
         }
     }
@@ -1068,7 +1050,7 @@ _dbus_string_get_dirname  (const DBusString *filename,
 static void
 string_squash_nonprintable (DBusString *str)
 {
-  char *buf;
+  unsigned char *buf;
   int i, len; 
   
   buf = _dbus_string_get_data (str);
@@ -1164,4 +1146,3 @@ fail:
   _dbus_string_free (&path);
   return FALSE;
 }
-