[vte] lib: Move fdwalk fallback implementation to its own file



commit 69ed779091b4165b8ea3894e4d58b986dde946a5
Author: Christian Persch <chpe src gnome org>
Date:   Mon Apr 27 20:49:04 2020 +0200

    lib: Move fdwalk fallback implementation to its own file

 src/meson.build |   1 +
 src/missing.cc  | 148 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/missing.hh  |   5 ++
 src/spawn.cc    |  33 ++++++++++++-
 src/spawn.hh    |   1 +
 src/vtespawn.cc | 139 ----------------------------------------------------
 src/vtespawn.hh |   6 ---
 7 files changed, 186 insertions(+), 147 deletions(-)
---
diff --git a/src/meson.build b/src/meson.build
index 5347f125..f25b425d 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -105,6 +105,7 @@ libvte_common_sources = debug_sources + glib_glue_sources + libc_glue_sources +
   'color-triple.hh',
   'keymap.cc',
   'keymap.h',
+  'missing.cc',
   'missing.hh',
   'reaper.cc',
   'reaper.hh',
diff --git a/src/missing.cc b/src/missing.cc
new file mode 100644
index 00000000..f374a466
--- /dev/null
+++ b/src/missing.cc
@@ -0,0 +1,148 @@
+/*
+ * Copyright © 2020 Christian Persch
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
+
+#include <glib-unix.h>
+#include <gio/gio.h>
+
+#ifdef __linux__
+#include <sys/syscall.h>  /* for syscall and SYS_getdents64 */
+#endif
+
+#include "missing.hh"
+
+/* BEGIN copied from glib
+ *
+ * Code for fdwalk copied from glib/glib/gspawn.c, there under LGPL2.1+,
+ * and used here under LGPL3+.
+ *
+ * Copyright 2000 Red Hat, Inc.
+ */
+
+#ifndef HAVE_FDWALK
+
+#ifdef __linux__
+
+struct linux_dirent64
+{
+  guint64        d_ino;    /* 64-bit inode number */
+  guint64        d_off;    /* 64-bit offset to next structure */
+  unsigned short d_reclen; /* Size of this dirent */
+  unsigned char  d_type;   /* File type */
+  char           d_name[]; /* Filename (null-terminated) */
+};
+
+static int
+filename_to_fd (const char *p)
+{
+  char c;
+  int fd = 0;
+  const int cutoff = G_MAXINT / 10;
+  const int cutlim = G_MAXINT % 10;
+
+  if (*p == '\0')
+    return -1;
+
+  while ((c = *p++) != '\0')
+    {
+      if (!g_ascii_isdigit (c))
+        return -1;
+      c -= '0';
+
+      /* Check for overflow. */
+      if (fd > cutoff || (fd == cutoff && c > cutlim))
+        return -1;
+
+      fd = fd * 10 + c;
+    }
+
+  return fd;
+}
+
+#endif /* __linux__ */
+
+int
+fdwalk(int (*cb)(void *data, int fd),
+       void *data)
+{
+  /* Fallback implementation of fdwalk. It should be async-signal safe, but it
+   * may be slow on non-Linux operating systems, especially on systems allowing
+   * very high number of open file descriptors.
+   */
+  int open_max;
+  int fd;
+  int res = 0;
+
+#ifdef HAVE_SYS_RESOURCE_H
+  struct rlimit rl;
+#endif
+
+#ifdef __linux__
+  /* Avoid use of opendir/closedir since these are not async-signal-safe. */
+  int dir_fd = open ("/proc/self/fd", O_RDONLY | O_DIRECTORY | O_CLOEXEC);
+  if (dir_fd >= 0)
+    {
+      char buf[4096];
+      int pos, nread;
+      struct linux_dirent64 *de;
+
+      while ((nread = syscall (SYS_getdents64, dir_fd, buf, sizeof(buf))) > 0)
+        {
+          for (pos = 0; pos < nread; pos += de->d_reclen)
+            {
+              de = (struct linux_dirent64 *)(buf + pos);
+
+              fd = filename_to_fd (de->d_name);
+              if (fd < 0 || fd == dir_fd)
+                  continue;
+
+              if ((res = cb (data, fd)) != 0)
+                  break;
+            }
+        }
+
+      close (dir_fd);
+      return res;
+    }
+
+  /* If /proc is not mounted or not accessible we fall back to the old
+   * rlimit trick */
+
+#endif
+
+#ifdef HAVE_SYS_RESOURCE_H
+
+  if (getrlimit(RLIMIT_NOFILE, &rl) == 0 && rl.rlim_max != RLIM_INFINITY)
+      open_max = rl.rlim_max;
+  else
+#endif
+      open_max = sysconf (_SC_OPEN_MAX);
+
+  for (fd = 0; fd < open_max; fd++)
+      if ((res = cb (data, fd)) != 0)
+          break;
+
+  return res;
+}
+#endif /* !HAVE_FDWALK */
+
+/* END copied from glib */
diff --git a/src/missing.hh b/src/missing.hh
index 0bff44a4..e0d49c7e 100644
--- a/src/missing.hh
+++ b/src/missing.hh
@@ -23,3 +23,8 @@
 #ifndef NSIG
 #define NSIG (8 * sizeof(sigset_t))
 #endif
+
+#ifndef HAVE_FDWALK
+int fdwalk(int (*cb)(void* data, int fd),
+           void* data);
+#endif
diff --git a/src/spawn.cc b/src/spawn.cc
index 67dea189..b8b78311 100644
--- a/src/spawn.cc
+++ b/src/spawn.cc
@@ -46,8 +46,25 @@
 
 #include "vtedefines.hh"
 
+#include "missing.hh"
+
 namespace vte::base {
 
+static int
+set_cloexec_cb(void* data,
+               int fd)
+{
+        if (fd >= *reinterpret_cast<int*>(data))
+                return vte::libc::fd_set_cloexec(fd);
+        return 0;
+}
+
+static int
+cloexec_from(int fd)
+{
+        return fdwalk(set_cloexec_cb, &fd);
+}
+
 static bool
 make_pipe(int flags,
           vte::libc::FD& read_fd,
@@ -186,7 +203,8 @@ SpawnContext::exec(vte::libc::FD& child_report_error_pipe_write) noexcept
          * child_error_report_pipe_write, which keeps the parent from blocking
          * forever on the other end of that pipe.
          */
-        _vte_cloexec_from(3);
+        if (cloexec_from(3) < 0)
+                return ExecError::FDWALK;
 
         /* Working directory */
         if (m_cwd && chdir(m_cwd.get()) < 0) {
@@ -427,6 +445,10 @@ SpawnOperation::run(vte::glib::Error& error) noexcept
                 return false;
 
         if (n_read >= 2) {
+                /* Spawn failed. buf[0] contains an error from
+                 * SpawnContext::ExecError, and buf[1] contains errno.
+                 */
+
                 /* The process will have called _exit(127) already, no need to kill it */
                 m_kill_pid = false;
 
@@ -460,6 +482,12 @@ SpawnOperation::run(vte::glib::Error& error) noexcept
                                   g_strerror(err));
                         break;
 
+                case SpawnContext::ExecError::FDWALK:
+                        error.set(G_IO_ERROR, g_io_error_from_errno(err),
+                                  "Failed to fdwalk: %s",
+                                  g_strerror(err));
+                        break;
+
                 case SpawnContext::ExecError::GETPTPEER:
                         error.set(G_IO_ERROR, g_io_error_from_errno(err),
                                   "Failed to open PTY peer: %s",
@@ -499,8 +527,9 @@ SpawnOperation::run(vte::glib::Error& error) noexcept
 
                 auto arg0 = vte::glib::take_string(g_utf8_make_valid(context().argv()[0], -1));
                 g_prefix_error(error,
-                               _("Failed to execute child process “%s”"),
+                               _("Failed to execute child process “%s”: "),
                                arg0.get());
+
                 return false;
         }
 
diff --git a/src/spawn.hh b/src/spawn.hh
index 26b0ec0b..d2ce5385 100644
--- a/src/spawn.hh
+++ b/src/spawn.hh
@@ -179,6 +179,7 @@ public:
                 DUP,
                 DUP2,
                 EXEC,
+                FDWALK,
                 GETPTPEER,
                 SCTTY,
                 SETSID,
diff --git a/src/vtespawn.cc b/src/vtespawn.cc
index 645600b3..662968be 100644
--- a/src/vtespawn.cc
+++ b/src/vtespawn.cc
@@ -32,17 +32,9 @@
 #include <stdlib.h>   /* for fdwalk */
 #include <dirent.h>
 
-#ifdef HAVE_SYS_RESOURCE_H
-#include <sys/resource.h>
-#endif /* HAVE_SYS_RESOURCE_H */
-
 #include <glib-unix.h>
 #include <gio/gio.h>
 
-#if defined(__linux__) || defined(__DragonFly__)
-#include <sys/syscall.h>  /* for syscall and SYS_getdents64 */
-#endif
-
 #include "vtespawn.hh"
 #include "vteutils.h"  /* for strchrnul on non-GNU systems */
 #include "reaper.hh"
@@ -81,16 +73,6 @@ _vte_write_err (int fd,
         write_all(fd, data, sizeof(data));
 }
 
-static int
-fd_set_cloexec(int fd)
-{
-        int flags = fcntl(fd, F_GETFD, 0);
-        if (flags < 0)
-                return flags;
-
-        return fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
-}
-
 static int
 fd_set_nonblocking(int fd)
 {
@@ -102,15 +84,6 @@ fd_set_nonblocking(int fd)
         return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
 }
 
-static int
-set_cloexec (void *data, int fd)
-{
-  if (fd >= GPOINTER_TO_INT (data))
-    fd_set_cloexec (fd);
-
-  return 0;
-}
-
 G_GNUC_UNUSED static int
 close_func (void *data, int fd)
 {
@@ -120,118 +93,6 @@ close_func (void *data, int fd)
   return 0;
 }
 
-#ifdef __linux__
-struct linux_dirent64
-{
-  guint64        d_ino;    /* 64-bit inode number */
-  guint64        d_off;    /* 64-bit offset to next structure */
-  unsigned short d_reclen; /* Size of this dirent */
-  unsigned char  d_type;   /* File type */
-  char           d_name[]; /* Filename (null-terminated) */
-};
-
-static int
-filename_to_fd (const char *p)
-{
-  char c;
-  int fd = 0;
-  const int cutoff = G_MAXINT / 10;
-  const int cutlim = G_MAXINT % 10;
-
-  if (*p == '\0')
-    return -1;
-
-  while ((c = *p++) != '\0')
-    {
-      if (!g_ascii_isdigit (c))
-        return -1;
-      c -= '0';
-
-      /* Check for overflow. */
-      if (fd > cutoff || (fd == cutoff && c > cutlim))
-        return -1;
-
-      fd = fd * 10 + c;
-    }
-
-  return fd;
-}
-#endif
-
-#ifndef HAVE_FDWALK
-int
-fdwalk (int (*cb)(void *data, int fd), void *data);
-
-int
-fdwalk (int (*cb)(void *data, int fd), void *data)
-{
-  /* Fallback implementation of fdwalk. It should be async-signal safe, but it
-   * may be slow on non-Linux operating systems, especially on systems allowing
-   * very high number of open file descriptors.
-   */
-  int open_max;
-  int fd;
-  int res = 0;
-
-#ifdef HAVE_SYS_RESOURCE_H
-  struct rlimit rl;
-#endif
-
-#ifdef __linux__
-  /* Avoid use of opendir/closedir since these are not async-signal-safe. */
-  int dir_fd = open ("/proc/self/fd", O_RDONLY | O_DIRECTORY);
-  if (dir_fd >= 0)
-    {
-      char buf[4096];
-      int pos, nread;
-      struct linux_dirent64 *de;
-
-      while ((nread = syscall (SYS_getdents64, dir_fd, buf, sizeof(buf))) > 0)
-        {
-          for (pos = 0; pos < nread; pos += de->d_reclen)
-            {
-              de = (struct linux_dirent64 *)(buf + pos);
-
-              fd = filename_to_fd (de->d_name);
-              if (fd < 0 || fd == dir_fd)
-                  continue;
-
-              if ((res = cb (data, fd)) != 0)
-                  break;
-            }
-        }
-
-      close (dir_fd);
-      return res;
-    }
-
-  /* If /proc is not mounted or not accessible we fall back to the old
-   * rlimit trick */
-
-#endif
-
-#ifdef HAVE_SYS_RESOURCE_H
-
-  if (getrlimit(RLIMIT_NOFILE, &rl) == 0 && rl.rlim_max != RLIM_INFINITY)
-      open_max = rl.rlim_max;
-  else
-#endif
-      open_max = sysconf (_SC_OPEN_MAX);
-
-  for (fd = 0; fd < open_max; fd++)
-      if ((res = cb (data, fd)) != 0)
-          break;
-
-  return res;
-}
-#endif /* HAVE_FDWALK */
-
-void
-_vte_cloexec_from(int fd)
-{
-        fdwalk(set_cloexec, GINT_TO_POINTER(fd));
-}
-
 bool
 _vte_read_ints(int      fd,
                int*    buf,
diff --git a/src/vtespawn.hh b/src/vtespawn.hh
index 855394e6..908fcbe9 100644
--- a/src/vtespawn.hh
+++ b/src/vtespawn.hh
@@ -22,12 +22,6 @@
 
 #include <glib.h>
 
-void _vte_cloexec_from(int fd);
-
-char** _vte_merge_envv(char** envp,
-                       char const* cwd,
-                       bool inherit);
-
 int _vte_execute(char const* file,
                  char** argv,
                  char** envp,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]