1278320Sjhb/*- 2278320Sjhb * Copyright (c) 2014 John Baldwin <jhb@FreeBSD.org> 3278320Sjhb * All rights reserved. 4278320Sjhb * 5278320Sjhb * Redistribution and use in source and binary forms, with or without 6278320Sjhb * modification, are permitted provided that the following conditions 7278320Sjhb * are met: 8278320Sjhb * 1. Redistributions of source code must retain the above copyright 9278320Sjhb * notice, this list of conditions and the following disclaimer. 10278320Sjhb * 2. Redistributions in binary form must reproduce the above copyright 11278320Sjhb * notice, this list of conditions and the following disclaimer in the 12278320Sjhb * documentation and/or other materials provided with the distribution. 13278320Sjhb * 14278320Sjhb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15278320Sjhb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16278320Sjhb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17278320Sjhb * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18278320Sjhb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19278320Sjhb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20278320Sjhb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21278320Sjhb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22278320Sjhb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23278320Sjhb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24278320Sjhb * SUCH DAMAGE. 25278320Sjhb */ 26278320Sjhb 27278320Sjhb#include <sys/cdefs.h> 28278320Sjhb__FBSDID("$FreeBSD: stable/10/usr.sbin/devctl/devctl.c 306533 2016-09-30 22:05:47Z jhb $"); 29278320Sjhb 30278320Sjhb#include <sys/linker_set.h> 31278320Sjhb#include <devctl.h> 32278320Sjhb#include <err.h> 33278320Sjhb#include <errno.h> 34278320Sjhb#include <stdio.h> 35278320Sjhb#include <stdlib.h> 36278320Sjhb#include <string.h> 37278320Sjhb#include <strings.h> 38278320Sjhb#include <unistd.h> 39278320Sjhb 40278320Sjhbstruct devctl_command { 41278320Sjhb const char *name; 42278320Sjhb int (*handler)(int ac, char **av); 43278320Sjhb}; 44278320Sjhb 45278320Sjhb#define DEVCTL_DATASET(name) devctl_ ## name ## _table 46278320Sjhb 47278320Sjhb#define DEVCTL_COMMAND(set, name, function) \ 48278320Sjhb static struct devctl_command function ## _devctl_command = \ 49278320Sjhb { #name, function }; \ 50278320Sjhb DATA_SET(DEVCTL_DATASET(set), function ## _devctl_command) 51278320Sjhb 52278320Sjhb#define DEVCTL_TABLE(set, name) \ 53278320Sjhb SET_DECLARE(DEVCTL_DATASET(name), struct devctl_command); \ 54278320Sjhb \ 55278320Sjhb static int \ 56278320Sjhb devctl_ ## name ## _table_handler(int ac, char **av) \ 57278320Sjhb { \ 58278320Sjhb return (devctl_table_handler(SET_BEGIN(DEVCTL_DATASET(name)), \ 59278320Sjhb SET_LIMIT(DEVCTL_DATASET(name)), ac, av)); \ 60278320Sjhb } \ 61278320Sjhb DEVCTL_COMMAND(set, name, devctl_ ## name ## _table_handler) 62278320Sjhb 63278320Sjhbstatic int devctl_table_handler(struct devctl_command **start, 64278320Sjhb struct devctl_command **end, int ac, char **av); 65278320Sjhb 66278320SjhbSET_DECLARE(DEVCTL_DATASET(top), struct devctl_command); 67278320Sjhb 68306533SjhbDEVCTL_TABLE(top, clear); 69278320SjhbDEVCTL_TABLE(top, set); 70278320Sjhb 71278320Sjhbstatic void 72278320Sjhbusage(void) 73278320Sjhb{ 74306533Sjhb fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n", 75278320Sjhb "usage: devctl attach device", 76278320Sjhb " devctl detach [-f] device", 77278320Sjhb " devctl disable [-f] device", 78278320Sjhb " devctl enable device", 79306533Sjhb " devctl set driver [-f] device driver", 80306533Sjhb " devctl clear driver [-f] device"); 81278320Sjhb exit(1); 82278320Sjhb} 83278320Sjhb 84278320Sjhbstatic int 85278320Sjhbdevctl_table_handler(struct devctl_command **start, 86278320Sjhb struct devctl_command **end, int ac, char **av) 87278320Sjhb{ 88278320Sjhb struct devctl_command **cmd; 89278320Sjhb 90278320Sjhb if (ac < 2) { 91278320Sjhb warnx("The %s command requires a sub-command.", av[0]); 92278320Sjhb return (EINVAL); 93278320Sjhb } 94278320Sjhb for (cmd = start; cmd < end; cmd++) { 95278320Sjhb if (strcmp((*cmd)->name, av[1]) == 0) 96278320Sjhb return ((*cmd)->handler(ac - 1, av + 1)); 97278320Sjhb } 98278320Sjhb 99278320Sjhb warnx("%s is not a valid sub-command of %s.", av[1], av[0]); 100278320Sjhb return (ENOENT); 101278320Sjhb} 102278320Sjhb 103278320Sjhbstatic int 104278320Sjhbhelp(int ac __unused, char **av __unused) 105278320Sjhb{ 106278320Sjhb 107278320Sjhb usage(); 108278320Sjhb return (0); 109278320Sjhb} 110278320SjhbDEVCTL_COMMAND(top, help, help); 111278320Sjhb 112278320Sjhbstatic int 113278320Sjhbattach(int ac, char **av) 114278320Sjhb{ 115278320Sjhb 116278320Sjhb if (ac != 2) 117278320Sjhb usage(); 118278320Sjhb if (devctl_attach(av[1]) < 0) 119278320Sjhb err(1, "Failed to attach %s", av[1]); 120278320Sjhb return (0); 121278320Sjhb} 122278320SjhbDEVCTL_COMMAND(top, attach, attach); 123278320Sjhb 124278320Sjhbstatic void 125278320Sjhbdetach_usage(void) 126278320Sjhb{ 127278320Sjhb 128278320Sjhb fprintf(stderr, "usage: devctl detach [-f] device\n"); 129278320Sjhb exit(1); 130278320Sjhb} 131278320Sjhb 132278320Sjhbstatic int 133278320Sjhbdetach(int ac, char **av) 134278320Sjhb{ 135278320Sjhb bool force; 136278320Sjhb int ch; 137278320Sjhb 138278320Sjhb force = false; 139278320Sjhb while ((ch = getopt(ac, av, "f")) != -1) 140278320Sjhb switch (ch) { 141278320Sjhb case 'f': 142278320Sjhb force = true; 143278320Sjhb break; 144278320Sjhb default: 145278320Sjhb detach_usage(); 146278320Sjhb } 147278320Sjhb ac -= optind; 148278320Sjhb av += optind; 149278320Sjhb 150278320Sjhb if (ac != 1) 151278320Sjhb detach_usage(); 152278320Sjhb if (devctl_detach(av[0], force) < 0) 153278320Sjhb err(1, "Failed to detach %s", av[0]); 154278320Sjhb return (0); 155278320Sjhb} 156278320SjhbDEVCTL_COMMAND(top, detach, detach); 157278320Sjhb 158278320Sjhbstatic void 159278320Sjhbdisable_usage(void) 160278320Sjhb{ 161278320Sjhb 162278320Sjhb fprintf(stderr, "usage: devctl disable [-f] device\n"); 163278320Sjhb exit(1); 164278320Sjhb} 165278320Sjhb 166278320Sjhbstatic int 167278320Sjhbdisable(int ac, char **av) 168278320Sjhb{ 169278320Sjhb bool force; 170278320Sjhb int ch; 171278320Sjhb 172278320Sjhb force = false; 173278320Sjhb while ((ch = getopt(ac, av, "f")) != -1) 174278320Sjhb switch (ch) { 175278320Sjhb case 'f': 176278320Sjhb force = true; 177278320Sjhb break; 178278320Sjhb default: 179278320Sjhb disable_usage(); 180278320Sjhb } 181278320Sjhb ac -= optind; 182278320Sjhb av += optind; 183278320Sjhb 184278320Sjhb if (ac != 1) 185278320Sjhb disable_usage(); 186278320Sjhb if (devctl_disable(av[0], force) < 0) 187278320Sjhb err(1, "Failed to disable %s", av[0]); 188278320Sjhb return (0); 189278320Sjhb} 190278320SjhbDEVCTL_COMMAND(top, disable, disable); 191278320Sjhb 192278320Sjhbstatic int 193278320Sjhbenable(int ac, char **av) 194278320Sjhb{ 195278320Sjhb 196278320Sjhb if (ac != 2) 197278320Sjhb usage(); 198278320Sjhb if (devctl_enable(av[1]) < 0) 199278320Sjhb err(1, "Failed to enable %s", av[1]); 200278320Sjhb return (0); 201278320Sjhb} 202278320SjhbDEVCTL_COMMAND(top, enable, enable); 203278320Sjhb 204278320Sjhbstatic void 205278320Sjhbset_driver_usage(void) 206278320Sjhb{ 207278320Sjhb 208278320Sjhb fprintf(stderr, "usage: devctl set driver [-f] device driver\n"); 209278320Sjhb exit(1); 210278320Sjhb} 211278320Sjhb 212278320Sjhbstatic int 213278320Sjhbset_driver(int ac, char **av) 214278320Sjhb{ 215278320Sjhb bool force; 216278320Sjhb int ch; 217278320Sjhb 218278320Sjhb force = false; 219278320Sjhb while ((ch = getopt(ac, av, "f")) != -1) 220278320Sjhb switch (ch) { 221278320Sjhb case 'f': 222278320Sjhb force = true; 223278320Sjhb break; 224278320Sjhb default: 225278320Sjhb set_driver_usage(); 226278320Sjhb } 227278320Sjhb ac -= optind; 228278320Sjhb av += optind; 229278320Sjhb 230278320Sjhb if (ac != 2) 231278320Sjhb set_driver_usage(); 232278320Sjhb if (devctl_set_driver(av[0], av[1], force) < 0) 233278320Sjhb err(1, "Failed to set %s driver to %s", av[0], av[1]); 234278320Sjhb return (0); 235278320Sjhb} 236278320SjhbDEVCTL_COMMAND(set, driver, set_driver); 237278320Sjhb 238306533Sjhbstatic void 239306533Sjhbclear_driver_usage(void) 240306533Sjhb{ 241306533Sjhb 242306533Sjhb fprintf(stderr, "usage: devctl clear driver [-f] device\n"); 243306533Sjhb exit(1); 244306533Sjhb} 245306533Sjhb 246306533Sjhbstatic int 247306533Sjhbclear_driver(int ac, char **av) 248306533Sjhb{ 249306533Sjhb bool force; 250306533Sjhb int ch; 251306533Sjhb 252306533Sjhb force = false; 253306533Sjhb while ((ch = getopt(ac, av, "f")) != -1) 254306533Sjhb switch (ch) { 255306533Sjhb case 'f': 256306533Sjhb force = true; 257306533Sjhb break; 258306533Sjhb default: 259306533Sjhb clear_driver_usage(); 260306533Sjhb } 261306533Sjhb ac -= optind; 262306533Sjhb av += optind; 263306533Sjhb 264306533Sjhb if (ac != 1) 265306533Sjhb clear_driver_usage(); 266306533Sjhb if (devctl_clear_driver(av[0], force) < 0) 267306533Sjhb err(1, "Failed to clear %s driver", av[0]); 268306533Sjhb return (0); 269306533Sjhb} 270306533SjhbDEVCTL_COMMAND(clear, driver, clear_driver); 271306533Sjhb 272278320Sjhbint 273278320Sjhbmain(int ac, char *av[]) 274278320Sjhb{ 275278320Sjhb struct devctl_command **cmd; 276278320Sjhb 277278320Sjhb if (ac == 1) 278278320Sjhb usage(); 279278320Sjhb ac--; 280278320Sjhb av++; 281278320Sjhb 282278320Sjhb SET_FOREACH(cmd, DEVCTL_DATASET(top)) { 283278320Sjhb if (strcmp((*cmd)->name, av[0]) == 0) { 284278320Sjhb if ((*cmd)->handler(ac, av) != 0) 285278320Sjhb return (1); 286278320Sjhb else 287278320Sjhb return (0); 288278320Sjhb } 289278320Sjhb } 290278320Sjhb warnx("Unknown command %s.", av[0]); 291278320Sjhb return (1); 292278320Sjhb} 293