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