xref: /kvmtool/builtin-setup.c (revision 7b6d50d6294bb630544556ee163098e482865f21)
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>
6282113fdSPekka Enberg 
7282113fdSPekka Enberg #include <sys/types.h>
8282113fdSPekka Enberg #include <sys/stat.h>
9282113fdSPekka Enberg #include <limits.h>
10282113fdSPekka Enberg #include <signal.h>
11282113fdSPekka Enberg #include <stdlib.h>
12282113fdSPekka Enberg #include <string.h>
13282113fdSPekka Enberg #include <unistd.h>
14282113fdSPekka Enberg #include <stdio.h>
15282113fdSPekka Enberg #include <sys/types.h>
16282113fdSPekka Enberg #include <sys/mman.h>
17282113fdSPekka Enberg #include <sys/stat.h>
18282113fdSPekka Enberg #include <string.h>
19282113fdSPekka Enberg #include <unistd.h>
20282113fdSPekka Enberg #include <fcntl.h>
21282113fdSPekka Enberg 
22282113fdSPekka Enberg #define KVM_PID_FILE_PATH	"/.kvm-tools/"
23282113fdSPekka Enberg #define HOME_DIR		getenv("HOME")
24282113fdSPekka Enberg 
25282113fdSPekka Enberg static const char *instance_name;
26282113fdSPekka Enberg 
27282113fdSPekka Enberg static const char * const setup_usage[] = {
28*7b6d50d6SSasha Levin 	"kvm setup [name]",
29282113fdSPekka Enberg 	NULL
30282113fdSPekka Enberg };
31282113fdSPekka Enberg 
32282113fdSPekka Enberg static const struct option setup_options[] = {
33282113fdSPekka Enberg 	OPT_END()
34282113fdSPekka Enberg };
35282113fdSPekka Enberg 
36282113fdSPekka Enberg static void parse_setup_options(int argc, const char **argv)
37282113fdSPekka Enberg {
38282113fdSPekka Enberg 	while (argc != 0) {
39282113fdSPekka Enberg 		argc = parse_options(argc, argv, setup_options, setup_usage,
40282113fdSPekka Enberg 				PARSE_OPT_STOP_AT_NON_OPTION);
41*7b6d50d6SSasha Levin 		if (argc != 0 && instance_name)
42282113fdSPekka Enberg 			kvm_setup_help();
43*7b6d50d6SSasha Levin 		else
44*7b6d50d6SSasha Levin 			instance_name = argv[0];
45*7b6d50d6SSasha Levin 		argv++;
46*7b6d50d6SSasha Levin 		argc--;
47282113fdSPekka Enberg 	}
48282113fdSPekka Enberg }
49282113fdSPekka Enberg 
50282113fdSPekka Enberg void kvm_setup_help(void)
51282113fdSPekka Enberg {
52f9613d9fSSasha Levin 	printf("\nkvm setup creates a new rootfs and stores it under ~/.kvm-tools/ .\n"
53f9613d9fSSasha Levin 		"This can be used later by the '-d' parameter of 'kvm run'.\n");
54282113fdSPekka Enberg 	usage_with_options(setup_usage, setup_options);
55282113fdSPekka Enberg }
56282113fdSPekka Enberg 
57282113fdSPekka Enberg static int copy_file(const char *from, const char *to)
58282113fdSPekka Enberg {
59282113fdSPekka Enberg 	int in_fd, out_fd;
60282113fdSPekka Enberg 	void *src, *dst;
61282113fdSPekka Enberg 	struct stat st;
62282113fdSPekka Enberg 	int err = -1;
63282113fdSPekka Enberg 
64282113fdSPekka Enberg 	in_fd = open(from, O_RDONLY);
65282113fdSPekka Enberg 	if (in_fd < 0)
66282113fdSPekka Enberg 		return err;
67282113fdSPekka Enberg 
68282113fdSPekka Enberg 	if (fstat(in_fd, &st) < 0)
69282113fdSPekka Enberg 		goto error_close_in;
70282113fdSPekka Enberg 
71282113fdSPekka Enberg 	out_fd = open(to, O_RDWR | O_CREAT | O_TRUNC, st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO));
72282113fdSPekka Enberg 	if (out_fd < 0)
73282113fdSPekka Enberg 		goto error_close_in;
74282113fdSPekka Enberg 
75282113fdSPekka Enberg 	src = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, in_fd, 0);
76282113fdSPekka Enberg 	if (src == MAP_FAILED)
77282113fdSPekka Enberg 		goto error_close_out;
78282113fdSPekka Enberg 
79282113fdSPekka Enberg 	if (ftruncate(out_fd, st.st_size) < 0)
80282113fdSPekka Enberg 		goto error_munmap_src;
81282113fdSPekka Enberg 
82282113fdSPekka Enberg 	dst = mmap(NULL, st.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, out_fd, 0);
83282113fdSPekka Enberg 	if (dst == MAP_FAILED)
84282113fdSPekka Enberg 		goto error_munmap_src;
85282113fdSPekka Enberg 
86282113fdSPekka Enberg 	memcpy(dst, src, st.st_size);
87282113fdSPekka Enberg 
88282113fdSPekka Enberg 	if (fsync(out_fd) < 0)
89282113fdSPekka Enberg 		goto error_munmap_dst;
90282113fdSPekka Enberg 
91282113fdSPekka Enberg 	err = 0;
92282113fdSPekka Enberg 
93282113fdSPekka Enberg error_munmap_dst:
94282113fdSPekka Enberg 	munmap(dst, st.st_size);
95282113fdSPekka Enberg error_munmap_src:
96282113fdSPekka Enberg 	munmap(src, st.st_size);
97282113fdSPekka Enberg error_close_out:
98282113fdSPekka Enberg 	close(out_fd);
99282113fdSPekka Enberg error_close_in:
100282113fdSPekka Enberg 	close(in_fd);
101282113fdSPekka Enberg 
102282113fdSPekka Enberg 	return err;
103282113fdSPekka Enberg }
104282113fdSPekka Enberg 
105282113fdSPekka Enberg static const char *guestfs_dirs[] = {
106282113fdSPekka Enberg 	"/dev",
107282113fdSPekka Enberg 	"/etc",
108282113fdSPekka Enberg 	"/home",
109282113fdSPekka Enberg 	"/host",
110282113fdSPekka Enberg 	"/proc",
111282113fdSPekka Enberg 	"/root",
112282113fdSPekka Enberg 	"/sys",
1134547fe2bSPekka Enberg 	"/tmp",
114282113fdSPekka Enberg 	"/var",
115282113fdSPekka Enberg 	"/var/lib",
116282113fdSPekka Enberg 	"/virt",
117282113fdSPekka Enberg };
118282113fdSPekka Enberg 
119282113fdSPekka Enberg static const char *guestfs_symlinks[] = {
120282113fdSPekka Enberg 	"/bin",
121282113fdSPekka Enberg 	"/lib",
122282113fdSPekka Enberg 	"/lib64",
123282113fdSPekka Enberg 	"/sbin",
124282113fdSPekka Enberg 	"/usr",
125282113fdSPekka Enberg };
126282113fdSPekka Enberg 
127282113fdSPekka Enberg static int copy_init(const char *guestfs_name)
128282113fdSPekka Enberg {
129282113fdSPekka Enberg 	char path[PATH_MAX];
130282113fdSPekka Enberg 
131282113fdSPekka Enberg 	snprintf(path, PATH_MAX, "%s%s%s/virt/init", HOME_DIR, KVM_PID_FILE_PATH, guestfs_name);
132282113fdSPekka Enberg 
133282113fdSPekka Enberg 	return copy_file("guest/init", path);
134282113fdSPekka Enberg }
135282113fdSPekka Enberg 
136282113fdSPekka Enberg static int make_guestfs_symlink(const char *guestfs_name, const char *path)
137282113fdSPekka Enberg {
138282113fdSPekka Enberg 	char target[PATH_MAX];
139282113fdSPekka Enberg 	char name[PATH_MAX];
140282113fdSPekka Enberg 
141282113fdSPekka Enberg 	snprintf(name, PATH_MAX, "%s%s%s%s", HOME_DIR, KVM_PID_FILE_PATH, guestfs_name, path);
142282113fdSPekka Enberg 
143282113fdSPekka Enberg 	snprintf(target, PATH_MAX, "/host%s", path);
144282113fdSPekka Enberg 
145282113fdSPekka Enberg 	return symlink(target, name);
146282113fdSPekka Enberg }
147282113fdSPekka Enberg 
1488928921aSHagen Paul Pfeifer static void make_root_dir(void)
1498928921aSHagen Paul Pfeifer {
1508928921aSHagen Paul Pfeifer 	char name[PATH_MAX];
1518928921aSHagen Paul Pfeifer 
1528928921aSHagen Paul Pfeifer 	snprintf(name, PATH_MAX, "%s%s", HOME_DIR, KVM_PID_FILE_PATH);
1538928921aSHagen Paul Pfeifer 
1548928921aSHagen Paul Pfeifer 	mkdir(name, 0777);
1558928921aSHagen Paul Pfeifer }
1568928921aSHagen Paul Pfeifer 
157c8675741SSasha Levin static int make_dir(const char *dir)
158282113fdSPekka Enberg {
159282113fdSPekka Enberg 	char name[PATH_MAX];
160282113fdSPekka Enberg 
161282113fdSPekka Enberg 	snprintf(name, PATH_MAX, "%s%s%s", HOME_DIR, KVM_PID_FILE_PATH, dir);
162282113fdSPekka Enberg 
163c8675741SSasha Levin 	return mkdir(name, 0777);
164282113fdSPekka Enberg }
165282113fdSPekka Enberg 
166282113fdSPekka Enberg static void make_guestfs_dir(const char *guestfs_name, const char *dir)
167282113fdSPekka Enberg {
168282113fdSPekka Enberg 	char name[PATH_MAX];
169282113fdSPekka Enberg 
170282113fdSPekka Enberg 	snprintf(name, PATH_MAX, "%s%s", guestfs_name, dir);
171282113fdSPekka Enberg 
172282113fdSPekka Enberg 	make_dir(name);
173282113fdSPekka Enberg }
174282113fdSPekka Enberg 
17569c88b95SSasha Levin void kvm_setup_resolv(const char *guestfs_name)
17669c88b95SSasha Levin {
17769c88b95SSasha Levin 	char path[PATH_MAX];
17869c88b95SSasha Levin 
17969c88b95SSasha Levin 	snprintf(path, PATH_MAX, "%s%s%s/etc/resolv.conf", HOME_DIR, KVM_PID_FILE_PATH, guestfs_name);
18069c88b95SSasha Levin 
18169c88b95SSasha Levin 	copy_file("/etc/resolv.conf", path);
18269c88b95SSasha Levin }
18369c88b95SSasha Levin 
184282113fdSPekka Enberg static int do_setup(const char *guestfs_name)
185282113fdSPekka Enberg {
186282113fdSPekka Enberg 	unsigned int i;
18790ef0dc6SSasha Levin 	int ret;
188282113fdSPekka Enberg 
1898928921aSHagen Paul Pfeifer 	make_root_dir();
1908928921aSHagen Paul Pfeifer 
191c8675741SSasha Levin 	ret = make_dir(guestfs_name);
192c8675741SSasha Levin 	if (ret < 0)
193c8675741SSasha Levin 		return ret;
194282113fdSPekka Enberg 
195282113fdSPekka Enberg 	for (i = 0; i < ARRAY_SIZE(guestfs_dirs); i++)
196282113fdSPekka Enberg 		make_guestfs_dir(guestfs_name, guestfs_dirs[i]);
197282113fdSPekka Enberg 
198282113fdSPekka Enberg 	for (i = 0; i < ARRAY_SIZE(guestfs_symlinks); i++) {
199282113fdSPekka Enberg 		make_guestfs_symlink(guestfs_name, guestfs_symlinks[i]);
200282113fdSPekka Enberg 	}
201282113fdSPekka Enberg 
202282113fdSPekka Enberg 	return copy_init(guestfs_name);
203282113fdSPekka Enberg }
204282113fdSPekka Enberg 
205c8675741SSasha Levin int kvm_setup_create_new(const char *guestfs_name)
206c8675741SSasha Levin {
207c8675741SSasha Levin 	return do_setup(guestfs_name);
208c8675741SSasha Levin }
209c8675741SSasha Levin 
210282113fdSPekka Enberg int kvm_cmd_setup(int argc, const char **argv, const char *prefix)
211282113fdSPekka Enberg {
212f9613d9fSSasha Levin 	int r;
213f9613d9fSSasha Levin 
214282113fdSPekka Enberg 	parse_setup_options(argc, argv);
215282113fdSPekka Enberg 
216282113fdSPekka Enberg 	if (instance_name == NULL)
217282113fdSPekka Enberg 		kvm_setup_help();
218282113fdSPekka Enberg 
219f9613d9fSSasha Levin 	r = do_setup(instance_name);
220f9613d9fSSasha Levin 	if (r == 0)
221f9613d9fSSasha Levin 		pr_info("Your new rootfs named %s has been created.\n"
222f9613d9fSSasha Levin 			"You can now start it by running 'kvm run -d %s'\n",
223f9613d9fSSasha Levin 			instance_name, instance_name);
224*7b6d50d6SSasha Levin 	else
225*7b6d50d6SSasha Levin 		perror("Error creating rootfs");
226f9613d9fSSasha Levin 
227f9613d9fSSasha Levin 	return r;
228282113fdSPekka Enberg }
229