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