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_drv; 401 int ch; 402 403 detach_drv = false; 404 while ((ch = getopt(ac, av, "d")) != -1) 405 switch (ch) { 406 case 'd': 407 detach_drv = 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_drv) < 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 } 444