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