guix-commits
[Top][All Lists]
Advanced

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

08/24: DRAFT daemon: Support chroot builds on GNU/Hurd.


From: guix-commits
Subject: 08/24: DRAFT daemon: Support chroot builds on GNU/Hurd.
Date: Fri, 29 Sep 2023 06:10:54 -0400 (EDT)

janneke pushed a commit to branch hurd-team
in repository guix.

commit cc6f036ddfe934c55404cfec95c14351d54cfe4f
Author: Ludovic Courtès <ludo@gnu.org>
AuthorDate: Wed Oct 7 23:57:24 2020 +0200

    DRAFT daemon: Support chroot builds on GNU/Hurd.
    
    * nix/libutil/util.cc (firmlink): New functions.
    (_deletePath) [__GNU__]: Check whether a translator is set on PATH.
    Call 'fsys_goaway' if this is the case.
    * nix/libutil/util.hh (firmlink): New declaration.
    * nix/libstore/build.cc (CHROOT_ENABLED): Define to 1.  Error out when
    both __GNU__ and __linux__ are undefined.
    (DerivationGoal::runChild): Remove special treatment of /proc.  Use
    'firmlink' instead of 'mount' with MS_BIND.
    Wrap /proc, /dev/shm, /dev/pts, and /proc/self handling in #ifdef
    __linux__.  Same for 'pivot_root' call.
    * config-daemon.ac: Set and substitute 'HURD_LIBS'.
    * nix/local.mk (guix_daemon_LDADD): Add $(HURD_LIBS).
---
 config-daemon.ac      |  13 +++++
 nix/libstore/build.cc |  43 ++++++++++++----
 nix/libutil/util.cc   | 139 ++++++++++++++++++++++++++++++++++++++++++++++++++
 nix/libutil/util.hh   |   3 ++
 nix/local.mk          |   3 +-
 5 files changed, 189 insertions(+), 12 deletions(-)

diff --git a/config-daemon.ac b/config-daemon.ac
index 86306effe1..315f4de28f 100644
--- a/config-daemon.ac
+++ b/config-daemon.ac
@@ -37,6 +37,19 @@ if test "x$guix_build_daemon" = "xyes"; then
   AC_DEFINE_UNQUOTED([SYSTEM], ["$guix_system"],
     [Guix host system type--i.e., platform and OS kernel tuple.])
 
+  dnl On GNU/Hurd guix-daemon depends on libfshelp.
+  case "$guix_system" in
+    *-gnu)
+      AC_CHECK_LIB([fshelp], [fshelp_start_translator])
+      if test "x$ac_cv_lib_fshelp_fshelp_start_translator" != "xyes"; then
+        AC_MSG_ERROR([libfshelp (GNU Hurd) could not be found])
+      fi
+      HURD_LIBS="-lfshelp";;
+    *)
+      HURD_LIBS="";;
+  esac
+  AC_SUBST([HURD_LIBS])
+
   case "$LIBGCRYPT_PREFIX" in
     no)
       LIBGCRYPT_CFLAGS=""
diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index c5383bc756..a708202f2b 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -52,7 +52,13 @@
 #endif
 
 
-#define CHROOT_ENABLED HAVE_CHROOT && HAVE_SYS_MOUNT_H && defined(MS_BIND) && 
defined(MS_PRIVATE)
+/* Chroot builds are supported both on GNU/Linux and on GNU/Hurd.  */
+#if defined __linux__ || defined __GNU__
+# define CHROOT_ENABLED 1
+#else
+# error unsupported operating system
+#endif
+
 #define CLONE_ENABLED defined(CLONE_NEWNS)
 
 #if defined(SYS_pivot_root)
@@ -1998,6 +2004,7 @@ void DerivationGoal::runChild()
             if (setdomainname(domainname, sizeof(domainname)) == -1)
                 throw SysError("cannot set domain name");
 
+#ifdef __linux__
             /* Make all filesystems private.  This is necessary
                because subtrees may have been mounted as "shared"
                (MS_SHARED).  (Systemd does this, for instance.)  Even
@@ -2014,27 +2021,30 @@ void DerivationGoal::runChild()
                different filesystem from /, as needed for pivot_root. */
             if (mount(chrootRootDir.c_str(), chrootRootDir.c_str(), 0, 
MS_BIND, 0) == -1)
                 throw SysError(format("unable to bind mount ‘%1%’") % 
chrootRootDir);
+#endif
 
             /* Set up a nearly empty /dev, unless the user asked to
                bind-mount the host /dev. */
             Strings ss;
             if (dirsInChroot.find("/dev") == dirsInChroot.end()) {
+#ifdef __linux__
                 createDirs(chrootRootDir + "/dev/shm");
                 createDirs(chrootRootDir + "/dev/pts");
-                ss.push_back("/dev/full");
-#ifdef __linux__
+                createSymlink("/proc/self/fd", chrootRootDir + "/dev/fd");
+                createSymlink("/proc/self/fd/0", chrootRootDir + "/dev/stdin");
+                createSymlink("/proc/self/fd/1", chrootRootDir + 
"/dev/stdout");
+                createSymlink("/proc/self/fd/2", chrootRootDir + 
"/dev/stderr");
+                ss.push_back("/dev/tty");
                 if (pathExists("/dev/kvm"))
                     ss.push_back("/dev/kvm");
+#elif __GNU__
+               ss.push_back("/servers");
 #endif
+                ss.push_back("/dev/full");
                 ss.push_back("/dev/null");
                 ss.push_back("/dev/random");
-                ss.push_back("/dev/tty");
                 ss.push_back("/dev/urandom");
                 ss.push_back("/dev/zero");
-                createSymlink("/proc/self/fd", chrootRootDir + "/dev/fd");
-                createSymlink("/proc/self/fd/0", chrootRootDir + "/dev/stdin");
-                createSymlink("/proc/self/fd/1", chrootRootDir + 
"/dev/stdout");
-                createSymlink("/proc/self/fd/2", chrootRootDir + 
"/dev/stderr");
             }
 
             /* Fixed-output derivations typically need to access the
@@ -2056,7 +2066,7 @@ void DerivationGoal::runChild()
                 struct stat st;
                 Path source = i->second;
                 Path target = chrootRootDir + i->first;
-                if (source == "/proc") continue; // backwards compatibility
+
                 if (stat(source.c_str(), &st) == -1)
                     throw SysError(format("getting attributes of path `%1%'") 
% source);
                 if (S_ISDIR(st.st_mode))
@@ -2065,10 +2075,11 @@ void DerivationGoal::runChild()
                     createDirs(dirOf(target));
                     writeFile(target, "");
                 }
-                if (mount(source.c_str(), target.c_str(), "", MS_BIND, 0) == 
-1)
+                if (firmlink(source, target) == -1)
                     throw SysError(format("bind mount from `%1%' to `%2%' 
failed") % source % target);
             }
 
+#ifdef __linux__
             /* Bind a new instance of procfs on /proc to reflect our
                private PID namespace. */
             createDirs(chrootRootDir + "/proc");
@@ -2096,11 +2107,16 @@ void DerivationGoal::runChild()
                    Linux versions, it is created with permissions 0.  */
                 chmod_(chrootRootDir + "/dev/pts/ptmx", 0666);
             }
+#elif __GNU__
+           /* Do not mount things that are implemented in user land: /proc,
+              /dev/shm, /dev/pts, etc.  */
+#endif
 
             /* Do the chroot(). */
             if (chdir(chrootRootDir.c_str()) == -1)
                 throw SysError(format("cannot change directory to '%1%'") % 
chrootRootDir);
 
+#ifdef __linux__
             if (mkdir("real-root", 0) == -1)
                 throw SysError("cannot create real-root directory");
 
@@ -2115,8 +2131,13 @@ void DerivationGoal::runChild()
 
             if (rmdir("real-root") == -1)
                 throw SysError("cannot remove real-root directory");
-        }
+#elif __GNU__
+            if (chroot(".") == -1)
+                throw SysError(format("cannot change root directory to '%1%'") 
% chrootRootDir);
+
 #endif
+        }
+#endif // CHROOT_ENABLED
 
         if (chdir(tmpDirInSandbox.c_str()) == -1)
             throw SysError(format("changing into `%1%'") % tmpDir);
diff --git a/nix/libutil/util.cc b/nix/libutil/util.cc
index 82eac72120..62ddec8126 100644
--- a/nix/libutil/util.cc
+++ b/nix/libutil/util.cc
@@ -23,6 +23,41 @@
 #include <sys/prctl.h>
 #endif
 
+#if HAVE_SYS_MOUNT_H
+#include <sys/mount.h>
+#endif
+
+#ifdef __GNU__
+
+extern "C" {
+
+/* XXX: <idvec.h> uses 'new' as a parameter name.  Work around it.  */
+# define new new_param
+
+# include <hurd.h>
+# include <hurd/paths.h>
+# include <hurd/fsys.h>
+# include <argz.h>
+
+# undef new
+
+/* XXX: <fshelp.h> is not C++-compatible.  Copy these declarations to work
+   around it.  */
+
+typedef error_t (*fshelp_open_fn_t) (int flags,
+                                    file_t *node,
+                                    mach_msg_type_name_t *node_type,
+                                    task_t, void *cookie);
+
+extern error_t
+fshelp_start_translator (fshelp_open_fn_t underlying_open_fn, void *cookie,
+                        char *name, char *argz, int argz_len,
+                        int timeout, fsys_t *control);
+
+}
+
+# define _HURD_FIRMLINK  _HURD "firmlink"
+#endif
 
 extern char * * environ;
 
@@ -214,6 +249,89 @@ bool isLink(const Path & path)
     return S_ISLNK(st.st_mode);
 }
 
+#if __linux__
+
+int firmlink(const Path &source, const Path &target)
+{
+    return mount(source.c_str(), target.c_str(), "", MS_BIND, 0);
+}
+
+#elif __GNU__
+
+static error_t return_node (int flags,
+                           mach_port_t *underlying,
+                           mach_msg_type_name_t *underlying_type,
+                           task_t task, void *node)
+{
+    *underlying = * (mach_port_t *) node;
+    *underlying_type = MACH_MSG_TYPE_COPY_SEND;
+
+    return ESUCCESS;
+}
+
+int firmlink(const Path &source, const Path &target)
+{
+    static char firmlink[] = _HURD_FIRMLINK;
+    char *arg_vec[] = { firmlink, (char *) source.c_str (), NULL };
+    char *args = NULL;
+    size_t args_len;
+
+    error_t err;
+    file_t target_file = MACH_PORT_NULL;
+
+    printMsg (lvlChatty, format("creating firmlink from '%1%' to '%2%'")
+             % source % target);
+
+    target_file = file_name_lookup (target.c_str (), O_NOTRANS, 0);
+    if (! MACH_PORT_VALID (target_file)) {
+       printMsg (lvlChatty, format("firmlink target '%s' unavailable: %s")
+                 % target % strerror (errno));
+       goto fail;
+    }
+
+    err = argz_create (arg_vec, &args, &args_len);
+    if (err != 0) goto fail;
+
+    mach_port_t control;
+    err = fshelp_start_translator (return_node, &target_file,
+                                  firmlink, args, args_len,
+                                  3000, &control);
+    if (err) {
+       printMsg (lvlChatty, format("failed to start '%s' translator: %s") %
+                 firmlink % strerror(errno));
+       goto fail;
+    }
+
+    free ((void *) args);
+    args = NULL;
+
+    err = (error_t) file_set_translator (target_file, 0, FS_TRANS_SET, 0,
+                                        NULL, 0,
+                                        control, MACH_MSG_TYPE_COPY_SEND);
+    mach_port_deallocate (mach_task_self (), control);
+    mach_port_deallocate (mach_task_self (), target_file);
+
+    if (err) {
+       printMsg (lvlChatty, format("failed to set '%s' translator on node 
'%s': %s") %
+                 firmlink % target % strerror(errno));
+       goto fail;
+    }
+
+    return err;
+
+fail:
+    int saved_errno = errno;
+    if (MACH_PORT_VALID (target_file))
+       mach_port_deallocate (mach_task_self (), target_file);
+    if (args != NULL)
+       free ((void *) args);
+    errno = saved_errno;
+    return -1;
+}
+
+#elif
+# error unsupported operating system
+#endif
 
 DirEntries readDirectory(const Path & path)
 {
@@ -311,6 +429,27 @@ static void _deletePath(const Path & path, unsigned long 
long & bytesFreed, size
 
     printMsg(lvlVomit, format("%1%") % path);
 
+#ifdef __GNU__
+    /* Check whether there's an active translator on PATH--typically
+       /hurd/firmlink.  If there is one, let it go away.  */
+    {
+       file_t file = file_name_lookup (path.c_str (), O_NOTRANS, 0);
+       if (MACH_PORT_VALID (file)) {
+           fsys_t fsys;
+           int err = file_get_translator_cntl (file, &fsys);
+           mach_port_deallocate (mach_task_self (), file);
+           if (err == 0) {
+               /* There's a translator, tell it to leave.  */
+               err = fsys_goaway (fsys, FSYS_GOAWAY_FORCE | 
FSYS_GOAWAY_RECURSE);
+               mach_port_deallocate (mach_task_self (), fsys);
+               if (err != 0) {
+                   throw SysError(format("removing translator from '%1%'") % 
path);
+               }
+           }
+       }
+    }
+#endif
+
 #ifdef HAVE_STATX
 # define st_mode stx_mode
 # define st_size stx_size
diff --git a/nix/libutil/util.hh b/nix/libutil/util.hh
index 880b0e93b2..2f33735e12 100644
--- a/nix/libutil/util.hh
+++ b/nix/libutil/util.hh
@@ -63,6 +63,9 @@ Path readLink(const Path & path);
 
 bool isLink(const Path & path);
 
+/* Make TARGET a firmlink (aka. "bind mount") to SOURCE.  */
+int firmlink(const Path & source, const Path & target);
+
 /* Read the contents of a directory.  The entries `.' and `..' are
    removed. */
 struct DirEntry
diff --git a/nix/local.mk b/nix/local.mk
index 44a26dd2c8..971dc72af4 100644
--- a/nix/local.mk
+++ b/nix/local.mk
@@ -124,7 +124,8 @@ guix_daemon_CPPFLAGS =                              \
 
 guix_daemon_LDADD =                            \
   libstore.a libutil.a libformat.a -lz         \
-  $(SQLITE3_LIBS) $(LIBGCRYPT_LIBS)
+  $(SQLITE3_LIBS) $(LIBGCRYPT_LIBS)            \
+  $(HURD_LIBS)
 
 guix_daemon_headers =                          \
   %D%/nix-daemon/shared.hh



reply via email to

[Prev in Thread] Current Thread [Next in Thread]