xref: /freebsd/usr.sbin/devctl/devctl.c (revision d66820f2c8c6cdc3d0359abf1004dac0a466a01d)
1 /*-
2  * Copyright (c) 2014 John Baldwin <jhb@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 
30 #include <sys/linker_set.h>
31 #include <devctl.h>
32 #include <err.h>
33 #include <errno.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <strings.h>
38 #include <unistd.h>
39 
40 struct devctl_command {
41 	const char *name;
42 	int (*handler)(int ac, char **av);
43 };
44 
45 #define	DEVCTL_DATASET(name)	devctl_ ## name ## _table
46 
47 #define	DEVCTL_COMMAND(set, name, function)				\
48 	static struct devctl_command function ## _devctl_command =	\
49 	{ #name, function };						\
50 	DATA_SET(DEVCTL_DATASET(set), function ## _devctl_command)
51 
52 #define	DEVCTL_TABLE(set, name)						\
53 	SET_DECLARE(DEVCTL_DATASET(name), struct devctl_command);	\
54 									\
55 	static int							\
56 	devctl_ ## name ## _table_handler(int ac, char **av)		\
57 	{								\
58 		return (devctl_table_handler(SET_BEGIN(DEVCTL_DATASET(name)), \
59 		    SET_LIMIT(DEVCTL_DATASET(name)), ac, av));		\
60 	}								\
61 	DEVCTL_COMMAND(set, name, devctl_ ## name ## _table_handler)
62 
63 static int	devctl_table_handler(struct devctl_command **start,
64     struct devctl_command **end, int ac, char **av);
65 
66 SET_DECLARE(DEVCTL_DATASET(top), struct devctl_command);
67 
68 DEVCTL_TABLE(top, clear);
69 DEVCTL_TABLE(top, set);
70 
71 static void
72 usage(void)
73 {
74 	fprintf(stderr,
75 	    "usage: devctl attach device\n"
76 	    "       devctl detach [-f] device\n"
77 	    "       devctl disable [-f] device\n"
78 	    "       devctl enable device\n"
79 	    "       devctl suspend device\n"
80 	    "       devctl resume device\n"
81 	    "       devctl set driver [-f] device driver\n"
82 	    "       devctl clear driver [-f] device\n"
83 	    "       devctl rescan device\n"
84 	    "       devctl delete [-f] device\n"
85 	    "       devctl freeze\n"
86 	    "       devctl thaw\n");
87 	exit(1);
88 }
89 
90 static int
91 devctl_table_handler(struct devctl_command **start,
92     struct devctl_command **end, int ac, char **av)
93 {
94 	struct devctl_command **cmd;
95 
96 	if (ac < 2) {
97 		warnx("The %s command requires a sub-command.", av[0]);
98 		return (EINVAL);
99 	}
100 	for (cmd = start; cmd < end; cmd++) {
101 		if (strcmp((*cmd)->name, av[1]) == 0)
102 			return ((*cmd)->handler(ac - 1, av + 1));
103 	}
104 
105 	warnx("%s is not a valid sub-command of %s.", av[1], av[0]);
106 	return (ENOENT);
107 }
108 
109 static int
110 help(int ac __unused, char **av __unused)
111 {
112 
113 	usage();
114 	return (0);
115 }
116 DEVCTL_COMMAND(top, help, help);
117 
118 static int
119 attach(int ac, char **av)
120 {
121 
122 	if (ac != 2)
123 		usage();
124 	if (devctl_attach(av[1]) < 0)
125 		err(1, "Failed to attach %s", av[1]);
126 	return (0);
127 }
128 DEVCTL_COMMAND(top, attach, attach);
129 
130 static void
131 detach_usage(void)
132 {
133 
134 	fprintf(stderr, "usage: devctl detach [-f] device\n");
135 	exit(1);
136 }
137 
138 static int
139 detach(int ac, char **av)
140 {
141 	bool force;
142 	int ch;
143 
144 	force = false;
145 	while ((ch = getopt(ac, av, "f")) != -1)
146 		switch (ch) {
147 		case 'f':
148 			force = true;
149 			break;
150 		default:
151 			detach_usage();
152 		}
153 	ac -= optind;
154 	av += optind;
155 
156 	if (ac != 1)
157 		detach_usage();
158 	if (devctl_detach(av[0], force) < 0)
159 		err(1, "Failed to detach %s", av[0]);
160 	return (0);
161 }
162 DEVCTL_COMMAND(top, detach, detach);
163 
164 static void
165 disable_usage(void)
166 {
167 
168 	fprintf(stderr, "usage: devctl disable [-f] device\n");
169 	exit(1);
170 }
171 
172 static int
173 disable(int ac, char **av)
174 {
175 	bool force;
176 	int ch;
177 
178 	force = false;
179 	while ((ch = getopt(ac, av, "f")) != -1)
180 		switch (ch) {
181 		case 'f':
182 			force = true;
183 			break;
184 		default:
185 			disable_usage();
186 		}
187 	ac -= optind;
188 	av += optind;
189 
190 	if (ac != 1)
191 		disable_usage();
192 	if (devctl_disable(av[0], force) < 0)
193 		err(1, "Failed to disable %s", av[0]);
194 	return (0);
195 }
196 DEVCTL_COMMAND(top, disable, disable);
197 
198 static int
199 enable(int ac, char **av)
200 {
201 
202 	if (ac != 2)
203 		usage();
204 	if (devctl_enable(av[1]) < 0)
205 		err(1, "Failed to enable %s", av[1]);
206 	return (0);
207 }
208 DEVCTL_COMMAND(top, enable, enable);
209 
210 static int
211 suspend(int ac, char **av)
212 {
213 
214 	if (ac != 2)
215 		usage();
216 	if (devctl_suspend(av[1]) < 0)
217 		err(1, "Failed to suspend %s", av[1]);
218 	return (0);
219 }
220 DEVCTL_COMMAND(top, suspend, suspend);
221 
222 static int
223 resume(int ac, char **av)
224 {
225 
226 	if (ac != 2)
227 		usage();
228 	if (devctl_resume(av[1]) < 0)
229 		err(1, "Failed to resume %s", av[1]);
230 	return (0);
231 }
232 DEVCTL_COMMAND(top, resume, resume);
233 
234 static void
235 set_driver_usage(void)
236 {
237 
238 	fprintf(stderr, "usage: devctl set driver [-f] device driver\n");
239 	exit(1);
240 }
241 
242 static int
243 set_driver(int ac, char **av)
244 {
245 	bool force;
246 	int ch;
247 
248 	force = false;
249 	while ((ch = getopt(ac, av, "f")) != -1)
250 		switch (ch) {
251 		case 'f':
252 			force = true;
253 			break;
254 		default:
255 			set_driver_usage();
256 		}
257 	ac -= optind;
258 	av += optind;
259 
260 	if (ac != 2)
261 		set_driver_usage();
262 	if (devctl_set_driver(av[0], av[1], force) < 0)
263 		err(1, "Failed to set %s driver to %s", av[0], av[1]);
264 	return (0);
265 }
266 DEVCTL_COMMAND(set, driver, set_driver);
267 
268 static void
269 clear_driver_usage(void)
270 {
271 
272 	fprintf(stderr, "usage: devctl clear driver [-f] device\n");
273 	exit(1);
274 }
275 
276 static int
277 clear_driver(int ac, char **av)
278 {
279 	bool force;
280 	int ch;
281 
282 	force = false;
283 	while ((ch = getopt(ac, av, "f")) != -1)
284 		switch (ch) {
285 		case 'f':
286 			force = true;
287 			break;
288 		default:
289 			clear_driver_usage();
290 		}
291 	ac -= optind;
292 	av += optind;
293 
294 	if (ac != 1)
295 		clear_driver_usage();
296 	if (devctl_clear_driver(av[0], force) < 0)
297 		err(1, "Failed to clear %s driver", av[0]);
298 	return (0);
299 }
300 DEVCTL_COMMAND(clear, driver, clear_driver);
301 
302 static int
303 rescan(int ac, char **av)
304 {
305 
306 	if (ac != 2)
307 		usage();
308 	if (devctl_rescan(av[1]) < 0)
309 		err(1, "Failed to rescan %s", av[1]);
310 	return (0);
311 }
312 DEVCTL_COMMAND(top, rescan, rescan);
313 
314 static void
315 delete_usage(void)
316 {
317 
318 	fprintf(stderr, "usage: devctl delete [-f] device\n");
319 	exit(1);
320 }
321 
322 static int
323 delete(int ac, char **av)
324 {
325 	bool force;
326 	int ch;
327 
328 	force = false;
329 	while ((ch = getopt(ac, av, "f")) != -1)
330 		switch (ch) {
331 		case 'f':
332 			force = true;
333 			break;
334 		default:
335 			delete_usage();
336 		}
337 	ac -= optind;
338 	av += optind;
339 
340 	if (ac != 1)
341 		delete_usage();
342 	if (devctl_delete(av[0], force) < 0)
343 		err(1, "Failed to delete %s", av[0]);
344 	return (0);
345 }
346 DEVCTL_COMMAND(top, delete, delete);
347 
348 static void
349 freeze_usage(void)
350 {
351 
352 	fprintf(stderr, "usage: devctl freeze\n");
353 	exit(1);
354 }
355 
356 static int
357 freeze(int ac, char **av __unused)
358 {
359 
360 	if (ac != 1)
361 		freeze_usage();
362 	if (devctl_freeze() < 0)
363 		err(1, "Failed to freeze probe/attach");
364 	return (0);
365 }
366 DEVCTL_COMMAND(top, freeze, freeze);
367 
368 static void
369 thaw_usage(void)
370 {
371 
372 	fprintf(stderr, "usage: devctl thaw\n");
373 	exit(1);
374 }
375 
376 static int
377 thaw(int ac, char **av __unused)
378 {
379 
380 	if (ac != 1)
381 		thaw_usage();
382 	if (devctl_thaw() < 0)
383 		err(1, "Failed to thaw probe/attach");
384 	return (0);
385 }
386 DEVCTL_COMMAND(top, thaw, thaw);
387 
388 int
389 main(int ac, char *av[])
390 {
391 	struct devctl_command **cmd;
392 
393 	if (ac == 1)
394 		usage();
395 	ac--;
396 	av++;
397 
398 	SET_FOREACH(cmd, DEVCTL_DATASET(top)) {
399 		if (strcmp((*cmd)->name, av[0]) == 0) {
400 			if ((*cmd)->handler(ac, av) != 0)
401 				return (1);
402 			else
403 				return (0);
404 		}
405 	}
406 	warnx("Unknown command %s.", av[0]);
407 	return (1);
408 }
409