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