Repositories / jai.git

jai.git

Clone (read-only): git clone http://git.guha-anderson.com/git/jai.git

Branch

work in progress

Author
David Mazieres <dm@uun.org>
Date
2026-03-17 18:17:37 -0700
Commit
78dad5190695328962709dc0de9e474448b67093
default_conf.cc
index a974103..beef2cc 100644
--- a/default_conf.cc
+++ b/default_conf.cc
@@ -29,14 +29,10 @@ const std::string default_conf =
 # name default
 
 # jai launches programs in a sandbox by running bash with the command
-# name in "$0" and the arguments in "@".  bash will have a PID 1,
-# which can confuse some programs.  Adding "; exit $?" after the
-# command and arguments will cause bash to fork and stay around,
-# giving "$0" PID 2.  For non-default configurations, you can also use
-# a command directive to insert extra arguments or set environment
-# variables.
+# name in "$0" and the arguments in "@".  Altering command allow you
+# to set enfironment variables or add command-line arguments.
 
-command "$0" "$@"; exit $?
+command "$0" "$@"
 
 # Masked files are deleted when an overlayfs is first created, but
 # have no effect on existing overlays or on strict/bare jails.  To
jai.cc
index 893053d..b95da73 100644
--- a/jai.cc
+++ b/jai.cc
@@ -380,7 +380,6 @@ Config::make_idmap_ns()
   });
   auto pfds = xpipe();
   if (!(pid = xfork(CLONE_NEWUSER))) {
-    prctl(PR_SET_PDEATHSIG, SIGKILL);
     pfds[1].reset();
     char c;
     read(*pfds[0], &c, 1);
@@ -640,6 +639,42 @@ Config::sanitize_env()
     unsetenv(v.c_str());
 }
 
+[[noreturn]] static void
+emulate_child(int pid, bool immediate)
+try {
+  for (;;) {
+    int status;
+    int r = waitpid(pid, &status, WUNTRACED);
+    std::println(stderr, "waitpid: pid {}, status 0x{:x}", pid, status);
+    fflush(stderr);
+    if (r != pid) {
+      if (r == -1 && errno != EINTR)
+        syserr("waitpid");
+      continue;
+    }
+    if (WIFSTOPPED(status)) {
+      if (int sig = WSTOPSIG(status); sig == SIGSTOP || sig == SIGTSTP ||
+                                      sig == SIGTTIN || sig == SIGTTOU) {
+        std::println(stderr, "attempting to stop myself with signal {}", sig);
+        raise(SIGSTOP);
+      }
+      continue;
+    }
+    // unmount();
+    if (WIFEXITED(status))
+      (immediate ? _exit : exit)(WEXITSTATUS(status));
+    if (WIFSIGNALED(status)) {
+      signal(WTERMSIG(status), SIG_DFL);
+      raise(WTERMSIG(status));
+      _exit(-1);
+    }
+    err("unknown child wait status 0x{:x}", status);
+  }
+} catch (const std::exception &e) {
+  warn("{}", e.what());
+  immediate ? _exit(1) : exit(1);
+}
+
 void
 Config::exec(int nsfd, char **argv)
 {
@@ -647,34 +682,20 @@ Config::exec(int nsfd, char **argv)
     syserr("unshare(CLONE_NEWPID)");
 
   if (auto pid = xfork()) {
+    // This is the last process in the old PID namespace
     close(nsfd);
-    int status = -1;
-    for (;;) {
-      int r = waitpid(pid, &status, WUNTRACED);
-      // std::println(stderr, "waitpid: pid = {}, status = 0x{:x}", r, status);
-      if (r != pid) {
-        if (r == -1 && errno != EINTR)
-          syserr("waitpid");
-      }
-      else if (WIFSTOPPED(status)) {
-        // Because the child is in its own PID namespace, it cannot
-        // stop us if it tries to suspend the process group.  Hence,
-        // detect if the child stopped and stop ourselves.
-        if (int sig = WSTOPSIG(status); sig == SIGSTOP || sig == SIGTSTP ||
-                                        sig == SIGTTIN || sig == SIGTTOU)
-          raise(sig);
-      }
-      else {
-        // unmount();
-        if (WIFEXITED(status))
-          exit(WEXITSTATUS(status));
-        if (WIFSIGNALED(status)) {
-          signal(WTERMSIG(status), SIG_DFL);
-          raise(WTERMSIG(status));
-        }
-        err("unknown child wait status 0x{:x}", status);
-      }
+    emulate_child(pid, false);
+  }
+
+  if (auto pid = xfork()) {
+    // This is the "init" process in the new PID namespace
+    prctl(PR_SET_PDEATHSIG, SIGKILL);
+    if (getppid() == 1) {
+      warn("parent killed before PR_SET_PDEATHSIG");
+      _exit(1);
     }
+    prctl(PR_SET_NAME, "jai-init");
+    emulate_child(pid, true);
   }
 
   try {
@@ -824,6 +845,10 @@ default: CMD.conf or default.conf if CMD.conf does not exist)",
       "FILE");
   (*opts)("--help", [] { usage(0); });
   (*opts)("--version", version, "Print copyright and version then exit");
+  (*opts)(
+      "--print-default-conf",
+      [] { write(1, default_conf.data(), default_conf.size()); },
+      "Show contents of the default configuration file");
   option_help = opts->help();
 
   std::vector<char *> cmd;