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]",
45 "",
46 " list all available monitors",
47 "",
48 " -h/--help: print this menu",
49 NULL,
50 };
51 int i;
52
53 if (argc > 1) {
54 fprintf(stderr, "rv version %s\n", VERSION);
55
56 /* more than 1 is always usage */
57 for (i = 0; usage[i]; i++)
58 fprintf(stderr, "%s\n", usage[i]);
59
60 /* but only -h is valid */
61 if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))
62 exit(0);
63 else
64 exit(1);
65 }
66
67 ikm_list_monitors();
68 exit(0);
69 }
70
71 /*
72 * rv_mon - try to run a monitor passed as argument
73 */
rv_mon(int argc,char ** argv)74 static void rv_mon(int argc, char **argv)
75 {
76 char *monitor_name;
77 int i, run = 0;
78
79 static const char *const usage[] = {
80 "",
81 " usage: rv mon [-h] monitor [monitor options]",
82 "",
83 " run a monitor",
84 "",
85 " -h/--help: print this menu",
86 "",
87 " monitor [monitor options]: the monitor, passing",
88 " the arguments to the [monitor options]",
89 NULL,
90 };
91
92 /* requires at least one argument */
93 if (argc == 1) {
94
95 fprintf(stderr, "rv version %s\n", VERSION);
96
97 for (i = 0; usage[i]; i++)
98 fprintf(stderr, "%s\n", usage[i]);
99 exit(1);
100 } else if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
101
102 fprintf(stderr, "rv version %s\n", VERSION);
103
104 for (i = 0; usage[i]; i++)
105 fprintf(stderr, "%s\n", usage[i]);
106 exit(0);
107 }
108
109 monitor_name = argv[1];
110 /*
111 * Call all possible monitor implementations, looking
112 * for the [monitor].
113 */
114 run += ikm_run_monitor(monitor_name, argc-1, &argv[1]);
115
116 if (!run)
117 err_msg("rv: monitor %s does not exist\n", monitor_name);
118 exit(!run);
119 }
120
usage(int exit_val,const char * fmt,...)121 static void usage(int exit_val, const char *fmt, ...)
122 {
123 char message[1024];
124 va_list ap;
125 int i;
126
127 static const char *const usage[] = {
128 "",
129 " usage: rv command [-h] [command_options]",
130 "",
131 " -h/--help: print this menu",
132 "",
133 " command: run one of the following command:",
134 " list: list all available monitors",
135 " mon: run a monitor",
136 "",
137 " [command options]: each command has its own set of options",
138 " run rv command -h for further information",
139 NULL,
140 };
141
142 va_start(ap, fmt);
143 vsnprintf(message, sizeof(message), fmt, ap);
144 va_end(ap);
145
146 fprintf(stderr, "rv version %s: %s\n", VERSION, message);
147
148 for (i = 0; usage[i]; i++)
149 fprintf(stderr, "%s\n", usage[i]);
150
151 exit(exit_val);
152 }
153
154 /*
155 * main - select which main sending the command
156 *
157 * main itself redirects the arguments to the sub-commands
158 * to handle the options.
159 *
160 * subcommands should exit.
161 */
main(int argc,char ** argv)162 int main(int argc, char **argv)
163 {
164 if (geteuid())
165 usage(1, "%s needs root permission", argv[0]);
166
167 if (argc <= 1)
168 usage(1, "%s requires a command", argv[0]);
169
170 if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))
171 usage(0, "help");
172
173 if (!strcmp(argv[1], "list"))
174 rv_list(--argc, &argv[1]);
175
176 if (!strcmp(argv[1], "mon")) {
177 /*
178 * monitor's main should monitor should_stop() function.
179 * and exit.
180 */
181 signal(SIGINT, stop_rv);
182
183 rv_mon(argc - 1, &argv[1]);
184 }
185
186 /* invalid sub-command */
187 usage(1, "%s does not know the %s command, old version?", argv[0], argv[1]);
188 }
189