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 #define KVM_PID_FILE_PATH "/.kvm-tools/" 23 #define HOME_DIR getenv("HOME") 24 25 static const char *instance_name; 26 27 static const char * const setup_usage[] = { 28 "kvm setup [name]", 29 NULL 30 }; 31 32 static const struct option setup_options[] = { 33 OPT_END() 34 }; 35 36 static void parse_setup_options(int argc, const char **argv) 37 { 38 while (argc != 0) { 39 argc = parse_options(argc, argv, setup_options, setup_usage, 40 PARSE_OPT_STOP_AT_NON_OPTION); 41 if (argc != 0 && instance_name) 42 kvm_setup_help(); 43 else 44 instance_name = argv[0]; 45 argv++; 46 argc--; 47 } 48 } 49 50 void kvm_setup_help(void) 51 { 52 printf("\nkvm setup creates a new rootfs and stores it under ~/.kvm-tools/ .\n" 53 "This can be used later by the '-d' parameter of 'kvm run'.\n"); 54 usage_with_options(setup_usage, setup_options); 55 } 56 57 static int copy_file(const char *from, const char *to) 58 { 59 int in_fd, out_fd; 60 void *src, *dst; 61 struct stat st; 62 int err = -1; 63 64 in_fd = open(from, O_RDONLY); 65 if (in_fd < 0) 66 return err; 67 68 if (fstat(in_fd, &st) < 0) 69 goto error_close_in; 70 71 out_fd = open(to, O_RDWR | O_CREAT | O_TRUNC, st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)); 72 if (out_fd < 0) 73 goto error_close_in; 74 75 src = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, in_fd, 0); 76 if (src == MAP_FAILED) 77 goto error_close_out; 78 79 if (ftruncate(out_fd, st.st_size) < 0) 80 goto error_munmap_src; 81 82 dst = mmap(NULL, st.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, out_fd, 0); 83 if (dst == MAP_FAILED) 84 goto error_munmap_src; 85 86 memcpy(dst, src, st.st_size); 87 88 if (fsync(out_fd) < 0) 89 goto error_munmap_dst; 90 91 err = 0; 92 93 error_munmap_dst: 94 munmap(dst, st.st_size); 95 error_munmap_src: 96 munmap(src, st.st_size); 97 error_close_out: 98 close(out_fd); 99 error_close_in: 100 close(in_fd); 101 102 return err; 103 } 104 105 static const char *guestfs_dirs[] = { 106 "/dev", 107 "/etc", 108 "/home", 109 "/host", 110 "/proc", 111 "/root", 112 "/sys", 113 "/tmp", 114 "/var", 115 "/var/lib", 116 "/virt", 117 }; 118 119 static const char *guestfs_symlinks[] = { 120 "/bin", 121 "/lib", 122 "/lib64", 123 "/sbin", 124 "/usr", 125 }; 126 127 static int copy_init(const char *guestfs_name) 128 { 129 char path[PATH_MAX]; 130 131 snprintf(path, PATH_MAX, "%s%s%s/virt/init", HOME_DIR, KVM_PID_FILE_PATH, guestfs_name); 132 133 return copy_file("guest/init", path); 134 } 135 136 static int make_guestfs_symlink(const char *guestfs_name, const char *path) 137 { 138 char target[PATH_MAX]; 139 char name[PATH_MAX]; 140 141 snprintf(name, PATH_MAX, "%s%s%s%s", HOME_DIR, KVM_PID_FILE_PATH, guestfs_name, path); 142 143 snprintf(target, PATH_MAX, "/host%s", path); 144 145 return symlink(target, name); 146 } 147 148 static void make_root_dir(void) 149 { 150 char name[PATH_MAX]; 151 152 snprintf(name, PATH_MAX, "%s%s", HOME_DIR, KVM_PID_FILE_PATH); 153 154 mkdir(name, 0777); 155 } 156 157 static int make_dir(const char *dir) 158 { 159 char name[PATH_MAX]; 160 161 snprintf(name, PATH_MAX, "%s%s%s", HOME_DIR, KVM_PID_FILE_PATH, dir); 162 163 return mkdir(name, 0777); 164 } 165 166 static void make_guestfs_dir(const char *guestfs_name, const char *dir) 167 { 168 char name[PATH_MAX]; 169 170 snprintf(name, PATH_MAX, "%s%s", guestfs_name, dir); 171 172 make_dir(name); 173 } 174 175 void kvm_setup_resolv(const char *guestfs_name) 176 { 177 char path[PATH_MAX]; 178 179 snprintf(path, PATH_MAX, "%s%s%s/etc/resolv.conf", HOME_DIR, KVM_PID_FILE_PATH, guestfs_name); 180 181 copy_file("/etc/resolv.conf", path); 182 } 183 184 static int do_setup(const char *guestfs_name) 185 { 186 unsigned int i; 187 int ret; 188 189 make_root_dir(); 190 191 ret = make_dir(guestfs_name); 192 if (ret < 0) 193 return ret; 194 195 for (i = 0; i < ARRAY_SIZE(guestfs_dirs); i++) 196 make_guestfs_dir(guestfs_name, guestfs_dirs[i]); 197 198 for (i = 0; i < ARRAY_SIZE(guestfs_symlinks); i++) { 199 make_guestfs_symlink(guestfs_name, guestfs_symlinks[i]); 200 } 201 202 return copy_init(guestfs_name); 203 } 204 205 int kvm_setup_create_new(const char *guestfs_name) 206 { 207 return do_setup(guestfs_name); 208 } 209 210 int kvm_cmd_setup(int argc, const char **argv, const char *prefix) 211 { 212 int r; 213 214 parse_setup_options(argc, argv); 215 216 if (instance_name == NULL) 217 kvm_setup_help(); 218 219 r = do_setup(instance_name); 220 if (r == 0) 221 pr_info("Your new rootfs named %s has been created.\n" 222 "You can now start it by running 'kvm run -d %s'\n", 223 instance_name, instance_name); 224 else 225 perror("Error creating rootfs"); 226 227 return r; 228 } 229