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