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