1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * rv tool, the interface for the Linux kernel RV subsystem and home of
4 * user-space controlled monitors.
5 *
6 * Copyright (C) 2022 Red Hat Inc, Daniel Bristot de Oliveira <bristot@kernel.org>
7 */
8
9 #include <stdlib.h>
10 #include <signal.h>
11 #include <unistd.h>
12
13 #include <trace.h>
14 #include <utils.h>
15 #include <in_kernel.h>
16
17 static int stop_session;
18
19 /*
20 * stop_rv - tell monitors to stop
21 */
stop_rv(int sig)22 static void stop_rv(int sig)
23 {
24 stop_session = 1;
25 }
26
27 /**
28 * should_stop - check if the monitor should stop.
29 *
30 * Returns 1 if the monitor should stop, 0 otherwise.
31 */
should_stop(void)32 int should_stop(void)
33 {
34 return stop_session;
35 }
36
37 /*
38 * rv_list - list all available monitors
39 */
rv_list(int argc,char ** argv)40 static void rv_list(int argc, char **argv)
41 {
42 static const char *const usage[] = {
43 "",
44 " usage: rv list [-h] [container]",
45 "",
46 " list all available monitors",
47 "",
48 " -h/--help: print this menu",
49 "",
50 " [container]: list only monitors in this container",
51 NULL,
52 };
53 int i, print_help = 0, retval = 0;
54 char *container = NULL;
55
56 if (argc == 2) {
57 if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
58 print_help = 1;
59 retval = 0;
60 } else if (argv[1][0] == '-') {
61 /* assume invalid option */
62 print_help = 1;
63 retval = 1;
64 } else
65 container = argv[1];
66 } else if (argc > 2) {
67 /* more than 2 is always usage */
68 print_help = 1;
69 retval = 1;
70 }
71 if (print_help) {
72 fprintf(stderr, "rv version %s\n", VERSION);
73 for (i = 0; usage[i]; i++)
74 fprintf(stderr, "%s\n", usage[i]);
75 exit(retval);
76 }
77
78 ikm_list_monitors(container);
79
80 exit(0);
81 }
82
83 /*
84 * rv_mon - try to run a monitor passed as argument
85 */
rv_mon(int argc,char ** argv)86 static void rv_mon(int argc, char **argv)
87 {
88 char *monitor_name;
89 int i, run = 0;
90
91 static const char *const usage[] = {
92 "",
93 " usage: rv mon [-h] monitor [monitor options]",
94 "",
95 " run a monitor",
96 "",
97 " -h/--help: print this menu",
98 "",
99 " monitor [monitor options]: the monitor, passing",
100 " the arguments to the [monitor options]",
101 NULL,
102 };
103
104 /* requires at least one argument */
105 if (argc == 1) {
106
107 fprintf(stderr, "rv version %s\n", VERSION);
108
109 for (i = 0; usage[i]; i++)
110 fprintf(stderr, "%s\n", usage[i]);
111 exit(1);
112 } else if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
113
114 fprintf(stderr, "rv version %s\n", VERSION);
115
116 for (i = 0; usage[i]; i++)
117 fprintf(stderr, "%s\n", usage[i]);
118 exit(0);
119 }
120
121 monitor_name = argv[1];
122 /*
123 * Call all possible monitor implementations, looking
124 * for the [monitor].
125 */
126 run += ikm_run_monitor(monitor_name, argc-1, &argv[1]);
127
128 if (!run)
129 err_msg("rv: monitor %s does not exist\n", monitor_name);
130 exit(!run);
131 }
132
usage(int exit_val,const char * fmt,...)133 static void usage(int exit_val, const char *fmt, ...)
134 {
135 char message[1024];
136 va_list ap;
137 int i;
138
139 static const char *const usage[] = {
140 "",
141 " usage: rv command [-h] [command_options]",
142 "",
143 " -h/--help: print this menu",
144 "",
145 " command: run one of the following command:",
146 " list: list all available monitors",
147 " mon: run a monitor",
148 "",
149 " [command options]: each command has its own set of options",
150 " run rv command -h for further information",
151 NULL,
152 };
153
154 va_start(ap, fmt);
155 vsnprintf(message, sizeof(message), fmt, ap);
156 va_end(ap);
157
158 fprintf(stderr, "rv version %s: %s\n", VERSION, message);
159
160 for (i = 0; usage[i]; i++)
161 fprintf(stderr, "%s\n", usage[i]);
162
163 exit(exit_val);
164 }
165
166 /*
167 * main - select which main sending the command
168 *
169 * main itself redirects the arguments to the sub-commands
170 * to handle the options.
171 *
172 * subcommands should exit.
173 */
main(int argc,char ** argv)174 int main(int argc, char **argv)
175 {
176 if (geteuid())
177 usage(1, "%s needs root permission", argv[0]);
178
179 if (argc <= 1)
180 usage(1, "%s requires a command", argv[0]);
181
182 if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))
183 usage(0, "help");
184
185 if (!strcmp(argv[1], "list"))
186 rv_list(--argc, &argv[1]);
187
188 if (!strcmp(argv[1], "mon")) {
189 /*
190 * monitor's main should monitor should_stop() function.
191 * and exit.
192 */
193 signal(SIGINT, stop_rv);
194
195 rv_mon(argc - 1, &argv[1]);
196 }
197
198 /* invalid sub-command */
199 usage(1, "%s does not know the %s command, old version?", argv[0], argv[1]);
200 }
201