xref: /kvmtool/builtin-setup.c (revision 30867c55012f05f3ad28322bcf86dcfb83b9f21b)
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 #include <kvm/read-write.h>
7 
8 #include <sys/types.h>
9 #include <sys/stat.h>
10 #include <limits.h>
11 #include <signal.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <unistd.h>
15 #include <stdio.h>
16 #include <sys/mman.h>
17 #include <fcntl.h>
18 
19 static const char *instance_name;
20 
21 static const char * const setup_usage[] = {
22 	"lkvm setup [name]",
23 	NULL
24 };
25 
26 static const struct option setup_options[] = {
27 	OPT_END()
28 };
29 
30 static void parse_setup_options(int argc, const char **argv)
31 {
32 	while (argc != 0) {
33 		argc = parse_options(argc, argv, setup_options, setup_usage,
34 				PARSE_OPT_STOP_AT_NON_OPTION);
35 		if (argc != 0 && instance_name)
36 			kvm_setup_help();
37 		else
38 			instance_name = argv[0];
39 		argv++;
40 		argc--;
41 	}
42 }
43 
44 void kvm_setup_help(void)
45 {
46 	printf("\n%s setup creates a new rootfs under %s.\n"
47 		"This can be used later by the '-d' parameter of '%s run'.\n",
48 		KVM_BINARY_NAME, kvm__get_dir(), KVM_BINARY_NAME);
49 	usage_with_options(setup_usage, setup_options);
50 }
51 
52 static int copy_file(const char *from, const char *to)
53 {
54 	int in_fd, out_fd;
55 	void *src, *dst;
56 	struct stat st;
57 	int err = -1;
58 
59 	in_fd = open(from, O_RDONLY);
60 	if (in_fd < 0)
61 		return err;
62 
63 	if (fstat(in_fd, &st) < 0)
64 		goto error_close_in;
65 
66 	out_fd = open(to, O_RDWR | O_CREAT | O_TRUNC, st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO));
67 	if (out_fd < 0)
68 		goto error_close_in;
69 
70 	src = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, in_fd, 0);
71 	if (src == MAP_FAILED)
72 		goto error_close_out;
73 
74 	if (ftruncate(out_fd, st.st_size) < 0)
75 		goto error_munmap_src;
76 
77 	dst = mmap(NULL, st.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, out_fd, 0);
78 	if (dst == MAP_FAILED)
79 		goto error_munmap_src;
80 
81 	memcpy(dst, src, st.st_size);
82 
83 	if (fsync(out_fd) < 0)
84 		goto error_munmap_dst;
85 
86 	err = 0;
87 
88 error_munmap_dst:
89 	munmap(dst, st.st_size);
90 error_munmap_src:
91 	munmap(src, st.st_size);
92 error_close_out:
93 	close(out_fd);
94 error_close_in:
95 	close(in_fd);
96 
97 	return err;
98 }
99 
100 static const char *guestfs_dirs[] = {
101 	"/dev",
102 	"/etc",
103 	"/home",
104 	"/host",
105 	"/proc",
106 	"/root",
107 	"/sys",
108 	"/tmp",
109 	"/var",
110 	"/var/lib",
111 	"/virt",
112 	"/virt/home",
113 };
114 
115 static const char *guestfs_symlinks[] = {
116 	"/bin",
117 	"/lib",
118 	"/lib64",
119 	"/sbin",
120 	"/usr",
121 	"/etc/ld.so.conf",
122 };
123 
124 #ifdef CONFIG_GUEST_INIT
125 static int extract_file(const char *guestfs_name, const char *filename,
126 			const void *data, const void *_size)
127 {
128 	char path[PATH_MAX];
129 	int fd, ret;
130 
131 	snprintf(path, PATH_MAX, "%s%s/%s", kvm__get_dir(),
132 				guestfs_name, filename);
133 
134 	fd = open(path, O_EXCL | O_CREAT | O_WRONLY, 0755);
135 	if (fd < 0) {
136 		if (errno == EEXIST)
137 			return 0;
138 		die("Fail to setup %s", path);
139 	}
140 
141 	ret = xwrite(fd, data, (size_t)_size);
142 	if (ret < 0)
143 		die("Fail to setup %s", path);
144 	close(fd);
145 
146 	return 0;
147 }
148 
149 extern char _binary_guest_init_start;
150 extern char _binary_guest_init_size;
151 extern char _binary_guest_pre_init_start;
152 extern char _binary_guest_pre_init_size;
153 
154 int kvm_setup_guest_init(const char *guestfs_name)
155 {
156 	int err;
157 
158 #ifdef CONFIG_GUEST_PRE_INIT
159 	err = extract_file(guestfs_name, "virt/pre_init",
160 				&_binary_guest_pre_init_start,
161 				&_binary_guest_pre_init_size);
162 	if (err)
163 		return err;
164 #endif
165 	err = extract_file(guestfs_name, "virt/init",
166 				&_binary_guest_init_start,
167 				&_binary_guest_init_size);
168 	return err;
169 }
170 #else
171 int kvm_setup_guest_init(const char *guestfs_name)
172 {
173 	die("Guest init image not compiled in");
174 	return 0;
175 }
176 #endif
177 
178 static int copy_passwd(const char *guestfs_name)
179 {
180 	char path[PATH_MAX];
181 	FILE *file;
182 	int ret;
183 
184 	snprintf(path, PATH_MAX, "%s%s/etc/passwd", kvm__get_dir(), guestfs_name);
185 
186 	file = fopen(path, "w");
187 	if (!file)
188 		return -1;
189 
190 	ret = fprintf(file, "root:x:0:0:root:/root:/bin/sh\n");
191 	if (ret > 0)
192 		ret = 0;
193 
194 	fclose(file);
195 
196 	return ret;
197 }
198 
199 static int make_guestfs_symlink(const char *guestfs_name, const char *path)
200 {
201 	char target[PATH_MAX];
202 	char name[PATH_MAX];
203 
204 	snprintf(name, PATH_MAX, "%s%s%s", kvm__get_dir(), guestfs_name, path);
205 
206 	snprintf(target, PATH_MAX, "/host%s", path);
207 
208 	return symlink(target, name);
209 }
210 
211 static int make_dir(const char *dir)
212 {
213 	char name[PATH_MAX];
214 
215 	snprintf(name, PATH_MAX, "%s%s", kvm__get_dir(), dir);
216 
217 	return mkdir(name, 0777);
218 }
219 
220 static void make_guestfs_dir(const char *guestfs_name, const char *dir)
221 {
222 	char name[PATH_MAX];
223 
224 	snprintf(name, PATH_MAX, "%s%s", guestfs_name, dir);
225 
226 	make_dir(name);
227 }
228 
229 void kvm_setup_resolv(const char *guestfs_name)
230 {
231 	char path[PATH_MAX];
232 
233 	snprintf(path, PATH_MAX, "%s%s/etc/resolv.conf", kvm__get_dir(), guestfs_name);
234 
235 	copy_file("/etc/resolv.conf", path);
236 }
237 
238 static int do_setup(const char *guestfs_name)
239 {
240 	unsigned int i;
241 	int ret;
242 
243 	ret = make_dir(guestfs_name);
244 	if (ret < 0)
245 		return ret;
246 
247 	for (i = 0; i < ARRAY_SIZE(guestfs_dirs); i++)
248 		make_guestfs_dir(guestfs_name, guestfs_dirs[i]);
249 
250 	for (i = 0; i < ARRAY_SIZE(guestfs_symlinks); i++) {
251 		make_guestfs_symlink(guestfs_name, guestfs_symlinks[i]);
252 	}
253 
254 	ret = kvm_setup_guest_init(guestfs_name);
255 	if (ret < 0)
256 		return ret;
257 
258 	return copy_passwd(guestfs_name);
259 }
260 
261 int kvm_setup_create_new(const char *guestfs_name)
262 {
263 	return do_setup(guestfs_name);
264 }
265 
266 int kvm_cmd_setup(int argc, const char **argv, const char *prefix)
267 {
268 	int r;
269 
270 	parse_setup_options(argc, argv);
271 
272 	if (instance_name == NULL)
273 		kvm_setup_help();
274 
275 	r = do_setup(instance_name);
276 	if (r == 0)
277 		printf("A new rootfs '%s' has been created in '%s%s'.\n\n"
278 			"You can now start it by running the following command:\n\n"
279 			"  %s run -d %s\n",
280 			instance_name, kvm__get_dir(), instance_name,
281 			KVM_BINARY_NAME,instance_name);
282 	else
283 		printf("Unable to create rootfs in %s%s: %s\n",
284 			kvm__get_dir(), instance_name, strerror(errno));
285 
286 	return r;
287 }
288