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 #include <kvm/read-write.h> 7 8 #include <sys/types.h> 9 #include <sys/stat.h> 10 #include <limits.h> 11 #include <signal.h> 12 #include <stdlib.h> 13 #include <string.h> 14 #include <unistd.h> 15 #include <stdio.h> 16 #include <sys/mman.h> 17 #include <fcntl.h> 18 19 static const char *instance_name; 20 21 static const char * const setup_usage[] = { 22 "lkvm setup [name]", 23 NULL 24 }; 25 26 static const struct option setup_options[] = { 27 OPT_END() 28 }; 29 30 static void parse_setup_options(int argc, const char **argv) 31 { 32 while (argc != 0) { 33 argc = parse_options(argc, argv, setup_options, setup_usage, 34 PARSE_OPT_STOP_AT_NON_OPTION); 35 if (argc != 0 && instance_name) 36 kvm_setup_help(); 37 else 38 instance_name = argv[0]; 39 argv++; 40 argc--; 41 } 42 } 43 44 void kvm_setup_help(void) 45 { 46 printf("\n%s setup creates a new rootfs under %s.\n" 47 "This can be used later by the '-d' parameter of '%s run'.\n", 48 KVM_BINARY_NAME, kvm__get_dir(), KVM_BINARY_NAME); 49 usage_with_options(setup_usage, setup_options); 50 } 51 52 static int copy_file(const char *from, const char *to) 53 { 54 int in_fd, out_fd; 55 void *src, *dst; 56 struct stat st; 57 int err = -1; 58 59 in_fd = open(from, O_RDONLY); 60 if (in_fd < 0) 61 return err; 62 63 if (fstat(in_fd, &st) < 0) 64 goto error_close_in; 65 66 out_fd = open(to, O_RDWR | O_CREAT | O_TRUNC, st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)); 67 if (out_fd < 0) 68 goto error_close_in; 69 70 src = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, in_fd, 0); 71 if (src == MAP_FAILED) 72 goto error_close_out; 73 74 if (ftruncate(out_fd, st.st_size) < 0) 75 goto error_munmap_src; 76 77 dst = mmap(NULL, st.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, out_fd, 0); 78 if (dst == MAP_FAILED) 79 goto error_munmap_src; 80 81 memcpy(dst, src, st.st_size); 82 83 if (fsync(out_fd) < 0) 84 goto error_munmap_dst; 85 86 err = 0; 87 88 error_munmap_dst: 89 munmap(dst, st.st_size); 90 error_munmap_src: 91 munmap(src, st.st_size); 92 error_close_out: 93 close(out_fd); 94 error_close_in: 95 close(in_fd); 96 97 return err; 98 } 99 100 static const char *guestfs_dirs[] = { 101 "/dev", 102 "/etc", 103 "/home", 104 "/host", 105 "/proc", 106 "/root", 107 "/sys", 108 "/tmp", 109 "/var", 110 "/var/lib", 111 "/virt", 112 "/virt/home", 113 }; 114 115 static const char *guestfs_symlinks[] = { 116 "/bin", 117 "/lib", 118 "/lib64", 119 "/sbin", 120 "/usr", 121 "/etc/ld.so.conf", 122 }; 123 124 #ifdef CONFIG_GUEST_INIT 125 static int extract_file(const char *guestfs_name, const char *filename, 126 const void *data, size_t size) 127 { 128 char path[PATH_MAX]; 129 int fd, ret; 130 131 snprintf(path, PATH_MAX, "%s%s/%s", kvm__get_dir(), 132 guestfs_name, filename); 133 134 fd = open(path, O_EXCL | O_CREAT | O_WRONLY, 0755); 135 if (fd < 0) { 136 if (errno == EEXIST) 137 return 0; 138 die("Fail to setup %s", path); 139 } 140 141 ret = xwrite(fd, data, size); 142 if (ret < 0) 143 die("Fail to setup %s", path); 144 close(fd); 145 146 return 0; 147 } 148 149 extern unsigned char init_binary[]; 150 extern unsigned long init_binary_size; 151 extern unsigned char pre_init_binary[]; 152 extern unsigned long pre_init_binary_size; 153 154 int kvm_setup_guest_init(const char *guestfs_name) 155 { 156 int err; 157 158 #ifdef CONFIG_GUEST_PRE_INIT 159 err = extract_file(guestfs_name, "virt/pre_init", 160 pre_init_binary, pre_init_binary_size); 161 if (err) 162 return err; 163 #endif 164 err = extract_file(guestfs_name, "virt/init", 165 init_binary, init_binary_size); 166 return err; 167 } 168 #else 169 int kvm_setup_guest_init(const char *guestfs_name) 170 { 171 die("Guest init image not compiled in"); 172 return 0; 173 } 174 #endif 175 176 static int copy_passwd(const char *guestfs_name) 177 { 178 char path[PATH_MAX]; 179 FILE *file; 180 int ret; 181 182 snprintf(path, PATH_MAX, "%s%s/etc/passwd", kvm__get_dir(), guestfs_name); 183 184 file = fopen(path, "w"); 185 if (!file) 186 return -1; 187 188 ret = fprintf(file, "root:x:0:0:root:/root:/bin/sh\n"); 189 if (ret > 0) 190 ret = 0; 191 192 fclose(file); 193 194 return ret; 195 } 196 197 static int make_guestfs_symlink(const char *guestfs_name, const char *path) 198 { 199 char target[PATH_MAX]; 200 char name[PATH_MAX]; 201 202 snprintf(name, PATH_MAX, "%s%s%s", kvm__get_dir(), guestfs_name, path); 203 204 snprintf(target, PATH_MAX, "/host%s", path); 205 206 return symlink(target, name); 207 } 208 209 static int make_dir(const char *dir) 210 { 211 char name[PATH_MAX]; 212 213 snprintf(name, PATH_MAX, "%s%s", kvm__get_dir(), dir); 214 215 return mkdir(name, 0777); 216 } 217 218 static void make_guestfs_dir(const char *guestfs_name, const char *dir) 219 { 220 char name[PATH_MAX]; 221 222 snprintf(name, PATH_MAX, "%s%s", guestfs_name, dir); 223 224 make_dir(name); 225 } 226 227 void kvm_setup_resolv(const char *guestfs_name) 228 { 229 char path[PATH_MAX]; 230 231 snprintf(path, PATH_MAX, "%s%s/etc/resolv.conf", kvm__get_dir(), guestfs_name); 232 233 copy_file("/etc/resolv.conf", path); 234 } 235 236 static int do_setup(const char *guestfs_name) 237 { 238 unsigned int i; 239 int ret; 240 241 ret = make_dir(guestfs_name); 242 if (ret < 0) 243 return ret; 244 245 for (i = 0; i < ARRAY_SIZE(guestfs_dirs); i++) 246 make_guestfs_dir(guestfs_name, guestfs_dirs[i]); 247 248 for (i = 0; i < ARRAY_SIZE(guestfs_symlinks); i++) { 249 make_guestfs_symlink(guestfs_name, guestfs_symlinks[i]); 250 } 251 252 ret = kvm_setup_guest_init(guestfs_name); 253 if (ret < 0) 254 return ret; 255 256 return copy_passwd(guestfs_name); 257 } 258 259 int kvm_setup_create_new(const char *guestfs_name) 260 { 261 return do_setup(guestfs_name); 262 } 263 264 int kvm_cmd_setup(int argc, const char **argv, const char *prefix) 265 { 266 int r; 267 268 parse_setup_options(argc, argv); 269 270 if (instance_name == NULL) 271 kvm_setup_help(); 272 273 r = do_setup(instance_name); 274 if (r == 0) 275 printf("A new rootfs '%s' has been created in '%s%s'.\n\n" 276 "You can now start it by running the following command:\n\n" 277 " %s run -d %s\n", 278 instance_name, kvm__get_dir(), instance_name, 279 KVM_BINARY_NAME,instance_name); 280 else 281 printf("Unable to create rootfs in %s%s: %s\n", 282 kvm__get_dir(), instance_name, strerror(errno)); 283 284 return r; 285 } 286