From 662532a0cf11ee73e855ac5cb668976da0542630 Mon Sep 17 00:00:00 2001
From: obarun <eric@obarun.org>
Date: Sat, 16 Jan 2021 16:10:09 +1100
Subject: [PATCH] add -z option. Pass new variable to rc.init file: CONTAINER,
 CATCHLOG, RCINIT_CONTAINER. Handle booting inside a container

---
 src/66/66-boot.c | 463 ++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 354 insertions(+), 109 deletions(-)

diff --git a/src/66/66-boot.c b/src/66/66-boot.c
index 39571d8e..e01a04e9 100644
--- a/src/66/66-boot.c
+++ b/src/66/66-boot.c
@@ -21,6 +21,11 @@
 #include <sys/mount.h>
 #include <sys/reboot.h>
 
+#ifdef __linux__
+    #include <linux/kd.h>
+    #include <skalibs/sig.h>
+#endif
+
 #include <oblibs/log.h>
 #include <oblibs/files.h>
 #include <oblibs/string.h>
@@ -38,46 +43,51 @@
 
 static mode_t mask = SS_BOOT_UMASK ;
 static unsigned int rescan = SS_BOOT_RESCAN ;
+static unsigned int container = SS_BOOT_CONTAINER ;
+static unsigned int catch_log = SS_BOOT_CATCH_LOG ;
 static char const *skel = SS_SKEL_DIR ;
 static char *live = SS_LIVE ;
 static char const *path = SS_BOOT_PATH ;
 static char const *tree = SS_BOOT_TREE ;
 static char const *rcinit = SS_SKEL_DIR SS_BOOT_RCINIT ;
+static char const *rcinit_container = SS_SKEL_DIR SS_BOOT_RCINIT_CONTAINER ;
 static char const *banner = "\n[Starts stage1 process...]" ;
 static char const *slashdev = 0 ;
 static char const *envdir = 0 ;
 static char const *fifo = 0 ;
 static char const *log_user = SS_LOGGER_RUNNER ;
 static char const *cver = 0 ;
-static char tpath[MAXENV+1] ;
-static char trcinit[MAXENV+1] ;
-static char tlive[MAXENV+1] ;
-static char ttree[MAXENV+1] ;
-static char confile[MAXENV+1] ;
+static char tpath[MAXENV + 1] ;
+static char trcinit[MAXENV + 1] ;
+static char trcinit_container[MAXENV + 1] ;
+static char tlive[MAXENV + 1] ;
+static char ttree[MAXENV + 1] ;
+static char confile[MAXENV + 1] ;
 static char const *const *genv = 0 ;
 static int fdin ;
 static char const *proc_cmdline="/proc/cmdline" ;
 static stralloc sacmdline = STRALLOC_ZERO ;
+static int notifpipe[2] ;
 
 #define MAXBUF 1024*64*2
 
-#define USAGE "66-boot [ -h ] [ -m ] [ -s skel ] [ -l log_user ] [ -e environment ] [ -d dev ] [ -b banner ]"
+#define USAGE "66-boot [ -h ] [ -z ] [ -m ] [ -s skel ] [ -l log_user ] [ -e environment ] [ -d dev ] [ -b banner ]"
 
 static void sulogin(char const *msg,char const *arg)
 {
     static char const *const newarg[2] = { SS_EXTBINPREFIX "sulogin" , 0 } ;
     pid_t pid ;
     int wstat ;
-    fd_close(0) ;
+    close(0) ;
     if (dup2(fdin,0) == -1) log_dieu(LOG_EXIT_SYS,"duplicate stdin -- you are on your own") ;
-    fd_close(fdin) ;
+    close(fdin) ;
     if (*msg) log_warnu(msg,arg) ;
     pid = child_spawn0(newarg[0],newarg,genv) ;
     if (waitpid_nointr(pid,&wstat, 0) < 0)
             log_dieusys(LOG_EXIT_SYS,"wait for sulogin -- you are on your own") ;
     fdin=dup(0) ;
     if (fdin == -1) log_dieu(LOG_EXIT_SYS,"duplicate stdin -- you are on your own") ;
-    fd_close(0) ;
+    close(0) ;
     if (open("/dev/null",O_WRONLY)) log_dieu(LOG_EXIT_SYS,"open /dev/null -- you are on your own") ;
 }
 
@@ -88,9 +98,10 @@ static inline void info_help (void)
 "\n"
 "options :\n"
 "   -h: print this help\n"
+"   -z: use color\n"
 "   -m: mount parent live directory\n"
-"   -l: run catch-all logger as log_user user\n"
 "   -s: skeleton directory\n"
+"   -l: run catch-all logger as log_user user\n"
 "   -e: environment directory or file\n"
 "   -d: dev directory\n"
 "   -b: banner to display\n"
@@ -149,8 +160,6 @@ static int read_line(stralloc *dst, char const *line)
 
 static int get_value(stralloc *val,char const *key)
 {
-    log_flow() ;
-
     if (!environ_get_val_of_key(val,key)) return 0 ;
     /** value may be empty, in this case we use the default one */
     if (!sastr_clean_element(val))
@@ -164,12 +173,33 @@ static int get_value(stralloc *val,char const *key)
     return 1 ;
 }
 
+static inline void string_to_table(char *table,char const *pointer,char const *str, uint8_t empty)
+{
+    log_flow() ;
+
+    if (!empty) {
+        auto_strings(table,str) ;
+        pointer = table ;
+    }
+}
+
+static inline uint8_t string_to_uint(char const *str, unsigned int *ui, uint8_t empty)
+{
+    log_flow() ;
+
+    if (!empty)
+        if (!uint0_oscan(str,ui))
+            return 0 ;
+
+    return 1 ;
+}
+
 static void parse_conf(void)
 {
     log_flow() ;
 
     static char const *valid[] =
-    { "VERBOSITY", "PATH", "LIVE", "TREE", "RCINIT", "UMASK", "RESCAN", 0 } ;
+    { "VERBOSITY", "PATH", "LIVE", "TREE", "RCINIT", "UMASK", "RESCAN", "CONTAINER", "CATCHLOG", "RCINIT_CONTAINER", 0 } ;
     int r ;
     unsigned int j = 0 ;
     uint8_t empty = 0 ;
@@ -222,71 +252,148 @@ static void parse_conf(void)
 
         switch (j)
         {
-            case 0: if (!empty)
-                        if (!uint0_scan(val.s, &VERBOSITY)) sulogin("parse VERBOSITY value: ",val.s) ;
-
-                    u[uint_fmt(u, VERBOSITY)] = 0 ;
-                    if (!auto_stra(&sacmdline,"VERBOSITY=",u,"\n"))
-                        sulogin("append environment stralloc with key: VERBOSITY=",u) ;
-                    break ;
-            case 1: if (!empty) {
-                        memcpy(tpath,val.s,val.len) ;
-                        tpath[val.len] = 0 ;
-                        path = tpath ;
-                    }
-                    if (!auto_stra(&sacmdline,"PATH=",path,"\n"))
-                        sulogin("append environment stralloc with key: PATH=",path) ;
-                    break ;
-            case 2: if (!empty) {
-                        memcpy(tlive,val.s,val.len) ;
-                        tlive[val.len] = 0 ;
-                        live = tlive ;
-                        if (live[0] != '/') sulogin ("LIVE must be an absolute path",val.s) ;
-                    }
-                    if (!auto_stra(&sacmdline,"LIVE=",live,"\n"))
-                        sulogin("append environment stralloc with key: LIVE=",live) ;
-                    break ;
-            case 3: if (!empty) {
-                        memcpy(ttree,val.s,val.len) ;
-                        ttree[val.len] = 0 ;
-                        tree = ttree ;
-                    }
-                    if (!auto_stra(&sacmdline,"TREE=",tree,"\n"))
-                        sulogin("append environment stralloc with key: TREE=",tree) ;
-                    break ;
-            case 4: if (!empty) {
-                        memcpy(trcinit,val.s,val.len) ;
-                        trcinit[val.len] = 0 ;
-                        rcinit = trcinit ;
-                        if (rcinit[0] != '/') sulogin ("RCINIT must be an absolute path: ",val.s) ;
-                    }
-                    if (!auto_stra(&sacmdline,"RCINIT=",rcinit,"\n"))
-                        sulogin("append environment stralloc with key: RCINIT=",rcinit) ;
-                    break ;
-            case 5: if (!empty)
-                        if (!uint0_oscan(val.s, &mask)) sulogin("invalid UMASK value: ",val.s) ;
-
-                    u[uint_fmt(u, mask)] = 0 ;
-                    if (!auto_stra(&sacmdline,"UMASK=",u,"\n"))
-                        sulogin("append environment stralloc with key: UMASK=",u) ;
-                    break ;
-            case 6: if (!empty)
-                        if (!uint0_scan(val.s, &rescan)) sulogin("invalid RESCAN value: ",val.s) ;
-
-                    u[uint_fmt(u, rescan)] = 0 ;
-                    if (!auto_stra(&sacmdline,"RESCAN=",u,"\n"))
-                            sulogin("append environment stralloc with key: RESCAN=",u) ;
-                    break ;
+            case 0:
+
+                if (!string_to_uint(val.s,&VERBOSITY,empty))
+                    sulogin("parse VERBOSITY value: ",val.s) ;
+
+                u[uint_fmt(u, VERBOSITY)] = 0 ;
+                if (!auto_stra(&sacmdline,"VERBOSITY=",u,"\n"))
+                    sulogin("append environment stralloc with key: VERBOSITY=",u) ;
+                break ;
+
+            case 1:
+
+                string_to_table(tpath,path,val.s,empty) ;
+
+                if (!auto_stra(&sacmdline,"PATH=",path,"\n"))
+                    sulogin("append environment stralloc with key: PATH=",path) ;
+                break ;
+
+            case 2:
+
+                string_to_table(tlive,live,val.s,empty) ;
+
+                if (live[0] != '/')
+                    sulogin ("LIVE must be an absolute path",live) ;
+
+                if (!auto_stra(&sacmdline,"LIVE=",live,"\n"))
+                    sulogin("append environment stralloc with key: LIVE=",live) ;
+                break ;
+
+            case 3:
+
+                string_to_table(ttree,tree,val.s,empty) ;
+
+                if (!auto_stra(&sacmdline,"TREE=",tree,"\n"))
+                    sulogin("append environment stralloc with key: TREE=",tree) ;
+                break ;
+
+            case 4:
+
+                string_to_table(trcinit,rcinit,val.s,empty) ;
+
+                if (rcinit[0] != '/')
+                    sulogin ("RCINIT must be an absolute path: ",rcinit) ;
+
+                if (!auto_stra(&sacmdline,"RCINIT=",rcinit,"\n"))
+                    sulogin("append environment stralloc with key: RCINIT=",rcinit) ;
+                break ;
+
+            case 5:
+
+                if (!string_to_uint(val.s,&mask,empty))
+                    sulogin("invalid UMASK value: ",val.s) ;
+
+                u[uint_fmt(u, mask)] = 0 ;
+                if (!auto_stra(&sacmdline,"UMASK=",u,"\n"))
+                    sulogin("append environment stralloc with key: UMASK=",u) ;
+                break ;
+
+            case 6:
+
+                if (!string_to_uint(val.s,&rescan,empty))
+                    sulogin("invalid RESCAN value: ",val.s) ;
+
+                u[uint_fmt(u, rescan)] = 0 ;
+                if (!auto_stra(&sacmdline,"RESCAN=",u,"\n"))
+                    sulogin("append environment stralloc with key: RESCAN=",u) ;
+                break ;
+
+            case 7:
+
+                if (!string_to_uint(val.s,&container,empty))
+                    sulogin("invalid CONTAINER value: ",val.s) ;
+
+                u[uint_fmt(u,container)] = 0 ;
+                if (!auto_stra(&sacmdline,"CONTAINER=",u,"\n"))
+                    sulogin("append environment stralloc with key: CONTAINER=",u) ;
+
+                break ;
+
+            case 8:
+
+                if (!string_to_uint(val.s,&catch_log,empty))
+                    sulogin("invalid CATCHLOG value: ",val.s) ;
+
+                u[uint_fmt(u,catch_log)] = 0 ;
+                if (!auto_stra(&sacmdline,"CATCHLOG=",u,"\n"))
+                    sulogin("append environment stralloc with key: CATCHLOG=",u) ;
+                break ;
+
+            case 9:
+
+                string_to_table(trcinit_container,rcinit_container,val.s,empty) ;
+
+                if (rcinit_container[0] != '/')
+                    sulogin ("RCINIT_CONTAINER must be an absolute path: ",rcinit_container) ;
+
+                if (!auto_stra(&sacmdline,"RCINIT_CONTAINER=",rcinit_container,"\n"))
+                    sulogin("append environment stralloc with key: RCINIT_CONTAINER=",rcinit_container) ;
+                break ;
+
             default: break ;
         }
 
     }
+    if (container) {
+        if (!auto_stra(&sacmdline,"CONTAINER_HALTCMD=",live,SS_BOOT_CONTAINER_DIR,"/0/",SS_BOOT_CONTAINER_HALTCMD,"\n")) {
+            char tmp[strlen(live) + SS_BOOT_CONTAINER_DIR_LEN + 1 + SS_BOOT_CONTAINER_HALTCMD_LEN +1] ;
+            auto_strings(tmp,live,SS_BOOT_CONTAINER_DIR,"/",SS_BOOT_CONTAINER_HALTCMD) ;
+            sulogin("append environment stralloc with key: CONTAINER_HALTCMD=",tmp) ;
+        }
+    }
+
     if (!sastr_split_string_in_nline(&sacmdline)) sulogin("split string: ",sacmdline.s) ;
+
     stralloc_free(&val) ;
     stralloc_free(&cmdline) ;
     stralloc_free(&src) ;
 }
 
+static inline void wait_for_notif (int fd)
+{
+    log_flow() ;
+
+    char buf[16] ;
+    for (;;) {
+
+        ssize_t r = read(fd, buf, 16) ;
+        if (r < 0)
+            sulogin("read from notification pipe","") ;
+
+        if (!r) {
+          log_warn("s6-svscan failed to send a notification byte!") ;
+          break ;
+        }
+
+        if (memchr(buf, '\n', r))
+            break ;
+    }
+
+    close(fd) ;
+}
+
 static int is_mnt(char const *str)
 {
     log_flow() ;
@@ -323,22 +430,46 @@ static inline void run_stage2 (char const *const *envp, size_t envlen, char cons
     log_flow() ;
 
     size_t pos = 0 ;
-    char const *newargv[3] = { rcinit, confile, 0 } ;
+    char const *newargv[3] ;
+
+    if (container) {
+        newargv[0]= rcinit_container ;
+
+    } else {
+
+        newargv[0] = rcinit ;
+    }
+
+    newargv[1] = confile ;
+    newargv[2] = 0 ;
+
     setsid() ;
-    fd_close(1) ;
-    if (open(fifo, O_WRONLY) != 1)  /* blocks until catch-all logger is up */
-        sulogin("open for writing fifo: ",fifo) ;
-    if (fd_copy(2, 1) == -1)
-        sulogin("copy stderr to stdout","") ;
-    fd_close(fdin) ;
+
+    if (catch_log) {
+
+        close(notifpipe[1]) ;
+        wait_for_notif(notifpipe[0]) ;
+    }
+    else {
+
+        close(1) ;
+        if (open(fifo, O_WRONLY) != 1)  /* blocks until catch-all logger is up */
+            sulogin("open for writing fifo: ",fifo) ;
+        if (fd_copy(2, 1) == -1)
+            sulogin("copy stderr to stdout","") ;
+    }
+
+    close(fdin) ;
+
     for (;pos < modiflen ; pos += strlen(modifs + pos) +1)
         if (!stralloc_catb(&sacmdline,modifs + pos, strlen(modifs + pos) + 1))
             sulogin("append environment stralloc with value: ",modifs + pos) ;
+
     size_t tlen = sacmdline.len ;
     char t[tlen + 1] ;
-    memcpy(t,sacmdline.s,tlen) ;
-    t[tlen] = 0 ;
+    auto_strings(t,sacmdline.s) ;
     stralloc_free(&sacmdline) ;
+    //xmexec_fm(newargv, envp, envlen, t, tlen) ;
     xpathexec_r(newargv, envp, envlen, t, tlen) ;
 }
 
@@ -371,29 +502,60 @@ static inline void make_cmdline(char const *prog,char const **add,int len,char c
     run_cmdline(newargv,envp,msg,arg) ;
 }
 
+static void cad(void)
+{
+    log_flow() ;
+
+    if (container)
+        return ;
+
+#ifdef __linux__
+    int fd ;
+    fd = open("/dev/tty0", O_RDONLY | O_NOCTTY) ;
+    if (fd < 0) {
+        log_warnusys("open /dev/", "tty0 (kbrequest will not be handled)") ;
+    }
+    else {
+
+        if (ioctl(fd, KDSIGACCEPT, SIGWINCH) < 0)
+            log_warnusys("ioctl KDSIGACCEPT on tty0 (kbrequest will not be handled)") ;
+        close(fd) ;
+    }
+
+    sig_block(SIGINT) ; /* don't panic on early cad before s6-svscan catches it */
+#endif
+
+    if (reboot(RB_DISABLE_CAD) == -1)
+        log_warnusys("trap ctrl-alt-del") ;
+
+}
+
 int main(int argc, char const *const *argv,char const *const *envp)
 {
     VERBOSITY = 0 ;
-    unsigned int r , tmpfs = 0 ;
+    unsigned int r , tmpfs = 0, opened = 0 ;
     size_t bannerlen, livelen ;
     pid_t pid ;
-    int opened = 0 ;
     char verbo[UINT_FMT] ;
     cver = verbo ;
     stralloc envmodifs = STRALLOC_ZERO ;
     genv = envp ;
+
+    log_color = &log_color_disable ;
+
     PROG = "66-boot" ;
     {
         subgetopt_t l = SUBGETOPT_ZERO ;
 
         for (;;)
         {
-            int opt = getopt_args(argc,argv, ">hms:e:d:b:l:", &l) ;
+            int opt = getopt_args(argc,argv, ">hzms:e:d:b:l:", &l) ;
             if (opt == -1) break ;
             if (opt == -2) sulogin("options must be set first","") ;
             switch (opt)
             {
                 case 'h' : info_help(); return 0 ;
+                case 'z' : log_color = !isatty(1) ? &log_color_disable : &log_color_enable ; break ;
                 case 'm' : tmpfs = 1 ; break ;
                 case 's' : skel = l.arg ; break ;
                 case 'e' : envdir = l.arg ; break ;
@@ -416,33 +578,69 @@ int main(int argc, char const *const *argv,char const *const *envp)
     bannerlen = strlen(banner) ;
     livelen = strlen(live) ;
     char tfifo[livelen + 1 + SS_BOOT_LOGFIFO_LEN + 1] ;
-    memcpy(tfifo,live,livelen) ;
-    tfifo[livelen] = '/' ;
-    memcpy(tfifo + livelen + 1,SS_BOOT_LOGFIFO,SS_BOOT_LOGFIFO_LEN) ;
-    tfifo[livelen + 1 + SS_BOOT_LOGFIFO_LEN] = 0 ;
+    auto_strings(tfifo,live,"/",SS_BOOT_LOGFIFO) ;
     fifo = tfifo ;
 
-    allwrite(1, banner, bannerlen) ;
-    allwrite(1, "\n", 2) ;
+    if (container) {
+        /* If there's a Docker synchronization pipe, wait on it */
+        char c ;
+        ssize_t r = read(3, &c, 1) ;
+        if (r < 0) {
+
+          if (errno != EBADF)
+            sulogin("read from fd 3","") ;
+
+        } else {
+
+          if (r)
+            log_warn("parent wrote to fd 3!") ;
+
+          close(3) ;
+        }
+    } else {
+
+        allwrite(1, banner, bannerlen) ;
+        allwrite(1, "\n", 2) ;
+    }
+
     if (chdir("/") == -1) sulogin("chdir to ","/") ;
     umask(mask) ;
     setpgid(0, 0) ;
-    fd_close(0) ;
+    close(0) ;
+
+    if (container && slashdev)
+        log_1_warn("-d options asked for a boot inside a container; are you sure your container does not come with a pre-mounted /dev?") ;
 
     if (slashdev)
     {
         log_info("Mount: ",slashdev) ;
-        fd_close(1) ;
-        fd_close(2) ;
+        close(1) ;
+        close(2) ;
         if (mount("dev", slashdev, "devtmpfs", MS_NOSUID | MS_NOEXEC, "") == -1)
             { opened++ ; sulogin ("mount: ", slashdev) ; }
 
         if (open("/dev/console", O_WRONLY) ||
-        fd_copy(1, 0) == -1 ||
-        fd_move(2, 0) == -1) return 111 ;
+        fd_move(2, 0) == -1 ||
+        fd_copy(1, 2) == -1) return 111 ;
+    }
+
+    if (!opened) {
+
+        if (open("/dev/null", O_RDONLY)) {
+
+            /* ghetto /dev/null to the rescue */
+            int p[2] ;
+            log_1_warnusys("open /dev/null") ;
+
+            if (pipe(p) < 0)
+                sulogin("pipe for /dev/null","") ;
+
+            close(p[1]) ;
+
+            if (fd_move(0, p[0]) < 0)
+                sulogin("fd_move to stdin","") ;
+        }
     }
-    if (!opened)
-        if (open("/dev/null", O_RDONLY)) sulogin("open: ", "/dev/null") ;
 
     char fs[livelen + 1] ;
     split_tmpfs(fs,live) ;
@@ -463,9 +661,27 @@ int main(int argc, char const *const *argv,char const *const *envp)
     if (setenv("PATH", path, 1) == -1) sulogin("set initial PATH: ",path) ;
     /** create scandir */
     {
-        char const *t[] = { "-b", "-c", "-s", skel, "-L", log_user } ;
+        size_t nargc = 6 + catch_log ;
+        unsigned int m = 0 ;
+
+        char const *t[nargc] ;
+
+        if (container) {
+            t[m++] = "-B" ;
+        } else {
+            t[m++] = "-b" ;
+        }
+
+        if (!catch_log)
+            t[m++] = "-c" ;
+
+        t[m++] = "-s" ;
+        t[m++] = skel ;
+        t[m++] = "-L" ;
+        t[m++] = log_user ;
+        t[m++] = "create" ;
         log_info("Create live scandir at: ",live) ;
-        make_cmdline(SS_EXTBINPREFIX "66-scandir",t,6,"create live scandir at: ",live,envp) ;
+        make_cmdline(SS_EXTBINPREFIX "66-scandir",t,nargc,"create live scandir at: ",live,envp) ;
     }
     /** initiate earlier service */
     {
@@ -480,6 +696,7 @@ int main(int argc, char const *const *argv,char const *const *envp)
         if (!sastr_split_string_in_nline(&envmodifs)) sulogin("rebuild environment: ",envdir) ;
     }
 
+    if (catch_log)
     {
         log_info("Starts boot logger at: ",live,"/log/0") ;
         int fdr = open_read(fifo) ;
@@ -491,26 +708,54 @@ int main(int argc, char const *const *argv,char const *const *envp)
 
     /** fork and starts scandir */
     {
-        static char const *newargv[7] ;
-        newargv[0] = SS_EXTBINPREFIX "66-scandir" ;
-        newargv[1] = "-v" ;
-        newargv[2] = verbo ;
-        newargv[3] = "-l" ;
-        newargv[4] = live ;
-        newargv[5] = "-u" ;
-        newargv[6] = 0 ;
-        char const *newenvp[2] = { 0, 0 } ;
         size_t pathlen = strlen(path) ;
+        char const *newenvp[2] = { 0, 0 } ;
         char pathvar[6 + pathlen] ;
+        char fmtfd[2 + UINT_FMT] = "-" ;
+
+        size_t m = 0 ;
+        static char const *newargv[7] ;
+        newargv[m++] = SS_EXTBINPREFIX "66-scanctl" ;
+        newargv[m++] = "-v0" ;
+        if (!catch_log)
+            newargv[m++] = fmtfd ;
+        newargv[m++] = "-l" ;
+        newargv[m++] = live ;
+        newargv[m++] = "start" ;
+        newargv[m++] = 0 ;
+
         memcpy(pathvar, "PATH=", 5) ;
         memcpy(pathvar + 5, path, pathlen + 1) ;
+
         newenvp[0] = pathvar ;
+
+        if (!catch_log && pipe(notifpipe) < 0)
+            sulogin("pipe","") ;
+
         pid = fork() ;
-        if (pid == -1) sulogin("fork: ",rcinit) ;
-        if (!pid) run_stage2(newenvp, 1, envmodifs.s,envmodifs.len) ;
-        if (reboot(RB_DISABLE_CAD) == -1) log_warnusys("trap ctrl-alt-del") ;
-        if (fd_copy(2, 1) == -1) sulogin("copy stderr to stdout","") ;
-        fd_close(fdin) ;
+
+        if (pid == -1)
+            sulogin("fork: ",container ? rcinit_container : rcinit) ;
+
+        if (!pid)
+            run_stage2(newenvp, 1, envmodifs.s,envmodifs.len) ;
+
+        if (!catch_log) {
+
+            close(notifpipe[0]) ;
+            fmtfd[1] = 'd' ;
+            fmtfd[2 + uint_fmt(fmtfd + 2, notifpipe[1])] = 0 ;
+            cad() ;
+
+        } else {
+
+            cad() ;
+            if (fd_copy(2, 1) == -1)
+                sulogin("copy stderr to stdout","") ;
+        }
+
+        close(fdin) ;
+       // xmexec_fm(newargv, newenvp, 1, envmodifs.s, envmodifs.len) ;
         xpathexec_r(newargv, newenvp, 1, envmodifs.s, envmodifs.len) ;
     }
 }
-- 
GitLab