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 7 #include <sys/types.h> 8 #include <sys/stat.h> 9 #include <limits.h> 10 #include <signal.h> 11 #include <stdlib.h> 12 #include <string.h> 13 #include <unistd.h> 14 #include <stdio.h> 15 #include <sys/types.h> 16 #include <sys/mman.h> 17 #include <sys/stat.h> 18 #include <string.h> 19 #include <unistd.h> 20 #include <fcntl.h> 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("\nkvm setup creates a new rootfs under %s.\n" 50 "This can be used later by the '-d' parameter of 'kvm run'.\n", 51 kvm__get_dir()); 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 }; 116 117 static const char *guestfs_symlinks[] = { 118 "/bin", 119 "/lib", 120 "/lib64", 121 "/sbin", 122 "/usr", 123 "/etc/ld.so.conf", 124 }; 125 126 static int copy_init(const char *guestfs_name) 127 { 128 char path[PATH_MAX]; 129 130 snprintf(path, PATH_MAX, "%s%s/virt/init", kvm__get_dir(), guestfs_name); 131 132 return copy_file("guest/init", path); 133 } 134 135 static int copy_passwd(const char *guestfs_name) 136 { 137 char path[PATH_MAX]; 138 139 snprintf(path, PATH_MAX, "%s%s/etc/passwd", kvm__get_dir(), guestfs_name); 140 141 return copy_file("guest/passwd", path); 142 } 143 144 static int make_guestfs_symlink(const char *guestfs_name, const char *path) 145 { 146 char target[PATH_MAX]; 147 char name[PATH_MAX]; 148 149 snprintf(name, PATH_MAX, "%s%s%s", kvm__get_dir(), guestfs_name, path); 150 151 snprintf(target, PATH_MAX, "/host%s", path); 152 153 return symlink(target, name); 154 } 155 156 static int make_dir(const char *dir) 157 { 158 char name[PATH_MAX]; 159 160 snprintf(name, PATH_MAX, "%s%s", kvm__get_dir(), dir); 161 162 return mkdir(name, 0777); 163 } 164 165 static void make_guestfs_dir(const char *guestfs_name, const char *dir) 166 { 167 char name[PATH_MAX]; 168 169 snprintf(name, PATH_MAX, "%s%s", guestfs_name, dir); 170 171 make_dir(name); 172 } 173 174 void kvm_setup_resolv(const char *guestfs_name) 175 { 176 char path[PATH_MAX]; 177 178 snprintf(path, PATH_MAX, "%s%s/etc/resolv.conf", kvm__get_dir(), guestfs_name); 179 180 copy_file("/etc/resolv.conf", path); 181 } 182 183 static int do_setup(const char *guestfs_name) 184 { 185 unsigned int i; 186 int ret; 187 188 ret = make_dir(guestfs_name); 189 if (ret < 0) 190 return ret; 191 192 for (i = 0; i < ARRAY_SIZE(guestfs_dirs); i++) 193 make_guestfs_dir(guestfs_name, guestfs_dirs[i]); 194 195 for (i = 0; i < ARRAY_SIZE(guestfs_symlinks); i++) { 196 make_guestfs_symlink(guestfs_name, guestfs_symlinks[i]); 197 } 198 199 ret = copy_init(guestfs_name); 200 if (ret < 0) 201 return ret; 202 203 return copy_passwd(guestfs_name); 204 } 205 206 int kvm_setup_create_new(const char *guestfs_name) 207 { 208 return do_setup(guestfs_name); 209 } 210 211 int kvm_cmd_setup(int argc, const char **argv, const char *prefix) 212 { 213 int r; 214 215 parse_setup_options(argc, argv); 216 217 if (instance_name == NULL) 218 kvm_setup_help(); 219 220 r = do_setup(instance_name); 221 if (r == 0) 222 printf("A new rootfs '%s' has been created in '%s%s'.\n\n" 223 "You can now start it by running the following command:\n\n" 224 " kvm run -d %s\n", 225 instance_name, kvm__get_dir(), instance_name, instance_name); 226 else 227 printf("Unable to create rootfs in %s%s: %s\n", 228 kvm__get_dir(), instance_name, strerror(errno)); 229 230 return r; 231 } 232