diff --git a/Makefile b/Makefile index 009a6ba..044ffb9 100644 --- a/Makefile +++ b/Makefile @@ -26,6 +26,7 @@ TAGS := ctags PROGRAM := kvm GUEST_INIT := guest/init +GUEST_INIT_S2 := guest/init_stage2 OBJS += builtin-balloon.o OBJS += builtin-debug.o @@ -207,7 +208,7 @@ WARNINGS += -Wwrite-strings CFLAGS += $(WARNINGS) -all: arch_support_check $(PROGRAM) $(GUEST_INIT) +all: arch_support_check $(PROGRAM) $(GUEST_INIT) $(GUEST_INIT_S2) arch_support_check: $(UNSUPP_ERR) @@ -224,6 +225,10 @@ $(GUEST_INIT): guest/init.c $(E) " LINK " $@ $(Q) $(CC) -static guest/init.c -o $@ +$(GUEST_INIT_S2): guest/init_stage2.c + $(E) " LINK " $@ + $(Q) $(CC) -static guest/init_stage2.c -o $@ + $(DEPS): %.d: %.c @@ -286,7 +291,7 @@ x86/bios/bios-rom.h: x86/bios/bios.bin.elf $(E) " NM " $@ $(Q) cd x86/bios && sh gen-offsets.sh > bios-rom.h && cd .. -check: $(PROGRAM) +check: all $(MAKE) -C tests ./$(PROGRAM) run tests/pit/tick.bin ./$(PROGRAM) run -d tests/boot/boot_test.iso -p "init=init" @@ -300,7 +305,7 @@ clean: $(Q) rm -f x86/bios/bios-rom.h $(Q) rm -f tests/boot/boot_test.iso $(Q) rm -rf tests/boot/rootfs/ - $(Q) rm -f $(DEPS) $(OBJS) $(PROGRAM) $(GUEST_INIT) + $(Q) rm -f $(DEPS) $(OBJS) $(PROGRAM) $(GUEST_INIT) $(GUEST_INIT_S2) $(Q) rm -f cscope.* $(Q) rm -f $(KVM_INCLUDE)/common-cmds.h $(Q) rm -f KVMTOOLS-VERSION-FILE diff --git a/builtin-run.c b/builtin-run.c index 7969901..724be87 100644 --- a/builtin-run.c +++ b/builtin-run.c @@ -703,6 +703,31 @@ void kvm_run_help(void) usage_with_options(run_usage, options); } +static int kvm_custom_stage2(void) +{ + char tmp[PATH_MAX], dst[PATH_MAX], *src; + const char *rootfs; + int r; + + src = realpath("guest/init_stage2", NULL); + if (src == NULL) + return -ENOMEM; + + if (image_filename[0] == NULL) + rootfs = "default"; + else + rootfs = image_filename[0]; + + snprintf(tmp, PATH_MAX, "%s%s/virt/init_stage2", kvm__get_dir(), rootfs); + remove(tmp); + + snprintf(dst, PATH_MAX, "/host/%s", src); + r = symlink(dst, tmp); + free(src); + + return r; +} + int kvm_cmd_run(int argc, const char **argv, const char *prefix) { static char real_cmdline[2048], default_name[20]; @@ -869,6 +894,8 @@ int kvm_cmd_run(int argc, const char **argv, const char *prefix) strcat(real_cmdline, " init=/virt/init"); if (!no_dhcp) strcat(real_cmdline, " ip=dhcp"); + if (kvm_custom_stage2()) + die("Failed linking stage 2 of init."); } } else if (!strstr(real_cmdline, "root=")) { strlcat(real_cmdline, " root=/dev/vda rw ", sizeof(real_cmdline)); diff --git a/guest/init.c b/guest/init.c index 8975023..032a261 100644 --- a/guest/init.c +++ b/guest/init.c @@ -1,6 +1,6 @@ /* - * This is a simple init for shared rootfs guests. It brings up critical - * mountpoints and then launches /bin/sh. + * This is a simple init for shared rootfs guests. This part should be limited + * to doing mounts and running stage 2 of the init process. */ #include #include @@ -30,15 +30,7 @@ int main(int argc, char *argv[]) do_mounts(); - /* get session leader */ - setsid(); - - /* set controlling terminal */ - ioctl (0, TIOCSCTTY, 1); - - puts("Starting '/bin/sh'..."); - - run_process("/bin/sh"); + run_process("/virt/init_stage2"); printf("Init failed: %s\n", strerror(errno)); diff --git a/guest/init_stage2.c b/guest/init_stage2.c new file mode 100644 index 0000000..af615a0 --- /dev/null +++ b/guest/init_stage2.c @@ -0,0 +1,34 @@ +/* + * This is a stage 2 of the init. This part should do all the heavy + * lifting such as setting up the console and calling /bin/sh. + */ +#include +#include +#include +#include +#include + +static int run_process(char *filename) +{ + char *new_argv[] = { filename, NULL }; + char *new_env[] = { "TERM=linux", NULL }; + + return execve(filename, new_argv, new_env); +} + +int main(int argc, char *argv[]) +{ + /* get session leader */ + setsid(); + + /* set controlling terminal */ + ioctl(0, TIOCSCTTY, 1); + + puts("Starting '/bin/sh'..."); + + run_process("/bin/sh"); + + printf("Init failed: %s\n", strerror(errno)); + + return 0; +}