]> rtime.felk.cvut.cz Git - jailhouse.git/blob - tools/jailhouse.c
tools: config-create: Initial support for non-Intel boards
[jailhouse.git] / tools / jailhouse.c
1 /*
2  * Jailhouse, a Linux-based partitioning hypervisor
3  *
4  * Copyright (c) Siemens AG, 2013
5  *
6  * Authors:
7  *  Jan Kiszka <jan.kiszka@siemens.com>
8  *
9  * This work is licensed under the terms of the GNU GPL, version 2.  See
10  * the COPYING file in the top-level directory.
11  */
12
13 #include <stdbool.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <unistd.h>
18 #include <fcntl.h>
19 #include <errno.h>
20 #include <limits.h>
21 #include <libgen.h>
22 #include <sys/types.h>
23 #include <sys/ioctl.h>
24 #include <sys/stat.h>
25
26 #include <jailhouse.h>
27
28 enum shutdown_load_mode {LOAD, SHUTDOWN};
29
30 struct extension {
31         char *cmd, *subcmd, *help;
32 };
33
34 static const struct extension extensions[] = {
35         { "cell", "list", "" },
36         { "cell", "stats", "{ ID | [--name] NAME }" },
37         { "config", "create", "[-h] [-g] [-r ROOT] "
38           "[--mem-inmates MEM_INMATES] [--mem-hv MEM_HV] FILE" },
39         { "config", "collect", "FILE.TAR" },
40         { NULL }
41 };
42
43 static void __attribute__((noreturn)) help(char *prog, int exit_status)
44 {
45         const struct extension *ext;
46
47         printf("Usage: %s { COMMAND | --help }\n"
48                "\nAvailable commands:\n"
49                "   enable SYSCONFIG\n"
50                "   disable\n"
51                "   cell create CELLCONFIG\n"
52                "   cell load { ID | [--name] NAME } IMAGE "
53                         "[ -a | --address ADDRESS] ...\n"
54                "   cell start { ID | [--name] NAME }\n"
55                "   cell shutdown { ID | [--name] NAME }\n"
56                "   cell destroy { ID | [--name] NAME }\n",
57                basename(prog));
58         for (ext = extensions; ext->cmd; ext++)
59                 printf("   %s %s %s\n", ext->cmd, ext->subcmd, ext->help);
60
61         exit(exit_status);
62 }
63
64 static void call_extension_script(const char *cmd, int argc, char *argv[])
65 {
66         const struct extension *ext;
67         char new_path[PATH_MAX];
68         char script[64];
69
70         if (argc < 3)
71                 return;
72
73         for (ext = extensions; ext->cmd; ext++) {
74                 if (strcmp(ext->cmd, cmd) != 0 ||
75                     strcmp(ext->subcmd, argv[2]) != 0)
76                         continue;
77
78                 snprintf(new_path, sizeof(new_path), "PATH=%s:%s:%s",
79                         dirname(argv[0]), "/usr/lib/jailhouse",
80                         getenv("PATH") ? : "");
81                 putenv(new_path);
82
83                 snprintf(script, sizeof(script), "jailhouse-%s-%s",
84                          cmd, ext->subcmd);
85                 execvp(script, &argv[2]);
86
87                 perror("execvp");
88                 exit(1);
89         }
90 }
91
92 static int open_dev()
93 {
94         int fd;
95
96         fd = open("/dev/jailhouse", O_RDWR);
97         if (fd < 0) {
98                 perror("opening /dev/jailhouse");
99                 exit(1);
100         }
101         return fd;
102 }
103
104 static void *read_file(const char *name, size_t *size)
105 {
106         struct stat stat;
107         void *buffer;
108         int fd;
109
110         fd = open(name, O_RDONLY);
111         if (fd < 0) {
112                 fprintf(stderr, "opening %s: %s\n", name, strerror(errno));
113                 exit(1);
114         }
115
116         if (fstat(fd, &stat) < 0) {
117                 perror("fstat");
118                 exit(1);
119         }
120
121         buffer = malloc(stat.st_size);
122         if (!buffer) {
123                 fprintf(stderr, "insufficient memory\n");
124                 exit(1);
125         }
126
127         if (read(fd, buffer, stat.st_size) < stat.st_size) {
128                 fprintf(stderr, "reading %s: %s\n", name, strerror(errno));
129                 exit(1);
130         }
131
132         close(fd);
133
134         if (size)
135                 *size = stat.st_size;
136
137         return buffer;
138 }
139
140 static int enable(int argc, char *argv[])
141 {
142         void *config;
143         int err, fd;
144
145         if (argc != 3)
146                 help(argv[0], 1);
147
148         config = read_file(argv[2], NULL);
149
150         fd = open_dev();
151
152         err = ioctl(fd, JAILHOUSE_ENABLE, config);
153         if (err)
154                 perror("JAILHOUSE_ENABLE");
155
156         close(fd);
157         free(config);
158
159         return err;
160 }
161
162 static int cell_create(int argc, char *argv[])
163 {
164         struct jailhouse_cell_create cell_create;
165         size_t size;
166         int err, fd;
167
168         if (argc != 4)
169                 help(argv[0], 1);
170
171         cell_create.config_address = (unsigned long)read_file(argv[3], &size);
172         cell_create.config_size = size;
173
174         fd = open_dev();
175
176         err = ioctl(fd, JAILHOUSE_CELL_CREATE, &cell_create);
177         if (err)
178                 perror("JAILHOUSE_CELL_CREATE");
179
180         close(fd);
181
182         return err;
183 }
184
185 static int parse_cell_id(struct jailhouse_cell_id *cell_id, int argc,
186                          char *argv[])
187 {
188         bool use_name = false;
189         int arg_pos = 0;
190         char *endp;
191
192         if (argc < 1)
193                 return 0;
194
195         if (strcmp(argv[0], "--name") == 0) {
196                 if (argc < 2)
197                         return 0;
198                 arg_pos++;
199                 use_name = true;
200         } else {
201                 errno = 0;
202                 cell_id->id = strtoll(argv[0], &endp, 0);
203                 if (errno != 0 || *endp != 0 || cell_id->id < 0)
204                         use_name = true;
205         }
206
207         if (use_name) {
208                 cell_id->id = JAILHOUSE_CELL_ID_UNUSED;
209                 strncpy(cell_id->name, argv[arg_pos], sizeof(cell_id->name));
210                 cell_id->name[sizeof(cell_id->name) - 1] = 0;
211         }
212
213         return arg_pos + 1;
214 }
215
216 static bool match_opt(const char *argv, const char *short_opt,
217                       const char *long_opt)
218 {
219         return strcmp(argv, short_opt) == 0 ||
220                 strcmp(argv, long_opt) == 0;
221 }
222
223 static int cell_shutdown_load(int argc, char *argv[],
224                               enum shutdown_load_mode mode)
225 {
226         unsigned int images, id_args, arg_num, n;
227         struct jailhouse_preload_image *image;
228         struct jailhouse_cell_load *cell_load;
229         struct jailhouse_cell_id cell_id;
230         size_t size;
231         int err, fd;
232         char *endp;
233
234         id_args = parse_cell_id(&cell_id, argc - 3, &argv[3]);
235         arg_num = 3 + id_args;
236         if (id_args == 0 || (mode == SHUTDOWN && arg_num != argc) ||
237             (mode == LOAD && arg_num == argc))
238                 help(argv[0], 1);
239
240         images = 0;
241         while (arg_num < argc) {
242                 images++;
243                 arg_num++;
244
245                 if (arg_num < argc &&
246                     match_opt(argv[arg_num], "-a", "--address")) {
247                         if (arg_num + 1 >= argc)
248                                 help(argv[0], 1);
249                         arg_num += 2;
250                 }
251         }
252
253         cell_load = malloc(sizeof(*cell_load) + sizeof(*image) * images);
254         if (!cell_load) {
255                 fprintf(stderr, "insufficient memory\n");
256                 exit(1);
257         }
258         cell_load->cell_id = cell_id;
259         cell_load->num_preload_images = images;
260
261         arg_num = 3 + id_args;
262
263         for (n = 0, image = cell_load->image; n < images; n++, image++) {
264                 image->source_address =
265                         (unsigned long)read_file(argv[arg_num++], &size);
266                 image->size = size;
267                 image->target_address = 0;
268
269                 if (arg_num < argc &&
270                     match_opt(argv[arg_num], "-a", "--address")) {
271                         errno = 0;
272                         image->target_address =
273                                 strtoll(argv[arg_num + 1], &endp, 0);
274                         if (errno != 0 || *endp != 0)
275                                 help(argv[0], 1);
276                         arg_num += 2;
277                 }
278         }
279
280         fd = open_dev();
281
282         err = ioctl(fd, JAILHOUSE_CELL_LOAD, cell_load);
283         if (err)
284                 perror("JAILHOUSE_CELL_LOAD");
285
286         close(fd);
287         for (n = 0, image = cell_load->image; n < images; n++, image++)
288                 free((void *)(unsigned long)image->source_address);
289         free(cell_load);
290
291         return err;
292 }
293
294 static int cell_simple_cmd(int argc, char *argv[], unsigned int command)
295 {
296         struct jailhouse_cell_id cell_id;
297         int id_args, err, fd;
298
299         id_args = parse_cell_id(&cell_id, argc - 3, &argv[3]);
300         if (id_args == 0 || 3 + id_args != argc)
301                 help(argv[0], 1);
302
303         fd = open_dev();
304
305         err = ioctl(fd, command, &cell_id);
306         if (err)
307                 perror(command == JAILHOUSE_CELL_START ?
308                        "JAILHOUSE_CELL_START" :
309                        command == JAILHOUSE_CELL_DESTROY ?
310                        "JAILHOUSE_CELL_DESTROY" :
311                        "<unknown command>");
312
313         close(fd);
314
315         return err;
316 }
317
318 static int cell_management(int argc, char *argv[])
319 {
320         int err;
321
322         if (argc < 3)
323                 help(argv[0], 1);
324
325         if (strcmp(argv[2], "create") == 0) {
326                 err = cell_create(argc, argv);
327         } else if (strcmp(argv[2], "load") == 0) {
328                 err = cell_shutdown_load(argc, argv, LOAD);
329         } else if (strcmp(argv[2], "start") == 0) {
330                 err = cell_simple_cmd(argc, argv, JAILHOUSE_CELL_START);
331         } else if (strcmp(argv[2], "shutdown") == 0) {
332                 err = cell_shutdown_load(argc, argv, SHUTDOWN);
333         } else if (strcmp(argv[2], "destroy") == 0) {
334                 err = cell_simple_cmd(argc, argv, JAILHOUSE_CELL_DESTROY);
335         } else {
336                 call_extension_script("cell", argc, argv);
337                 help(argv[0], 1);
338         }
339
340         return err;
341 }
342
343 int main(int argc, char *argv[])
344 {
345         int fd;
346         int err;
347
348         if (argc < 2)
349                 help(argv[0], 1);
350
351         if (strcmp(argv[1], "enable") == 0) {
352                 err = enable(argc, argv);
353         } else if (strcmp(argv[1], "disable") == 0) {
354                 fd = open_dev();
355                 err = ioctl(fd, JAILHOUSE_DISABLE);
356                 if (err)
357                         perror("JAILHOUSE_DISABLE");
358                 close(fd);
359         } else if (strcmp(argv[1], "cell") == 0) {
360                 err = cell_management(argc, argv);
361         } else if (strcmp(argv[1], "config") == 0) {
362                 call_extension_script(argv[1], argc, argv);
363                 help(argv[0], 1);
364         } else if (strcmp(argv[1], "--help") == 0) {
365                 help(argv[0], 0);
366         } else
367                 help(argv[0], 1);
368
369         return err ? 1 : 0;
370 }