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