看板 DFBSD_submit 關於我們 聯絡資訊
Hi, The patch below adds a feature to sbin/init that has been discussed in the users list recently. It enables init to optionally perform a chroot() operation very early, so that the rest of the boot process runs from a subdirectory of the root file system. This feature enables you to have several bootable versions of DragonFly and FreeBSD on the same file system (such as a CD or DVD). Personally I'm using this to let the DragonFly install co-exist with the FreeBSD install + fix-it on the same DVD. The feature might also be useful for other things, such as diskless booting. The chroot feature is controlled by a kernel environment variable "init_chroot" which can be set in loader.conf. If it is set to a non-empty value containing the name of an existing directory, init will chroot() into it. To test it, I prepared a CD-R like this: 1. Make a copy of the latest DF stable ISO (20041107). 2. Replace sbin/init with the patched version. 3. # mkdir dragonfly 4. Copy everything except boot into dragonfly. Now the root directory of the CD contains only /boot and /dragonfly, nothing else. 5. The installer needs /boot, too, so we need a copy of it in the dragonfly subdirectory. To save space, we make hardlinks instead of plain copies: # find boot | cpio -dumpl dragonfly 6. # cd dragonfly; ln -s . dragonfly 7. Modify /boot/loader.conf so everything is loaded from the /dragonfly directory. Add these lines: kernel="/dragonfly/kernel" bootfile="/dragonfly/kernel" module_path="/;/modules;/dragonfly/modules" init_path="/dragonfly/sbin/init:/sbin/init" init_chroot="/dragonfly" 8. Run mkisofs as usual and write to CD-R/RW. Booting from that CD-R works perfectly. You don't notice that the system actually runs from a chroot directory of the CD. It is possible to add further directories to the CD containing different DragonFly BSD versions, or even FreeBSD. The loader menu can be modified to allow booting the various systems by setting the appropriate variables (see above). The patch is pretty straight-forward. Most of the actual code has been copied from src/usr.bin/kenv/kenv.c with only minor modifications. Best regards Oliver --- src/sbin/init.c.orig Thu Nov 18 18:26:13 2004 +++ src/sbin/init.c Fri Nov 19 00:43:57 2004 @@ -162,6 +162,7 @@ void alrm_handler(int); void setsecuritylevel(int); int getsecuritylevel(void); +char *get_chroot(void); int setupargv(session_t *, struct ttyent *); #ifdef LOGIN_CAP void setprocresources(const char *); @@ -182,6 +183,7 @@ int main(int argc, char **argv) { + char *init_chroot; int c; struct sigaction sa; sigset_t mask; @@ -236,6 +238,18 @@ openlog("init", LOG_CONS|LOG_ODELAY, LOG_AUTH); /* + * If chroot has been requested by the boot loader, + * do it now. Try to be robust: If the directory + * doesn't exist, continue anyway. + */ + init_chroot = get_chroot(); + if (init_chroot != NULL) { + if (chdir(init_chroot) == -1 || chroot(".") == -1) + warning("can't chroot to %s: %m", init_chroot); + free(init_chroot); + } + + /* * Create an initial session. */ if (setsid() < 0) @@ -455,6 +469,59 @@ #else return (-1); #endif +} + +/* + * Get the value of the "init_chroot" variable from the + * kernel environment (or NULL if not set). + * (Most of this has been copied from src/usr.bin/kenv/kenv.c.) + */ +char * +get_chroot(void) +{ + char sbuf[1024]; + int name2oid_oid[2]; + int real_oid[CTL_MAXNAME+4]; + size_t oidlen; + int i, slen; + char *eq, *name; + + name2oid_oid[0] = 0; /* This is magic & undocumented! */ + name2oid_oid[1] = 3; + oidlen = sizeof(real_oid); + name = "kern.environment"; + if (sysctl(name2oid_oid, 2, real_oid, &oidlen, name, strlen(name)) < 0) { + warning("cannot find kern.environment base sysctl OID"); + return NULL; + } + oidlen /= sizeof(int); + if (oidlen >= CTL_MAXNAME) { + warning("kern.environment OID is too large!"); + return NULL; + } + real_oid[oidlen] = 0; + for (i = 0; ; i++) { + real_oid[oidlen + 1] = i; + slen = sizeof(sbuf) - 1; + if (sysctl(real_oid, oidlen + 2, sbuf, &slen, NULL, 0) < 0) { + if (errno != ENOENT) + warning("sysctl kern.environment.%d: %m", i); + break; + } + sbuf[sizeof(sbuf) - 1] = '\0'; + eq = strchr(sbuf, '='); + if (eq == NULL) { + warning("malformed environment string: %s", sbuf); + break; + } + *eq = '\0'; + if (strcmp(sbuf, "init_chroot") == 0) + if (eq[1]) + return strdup(eq + 1); + else + break; + } + return NULL; } /*