1 /*-
2 * Copyright (c) 2014 John Baldwin <[email protected]>
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
usage(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 " devctl reset [-d] device\n"
88 );
89 exit(1);
90 }
91
92 static int
devctl_table_handler(struct devctl_command ** start,struct devctl_command ** end,int ac,char ** av)93 devctl_table_handler(struct devctl_command **start,
94 struct devctl_command **end, int ac, char **av)
95 {
96 struct devctl_command **cmd;
97
98 if (ac < 2) {
99 warnx("The %s command requires a sub-command.", av[0]);
100 return (EINVAL);
101 }
102 for (cmd = start; cmd < end; cmd++) {
103 if (strcmp((*cmd)->name, av[1]) == 0)
104 return ((*cmd)->handler(ac - 1, av + 1));
105 }
106
107 warnx("%s is not a valid sub-command of %s.", av[1], av[0]);
108 return (ENOENT);
109 }
110
111 static int
help(int ac __unused,char ** av __unused)112 help(int ac __unused, char **av __unused)
113 {
114
115 usage();
116 return (0);
117 }
118 DEVCTL_COMMAND(top, help, help);
119
120 static int
attach(int ac,char ** av)121 attach(int ac, char **av)
122 {
123
124 if (ac != 2)
125 usage();
126 if (devctl_attach(av[1]) < 0)
127 err(1, "Failed to attach %s", av[1]);
128 return (0);
129 }
130 DEVCTL_COMMAND(top, attach, attach);
131
132 static void
detach_usage(void)133 detach_usage(void)
134 {
135
136 fprintf(stderr, "usage: devctl detach [-f] device\n");
137 exit(1);
138 }
139
140 static int
detach(int ac,char ** av)141 detach(int ac, char **av)
142 {
143 bool force;
144 int ch;
145
146 force = false;
147 while ((ch = getopt(ac, av, "f")) != -1)
148 switch (ch) {
149 case 'f':
150 force = true;
151 break;
152 default:
153 detach_usage();
154 }
155 ac -= optind;
156 av += optind;
157
158 if (ac != 1)
159 detach_usage();
160 if (devctl_detach(av[0], force) < 0)
161 err(1, "Failed to detach %s", av[0]);
162 return (0);
163 }
164 DEVCTL_COMMAND(top, detach, detach);
165
166 static void
disable_usage(void)167 disable_usage(void)
168 {
169
170 fprintf(stderr, "usage: devctl disable [-f] device\n");
171 exit(1);
172 }
173
174 static int
disable(int ac,char ** av)175 disable(int ac, char **av)
176 {
177 bool force;
178 int ch;
179
180 force = false;
181 while ((ch = getopt(ac, av, "f")) != -1)
182 switch (ch) {
183 case 'f':
184 force = true;
185 break;
186 default:
187 disable_usage();
188 }
189 ac -= optind;
190 av += optind;
191
192 if (ac != 1)
193 disable_usage();
194 if (devctl_disable(av[0], force) < 0)
195 err(1, "Failed to disable %s", av[0]);
196 return (0);
197 }
198 DEVCTL_COMMAND(top, disable, disable);
199
200 static int
enable(int ac,char ** av)201 enable(int ac, char **av)
202 {
203
204 if (ac != 2)
205 usage();
206 if (devctl_enable(av[1]) < 0)
207 err(1, "Failed to enable %s", av[1]);
208 return (0);
209 }
210 DEVCTL_COMMAND(top, enable, enable);
211
212 static int
suspend(int ac,char ** av)213 suspend(int ac, char **av)
214 {
215
216 if (ac != 2)
217 usage();
218 if (devctl_suspend(av[1]) < 0)
219 err(1, "Failed to suspend %s", av[1]);
220 return (0);
221 }
222 DEVCTL_COMMAND(top, suspend, suspend);
223
224 static int
resume(int ac,char ** av)225 resume(int ac, char **av)
226 {
227
228 if (ac != 2)
229 usage();
230 if (devctl_resume(av[1]) < 0)
231 err(1, "Failed to resume %s", av[1]);
232 return (0);
233 }
234 DEVCTL_COMMAND(top, resume, resume);
235
236 static void
set_driver_usage(void)237 set_driver_usage(void)
238 {
239
240 fprintf(stderr, "usage: devctl set driver [-f] device driver\n");
241 exit(1);
242 }
243
244 static int
set_driver(int ac,char ** av)245 set_driver(int ac, char **av)
246 {
247 bool force;
248 int ch;
249
250 force = false;
251 while ((ch = getopt(ac, av, "f")) != -1)
252 switch (ch) {
253 case 'f':
254 force = true;
255 break;
256 default:
257 set_driver_usage();
258 }
259 ac -= optind;
260 av += optind;
261
262 if (ac != 2)
263 set_driver_usage();
264 if (devctl_set_driver(av[0], av[1], force) < 0)
265 err(1, "Failed to set %s driver to %s", av[0], av[1]);
266 return (0);
267 }
268 DEVCTL_COMMAND(set, driver, set_driver);
269
270 static void
clear_driver_usage(void)271 clear_driver_usage(void)
272 {
273
274 fprintf(stderr, "usage: devctl clear driver [-f] device\n");
275 exit(1);
276 }
277
278 static int
clear_driver(int ac,char ** av)279 clear_driver(int ac, char **av)
280 {
281 bool force;
282 int ch;
283
284 force = false;
285 while ((ch = getopt(ac, av, "f")) != -1)
286 switch (ch) {
287 case 'f':
288 force = true;
289 break;
290 default:
291 clear_driver_usage();
292 }
293 ac -= optind;
294 av += optind;
295
296 if (ac != 1)
297 clear_driver_usage();
298 if (devctl_clear_driver(av[0], force) < 0)
299 err(1, "Failed to clear %s driver", av[0]);
300 return (0);
301 }
302 DEVCTL_COMMAND(clear, driver, clear_driver);
303
304 static int
rescan(int ac,char ** av)305 rescan(int ac, char **av)
306 {
307
308 if (ac != 2)
309 usage();
310 if (devctl_rescan(av[1]) < 0)
311 err(1, "Failed to rescan %s", av[1]);
312 return (0);
313 }
314 DEVCTL_COMMAND(top, rescan, rescan);
315
316 static void
delete_usage(void)317 delete_usage(void)
318 {
319
320 fprintf(stderr, "usage: devctl delete [-f] device\n");
321 exit(1);
322 }
323
324 static int
delete(int ac,char ** av)325 delete(int ac, char **av)
326 {
327 bool force;
328 int ch;
329
330 force = false;
331 while ((ch = getopt(ac, av, "f")) != -1)
332 switch (ch) {
333 case 'f':
334 force = true;
335 break;
336 default:
337 delete_usage();
338 }
339 ac -= optind;
340 av += optind;
341
342 if (ac != 1)
343 delete_usage();
344 if (devctl_delete(av[0], force) < 0)
345 err(1, "Failed to delete %s", av[0]);
346 return (0);
347 }
348 DEVCTL_COMMAND(top, delete, delete);
349
350 static void
freeze_usage(void)351 freeze_usage(void)
352 {
353
354 fprintf(stderr, "usage: devctl freeze\n");
355 exit(1);
356 }
357
358 static int
freeze(int ac,char ** av __unused)359 freeze(int ac, char **av __unused)
360 {
361
362 if (ac != 1)
363 freeze_usage();
364 if (devctl_freeze() < 0)
365 err(1, "Failed to freeze probe/attach");
366 return (0);
367 }
368 DEVCTL_COMMAND(top, freeze, freeze);
369
370 static void
thaw_usage(void)371 thaw_usage(void)
372 {
373
374 fprintf(stderr, "usage: devctl thaw\n");
375 exit(1);
376 }
377
378 static int
thaw(int ac,char ** av __unused)379 thaw(int ac, char **av __unused)
380 {
381
382 if (ac != 1)
383 thaw_usage();
384 if (devctl_thaw() < 0)
385 err(1, "Failed to thaw probe/attach");
386 return (0);
387 }
388 DEVCTL_COMMAND(top, thaw, thaw);
389
390 static void
reset_usage(void)391 reset_usage(void)
392 {
393
394 fprintf(stderr, "usage: devctl reset [-d] device\n");
395 exit(1);
396 }
397
398 static int
reset(int ac,char ** av)399 reset(int ac, char **av)
400 {
401 bool detach_drv;
402 int ch;
403
404 detach_drv = false;
405 while ((ch = getopt(ac, av, "d")) != -1)
406 switch (ch) {
407 case 'd':
408 detach_drv = true;
409 break;
410 default:
411 reset_usage();
412 }
413 ac -= optind;
414 av += optind;
415
416 if (ac != 1)
417 reset_usage();
418 if (devctl_reset(av[0], detach_drv) < 0)
419 err(1, "Failed to reset %s", av[0]);
420 return (0);
421 }
422 DEVCTL_COMMAND(top, reset, reset);
423
424 int
main(int ac,char * av[])425 main(int ac, char *av[])
426 {
427 struct devctl_command **cmd;
428
429 if (ac == 1)
430 usage();
431 ac--;
432 av++;
433
434 SET_FOREACH(cmd, DEVCTL_DATASET(top)) {
435 if (strcmp((*cmd)->name, av[0]) == 0) {
436 if ((*cmd)->handler(ac, av) != 0)
437 return (1);
438 else
439 return (0);
440 }
441 }
442 warnx("Unknown command %s.", av[0]);
443 return (1);
444 }
445