xref: /kvmtool/builtin-setup.c (revision 5614f9d933c9fac94886fe359f807a60acda3fa4)
1282113fdSPekka Enberg #include <kvm/util.h>
2282113fdSPekka Enberg #include <kvm/kvm-cmd.h>
3282113fdSPekka Enberg #include <kvm/builtin-setup.h>
4282113fdSPekka Enberg #include <kvm/kvm.h>
5282113fdSPekka Enberg #include <kvm/parse-options.h>
6f20814b8SAsias He #include <kvm/read-write.h>
7282113fdSPekka Enberg 
8282113fdSPekka Enberg #include <sys/types.h>
9282113fdSPekka Enberg #include <sys/stat.h>
10282113fdSPekka Enberg #include <limits.h>
11282113fdSPekka Enberg #include <signal.h>
12282113fdSPekka Enberg #include <stdlib.h>
13282113fdSPekka Enberg #include <string.h>
14282113fdSPekka Enberg #include <unistd.h>
15282113fdSPekka Enberg #include <stdio.h>
16282113fdSPekka Enberg #include <sys/mman.h>
17282113fdSPekka Enberg #include <fcntl.h>
18282113fdSPekka Enberg 
19282113fdSPekka Enberg static const char *instance_name;
20282113fdSPekka Enberg 
21282113fdSPekka Enberg static const char * const setup_usage[] = {
228d2ff5daSWanlong Gao 	"lkvm setup [name]",
23282113fdSPekka Enberg 	NULL
24282113fdSPekka Enberg };
25282113fdSPekka Enberg 
26282113fdSPekka Enberg static const struct option setup_options[] = {
27282113fdSPekka Enberg 	OPT_END()
28282113fdSPekka Enberg };
29282113fdSPekka Enberg 
30282113fdSPekka Enberg static void parse_setup_options(int argc, const char **argv)
31282113fdSPekka Enberg {
32282113fdSPekka Enberg 	while (argc != 0) {
33282113fdSPekka Enberg 		argc = parse_options(argc, argv, setup_options, setup_usage,
34282113fdSPekka Enberg 				PARSE_OPT_STOP_AT_NON_OPTION);
357b6d50d6SSasha Levin 		if (argc != 0 && instance_name)
36282113fdSPekka Enberg 			kvm_setup_help();
377b6d50d6SSasha Levin 		else
387b6d50d6SSasha Levin 			instance_name = argv[0];
397b6d50d6SSasha Levin 		argv++;
407b6d50d6SSasha Levin 		argc--;
41282113fdSPekka Enberg 	}
42282113fdSPekka Enberg }
43282113fdSPekka Enberg 
44282113fdSPekka Enberg void kvm_setup_help(void)
45282113fdSPekka Enberg {
46ee8b1456SWanlong Gao 	printf("\n%s setup creates a new rootfs under %s.\n"
47ee8b1456SWanlong Gao 		"This can be used later by the '-d' parameter of '%s run'.\n",
48d15572a9SPekka Enberg 		KVM_BINARY_NAME, kvm__get_dir(), KVM_BINARY_NAME);
49282113fdSPekka Enberg 	usage_with_options(setup_usage, setup_options);
50282113fdSPekka Enberg }
51282113fdSPekka Enberg 
52282113fdSPekka Enberg static int copy_file(const char *from, const char *to)
53282113fdSPekka Enberg {
54282113fdSPekka Enberg 	int in_fd, out_fd;
55282113fdSPekka Enberg 	void *src, *dst;
56282113fdSPekka Enberg 	struct stat st;
57282113fdSPekka Enberg 	int err = -1;
58282113fdSPekka Enberg 
59282113fdSPekka Enberg 	in_fd = open(from, O_RDONLY);
60282113fdSPekka Enberg 	if (in_fd < 0)
61282113fdSPekka Enberg 		return err;
62282113fdSPekka Enberg 
63282113fdSPekka Enberg 	if (fstat(in_fd, &st) < 0)
64282113fdSPekka Enberg 		goto error_close_in;
65282113fdSPekka Enberg 
66282113fdSPekka Enberg 	out_fd = open(to, O_RDWR | O_CREAT | O_TRUNC, st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO));
67282113fdSPekka Enberg 	if (out_fd < 0)
68282113fdSPekka Enberg 		goto error_close_in;
69282113fdSPekka Enberg 
70282113fdSPekka Enberg 	src = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, in_fd, 0);
71282113fdSPekka Enberg 	if (src == MAP_FAILED)
72282113fdSPekka Enberg 		goto error_close_out;
73282113fdSPekka Enberg 
74282113fdSPekka Enberg 	if (ftruncate(out_fd, st.st_size) < 0)
75282113fdSPekka Enberg 		goto error_munmap_src;
76282113fdSPekka Enberg 
77282113fdSPekka Enberg 	dst = mmap(NULL, st.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, out_fd, 0);
78282113fdSPekka Enberg 	if (dst == MAP_FAILED)
79282113fdSPekka Enberg 		goto error_munmap_src;
80282113fdSPekka Enberg 
81282113fdSPekka Enberg 	memcpy(dst, src, st.st_size);
82282113fdSPekka Enberg 
83282113fdSPekka Enberg 	if (fsync(out_fd) < 0)
84282113fdSPekka Enberg 		goto error_munmap_dst;
85282113fdSPekka Enberg 
86282113fdSPekka Enberg 	err = 0;
87282113fdSPekka Enberg 
88282113fdSPekka Enberg error_munmap_dst:
89282113fdSPekka Enberg 	munmap(dst, st.st_size);
90282113fdSPekka Enberg error_munmap_src:
91282113fdSPekka Enberg 	munmap(src, st.st_size);
92282113fdSPekka Enberg error_close_out:
93282113fdSPekka Enberg 	close(out_fd);
94282113fdSPekka Enberg error_close_in:
95282113fdSPekka Enberg 	close(in_fd);
96282113fdSPekka Enberg 
97282113fdSPekka Enberg 	return err;
98282113fdSPekka Enberg }
99282113fdSPekka Enberg 
100282113fdSPekka Enberg static const char *guestfs_dirs[] = {
101282113fdSPekka Enberg 	"/dev",
102282113fdSPekka Enberg 	"/etc",
103282113fdSPekka Enberg 	"/home",
104282113fdSPekka Enberg 	"/host",
105282113fdSPekka Enberg 	"/proc",
106282113fdSPekka Enberg 	"/root",
107282113fdSPekka Enberg 	"/sys",
1084547fe2bSPekka Enberg 	"/tmp",
109282113fdSPekka Enberg 	"/var",
110282113fdSPekka Enberg 	"/var/lib",
111282113fdSPekka Enberg 	"/virt",
1125fab5964SSasha Levin 	"/virt/home",
113282113fdSPekka Enberg };
114282113fdSPekka Enberg 
115282113fdSPekka Enberg static const char *guestfs_symlinks[] = {
116282113fdSPekka Enberg 	"/bin",
117282113fdSPekka Enberg 	"/lib",
118282113fdSPekka Enberg 	"/lib64",
119282113fdSPekka Enberg 	"/sbin",
120282113fdSPekka Enberg 	"/usr",
121d6080290SSasha Levin 	"/etc/ld.so.conf",
122282113fdSPekka Enberg };
123282113fdSPekka Enberg 
124cdce942cSDimitri John Ledkov #ifdef CONFIG_GUEST_INIT
12526e94dc4SOleg Nesterov static int extract_file(const char *guestfs_name, const char *filename,
12626e94dc4SOleg Nesterov 			const void *data, const void *_size)
127282113fdSPekka Enberg {
128282113fdSPekka Enberg 	char path[PATH_MAX];
129f20814b8SAsias He 	int fd, ret;
130282113fdSPekka Enberg 
13126e94dc4SOleg Nesterov 	snprintf(path, PATH_MAX, "%s%s/%s", kvm__get_dir(),
13226e94dc4SOleg Nesterov 				guestfs_name, filename);
133f20814b8SAsias He 	remove(path);
134f20814b8SAsias He 	fd = open(path, O_CREAT | O_WRONLY, 0755);
135f20814b8SAsias He 	if (fd < 0)
136f20814b8SAsias He 		die("Fail to setup %s", path);
13726e94dc4SOleg Nesterov 	ret = xwrite(fd, data, (size_t)_size);
138f20814b8SAsias He 	if (ret < 0)
139f20814b8SAsias He 		die("Fail to setup %s", path);
140f20814b8SAsias He 	close(fd);
141282113fdSPekka Enberg 
142f20814b8SAsias He 	return 0;
14326e94dc4SOleg Nesterov }
144cdce942cSDimitri John Ledkov 
14526e94dc4SOleg Nesterov extern char _binary_guest_init_start;
14626e94dc4SOleg Nesterov extern char _binary_guest_init_size;
147*5614f9d9SOleg Nesterov extern char _binary_guest_pre_init_start;
148*5614f9d9SOleg Nesterov extern char _binary_guest_pre_init_size;
14926e94dc4SOleg Nesterov 
15026e94dc4SOleg Nesterov int kvm_setup_guest_init(const char *guestfs_name)
15126e94dc4SOleg Nesterov {
152*5614f9d9SOleg Nesterov 	int err;
153*5614f9d9SOleg Nesterov 
154*5614f9d9SOleg Nesterov #ifdef CONFIG_GUEST_PRE_INIT
155*5614f9d9SOleg Nesterov 	err = extract_file(guestfs_name, "virt/pre_init",
156*5614f9d9SOleg Nesterov 				&_binary_guest_pre_init_start,
157*5614f9d9SOleg Nesterov 				&_binary_guest_pre_init_size);
158*5614f9d9SOleg Nesterov 	if (err)
159*5614f9d9SOleg Nesterov 		return err;
160*5614f9d9SOleg Nesterov #endif
161*5614f9d9SOleg Nesterov 	err = extract_file(guestfs_name, "virt/init",
16226e94dc4SOleg Nesterov 				&_binary_guest_init_start,
16326e94dc4SOleg Nesterov 				&_binary_guest_init_size);
164*5614f9d9SOleg Nesterov 	return err;
165282113fdSPekka Enberg }
166cdce942cSDimitri John Ledkov #else
167cdce942cSDimitri John Ledkov int kvm_setup_guest_init(const char *guestfs_name)
168cdce942cSDimitri John Ledkov {
169cdce942cSDimitri John Ledkov 	die("Guest init image not compiled in");
170cdce942cSDimitri John Ledkov 	return 0;
171cdce942cSDimitri John Ledkov }
172cdce942cSDimitri John Ledkov #endif
173282113fdSPekka Enberg 
174ce6927e8SSasha Levin static int copy_passwd(const char *guestfs_name)
175ce6927e8SSasha Levin {
176ce6927e8SSasha Levin 	char path[PATH_MAX];
177f20814b8SAsias He 	FILE *file;
178f20814b8SAsias He 	int ret;
179ce6927e8SSasha Levin 
180ce6927e8SSasha Levin 	snprintf(path, PATH_MAX, "%s%s/etc/passwd", kvm__get_dir(), guestfs_name);
181ce6927e8SSasha Levin 
182f20814b8SAsias He 	file = fopen(path, "w");
183f20814b8SAsias He 	if (!file)
184f20814b8SAsias He 		return -1;
185f20814b8SAsias He 
186f20814b8SAsias He 	ret = fprintf(file, "root:x:0:0:root:/root:/bin/sh\n");
18763fd57b9SCong Ding 	if (ret > 0)
18863fd57b9SCong Ding 		ret = 0;
189f20814b8SAsias He 
190f20814b8SAsias He 	fclose(file);
191f20814b8SAsias He 
19263fd57b9SCong Ding 	return ret;
193ce6927e8SSasha Levin }
194ce6927e8SSasha Levin 
195282113fdSPekka Enberg static int make_guestfs_symlink(const char *guestfs_name, const char *path)
196282113fdSPekka Enberg {
197282113fdSPekka Enberg 	char target[PATH_MAX];
198282113fdSPekka Enberg 	char name[PATH_MAX];
199282113fdSPekka Enberg 
2009667701cSPekka Enberg 	snprintf(name, PATH_MAX, "%s%s%s", kvm__get_dir(), guestfs_name, path);
201282113fdSPekka Enberg 
202282113fdSPekka Enberg 	snprintf(target, PATH_MAX, "/host%s", path);
203282113fdSPekka Enberg 
204282113fdSPekka Enberg 	return symlink(target, name);
205282113fdSPekka Enberg }
206282113fdSPekka Enberg 
207c8675741SSasha Levin static int make_dir(const char *dir)
208282113fdSPekka Enberg {
209282113fdSPekka Enberg 	char name[PATH_MAX];
210282113fdSPekka Enberg 
2119667701cSPekka Enberg 	snprintf(name, PATH_MAX, "%s%s", kvm__get_dir(), dir);
212282113fdSPekka Enberg 
213c8675741SSasha Levin 	return mkdir(name, 0777);
214282113fdSPekka Enberg }
215282113fdSPekka Enberg 
216282113fdSPekka Enberg static void make_guestfs_dir(const char *guestfs_name, const char *dir)
217282113fdSPekka Enberg {
218282113fdSPekka Enberg 	char name[PATH_MAX];
219282113fdSPekka Enberg 
220282113fdSPekka Enberg 	snprintf(name, PATH_MAX, "%s%s", guestfs_name, dir);
221282113fdSPekka Enberg 
222282113fdSPekka Enberg 	make_dir(name);
223282113fdSPekka Enberg }
224282113fdSPekka Enberg 
22569c88b95SSasha Levin void kvm_setup_resolv(const char *guestfs_name)
22669c88b95SSasha Levin {
22769c88b95SSasha Levin 	char path[PATH_MAX];
22869c88b95SSasha Levin 
2299667701cSPekka Enberg 	snprintf(path, PATH_MAX, "%s%s/etc/resolv.conf", kvm__get_dir(), guestfs_name);
23069c88b95SSasha Levin 
23169c88b95SSasha Levin 	copy_file("/etc/resolv.conf", path);
23269c88b95SSasha Levin }
23369c88b95SSasha Levin 
234282113fdSPekka Enberg static int do_setup(const char *guestfs_name)
235282113fdSPekka Enberg {
236282113fdSPekka Enberg 	unsigned int i;
23790ef0dc6SSasha Levin 	int ret;
238282113fdSPekka Enberg 
239c8675741SSasha Levin 	ret = make_dir(guestfs_name);
240c8675741SSasha Levin 	if (ret < 0)
241c8675741SSasha Levin 		return ret;
242282113fdSPekka Enberg 
243282113fdSPekka Enberg 	for (i = 0; i < ARRAY_SIZE(guestfs_dirs); i++)
244282113fdSPekka Enberg 		make_guestfs_dir(guestfs_name, guestfs_dirs[i]);
245282113fdSPekka Enberg 
246282113fdSPekka Enberg 	for (i = 0; i < ARRAY_SIZE(guestfs_symlinks); i++) {
247282113fdSPekka Enberg 		make_guestfs_symlink(guestfs_name, guestfs_symlinks[i]);
248282113fdSPekka Enberg 	}
249282113fdSPekka Enberg 
250cdce942cSDimitri John Ledkov 	ret = kvm_setup_guest_init(guestfs_name);
251ce6927e8SSasha Levin 	if (ret < 0)
252ce6927e8SSasha Levin 		return ret;
253ce6927e8SSasha Levin 
254ce6927e8SSasha Levin 	return copy_passwd(guestfs_name);
255282113fdSPekka Enberg }
256282113fdSPekka Enberg 
257c8675741SSasha Levin int kvm_setup_create_new(const char *guestfs_name)
258c8675741SSasha Levin {
259c8675741SSasha Levin 	return do_setup(guestfs_name);
260c8675741SSasha Levin }
261c8675741SSasha Levin 
262282113fdSPekka Enberg int kvm_cmd_setup(int argc, const char **argv, const char *prefix)
263282113fdSPekka Enberg {
264f9613d9fSSasha Levin 	int r;
265f9613d9fSSasha Levin 
266282113fdSPekka Enberg 	parse_setup_options(argc, argv);
267282113fdSPekka Enberg 
268282113fdSPekka Enberg 	if (instance_name == NULL)
269282113fdSPekka Enberg 		kvm_setup_help();
270282113fdSPekka Enberg 
271f9613d9fSSasha Levin 	r = do_setup(instance_name);
272f9613d9fSSasha Levin 	if (r == 0)
273f9ea40eaSPekka Enberg 		printf("A new rootfs '%s' has been created in '%s%s'.\n\n"
274f9ea40eaSPekka Enberg 			"You can now start it by running the following command:\n\n"
275ee8b1456SWanlong Gao 			"  %s run -d %s\n",
276ee8b1456SWanlong Gao 			instance_name, kvm__get_dir(), instance_name,
277ee8b1456SWanlong Gao 			KVM_BINARY_NAME,instance_name);
2787b6d50d6SSasha Levin 	else
279f9ea40eaSPekka Enberg 		printf("Unable to create rootfs in %s%s: %s\n",
280f9ea40eaSPekka Enberg 			kvm__get_dir(), instance_name, strerror(errno));
281f9613d9fSSasha Levin 
282f9613d9fSSasha Levin 	return r;
283282113fdSPekka Enberg }
284