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 extern char _binary_guest_init_start; 20 extern char _binary_guest_init_size; 21 22 static const char *instance_name; 23 24 static const char * const setup_usage[] = { 25 "lkvm setup [name]", 26 NULL 27 }; 28 29 static const struct option setup_options[] = { 30 OPT_END() 31 }; 32 33 static void parse_setup_options(int argc, const char **argv) 34 { 35 while (argc != 0) { 36 argc = parse_options(argc, argv, setup_options, setup_usage, 37 PARSE_OPT_STOP_AT_NON_OPTION); 38 if (argc != 0 && instance_name) 39 kvm_setup_help(); 40 else 41 instance_name = argv[0]; 42 argv++; 43 argc--; 44 } 45 } 46 47 void kvm_setup_help(void) 48 { 49 printf("\n%s setup creates a new rootfs under %s.\n" 50 "This can be used later by the '-d' parameter of '%s run'.\n", 51 KVM_BINARY_NAME, kvm__get_dir(), KVM_BINARY_NAME); 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 "/virt/home", 116 }; 117 118 static const char *guestfs_symlinks[] = { 119 "/bin", 120 "/lib", 121 "/lib64", 122 "/sbin", 123 "/usr", 124 "/etc/ld.so.conf", 125 }; 126 127 static int copy_init(const char *guestfs_name) 128 { 129 char path[PATH_MAX]; 130 size_t size; 131 int fd, ret; 132 char *data; 133 134 size = (size_t)&_binary_guest_init_size; 135 data = (char *)&_binary_guest_init_start; 136 snprintf(path, PATH_MAX, "%s%s/virt/init", kvm__get_dir(), guestfs_name); 137 remove(path); 138 fd = open(path, O_CREAT | O_WRONLY, 0755); 139 if (fd < 0) 140 die("Fail to setup %s", path); 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 static int copy_passwd(const char *guestfs_name) 150 { 151 char path[PATH_MAX]; 152 FILE *file; 153 int ret; 154 155 snprintf(path, PATH_MAX, "%s%s/etc/passwd", kvm__get_dir(), guestfs_name); 156 157 file = fopen(path, "w"); 158 if (!file) 159 return -1; 160 161 ret = fprintf(file, "root:x:0:0:root:/root:/bin/sh\n"); 162 if (ret > 0) 163 ret = 0; 164 165 fclose(file); 166 167 return ret; 168 } 169 170 static int make_guestfs_symlink(const char *guestfs_name, const char *path) 171 { 172 char target[PATH_MAX]; 173 char name[PATH_MAX]; 174 175 snprintf(name, PATH_MAX, "%s%s%s", kvm__get_dir(), guestfs_name, path); 176 177 snprintf(target, PATH_MAX, "/host%s", path); 178 179 return symlink(target, name); 180 } 181 182 static int make_dir(const char *dir) 183 { 184 char name[PATH_MAX]; 185 186 snprintf(name, PATH_MAX, "%s%s", kvm__get_dir(), dir); 187 188 return mkdir(name, 0777); 189 } 190 191 static void make_guestfs_dir(const char *guestfs_name, const char *dir) 192 { 193 char name[PATH_MAX]; 194 195 snprintf(name, PATH_MAX, "%s%s", guestfs_name, dir); 196 197 make_dir(name); 198 } 199 200 void kvm_setup_resolv(const char *guestfs_name) 201 { 202 char path[PATH_MAX]; 203 204 snprintf(path, PATH_MAX, "%s%s/etc/resolv.conf", kvm__get_dir(), guestfs_name); 205 206 copy_file("/etc/resolv.conf", path); 207 } 208 209 static int do_setup(const char *guestfs_name) 210 { 211 unsigned int i; 212 int ret; 213 214 ret = make_dir(guestfs_name); 215 if (ret < 0) 216 return ret; 217 218 for (i = 0; i < ARRAY_SIZE(guestfs_dirs); i++) 219 make_guestfs_dir(guestfs_name, guestfs_dirs[i]); 220 221 for (i = 0; i < ARRAY_SIZE(guestfs_symlinks); i++) { 222 make_guestfs_symlink(guestfs_name, guestfs_symlinks[i]); 223 } 224 225 ret = copy_init(guestfs_name); 226 if (ret < 0) 227 return ret; 228 229 return copy_passwd(guestfs_name); 230 } 231 232 int kvm_setup_create_new(const char *guestfs_name) 233 { 234 return do_setup(guestfs_name); 235 } 236 237 int kvm_cmd_setup(int argc, const char **argv, const char *prefix) 238 { 239 int r; 240 241 parse_setup_options(argc, argv); 242 243 if (instance_name == NULL) 244 kvm_setup_help(); 245 246 r = do_setup(instance_name); 247 if (r == 0) 248 printf("A new rootfs '%s' has been created in '%s%s'.\n\n" 249 "You can now start it by running the following command:\n\n" 250 " %s run -d %s\n", 251 instance_name, kvm__get_dir(), instance_name, 252 KVM_BINARY_NAME,instance_name); 253 else 254 printf("Unable to create rootfs in %s%s: %s\n", 255 kvm__get_dir(), instance_name, strerror(errno)); 256 257 return r; 258 } 259