xref: /kvmtool/builtin-setup.c (revision 282113fd5168ea00fa06f7581bf958eb02c8cca7)
1*282113fdSPekka Enberg #include <kvm/util.h>
2*282113fdSPekka Enberg #include <kvm/kvm-cmd.h>
3*282113fdSPekka Enberg #include <kvm/builtin-setup.h>
4*282113fdSPekka Enberg #include <kvm/kvm.h>
5*282113fdSPekka Enberg #include <kvm/parse-options.h>
6*282113fdSPekka Enberg 
7*282113fdSPekka Enberg #include <sys/types.h>
8*282113fdSPekka Enberg #include <sys/stat.h>
9*282113fdSPekka Enberg #include <limits.h>
10*282113fdSPekka Enberg #include <signal.h>
11*282113fdSPekka Enberg #include <stdlib.h>
12*282113fdSPekka Enberg #include <string.h>
13*282113fdSPekka Enberg #include <unistd.h>
14*282113fdSPekka Enberg #include <stdio.h>
15*282113fdSPekka Enberg #include <sys/types.h>
16*282113fdSPekka Enberg #include <sys/mman.h>
17*282113fdSPekka Enberg #include <sys/stat.h>
18*282113fdSPekka Enberg #include <string.h>
19*282113fdSPekka Enberg #include <unistd.h>
20*282113fdSPekka Enberg #include <fcntl.h>
21*282113fdSPekka Enberg 
22*282113fdSPekka Enberg #define KVM_PID_FILE_PATH	"/.kvm-tools/"
23*282113fdSPekka Enberg #define HOME_DIR		getenv("HOME")
24*282113fdSPekka Enberg 
25*282113fdSPekka Enberg static const char *instance_name;
26*282113fdSPekka Enberg 
27*282113fdSPekka Enberg static const char * const setup_usage[] = {
28*282113fdSPekka Enberg 	"kvm setup [-n name]",
29*282113fdSPekka Enberg 	NULL
30*282113fdSPekka Enberg };
31*282113fdSPekka Enberg 
32*282113fdSPekka Enberg static const struct option setup_options[] = {
33*282113fdSPekka Enberg 	OPT_GROUP("General options:"),
34*282113fdSPekka Enberg 	OPT_STRING('n', "name", &instance_name, "name", "Instance name"),
35*282113fdSPekka Enberg 	OPT_END()
36*282113fdSPekka Enberg };
37*282113fdSPekka Enberg 
38*282113fdSPekka Enberg static void parse_setup_options(int argc, const char **argv)
39*282113fdSPekka Enberg {
40*282113fdSPekka Enberg 	while (argc != 0) {
41*282113fdSPekka Enberg 		argc = parse_options(argc, argv, setup_options, setup_usage,
42*282113fdSPekka Enberg 				PARSE_OPT_STOP_AT_NON_OPTION);
43*282113fdSPekka Enberg 		if (argc != 0)
44*282113fdSPekka Enberg 			kvm_setup_help();
45*282113fdSPekka Enberg 	}
46*282113fdSPekka Enberg }
47*282113fdSPekka Enberg 
48*282113fdSPekka Enberg void kvm_setup_help(void)
49*282113fdSPekka Enberg {
50*282113fdSPekka Enberg 	usage_with_options(setup_usage, setup_options);
51*282113fdSPekka Enberg }
52*282113fdSPekka Enberg 
53*282113fdSPekka Enberg static int copy_file(const char *from, const char *to)
54*282113fdSPekka Enberg {
55*282113fdSPekka Enberg 	int in_fd, out_fd;
56*282113fdSPekka Enberg 	void *src, *dst;
57*282113fdSPekka Enberg 	struct stat st;
58*282113fdSPekka Enberg 	int err = -1;
59*282113fdSPekka Enberg 
60*282113fdSPekka Enberg 	in_fd = open(from, O_RDONLY);
61*282113fdSPekka Enberg 	if (in_fd < 0)
62*282113fdSPekka Enberg 		return err;
63*282113fdSPekka Enberg 
64*282113fdSPekka Enberg 	if (fstat(in_fd, &st) < 0)
65*282113fdSPekka Enberg 		goto error_close_in;
66*282113fdSPekka Enberg 
67*282113fdSPekka Enberg 	out_fd = open(to, O_RDWR | O_CREAT | O_TRUNC, st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO));
68*282113fdSPekka Enberg 	if (out_fd < 0)
69*282113fdSPekka Enberg 		goto error_close_in;
70*282113fdSPekka Enberg 
71*282113fdSPekka Enberg 	src = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, in_fd, 0);
72*282113fdSPekka Enberg 	if (src == MAP_FAILED)
73*282113fdSPekka Enberg 		goto error_close_out;
74*282113fdSPekka Enberg 
75*282113fdSPekka Enberg 	if (ftruncate(out_fd, st.st_size) < 0)
76*282113fdSPekka Enberg 		goto error_munmap_src;
77*282113fdSPekka Enberg 
78*282113fdSPekka Enberg 	dst = mmap(NULL, st.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, out_fd, 0);
79*282113fdSPekka Enberg 	if (dst == MAP_FAILED)
80*282113fdSPekka Enberg 		goto error_munmap_src;
81*282113fdSPekka Enberg 
82*282113fdSPekka Enberg 	memcpy(dst, src, st.st_size);
83*282113fdSPekka Enberg 
84*282113fdSPekka Enberg 	if (fsync(out_fd) < 0)
85*282113fdSPekka Enberg 		goto error_munmap_dst;
86*282113fdSPekka Enberg 
87*282113fdSPekka Enberg 	err = 0;
88*282113fdSPekka Enberg 
89*282113fdSPekka Enberg error_munmap_dst:
90*282113fdSPekka Enberg 	munmap(dst, st.st_size);
91*282113fdSPekka Enberg error_munmap_src:
92*282113fdSPekka Enberg 	munmap(src, st.st_size);
93*282113fdSPekka Enberg error_close_out:
94*282113fdSPekka Enberg 	close(out_fd);
95*282113fdSPekka Enberg error_close_in:
96*282113fdSPekka Enberg 	close(in_fd);
97*282113fdSPekka Enberg 
98*282113fdSPekka Enberg 	return err;
99*282113fdSPekka Enberg }
100*282113fdSPekka Enberg 
101*282113fdSPekka Enberg static const char *guestfs_dirs[] = {
102*282113fdSPekka Enberg 	"/dev",
103*282113fdSPekka Enberg 	"/etc",
104*282113fdSPekka Enberg 	"/home",
105*282113fdSPekka Enberg 	"/host",
106*282113fdSPekka Enberg 	"/proc",
107*282113fdSPekka Enberg 	"/root",
108*282113fdSPekka Enberg 	"/sys",
109*282113fdSPekka Enberg 	"/var",
110*282113fdSPekka Enberg 	"/var/lib",
111*282113fdSPekka Enberg 	"/virt",
112*282113fdSPekka Enberg };
113*282113fdSPekka Enberg 
114*282113fdSPekka Enberg static const char *guestfs_symlinks[] = {
115*282113fdSPekka Enberg 	"/bin",
116*282113fdSPekka Enberg 	"/lib",
117*282113fdSPekka Enberg 	"/lib64",
118*282113fdSPekka Enberg 	"/sbin",
119*282113fdSPekka Enberg 	"/usr",
120*282113fdSPekka Enberg };
121*282113fdSPekka Enberg 
122*282113fdSPekka Enberg static int copy_init(const char *guestfs_name)
123*282113fdSPekka Enberg {
124*282113fdSPekka Enberg 	char path[PATH_MAX];
125*282113fdSPekka Enberg 
126*282113fdSPekka Enberg 	snprintf(path, PATH_MAX, "%s%s%s/virt/init", HOME_DIR, KVM_PID_FILE_PATH, guestfs_name);
127*282113fdSPekka Enberg 
128*282113fdSPekka Enberg 	return copy_file("guest/init", path);
129*282113fdSPekka Enberg }
130*282113fdSPekka Enberg 
131*282113fdSPekka Enberg static int make_guestfs_symlink(const char *guestfs_name, const char *path)
132*282113fdSPekka Enberg {
133*282113fdSPekka Enberg 	char target[PATH_MAX];
134*282113fdSPekka Enberg 	char name[PATH_MAX];
135*282113fdSPekka Enberg 
136*282113fdSPekka Enberg 	snprintf(name, PATH_MAX, "%s%s%s%s", HOME_DIR, KVM_PID_FILE_PATH, guestfs_name, path);
137*282113fdSPekka Enberg 
138*282113fdSPekka Enberg 	snprintf(target, PATH_MAX, "/host%s", path);
139*282113fdSPekka Enberg 
140*282113fdSPekka Enberg 	return symlink(target, name);
141*282113fdSPekka Enberg }
142*282113fdSPekka Enberg 
143*282113fdSPekka Enberg static void make_dir(const char *dir)
144*282113fdSPekka Enberg {
145*282113fdSPekka Enberg 	char name[PATH_MAX];
146*282113fdSPekka Enberg 
147*282113fdSPekka Enberg 	snprintf(name, PATH_MAX, "%s%s%s", HOME_DIR, KVM_PID_FILE_PATH, dir);
148*282113fdSPekka Enberg 
149*282113fdSPekka Enberg 	mkdir(name, 0777);
150*282113fdSPekka Enberg }
151*282113fdSPekka Enberg 
152*282113fdSPekka Enberg static void make_guestfs_dir(const char *guestfs_name, const char *dir)
153*282113fdSPekka Enberg {
154*282113fdSPekka Enberg 	char name[PATH_MAX];
155*282113fdSPekka Enberg 
156*282113fdSPekka Enberg 	snprintf(name, PATH_MAX, "%s%s", guestfs_name, dir);
157*282113fdSPekka Enberg 
158*282113fdSPekka Enberg 	make_dir(name);
159*282113fdSPekka Enberg }
160*282113fdSPekka Enberg 
161*282113fdSPekka Enberg static int do_setup(const char *guestfs_name)
162*282113fdSPekka Enberg {
163*282113fdSPekka Enberg 	unsigned int i;
164*282113fdSPekka Enberg 
165*282113fdSPekka Enberg 	make_dir(guestfs_name);
166*282113fdSPekka Enberg 
167*282113fdSPekka Enberg 	for (i = 0; i < ARRAY_SIZE(guestfs_dirs); i++)
168*282113fdSPekka Enberg 		make_guestfs_dir(guestfs_name, guestfs_dirs[i]);
169*282113fdSPekka Enberg 
170*282113fdSPekka Enberg 	for (i = 0; i < ARRAY_SIZE(guestfs_symlinks); i++) {
171*282113fdSPekka Enberg 		make_guestfs_symlink(guestfs_name, guestfs_symlinks[i]);
172*282113fdSPekka Enberg 	}
173*282113fdSPekka Enberg 
174*282113fdSPekka Enberg 	return copy_init(guestfs_name);
175*282113fdSPekka Enberg }
176*282113fdSPekka Enberg 
177*282113fdSPekka Enberg int kvm_cmd_setup(int argc, const char **argv, const char *prefix)
178*282113fdSPekka Enberg {
179*282113fdSPekka Enberg 	parse_setup_options(argc, argv);
180*282113fdSPekka Enberg 
181*282113fdSPekka Enberg 	if (instance_name == NULL)
182*282113fdSPekka Enberg 		kvm_setup_help();
183*282113fdSPekka Enberg 
184*282113fdSPekka Enberg 	return do_setup(instance_name);
185*282113fdSPekka Enberg }
186