xref: /freebsd/usr.sbin/devctl/devctl.c (revision d6b92ffa)
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, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
75 	    "usage: devctl attach device",
76 	    "       devctl detach [-f] device",
77 	    "       devctl disable [-f] device",
78 	    "       devctl enable device",
79 	    "       devctl suspend device",
80 	    "       devctl resume device",
81 	    "       devctl set driver [-f] device driver",
82 	    "       devctl clear driver [-f] device",
83 	    "       devctl rescan device",
84 	    "       devctl delete [-f] device");
85 	exit(1);
86 }
87 
88 static int
89 devctl_table_handler(struct devctl_command **start,
90     struct devctl_command **end, int ac, char **av)
91 {
92 	struct devctl_command **cmd;
93 
94 	if (ac < 2) {
95 		warnx("The %s command requires a sub-command.", av[0]);
96 		return (EINVAL);
97 	}
98 	for (cmd = start; cmd < end; cmd++) {
99 		if (strcmp((*cmd)->name, av[1]) == 0)
100 			return ((*cmd)->handler(ac - 1, av + 1));
101 	}
102 
103 	warnx("%s is not a valid sub-command of %s.", av[1], av[0]);
104 	return (ENOENT);
105 }
106 
107 static int
108 help(int ac __unused, char **av __unused)
109 {
110 
111 	usage();
112 	return (0);
113 }
114 DEVCTL_COMMAND(top, help, help);
115 
116 static int
117 attach(int ac, char **av)
118 {
119 
120 	if (ac != 2)
121 		usage();
122 	if (devctl_attach(av[1]) < 0)
123 		err(1, "Failed to attach %s", av[1]);
124 	return (0);
125 }
126 DEVCTL_COMMAND(top, attach, attach);
127 
128 static void
129 detach_usage(void)
130 {
131 
132 	fprintf(stderr, "usage: devctl detach [-f] device\n");
133 	exit(1);
134 }
135 
136 static int
137 detach(int ac, char **av)
138 {
139 	bool force;
140 	int ch;
141 
142 	force = false;
143 	while ((ch = getopt(ac, av, "f")) != -1)
144 		switch (ch) {
145 		case 'f':
146 			force = true;
147 			break;
148 		default:
149 			detach_usage();
150 		}
151 	ac -= optind;
152 	av += optind;
153 
154 	if (ac != 1)
155 		detach_usage();
156 	if (devctl_detach(av[0], force) < 0)
157 		err(1, "Failed to detach %s", av[0]);
158 	return (0);
159 }
160 DEVCTL_COMMAND(top, detach, detach);
161 
162 static void
163 disable_usage(void)
164 {
165 
166 	fprintf(stderr, "usage: devctl disable [-f] device\n");
167 	exit(1);
168 }
169 
170 static int
171 disable(int ac, char **av)
172 {
173 	bool force;
174 	int ch;
175 
176 	force = false;
177 	while ((ch = getopt(ac, av, "f")) != -1)
178 		switch (ch) {
179 		case 'f':
180 			force = true;
181 			break;
182 		default:
183 			disable_usage();
184 		}
185 	ac -= optind;
186 	av += optind;
187 
188 	if (ac != 1)
189 		disable_usage();
190 	if (devctl_disable(av[0], force) < 0)
191 		err(1, "Failed to disable %s", av[0]);
192 	return (0);
193 }
194 DEVCTL_COMMAND(top, disable, disable);
195 
196 static int
197 enable(int ac, char **av)
198 {
199 
200 	if (ac != 2)
201 		usage();
202 	if (devctl_enable(av[1]) < 0)
203 		err(1, "Failed to enable %s", av[1]);
204 	return (0);
205 }
206 DEVCTL_COMMAND(top, enable, enable);
207 
208 static int
209 suspend(int ac, char **av)
210 {
211 
212 	if (ac != 2)
213 		usage();
214 	if (devctl_suspend(av[1]) < 0)
215 		err(1, "Failed to suspend %s", av[1]);
216 	return (0);
217 }
218 DEVCTL_COMMAND(top, suspend, suspend);
219 
220 static int
221 resume(int ac, char **av)
222 {
223 
224 	if (ac != 2)
225 		usage();
226 	if (devctl_resume(av[1]) < 0)
227 		err(1, "Failed to resume %s", av[1]);
228 	return (0);
229 }
230 DEVCTL_COMMAND(top, resume, resume);
231 
232 static void
233 set_driver_usage(void)
234 {
235 
236 	fprintf(stderr, "usage: devctl set driver [-f] device driver\n");
237 	exit(1);
238 }
239 
240 static int
241 set_driver(int ac, char **av)
242 {
243 	bool force;
244 	int ch;
245 
246 	force = false;
247 	while ((ch = getopt(ac, av, "f")) != -1)
248 		switch (ch) {
249 		case 'f':
250 			force = true;
251 			break;
252 		default:
253 			set_driver_usage();
254 		}
255 	ac -= optind;
256 	av += optind;
257 
258 	if (ac != 2)
259 		set_driver_usage();
260 	if (devctl_set_driver(av[0], av[1], force) < 0)
261 		err(1, "Failed to set %s driver to %s", av[0], av[1]);
262 	return (0);
263 }
264 DEVCTL_COMMAND(set, driver, set_driver);
265 
266 static void
267 clear_driver_usage(void)
268 {
269 
270 	fprintf(stderr, "usage: devctl clear driver [-f] device\n");
271 	exit(1);
272 }
273 
274 static int
275 clear_driver(int ac, char **av)
276 {
277 	bool force;
278 	int ch;
279 
280 	force = false;
281 	while ((ch = getopt(ac, av, "f")) != -1)
282 		switch (ch) {
283 		case 'f':
284 			force = true;
285 			break;
286 		default:
287 			clear_driver_usage();
288 		}
289 	ac -= optind;
290 	av += optind;
291 
292 	if (ac != 1)
293 		clear_driver_usage();
294 	if (devctl_clear_driver(av[0], force) < 0)
295 		err(1, "Failed to clear %s driver", av[0]);
296 	return (0);
297 }
298 DEVCTL_COMMAND(clear, driver, clear_driver);
299 
300 static int
301 rescan(int ac, char **av)
302 {
303 
304 	if (ac != 2)
305 		usage();
306 	if (devctl_rescan(av[1]) < 0)
307 		err(1, "Failed to rescan %s", av[1]);
308 	return (0);
309 }
310 DEVCTL_COMMAND(top, rescan, rescan);
311 
312 static void
313 delete_usage(void)
314 {
315 
316 	fprintf(stderr, "usage: devctl delete [-f] device\n");
317 	exit(1);
318 }
319 
320 static int
321 delete(int ac, char **av)
322 {
323 	bool force;
324 	int ch;
325 
326 	force = false;
327 	while ((ch = getopt(ac, av, "f")) != -1)
328 		switch (ch) {
329 		case 'f':
330 			force = true;
331 			break;
332 		default:
333 			delete_usage();
334 		}
335 	ac -= optind;
336 	av += optind;
337 
338 	if (ac != 1)
339 		delete_usage();
340 	if (devctl_delete(av[0], force) < 0)
341 		err(1, "Failed to delete %s", av[0]);
342 	return (0);
343 }
344 DEVCTL_COMMAND(top, delete, delete);
345 
346 int
347 main(int ac, char *av[])
348 {
349 	struct devctl_command **cmd;
350 
351 	if (ac == 1)
352 		usage();
353 	ac--;
354 	av++;
355 
356 	SET_FOREACH(cmd, DEVCTL_DATASET(top)) {
357 		if (strcmp((*cmd)->name, av[0]) == 0) {
358 			if ((*cmd)->handler(ac, av) != 0)
359 				return (1);
360 			else
361 				return (0);
362 		}
363 	}
364 	warnx("Unknown command %s.", av[0]);
365 	return (1);
366 }
367