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