// SPDX-License-Identifier: GPL-2.0 /* * rv tool, the interface for the Linux kernel RV subsystem and home of * user-space controlled monitors. * * Copyright (C) 2022 Red Hat Inc, Daniel Bristot de Oliveira <bristot@kernel.org> */ #include <stdlib.h> #include <signal.h> #include <unistd.h> #include <trace.h> #include <utils.h> #include <in_kernel.h> static int stop_session; /* * stop_rv - tell monitors to stop */ static void stop_rv(int sig) { stop_session = 1; } /** * should_stop - check if the monitor should stop. * * Returns 1 if the monitor should stop, 0 otherwise. */ int should_stop(void) { return stop_session; } /* * rv_list - list all available monitors */ static void rv_list(int argc, char **argv) { static const char *const usage[] = { "", " usage: rv list [-h]", "", " list all available monitors", "", " -h/--help: print this menu", NULL, }; int i; if (argc > 1) { fprintf(stderr, "rv version %s\n", VERSION); /* more than 1 is always usage */ for (i = 0; usage[i]; i++) fprintf(stderr, "%s\n", usage[i]); /* but only -h is valid */ if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) exit(0); else exit(1); } ikm_list_monitors(); exit(0); } /* * rv_mon - try to run a monitor passed as argument */ static void rv_mon(int argc, char **argv) { char *monitor_name; int i, run = 0; static const char *const usage[] = { "", " usage: rv mon [-h] monitor [monitor options]", "", " run a monitor", "", " -h/--help: print this menu", "", " monitor [monitor options]: the monitor, passing", " the arguments to the [monitor options]", NULL, }; /* requires at least one argument */ if (argc == 1) { fprintf(stderr, "rv version %s\n", VERSION); for (i = 0; usage[i]; i++) fprintf(stderr, "%s\n", usage[i]); exit(1); } else if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) { fprintf(stderr, "rv version %s\n", VERSION); for (i = 0; usage[i]; i++) fprintf(stderr, "%s\n", usage[i]); exit(0); } monitor_name = argv[1]; /* * Call all possible monitor implementations, looking * for the [monitor]. */ run += ikm_run_monitor(monitor_name, argc-1, &argv[1]); if (!run) err_msg("rv: monitor %s does not exist\n", monitor_name); exit(!run); } static void usage(int exit_val, const char *fmt, ...) { char message[1024]; va_list ap; int i; static const char *const usage[] = { "", " usage: rv command [-h] [command_options]", "", " -h/--help: print this menu", "", " command: run one of the following command:", " list: list all available monitors", " mon: run a monitor", "", " [command options]: each command has its own set of options", " run rv command -h for further information", NULL, }; va_start(ap, fmt); vsnprintf(message, sizeof(message), fmt, ap); va_end(ap); fprintf(stderr, "rv version %s: %s\n", VERSION, message); for (i = 0; usage[i]; i++) fprintf(stderr, "%s\n", usage[i]); exit(exit_val); } /* * main - select which main sending the command * * main itself redirects the arguments to the sub-commands * to handle the options. * * subcommands should exit. */ int main(int argc, char **argv) { if (geteuid()) usage(1, "%s needs root permission", argv[0]); if (argc <= 1) usage(1, "%s requires a command", argv[0]); if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) usage(0, "help"); if (!strcmp(argv[1], "list")) rv_list(--argc, &argv[1]); if (!strcmp(argv[1], "mon")) { /* * monitor's main should monitor should_stop() function. * and exit. */ signal(SIGINT, stop_rv); rv_mon(argc - 1, &argv[1]); } /* invalid sub-command */ usage(1, "%s does not know the %s command, old version?", argv[0], argv[1]); }