xref: /linux/tools/verification/rv/src/rv.c (revision cbdb1f163af2bb90d01be1f0263df1d8d5c9d9d3)
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  */
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  */
32 int should_stop(void)
33 {
34 	return stop_session;
35 }
36 
37 /*
38  * rv_list - list all available monitors
39  */
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  */
74 static void rv_mon(int argc, char **argv)
75 {
76 	char *monitor_name;
77 	int i, run;
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 
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  */
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