1 /*- 2 * Copyright (c) 2014 John Baldwin <jhb@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <sys/linker_set.h> 31 #include <devctl.h> 32 #include <err.h> 33 #include <errno.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <strings.h> 38 #include <unistd.h> 39 40 struct devctl_command { 41 const char *name; 42 int (*handler)(int ac, char **av); 43 }; 44 45 #define DEVCTL_DATASET(name) devctl_ ## name ## _table 46 47 #define DEVCTL_COMMAND(set, name, function) \ 48 static struct devctl_command function ## _devctl_command = \ 49 { #name, function }; \ 50 DATA_SET(DEVCTL_DATASET(set), function ## _devctl_command) 51 52 #define DEVCTL_TABLE(set, name) \ 53 SET_DECLARE(DEVCTL_DATASET(name), struct devctl_command); \ 54 \ 55 static int \ 56 devctl_ ## name ## _table_handler(int ac, char **av) \ 57 { \ 58 return (devctl_table_handler(SET_BEGIN(DEVCTL_DATASET(name)), \ 59 SET_LIMIT(DEVCTL_DATASET(name)), ac, av)); \ 60 } \ 61 DEVCTL_COMMAND(set, name, devctl_ ## name ## _table_handler) 62 63 static int devctl_table_handler(struct devctl_command **start, 64 struct devctl_command **end, int ac, char **av); 65 66 SET_DECLARE(DEVCTL_DATASET(top), struct devctl_command); 67 68 DEVCTL_TABLE(top, clear); 69 DEVCTL_TABLE(top, set); 70 71 static void 72 usage(void) 73 { 74 fprintf(stderr, 75 "usage: devctl attach device\n" 76 " devctl detach [-f] device\n" 77 " devctl disable [-f] device\n" 78 " devctl enable device\n" 79 " devctl suspend device\n" 80 " devctl resume device\n" 81 " devctl set driver [-f] device driver\n" 82 " devctl clear driver [-f] device\n" 83 " devctl rescan device\n" 84 " devctl delete [-f] device\n" 85 " devctl freeze\n" 86 " devctl thaw\n"); 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 int 389 main(int ac, char *av[]) 390 { 391 struct devctl_command **cmd; 392 393 if (ac == 1) 394 usage(); 395 ac--; 396 av++; 397 398 SET_FOREACH(cmd, DEVCTL_DATASET(top)) { 399 if (strcmp((*cmd)->name, av[0]) == 0) { 400 if ((*cmd)->handler(ac, av) != 0) 401 return (1); 402 else 403 return (0); 404 } 405 } 406 warnx("Unknown command %s.", av[0]); 407 return (1); 408 } 409