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 #define KVM_PID_FILE_PATH "/.kvm-tools/" 23282113fdSPekka Enberg #define HOME_DIR getenv("HOME") 24282113fdSPekka Enberg 25282113fdSPekka Enberg static const char *instance_name; 26282113fdSPekka Enberg 27282113fdSPekka Enberg static const char * const setup_usage[] = { 28282113fdSPekka Enberg "kvm setup [-n name]", 29282113fdSPekka Enberg NULL 30282113fdSPekka Enberg }; 31282113fdSPekka Enberg 32282113fdSPekka Enberg static const struct option setup_options[] = { 33282113fdSPekka Enberg OPT_GROUP("General options:"), 34282113fdSPekka Enberg OPT_STRING('n', "name", &instance_name, "name", "Instance name"), 35282113fdSPekka Enberg OPT_END() 36282113fdSPekka Enberg }; 37282113fdSPekka Enberg 38282113fdSPekka Enberg static void parse_setup_options(int argc, const char **argv) 39282113fdSPekka Enberg { 40282113fdSPekka Enberg while (argc != 0) { 41282113fdSPekka Enberg argc = parse_options(argc, argv, setup_options, setup_usage, 42282113fdSPekka Enberg PARSE_OPT_STOP_AT_NON_OPTION); 43282113fdSPekka Enberg if (argc != 0) 44282113fdSPekka Enberg kvm_setup_help(); 45282113fdSPekka Enberg } 46282113fdSPekka Enberg } 47282113fdSPekka Enberg 48282113fdSPekka Enberg void kvm_setup_help(void) 49282113fdSPekka Enberg { 50282113fdSPekka Enberg usage_with_options(setup_usage, setup_options); 51282113fdSPekka Enberg } 52282113fdSPekka Enberg 53282113fdSPekka Enberg static int copy_file(const char *from, const char *to) 54282113fdSPekka Enberg { 55282113fdSPekka Enberg int in_fd, out_fd; 56282113fdSPekka Enberg void *src, *dst; 57282113fdSPekka Enberg struct stat st; 58282113fdSPekka Enberg int err = -1; 59282113fdSPekka Enberg 60282113fdSPekka Enberg in_fd = open(from, O_RDONLY); 61282113fdSPekka Enberg if (in_fd < 0) 62282113fdSPekka Enberg return err; 63282113fdSPekka Enberg 64282113fdSPekka Enberg if (fstat(in_fd, &st) < 0) 65282113fdSPekka Enberg goto error_close_in; 66282113fdSPekka Enberg 67282113fdSPekka Enberg out_fd = open(to, O_RDWR | O_CREAT | O_TRUNC, st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)); 68282113fdSPekka Enberg if (out_fd < 0) 69282113fdSPekka Enberg goto error_close_in; 70282113fdSPekka Enberg 71282113fdSPekka Enberg src = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, in_fd, 0); 72282113fdSPekka Enberg if (src == MAP_FAILED) 73282113fdSPekka Enberg goto error_close_out; 74282113fdSPekka Enberg 75282113fdSPekka Enberg if (ftruncate(out_fd, st.st_size) < 0) 76282113fdSPekka Enberg goto error_munmap_src; 77282113fdSPekka Enberg 78282113fdSPekka Enberg dst = mmap(NULL, st.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, out_fd, 0); 79282113fdSPekka Enberg if (dst == MAP_FAILED) 80282113fdSPekka Enberg goto error_munmap_src; 81282113fdSPekka Enberg 82282113fdSPekka Enberg memcpy(dst, src, st.st_size); 83282113fdSPekka Enberg 84282113fdSPekka Enberg if (fsync(out_fd) < 0) 85282113fdSPekka Enberg goto error_munmap_dst; 86282113fdSPekka Enberg 87282113fdSPekka Enberg err = 0; 88282113fdSPekka Enberg 89282113fdSPekka Enberg error_munmap_dst: 90282113fdSPekka Enberg munmap(dst, st.st_size); 91282113fdSPekka Enberg error_munmap_src: 92282113fdSPekka Enberg munmap(src, st.st_size); 93282113fdSPekka Enberg error_close_out: 94282113fdSPekka Enberg close(out_fd); 95282113fdSPekka Enberg error_close_in: 96282113fdSPekka Enberg close(in_fd); 97282113fdSPekka Enberg 98282113fdSPekka Enberg return err; 99282113fdSPekka Enberg } 100282113fdSPekka Enberg 101282113fdSPekka Enberg static const char *guestfs_dirs[] = { 102282113fdSPekka Enberg "/dev", 103282113fdSPekka Enberg "/etc", 104282113fdSPekka Enberg "/home", 105282113fdSPekka Enberg "/host", 106282113fdSPekka Enberg "/proc", 107282113fdSPekka Enberg "/root", 108282113fdSPekka Enberg "/sys", 1094547fe2bSPekka Enberg "/tmp", 110282113fdSPekka Enberg "/var", 111282113fdSPekka Enberg "/var/lib", 112282113fdSPekka Enberg "/virt", 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", 121282113fdSPekka Enberg }; 122282113fdSPekka Enberg 123282113fdSPekka Enberg static int copy_init(const char *guestfs_name) 124282113fdSPekka Enberg { 125282113fdSPekka Enberg char path[PATH_MAX]; 126282113fdSPekka Enberg 127282113fdSPekka Enberg snprintf(path, PATH_MAX, "%s%s%s/virt/init", HOME_DIR, KVM_PID_FILE_PATH, guestfs_name); 128282113fdSPekka Enberg 129282113fdSPekka Enberg return copy_file("guest/init", path); 130282113fdSPekka Enberg } 131282113fdSPekka Enberg 13290ef0dc6SSasha Levin static int copy_net(const char *guestfs_name) 13390ef0dc6SSasha Levin { 13490ef0dc6SSasha Levin char path[PATH_MAX]; 13590ef0dc6SSasha Levin 13690ef0dc6SSasha Levin snprintf(path, PATH_MAX, "%s%s%s/virt/setnet.sh", HOME_DIR, KVM_PID_FILE_PATH, guestfs_name); 13790ef0dc6SSasha Levin 13890ef0dc6SSasha Levin return copy_file("guest/setnet.sh", path); 13990ef0dc6SSasha Levin } 14090ef0dc6SSasha Levin 141282113fdSPekka Enberg static int make_guestfs_symlink(const char *guestfs_name, const char *path) 142282113fdSPekka Enberg { 143282113fdSPekka Enberg char target[PATH_MAX]; 144282113fdSPekka Enberg char name[PATH_MAX]; 145282113fdSPekka Enberg 146282113fdSPekka Enberg snprintf(name, PATH_MAX, "%s%s%s%s", HOME_DIR, KVM_PID_FILE_PATH, guestfs_name, path); 147282113fdSPekka Enberg 148282113fdSPekka Enberg snprintf(target, PATH_MAX, "/host%s", path); 149282113fdSPekka Enberg 150282113fdSPekka Enberg return symlink(target, name); 151282113fdSPekka Enberg } 152282113fdSPekka Enberg 1538928921aSHagen Paul Pfeifer static void make_root_dir(void) 1548928921aSHagen Paul Pfeifer { 1558928921aSHagen Paul Pfeifer char name[PATH_MAX]; 1568928921aSHagen Paul Pfeifer 1578928921aSHagen Paul Pfeifer snprintf(name, PATH_MAX, "%s%s", HOME_DIR, KVM_PID_FILE_PATH); 1588928921aSHagen Paul Pfeifer 1598928921aSHagen Paul Pfeifer mkdir(name, 0777); 1608928921aSHagen Paul Pfeifer } 1618928921aSHagen Paul Pfeifer 162*c8675741SSasha Levin static int make_dir(const char *dir) 163282113fdSPekka Enberg { 164282113fdSPekka Enberg char name[PATH_MAX]; 165282113fdSPekka Enberg 166282113fdSPekka Enberg snprintf(name, PATH_MAX, "%s%s%s", HOME_DIR, KVM_PID_FILE_PATH, dir); 167282113fdSPekka Enberg 168*c8675741SSasha Levin return mkdir(name, 0777); 169282113fdSPekka Enberg } 170282113fdSPekka Enberg 171282113fdSPekka Enberg static void make_guestfs_dir(const char *guestfs_name, const char *dir) 172282113fdSPekka Enberg { 173282113fdSPekka Enberg char name[PATH_MAX]; 174282113fdSPekka Enberg 175282113fdSPekka Enberg snprintf(name, PATH_MAX, "%s%s", guestfs_name, dir); 176282113fdSPekka Enberg 177282113fdSPekka Enberg make_dir(name); 178282113fdSPekka Enberg } 179282113fdSPekka Enberg 180282113fdSPekka Enberg static int do_setup(const char *guestfs_name) 181282113fdSPekka Enberg { 182282113fdSPekka Enberg unsigned int i; 18390ef0dc6SSasha Levin int ret; 184282113fdSPekka Enberg 1858928921aSHagen Paul Pfeifer make_root_dir(); 1868928921aSHagen Paul Pfeifer 187*c8675741SSasha Levin ret = make_dir(guestfs_name); 188*c8675741SSasha Levin if (ret < 0) 189*c8675741SSasha Levin return ret; 190282113fdSPekka Enberg 191282113fdSPekka Enberg for (i = 0; i < ARRAY_SIZE(guestfs_dirs); i++) 192282113fdSPekka Enberg make_guestfs_dir(guestfs_name, guestfs_dirs[i]); 193282113fdSPekka Enberg 194282113fdSPekka Enberg for (i = 0; i < ARRAY_SIZE(guestfs_symlinks); i++) { 195282113fdSPekka Enberg make_guestfs_symlink(guestfs_name, guestfs_symlinks[i]); 196282113fdSPekka Enberg } 197282113fdSPekka Enberg 19890ef0dc6SSasha Levin ret = copy_net(guestfs_name); 19990ef0dc6SSasha Levin if (ret < 0) 20090ef0dc6SSasha Levin return ret; 20190ef0dc6SSasha Levin 202282113fdSPekka Enberg return copy_init(guestfs_name); 203282113fdSPekka Enberg } 204282113fdSPekka Enberg 205*c8675741SSasha Levin int kvm_setup_create_new(const char *guestfs_name) 206*c8675741SSasha Levin { 207*c8675741SSasha Levin return do_setup(guestfs_name); 208*c8675741SSasha Levin } 209*c8675741SSasha Levin 210282113fdSPekka Enberg int kvm_cmd_setup(int argc, const char **argv, const char *prefix) 211282113fdSPekka Enberg { 212282113fdSPekka Enberg parse_setup_options(argc, argv); 213282113fdSPekka Enberg 214282113fdSPekka Enberg if (instance_name == NULL) 215282113fdSPekka Enberg kvm_setup_help(); 216282113fdSPekka Enberg 217282113fdSPekka Enberg return do_setup(instance_name); 218282113fdSPekka Enberg } 219