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