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> 6282113fdSPekka Enberg 7282113fdSPekka Enberg #include <sys/types.h> 8282113fdSPekka Enberg #include <sys/stat.h> 9282113fdSPekka Enberg #include <limits.h> 10282113fdSPekka Enberg #include <signal.h> 11282113fdSPekka Enberg #include <stdlib.h> 12282113fdSPekka Enberg #include <string.h> 13282113fdSPekka Enberg #include <unistd.h> 14282113fdSPekka Enberg #include <stdio.h> 15282113fdSPekka Enberg #include <sys/types.h> 16282113fdSPekka Enberg #include <sys/mman.h> 17282113fdSPekka Enberg #include <sys/stat.h> 18282113fdSPekka Enberg #include <string.h> 19282113fdSPekka Enberg #include <unistd.h> 20282113fdSPekka Enberg #include <fcntl.h> 21282113fdSPekka Enberg 22282113fdSPekka Enberg static const char *instance_name; 23282113fdSPekka Enberg 24282113fdSPekka Enberg static const char * const setup_usage[] = { 258d2ff5daSWanlong Gao "lkvm setup [name]", 26282113fdSPekka Enberg NULL 27282113fdSPekka Enberg }; 28282113fdSPekka Enberg 29282113fdSPekka Enberg static const struct option setup_options[] = { 30282113fdSPekka Enberg OPT_END() 31282113fdSPekka Enberg }; 32282113fdSPekka Enberg 33282113fdSPekka Enberg static void parse_setup_options(int argc, const char **argv) 34282113fdSPekka Enberg { 35282113fdSPekka Enberg while (argc != 0) { 36282113fdSPekka Enberg argc = parse_options(argc, argv, setup_options, setup_usage, 37282113fdSPekka Enberg PARSE_OPT_STOP_AT_NON_OPTION); 387b6d50d6SSasha Levin if (argc != 0 && instance_name) 39282113fdSPekka Enberg kvm_setup_help(); 407b6d50d6SSasha Levin else 417b6d50d6SSasha Levin instance_name = argv[0]; 427b6d50d6SSasha Levin argv++; 437b6d50d6SSasha Levin argc--; 44282113fdSPekka Enberg } 45282113fdSPekka Enberg } 46282113fdSPekka Enberg 47282113fdSPekka Enberg void kvm_setup_help(void) 48282113fdSPekka Enberg { 49ee8b1456SWanlong Gao printf("\n%s setup creates a new rootfs under %s.\n" 50ee8b1456SWanlong Gao "This can be used later by the '-d' parameter of '%s run'.\n", 51*d15572a9SPekka Enberg KVM_BINARY_NAME, kvm__get_dir(), KVM_BINARY_NAME); 52282113fdSPekka Enberg usage_with_options(setup_usage, setup_options); 53282113fdSPekka Enberg } 54282113fdSPekka Enberg 55282113fdSPekka Enberg static int copy_file(const char *from, const char *to) 56282113fdSPekka Enberg { 57282113fdSPekka Enberg int in_fd, out_fd; 58282113fdSPekka Enberg void *src, *dst; 59282113fdSPekka Enberg struct stat st; 60282113fdSPekka Enberg int err = -1; 61282113fdSPekka Enberg 62282113fdSPekka Enberg in_fd = open(from, O_RDONLY); 63282113fdSPekka Enberg if (in_fd < 0) 64282113fdSPekka Enberg return err; 65282113fdSPekka Enberg 66282113fdSPekka Enberg if (fstat(in_fd, &st) < 0) 67282113fdSPekka Enberg goto error_close_in; 68282113fdSPekka Enberg 69282113fdSPekka Enberg out_fd = open(to, O_RDWR | O_CREAT | O_TRUNC, st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)); 70282113fdSPekka Enberg if (out_fd < 0) 71282113fdSPekka Enberg goto error_close_in; 72282113fdSPekka Enberg 73282113fdSPekka Enberg src = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, in_fd, 0); 74282113fdSPekka Enberg if (src == MAP_FAILED) 75282113fdSPekka Enberg goto error_close_out; 76282113fdSPekka Enberg 77282113fdSPekka Enberg if (ftruncate(out_fd, st.st_size) < 0) 78282113fdSPekka Enberg goto error_munmap_src; 79282113fdSPekka Enberg 80282113fdSPekka Enberg dst = mmap(NULL, st.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, out_fd, 0); 81282113fdSPekka Enberg if (dst == MAP_FAILED) 82282113fdSPekka Enberg goto error_munmap_src; 83282113fdSPekka Enberg 84282113fdSPekka Enberg memcpy(dst, src, st.st_size); 85282113fdSPekka Enberg 86282113fdSPekka Enberg if (fsync(out_fd) < 0) 87282113fdSPekka Enberg goto error_munmap_dst; 88282113fdSPekka Enberg 89282113fdSPekka Enberg err = 0; 90282113fdSPekka Enberg 91282113fdSPekka Enberg error_munmap_dst: 92282113fdSPekka Enberg munmap(dst, st.st_size); 93282113fdSPekka Enberg error_munmap_src: 94282113fdSPekka Enberg munmap(src, st.st_size); 95282113fdSPekka Enberg error_close_out: 96282113fdSPekka Enberg close(out_fd); 97282113fdSPekka Enberg error_close_in: 98282113fdSPekka Enberg close(in_fd); 99282113fdSPekka Enberg 100282113fdSPekka Enberg return err; 101282113fdSPekka Enberg } 102282113fdSPekka Enberg 103282113fdSPekka Enberg static const char *guestfs_dirs[] = { 104282113fdSPekka Enberg "/dev", 105282113fdSPekka Enberg "/etc", 106282113fdSPekka Enberg "/home", 107282113fdSPekka Enberg "/host", 108282113fdSPekka Enberg "/proc", 109282113fdSPekka Enberg "/root", 110282113fdSPekka Enberg "/sys", 1114547fe2bSPekka Enberg "/tmp", 112282113fdSPekka Enberg "/var", 113282113fdSPekka Enberg "/var/lib", 114282113fdSPekka Enberg "/virt", 115282113fdSPekka Enberg }; 116282113fdSPekka Enberg 117282113fdSPekka Enberg static const char *guestfs_symlinks[] = { 118282113fdSPekka Enberg "/bin", 119282113fdSPekka Enberg "/lib", 120282113fdSPekka Enberg "/lib64", 121282113fdSPekka Enberg "/sbin", 122282113fdSPekka Enberg "/usr", 123d6080290SSasha Levin "/etc/ld.so.conf", 124282113fdSPekka Enberg }; 125282113fdSPekka Enberg 126282113fdSPekka Enberg static int copy_init(const char *guestfs_name) 127282113fdSPekka Enberg { 128282113fdSPekka Enberg char path[PATH_MAX]; 129282113fdSPekka Enberg 1309667701cSPekka Enberg snprintf(path, PATH_MAX, "%s%s/virt/init", kvm__get_dir(), guestfs_name); 131282113fdSPekka Enberg 132282113fdSPekka Enberg return copy_file("guest/init", path); 133282113fdSPekka Enberg } 134282113fdSPekka Enberg 135ce6927e8SSasha Levin static int copy_passwd(const char *guestfs_name) 136ce6927e8SSasha Levin { 137ce6927e8SSasha Levin char path[PATH_MAX]; 138ce6927e8SSasha Levin 139ce6927e8SSasha Levin snprintf(path, PATH_MAX, "%s%s/etc/passwd", kvm__get_dir(), guestfs_name); 140ce6927e8SSasha Levin 141ce6927e8SSasha Levin return copy_file("guest/passwd", path); 142ce6927e8SSasha Levin } 143ce6927e8SSasha Levin 144282113fdSPekka Enberg static int make_guestfs_symlink(const char *guestfs_name, const char *path) 145282113fdSPekka Enberg { 146282113fdSPekka Enberg char target[PATH_MAX]; 147282113fdSPekka Enberg char name[PATH_MAX]; 148282113fdSPekka Enberg 1499667701cSPekka Enberg snprintf(name, PATH_MAX, "%s%s%s", kvm__get_dir(), guestfs_name, path); 150282113fdSPekka Enberg 151282113fdSPekka Enberg snprintf(target, PATH_MAX, "/host%s", path); 152282113fdSPekka Enberg 153282113fdSPekka Enberg return symlink(target, name); 154282113fdSPekka Enberg } 155282113fdSPekka Enberg 156c8675741SSasha Levin static int make_dir(const char *dir) 157282113fdSPekka Enberg { 158282113fdSPekka Enberg char name[PATH_MAX]; 159282113fdSPekka Enberg 1609667701cSPekka Enberg snprintf(name, PATH_MAX, "%s%s", kvm__get_dir(), dir); 161282113fdSPekka Enberg 162c8675741SSasha Levin return mkdir(name, 0777); 163282113fdSPekka Enberg } 164282113fdSPekka Enberg 165282113fdSPekka Enberg static void make_guestfs_dir(const char *guestfs_name, const char *dir) 166282113fdSPekka Enberg { 167282113fdSPekka Enberg char name[PATH_MAX]; 168282113fdSPekka Enberg 169282113fdSPekka Enberg snprintf(name, PATH_MAX, "%s%s", guestfs_name, dir); 170282113fdSPekka Enberg 171282113fdSPekka Enberg make_dir(name); 172282113fdSPekka Enberg } 173282113fdSPekka Enberg 17469c88b95SSasha Levin void kvm_setup_resolv(const char *guestfs_name) 17569c88b95SSasha Levin { 17669c88b95SSasha Levin char path[PATH_MAX]; 17769c88b95SSasha Levin 1789667701cSPekka Enberg snprintf(path, PATH_MAX, "%s%s/etc/resolv.conf", kvm__get_dir(), guestfs_name); 17969c88b95SSasha Levin 18069c88b95SSasha Levin copy_file("/etc/resolv.conf", path); 18169c88b95SSasha Levin } 18269c88b95SSasha Levin 183282113fdSPekka Enberg static int do_setup(const char *guestfs_name) 184282113fdSPekka Enberg { 185282113fdSPekka Enberg unsigned int i; 18690ef0dc6SSasha Levin int ret; 187282113fdSPekka Enberg 188c8675741SSasha Levin ret = make_dir(guestfs_name); 189c8675741SSasha Levin if (ret < 0) 190c8675741SSasha Levin return ret; 191282113fdSPekka Enberg 192282113fdSPekka Enberg for (i = 0; i < ARRAY_SIZE(guestfs_dirs); i++) 193282113fdSPekka Enberg make_guestfs_dir(guestfs_name, guestfs_dirs[i]); 194282113fdSPekka Enberg 195282113fdSPekka Enberg for (i = 0; i < ARRAY_SIZE(guestfs_symlinks); i++) { 196282113fdSPekka Enberg make_guestfs_symlink(guestfs_name, guestfs_symlinks[i]); 197282113fdSPekka Enberg } 198282113fdSPekka Enberg 199ce6927e8SSasha Levin ret = copy_init(guestfs_name); 200ce6927e8SSasha Levin if (ret < 0) 201ce6927e8SSasha Levin return ret; 202ce6927e8SSasha Levin 203ce6927e8SSasha Levin return copy_passwd(guestfs_name); 204282113fdSPekka Enberg } 205282113fdSPekka Enberg 206c8675741SSasha Levin int kvm_setup_create_new(const char *guestfs_name) 207c8675741SSasha Levin { 208c8675741SSasha Levin return do_setup(guestfs_name); 209c8675741SSasha Levin } 210c8675741SSasha Levin 211282113fdSPekka Enberg int kvm_cmd_setup(int argc, const char **argv, const char *prefix) 212282113fdSPekka Enberg { 213f9613d9fSSasha Levin int r; 214f9613d9fSSasha Levin 215282113fdSPekka Enberg parse_setup_options(argc, argv); 216282113fdSPekka Enberg 217282113fdSPekka Enberg if (instance_name == NULL) 218282113fdSPekka Enberg kvm_setup_help(); 219282113fdSPekka Enberg 220f9613d9fSSasha Levin r = do_setup(instance_name); 221f9613d9fSSasha Levin if (r == 0) 222f9ea40eaSPekka Enberg printf("A new rootfs '%s' has been created in '%s%s'.\n\n" 223f9ea40eaSPekka Enberg "You can now start it by running the following command:\n\n" 224ee8b1456SWanlong Gao " %s run -d %s\n", 225ee8b1456SWanlong Gao instance_name, kvm__get_dir(), instance_name, 226ee8b1456SWanlong Gao KVM_BINARY_NAME,instance_name); 2277b6d50d6SSasha Levin else 228f9ea40eaSPekka Enberg printf("Unable to create rootfs in %s%s: %s\n", 229f9ea40eaSPekka Enberg kvm__get_dir(), instance_name, strerror(errno)); 230f9613d9fSSasha Levin 231f9613d9fSSasha Levin return r; 232282113fdSPekka Enberg } 233