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