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