Repositories / jai.git

jai.git

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

Branch

allow --init but don't require it

Author
David Mazieres <dm@uun.org>
Date
2026-03-24 17:02:04 -0700
Commit
414566d68bf0c5b419f357833d7e42ad20027364
fs.cc
index 773c6fd..2fa3aed 100644
--- a/fs.cc
+++ b/fs.cc
@@ -437,15 +437,13 @@ try_read_file(int dfd, path file)
 
 Fd
 ensure_file(int dfd, path file, std::string_view contents, int mode,
-            bool *created)
+            std::function<void(int)> createcb)
 {
   assert(!file.empty());
 
   if (Fd fd = openat(dfd, file.c_str(), O_RDONLY | O_CLOEXEC)) {
     if (!S_ISREG(xfstat(*fd).st_mode))
       err("{}: not a regular file", fdpath(dfd, file));
-    if (created)
-      *created = false;
     return fd;
   }
   if (errno != ENOENT)
@@ -469,8 +467,8 @@ ensure_file(int dfd, path file, std::string_view contents, int mode,
     syserr(R"(rename("{}" -> "{}") in "{}")", tmp.string(), file.string(),
            fdpath(*fd));
   cleanup.release();
-  if (created)
-    *created = true;
-  fd.reset();                   // have to reopen for reading
-  return xopenat(dfd, file.c_str(), O_RDONLY | O_CLOEXEC);
+  // have to reopen for reading
+  fd = xopenat(dfd, file.c_str(), O_RDONLY | O_CLOEXEC);
+  createcb(*fd);
+  return fd;
 }
fs.h
index 2d4c24a..768df5a 100644
--- a/fs.h
+++ b/fs.h
@@ -295,8 +295,15 @@ read_file(int dfd, path file = {})
     throw res.error();
 }
 
-Fd ensure_file(int dfd, path file, std::string_view contents, int mode = 0600,
-               bool *created = nullptr);
+inline void
+create_warn(int fd)
+{
+  warn("created {}", fdpath(fd));
+}
+
+Fd ensure_file(
+    int dfd, path file, std::string_view contents, int mode = 0600,
+    std::function<void(int)> createcb = [](int) {});
 
 using ACL = RaiiHelper<acl_free, acl_t>;
 
jai.1.md
index 2173eaa..ee9decf 100644
--- a/jai.1.md
+++ b/jai.1.md
@@ -206,8 +206,8 @@ opencode`):
 # OPTIONS
 
 `--init`
-: Create default configuration files and exit.  You should run this
-  first, before activating any jails.
+: Create default configuration files and exit.  Gives you a chance to
+  edit the default configuration files before creating any jails.
 
 `-C` *file*, `--conf` *file*
 : Specifies the configuration file to read.  If *file* does not
jai.cc
index 9031f09..624cbe3 100644
--- a/jai.cc
+++ b/jai.cc
@@ -1147,13 +1147,19 @@ The default is CMD.conf if it exists, otherwise default.conf)",
   if (!conf.mask_files_.empty())
     conf.mask_warn_ = true;
 
-  ensure_file(conf.home_jai(opt_init), ".defaults", jai_defaults, 0600);
-  ensure_file(conf.home_jai(), "default.conf", default_conf, 0600);
+  // true instead of opt_init, just so it works by default.
+  ensure_file(conf.home_jai(true), ".defaults", jai_defaults, 0600,
+              create_warn);
+  ensure_file(conf.home_jai(), "default.conf", default_conf, 0600, create_warn);
 
   if (opt_init) {
-    ensure_file(conf.storage(), "default.jail", default_jail, 0600);
-    std::println("You can edit the configuration defaults in {}/.defaults",
+    ensure_file(conf.storage(), "default.jail", default_jail, 0600,
+                create_warn);
+    std::println("You can edit the configuration defaults in {}/.defaults.",
                  conf.homejaipath_.string());
+    std::println(
+        "Run {} --print-defaults to see the original contents of that file.",
+        prog.filename().string());
     exit(0);
   }
 
@@ -1186,10 +1192,7 @@ The default is CMD.conf if it exists, otherwise default.conf)",
                            conf.sandbox_name_ == "default"
                                ? default_jail
                                : std::format("mode {}\n", conf.mode_),
-                           0600, &createwarn);
-
-  if (createwarn)
-    warn("created {}", fdpath(*dotjail));
+                           0600, create_warn);
   conf.parse_config_fd(*dotjail, conf.opt_parser(true).get());
 
   // Re-parse command line to override files