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