1 #include <kvm/util.h> 2 #include <kvm/kvm-cmd.h> 3 #include <kvm/builtin-setup.h> 4 #include <kvm/kvm.h> 5 #include <kvm/parse-options.h> 6 7 #include <sys/types.h> 8 #include <sys/stat.h> 9 #include <limits.h> 10 #include <signal.h> 11 #include <stdlib.h> 12 #include <string.h> 13 #include <unistd.h> 14 #include <stdio.h> 15 #include <sys/types.h> 16 #include <sys/mman.h> 17 #include <sys/stat.h> 18 #include <string.h> 19 #include <unistd.h> 20 #include <fcntl.h> 21 22 #define KVM_PID_FILE_PATH "/.kvm-tools/" 23 #define HOME_DIR getenv("HOME") 24 25 static const char *instance_name; 26 27 static const char * const setup_usage[] = { 28 "kvm setup [-n name]", 29 NULL 30 }; 31 32 static const struct option setup_options[] = { 33 OPT_GROUP("General options:"), 34 OPT_STRING('n', "name", &instance_name, "name", "Instance name"), 35 OPT_END() 36 }; 37 38 static void parse_setup_options(int argc, const char **argv) 39 { 40 while (argc != 0) { 41 argc = parse_options(argc, argv, setup_options, setup_usage, 42 PARSE_OPT_STOP_AT_NON_OPTION); 43 if (argc != 0) 44 kvm_setup_help(); 45 } 46 } 47 48 void kvm_setup_help(void) 49 { 50 printf("\nkvm setup creates a new rootfs and stores it under ~/.kvm-tools/ .\n" 51 "This can be used later by the '-d' parameter of 'kvm run'.\n"); 52 usage_with_options(setup_usage, setup_options); 53 } 54 55 static int copy_file(const char *from, const char *to) 56 { 57 int in_fd, out_fd; 58 void *src, *dst; 59 struct stat st; 60 int err = -1; 61 62 in_fd = open(from, O_RDONLY); 63 if (in_fd < 0) 64 return err; 65 66 if (fstat(in_fd, &st) < 0) 67 goto error_close_in; 68 69 out_fd = open(to, O_RDWR | O_CREAT | O_TRUNC, st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)); 70 if (out_fd < 0) 71 goto error_close_in; 72 73 src = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, in_fd, 0); 74 if (src == MAP_FAILED) 75 goto error_close_out; 76 77 if (ftruncate(out_fd, st.st_size) < 0) 78 goto error_munmap_src; 79 80 dst = mmap(NULL, st.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, out_fd, 0); 81 if (dst == MAP_FAILED) 82 goto error_munmap_src; 83 84 memcpy(dst, src, st.st_size); 85 86 if (fsync(out_fd) < 0) 87 goto error_munmap_dst; 88 89 err = 0; 90 91 error_munmap_dst: 92 munmap(dst, st.st_size); 93 error_munmap_src: 94 munmap(src, st.st_size); 95 error_close_out: 96 close(out_fd); 97 error_close_in: 98 close(in_fd); 99 100 return err; 101 } 102 103 static const char *guestfs_dirs[] = { 104 "/dev", 105 "/etc", 106 "/home", 107 "/host", 108 "/proc", 109 "/root", 110 "/sys", 111 "/tmp", 112 "/var", 113 "/var/lib", 114 "/virt", 115 }; 116 117 static const char *guestfs_symlinks[] = { 118 "/bin", 119 "/lib", 120 "/lib64", 121 "/sbin", 122 "/usr", 123 }; 124 125 static int copy_init(const char *guestfs_name) 126 { 127 char path[PATH_MAX]; 128 129 snprintf(path, PATH_MAX, "%s%s%s/virt/init", HOME_DIR, KVM_PID_FILE_PATH, guestfs_name); 130 131 return copy_file("guest/init", path); 132 } 133 134 static int make_guestfs_symlink(const char *guestfs_name, const char *path) 135 { 136 char target[PATH_MAX]; 137 char name[PATH_MAX]; 138 139 snprintf(name, PATH_MAX, "%s%s%s%s", HOME_DIR, KVM_PID_FILE_PATH, guestfs_name, path); 140 141 snprintf(target, PATH_MAX, "/host%s", path); 142 143 return symlink(target, name); 144 } 145 146 static void make_root_dir(void) 147 { 148 char name[PATH_MAX]; 149 150 snprintf(name, PATH_MAX, "%s%s", HOME_DIR, KVM_PID_FILE_PATH); 151 152 mkdir(name, 0777); 153 } 154 155 static int make_dir(const char *dir) 156 { 157 char name[PATH_MAX]; 158 159 snprintf(name, PATH_MAX, "%s%s%s", HOME_DIR, KVM_PID_FILE_PATH, dir); 160 161 return mkdir(name, 0777); 162 } 163 164 static void make_guestfs_dir(const char *guestfs_name, const char *dir) 165 { 166 char name[PATH_MAX]; 167 168 snprintf(name, PATH_MAX, "%s%s", guestfs_name, dir); 169 170 make_dir(name); 171 } 172 173 void kvm_setup_resolv(const char *guestfs_name) 174 { 175 char path[PATH_MAX]; 176 177 snprintf(path, PATH_MAX, "%s%s%s/etc/resolv.conf", HOME_DIR, KVM_PID_FILE_PATH, guestfs_name); 178 179 copy_file("/etc/resolv.conf", path); 180 } 181 182 static int do_setup(const char *guestfs_name) 183 { 184 unsigned int i; 185 int ret; 186 187 make_root_dir(); 188 189 ret = make_dir(guestfs_name); 190 if (ret < 0) 191 return ret; 192 193 for (i = 0; i < ARRAY_SIZE(guestfs_dirs); i++) 194 make_guestfs_dir(guestfs_name, guestfs_dirs[i]); 195 196 for (i = 0; i < ARRAY_SIZE(guestfs_symlinks); i++) { 197 make_guestfs_symlink(guestfs_name, guestfs_symlinks[i]); 198 } 199 200 return copy_init(guestfs_name); 201 } 202 203 int kvm_setup_create_new(const char *guestfs_name) 204 { 205 return do_setup(guestfs_name); 206 } 207 208 int kvm_cmd_setup(int argc, const char **argv, const char *prefix) 209 { 210 int r; 211 212 parse_setup_options(argc, argv); 213 214 if (instance_name == NULL) 215 kvm_setup_help(); 216 217 r = do_setup(instance_name); 218 if (r == 0) 219 pr_info("Your new rootfs named %s has been created.\n" 220 "You can now start it by running 'kvm run -d %s'\n", 221 instance_name, instance_name); 222 223 return r; 224 } 225