xref: /linux/tools/verification/rv/src/rv.c (revision 88221ac0d560700b50493aedc768f728aa585141)
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