Re: Init.c, making it chroot
In message: <[EMAIL PROTECTED]> Oliver Fromme <[EMAIL PROTECTED]> writes: : : John Baldwin wrote: : > On Saturday 06 January 2007 14:27, Oliver Fromme wrote: : > > M. Warner Losh wrote: : > > > Also, kenv(KENV_GET, ... is used a lot. Maybe it makes sense to have : > > > a simple kenvget call. Would make a few lines a little shorter if : > > > nothing else. : > > : > > KENV_GET is used three times. Using a wrapper function : > > would save 7 characters per call. I don't think it's : > > really worth it. But if you insist, I can update the : > > patch with such a function. : > : > I think just using kenv() is fine. : : OK, so how do we proceed now? : Should I submit a PR containing the patch? Send me the final patch as an attachment to an email, and I'll make sure it gets committed. Warner : I'm also willing to write a bit of documentation for the : new init_* kenv variables, but I'm not sure where to put : it. The existing init_path variable is documented in : loader(8), so maybe it should go there? Also there should : be sample entries in /boot/defaults/loader.conf, of course, : like this: Both ideas are good. : --- loader.conf.orig Mon Jan 8 20:45:23 2007 : +++ loader.conf Mon Jan 8 20:47:48 2007 : @@ -77,6 +77,9 @@ : #boot_verbose="" # -v: Causes extra debugging information to be printed : #init_path="/sbin/init:/sbin/oinit:/sbin/init.bak:/rescue/init:/stand/sysinstall" : # Sets the list of init candidates : +#init_shell="/bin/sh"# The shell binary used by init(8). : +#init_shript="" # Initial script to run by init(8) before chrooting. : +#init_chroot="" # Directory for init(8) to chroot into. : : : ## : : By the way, I just verified in the CVS repository that the : init.c code is identical in HEAD (1.62) and in RELENG_6 : (1.60.2.2). Therefore the patch should apply cleanly to : both HEAD and RELENG_6. Excellent! I look forward to it. BTW, if you have other patches/PRs, please contact me privately and I'll review/commit them. Warner : Best regards :Oliver : : -- : Oliver Fromme, secnetix GmbH & Co. KG, Marktplatz 29, 85567 Grafing : Dienstleistungen mit Schwerpunkt FreeBSD: http://www.secnetix.de/bsd : Any opinions expressed in this message may be personal to the author : and may not necessarily reflect the opinions of secnetix in any way. : : 'Instead of asking why a piece of software is using "1970s technology," : start asking why software is ignoring 30 years of accumulated wisdom.' : : ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "[EMAIL PROTECTED]"
Re: Init.c, making it chroot
John Baldwin wrote: > On Saturday 06 January 2007 14:27, Oliver Fromme wrote: > > M. Warner Losh wrote: > > > Also, kenv(KENV_GET, ... is used a lot. Maybe it makes sense to have > > > a simple kenvget call. Would make a few lines a little shorter if > > > nothing else. > > > > KENV_GET is used three times. Using a wrapper function > > would save 7 characters per call. I don't think it's > > really worth it. But if you insist, I can update the > > patch with such a function. > > I think just using kenv() is fine. OK, so how do we proceed now? Should I submit a PR containing the patch? I'm also willing to write a bit of documentation for the new init_* kenv variables, but I'm not sure where to put it. The existing init_path variable is documented in loader(8), so maybe it should go there? Also there should be sample entries in /boot/defaults/loader.conf, of course, like this: --- loader.conf.origMon Jan 8 20:45:23 2007 +++ loader.conf Mon Jan 8 20:47:48 2007 @@ -77,6 +77,9 @@ #boot_verbose="" # -v: Causes extra debugging information to be printed #init_path="/sbin/init:/sbin/oinit:/sbin/init.bak:/rescue/init:/stand/sysinstall" # Sets the list of init candidates +#init_shell="/bin/sh" # The shell binary used by init(8). +#init_shript=""# Initial script to run by init(8) before chrooting. +#init_chroot=""# Directory for init(8) to chroot into. ## By the way, I just verified in the CVS repository that the init.c code is identical in HEAD (1.62) and in RELENG_6 (1.60.2.2). Therefore the patch should apply cleanly to both HEAD and RELENG_6. Best regards Oliver -- Oliver Fromme, secnetix GmbH & Co. KG, Marktplatz 29, 85567 Grafing Dienstleistungen mit Schwerpunkt FreeBSD: http://www.secnetix.de/bsd Any opinions expressed in this message may be personal to the author and may not necessarily reflect the opinions of secnetix in any way. 'Instead of asking why a piece of software is using "1970s technology," start asking why software is ignoring 30 years of accumulated wisdom.' ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "[EMAIL PROTECTED]"
Re: Init.c, making it chroot
On Saturday 06 January 2007 14:27, Oliver Fromme wrote: > M. Warner Losh wrote: > > Also, kenv(KENV_GET, ... is used a lot. Maybe it makes sense to have > > a simple kenvget call. Would make a few lines a little shorter if > > nothing else. > > KENV_GET is used three times. Using a wrapper function > would save 7 characters per call. I don't think it's > really worth it. But if you insist, I can update the > patch with such a function. I think just using kenv() is fine. -- John Baldwin ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "[EMAIL PROTECTED]"
Re: Init.c, making it chroot
M. Warner Losh wrote: > > this patch looks good, however, one nit: > > In message: <[EMAIL PROTECTED]> > Oliver Fromme <[EMAIL PROTECTED]> writes: > : + if (stat("/dev", &stst) != 0) > : + warning("Can't stat /dev: %m"); > : + else { > : + if (stst.st_dev == root_devno) > : + devfs++; > : + } > > is more succinctly expressed as: > > +if (stat("/dev", &stst) != 0) > +warning("Can't stat /dev: %m"); > +else if (stst.st_dev == root_devno) > +devfs++; Agreed. I thought style(9) would forbid nesting "else if" like that, but I was wrong. > Also, kenv(KENV_GET, ... is used a lot. Maybe it makes sense to have > a simple kenvget call. Would make a few lines a little shorter if > nothing else. KENV_GET is used three times. Using a wrapper function would save 7 characters per call. I don't think it's really worth it. But if you insist, I can update the patch with such a function. By the way, how about declaring requested_transition volatile, as explained in my previus mail? Best regards Oliver -- Oliver Fromme, secnetix GmbH & Co. KG, Marktplatz 29, 85567 Grafing Dienstleistungen mit Schwerpunkt FreeBSD: http://www.secnetix.de/bsd Any opinions expressed in this message may be personal to the author and may not necessarily reflect the opinions of secnetix in any way. cat man du : where Unix geeks go when they die ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "[EMAIL PROTECTED]"
Re: Init.c, making it chroot
this patch looks good, however, one nit: In message: <[EMAIL PROTECTED]> Oliver Fromme <[EMAIL PROTECTED]> writes: : + if (stat("/dev", &stst) != 0) : + warning("Can't stat /dev: %m"); : + else { : + if (stst.st_dev == root_devno) : + devfs++; : + } is more succinctly expressed as: + if (stat("/dev", &stst) != 0) + warning("Can't stat /dev: %m"); + else if (stst.st_dev == root_devno) + devfs++; Also, kenv(KENV_GET, ... is used a lot. Maybe it makes sense to have a simple kenvget call. Would make a few lines a little shorter if nothing else. Otherwise, I think this is a great patch. I don't see other problems with it. Warner ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "[EMAIL PROTECTED]"
Re: Init.c, making it chroot
John Baldwin wrote: > Oliver Fromme wrote: > > John Baldwin wrote: > > > just pass the string literal to the kenv() function, e.g. > > > > In fact that's what I tried first ... Alas: > > warning: passing arg 2 of `kenv' discards qualifiers from pointer target > > type > > It's fixed in HEAD, I'll MFC the prototype fix for kenv() to 6.x. Thankyou! That const stuff really drives me crazy. I still need the ugly __DECONST macro to assign the script name to argv[2] for the execv() call. :-( > > Of course it is possible to write an additional function > > run_script(char *script) which contains runcom's current > > code, and make the runcom() function a wrapper that just > > calls run_script(_PATH_RUNCOM). > > [...] > > That sounds great. I have updated the patch and included your suggestions. Also, a bug has been fixed: The -s option was ignored if an init_script was executed that terminated successfully (exit code 0). That's the one case that I didn't test earlier. :-) To fix it, I needed to introduce a new variable for the initial state transition. By the way, I'm wondering why the requested_transition variable is not declared "volatile". It is modified from a signal handler, so it should be declared volatile in order to prevent the compiler from optimizing certain access patterns. Is there a reason why it isn't declared that way, or have we just been lucky that it didn't break? While I was there, I added a third kenv variable called "init_shell". If it is set, it is used as the shell executable for running scripts, instead of the default /bin/sh. I think that's useful, because when using the init_script and init_chroot features, it might make sense to use a shell binary (maybe statically linked) that's located at a special place inside the chroot. After all, the point of allowing chrooted systems is to share the file system with other systems, so it's better to keep as few files as possible outside the chroot. On my test ISO -- which uses all of the new features -- the root directory only contains /boot, /dev and /ochroot. As usual, the new ISO is here (17.5 MB): http://www.secnetix.de/tmp/init_chroot/ (BTW, when you boot it to multi-user mode, you can log in as "root" without password.) /boot/loader.conf contains these lines: init_path="/ochroot/sbin/init" init_shell="/ochroot/static/sh" init_script="/ochroot/etc/rc.init" init_chroot="/ochroot" That means that init(8) runs /ochroot/etc/rc.init first, using /ochroot/static/sh as the shell. The rc.init file prints a message and changes init_shell to the default "/bin/sh" (using the kenv(1) utility). Then init(8) performs a chroot to /ochroot and runs /etc/rc within it, now using /bin/sh as the shell (inside chroot), as usual. A final note: With my patch, the init binary grows from 535 KB to 537 KB (on RELENG_6), i.e. < 0.5%. Best regards Oliver --- init.c.orig Mon Aug 7 15:10:25 2006 +++ init.c Fri Jan 5 21:16:05 2007 @@ -55,6 +55,7 @@ #include #include #include +#include #include #include #include @@ -121,6 +122,8 @@ state_func_t catatonia(void); state_func_t death(void); +state_func_t run_script(const char *); + enum { AUTOBOOT, FASTBOOT } runcom_mode = AUTOBOOT; #define FALSE 0 #define TRUE 1 @@ -131,9 +134,11 @@ int devfs; void transition(state_t); -state_t requested_transition = runcom; +state_t requested_transition; void setctty(const char *); +const char *get_shell(void); +void write_stderr(const char *message); typedef struct init_session { int se_index; /* index of entry in ttys file */ @@ -187,6 +192,8 @@ int main(int argc, char *argv[]) { + state_t initial_transition = runcom; + char kenv_value[PATH_MAX]; int c; struct sigaction sa; sigset_t mask; @@ -262,7 +269,7 @@ devfs = 1; break; case 's': - requested_transition = single_user; + initial_transition = single_user; break; case 'f': runcom_mode = FASTBOOT; @@ -275,6 +282,65 @@ if (optind != argc) warning("ignoring excess arguments"); + /* +* We catch or block signals rather than ignore them, +* so that they get reset on exec. +*/ + handle(badsys, SIGSYS, 0); + handle(disaster, SIGABRT, SIGFPE, SIGILL, SIGSEGV, + SIGBUS, SIGXCPU, SIGXFSZ, 0); + handle(transition_handler, SIGHUP, SIGINT, SIGTERM, SIGTSTP, + SIGUSR1, SIGUSR2, 0); + handle(alrm_handler, SIGALRM, 0); + sigfillset(&mask); + delset(&mask, SIGABRT, SIGFPE, SIGILL, SIGSEGV, SIGBUS, SIGSYS, + SIGXCPU, SIGXFSZ, SIGHUP, SIGINT, SIGTERM, SIGTSTP, SIGALRM, + SIGUSR1, SIGUSR2, 0); + sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0); + sigemptyset(&sa.sa
Re: Init.c, making it chroot
John Baldwin wrote: > Oliver Fromme wrote: > > I've created (and tested!) a new patch. I've tested on > > RELENG_6, but I think init(8) isn't very different on > > HEAD, so it should work there, too. > > > > Any comments are welcome. I particularly appreciate > > if others test this stuff. > > Some things I noticed: > > - Why do you have the 'ichroot_name' and 'iscript_name' variables? I would > just pass the string literal to the kenv() function, e.g. > > if (kenv(KENV_GET, "init_script", kenv_value, sizeof(kenv_value)) > 0) { > > I think that putting the constant right there is easier for someone who > is reading the code to see what is going on. In fact that's what I tried first ... Alas: warning: passing arg 2 of `kenv' discards qualifiers from pointer target type > - Rather than abusing a global runcom_script variable that you change to > get side effects when you invoke runcom(), why not change runcom() to > take a single 'char *script' as an argument and just pass _PATH_RUNCOM > or kenv_value as appropriate and get rid of the global runcom_script > variable? You are right, the global runcom_script variable does not look very clean. However, the problem is that runcom() is one of the transition action functions, i.e. it is called by the transition() function and never gets an argument. Of course it is possible to write an additional function run_script(char *script) which contains runcom's current code, and make the runcom() function a wrapper that just calls run_script(_PATH_RUNCOM). This isn't a perfectly clean solution either, but maybe it's at least a little bit better. e.g. basically: state_func_t runcom (void) { return run_script(_PATH_RUNCOM); } state_func_t run_script (char *script) { /* all the code formerly in runcom() */ } Then the init_script code would call run_script(kenv_value) instead of runcom(), of course. Would that be acceptable? Or do you have an even better solution in mind? Best regards Oliver -- Oliver Fromme, secnetix GmbH & Co. KG, Marktplatz 29, 85567 Grafing Dienstleistungen mit Schwerpunkt FreeBSD: http://www.secnetix.de/bsd Any opinions expressed in this message may be personal to the author and may not necessarily reflect the opinions of secnetix in any way. "If Java had true garbage collection, most programs would delete themselves upon execution." -- Robert Sewell ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "[EMAIL PROTECTED]"
Re: Init.c, making it chroot
On Thursday 04 January 2007 13:03, Oliver Fromme wrote: > > John Baldwin wrote: > > Oliver Fromme wrote: > > > I've created (and tested!) a new patch. I've tested on > > > RELENG_6, but I think init(8) isn't very different on > > > HEAD, so it should work there, too. > > > > > > Any comments are welcome. I particularly appreciate > > > if others test this stuff. > > > > Some things I noticed: > > > > - Why do you have the 'ichroot_name' and 'iscript_name' variables? I would > > just pass the string literal to the kenv() function, e.g. > > > >if (kenv(KENV_GET, "init_script", kenv_value, sizeof(kenv_value)) > 0) { > > > > I think that putting the constant right there is easier for someone who > > is reading the code to see what is going on. > > In fact that's what I tried first ... Alas: > warning: passing arg 2 of `kenv' discards qualifiers from pointer target type It's fixed in HEAD, I'll MFC the prototype fix for kenv() to 6.x. > > - Rather than abusing a global runcom_script variable that you change to > > get side effects when you invoke runcom(), why not change runcom() to > > take a single 'char *script' as an argument and just pass _PATH_RUNCOM > > or kenv_value as appropriate and get rid of the global runcom_script > > variable? > > You are right, the global runcom_script variable does not > look very clean. However, the problem is that runcom() is > one of the transition action functions, i.e. it is called > by the transition() function and never gets an argument. > > Of course it is possible to write an additional function > run_script(char *script) which contains runcom's current > code, and make the runcom() function a wrapper that just > calls run_script(_PATH_RUNCOM). This isn't a perfectly > clean solution either, but maybe it's at least a little bit > better. > > e.g. basically: > > state_func_t > runcom (void) > { > return run_script(_PATH_RUNCOM); > } > > state_func_t > run_script (char *script) > { > /* all the code formerly in runcom() */ > } > > Then the init_script code would call run_script(kenv_value) > instead of runcom(), of course. > > Would that be acceptable? Or do you have an even better > solution in mind? That sounds great. -- John Baldwin ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "[EMAIL PROTECTED]"
Re: Init.c, making it chroot
Oh and i tested it on 6.1-RELEASE on my own livecd. It works! Oliver Fromme wrote: M. Warner Losh wrote: > In message: <[EMAIL PROTECTED]> > Doug Barton <[EMAIL PROTECTED]> writes: > : Erik Udo wrote: > : > That's nice. But NetBSDs init.c executes /etc/rc before calling > : > chroot(), and that's what i'm looking for > : > : Sorry if I missed your rationale earlier, but could you perhaps > : explain a bit more about why you want to do this? I ask because I'm > : generally interested in boot-time issues, and this sounds like an > : interesting problem. > > This allows one to have a 'simple' /etc/rc that arranges things so > that a new '/' is ready to 'boot'. Sorry, I missed that part of the thread because I wasn't on Cc and didn't look at the list for a while. I've created (and tested!) a new patch. I've tested on RELENG_6, but I think init(8) isn't very different on HEAD, so it should work there, too. The patched init does the following: - If the kenv variable "init_script" is set, it is expected to be the name of a shell script that is executed before init(8) enters its usual state machine, and before chrooting (if requested, see below). If the script terminates with an exit code other than 0, single user mode is enforced. - If the kenv variable "init_chroot" is set, init(8) performs a chroot(2) operation into that directory. That happens after executing the init_script, if any, but before entering the usual state machine, i.e. before going into single or multi user mode. - A check is performed whether /dev is mounted (inside the chroot, if any). If not, it is mounted. - Afterwards, init(8) proceeds normally. It should be noted that the init_script can create or modify the "init_chroot" variable using the kenv(1) tool. So the chroot directory can be specified dynamically by the init_script; it does not have to be hardcoded in /boot/loader.conf. It should also be noted that the init_script requires a few files and directories to be present _outside_ of any chroot: /bin/sh /dev /lib/libc.so.6 /lib/libedit.so.5 /lib/libncurses.so.6 /libexec/ld-elf.so.1 Alternatively you can compile a static shell binary, then you only need /bin/sh and dev (I haven't tested this, though). Note that the /dev directory must exist (outside the chroot), because running the init_script requires certain devices (/dev/console). It is mounted by the kernel before starting init(8). As usual, have prepared an ISO image which tests and demonstrates the patch. It's 17.5 MB compressed: http://www.secnetix.de/tmp/init_chroot/ The /boot/loader.conf file looks like this: kernel_options="-C" init_path="/ochroot/sbin/init" init_script="/ochroot/etc/rc.init" init_chroot="/ochroot" The /ochroot/etc/rc.init just prints a few messages, so you can see that it actually does something. It does not have to be inside the chroot (I put it there because of convenience only). Any comments are welcome. I particularly appreciate if others test this stuff. Best regards Oliver PS: Here's the patch, relatve to rev. 1.60.2.2. I had to move some parts of the original code around, so the setup of the signal handlers happen before any script is run, and the mount of /dev happens afterwards. That's why the diff grew somewhat, even though my actual code changes aren't that many. For executing the init_script, I re-used the runcom() function which required a few minor modifications to it so it was a bit more flexible. In particular I had to move the _PATH_RUNCOM constant into a variable. --- src/sbin/init/init.c.orig Mon Aug 7 15:10:25 2006 +++ src/sbin/init/init.cThu Jan 4 11:53:00 2007 @@ -55,6 +55,7 @@ #include #include #include +#include #include #include #include @@ -121,6 +122,7 @@ state_func_t catatonia(void); state_func_t death(void); +const char *runcom_script = _PATH_RUNCOM; enum { AUTOBOOT, FASTBOOT } runcom_mode = AUTOBOOT; #define FALSE 0 #define TRUE 1 @@ -187,6 +189,9 @@ int main(int argc, char *argv[]) { + char kenv_value[PATH_MAX]; + char ichroot_name[] = "init_chroot"; + char iscript_name[] = "init_script"; int c; struct sigaction sa; sigset_t mask; @@ -275,6 +280,66 @@ if (optind != argc) warning("ignoring excess arguments"); + /* +* We catch or block signals rather than ignore them, +* so that they get reset on exec. +*/ + handle(badsys, SIGSYS, 0); + handle(disaster, SIGABRT, SIGFPE, SIGILL, SIGSEGV, + SIGBUS, SIGXCPU, SIGXFSZ, 0); + handle(transition_handler, SIGHUP, SIGINT, SIGTERM, SIGTSTP, + SIGUSR1, SIGUSR2, 0); + handle(alrm_handler, SIGALRM, 0); + sigfillset(&mask); + delset(&mask, SIGABRT, SIGFPE, SIGILL, SIGSEGV, SIGBUS, SIGSYS, + SIGXCPU, SIGXFSZ, SIGHUP, SIGINT, SIGTERM, SIGTSTP, SIGALRM, + SIGUSR1, SIGUSR2, 0);
Re: Init.c, making it chroot
On Thursday 04 January 2007 09:32, Oliver Fromme wrote: > M. Warner Losh wrote: > > In message: <[EMAIL PROTECTED]> > > Doug Barton <[EMAIL PROTECTED]> writes: > > : Erik Udo wrote: > > : > That's nice. But NetBSDs init.c executes /etc/rc before calling > > : > chroot(), and that's what i'm looking for > > : > > : Sorry if I missed your rationale earlier, but could you perhaps > > : explain a bit more about why you want to do this? I ask because I'm > > : generally interested in boot-time issues, and this sounds like an > > : interesting problem. > > > > This allows one to have a 'simple' /etc/rc that arranges things so > > that a new '/' is ready to 'boot'. > > I've created (and tested!) a new patch. I've tested on > RELENG_6, but I think init(8) isn't very different on > HEAD, so it should work there, too. > > Any comments are welcome. I particularly appreciate > if others test this stuff. Some things I noticed: - Why do you have the 'ichroot_name' and 'iscript_name' variables? I would just pass the string literal to the kenv() function, e.g. if (kenv(KENV_GET, "init_script", kenv_value, sizeof(kenv_value)) > 0) { I think that putting the constant right there is easier for someone who is reading the code to see what is going on. - Rather than abusing a global runcom_script variable that you change to get side effects when you invoke runcom(), why not change runcom() to take a single 'char *script' as an argument and just pass _PATH_RUNCOM or kenv_value as appropriate and get rid of the global runcom_script variable? -- John Baldwin ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "[EMAIL PROTECTED]"
Re: Init.c, making it chroot
PERFECT! Just what i needed. Thanks :) Oliver Fromme wrote: M. Warner Losh wrote: > In message: <[EMAIL PROTECTED]> > Doug Barton <[EMAIL PROTECTED]> writes: > : Erik Udo wrote: > : > That's nice. But NetBSDs init.c executes /etc/rc before calling > : > chroot(), and that's what i'm looking for > : > : Sorry if I missed your rationale earlier, but could you perhaps > : explain a bit more about why you want to do this? I ask because I'm > : generally interested in boot-time issues, and this sounds like an > : interesting problem. > > This allows one to have a 'simple' /etc/rc that arranges things so > that a new '/' is ready to 'boot'. Sorry, I missed that part of the thread because I wasn't on Cc and didn't look at the list for a while. I've created (and tested!) a new patch. I've tested on RELENG_6, but I think init(8) isn't very different on HEAD, so it should work there, too. The patched init does the following: - If the kenv variable "init_script" is set, it is expected to be the name of a shell script that is executed before init(8) enters its usual state machine, and before chrooting (if requested, see below). If the script terminates with an exit code other than 0, single user mode is enforced. - If the kenv variable "init_chroot" is set, init(8) performs a chroot(2) operation into that directory. That happens after executing the init_script, if any, but before entering the usual state machine, i.e. before going into single or multi user mode. - A check is performed whether /dev is mounted (inside the chroot, if any). If not, it is mounted. - Afterwards, init(8) proceeds normally. It should be noted that the init_script can create or modify the "init_chroot" variable using the kenv(1) tool. So the chroot directory can be specified dynamically by the init_script; it does not have to be hardcoded in /boot/loader.conf. It should also be noted that the init_script requires a few files and directories to be present _outside_ of any chroot: /bin/sh /dev /lib/libc.so.6 /lib/libedit.so.5 /lib/libncurses.so.6 /libexec/ld-elf.so.1 Alternatively you can compile a static shell binary, then you only need /bin/sh and dev (I haven't tested this, though). Note that the /dev directory must exist (outside the chroot), because running the init_script requires certain devices (/dev/console). It is mounted by the kernel before starting init(8). As usual, have prepared an ISO image which tests and demonstrates the patch. It's 17.5 MB compressed: http://www.secnetix.de/tmp/init_chroot/ The /boot/loader.conf file looks like this: kernel_options="-C" init_path="/ochroot/sbin/init" init_script="/ochroot/etc/rc.init" init_chroot="/ochroot" The /ochroot/etc/rc.init just prints a few messages, so you can see that it actually does something. It does not have to be inside the chroot (I put it there because of convenience only). Any comments are welcome. I particularly appreciate if others test this stuff. Best regards Oliver PS: Here's the patch, relatve to rev. 1.60.2.2. I had to move some parts of the original code around, so the setup of the signal handlers happen before any script is run, and the mount of /dev happens afterwards. That's why the diff grew somewhat, even though my actual code changes aren't that many. For executing the init_script, I re-used the runcom() function which required a few minor modifications to it so it was a bit more flexible. In particular I had to move the _PATH_RUNCOM constant into a variable. --- src/sbin/init/init.c.orig Mon Aug 7 15:10:25 2006 +++ src/sbin/init/init.cThu Jan 4 11:53:00 2007 @@ -55,6 +55,7 @@ #include #include #include +#include #include #include #include @@ -121,6 +122,7 @@ state_func_t catatonia(void); state_func_t death(void); +const char *runcom_script = _PATH_RUNCOM; enum { AUTOBOOT, FASTBOOT } runcom_mode = AUTOBOOT; #define FALSE 0 #define TRUE 1 @@ -187,6 +189,9 @@ int main(int argc, char *argv[]) { + char kenv_value[PATH_MAX]; + char ichroot_name[] = "init_chroot"; + char iscript_name[] = "init_script"; int c; struct sigaction sa; sigset_t mask; @@ -275,6 +280,66 @@ if (optind != argc) warning("ignoring excess arguments"); + /* +* We catch or block signals rather than ignore them, +* so that they get reset on exec. +*/ + handle(badsys, SIGSYS, 0); + handle(disaster, SIGABRT, SIGFPE, SIGILL, SIGSEGV, + SIGBUS, SIGXCPU, SIGXFSZ, 0); + handle(transition_handler, SIGHUP, SIGINT, SIGTERM, SIGTSTP, + SIGUSR1, SIGUSR2, 0); + handle(alrm_handler, SIGALRM, 0); + sigfillset(&mask); + delset(&mask, SIGABRT, SIGFPE, SIGILL, SIGSEGV, SIGBUS, SIGSYS, + SIGXCPU, SIGXFSZ, SIGHUP, SIGINT, SIGTERM, SIGTSTP, SIGALRM, + SIGUSR1, SIGUSR2, 0); + sigprocmask(SI
Re: Init.c, making it chroot
M. Warner Losh wrote: > In message: <[EMAIL PROTECTED]> > Doug Barton <[EMAIL PROTECTED]> writes: > : Erik Udo wrote: > : > That's nice. But NetBSDs init.c executes /etc/rc before calling > : > chroot(), and that's what i'm looking for > : > : Sorry if I missed your rationale earlier, but could you perhaps > : explain a bit more about why you want to do this? I ask because I'm > : generally interested in boot-time issues, and this sounds like an > : interesting problem. > > This allows one to have a 'simple' /etc/rc that arranges things so > that a new '/' is ready to 'boot'. Sorry, I missed that part of the thread because I wasn't on Cc and didn't look at the list for a while. I've created (and tested!) a new patch. I've tested on RELENG_6, but I think init(8) isn't very different on HEAD, so it should work there, too. The patched init does the following: - If the kenv variable "init_script" is set, it is expected to be the name of a shell script that is executed before init(8) enters its usual state machine, and before chrooting (if requested, see below). If the script terminates with an exit code other than 0, single user mode is enforced. - If the kenv variable "init_chroot" is set, init(8) performs a chroot(2) operation into that directory. That happens after executing the init_script, if any, but before entering the usual state machine, i.e. before going into single or multi user mode. - A check is performed whether /dev is mounted (inside the chroot, if any). If not, it is mounted. - Afterwards, init(8) proceeds normally. It should be noted that the init_script can create or modify the "init_chroot" variable using the kenv(1) tool. So the chroot directory can be specified dynamically by the init_script; it does not have to be hardcoded in /boot/loader.conf. It should also be noted that the init_script requires a few files and directories to be present _outside_ of any chroot: /bin/sh /dev /lib/libc.so.6 /lib/libedit.so.5 /lib/libncurses.so.6 /libexec/ld-elf.so.1 Alternatively you can compile a static shell binary, then you only need /bin/sh and dev (I haven't tested this, though). Note that the /dev directory must exist (outside the chroot), because running the init_script requires certain devices (/dev/console). It is mounted by the kernel before starting init(8). As usual, have prepared an ISO image which tests and demonstrates the patch. It's 17.5 MB compressed: http://www.secnetix.de/tmp/init_chroot/ The /boot/loader.conf file looks like this: kernel_options="-C" init_path="/ochroot/sbin/init" init_script="/ochroot/etc/rc.init" init_chroot="/ochroot" The /ochroot/etc/rc.init just prints a few messages, so you can see that it actually does something. It does not have to be inside the chroot (I put it there because of convenience only). Any comments are welcome. I particularly appreciate if others test this stuff. Best regards Oliver PS: Here's the patch, relatve to rev. 1.60.2.2. I had to move some parts of the original code around, so the setup of the signal handlers happen before any script is run, and the mount of /dev happens afterwards. That's why the diff grew somewhat, even though my actual code changes aren't that many. For executing the init_script, I re-used the runcom() function which required a few minor modifications to it so it was a bit more flexible. In particular I had to move the _PATH_RUNCOM constant into a variable. --- src/sbin/init/init.c.orig Mon Aug 7 15:10:25 2006 +++ src/sbin/init/init.cThu Jan 4 11:53:00 2007 @@ -55,6 +55,7 @@ #include #include #include +#include #include #include #include @@ -121,6 +122,7 @@ state_func_t catatonia(void); state_func_t death(void); +const char *runcom_script = _PATH_RUNCOM; enum { AUTOBOOT, FASTBOOT } runcom_mode = AUTOBOOT; #define FALSE 0 #define TRUE 1 @@ -187,6 +189,9 @@ int main(int argc, char *argv[]) { + char kenv_value[PATH_MAX]; + char ichroot_name[] = "init_chroot"; + char iscript_name[] = "init_script"; int c; struct sigaction sa; sigset_t mask; @@ -275,6 +280,66 @@ if (optind != argc) warning("ignoring excess arguments"); + /* +* We catch or block signals rather than ignore them, +* so that they get reset on exec. +*/ + handle(badsys, SIGSYS, 0); + handle(disaster, SIGABRT, SIGFPE, SIGILL, SIGSEGV, + SIGBUS, SIGXCPU, SIGXFSZ, 0); + handle(transition_handler, SIGHUP, SIGINT, SIGTERM, SIGTSTP, + SIGUSR1, SIGUSR2, 0); + handle(alrm_handler, SIGALRM, 0); + sigfillset(&mask); + delset(&mask, SIGABRT, SIGFPE, SIGILL, SIGSEGV, SIGBUS, SIGSYS, + SIGXCPU, SIGXFSZ, SIGHUP, SIGINT, SIGTERM, SIGTSTP, SIGALRM, + SIGUSR1, SIGUSR2, 0); + sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0); +
Re: Init.c, making it chroot
M. Warner Losh wrote: > In message: <[EMAIL PROTECTED]> > Oliver Fromme <[EMAIL PROTECTED]> writes: > : 1- Why does the kernel try to mount /dev at all? Why not > : simply let init mount it in all cases, with ot without > : init_chroot? Would make things simpler. There doesn't > : seem to be a clear reason why the kernel needs to mount > : it. (Or maybe there _are_ reasons, byt they don't > : appear during my testing.) > > The kernel needs to mount /, and to do that it needs to have a /dev to > look things up in. Well, it actually mounts devfs on / before > looking up and mounting the real /. After it does that, it pivots the > devfs mounted on / into /dev, which is the source of the warning that > you see. OK, it's clear to me now. Also thanks to Robert Watson for the detailed explanation. So the warning is caused by the inability of the "fixup" code to move the devfs mount from / to /dev. This is to be expected in the init_chroot case (because there's no /dev outside of the chroot), so the warning can be safely ignored. Just a small question: What happens with the devfs mount previously mounted on /? Does the kernel silently discard it when the fixup fails, or is it still "hanging around" somehow? I don't see it in mount(8) or df(1) output, so I assume it is discarded. > : 2- Another solution would be to let init(8) autodetect > : whether /dev needs to be mounted. However, that might > : not be as trivial as it sounds. > > Indeed. As far as I can tell, the -d fallback in init is totally > unused these days. Since the kernel doesn't have a general list of > args passed to init, but instead has to construct them one at time > from flags set by the boot loader, I'm pretty sure that it can't be > easily specified. Yes, that seems to be right. An idea that just came to my mind: init could call stat() on / and on /dev (_after_ calling chroot() if applicable), and if the devices (st_dev) are the same, then devfs isn't mounted yet, so the devfs flag must be set for init to proceed successfully. That kind of autodetection should work reliably in all cases. What do you think? Any way, the latest patch that you mailed works perfectly, as I wrote earlier. Should I submit a PR with that patch, or would that be unneccessary? Best regards Oliver -- Oliver Fromme, secnetix GmbH & Co. KG, Marktplatz 29, 85567 Grafing Dienstleistungen mit Schwerpunkt FreeBSD: http://www.secnetix.de/bsd Any opinions expressed in this message may be personal to the author and may not necessarily reflect the opinions of secnetix in any way. "When your hammer is C++, everything begins to look like a thumb." -- Steve Haflich, in comp.lang.c++ ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "[EMAIL PROTECTED]"
Re: Init.c, making it chroot
I just made patch. It's supposed to run /etc/rc before chrooting. This is the NetBSD "way" of doing it. All i can say is that it compiled. So if anyone can look at it before i get to test it becouse i might be forgetting something. (i can't even test it now) diff attached. On 12/27/06, Erik Udo <[EMAIL PROTECTED]> wrote: How can i make init chroot after executing /etc/rc, and executing /etc/rc again in the chrooted enviroment? For this to work, i'd like to know at what point do i call chroot(), becouse init.c uses fork() at the point where it runs the rc script. The thing is, i want to run a whole system in a chrooted enviroment in this livecd i'm making. But the command "chroot /mnt/root /etc/rc" returns after the /etc/rc has been run, dropping me back from the chrooted enviroment. And if it doesn't, init never starts the multiuser mode. So how can i go to the multiuser mode in a chrooted enviroment? I guess the only way to do that is to modify init.c Any help/feedback is appreciated. Cheers, Erik ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "[EMAIL PROTECTED]" init.diff Description: Binary data ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "[EMAIL PROTECTED]"
Re: Init.c, making it chroot
Nah, forget that patch, it's missing alot of stuff. On 1/3/07, Erik Udo <[EMAIL PROTECTED]> wrote: I just made patch. It's supposed to run /etc/rc before chrooting. This is the NetBSD "way" of doing it. All i can say is that it compiled. So if anyone can look at it before i get to test it becouse i might be forgetting something. (i can't even test it now) diff attached. On 12/27/06, Erik Udo < [EMAIL PROTECTED]> wrote: > > How can i make init chroot after executing /etc/rc, and executing > /etc/rc again in the chrooted enviroment? > > For this to work, i'd like to know at what point do i call chroot(), > becouse init.c uses fork() at the point where it runs the rc script. > > The thing is, i want to run a whole system in a chrooted enviroment in > this livecd i'm making. But the command "chroot /mnt/root /etc/rc" > returns after the /etc/rc has been run, dropping me back from the > chrooted enviroment. And if it doesn't, init never starts the multiuser > mode. > > So how can i go to the multiuser mode in a chrooted enviroment? I guess > the only way to do that is to modify init.c > > Any help/feedback is appreciated. > > Cheers, Erik > > ___ > freebsd-hackers@freebsd.org mailing list > http://lists.freebsd.org/mailman/listinfo/freebsd-hackers > To unsubscribe, send any mail to "[EMAIL PROTECTED] > " > ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "[EMAIL PROTECTED]"
Re: Init.c, making it chroot
On Sun, 31 Dec 2006, Tim Kientzle wrote: Robert Watson wrote: ... It used to be that only certain file systems could be used as a root file system, because only they knew how to bypass the lookup procedure to find their device node, short-circuiting to the in-kernel device list. So why are the MD_ROOT and NFS_ROOT options still around? It sounds like there must still be something special about root-capable file systems. NFS_ROOT has to do with extracting the root mount configuration information from the interface list, loader environment, prior to the file system mount process so that NFS knows where to go to find a file system, configure networking, etc. MD_ROOT has to do with setting up the md device to mount the root file system from in memory without having mdconfig run. A glance at the md(4) source code suggests that it also tweaks the default root device to be "ufs:/dev/md0". This is not actually a file system option so much as an option in the behavior of the md(4) device driver. At least, this is my understanding from a very casual glance at the source. In both cases, we now use the single vfs_mount VFSOP. Robert N M Watson Computer Laboratory University of Cambridge ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "[EMAIL PROTECTED]"
Re: Init.c, making it chroot
Robert Watson wrote: ... It used to be that only certain file systems could be used as a root file system, because only they knew how to bypass the lookup procedure to find their device node, short-circuiting to the in-kernel device list. So why are the MD_ROOT and NFS_ROOT options still around? It sounds like there must still be something special about root-capable file systems. Tim Kientzle ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "[EMAIL PROTECTED]"
Re: Init.c, making it chroot
M. Warner Losh wrote: Oh! I see. Reading the actual code is instructive... Run /etc/rc, maybe chroot and run a different /etc/rc... That makes a lot more sense... Warner Yes, it allows for me to create the new chroot, becouse in a livecd it's a disk image. Maybe the /etc/rc is a bit misleading becouse it's only a script that sets up the new chroot and nothing else. ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "[EMAIL PROTECTED]"
Re: Init.c, making it chroot
In message: <[EMAIL PROTECTED]> Doug Barton <[EMAIL PROTECTED]> writes: : Erik Udo wrote: : > That's nice. But NetBSDs init.c executes /etc/rc before calling : > chroot(), and that's what i'm looking for : : Sorry if I missed your rationale earlier, but could you perhaps : explain a bit more about why you want to do this? I ask because I'm : generally interested in boot-time issues, and this sounds like an : interesting problem. This allows one to have a 'simple' /etc/rc that arranges things so that a new '/' is ready to 'boot'. Warner ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "[EMAIL PROTECTED]"
Re: Init.c, making it chroot
Erik Udo wrote: > That's nice. But NetBSDs init.c executes /etc/rc before calling > chroot(), and that's what i'm looking for Sorry if I missed your rationale earlier, but could you perhaps explain a bit more about why you want to do this? I ask because I'm generally interested in boot-time issues, and this sounds like an interesting problem. Doug -- This .signature sanitized for your protection ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "[EMAIL PROTECTED]"
Re: Init.c, making it chroot
On Sat, 30 Dec 2006, M. Warner Losh wrote: In message: <[EMAIL PROTECTED]> Robert Watson <[EMAIL PROTECTED]> writes: : Mounting a second devfs instance is undesirable for a number of : reasons, not least that you end up with an extra file system : floating around (although not reachable via the name space). It's : certainly not disastrous though. At work, we have a build server. Our build environment is a chroot'd area that allows us to insultate the products we're building from the host os's files completely. We have to have a devfs entry in each of these chroots. We often see dozens of devfs instances mounted on our 6.2 build boxes w/o ill effect. We've done this as far back as 5.3. Yes, this is certainly a supported configuration, as it's also used extensively with jail. Robert N M Watson Computer Laboratory University of Cambridge ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "[EMAIL PROTECTED]"
Re: Init.c, making it chroot
In message: <[EMAIL PROTECTED]> Oliver Fromme <[EMAIL PROTECTED]> writes: : 1- Why does the kernel try to mount /dev at all? Why not : simply let init mount it in all cases, with ot without : init_chroot? Would make things simpler. There doesn't : seem to be a clear reason why the kernel needs to mount : it. (Or maybe there _are_ reasons, byt they don't : appear during my testing.) The kernel needs to mount /, and to do that it needs to have a /dev to look things up in. Well, it actually mounts devfs on / before looking up and mounting the real /. After it does that, it pivots the devfs mounted on / into /dev, which is the source of the warning that you see. : 2- Another solution would be to let init(8) autodetect : whether /dev needs to be mounted. However, that might : not be as trivial as it sounds. Indeed. As far as I can tell, the -d fallback in init is totally unused these days. Since the kernel doesn't have a general list of args passed to init, but instead has to construct them one at time from flags set by the boot loader, I'm pretty sure that it can't be easily specified. : By the way, testing the whole thing is easy. Just install : qemu from ports, then run this command: : :qemu -monitor stdio -cdrom chroot-test.iso -boot d : : Creating the ISO (with mkisofs) takes 5 seconds, and booting : it in qemu takes 10 seconds (even without the kqemu kernel : accelerator module), so the development and testing cycles : are very short. That's how I developed my CD/DVD boot : manager "eltoro"[1]. As soon as the ISO runs successfully : in qemu, I write it to a CD-RW and boot it on a real PC : for verification. Cool! : Best regards :Oliver : : : PS: [1] http://www.secnetix.de/products/eltoro/ : : -- : Oliver Fromme, secnetix GmbH & Co. KG, Marktplatz 29, 85567 Grafing : Dienstleistungen mit Schwerpunkt FreeBSD: http://www.secnetix.de/bsd : Any opinions expressed in this message may be personal to the author : and may not necessarily reflect the opinions of secnetix in any way. : : "One of the main causes of the fall of the Roman Empire was that, : lacking zero, they had no way to indicate successful termination : of their C programs." : -- Robert Firth : : ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "[EMAIL PROTECTED]"
Re: Init.c, making it chroot
In message: <[EMAIL PROTECTED]> Robert Watson <[EMAIL PROTECTED]> writes: : Mounting a second devfs instance is undesirable for a number of : reasons, not least that you end up with an extra file system : floating around (although not reachable via the name space). It's : certainly not disastrous though. At work, we have a build server. Our build environment is a chroot'd area that allows us to insultate the products we're building from the host os's files completely. We have to have a devfs entry in each of these chroots. We often see dozens of devfs instances mounted on our 6.2 build boxes w/o ill effect. We've done this as far back as 5.3. Warner ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "[EMAIL PROTECTED]"
Re: Init.c, making it chroot
On Sat, 30 Dec 2006, Oliver Fromme wrote: In particular, there is no /dev, so I still get this one from the kernel: Lookup of /dev for devfs, error: 2 But then init and everything starts up fine, so it doesn't seem to cause any harm. That raises two questions: 1- Why does the kernel try to mount /dev at all? Why not simply let init mount it in all cases, with ot without init_chroot? Would make things simpler. There doesn't seem to be a clear reason why the kernel needs to mount it. (Or maybe there _are_ reasons, byt they don't appear during my testing.) 2- Another solution would be to let init(8) autodetect whether /dev needs to be mounted. However, that might not be as trivial as it sounds. The kernel needs to mount devfs because that's how it finds the device node to mount the root file system from. The bootstrap process is a bit complex, but basically what happens is this: (1) The kernel mounts devfs as /, and creates a /dev -> / symlink so that lookups in /dev using standard device names will work. (2) The kernel then attempts to mount the requested root file system using a device node from the devfs root. (3) Once a real root file system is successfully mounted, it performs a "fixup", which makes the new root file system the actual root file system, and re-grafts the original devfs mount onto /dev of the new root file system. It also removes the /dev/dev symlink. The error message you're seeing is the kernel failing to find a /dev directory on the new root file system so having no where to regraft the boot-time /dev. You can see the logic for this in vfs_mountroot_try(), devfs_first(), and devfs_fixup(). The point of all this is that we want the mount logic in every file system to be identical whether it's being used for the root file system or not. It used to be that only certain file systems could be used as a root file system, because only they knew how to bypass the lookup procedure to find their device node, short-circuiting to the in-kernel device list. Normally when a file system is mounted, it is given a path to a device node, which it looks up using VFS and then mounts, so the root file system required quite special behavior. Since devfs doesn't require a source device to mount, being purely synthetic, this isn't an issue, and every file system now has exactly one mount routine that can make consistent assumptions about what it's being mounted on/with. The grafting logic is entirely a property of VFS, and while not pretty, it is fairly functional, and is not in per-file system code. init contains fallback logic to mount a devfs instance if requested (-d), but I believe this exists largely to support upgrade transitions that may or may not still be relevant. Mounting a second devfs instance is undesirable for a number of reasons, not least that you end up with an extra file system floating around (although not reachable via the name space). It's certainly not disastrous though. Robert N M Watson Computer Laboratory University of Cambridge By the way, testing the whole thing is easy. Just install qemu from ports, then run this command: qemu -monitor stdio -cdrom chroot-test.iso -boot d Creating the ISO (with mkisofs) takes 5 seconds, and booting it in qemu takes 10 seconds (even without the kqemu kernel accelerator module), so the development and testing cycles are very short. That's how I developed my CD/DVD boot manager "eltoro"[1]. As soon as the ISO runs successfully in qemu, I write it to a CD-RW and boot it on a real PC for verification. Best regards Oliver PS: [1] http://www.secnetix.de/products/eltoro/ -- Oliver Fromme, secnetix GmbH & Co. KG, Marktplatz 29, 85567 Grafing Dienstleistungen mit Schwerpunkt FreeBSD: http://www.secnetix.de/bsd Any opinions expressed in this message may be personal to the author and may not necessarily reflect the opinions of secnetix in any way. "One of the main causes of the fall of the Roman Empire was that, lacking zero, they had no way to indicate successful termination of their C programs." -- Robert Firth ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "[EMAIL PROTECTED]" ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "[EMAIL PROTECTED]"
Re: Init.c, making it chroot
M. Warner Losh wrote: > Oliver Fromme <[EMAIL PROTECTED]> writes: > : Thanks for the new patch, I'll try it as soon as possible. I got a few minutes and tested it. > I don't have the proper environment to easily test this > out, but I think what I sent will work... It does work indeed! With that patch, the chrooted system boots fine into multi-user mode and I get a login prompt. If you would like to look at my ISO (or anybody else who's following this thread): http://www.secnetix.de/tmp/init_chroot/ The ISO is 17 MB compressed (I removed some stuff to keep it small). Actually it's pretty much a standard FreeBSD base system. There's also an ls -alR listing on the URL above. The directory structure on it looks like this: /boot /ochroot /ochroot/bin /ochroot/boot /ochroot/dev /ochroot/etc /ochroot/... i.e. basically everything is located under /ochroot, except for /boot which is hardlinked from /ochroot/boot (to save space). In particular, there is no /dev, so I still get this one from the kernel: Lookup of /dev for devfs, error: 2 But then init and everything starts up fine, so it doesn't seem to cause any harm. That raises two questions: 1- Why does the kernel try to mount /dev at all? Why not simply let init mount it in all cases, with ot without init_chroot? Would make things simpler. There doesn't seem to be a clear reason why the kernel needs to mount it. (Or maybe there _are_ reasons, byt they don't appear during my testing.) 2- Another solution would be to let init(8) autodetect whether /dev needs to be mounted. However, that might not be as trivial as it sounds. By the way, testing the whole thing is easy. Just install qemu from ports, then run this command: qemu -monitor stdio -cdrom chroot-test.iso -boot d Creating the ISO (with mkisofs) takes 5 seconds, and booting it in qemu takes 10 seconds (even without the kqemu kernel accelerator module), so the development and testing cycles are very short. That's how I developed my CD/DVD boot manager "eltoro"[1]. As soon as the ISO runs successfully in qemu, I write it to a CD-RW and boot it on a real PC for verification. Best regards Oliver PS: [1] http://www.secnetix.de/products/eltoro/ -- Oliver Fromme, secnetix GmbH & Co. KG, Marktplatz 29, 85567 Grafing Dienstleistungen mit Schwerpunkt FreeBSD: http://www.secnetix.de/bsd Any opinions expressed in this message may be personal to the author and may not necessarily reflect the opinions of secnetix in any way. "One of the main causes of the fall of the Roman Empire was that, lacking zero, they had no way to indicate successful termination of their C programs." -- Robert Firth ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "[EMAIL PROTECTED]"
Re: Init.c, making it chroot
That's nice. But NetBSDs init.c executes /etc/rc before calling chroot(), and that's what i'm looking for, and for a moment tried to implement, but i'm not very familiar with FreeBSD code :) For example that kenv() came to me as a suprise. I'll have to try to implement the NetBSD way where /etc/rc is executed before chroot(). Ofcourse now that i dont have to use sysctls, it's alot easier. M. Warner Losh wrote: BTW, here's a patch to test. Since FreeBSD has kenv(2), the patch is actually very small. Warner Index: init.c === RCS file: /cache/ncvs/src/sbin/init/init.c,v retrieving revision 1.62 diff -u -r1.62 init.c --- init.c 8 Jun 2006 14:04:36 - 1.62 +++ init.c 28 Dec 2006 20:39:33 - @@ -55,6 +55,7 @@ #include #include #include +#include #include #include #include @@ -187,6 +188,7 @@ int main(int argc, char *argv[]) { + char init_chroot[PATH_MAX]; int c; struct sigaction sa; sigset_t mask; @@ -239,6 +241,12 @@ */ openlog("init", LOG_CONS|LOG_ODELAY, LOG_AUTH); + *init_chroot = '\0'; + kenv(KENV_GET, "init_chroot", init_chroot, sizeof(init_chroot)); + if (*init_chroot) + if (chdir(init_chroot) != 0 || chroot(".") != 0) + warning("Can't chroot to %s: %m", init_chroot); + /* * Create an initial session. */ ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "[EMAIL PROTECTED]"
Re: Init.c, making it chroot
In message: <[EMAIL PROTECTED]> Oliver Fromme <[EMAIL PROTECTED]> writes: : : Thanks for the new patch, I'll try it as soon as possible. : : However, that might not be before Tuesday or Wednesday : because of wedding anniversary, birthday and new year's eve : (yup, all on one weekend), and it might take a day or two : until I'm sober again. ;-) Sounds good. I don't have the proper environment to easily test this out, but I think what I sent will work... Warner ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "[EMAIL PROTECTED]"
Re: Init.c, making it chroot
Thanks for the new patch, I'll try it as soon as possible. However, that might not be before Tuesday or Wednesday because of wedding anniversary, birthday and new year's eve (yup, all on one weekend), and it might take a day or two until I'm sober again. ;-) Best regards Oliver -- Oliver Fromme, secnetix GmbH & Co. KG, Marktplatz 29, 85567 Grafing Dienstleistungen mit Schwerpunkt FreeBSD: http://www.secnetix.de/bsd Any opinions expressed in this message may be personal to the author and may not necessarily reflect the opinions of secnetix in any way. With Perl you can manipulate text, interact with programs, talk over networks, drive Web pages, perform arbitrary precision arithmetic, and write programs that look like Snoopy swearing. ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "[EMAIL PROTECTED]"
Re: Init.c, making it chroot
M. Warner Losh wrote: > BTW, here's a patch to test. Since FreeBSD has kenv(2), the patch is > actually very small. OK, I tried it. The patch applied cleanly to RELENG_6. The following line triggered a warning and caused the compilation to be aborted: > +kenv(KENV_GET, "init_chroot", init_chroot, sizeof(init_chroot)); I get: /usr/src/sbin/init/init.c: In function `main': /usr/src/sbin/init/init.c:245: warning: passing arg 2 of `kenv' discards qualifiers from pointer target type I modified your patch slightly, now also checking the return value from kenv(): --- init.orig/init.cSat Jul 15 13:12:44 2006 +++ init/init.c Fri Dec 29 14:52:59 2006 @@ -55,6 +55,7 @@ #include #include #include +#include #include #include #include @@ -187,6 +188,8 @@ int main(int argc, char *argv[]) { + char init_chroot[PATH_MAX]; + char init_chroot_name[] = "init_chroot"; int c; struct sigaction sa; sigset_t mask; @@ -238,6 +241,13 @@ * Does 'init' deserve its own facility number? */ openlog("init", LOG_CONS|LOG_ODELAY, LOG_AUTH); + + *init_chroot = '\0'; + if (kenv(KENV_GET, init_chroot_name, init_chroot, sizeof(init_chroot)) + && *init_chroot != '\0') { + if (chdir(init_chroot) != 0 || chroot(".") != 0) + warning("Can't chroot to %s: %m", init_chroot); + } /* * Create an initial session. It compiles without problems. For testing I prepared an ISO image and put everything into a subdirectory called /chroot, except for /boot. /boot/loader.conf contains these lines: init_path="/ochroot/sbin/init" init_chroot="/ochroot" When I boot the CD (with -v), it freezes after printing these lines: cd9660: RockRidge Extension Lookup of /dev for devfs, error: 2 start_init: trying /ochroot/sbin/init It seems that the kernel looks for /dev before starting init, hence before the chroot. So I created /dev in the ISO image and tried again. Now the "devfs error 2" line doesn't appear anymore, but it still freezes after the "start_init" line. I suspect that init expects devfs to be mounted on /dev _inside_ the chroot (i.e. on /ochroot/dev in my case), but I'm not sure if that's really causing the freeze. Unfortunately I haven't been able to analyse the problem further. Do you have an idea or hint? (I can put my ISO online for testing if someone wants to look at it. It's 27 MB compressed.) Best regards Oliver PS: The init_chroot feature would also be useful for making a shared CD/DVD that contains a standard FreeBSD installation (with sysinstall and "fixit") and a bootable live FS such as FreeSBIE at the same time. -- Oliver Fromme, secnetix GmbH & Co. KG, Marktplatz 29, 85567 Grafing Dienstleistungen mit Schwerpunkt FreeBSD: http://www.secnetix.de/bsd Any opinions expressed in this message may be personal to the author and may not necessarily reflect the opinions of secnetix in any way. Perl is worse than Python because people wanted it worse. -- Larry Wall ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "[EMAIL PROTECTED]"
Re: Init.c, making it chroot
M. Warner Losh wrote: > Oliver Fromme <[EMAIL PROTECTED]> writes: > : Erik Udo wrote: > : > How can i make init chroot after executing /etc/rc, and executing > : > /etc/rc again in the chrooted enviroment? > : > > : > For this to work, i'd like to know at what point do i call chroot(), > : > becouse init.c uses fork() at the point where it runs the rc script. > : > > : > The thing is, i want to run a whole system in a chrooted enviroment in > : > this livecd i'm making. But the command "chroot /mnt/root /etc/rc" > : > returns after the /etc/rc has been run, dropping me back from the > : > chrooted enviroment. And if it doesn't, init never starts the multiuser > : > mode. > : > : That's exactly the problem I had when I created a combined > : DVD-ROM with FreeBSD and DragonFly BSD on it. For them to > : share the same ISO-9660, at least one of them needed to be > : chrooted. I decided to add the feature to DragonFly BSD's > : init(8) because the DragonFly people seemed to be easier to > : convince of the usefulness. ;-) Indeed, the feature was > : committed quickly. I didn't try to send-pr a similar patch > : for FreeBSD. > > You do the FreeBSD developer community a disservice with this > attitude. We've been talking about needing something like this for a > while. I'm sorry, I must have missed that then. Would you point me to the URL of a thread discussing that, or a subject I could grep for? When I first mentioned it (2 or 3 years ago), nobody was interested. When I needed a solution, I needed the chroot feature in either of the two BSDs, but not necessarily in both. And most importantly, I needed it quickly because the publisher had a deadline. I mentioned the issue in both lists, and Matt responded and assisted quickly, so the feature went into DragonFly. At that moment I simply didn't have enough time to try to convince the people on this side of the borderline ;-) that the feature might also be useful for FreeBSD. My immediate problem was solved. If you look at the archives and at the PR database you will see that I have submitted quite a lot of things to the FreeBSD project. And there are quite many submissions that stay in the PR database (open or closed) without a chance of getting committed, because they're not deemed to be useful, or nobody is interested in them, or no responsible person shows up, or it ends up in a bikeshed discussion, or I don't know what else. Don't worry, I'll continue to submit code, when I have the time to do so, and if I see at least a slim chance that a committer will pick it up. > : PS: I see NetBSD has a similar feature, too. Maybe > : FreeBSD should join the crowd and adopt it. ;-) > > Please, don't come into the FreeBSD forums and talk trash on FreeBSD > when you've not even tried to get a change into the base system. I have tried. Best regards Oliver PS: I'll write another mail in a few minutes, in reply to your patch. -- Oliver Fromme, secnetix GmbH & Co. KG, Marktplatz 29, 85567 Grafing Dienstleistungen mit Schwerpunkt FreeBSD: http://www.secnetix.de/bsd Any opinions expressed in this message may be personal to the author and may not necessarily reflect the opinions of secnetix in any way. > Can the denizens of this group enlighten me about what the > advantages of Python are, versus Perl ? "python" is more likely to pass unharmed through your spelling checker than "perl". -- An unknown poster and Fredrik Lundh ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "[EMAIL PROTECTED]"
Re: Init.c, making it chroot
In message: <[EMAIL PROTECTED]> Oliver Fromme <[EMAIL PROTECTED]> writes: : : M. Warner Losh wrote: : > BTW, here's a patch to test. Since FreeBSD has kenv(2), the patch is : > actually very small. : : OK, I tried it. The patch applied cleanly to RELENG_6. : The following line triggered a warning and caused the : compilation to be aborted: : : > + kenv(KENV_GET, "init_chroot", init_chroot, sizeof(init_chroot)); : : I get: : :/usr/src/sbin/init/init.c: In function `main': :/usr/src/sbin/init/init.c:245: warning: passing arg 2 of `kenv' discards qualifiers from pointer target type looks like kenv on RELENG_6 hadn't been const poisoned :-(. : It compiles without problems. For testing I prepared an : ISO image and put everything into a subdirectory called : /chroot, except for /boot. /boot/loader.conf contains : these lines: : :init_path="/ochroot/sbin/init" :init_chroot="/ochroot" : : When I boot the CD (with -v), it freezes after printing : these lines: : :cd9660: RockRidge Extension :Lookup of /dev for devfs, error: 2 :start_init: trying /ochroot/sbin/init OK. There's code in init to mount devfs, but it is disabled by default. The error message is from devfs_fixup. Early in the kernel boot, just before we mount root, the kernel executes devfs_first. This mounts devfs as / and creates a /dev -> / symlink. This allows mounting and the like to work. Later, after we've mounted /, we do what linux would call 'pivot root' and remount this devfs on / as /dev. That's devfs_fixup. : It seems that the kernel looks for /dev before starting : init, hence before the chroot. So I created /dev in the : ISO image and tried again. Now the "devfs error 2" line : doesn't appear anymore, but it still freezes after the : "start_init" line. I can understand that. init doesn't try to mount devfs on /dev unless you pass it -d. The -d comes from the boot loader somehow, but I've not threaded to see how it could be set. It appears, from first blush, that RB_SINGLE gets 's' set, but there's no way to get 'd' set. Maybe init_chroot should imply it. : I suspect that init expects devfs to be mounted on /dev : _inside_ the chroot (i.e. on /ochroot/dev in my case), : but I'm not sure if that's really causing the freeze. : Unfortunately I haven't been able to analyse the problem : further. Do you have an idea or hint? Once we chroot, we need to have a sane environment inside the chroot. Since the patches I posted chroot so early, /dev doesn't exist inside of it... : PS: The init_chroot feature would also be useful for : making a shared CD/DVD that contains a standard FreeBSD : installation (with sysinstall and "fixit") and a bootable : live FS such as FreeSBIE at the same time. The desire for a feature similar to this has come up many times, usually in one-on-one meetings. I'm sold on its need. I've enclosed a patch. delphi@ also checked the return value of kenv too, which is more documented an interface. Warner Index: init.c === RCS file: /cache/ncvs/src/sbin/init/init.c,v retrieving revision 1.62 diff -u -r1.62 init.c --- init.c 8 Jun 2006 14:04:36 - 1.62 +++ init.c 29 Dec 2006 18:32:22 - @@ -55,6 +55,7 @@ #include #include #include +#include #include #include #include @@ -187,6 +188,8 @@ int main(int argc, char *argv[]) { + char init_chroot[PATH_MAX]; + char icname[] = "init_chroot"; int c; struct sigaction sa; sigset_t mask; @@ -239,6 +242,13 @@ */ openlog("init", LOG_CONS|LOG_ODELAY, LOG_AUTH); + if (kenv(KENV_GET, icname, init_chroot, sizeof(init_chroot)) > 0) { + if (chdir(init_chroot) != 0 || chroot(".") != 0) + warning("Can't chroot to %s: %m", init_chroot); + else + devfs++; + } + /* * Create an initial session. */ ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "[EMAIL PROTECTED]"
Re: Init.c, making it chroot
BTW, here's a patch to test. Since FreeBSD has kenv(2), the patch is actually very small. Warner Index: init.c === RCS file: /cache/ncvs/src/sbin/init/init.c,v retrieving revision 1.62 diff -u -r1.62 init.c --- init.c 8 Jun 2006 14:04:36 - 1.62 +++ init.c 28 Dec 2006 20:39:33 - @@ -55,6 +55,7 @@ #include #include #include +#include #include #include #include @@ -187,6 +188,7 @@ int main(int argc, char *argv[]) { + char init_chroot[PATH_MAX]; int c; struct sigaction sa; sigset_t mask; @@ -239,6 +241,12 @@ */ openlog("init", LOG_CONS|LOG_ODELAY, LOG_AUTH); + *init_chroot = '\0'; + kenv(KENV_GET, "init_chroot", init_chroot, sizeof(init_chroot)); + if (*init_chroot) + if (chdir(init_chroot) != 0 || chroot(".") != 0) + warning("Can't chroot to %s: %m", init_chroot); + /* * Create an initial session. */ ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "[EMAIL PROTECTED]"
Re: Init.c, making it chroot
In message: <[EMAIL PROTECTED]> Oliver Fromme <[EMAIL PROTECTED]> writes: : Erik Udo wrote: : > How can i make init chroot after executing /etc/rc, and executing : > /etc/rc again in the chrooted enviroment? : > : > For this to work, i'd like to know at what point do i call chroot(), : > becouse init.c uses fork() at the point where it runs the rc script. : > : > The thing is, i want to run a whole system in a chrooted enviroment in : > this livecd i'm making. But the command "chroot /mnt/root /etc/rc" : > returns after the /etc/rc has been run, dropping me back from the : > chrooted enviroment. And if it doesn't, init never starts the multiuser : > mode. : : That's exactly the problem I had when I created a combined : DVD-ROM with FreeBSD and DragonFly BSD on it. For them to : share the same ISO-9660, at least one of them needed to be : chrooted. I decided to add the feature to DragonFly BSD's : init(8) because the DragonFly people seemed to be easier to : convince of the usefulness. ;-) Indeed, the feature was : committed quickly. I didn't try to send-pr a similar patch : for FreeBSD. You do the FreeBSD developer community a disservice with this attitude. We've been talking about needing something like this for a while. : It shouldn't be too difficult to port it, though: : : http://www.dragonflybsd.org/cvsweb/src/sbin/init/init.c : : The chroot() patch has been committed with r1.6. It uses : kenv to specify the chroot directory, so it can easily be : set by the loader(8), e.g. using a custom boot menu. : : Best regards :Oliver : : PS: I see NetBSD has a similar feature, too. Maybe : FreeBSD should join the crowd and adopt it. ;-) Please, don't come into the FreeBSD forums and talk trash on FreeBSD when you've not even tried to get a change into the base system. Warner ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "[EMAIL PROTECTED]"
Re: Init.c, making it chroot
Erik Udo wrote: > How can i make init chroot after executing /etc/rc, and executing > /etc/rc again in the chrooted enviroment? > > For this to work, i'd like to know at what point do i call chroot(), > becouse init.c uses fork() at the point where it runs the rc script. > > The thing is, i want to run a whole system in a chrooted enviroment in > this livecd i'm making. But the command "chroot /mnt/root /etc/rc" > returns after the /etc/rc has been run, dropping me back from the > chrooted enviroment. And if it doesn't, init never starts the multiuser > mode. That's exactly the problem I had when I created a combined DVD-ROM with FreeBSD and DragonFly BSD on it. For them to share the same ISO-9660, at least one of them needed to be chrooted. I decided to add the feature to DragonFly BSD's init(8) because the DragonFly people seemed to be easier to convince of the usefulness. ;-) Indeed, the feature was committed quickly. I didn't try to send-pr a similar patch for FreeBSD. It shouldn't be too difficult to port it, though: http://www.dragonflybsd.org/cvsweb/src/sbin/init/init.c The chroot() patch has been committed with r1.6. It uses kenv to specify the chroot directory, so it can easily be set by the loader(8), e.g. using a custom boot menu. Best regards Oliver PS: I see NetBSD has a similar feature, too. Maybe FreeBSD should join the crowd and adopt it. ;-) -- Oliver Fromme, secnetix GmbH & Co. KG, Marktplatz 29, 85567 Grafing Dienstleistungen mit Schwerpunkt FreeBSD: http://www.secnetix.de/bsd Any opinions expressed in this message may be personal to the author and may not necessarily reflect the opinions of secnetix in any way. "Python tricks" is a tough one, cuz the language is so clean. E.g., C makes an art of confusing pointers with arrays and strings, which leads to lotsa neat pointer tricks; APL mistakes everything for an array, leading to neat one-liners; and Perl confuses everything period, making each line a joyous adventure . -- Tim Peters ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "[EMAIL PROTECTED]"
Re: Init.c, making it chroot
On Wed, Dec 27, 2006 at 09:27:24PM +0200, Erik Udo wrote: > How can i make init chroot after executing /etc/rc, and executing > /etc/rc again in the chrooted enviroment? > Go look at the NetBSD init(8) that can do this, and bring us back a patch for this. Quote from the NetBSD init(8) manpage: : 2. Multi-user boot (default operation). Executes /etc/rc (see rc(8)). : If this was the first state entered (as opposed to entering here : after state 1), then /etc/rc will be invoked with its first argument : being `autoboot'. If /etc/rc exits with a non-zero (error) exit : code, commence single user operation by giving the super-user a : shell on the console by going to state 1 (single user). Otherwise, : proceed to state 3. : : If value of the ``init.root'' sysctl node is not equal to / at this : point, the /etc/rc process will be run inside a chroot(2) indicated : by sysctl with the same error handling as above. Cheers, -- Ruslan Ermilov [EMAIL PROTECTED] FreeBSD committer pgpO7LdxYof4f.pgp Description: PGP signature
Init.c, making it chroot
How can i make init chroot after executing /etc/rc, and executing /etc/rc again in the chrooted enviroment? For this to work, i'd like to know at what point do i call chroot(), becouse init.c uses fork() at the point where it runs the rc script. The thing is, i want to run a whole system in a chrooted enviroment in this livecd i'm making. But the command "chroot /mnt/root /etc/rc" returns after the /etc/rc has been run, dropping me back from the chrooted enviroment. And if it doesn't, init never starts the multiuser mode. So how can i go to the multiuser mode in a chrooted enviroment? I guess the only way to do that is to modify init.c Any help/feedback is appreciated. Cheers, Erik ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "[EMAIL PROTECTED]"