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, const void *_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 remove(path); 134 fd = open(path, O_CREAT | O_WRONLY, 0755); 135 if (fd < 0) 136 die("Fail to setup %s", path); 137 ret = xwrite(fd, data, (size_t)_size); 138 if (ret < 0) 139 die("Fail to setup %s", path); 140 close(fd); 141 142 return 0; 143 } 144 145 extern char _binary_guest_init_start; 146 extern char _binary_guest_init_size; 147 148 int kvm_setup_guest_init(const char *guestfs_name) 149 { 150 return extract_file(guestfs_name, "virt/init", 151 &_binary_guest_init_start, 152 &_binary_guest_init_size); 153 } 154 #else 155 int kvm_setup_guest_init(const char *guestfs_name) 156 { 157 die("Guest init image not compiled in"); 158 return 0; 159 } 160 #endif 161 162 static int copy_passwd(const char *guestfs_name) 163 { 164 char path[PATH_MAX]; 165 FILE *file; 166 int ret; 167 168 snprintf(path, PATH_MAX, "%s%s/etc/passwd", kvm__get_dir(), guestfs_name); 169 170 file = fopen(path, "w"); 171 if (!file) 172 return -1; 173 174 ret = fprintf(file, "root:x:0:0:root:/root:/bin/sh\n"); 175 if (ret > 0) 176 ret = 0; 177 178 fclose(file); 179 180 return ret; 181 } 182 183 static int make_guestfs_symlink(const char *guestfs_name, const char *path) 184 { 185 char target[PATH_MAX]; 186 char name[PATH_MAX]; 187 188 snprintf(name, PATH_MAX, "%s%s%s", kvm__get_dir(), guestfs_name, path); 189 190 snprintf(target, PATH_MAX, "/host%s", path); 191 192 return symlink(target, name); 193 } 194 195 static int make_dir(const char *dir) 196 { 197 char name[PATH_MAX]; 198 199 snprintf(name, PATH_MAX, "%s%s", kvm__get_dir(), dir); 200 201 return mkdir(name, 0777); 202 } 203 204 static void make_guestfs_dir(const char *guestfs_name, const char *dir) 205 { 206 char name[PATH_MAX]; 207 208 snprintf(name, PATH_MAX, "%s%s", guestfs_name, dir); 209 210 make_dir(name); 211 } 212 213 void kvm_setup_resolv(const char *guestfs_name) 214 { 215 char path[PATH_MAX]; 216 217 snprintf(path, PATH_MAX, "%s%s/etc/resolv.conf", kvm__get_dir(), guestfs_name); 218 219 copy_file("/etc/resolv.conf", path); 220 } 221 222 static int do_setup(const char *guestfs_name) 223 { 224 unsigned int i; 225 int ret; 226 227 ret = make_dir(guestfs_name); 228 if (ret < 0) 229 return ret; 230 231 for (i = 0; i < ARRAY_SIZE(guestfs_dirs); i++) 232 make_guestfs_dir(guestfs_name, guestfs_dirs[i]); 233 234 for (i = 0; i < ARRAY_SIZE(guestfs_symlinks); i++) { 235 make_guestfs_symlink(guestfs_name, guestfs_symlinks[i]); 236 } 237 238 ret = kvm_setup_guest_init(guestfs_name); 239 if (ret < 0) 240 return ret; 241 242 return copy_passwd(guestfs_name); 243 } 244 245 int kvm_setup_create_new(const char *guestfs_name) 246 { 247 return do_setup(guestfs_name); 248 } 249 250 int kvm_cmd_setup(int argc, const char **argv, const char *prefix) 251 { 252 int r; 253 254 parse_setup_options(argc, argv); 255 256 if (instance_name == NULL) 257 kvm_setup_help(); 258 259 r = do_setup(instance_name); 260 if (r == 0) 261 printf("A new rootfs '%s' has been created in '%s%s'.\n\n" 262 "You can now start it by running the following command:\n\n" 263 " %s run -d %s\n", 264 instance_name, kvm__get_dir(), instance_name, 265 KVM_BINARY_NAME,instance_name); 266 else 267 printf("Unable to create rootfs in %s%s: %s\n", 268 kvm__get_dir(), instance_name, strerror(errno)); 269 270 return r; 271 } 272