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