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 #include <sys/linker_set.h>
28 #include <devctl.h>
29 #include <err.h>
30 #include <errno.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <strings.h>
35 #include <unistd.h>
36
37 struct devctl_command {
38 const char *name;
39 int (*handler)(int ac, char **av);
40 };
41
42 #define DEVCTL_DATASET(name) devctl_ ## name ## _table
43
44 #define DEVCTL_COMMAND(set, name, function) \
45 static struct devctl_command function ## _devctl_command = \
46 { #name, function }; \
47 DATA_SET(DEVCTL_DATASET(set), function ## _devctl_command)
48
49 #define DEVCTL_TABLE(set, name) \
50 SET_DECLARE(DEVCTL_DATASET(name), struct devctl_command); \
51 \
52 static int \
53 devctl_ ## name ## _table_handler(int ac, char **av) \
54 { \
55 return (devctl_table_handler(SET_BEGIN(DEVCTL_DATASET(name)), \
56 SET_LIMIT(DEVCTL_DATASET(name)), ac, av)); \
57 } \
58 DEVCTL_COMMAND(set, name, devctl_ ## name ## _table_handler)
59
60 static int devctl_table_handler(struct devctl_command **start,
61 struct devctl_command **end, int ac, char **av);
62
63 SET_DECLARE(DEVCTL_DATASET(top), struct devctl_command);
64
65 DEVCTL_TABLE(top, clear);
66 DEVCTL_TABLE(top, set);
67
68 static void
usage(void)69 usage(void)
70 {
71 fprintf(stderr,
72 "usage: devctl attach device\n"
73 " devctl detach [-f] device\n"
74 " devctl disable [-f] device\n"
75 " devctl enable device\n"
76 " devctl suspend device\n"
77 " devctl resume device\n"
78 " devctl set driver [-f] device driver\n"
79 " devctl clear driver [-f] device\n"
80 " devctl rescan device\n"
81 " devctl delete [-f] device\n"
82 " devctl freeze\n"
83 " devctl thaw\n"
84 " devctl reset [-d] device\n"
85 " devctl getpath locator device\n"
86 );
87 exit(1);
88 }
89
90 static int
devctl_table_handler(struct devctl_command ** start,struct devctl_command ** end,int ac,char ** av)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
help(int ac __unused,char ** av __unused)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
attach(int ac,char ** av)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
detach_usage(void)131 detach_usage(void)
132 {
133
134 fprintf(stderr, "usage: devctl detach [-f] device\n");
135 exit(1);
136 }
137
138 static int
detach(int ac,char ** av)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
disable_usage(void)165 disable_usage(void)
166 {
167
168 fprintf(stderr, "usage: devctl disable [-f] device\n");
169 exit(1);
170 }
171
172 static int
disable(int ac,char ** av)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
enable(int ac,char ** av)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
suspend(int ac,char ** av)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
resume(int ac,char ** av)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
set_driver_usage(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
set_driver(int ac,char ** av)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
clear_driver_usage(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
clear_driver(int ac,char ** av)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
rescan(int ac,char ** av)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
delete_usage(void)315 delete_usage(void)
316 {
317
318 fprintf(stderr, "usage: devctl delete [-f] device\n");
319 exit(1);
320 }
321
322 static int
delete(int ac,char ** av)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
freeze_usage(void)349 freeze_usage(void)
350 {
351
352 fprintf(stderr, "usage: devctl freeze\n");
353 exit(1);
354 }
355
356 static int
freeze(int ac,char ** av __unused)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
thaw_usage(void)369 thaw_usage(void)
370 {
371
372 fprintf(stderr, "usage: devctl thaw\n");
373 exit(1);
374 }
375
376 static int
thaw(int ac,char ** av __unused)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 static void
reset_usage(void)389 reset_usage(void)
390 {
391
392 fprintf(stderr, "usage: devctl reset [-d] device\n");
393 exit(1);
394 }
395
396 static int
reset(int ac,char ** av)397 reset(int ac, char **av)
398 {
399 bool detach_drv;
400 int ch;
401
402 detach_drv = false;
403 while ((ch = getopt(ac, av, "d")) != -1)
404 switch (ch) {
405 case 'd':
406 detach_drv = true;
407 break;
408 default:
409 reset_usage();
410 }
411 ac -= optind;
412 av += optind;
413
414 if (ac != 1)
415 reset_usage();
416 if (devctl_reset(av[0], detach_drv) < 0)
417 err(1, "Failed to reset %s", av[0]);
418 return (0);
419 }
420 DEVCTL_COMMAND(top, reset, reset);
421
422 static int
getpath(int ac,char ** av)423 getpath(int ac, char **av)
424 {
425 char *buffer = NULL;
426
427 if (ac != 3)
428 usage();
429 if (devctl_getpath(av[2], av[1], &buffer) < 0)
430 err(1, "Failed to get path via %s to %s", av[1], av[2]);
431 printf("%s\n", buffer);
432 free(buffer);
433 return (0);
434 }
435 DEVCTL_COMMAND(top, getpath, getpath);
436
437 int
main(int ac,char * av[])438 main(int ac, char *av[])
439 {
440 struct devctl_command **cmd;
441
442 if (ac == 1)
443 usage();
444 ac--;
445 av++;
446
447 SET_FOREACH(cmd, DEVCTL_DATASET(top)) {
448 if (strcmp((*cmd)->name, av[0]) == 0) {
449 if ((*cmd)->handler(ac, av) != 0)
450 return (1);
451 else
452 return (0);
453 }
454 }
455 warnx("Unknown command %s.", av[0]);
456 return (1);
457 }
458