1282113fdSPekka Enberg #include <kvm/util.h> 2282113fdSPekka Enberg #include <kvm/kvm-cmd.h> 3282113fdSPekka Enberg #include <kvm/builtin-setup.h> 4282113fdSPekka Enberg #include <kvm/kvm.h> 5282113fdSPekka Enberg #include <kvm/parse-options.h> 6f20814b8SAsias He #include <kvm/read-write.h> 7282113fdSPekka Enberg 8282113fdSPekka Enberg #include <sys/types.h> 9282113fdSPekka Enberg #include <sys/stat.h> 10282113fdSPekka Enberg #include <limits.h> 11282113fdSPekka Enberg #include <signal.h> 12282113fdSPekka Enberg #include <stdlib.h> 13282113fdSPekka Enberg #include <string.h> 14282113fdSPekka Enberg #include <unistd.h> 15282113fdSPekka Enberg #include <stdio.h> 16282113fdSPekka Enberg #include <sys/mman.h> 17282113fdSPekka Enberg #include <fcntl.h> 18282113fdSPekka Enberg 19282113fdSPekka Enberg static const char *instance_name; 20282113fdSPekka Enberg 21282113fdSPekka Enberg static const char * const setup_usage[] = { 228d2ff5daSWanlong Gao "lkvm setup [name]", 23282113fdSPekka Enberg NULL 24282113fdSPekka Enberg }; 25282113fdSPekka Enberg 26282113fdSPekka Enberg static const struct option setup_options[] = { 27282113fdSPekka Enberg OPT_END() 28282113fdSPekka Enberg }; 29282113fdSPekka Enberg 30282113fdSPekka Enberg static void parse_setup_options(int argc, const char **argv) 31282113fdSPekka Enberg { 32282113fdSPekka Enberg while (argc != 0) { 33282113fdSPekka Enberg argc = parse_options(argc, argv, setup_options, setup_usage, 34282113fdSPekka Enberg PARSE_OPT_STOP_AT_NON_OPTION); 357b6d50d6SSasha Levin if (argc != 0 && instance_name) 36282113fdSPekka Enberg kvm_setup_help(); 377b6d50d6SSasha Levin else 387b6d50d6SSasha Levin instance_name = argv[0]; 397b6d50d6SSasha Levin argv++; 407b6d50d6SSasha Levin argc--; 41282113fdSPekka Enberg } 42282113fdSPekka Enberg } 43282113fdSPekka Enberg 44282113fdSPekka Enberg void kvm_setup_help(void) 45282113fdSPekka Enberg { 46ee8b1456SWanlong Gao printf("\n%s setup creates a new rootfs under %s.\n" 47ee8b1456SWanlong Gao "This can be used later by the '-d' parameter of '%s run'.\n", 48d15572a9SPekka Enberg KVM_BINARY_NAME, kvm__get_dir(), KVM_BINARY_NAME); 49282113fdSPekka Enberg usage_with_options(setup_usage, setup_options); 50282113fdSPekka Enberg } 51282113fdSPekka Enberg 52282113fdSPekka Enberg static int copy_file(const char *from, const char *to) 53282113fdSPekka Enberg { 54282113fdSPekka Enberg int in_fd, out_fd; 55282113fdSPekka Enberg void *src, *dst; 56282113fdSPekka Enberg struct stat st; 57282113fdSPekka Enberg int err = -1; 58282113fdSPekka Enberg 59282113fdSPekka Enberg in_fd = open(from, O_RDONLY); 60282113fdSPekka Enberg if (in_fd < 0) 61282113fdSPekka Enberg return err; 62282113fdSPekka Enberg 63282113fdSPekka Enberg if (fstat(in_fd, &st) < 0) 64282113fdSPekka Enberg goto error_close_in; 65282113fdSPekka Enberg 66282113fdSPekka Enberg out_fd = open(to, O_RDWR | O_CREAT | O_TRUNC, st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)); 67282113fdSPekka Enberg if (out_fd < 0) 68282113fdSPekka Enberg goto error_close_in; 69282113fdSPekka Enberg 70282113fdSPekka Enberg src = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, in_fd, 0); 71282113fdSPekka Enberg if (src == MAP_FAILED) 72282113fdSPekka Enberg goto error_close_out; 73282113fdSPekka Enberg 74282113fdSPekka Enberg if (ftruncate(out_fd, st.st_size) < 0) 75282113fdSPekka Enberg goto error_munmap_src; 76282113fdSPekka Enberg 77282113fdSPekka Enberg dst = mmap(NULL, st.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, out_fd, 0); 78282113fdSPekka Enberg if (dst == MAP_FAILED) 79282113fdSPekka Enberg goto error_munmap_src; 80282113fdSPekka Enberg 81282113fdSPekka Enberg memcpy(dst, src, st.st_size); 82282113fdSPekka Enberg 83282113fdSPekka Enberg if (fsync(out_fd) < 0) 84282113fdSPekka Enberg goto error_munmap_dst; 85282113fdSPekka Enberg 86282113fdSPekka Enberg err = 0; 87282113fdSPekka Enberg 88282113fdSPekka Enberg error_munmap_dst: 89282113fdSPekka Enberg munmap(dst, st.st_size); 90282113fdSPekka Enberg error_munmap_src: 91282113fdSPekka Enberg munmap(src, st.st_size); 92282113fdSPekka Enberg error_close_out: 93282113fdSPekka Enberg close(out_fd); 94282113fdSPekka Enberg error_close_in: 95282113fdSPekka Enberg close(in_fd); 96282113fdSPekka Enberg 97282113fdSPekka Enberg return err; 98282113fdSPekka Enberg } 99282113fdSPekka Enberg 100282113fdSPekka Enberg static const char *guestfs_dirs[] = { 101282113fdSPekka Enberg "/dev", 102282113fdSPekka Enberg "/etc", 103282113fdSPekka Enberg "/home", 104282113fdSPekka Enberg "/host", 105282113fdSPekka Enberg "/proc", 106282113fdSPekka Enberg "/root", 107282113fdSPekka Enberg "/sys", 1084547fe2bSPekka Enberg "/tmp", 109282113fdSPekka Enberg "/var", 110282113fdSPekka Enberg "/var/lib", 111282113fdSPekka Enberg "/virt", 1125fab5964SSasha Levin "/virt/home", 113282113fdSPekka Enberg }; 114282113fdSPekka Enberg 115282113fdSPekka Enberg static const char *guestfs_symlinks[] = { 116282113fdSPekka Enberg "/bin", 117282113fdSPekka Enberg "/lib", 118282113fdSPekka Enberg "/lib64", 119282113fdSPekka Enberg "/sbin", 120282113fdSPekka Enberg "/usr", 121d6080290SSasha Levin "/etc/ld.so.conf", 122282113fdSPekka Enberg }; 123282113fdSPekka Enberg 124cdce942cSDimitri John Ledkov #ifdef CONFIG_GUEST_INIT 12526e94dc4SOleg Nesterov static int extract_file(const char *guestfs_name, const char *filename, 12626e94dc4SOleg Nesterov const void *data, const void *_size) 127282113fdSPekka Enberg { 128282113fdSPekka Enberg char path[PATH_MAX]; 129f20814b8SAsias He int fd, ret; 130282113fdSPekka Enberg 13126e94dc4SOleg Nesterov snprintf(path, PATH_MAX, "%s%s/%s", kvm__get_dir(), 13226e94dc4SOleg Nesterov guestfs_name, filename); 133*30867c55SOleg Nesterov 134*30867c55SOleg Nesterov fd = open(path, O_EXCL | O_CREAT | O_WRONLY, 0755); 135*30867c55SOleg Nesterov if (fd < 0) { 136*30867c55SOleg Nesterov if (errno == EEXIST) 137*30867c55SOleg Nesterov return 0; 138f20814b8SAsias He die("Fail to setup %s", path); 139*30867c55SOleg Nesterov } 140*30867c55SOleg Nesterov 14126e94dc4SOleg Nesterov ret = xwrite(fd, data, (size_t)_size); 142f20814b8SAsias He if (ret < 0) 143f20814b8SAsias He die("Fail to setup %s", path); 144f20814b8SAsias He close(fd); 145282113fdSPekka Enberg 146f20814b8SAsias He return 0; 14726e94dc4SOleg Nesterov } 148cdce942cSDimitri John Ledkov 14926e94dc4SOleg Nesterov extern char _binary_guest_init_start; 15026e94dc4SOleg Nesterov extern char _binary_guest_init_size; 1515614f9d9SOleg Nesterov extern char _binary_guest_pre_init_start; 1525614f9d9SOleg Nesterov extern char _binary_guest_pre_init_size; 15326e94dc4SOleg Nesterov 15426e94dc4SOleg Nesterov int kvm_setup_guest_init(const char *guestfs_name) 15526e94dc4SOleg Nesterov { 1565614f9d9SOleg Nesterov int err; 1575614f9d9SOleg Nesterov 1585614f9d9SOleg Nesterov #ifdef CONFIG_GUEST_PRE_INIT 1595614f9d9SOleg Nesterov err = extract_file(guestfs_name, "virt/pre_init", 1605614f9d9SOleg Nesterov &_binary_guest_pre_init_start, 1615614f9d9SOleg Nesterov &_binary_guest_pre_init_size); 1625614f9d9SOleg Nesterov if (err) 1635614f9d9SOleg Nesterov return err; 1645614f9d9SOleg Nesterov #endif 1655614f9d9SOleg Nesterov err = extract_file(guestfs_name, "virt/init", 16626e94dc4SOleg Nesterov &_binary_guest_init_start, 16726e94dc4SOleg Nesterov &_binary_guest_init_size); 1685614f9d9SOleg Nesterov return err; 169282113fdSPekka Enberg } 170cdce942cSDimitri John Ledkov #else 171cdce942cSDimitri John Ledkov int kvm_setup_guest_init(const char *guestfs_name) 172cdce942cSDimitri John Ledkov { 173cdce942cSDimitri John Ledkov die("Guest init image not compiled in"); 174cdce942cSDimitri John Ledkov return 0; 175cdce942cSDimitri John Ledkov } 176cdce942cSDimitri John Ledkov #endif 177282113fdSPekka Enberg 178ce6927e8SSasha Levin static int copy_passwd(const char *guestfs_name) 179ce6927e8SSasha Levin { 180ce6927e8SSasha Levin char path[PATH_MAX]; 181f20814b8SAsias He FILE *file; 182f20814b8SAsias He int ret; 183ce6927e8SSasha Levin 184ce6927e8SSasha Levin snprintf(path, PATH_MAX, "%s%s/etc/passwd", kvm__get_dir(), guestfs_name); 185ce6927e8SSasha Levin 186f20814b8SAsias He file = fopen(path, "w"); 187f20814b8SAsias He if (!file) 188f20814b8SAsias He return -1; 189f20814b8SAsias He 190f20814b8SAsias He ret = fprintf(file, "root:x:0:0:root:/root:/bin/sh\n"); 19163fd57b9SCong Ding if (ret > 0) 19263fd57b9SCong Ding ret = 0; 193f20814b8SAsias He 194f20814b8SAsias He fclose(file); 195f20814b8SAsias He 19663fd57b9SCong Ding return ret; 197ce6927e8SSasha Levin } 198ce6927e8SSasha Levin 199282113fdSPekka Enberg static int make_guestfs_symlink(const char *guestfs_name, const char *path) 200282113fdSPekka Enberg { 201282113fdSPekka Enberg char target[PATH_MAX]; 202282113fdSPekka Enberg char name[PATH_MAX]; 203282113fdSPekka Enberg 2049667701cSPekka Enberg snprintf(name, PATH_MAX, "%s%s%s", kvm__get_dir(), guestfs_name, path); 205282113fdSPekka Enberg 206282113fdSPekka Enberg snprintf(target, PATH_MAX, "/host%s", path); 207282113fdSPekka Enberg 208282113fdSPekka Enberg return symlink(target, name); 209282113fdSPekka Enberg } 210282113fdSPekka Enberg 211c8675741SSasha Levin static int make_dir(const char *dir) 212282113fdSPekka Enberg { 213282113fdSPekka Enberg char name[PATH_MAX]; 214282113fdSPekka Enberg 2159667701cSPekka Enberg snprintf(name, PATH_MAX, "%s%s", kvm__get_dir(), dir); 216282113fdSPekka Enberg 217c8675741SSasha Levin return mkdir(name, 0777); 218282113fdSPekka Enberg } 219282113fdSPekka Enberg 220282113fdSPekka Enberg static void make_guestfs_dir(const char *guestfs_name, const char *dir) 221282113fdSPekka Enberg { 222282113fdSPekka Enberg char name[PATH_MAX]; 223282113fdSPekka Enberg 224282113fdSPekka Enberg snprintf(name, PATH_MAX, "%s%s", guestfs_name, dir); 225282113fdSPekka Enberg 226282113fdSPekka Enberg make_dir(name); 227282113fdSPekka Enberg } 228282113fdSPekka Enberg 22969c88b95SSasha Levin void kvm_setup_resolv(const char *guestfs_name) 23069c88b95SSasha Levin { 23169c88b95SSasha Levin char path[PATH_MAX]; 23269c88b95SSasha Levin 2339667701cSPekka Enberg snprintf(path, PATH_MAX, "%s%s/etc/resolv.conf", kvm__get_dir(), guestfs_name); 23469c88b95SSasha Levin 23569c88b95SSasha Levin copy_file("/etc/resolv.conf", path); 23669c88b95SSasha Levin } 23769c88b95SSasha Levin 238282113fdSPekka Enberg static int do_setup(const char *guestfs_name) 239282113fdSPekka Enberg { 240282113fdSPekka Enberg unsigned int i; 24190ef0dc6SSasha Levin int ret; 242282113fdSPekka Enberg 243c8675741SSasha Levin ret = make_dir(guestfs_name); 244c8675741SSasha Levin if (ret < 0) 245c8675741SSasha Levin return ret; 246282113fdSPekka Enberg 247282113fdSPekka Enberg for (i = 0; i < ARRAY_SIZE(guestfs_dirs); i++) 248282113fdSPekka Enberg make_guestfs_dir(guestfs_name, guestfs_dirs[i]); 249282113fdSPekka Enberg 250282113fdSPekka Enberg for (i = 0; i < ARRAY_SIZE(guestfs_symlinks); i++) { 251282113fdSPekka Enberg make_guestfs_symlink(guestfs_name, guestfs_symlinks[i]); 252282113fdSPekka Enberg } 253282113fdSPekka Enberg 254cdce942cSDimitri John Ledkov ret = kvm_setup_guest_init(guestfs_name); 255ce6927e8SSasha Levin if (ret < 0) 256ce6927e8SSasha Levin return ret; 257ce6927e8SSasha Levin 258ce6927e8SSasha Levin return copy_passwd(guestfs_name); 259282113fdSPekka Enberg } 260282113fdSPekka Enberg 261c8675741SSasha Levin int kvm_setup_create_new(const char *guestfs_name) 262c8675741SSasha Levin { 263c8675741SSasha Levin return do_setup(guestfs_name); 264c8675741SSasha Levin } 265c8675741SSasha Levin 266282113fdSPekka Enberg int kvm_cmd_setup(int argc, const char **argv, const char *prefix) 267282113fdSPekka Enberg { 268f9613d9fSSasha Levin int r; 269f9613d9fSSasha Levin 270282113fdSPekka Enberg parse_setup_options(argc, argv); 271282113fdSPekka Enberg 272282113fdSPekka Enberg if (instance_name == NULL) 273282113fdSPekka Enberg kvm_setup_help(); 274282113fdSPekka Enberg 275f9613d9fSSasha Levin r = do_setup(instance_name); 276f9613d9fSSasha Levin if (r == 0) 277f9ea40eaSPekka Enberg printf("A new rootfs '%s' has been created in '%s%s'.\n\n" 278f9ea40eaSPekka Enberg "You can now start it by running the following command:\n\n" 279ee8b1456SWanlong Gao " %s run -d %s\n", 280ee8b1456SWanlong Gao instance_name, kvm__get_dir(), instance_name, 281ee8b1456SWanlong Gao KVM_BINARY_NAME,instance_name); 2827b6d50d6SSasha Levin else 283f9ea40eaSPekka Enberg printf("Unable to create rootfs in %s%s: %s\n", 284f9ea40eaSPekka Enberg kvm__get_dir(), instance_name, strerror(errno)); 285f9613d9fSSasha Levin 286f9613d9fSSasha Levin return r; 287282113fdSPekka Enberg } 288