xref: /kvmtool/builtin-setup.c (revision 63fd57b95c607d9465eb53ae82533e7e93515c97)
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 extern char _binary_guest_init_start;
20 extern char _binary_guest_init_size;
21 
22 static const char *instance_name;
23 
24 static const char * const setup_usage[] = {
25 	"lkvm 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("\n%s setup creates a new rootfs under %s.\n"
50 		"This can be used later by the '-d' parameter of '%s run'.\n",
51 		KVM_BINARY_NAME, kvm__get_dir(), KVM_BINARY_NAME);
52 	usage_with_options(setup_usage, setup_options);
53 }
54 
55 static int copy_file(const char *from, const char *to)
56 {
57 	int in_fd, out_fd;
58 	void *src, *dst;
59 	struct stat st;
60 	int err = -1;
61 
62 	in_fd = open(from, O_RDONLY);
63 	if (in_fd < 0)
64 		return err;
65 
66 	if (fstat(in_fd, &st) < 0)
67 		goto error_close_in;
68 
69 	out_fd = open(to, O_RDWR | O_CREAT | O_TRUNC, st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO));
70 	if (out_fd < 0)
71 		goto error_close_in;
72 
73 	src = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, in_fd, 0);
74 	if (src == MAP_FAILED)
75 		goto error_close_out;
76 
77 	if (ftruncate(out_fd, st.st_size) < 0)
78 		goto error_munmap_src;
79 
80 	dst = mmap(NULL, st.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, out_fd, 0);
81 	if (dst == MAP_FAILED)
82 		goto error_munmap_src;
83 
84 	memcpy(dst, src, st.st_size);
85 
86 	if (fsync(out_fd) < 0)
87 		goto error_munmap_dst;
88 
89 	err = 0;
90 
91 error_munmap_dst:
92 	munmap(dst, st.st_size);
93 error_munmap_src:
94 	munmap(src, st.st_size);
95 error_close_out:
96 	close(out_fd);
97 error_close_in:
98 	close(in_fd);
99 
100 	return err;
101 }
102 
103 static const char *guestfs_dirs[] = {
104 	"/dev",
105 	"/etc",
106 	"/home",
107 	"/host",
108 	"/proc",
109 	"/root",
110 	"/sys",
111 	"/tmp",
112 	"/var",
113 	"/var/lib",
114 	"/virt",
115 	"/virt/home",
116 };
117 
118 static const char *guestfs_symlinks[] = {
119 	"/bin",
120 	"/lib",
121 	"/lib64",
122 	"/sbin",
123 	"/usr",
124 	"/etc/ld.so.conf",
125 };
126 
127 static int copy_init(const char *guestfs_name)
128 {
129 	char path[PATH_MAX];
130 	size_t size;
131 	int fd, ret;
132 	char *data;
133 
134 	size = (size_t)&_binary_guest_init_size;
135 	data = (char *)&_binary_guest_init_start;
136 	snprintf(path, PATH_MAX, "%s%s/virt/init", kvm__get_dir(), guestfs_name);
137 	remove(path);
138 	fd = open(path, O_CREAT | O_WRONLY, 0755);
139 	if (fd < 0)
140 		die("Fail to setup %s", path);
141 	ret = xwrite(fd, data, size);
142 	if (ret < 0)
143 		die("Fail to setup %s", path);
144 	close(fd);
145 
146 	return 0;
147 }
148 
149 static int copy_passwd(const char *guestfs_name)
150 {
151 	char path[PATH_MAX];
152 	FILE *file;
153 	int ret;
154 
155 	snprintf(path, PATH_MAX, "%s%s/etc/passwd", kvm__get_dir(), guestfs_name);
156 
157 	file = fopen(path, "w");
158 	if (!file)
159 		return -1;
160 
161 	ret = fprintf(file, "root:x:0:0:root:/root:/bin/sh\n");
162 	if (ret > 0)
163 		ret = 0;
164 
165 	fclose(file);
166 
167 	return ret;
168 }
169 
170 static int make_guestfs_symlink(const char *guestfs_name, const char *path)
171 {
172 	char target[PATH_MAX];
173 	char name[PATH_MAX];
174 
175 	snprintf(name, PATH_MAX, "%s%s%s", kvm__get_dir(), guestfs_name, path);
176 
177 	snprintf(target, PATH_MAX, "/host%s", path);
178 
179 	return symlink(target, name);
180 }
181 
182 static int make_dir(const char *dir)
183 {
184 	char name[PATH_MAX];
185 
186 	snprintf(name, PATH_MAX, "%s%s", kvm__get_dir(), dir);
187 
188 	return mkdir(name, 0777);
189 }
190 
191 static void make_guestfs_dir(const char *guestfs_name, const char *dir)
192 {
193 	char name[PATH_MAX];
194 
195 	snprintf(name, PATH_MAX, "%s%s", guestfs_name, dir);
196 
197 	make_dir(name);
198 }
199 
200 void kvm_setup_resolv(const char *guestfs_name)
201 {
202 	char path[PATH_MAX];
203 
204 	snprintf(path, PATH_MAX, "%s%s/etc/resolv.conf", kvm__get_dir(), guestfs_name);
205 
206 	copy_file("/etc/resolv.conf", path);
207 }
208 
209 static int do_setup(const char *guestfs_name)
210 {
211 	unsigned int i;
212 	int ret;
213 
214 	ret = make_dir(guestfs_name);
215 	if (ret < 0)
216 		return ret;
217 
218 	for (i = 0; i < ARRAY_SIZE(guestfs_dirs); i++)
219 		make_guestfs_dir(guestfs_name, guestfs_dirs[i]);
220 
221 	for (i = 0; i < ARRAY_SIZE(guestfs_symlinks); i++) {
222 		make_guestfs_symlink(guestfs_name, guestfs_symlinks[i]);
223 	}
224 
225 	ret = copy_init(guestfs_name);
226 	if (ret < 0)
227 		return ret;
228 
229 	return copy_passwd(guestfs_name);
230 }
231 
232 int kvm_setup_create_new(const char *guestfs_name)
233 {
234 	return do_setup(guestfs_name);
235 }
236 
237 int kvm_cmd_setup(int argc, const char **argv, const char *prefix)
238 {
239 	int r;
240 
241 	parse_setup_options(argc, argv);
242 
243 	if (instance_name == NULL)
244 		kvm_setup_help();
245 
246 	r = do_setup(instance_name);
247 	if (r == 0)
248 		printf("A new rootfs '%s' has been created in '%s%s'.\n\n"
249 			"You can now start it by running the following command:\n\n"
250 			"  %s run -d %s\n",
251 			instance_name, kvm__get_dir(), instance_name,
252 			KVM_BINARY_NAME,instance_name);
253 	else
254 		printf("Unable to create rootfs in %s%s: %s\n",
255 			kvm__get_dir(), instance_name, strerror(errno));
256 
257 	return r;
258 }
259