1278320Sjhb/*- 2278320Sjhb * Copyright (c) 2014 John Baldwin <jhb@FreeBSD.org> 3278320Sjhb * 4278320Sjhb * Redistribution and use in source and binary forms, with or without 5278320Sjhb * modification, are permitted provided that the following conditions 6278320Sjhb * are met: 7278320Sjhb * 1. Redistributions of source code must retain the above copyright 8278320Sjhb * notice, this list of conditions and the following disclaimer. 9278320Sjhb * 2. Redistributions in binary form must reproduce the above copyright 10278320Sjhb * notice, this list of conditions and the following disclaimer in the 11278320Sjhb * documentation and/or other materials provided with the distribution. 12278320Sjhb * 13278320Sjhb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14278320Sjhb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15278320Sjhb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16278320Sjhb * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17278320Sjhb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18278320Sjhb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19278320Sjhb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20278320Sjhb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21278320Sjhb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22278320Sjhb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23278320Sjhb * SUCH DAMAGE. 24278320Sjhb */ 25278320Sjhb 26278320Sjhb#include <sys/cdefs.h> 27278320Sjhb__FBSDID("$FreeBSD: stable/11/usr.sbin/devctl/devctl.c 367457 2020-11-07 18:10:59Z dim $"); 28278320Sjhb 29278320Sjhb#include <sys/linker_set.h> 30278320Sjhb#include <devctl.h> 31278320Sjhb#include <err.h> 32278320Sjhb#include <errno.h> 33278320Sjhb#include <stdio.h> 34278320Sjhb#include <stdlib.h> 35278320Sjhb#include <string.h> 36278320Sjhb#include <strings.h> 37278320Sjhb#include <unistd.h> 38278320Sjhb 39278320Sjhbstruct devctl_command { 40278320Sjhb const char *name; 41278320Sjhb int (*handler)(int ac, char **av); 42278320Sjhb}; 43278320Sjhb 44278320Sjhb#define DEVCTL_DATASET(name) devctl_ ## name ## _table 45278320Sjhb 46278320Sjhb#define DEVCTL_COMMAND(set, name, function) \ 47278320Sjhb static struct devctl_command function ## _devctl_command = \ 48278320Sjhb { #name, function }; \ 49278320Sjhb DATA_SET(DEVCTL_DATASET(set), function ## _devctl_command) 50278320Sjhb 51278320Sjhb#define DEVCTL_TABLE(set, name) \ 52278320Sjhb SET_DECLARE(DEVCTL_DATASET(name), struct devctl_command); \ 53278320Sjhb \ 54278320Sjhb static int \ 55278320Sjhb devctl_ ## name ## _table_handler(int ac, char **av) \ 56278320Sjhb { \ 57278320Sjhb return (devctl_table_handler(SET_BEGIN(DEVCTL_DATASET(name)), \ 58278320Sjhb SET_LIMIT(DEVCTL_DATASET(name)), ac, av)); \ 59278320Sjhb } \ 60278320Sjhb DEVCTL_COMMAND(set, name, devctl_ ## name ## _table_handler) 61278320Sjhb 62278320Sjhbstatic int devctl_table_handler(struct devctl_command **start, 63278320Sjhb struct devctl_command **end, int ac, char **av); 64278320Sjhb 65278320SjhbSET_DECLARE(DEVCTL_DATASET(top), struct devctl_command); 66278320Sjhb 67306533SjhbDEVCTL_TABLE(top, clear); 68278320SjhbDEVCTL_TABLE(top, set); 69278320Sjhb 70278320Sjhbstatic void 71278320Sjhbusage(void) 72278320Sjhb{ 73346384Skib fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n", 74278320Sjhb "usage: devctl attach device", 75278320Sjhb " devctl detach [-f] device", 76278320Sjhb " devctl disable [-f] device", 77278320Sjhb " devctl enable device", 78278320Sjhb " devctl suspend device", 79278320Sjhb " devctl resume device", 80298709Sjhb " devctl set driver [-f] device driver", 81306533Sjhb " devctl clear driver [-f] device", 82298709Sjhb " devctl rescan device", 83346384Skib " devctl delete [-f] device", 84346384Skib " devctl reset [-d] device" 85346384Skib ); 86278320Sjhb exit(1); 87278320Sjhb} 88278320Sjhb 89278320Sjhbstatic int 90278320Sjhbdevctl_table_handler(struct devctl_command **start, 91278320Sjhb struct devctl_command **end, int ac, char **av) 92278320Sjhb{ 93278320Sjhb struct devctl_command **cmd; 94278320Sjhb 95278320Sjhb if (ac < 2) { 96278320Sjhb warnx("The %s command requires a sub-command.", av[0]); 97278320Sjhb return (EINVAL); 98278320Sjhb } 99278320Sjhb for (cmd = start; cmd < end; cmd++) { 100278320Sjhb if (strcmp((*cmd)->name, av[1]) == 0) 101278320Sjhb return ((*cmd)->handler(ac - 1, av + 1)); 102278320Sjhb } 103278320Sjhb 104278320Sjhb warnx("%s is not a valid sub-command of %s.", av[1], av[0]); 105278320Sjhb return (ENOENT); 106278320Sjhb} 107278320Sjhb 108278320Sjhbstatic int 109278320Sjhbhelp(int ac __unused, char **av __unused) 110278320Sjhb{ 111278320Sjhb 112278320Sjhb usage(); 113278320Sjhb return (0); 114278320Sjhb} 115278320SjhbDEVCTL_COMMAND(top, help, help); 116278320Sjhb 117278320Sjhbstatic int 118278320Sjhbattach(int ac, char **av) 119278320Sjhb{ 120278320Sjhb 121278320Sjhb if (ac != 2) 122278320Sjhb usage(); 123278320Sjhb if (devctl_attach(av[1]) < 0) 124278320Sjhb err(1, "Failed to attach %s", av[1]); 125278320Sjhb return (0); 126278320Sjhb} 127278320SjhbDEVCTL_COMMAND(top, attach, attach); 128278320Sjhb 129278320Sjhbstatic void 130278320Sjhbdetach_usage(void) 131278320Sjhb{ 132278320Sjhb 133278320Sjhb fprintf(stderr, "usage: devctl detach [-f] device\n"); 134278320Sjhb exit(1); 135278320Sjhb} 136278320Sjhb 137278320Sjhbstatic int 138278320Sjhbdetach(int ac, char **av) 139278320Sjhb{ 140278320Sjhb bool force; 141278320Sjhb int ch; 142278320Sjhb 143278320Sjhb force = false; 144278320Sjhb while ((ch = getopt(ac, av, "f")) != -1) 145278320Sjhb switch (ch) { 146278320Sjhb case 'f': 147278320Sjhb force = true; 148278320Sjhb break; 149278320Sjhb default: 150278320Sjhb detach_usage(); 151278320Sjhb } 152278320Sjhb ac -= optind; 153278320Sjhb av += optind; 154278320Sjhb 155278320Sjhb if (ac != 1) 156278320Sjhb detach_usage(); 157278320Sjhb if (devctl_detach(av[0], force) < 0) 158278320Sjhb err(1, "Failed to detach %s", av[0]); 159278320Sjhb return (0); 160278320Sjhb} 161278320SjhbDEVCTL_COMMAND(top, detach, detach); 162278320Sjhb 163278320Sjhbstatic void 164278320Sjhbdisable_usage(void) 165278320Sjhb{ 166278320Sjhb 167278320Sjhb fprintf(stderr, "usage: devctl disable [-f] device\n"); 168278320Sjhb exit(1); 169278320Sjhb} 170278320Sjhb 171278320Sjhbstatic int 172278320Sjhbdisable(int ac, char **av) 173278320Sjhb{ 174278320Sjhb bool force; 175278320Sjhb int ch; 176278320Sjhb 177278320Sjhb force = false; 178278320Sjhb while ((ch = getopt(ac, av, "f")) != -1) 179278320Sjhb switch (ch) { 180278320Sjhb case 'f': 181278320Sjhb force = true; 182278320Sjhb break; 183278320Sjhb default: 184278320Sjhb disable_usage(); 185278320Sjhb } 186278320Sjhb ac -= optind; 187278320Sjhb av += optind; 188278320Sjhb 189278320Sjhb if (ac != 1) 190278320Sjhb disable_usage(); 191278320Sjhb if (devctl_disable(av[0], force) < 0) 192278320Sjhb err(1, "Failed to disable %s", av[0]); 193278320Sjhb return (0); 194278320Sjhb} 195278320SjhbDEVCTL_COMMAND(top, disable, disable); 196278320Sjhb 197278320Sjhbstatic int 198278320Sjhbenable(int ac, char **av) 199278320Sjhb{ 200278320Sjhb 201278320Sjhb if (ac != 2) 202278320Sjhb usage(); 203278320Sjhb if (devctl_enable(av[1]) < 0) 204278320Sjhb err(1, "Failed to enable %s", av[1]); 205278320Sjhb return (0); 206278320Sjhb} 207278320SjhbDEVCTL_COMMAND(top, enable, enable); 208278320Sjhb 209278320Sjhbstatic int 210278320Sjhbsuspend(int ac, char **av) 211278320Sjhb{ 212278320Sjhb 213278320Sjhb if (ac != 2) 214278320Sjhb usage(); 215278320Sjhb if (devctl_suspend(av[1]) < 0) 216278320Sjhb err(1, "Failed to suspend %s", av[1]); 217278320Sjhb return (0); 218278320Sjhb} 219278320SjhbDEVCTL_COMMAND(top, suspend, suspend); 220278320Sjhb 221278320Sjhbstatic int 222278320Sjhbresume(int ac, char **av) 223278320Sjhb{ 224278320Sjhb 225278320Sjhb if (ac != 2) 226278320Sjhb usage(); 227278320Sjhb if (devctl_resume(av[1]) < 0) 228278320Sjhb err(1, "Failed to resume %s", av[1]); 229278320Sjhb return (0); 230278320Sjhb} 231278320SjhbDEVCTL_COMMAND(top, resume, resume); 232278320Sjhb 233278320Sjhbstatic void 234278320Sjhbset_driver_usage(void) 235278320Sjhb{ 236278320Sjhb 237278320Sjhb fprintf(stderr, "usage: devctl set driver [-f] device driver\n"); 238278320Sjhb exit(1); 239278320Sjhb} 240278320Sjhb 241278320Sjhbstatic int 242278320Sjhbset_driver(int ac, char **av) 243278320Sjhb{ 244278320Sjhb bool force; 245278320Sjhb int ch; 246278320Sjhb 247278320Sjhb force = false; 248278320Sjhb while ((ch = getopt(ac, av, "f")) != -1) 249278320Sjhb switch (ch) { 250278320Sjhb case 'f': 251278320Sjhb force = true; 252278320Sjhb break; 253278320Sjhb default: 254278320Sjhb set_driver_usage(); 255278320Sjhb } 256278320Sjhb ac -= optind; 257278320Sjhb av += optind; 258278320Sjhb 259278320Sjhb if (ac != 2) 260278320Sjhb set_driver_usage(); 261278320Sjhb if (devctl_set_driver(av[0], av[1], force) < 0) 262278320Sjhb err(1, "Failed to set %s driver to %s", av[0], av[1]); 263278320Sjhb return (0); 264278320Sjhb} 265278320SjhbDEVCTL_COMMAND(set, driver, set_driver); 266278320Sjhb 267306533Sjhbstatic void 268306533Sjhbclear_driver_usage(void) 269306533Sjhb{ 270306533Sjhb 271306533Sjhb fprintf(stderr, "usage: devctl clear driver [-f] device\n"); 272306533Sjhb exit(1); 273306533Sjhb} 274306533Sjhb 275298707Sjhbstatic int 276306533Sjhbclear_driver(int ac, char **av) 277306533Sjhb{ 278306533Sjhb bool force; 279306533Sjhb int ch; 280306533Sjhb 281306533Sjhb force = false; 282306533Sjhb while ((ch = getopt(ac, av, "f")) != -1) 283306533Sjhb switch (ch) { 284306533Sjhb case 'f': 285306533Sjhb force = true; 286306533Sjhb break; 287306533Sjhb default: 288306533Sjhb clear_driver_usage(); 289306533Sjhb } 290306533Sjhb ac -= optind; 291306533Sjhb av += optind; 292306533Sjhb 293306533Sjhb if (ac != 1) 294306533Sjhb clear_driver_usage(); 295306533Sjhb if (devctl_clear_driver(av[0], force) < 0) 296306533Sjhb err(1, "Failed to clear %s driver", av[0]); 297306533Sjhb return (0); 298306533Sjhb} 299306533SjhbDEVCTL_COMMAND(clear, driver, clear_driver); 300306533Sjhb 301306533Sjhbstatic int 302298707Sjhbrescan(int ac, char **av) 303298707Sjhb{ 304298707Sjhb 305298707Sjhb if (ac != 2) 306298707Sjhb usage(); 307298707Sjhb if (devctl_rescan(av[1]) < 0) 308298707Sjhb err(1, "Failed to rescan %s", av[1]); 309298707Sjhb return (0); 310298707Sjhb} 311298707SjhbDEVCTL_COMMAND(top, rescan, rescan); 312298707Sjhb 313298709Sjhbstatic void 314298709Sjhbdelete_usage(void) 315298709Sjhb{ 316298709Sjhb 317298709Sjhb fprintf(stderr, "usage: devctl delete [-f] device\n"); 318298709Sjhb exit(1); 319298709Sjhb} 320298709Sjhb 321298709Sjhbstatic int 322298709Sjhbdelete(int ac, char **av) 323298709Sjhb{ 324298709Sjhb bool force; 325298709Sjhb int ch; 326298709Sjhb 327298709Sjhb force = false; 328298709Sjhb while ((ch = getopt(ac, av, "f")) != -1) 329298709Sjhb switch (ch) { 330298709Sjhb case 'f': 331298709Sjhb force = true; 332298709Sjhb break; 333298709Sjhb default: 334298709Sjhb delete_usage(); 335298709Sjhb } 336298709Sjhb ac -= optind; 337298709Sjhb av += optind; 338298709Sjhb 339298709Sjhb if (ac != 1) 340298709Sjhb delete_usage(); 341298709Sjhb if (devctl_delete(av[0], force) < 0) 342298709Sjhb err(1, "Failed to delete %s", av[0]); 343298709Sjhb return (0); 344298709Sjhb} 345298709SjhbDEVCTL_COMMAND(top, delete, delete); 346298709Sjhb 347346384Skibstatic void 348346384Skibreset_usage(void) 349346384Skib{ 350346384Skib 351346384Skib fprintf(stderr, "usage: devctl reset [-d] device\n"); 352346384Skib exit(1); 353346384Skib} 354346384Skib 355346384Skibstatic int 356346384Skibreset(int ac, char **av) 357346384Skib{ 358346384Skib bool detach_drv; 359346384Skib int ch; 360346384Skib 361346384Skib detach_drv = false; 362346384Skib while ((ch = getopt(ac, av, "d")) != -1) 363346384Skib switch (ch) { 364346384Skib case 'd': 365346384Skib detach_drv = true; 366346384Skib break; 367346384Skib default: 368346384Skib reset_usage(); 369346384Skib } 370346384Skib ac -= optind; 371346384Skib av += optind; 372346384Skib 373346384Skib if (ac != 1) 374346384Skib reset_usage(); 375346384Skib if (devctl_reset(av[0], detach_drv) < 0) 376346384Skib err(1, "Failed to reset %s", av[0]); 377346384Skib return (0); 378346384Skib} 379346384SkibDEVCTL_COMMAND(top, reset, reset); 380346384Skib 381278320Sjhbint 382278320Sjhbmain(int ac, char *av[]) 383278320Sjhb{ 384278320Sjhb struct devctl_command **cmd; 385278320Sjhb 386278320Sjhb if (ac == 1) 387278320Sjhb usage(); 388278320Sjhb ac--; 389278320Sjhb av++; 390278320Sjhb 391278320Sjhb SET_FOREACH(cmd, DEVCTL_DATASET(top)) { 392278320Sjhb if (strcmp((*cmd)->name, av[0]) == 0) { 393278320Sjhb if ((*cmd)->handler(ac, av) != 0) 394278320Sjhb return (1); 395278320Sjhb else 396278320Sjhb return (0); 397278320Sjhb } 398278320Sjhb } 399278320Sjhb warnx("Unknown command %s.", av[0]); 400278320Sjhb return (1); 401278320Sjhb} 402