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