diff --git a/doc/66-boot.md b/doc/66-boot.md index e8cdd85ab7793f3becf3230b47c2b1a589667cb3..5477fb5dd20c69661e4875c21a486e8273ce69e8 100644 --- a/doc/66-boot.md +++ b/doc/66-boot.md @@ -90,7 +90,7 @@ In the unusual event that any of the above processes fail, *66-boot* will try to Skeleton files are mandatory and must exist on your system to be able to boot and shutdown the machine properly. By default those files are installed at `%%skel%%`. Use the `--with-skeleton=DIR` option at compile time to change it. -- `init` : the *66-boot* binary is not meant to be called directly or be linked to the binary directory because it takes command line options. Therefore the `init` skeleton file is used to pass any options to *66-boot. By default *66-boot* is launched with **-m** options. This file ***should be copied*** by the administrator into the binary directory of your system. +- `init` : the *66-boot* binary is not meant to be called directly or be linked to the binary directory because it takes command line options. Therefore the `init` skeleton file is used to pass any options to *66-boot. By default *66-boot* is launched without options. This file ***should be copied*** by the administrator into the binary directory of your system. - `init.conf` : this file contains a set of `key=value` pairs. ***All*** keys are mandatory where the name of the key ***must not*** be changed. This is the file available to a user to configure the boot process. By default: @@ -112,7 +112,7 @@ Skeleton files are mandatory and must exist on your system to be able to boot an * `RESCAN=0` : forces [s6-svscan](https://skarnet.org/software/s6/s6-svscan.html) to perform a scan every *RESCAN* milliseconds. This is an overload function mostly for debugging. It should be 0 during *stage1*. It is strongly discouraged to set *RESCAN* to a positive value smaller than 500. - * `ISHELL=%%skel%%/ishell` : an absolute path. Gets called in case *stage2* crashes. This file will try to run a *sulogin*. + * `ISHELL=%%skel%%/ishell` : an absolute path. Gets called in case *stage2* crashes if define by the administrator at the `rc.init` file. - `rc.init` : this file is called by the child of *66-boot* to process *stage2*. It invokes two commands: @@ -120,14 +120,12 @@ Skeleton files are mandatory and must exist on your system to be able to boot an * `66-dbctl -v${VERBOSITY} -l ${LIVE} -t ${TREE} -u` will bring up all `bundle` and `atomic` services inside of *TREE*. - * If any of these two commands fail the *ISHELL* file is called to provide the means for repair. + * If any of these two commands fail a warning message is sent to sdtout. It's the responsability of the administrator to call or not the `ishell` file. - `rc.shutdown` : this file is called at shudown when the administrator requests the `shutdown`, `halt`, `poweroff` or `reboot` command. It invokes a single command: * `66-all -v${VERBOSITY} -l ${LIVE} -t ${TREE} -f down` to bring down all *services* for all *trees* marked as enabled. - * `ishell` : this file is called by `rc.init` in case *stage2* crashes. It will try to run *sulogin* to provide a means of repair. - The following skeleton files are called to execute their corresponding power related functions and are safe wrappers that accept their corresponding command options. They **should be copied or symlinked** to the binary directory of the system. - `halt` : wraps [66-hpr -h](66-hpr.html). Terminates all processes and shuts down the CPU. @@ -137,3 +135,13 @@ The following skeleton files are called to execute their corresponding power rel - `reboot` : wraps [66-hpr -r](66-hpr.html). Terminates all processes and instructs a warm boot. - `shutdown` : wraps [66-shutdown](66-shutdown.html). Like `poweroff` but also runs scripts to bring the system down in a sane way including user notification. + +- `ishell` : this file will try to run *sulogin* to provide a means of repair. + +## Kernel command line + +Any valid `key=value` pair set at the `init.conf` skeleton file can be passed on the kernel command line as parameter: + +``` + BOOT_IMAGE=../vmlinuz-linux root=/dev/sda3 ro vga=895 initrd=../intel-ucode.img,../initramfs-linux.img TREE=boot +``` diff --git a/src/66/66-boot.c b/src/66/66-boot.c index 900468a26559e3c0e7750c3287adc25542cfc492..6f9f7d71d0f3afef3288015737b238e153bc63ec 100644 --- a/src/66/66-boot.c +++ b/src/66/66-boot.c @@ -56,6 +56,9 @@ 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" ; + +#define MAXBUF 1024*64*2 #define USAGE "66-boot [ -h ] [ -m ] [ -s skel ] [ -l log_user ] [ -e environment ] [ -d dev ] [ -b banner ]" @@ -95,6 +98,67 @@ static inline void info_help (void) if (buffer_putsflush(buffer_1, help) < 0) sulogin("","") ; } +static int read_line(stralloc *dst, char const *line) +{ + char b[MAXBUF] ; + int fd ; + unsigned int n = 0, m = MAXBUF ; + + fd = open(line, O_RDONLY) ; + if (fd == -1) return 0 ; + + for(;;) + { + ssize_t r = read(fd,b+n,m-n); + if (r == -1) + { + if (errno == EINTR) continue ; + break ; + } + n += r ; + // buffer is full + if (n == m) + { + --n ; + break ; + } + // end of file + if (r == 0) break ; + } + close(fd) ; + + if(n) + { + int i = n ; + // remove trailing zeroes + while (i && b[i-1] == '\0') --i ; + while (i--) + if (b[i] == '\n' || b[i] == '\0') b[i] = ' ' ; + + if (b[n-1] == ' ') b[n-1] = '\0' ; + } + b[n] = '\0'; + + if (!stralloc_cats(dst,b) || + !stralloc_0(dst)) sulogin("close stralloc",dst->s) ; + return n ; +} + +static int get_value(stralloc *val,char const *key) +{ + 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)) + { + log_warnu("get value of: ",key," -- keeps the default") ; + return 0 ; + } + if (!sastr_rebuild_in_oneline(val)) sulogin("rebuild line of value: ",val->s) ; + if (!stralloc_0(val)) sulogin("append stralloc of value: ",val->s) ; + + return 1 ; +} + static void parse_conf(void) { static char const *valid[] = @@ -102,6 +166,7 @@ static void parse_conf(void) int r ; unsigned int j = 0 ; stralloc src = STRALLOC_ZERO ; + stralloc cmdline = STRALLOC_ZERO ; stralloc val = STRALLOC_ZERO ; if (skel[0] != '/') sulogin("skeleton directory must be an aboslute path: ",skel) ; size_t skelen = strlen(skel) ; @@ -110,22 +175,38 @@ static void parse_conf(void) memcpy(confile + skelen + 1, SS_BOOT_CONF, SS_BOOT_CONF_LEN) ; confile[skelen + 1 + SS_BOOT_CONF_LEN] = 0 ; size_t filesize=file_get_size(confile) ; + /** skeleton file */ r = openreadfileclose(confile,&src,filesize) ; if(!r) sulogin("open configuration file: ",confile) ; if (!stralloc_0(&src)) sulogin("append stralloc of file: ",confile) ; - + + /** /proc/cmdline */ + if (!read_line(&cmdline,proc_cmdline)) { + /** we don't want to die here */ + log_warnu("read: ",proc_cmdline) ; + cmdline.len = 0 ; + } + if (!sastr_split_element_in_nline(&cmdline)) { + log_warnu("split: ",proc_cmdline) ; + cmdline.len = 0 ; + } for (char const *const *p = valid;*p;p++,j++) { - if (!stralloc_copy(&val,&src)) sulogin("copy stralloc of file: ",confile) ; - if (!environ_get_val_of_key(&val,*p)) continue ; - /** value may be empty, in this case we use the default one */ - if (!sastr_clean_element(&val)) - { - log_warnu("get value of: ",*p," -- keeps the default") ; - continue ; + /** try first to read from /proc/cmdline. + * If the key is not found, try to read the skeleton file. + * Finally keep the default value if we cannot get a correct + * key=value pair */ + if (cmdline.len > 0) { + if (!stralloc_copy(&val,&cmdline)) sulogin("copy stralloc of file: ",proc_cmdline) ; + } + else if (!stralloc_copy(&val,&src)) sulogin("copy stralloc of file: ",confile) ; + + if (!get_value(&val,*p) && cmdline.len > 0) + { + if (!stralloc_copy(&val,&src)) sulogin("copy stralloc of file: ",confile) ; + if (!get_value(&val,*p)) continue ; } - if (!sastr_rebuild_in_oneline(&val)) sulogin("rebuild line of value: ",val.s) ; - if (!stralloc_0(&val)) sulogin("append stralloc of value: ",val.s) ; + else continue ; switch (j) { @@ -156,6 +237,7 @@ static void parse_conf(void) } stralloc_free(&val) ; + stralloc_free(&cmdline) ; stralloc_free(&src) ; }