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