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: releng/10.3/usr.sbin/devctl/devctl.c 295131 2016-02-01 23:07:31Z 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 68278320SjhbDEVCTL_TABLE(top, set); 69278320Sjhb 70278320Sjhbstatic void 71278320Sjhbusage(void) 72278320Sjhb{ 73295131Sjhb fprintf(stderr, "%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 set driver [-f] device driver"); 79278320Sjhb exit(1); 80278320Sjhb} 81278320Sjhb 82278320Sjhbstatic int 83278320Sjhbdevctl_table_handler(struct devctl_command **start, 84278320Sjhb struct devctl_command **end, int ac, char **av) 85278320Sjhb{ 86278320Sjhb struct devctl_command **cmd; 87278320Sjhb 88278320Sjhb if (ac < 2) { 89278320Sjhb warnx("The %s command requires a sub-command.", av[0]); 90278320Sjhb return (EINVAL); 91278320Sjhb } 92278320Sjhb for (cmd = start; cmd < end; cmd++) { 93278320Sjhb if (strcmp((*cmd)->name, av[1]) == 0) 94278320Sjhb return ((*cmd)->handler(ac - 1, av + 1)); 95278320Sjhb } 96278320Sjhb 97278320Sjhb warnx("%s is not a valid sub-command of %s.", av[1], av[0]); 98278320Sjhb return (ENOENT); 99278320Sjhb} 100278320Sjhb 101278320Sjhbstatic int 102278320Sjhbhelp(int ac __unused, char **av __unused) 103278320Sjhb{ 104278320Sjhb 105278320Sjhb usage(); 106278320Sjhb return (0); 107278320Sjhb} 108278320SjhbDEVCTL_COMMAND(top, help, help); 109278320Sjhb 110278320Sjhbstatic int 111278320Sjhbattach(int ac, char **av) 112278320Sjhb{ 113278320Sjhb 114278320Sjhb if (ac != 2) 115278320Sjhb usage(); 116278320Sjhb if (devctl_attach(av[1]) < 0) 117278320Sjhb err(1, "Failed to attach %s", av[1]); 118278320Sjhb return (0); 119278320Sjhb} 120278320SjhbDEVCTL_COMMAND(top, attach, attach); 121278320Sjhb 122278320Sjhbstatic void 123278320Sjhbdetach_usage(void) 124278320Sjhb{ 125278320Sjhb 126278320Sjhb fprintf(stderr, "usage: devctl detach [-f] device\n"); 127278320Sjhb exit(1); 128278320Sjhb} 129278320Sjhb 130278320Sjhbstatic int 131278320Sjhbdetach(int ac, char **av) 132278320Sjhb{ 133278320Sjhb bool force; 134278320Sjhb int ch; 135278320Sjhb 136278320Sjhb force = false; 137278320Sjhb while ((ch = getopt(ac, av, "f")) != -1) 138278320Sjhb switch (ch) { 139278320Sjhb case 'f': 140278320Sjhb force = true; 141278320Sjhb break; 142278320Sjhb default: 143278320Sjhb detach_usage(); 144278320Sjhb } 145278320Sjhb ac -= optind; 146278320Sjhb av += optind; 147278320Sjhb 148278320Sjhb if (ac != 1) 149278320Sjhb detach_usage(); 150278320Sjhb if (devctl_detach(av[0], force) < 0) 151278320Sjhb err(1, "Failed to detach %s", av[0]); 152278320Sjhb return (0); 153278320Sjhb} 154278320SjhbDEVCTL_COMMAND(top, detach, detach); 155278320Sjhb 156278320Sjhbstatic void 157278320Sjhbdisable_usage(void) 158278320Sjhb{ 159278320Sjhb 160278320Sjhb fprintf(stderr, "usage: devctl disable [-f] device\n"); 161278320Sjhb exit(1); 162278320Sjhb} 163278320Sjhb 164278320Sjhbstatic int 165278320Sjhbdisable(int ac, char **av) 166278320Sjhb{ 167278320Sjhb bool force; 168278320Sjhb int ch; 169278320Sjhb 170278320Sjhb force = false; 171278320Sjhb while ((ch = getopt(ac, av, "f")) != -1) 172278320Sjhb switch (ch) { 173278320Sjhb case 'f': 174278320Sjhb force = true; 175278320Sjhb break; 176278320Sjhb default: 177278320Sjhb disable_usage(); 178278320Sjhb } 179278320Sjhb ac -= optind; 180278320Sjhb av += optind; 181278320Sjhb 182278320Sjhb if (ac != 1) 183278320Sjhb disable_usage(); 184278320Sjhb if (devctl_disable(av[0], force) < 0) 185278320Sjhb err(1, "Failed to disable %s", av[0]); 186278320Sjhb return (0); 187278320Sjhb} 188278320SjhbDEVCTL_COMMAND(top, disable, disable); 189278320Sjhb 190278320Sjhbstatic int 191278320Sjhbenable(int ac, char **av) 192278320Sjhb{ 193278320Sjhb 194278320Sjhb if (ac != 2) 195278320Sjhb usage(); 196278320Sjhb if (devctl_enable(av[1]) < 0) 197278320Sjhb err(1, "Failed to enable %s", av[1]); 198278320Sjhb return (0); 199278320Sjhb} 200278320SjhbDEVCTL_COMMAND(top, enable, enable); 201278320Sjhb 202278320Sjhbstatic void 203278320Sjhbset_driver_usage(void) 204278320Sjhb{ 205278320Sjhb 206278320Sjhb fprintf(stderr, "usage: devctl set driver [-f] device driver\n"); 207278320Sjhb exit(1); 208278320Sjhb} 209278320Sjhb 210278320Sjhbstatic int 211278320Sjhbset_driver(int ac, char **av) 212278320Sjhb{ 213278320Sjhb bool force; 214278320Sjhb int ch; 215278320Sjhb 216278320Sjhb force = false; 217278320Sjhb while ((ch = getopt(ac, av, "f")) != -1) 218278320Sjhb switch (ch) { 219278320Sjhb case 'f': 220278320Sjhb force = true; 221278320Sjhb break; 222278320Sjhb default: 223278320Sjhb set_driver_usage(); 224278320Sjhb } 225278320Sjhb ac -= optind; 226278320Sjhb av += optind; 227278320Sjhb 228278320Sjhb if (ac != 2) 229278320Sjhb set_driver_usage(); 230278320Sjhb if (devctl_set_driver(av[0], av[1], force) < 0) 231278320Sjhb err(1, "Failed to set %s driver to %s", av[0], av[1]); 232278320Sjhb return (0); 233278320Sjhb} 234278320SjhbDEVCTL_COMMAND(set, driver, set_driver); 235278320Sjhb 236278320Sjhbint 237278320Sjhbmain(int ac, char *av[]) 238278320Sjhb{ 239278320Sjhb struct devctl_command **cmd; 240278320Sjhb 241278320Sjhb if (ac == 1) 242278320Sjhb usage(); 243278320Sjhb ac--; 244278320Sjhb av++; 245278320Sjhb 246278320Sjhb SET_FOREACH(cmd, DEVCTL_DATASET(top)) { 247278320Sjhb if (strcmp((*cmd)->name, av[0]) == 0) { 248278320Sjhb if ((*cmd)->handler(ac, av) != 0) 249278320Sjhb return (1); 250278320Sjhb else 251278320Sjhb return (0); 252278320Sjhb } 253278320Sjhb } 254278320Sjhb warnx("Unknown command %s.", av[0]); 255278320Sjhb return (1); 256278320Sjhb} 257