xref: /kvmtool/builtin-setup.c (revision 5fab5964e210bc82340ea89ef65a6309cd08a8c2)
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/types.h>
17282113fdSPekka Enberg #include <sys/mman.h>
18282113fdSPekka Enberg #include <sys/stat.h>
19282113fdSPekka Enberg #include <string.h>
20282113fdSPekka Enberg #include <unistd.h>
21282113fdSPekka Enberg #include <fcntl.h>
22282113fdSPekka Enberg 
23f20814b8SAsias He extern char _binary_guest_init_start;
24f20814b8SAsias He extern char _binary_guest_init_size;
25f20814b8SAsias He 
26282113fdSPekka Enberg static const char *instance_name;
27282113fdSPekka Enberg 
28282113fdSPekka Enberg static const char * const setup_usage[] = {
298d2ff5daSWanlong Gao 	"lkvm setup [name]",
30282113fdSPekka Enberg 	NULL
31282113fdSPekka Enberg };
32282113fdSPekka Enberg 
33282113fdSPekka Enberg static const struct option setup_options[] = {
34282113fdSPekka Enberg 	OPT_END()
35282113fdSPekka Enberg };
36282113fdSPekka Enberg 
37282113fdSPekka Enberg static void parse_setup_options(int argc, const char **argv)
38282113fdSPekka Enberg {
39282113fdSPekka Enberg 	while (argc != 0) {
40282113fdSPekka Enberg 		argc = parse_options(argc, argv, setup_options, setup_usage,
41282113fdSPekka Enberg 				PARSE_OPT_STOP_AT_NON_OPTION);
427b6d50d6SSasha Levin 		if (argc != 0 && instance_name)
43282113fdSPekka Enberg 			kvm_setup_help();
447b6d50d6SSasha Levin 		else
457b6d50d6SSasha Levin 			instance_name = argv[0];
467b6d50d6SSasha Levin 		argv++;
477b6d50d6SSasha Levin 		argc--;
48282113fdSPekka Enberg 	}
49282113fdSPekka Enberg }
50282113fdSPekka Enberg 
51282113fdSPekka Enberg void kvm_setup_help(void)
52282113fdSPekka Enberg {
53ee8b1456SWanlong Gao 	printf("\n%s setup creates a new rootfs under %s.\n"
54ee8b1456SWanlong Gao 		"This can be used later by the '-d' parameter of '%s run'.\n",
55d15572a9SPekka Enberg 		KVM_BINARY_NAME, kvm__get_dir(), KVM_BINARY_NAME);
56282113fdSPekka Enberg 	usage_with_options(setup_usage, setup_options);
57282113fdSPekka Enberg }
58282113fdSPekka Enberg 
59282113fdSPekka Enberg static int copy_file(const char *from, const char *to)
60282113fdSPekka Enberg {
61282113fdSPekka Enberg 	int in_fd, out_fd;
62282113fdSPekka Enberg 	void *src, *dst;
63282113fdSPekka Enberg 	struct stat st;
64282113fdSPekka Enberg 	int err = -1;
65282113fdSPekka Enberg 
66282113fdSPekka Enberg 	in_fd = open(from, O_RDONLY);
67282113fdSPekka Enberg 	if (in_fd < 0)
68282113fdSPekka Enberg 		return err;
69282113fdSPekka Enberg 
70282113fdSPekka Enberg 	if (fstat(in_fd, &st) < 0)
71282113fdSPekka Enberg 		goto error_close_in;
72282113fdSPekka Enberg 
73282113fdSPekka Enberg 	out_fd = open(to, O_RDWR | O_CREAT | O_TRUNC, st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO));
74282113fdSPekka Enberg 	if (out_fd < 0)
75282113fdSPekka Enberg 		goto error_close_in;
76282113fdSPekka Enberg 
77282113fdSPekka Enberg 	src = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, in_fd, 0);
78282113fdSPekka Enberg 	if (src == MAP_FAILED)
79282113fdSPekka Enberg 		goto error_close_out;
80282113fdSPekka Enberg 
81282113fdSPekka Enberg 	if (ftruncate(out_fd, st.st_size) < 0)
82282113fdSPekka Enberg 		goto error_munmap_src;
83282113fdSPekka Enberg 
84282113fdSPekka Enberg 	dst = mmap(NULL, st.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, out_fd, 0);
85282113fdSPekka Enberg 	if (dst == MAP_FAILED)
86282113fdSPekka Enberg 		goto error_munmap_src;
87282113fdSPekka Enberg 
88282113fdSPekka Enberg 	memcpy(dst, src, st.st_size);
89282113fdSPekka Enberg 
90282113fdSPekka Enberg 	if (fsync(out_fd) < 0)
91282113fdSPekka Enberg 		goto error_munmap_dst;
92282113fdSPekka Enberg 
93282113fdSPekka Enberg 	err = 0;
94282113fdSPekka Enberg 
95282113fdSPekka Enberg error_munmap_dst:
96282113fdSPekka Enberg 	munmap(dst, st.st_size);
97282113fdSPekka Enberg error_munmap_src:
98282113fdSPekka Enberg 	munmap(src, st.st_size);
99282113fdSPekka Enberg error_close_out:
100282113fdSPekka Enberg 	close(out_fd);
101282113fdSPekka Enberg error_close_in:
102282113fdSPekka Enberg 	close(in_fd);
103282113fdSPekka Enberg 
104282113fdSPekka Enberg 	return err;
105282113fdSPekka Enberg }
106282113fdSPekka Enberg 
107282113fdSPekka Enberg static const char *guestfs_dirs[] = {
108282113fdSPekka Enberg 	"/dev",
109282113fdSPekka Enberg 	"/etc",
110282113fdSPekka Enberg 	"/home",
111282113fdSPekka Enberg 	"/host",
112282113fdSPekka Enberg 	"/proc",
113282113fdSPekka Enberg 	"/root",
114282113fdSPekka Enberg 	"/sys",
1154547fe2bSPekka Enberg 	"/tmp",
116282113fdSPekka Enberg 	"/var",
117282113fdSPekka Enberg 	"/var/lib",
118282113fdSPekka Enberg 	"/virt",
119*5fab5964SSasha Levin 	"/virt/home",
120282113fdSPekka Enberg };
121282113fdSPekka Enberg 
122282113fdSPekka Enberg static const char *guestfs_symlinks[] = {
123282113fdSPekka Enberg 	"/bin",
124282113fdSPekka Enberg 	"/lib",
125282113fdSPekka Enberg 	"/lib64",
126282113fdSPekka Enberg 	"/sbin",
127282113fdSPekka Enberg 	"/usr",
128d6080290SSasha Levin 	"/etc/ld.so.conf",
129282113fdSPekka Enberg };
130282113fdSPekka Enberg 
131282113fdSPekka Enberg static int copy_init(const char *guestfs_name)
132282113fdSPekka Enberg {
133282113fdSPekka Enberg 	char path[PATH_MAX];
134f20814b8SAsias He 	size_t size;
135f20814b8SAsias He 	int fd, ret;
136f20814b8SAsias He 	char *data;
137282113fdSPekka Enberg 
138f20814b8SAsias He 	size = (size_t)&_binary_guest_init_size;
139f20814b8SAsias He 	data = (char *)&_binary_guest_init_start;
1409667701cSPekka Enberg 	snprintf(path, PATH_MAX, "%s%s/virt/init", kvm__get_dir(), guestfs_name);
141f20814b8SAsias He 	remove(path);
142f20814b8SAsias He 	fd = open(path, O_CREAT | O_WRONLY, 0755);
143f20814b8SAsias He 	if (fd < 0)
144f20814b8SAsias He 		die("Fail to setup %s", path);
145f20814b8SAsias He 	ret = xwrite(fd, data, size);
146f20814b8SAsias He 	if (ret < 0)
147f20814b8SAsias He 		die("Fail to setup %s", path);
148f20814b8SAsias He 	close(fd);
149282113fdSPekka Enberg 
150f20814b8SAsias He 	return 0;
151282113fdSPekka Enberg }
152282113fdSPekka Enberg 
153ce6927e8SSasha Levin static int copy_passwd(const char *guestfs_name)
154ce6927e8SSasha Levin {
155ce6927e8SSasha Levin 	char path[PATH_MAX];
156f20814b8SAsias He 	FILE *file;
157f20814b8SAsias He 	int ret;
158ce6927e8SSasha Levin 
159ce6927e8SSasha Levin 	snprintf(path, PATH_MAX, "%s%s/etc/passwd", kvm__get_dir(), guestfs_name);
160ce6927e8SSasha Levin 
161f20814b8SAsias He 	file = fopen(path, "w");
162f20814b8SAsias He 	if (!file)
163f20814b8SAsias He 		return -1;
164f20814b8SAsias He 
165f20814b8SAsias He 	ret = fprintf(file, "root:x:0:0:root:/root:/bin/sh\n");
166f20814b8SAsias He 	if (ret < 0)
167f20814b8SAsias He 		return ret;
168f20814b8SAsias He 
169f20814b8SAsias He 	fclose(file);
170f20814b8SAsias He 
171f20814b8SAsias He 	return 0;
172ce6927e8SSasha Levin }
173ce6927e8SSasha Levin 
174282113fdSPekka Enberg static int make_guestfs_symlink(const char *guestfs_name, const char *path)
175282113fdSPekka Enberg {
176282113fdSPekka Enberg 	char target[PATH_MAX];
177282113fdSPekka Enberg 	char name[PATH_MAX];
178282113fdSPekka Enberg 
1799667701cSPekka Enberg 	snprintf(name, PATH_MAX, "%s%s%s", kvm__get_dir(), guestfs_name, path);
180282113fdSPekka Enberg 
181282113fdSPekka Enberg 	snprintf(target, PATH_MAX, "/host%s", path);
182282113fdSPekka Enberg 
183282113fdSPekka Enberg 	return symlink(target, name);
184282113fdSPekka Enberg }
185282113fdSPekka Enberg 
186c8675741SSasha Levin static int make_dir(const char *dir)
187282113fdSPekka Enberg {
188282113fdSPekka Enberg 	char name[PATH_MAX];
189282113fdSPekka Enberg 
1909667701cSPekka Enberg 	snprintf(name, PATH_MAX, "%s%s", kvm__get_dir(), dir);
191282113fdSPekka Enberg 
192c8675741SSasha Levin 	return mkdir(name, 0777);
193282113fdSPekka Enberg }
194282113fdSPekka Enberg 
195282113fdSPekka Enberg static void make_guestfs_dir(const char *guestfs_name, const char *dir)
196282113fdSPekka Enberg {
197282113fdSPekka Enberg 	char name[PATH_MAX];
198282113fdSPekka Enberg 
199282113fdSPekka Enberg 	snprintf(name, PATH_MAX, "%s%s", guestfs_name, dir);
200282113fdSPekka Enberg 
201282113fdSPekka Enberg 	make_dir(name);
202282113fdSPekka Enberg }
203282113fdSPekka Enberg 
20469c88b95SSasha Levin void kvm_setup_resolv(const char *guestfs_name)
20569c88b95SSasha Levin {
20669c88b95SSasha Levin 	char path[PATH_MAX];
20769c88b95SSasha Levin 
2089667701cSPekka Enberg 	snprintf(path, PATH_MAX, "%s%s/etc/resolv.conf", kvm__get_dir(), guestfs_name);
20969c88b95SSasha Levin 
21069c88b95SSasha Levin 	copy_file("/etc/resolv.conf", path);
21169c88b95SSasha Levin }
21269c88b95SSasha Levin 
213282113fdSPekka Enberg static int do_setup(const char *guestfs_name)
214282113fdSPekka Enberg {
215282113fdSPekka Enberg 	unsigned int i;
21690ef0dc6SSasha Levin 	int ret;
217282113fdSPekka Enberg 
218c8675741SSasha Levin 	ret = make_dir(guestfs_name);
219c8675741SSasha Levin 	if (ret < 0)
220c8675741SSasha Levin 		return ret;
221282113fdSPekka Enberg 
222282113fdSPekka Enberg 	for (i = 0; i < ARRAY_SIZE(guestfs_dirs); i++)
223282113fdSPekka Enberg 		make_guestfs_dir(guestfs_name, guestfs_dirs[i]);
224282113fdSPekka Enberg 
225282113fdSPekka Enberg 	for (i = 0; i < ARRAY_SIZE(guestfs_symlinks); i++) {
226282113fdSPekka Enberg 		make_guestfs_symlink(guestfs_name, guestfs_symlinks[i]);
227282113fdSPekka Enberg 	}
228282113fdSPekka Enberg 
229ce6927e8SSasha Levin 	ret = copy_init(guestfs_name);
230ce6927e8SSasha Levin 	if (ret < 0)
231ce6927e8SSasha Levin 		return ret;
232ce6927e8SSasha Levin 
233ce6927e8SSasha Levin 	return copy_passwd(guestfs_name);
234282113fdSPekka Enberg }
235282113fdSPekka Enberg 
236c8675741SSasha Levin int kvm_setup_create_new(const char *guestfs_name)
237c8675741SSasha Levin {
238c8675741SSasha Levin 	return do_setup(guestfs_name);
239c8675741SSasha Levin }
240c8675741SSasha Levin 
241282113fdSPekka Enberg int kvm_cmd_setup(int argc, const char **argv, const char *prefix)
242282113fdSPekka Enberg {
243f9613d9fSSasha Levin 	int r;
244f9613d9fSSasha Levin 
245282113fdSPekka Enberg 	parse_setup_options(argc, argv);
246282113fdSPekka Enberg 
247282113fdSPekka Enberg 	if (instance_name == NULL)
248282113fdSPekka Enberg 		kvm_setup_help();
249282113fdSPekka Enberg 
250f9613d9fSSasha Levin 	r = do_setup(instance_name);
251f9613d9fSSasha Levin 	if (r == 0)
252f9ea40eaSPekka Enberg 		printf("A new rootfs '%s' has been created in '%s%s'.\n\n"
253f9ea40eaSPekka Enberg 			"You can now start it by running the following command:\n\n"
254ee8b1456SWanlong Gao 			"  %s run -d %s\n",
255ee8b1456SWanlong Gao 			instance_name, kvm__get_dir(), instance_name,
256ee8b1456SWanlong Gao 			KVM_BINARY_NAME,instance_name);
2577b6d50d6SSasha Levin 	else
258f9ea40eaSPekka Enberg 		printf("Unable to create rootfs in %s%s: %s\n",
259f9ea40eaSPekka Enberg 			kvm__get_dir(), instance_name, strerror(errno));
260f9613d9fSSasha Levin 
261f9613d9fSSasha Levin 	return r;
262282113fdSPekka Enberg }
263