diff --git a/src/66/66-boot.c b/src/66/66-boot.c index 39571d8e1fccd48f3ecf13f1fe645443dd6f95ac..e01a04e9eaffe68e2d64c82e2a845eea3e4f9933 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) ; } }