]> rtime.felk.cvut.cz Git - jailhouse.git/blob - tools/jailhouse.c
arm: Fold irqchip_root_cell_shrink into irqchip_cell_init
[jailhouse.git] / tools / jailhouse.c
1 /*
2  * Jailhouse, a Linux-based partitioning hypervisor
3  *
4  * Copyright (c) Siemens AG, 2013-2016
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 #define JAILHOUSE_EXEC_DIR      LIBEXECDIR "/jailhouse"
29
30 enum shutdown_load_mode {LOAD, SHUTDOWN};
31
32 struct extension {
33         char *cmd, *subcmd, *help;
34 };
35
36 static const struct extension extensions[] = {
37         { "cell", "linux", "CELLCONFIG KERNEL [-i | --initrd FILE]\n"
38           "              [-c | --cmdline \"STRING\"] "
39                                         "[-w | --write-params FILE]" },
40         { "cell", "list", "" },
41         { "cell", "stats", "{ ID | [--name] NAME }" },
42         { "config", "create", "[-h] [-g] [-r ROOT] "
43           "[--mem-inmates MEM_INMATES]\n"
44           "                 [--mem-hv MEM_HV] FILE" },
45         { "config", "collect", "FILE.TAR" },
46         { "hardware", "check", "SYSCONFIG" },
47         { NULL }
48 };
49
50 static void __attribute__((noreturn)) help(char *prog, int exit_status)
51 {
52         const struct extension *ext;
53
54         printf("Usage: %s { COMMAND | --help || --version }\n"
55                "\nAvailable commands:\n"
56                "   enable SYSCONFIG\n"
57                "   disable\n"
58                "   cell create CELLCONFIG\n"
59                "   cell load { ID | [--name] NAME } "
60                                 "{ IMAGE | { -s | --string } \"STRING\" }\n"
61                "             [-a | --address ADDRESS] ...\n"
62                "   cell start { ID | [--name] NAME }\n"
63                "   cell shutdown { ID | [--name] NAME }\n"
64                "   cell destroy { ID | [--name] NAME }\n",
65                basename(prog));
66         for (ext = extensions; ext->cmd; ext++)
67                 printf("   %s %s %s\n", ext->cmd, ext->subcmd, ext->help);
68
69         exit(exit_status);
70 }
71
72 static void call_extension_script(const char *cmd, int argc, char *argv[])
73 {
74         const struct extension *ext;
75         char new_path[PATH_MAX];
76         char script[64];
77
78         if (argc < 3)
79                 return;
80
81         for (ext = extensions; ext->cmd; ext++) {
82                 if (strcmp(ext->cmd, cmd) != 0 ||
83                     strcmp(ext->subcmd, argv[2]) != 0)
84                         continue;
85
86                 snprintf(new_path, sizeof(new_path), "PATH=%s:%s:%s",
87                         dirname(argv[0]), JAILHOUSE_EXEC_DIR,
88                         getenv("PATH") ? : "");
89                 putenv(new_path);
90
91                 snprintf(script, sizeof(script), "jailhouse-%s-%s",
92                          cmd, ext->subcmd);
93                 execvp(script, &argv[2]);
94
95                 perror("execvp");
96                 exit(1);
97         }
98 }
99
100 static int open_dev()
101 {
102         int fd;
103
104         fd = open("/dev/jailhouse", O_RDWR);
105         if (fd < 0) {
106                 perror("opening /dev/jailhouse");
107                 exit(1);
108         }
109         return fd;
110 }
111
112 static void *read_string(const char *string, size_t *size)
113 {
114         void *buffer;
115
116         *size = strlen(string) + 1;
117
118         buffer = strdup(string);
119         if (!buffer) {
120                 fprintf(stderr, "insufficient memory\n");
121                 exit(1);
122         }
123
124         return buffer;
125 }
126
127 static void *read_file(const char *name, size_t *size)
128 {
129         struct stat stat;
130         void *buffer;
131         int fd;
132
133         fd = open(name, O_RDONLY);
134         if (fd < 0) {
135                 fprintf(stderr, "opening %s: %s\n", name, strerror(errno));
136                 exit(1);
137         }
138
139         if (fstat(fd, &stat) < 0) {
140                 perror("fstat");
141                 exit(1);
142         }
143
144         buffer = malloc(stat.st_size);
145         if (!buffer) {
146                 fprintf(stderr, "insufficient memory\n");
147                 exit(1);
148         }
149
150         if (read(fd, buffer, stat.st_size) < stat.st_size) {
151                 fprintf(stderr, "reading %s: %s\n", name, strerror(errno));
152                 exit(1);
153         }
154
155         close(fd);
156
157         if (size)
158                 *size = stat.st_size;
159
160         return buffer;
161 }
162
163 static int enable(int argc, char *argv[])
164 {
165         void *config;
166         int err, fd;
167
168         if (argc != 3)
169                 help(argv[0], 1);
170
171         config = read_file(argv[2], NULL);
172
173         fd = open_dev();
174
175         err = ioctl(fd, JAILHOUSE_ENABLE, config);
176         if (err)
177                 perror("JAILHOUSE_ENABLE");
178
179         close(fd);
180         free(config);
181
182         return err;
183 }
184
185 static int cell_create(int argc, char *argv[])
186 {
187         struct jailhouse_cell_create cell_create;
188         size_t size;
189         int err, fd;
190
191         if (argc != 4)
192                 help(argv[0], 1);
193
194         cell_create.config_address = (unsigned long)read_file(argv[3], &size);
195         cell_create.config_size = size;
196
197         fd = open_dev();
198
199         err = ioctl(fd, JAILHOUSE_CELL_CREATE, &cell_create);
200         if (err)
201                 perror("JAILHOUSE_CELL_CREATE");
202
203         close(fd);
204         free((void *)(unsigned long)cell_create.config_address);
205
206         return err;
207 }
208
209 static int parse_cell_id(struct jailhouse_cell_id *cell_id, int argc,
210                          char *argv[])
211 {
212         bool use_name = false;
213         int arg_pos = 0;
214         char *endp;
215
216         memset(cell_id, 0, sizeof(*cell_id));
217
218         if (argc < 1)
219                 return 0;
220
221         if (strcmp(argv[0], "--name") == 0) {
222                 if (argc < 2)
223                         return 0;
224                 arg_pos++;
225                 use_name = true;
226         } else {
227                 errno = 0;
228                 cell_id->id = strtoll(argv[0], &endp, 0);
229                 if (errno != 0 || *endp != 0 || cell_id->id < 0)
230                         use_name = true;
231         }
232
233         if (use_name) {
234                 cell_id->id = JAILHOUSE_CELL_ID_UNUSED;
235                 /* cell_id is initialized with zeros, so leaving out the last
236                  * byte ensures that the string is always terminated. */
237                 strncpy(cell_id->name, argv[arg_pos],
238                         sizeof(cell_id->name) - 1);
239         }
240
241         return arg_pos + 1;
242 }
243
244 static bool match_opt(const char *argv, const char *short_opt,
245                       const char *long_opt)
246 {
247         return strcmp(argv, short_opt) == 0 ||
248                 strcmp(argv, long_opt) == 0;
249 }
250
251 static int cell_shutdown_load(int argc, char *argv[],
252                               enum shutdown_load_mode mode)
253 {
254         struct jailhouse_preload_image *image;
255         struct jailhouse_cell_load *cell_load;
256         struct jailhouse_cell_id cell_id;
257         int err, fd, id_args, arg_num;
258         unsigned int images, n;
259         size_t size;
260         char *endp;
261
262         id_args = parse_cell_id(&cell_id, argc - 3, &argv[3]);
263         arg_num = 3 + id_args;
264         if (id_args == 0 || (mode == SHUTDOWN && arg_num != argc) ||
265             (mode == LOAD && arg_num == argc))
266                 help(argv[0], 1);
267
268         images = 0;
269         while (arg_num < argc) {
270                 if (match_opt(argv[arg_num], "-s", "--string")) {
271                         if (arg_num + 1 >= argc)
272                                 help(argv[0], 1);
273                         arg_num++;
274                 }
275
276                 images++;
277                 arg_num++;
278
279                 if (arg_num < argc &&
280                     match_opt(argv[arg_num], "-a", "--address")) {
281                         if (arg_num + 1 >= argc)
282                                 help(argv[0], 1);
283                         arg_num += 2;
284                 }
285         }
286
287         cell_load = malloc(sizeof(*cell_load) + sizeof(*image) * images);
288         if (!cell_load) {
289                 fprintf(stderr, "insufficient memory\n");
290                 exit(1);
291         }
292         cell_load->cell_id = cell_id;
293         cell_load->num_preload_images = images;
294
295         arg_num = 3 + id_args;
296
297         for (n = 0, image = cell_load->image; n < images; n++, image++) {
298                 if (match_opt(argv[arg_num], "-s", "--string")) {
299                         arg_num++;
300                         image->source_address =
301                                 (unsigned long)read_string(argv[arg_num++],
302                                                            &size);
303                 } else {
304                         image->source_address =
305                                 (unsigned long)read_file(argv[arg_num++],
306                                                          &size);
307                 }
308                 image->size = size;
309                 image->target_address = 0;
310
311                 if (arg_num < argc &&
312                     match_opt(argv[arg_num], "-a", "--address")) {
313                         errno = 0;
314                         image->target_address =
315                                 strtoll(argv[arg_num + 1], &endp, 0);
316                         if (errno != 0 || *endp != 0)
317                                 help(argv[0], 1);
318                         arg_num += 2;
319                 }
320         }
321
322         fd = open_dev();
323
324         err = ioctl(fd, JAILHOUSE_CELL_LOAD, cell_load);
325         if (err)
326                 perror("JAILHOUSE_CELL_LOAD");
327
328         close(fd);
329         for (n = 0, image = cell_load->image; n < images; n++, image++)
330                 free((void *)(unsigned long)image->source_address);
331         free(cell_load);
332
333         return err;
334 }
335
336 static int cell_simple_cmd(int argc, char *argv[], unsigned int command)
337 {
338         struct jailhouse_cell_id cell_id;
339         int id_args, err, fd;
340
341         id_args = parse_cell_id(&cell_id, argc - 3, &argv[3]);
342         if (id_args == 0 || 3 + id_args != argc)
343                 help(argv[0], 1);
344
345         fd = open_dev();
346
347         err = ioctl(fd, command, &cell_id);
348         if (err)
349                 perror(command == JAILHOUSE_CELL_START ?
350                        "JAILHOUSE_CELL_START" :
351                        command == JAILHOUSE_CELL_DESTROY ?
352                        "JAILHOUSE_CELL_DESTROY" :
353                        "<unknown command>");
354
355         close(fd);
356
357         return err;
358 }
359
360 static int cell_management(int argc, char *argv[])
361 {
362         int err;
363
364         if (argc < 3)
365                 help(argv[0], 1);
366
367         if (strcmp(argv[2], "create") == 0) {
368                 err = cell_create(argc, argv);
369         } else if (strcmp(argv[2], "load") == 0) {
370                 err = cell_shutdown_load(argc, argv, LOAD);
371         } else if (strcmp(argv[2], "start") == 0) {
372                 err = cell_simple_cmd(argc, argv, JAILHOUSE_CELL_START);
373         } else if (strcmp(argv[2], "shutdown") == 0) {
374                 err = cell_shutdown_load(argc, argv, SHUTDOWN);
375         } else if (strcmp(argv[2], "destroy") == 0) {
376                 err = cell_simple_cmd(argc, argv, JAILHOUSE_CELL_DESTROY);
377         } else {
378                 call_extension_script("cell", argc, argv);
379                 help(argv[0], 1);
380         }
381
382         return err;
383 }
384
385 int main(int argc, char *argv[])
386 {
387         int fd;
388         int err;
389
390         if (argc < 2)
391                 help(argv[0], 1);
392
393         if (strcmp(argv[1], "enable") == 0) {
394                 err = enable(argc, argv);
395         } else if (strcmp(argv[1], "disable") == 0) {
396                 fd = open_dev();
397                 err = ioctl(fd, JAILHOUSE_DISABLE);
398                 if (err)
399                         perror("JAILHOUSE_DISABLE");
400                 close(fd);
401         } else if (strcmp(argv[1], "cell") == 0) {
402                 err = cell_management(argc, argv);
403         } else if (strcmp(argv[1], "config") == 0 ||
404                    strcmp(argv[1], "hardware") == 0) {
405                 call_extension_script(argv[1], argc, argv);
406                 help(argv[0], 1);
407         } else if (strcmp(argv[1], "--version") == 0) {
408                 printf("Jailhouse management tool %s\n", JAILHOUSE_VERSION);
409                 return 0;
410         } else if (strcmp(argv[1], "--help") == 0) {
411                 help(argv[0], 0);
412         } else {
413                 help(argv[0], 1);
414         }
415
416         return err ? 1 : 0;
417 }