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