]> rtime.felk.cvut.cz Git - jailhouse.git/blobdiff - tools/jailhouse.c
tools: Add hardware feature check
[jailhouse.git] / tools / jailhouse.c
index 2fad3eda6a81712778e5e6828dff88dc385a4ee8..ba2af66a666338b4b96da88cee58dc597ebe5062 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Jailhouse, a Linux-based partitioning hypervisor
  *
- * Copyright (c) Siemens AG, 2013
+ * Copyright (c) Siemens AG, 2013-2016
  *
  * Authors:
  *  Jan Kiszka <jan.kiszka@siemens.com>
  * the COPYING file in the top-level directory.
  */
 
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <errno.h>
+#include <limits.h>
+#include <libgen.h>
 #include <sys/types.h>
 #include <sys/ioctl.h>
 #include <sys/stat.h>
 
 #include <jailhouse.h>
 
-static void help(const char *progname)
+#define JAILHOUSE_EXEC_DIR     LIBEXECDIR "/jailhouse"
+
+enum shutdown_load_mode {LOAD, SHUTDOWN};
+
+struct extension {
+       char *cmd, *subcmd, *help;
+};
+
+static const struct extension extensions[] = {
+       { "cell", "linux", "CELLCONFIG KERNEL [-i | --initrd FILE]\n"
+         "              [-c | --cmdline \"STRING\"] "
+                                       "[-w | --write-params FILE]" },
+       { "cell", "list", "" },
+       { "cell", "stats", "{ ID | [--name] NAME }" },
+       { "config", "create", "[-h] [-g] [-r ROOT] "
+         "[--mem-inmates MEM_INMATES]\n"
+         "                 [--mem-hv MEM_HV] FILE" },
+       { "config", "collect", "FILE.TAR" },
+       { "hardware", "check", "SYSCONFIG" },
+       { NULL }
+};
+
+static void __attribute__((noreturn)) help(char *prog, int exit_status)
 {
-       printf("%s <command> <args>\n"
+       const struct extension *ext;
+
+       printf("Usage: %s { COMMAND | --help || --version }\n"
               "\nAvailable commands:\n"
-              "   enable CONFIGFILE\n"
+              "   enable SYSCONFIG\n"
               "   disable\n"
-              "   cell create CONFIGFILE PRELOADIMAGE [-l ADDRESS]\n"
-              "   cell destroy CONFIGFILE\n",
-              progname);
+              "   cell create CELLCONFIG\n"
+              "   cell load { ID | [--name] NAME } "
+                               "{ IMAGE | { -s | --string } \"STRING\" }\n"
+              "             [-a | --address ADDRESS] ...\n"
+              "   cell start { ID | [--name] NAME }\n"
+              "   cell shutdown { ID | [--name] NAME }\n"
+              "   cell destroy { ID | [--name] NAME }\n",
+              basename(prog));
+       for (ext = extensions; ext->cmd; ext++)
+               printf("   %s %s %s\n", ext->cmd, ext->subcmd, ext->help);
+
+       exit(exit_status);
+}
+
+static void call_extension_script(const char *cmd, int argc, char *argv[])
+{
+       const struct extension *ext;
+       char new_path[PATH_MAX];
+       char script[64];
+
+       if (argc < 3)
+               return;
+
+       for (ext = extensions; ext->cmd; ext++) {
+               if (strcmp(ext->cmd, cmd) != 0 ||
+                   strcmp(ext->subcmd, argv[2]) != 0)
+                       continue;
+
+               snprintf(new_path, sizeof(new_path), "PATH=%s:%s:%s",
+                       dirname(argv[0]), JAILHOUSE_EXEC_DIR,
+                       getenv("PATH") ? : "");
+               putenv(new_path);
+
+               snprintf(script, sizeof(script), "jailhouse-%s-%s",
+                        cmd, ext->subcmd);
+               execvp(script, &argv[2]);
+
+               perror("execvp");
+               exit(1);
+       }
 }
 
 static int open_dev()
@@ -45,6 +109,21 @@ static int open_dev()
        return fd;
 }
 
+static void *read_string(const char *string, size_t *size)
+{
+       void *buffer;
+
+       *size = strlen(string) + 1;
+
+       buffer = strdup(string);
+       if (!buffer) {
+               fprintf(stderr, "insufficient memory\n");
+               exit(1);
+       }
+
+       return buffer;
+}
+
 static void *read_file(const char *name, size_t *size)
 {
        struct stat stat;
@@ -86,10 +165,8 @@ static int enable(int argc, char *argv[])
        void *config;
        int err, fd;
 
-       if (argc != 3) {
-               help(argv[0]);
-               exit(1);
-       }
+       if (argc != 3)
+               help(argv[0], 1);
 
        config = read_file(argv[2], NULL);
 
@@ -107,73 +184,175 @@ static int enable(int argc, char *argv[])
 
 static int cell_create(int argc, char *argv[])
 {
-       struct {
-               struct jailhouse_new_cell cell;
-               struct jailhouse_preload_image image;
-       } params;
-       struct jailhouse_new_cell *cell = &params.cell;
-       struct jailhouse_preload_image *image = params.cell.image;
+       struct jailhouse_cell_create cell_create;
        size_t size;
        int err, fd;
+
+       if (argc != 4)
+               help(argv[0], 1);
+
+       cell_create.config_address = (unsigned long)read_file(argv[3], &size);
+       cell_create.config_size = size;
+
+       fd = open_dev();
+
+       err = ioctl(fd, JAILHOUSE_CELL_CREATE, &cell_create);
+       if (err)
+               perror("JAILHOUSE_CELL_CREATE");
+
+       close(fd);
+       free((void *)(unsigned long)cell_create.config_address);
+
+       return err;
+}
+
+static int parse_cell_id(struct jailhouse_cell_id *cell_id, int argc,
+                        char *argv[])
+{
+       bool use_name = false;
+       int arg_pos = 0;
        char *endp;
 
-       if (argc != 5 && argc != 7) {
-               help(argv[0]);
-               exit(1);
+       memset(cell_id, 0, sizeof(*cell_id));
+
+       if (argc < 1)
+               return 0;
+
+       if (strcmp(argv[0], "--name") == 0) {
+               if (argc < 2)
+                       return 0;
+               arg_pos++;
+               use_name = true;
+       } else {
+               errno = 0;
+               cell_id->id = strtoll(argv[0], &endp, 0);
+               if (errno != 0 || *endp != 0 || cell_id->id < 0)
+                       use_name = true;
        }
 
-       cell->config_address = (unsigned long)read_file(argv[3], &size);
-       cell->config_size = size;
-       cell->num_preload_images = 1;
+       if (use_name) {
+               cell_id->id = JAILHOUSE_CELL_ID_UNUSED;
+               /* cell_id is initialized with zeros, so leaving out the last
+                * byte ensures that the string is always terminated. */
+               strncpy(cell_id->name, argv[arg_pos],
+                       sizeof(cell_id->name) - 1);
+       }
 
-       image->source_address = (unsigned long)read_file(argv[4], &size);
-       image->size = size;
-       image->target_address = 0;
+       return arg_pos + 1;
+}
 
-       if (argc == 7) {
-               errno = 0;
-               image->target_address = strtoll(argv[6], &endp, 0);
-               if (errno != 0 || *endp != 0 || strcmp(argv[5], "-l") != 0) {
-                       help(argv[0]);
-                       exit(1);
+static bool match_opt(const char *argv, const char *short_opt,
+                     const char *long_opt)
+{
+       return strcmp(argv, short_opt) == 0 ||
+               strcmp(argv, long_opt) == 0;
+}
+
+static int cell_shutdown_load(int argc, char *argv[],
+                             enum shutdown_load_mode mode)
+{
+       struct jailhouse_preload_image *image;
+       struct jailhouse_cell_load *cell_load;
+       struct jailhouse_cell_id cell_id;
+       int err, fd, id_args, arg_num;
+       unsigned int images, n;
+       size_t size;
+       char *endp;
+
+       id_args = parse_cell_id(&cell_id, argc - 3, &argv[3]);
+       arg_num = 3 + id_args;
+       if (id_args == 0 || (mode == SHUTDOWN && arg_num != argc) ||
+           (mode == LOAD && arg_num == argc))
+               help(argv[0], 1);
+
+       images = 0;
+       while (arg_num < argc) {
+               if (match_opt(argv[arg_num], "-s", "--string")) {
+                       if (arg_num + 1 >= argc)
+                               help(argv[0], 1);
+                       arg_num++;
+               }
+
+               images++;
+               arg_num++;
+
+               if (arg_num < argc &&
+                   match_opt(argv[arg_num], "-a", "--address")) {
+                       if (arg_num + 1 >= argc)
+                               help(argv[0], 1);
+                       arg_num += 2;
+               }
+       }
+
+       cell_load = malloc(sizeof(*cell_load) + sizeof(*image) * images);
+       if (!cell_load) {
+               fprintf(stderr, "insufficient memory\n");
+               exit(1);
+       }
+       cell_load->cell_id = cell_id;
+       cell_load->num_preload_images = images;
+
+       arg_num = 3 + id_args;
+
+       for (n = 0, image = cell_load->image; n < images; n++, image++) {
+               if (match_opt(argv[arg_num], "-s", "--string")) {
+                       arg_num++;
+                       image->source_address =
+                               (unsigned long)read_string(argv[arg_num++],
+                                                          &size);
+               } else {
+                       image->source_address =
+                               (unsigned long)read_file(argv[arg_num++],
+                                                        &size);
+               }
+               image->size = size;
+               image->target_address = 0;
+
+               if (arg_num < argc &&
+                   match_opt(argv[arg_num], "-a", "--address")) {
+                       errno = 0;
+                       image->target_address =
+                               strtoll(argv[arg_num + 1], &endp, 0);
+                       if (errno != 0 || *endp != 0)
+                               help(argv[0], 1);
+                       arg_num += 2;
                }
        }
 
        fd = open_dev();
 
-       err = ioctl(fd, JAILHOUSE_CELL_CREATE, &params);
+       err = ioctl(fd, JAILHOUSE_CELL_LOAD, cell_load);
        if (err)
-               perror("JAILHOUSE_CELL_CREATE");
+               perror("JAILHOUSE_CELL_LOAD");
 
        close(fd);
-       free((void *)(unsigned long)cell->config_address);
-       free((void *)(unsigned long)image->source_address);
+       for (n = 0, image = cell_load->image; n < images; n++, image++)
+               free((void *)(unsigned long)image->source_address);
+       free(cell_load);
 
        return err;
 }
 
-static int cell_destroy(int argc, char *argv[])
+static int cell_simple_cmd(int argc, char *argv[], unsigned int command)
 {
-       struct jailhouse_cell cell;
-       size_t size;
-       int err, fd;
+       struct jailhouse_cell_id cell_id;
+       int id_args, err, fd;
 
-       if (argc != 4) {
-               help(argv[0]);
-               exit(1);
-       }
-
-       cell.config_address = (unsigned long)read_file(argv[3], &size);
-       cell.config_size = size;
+       id_args = parse_cell_id(&cell_id, argc - 3, &argv[3]);
+       if (id_args == 0 || 3 + id_args != argc)
+               help(argv[0], 1);
 
        fd = open_dev();
 
-       err = ioctl(fd, JAILHOUSE_CELL_DESTROY, &cell);
+       err = ioctl(fd, command, &cell_id);
        if (err)
-               perror("JAILHOUSE_CELL_DESTROY");
+               perror(command == JAILHOUSE_CELL_START ?
+                      "JAILHOUSE_CELL_START" :
+                      command == JAILHOUSE_CELL_DESTROY ?
+                      "JAILHOUSE_CELL_DESTROY" :
+                      "<unknown command>");
 
        close(fd);
-       free((void *)(unsigned long)cell.config_address);
 
        return err;
 }
@@ -182,18 +361,22 @@ static int cell_management(int argc, char *argv[])
 {
        int err;
 
-       if (argc < 3) {
-               help(argv[0]);
-               exit(1);
-       }
+       if (argc < 3)
+               help(argv[0], 1);
 
-       if (strcmp(argv[2], "create") == 0)
+       if (strcmp(argv[2], "create") == 0) {
                err = cell_create(argc, argv);
-       else if (strcmp(argv[2], "destroy") == 0)
-               err = cell_destroy(argc, argv);
-       else {
-               help(argv[0]);
-               exit(1);
+       } else if (strcmp(argv[2], "load") == 0) {
+               err = cell_shutdown_load(argc, argv, LOAD);
+       } else if (strcmp(argv[2], "start") == 0) {
+               err = cell_simple_cmd(argc, argv, JAILHOUSE_CELL_START);
+       } else if (strcmp(argv[2], "shutdown") == 0) {
+               err = cell_shutdown_load(argc, argv, SHUTDOWN);
+       } else if (strcmp(argv[2], "destroy") == 0) {
+               err = cell_simple_cmd(argc, argv, JAILHOUSE_CELL_DESTROY);
+       } else {
+               call_extension_script("cell", argc, argv);
+               help(argv[0], 1);
        }
 
        return err;
@@ -204,10 +387,8 @@ int main(int argc, char *argv[])
        int fd;
        int err;
 
-       if (argc < 2) {
-               help(argv[0]);
-               exit(1);
-       }
+       if (argc < 2)
+               help(argv[0], 1);
 
        if (strcmp(argv[1], "enable") == 0) {
                err = enable(argc, argv);
@@ -219,9 +400,17 @@ int main(int argc, char *argv[])
                close(fd);
        } else if (strcmp(argv[1], "cell") == 0) {
                err = cell_management(argc, argv);
+       } else if (strcmp(argv[1], "config") == 0 ||
+                  strcmp(argv[1], "hardware") == 0) {
+               call_extension_script(argv[1], argc, argv);
+               help(argv[0], 1);
+       } else if (strcmp(argv[1], "--version") == 0) {
+               printf("Jailhouse management tool %s\n", JAILHOUSE_VERSION);
+               return 0;
+       } else if (strcmp(argv[1], "--help") == 0) {
+               help(argv[0], 0);
        } else {
-               help(argv[0]);
-               exit(1);
+               help(argv[0], 1);
        }
 
        return err ? 1 : 0;