On Tue, Jan 31, 2017 at 09:35:55PM +0000, Laurent Bercot wrote: > It won't do it in every case: parsing /proc/cmdline is hazardous and > much more difficult than it appears. (There could be quotes, and quoted > spaces, in the elements.) We had a discussion about this on the Alpine > development IRC channel, and it appeared that you can't do it safely > with less than 50 lines of shell.
Perhaps more than 50 lines if you insist on use sh(1) because of the usage of `eval' to set up dynamically-named variables, eg.: > eval "${opt%%=*}='${opt#*=}'" which, for opt="a=b' dont-rm -rf /'", becomes > a='b' dont-rm -rf /'' However, the code can be very simple if you use a shell that does not forbid "$key=val", and restrict the kernel command line as a space-separated list of strings in the `key[=val1,val2,...]' form, where `key's are valid shell variable names, and `val's are strings of non-whitespace non-comma printable characters. Here's an example written in rc(1) (the Byron Rakitzis implementation): > for (opt in `{cat /proc/cmdline}) { > if (~ $opt *'='*) { > key=`{echo $opt | sed 's/=.*$//'} > KOPT_$key=`{echo $opt | sed 's/^[^=]*=//; s/,/ /g'} > } else if (~ $opt no*) { > KOPT_`{echo $opt | sed 's/^no//'}=no > } else KOPT_$opt=yes > } > The simplest solution, if you control the kernel command line, is to > duplicate the root= argument with something the kernel will let through: > The kernel keeps the "root" argument, but puts "rootfs" in the > environment, which you can easily read from. >From those distros I have used, it seems that the kernel does not eat anything from its command line, so I think it is unnecessary to duplicate the `rootfs' parameter. > Once it has all the information it needs and has found its rootfs, the > initramfs script doesn't need environment variables anymore, so it > cleans up its environment. You should do the same: be as transparent as > possible, do not leak into /sbin/init anything it doesn't strictly need. > /sbin/init may have the environment variables set by the kernel, but it > definitely shouldn't have any variables set by your initramfs script. In addition, the cause for `KOPT_*' not showing up in Alpine init is that sh(1) does not leak manually set variables except when told to `export'. In contrast, rc(1) does not have the `export' builtin, and simply exports all variables. Anyway, you can use the following chainloading command to clean up the environment just before switching root: > /bin/busybox env -i [key1=val1 key2=val2 ...] \ > /bin/busybox switch_root $root $init -- My current OpenPGP key: RSA4096/0x227E8CAAB7AA186C (expires: 2020.10.19) 7077 7781 B859 5166 AE07 0286 227E 8CAA B7AA 186C