#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static const char *instance_name; static const char * const setup_usage[] = { "lkvm setup [name]", NULL }; static const struct option setup_options[] = { OPT_END() }; static void parse_setup_options(int argc, const char **argv) { while (argc != 0) { argc = parse_options(argc, argv, setup_options, setup_usage, PARSE_OPT_STOP_AT_NON_OPTION); if (argc != 0 && instance_name) kvm_setup_help(); else instance_name = argv[0]; argv++; argc--; } } void kvm_setup_help(void) { printf("\n%s setup creates a new rootfs under %s.\n" "This can be used later by the '-d' parameter of '%s run'.\n", KVM_BINARY_NAME, kvm__get_dir(), KVM_BINARY_NAME); usage_with_options(setup_usage, setup_options); } static int copy_file(const char *from, const char *to) { int in_fd, out_fd; void *src, *dst; struct stat st; int err = -1; in_fd = open(from, O_RDONLY); if (in_fd < 0) return err; if (fstat(in_fd, &st) < 0) goto error_close_in; out_fd = open(to, O_RDWR | O_CREAT | O_TRUNC, st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)); if (out_fd < 0) goto error_close_in; src = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, in_fd, 0); if (src == MAP_FAILED) goto error_close_out; if (ftruncate(out_fd, st.st_size) < 0) goto error_munmap_src; dst = mmap(NULL, st.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, out_fd, 0); if (dst == MAP_FAILED) goto error_munmap_src; memcpy(dst, src, st.st_size); if (fsync(out_fd) < 0) goto error_munmap_dst; err = 0; error_munmap_dst: munmap(dst, st.st_size); error_munmap_src: munmap(src, st.st_size); error_close_out: close(out_fd); error_close_in: close(in_fd); return err; } static const char *guestfs_dirs[] = { "/dev", "/etc", "/home", "/host", "/proc", "/root", "/sys", "/tmp", "/var", "/var/lib", "/virt", "/virt/home", }; static const char *guestfs_symlinks[] = { "/bin", "/lib", "/lib64", "/sbin", "/usr", "/etc/ld.so.conf", }; #ifdef CONFIG_GUEST_INIT static int extract_file(const char *guestfs_name, const char *filename, const void *data, size_t size) { char path[PATH_MAX]; int fd, ret; snprintf(path, PATH_MAX, "%s%s/%s", kvm__get_dir(), guestfs_name, filename); fd = open(path, O_EXCL | O_CREAT | O_WRONLY, 0755); if (fd < 0) { if (errno == EEXIST) return 0; die("Fail to setup %s", path); } ret = xwrite(fd, data, size); if (ret < 0) die("Fail to setup %s", path); close(fd); return 0; } extern unsigned char init_binary[]; extern unsigned long init_binary_size; extern unsigned char pre_init_binary[]; extern unsigned long pre_init_binary_size; int kvm_setup_guest_init(const char *guestfs_name) { int err; #ifdef CONFIG_GUEST_PRE_INIT err = extract_file(guestfs_name, "virt/pre_init", pre_init_binary, pre_init_binary_size); if (err) return err; #endif err = extract_file(guestfs_name, "virt/init", init_binary, init_binary_size); return err; } #else int kvm_setup_guest_init(const char *guestfs_name) { die("Guest init image not compiled in"); return 0; } #endif static int copy_passwd(const char *guestfs_name) { char path[PATH_MAX]; FILE *file; int ret; snprintf(path, PATH_MAX, "%s%s/etc/passwd", kvm__get_dir(), guestfs_name); file = fopen(path, "w"); if (!file) return -1; ret = fprintf(file, "root:x:0:0:root:/root:/bin/sh\n"); if (ret > 0) ret = 0; fclose(file); return ret; } static int make_guestfs_symlink(const char *guestfs_name, const char *path) { char target[PATH_MAX]; char name[PATH_MAX]; snprintf(name, PATH_MAX, "%s%s%s", kvm__get_dir(), guestfs_name, path); snprintf(target, PATH_MAX, "/host%s", path); return symlink(target, name); } static int make_dir(const char *dir) { char name[PATH_MAX]; snprintf(name, PATH_MAX, "%s%s", kvm__get_dir(), dir); return mkdir(name, 0777); } static void make_guestfs_dir(const char *guestfs_name, const char *dir) { char name[PATH_MAX]; snprintf(name, PATH_MAX, "%s%s", guestfs_name, dir); make_dir(name); } void kvm_setup_resolv(const char *guestfs_name) { char path[PATH_MAX]; snprintf(path, PATH_MAX, "%s%s/etc/resolv.conf", kvm__get_dir(), guestfs_name); copy_file("/etc/resolv.conf", path); } static int do_setup(const char *guestfs_name) { unsigned int i; int ret; ret = make_dir(guestfs_name); if (ret < 0) return ret; for (i = 0; i < ARRAY_SIZE(guestfs_dirs); i++) make_guestfs_dir(guestfs_name, guestfs_dirs[i]); for (i = 0; i < ARRAY_SIZE(guestfs_symlinks); i++) { make_guestfs_symlink(guestfs_name, guestfs_symlinks[i]); } ret = kvm_setup_guest_init(guestfs_name); if (ret < 0) return ret; return copy_passwd(guestfs_name); } int kvm_setup_create_new(const char *guestfs_name) { return do_setup(guestfs_name); } int kvm_cmd_setup(int argc, const char **argv, const char *prefix) { int r; parse_setup_options(argc, argv); if (instance_name == NULL) kvm_setup_help(); r = do_setup(instance_name); if (r == 0) { pr_info("A new rootfs '%s' has been created in '%s%s'.", instance_name, kvm__get_dir(), instance_name); pr_info("You can now start it by running the following command:"); pr_info("%s run -d %s", KVM_BINARY_NAME, instance_name); } else { pr_err("Unable to create rootfs in %s%s: %s", kvm__get_dir(), instance_name, strerror(errno)); } return r; }