1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <string.h> 29 #include <locale.h> 30 #include <libintl.h> 31 #include <alloca.h> 32 #include <getopt.h> 33 #include <libhotplug.h> 34 #include <sys/types.h> 35 #include <sys/sunddi.h> 36 #include <sys/ddi_hp.h> 37 38 #if !defined(TEXT_DOMAIN) /* should be defined by cc -D */ 39 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it wasn't */ 40 #endif 41 42 /* 43 * Function prototypes. 44 */ 45 static int cmd_list(int, char **, const char *); 46 static int cmd_online(int, char **, const char *); 47 static int cmd_offline(int, char **, const char *); 48 static int cmd_enable(int, char **, const char *); 49 static int cmd_disable(int, char **, const char *); 50 static int cmd_poweron(int, char **, const char *); 51 static int cmd_poweroff(int, char **, const char *); 52 static int cmd_getpriv(int, char **, const char *); 53 static int cmd_setpriv(int, char **, const char *); 54 static int cmd_changestate(int, char **, const char *); 55 static void parse_common(int, char **, const char *); 56 static void parse_flags(int, char **, int *, const char *); 57 static void parse_target(int, char **, char **, char **, const char *); 58 static void parse_options(int, char **, char **, const char *); 59 static void bad_option(int, int, const char *); 60 static void usage(const char *); 61 static int list_cb(hp_node_t, void *); 62 static int list_long_cb(hp_node_t, void *); 63 static int error_cb(hp_node_t, void *); 64 static void print_options(const char *); 65 static void print_error(int); 66 static int state_atoi(char *); 67 static char *state_itoa(int); 68 static short valid_target(int); 69 70 /* 71 * Define a conversion table for hotplug states. 72 */ 73 typedef struct { 74 int state; 75 char *state_str; 76 short valid_target; 77 } hpstate_t; 78 79 static hpstate_t hpstates[] = { 80 { DDI_HP_CN_STATE_EMPTY, "EMPTY", 0 }, 81 { DDI_HP_CN_STATE_PRESENT, "PRESENT", 1 }, 82 { DDI_HP_CN_STATE_POWERED, "POWERED", 1 }, 83 { DDI_HP_CN_STATE_ENABLED, "ENABLED", 1 }, 84 { DDI_HP_CN_STATE_PORT_EMPTY, "PORT-EMPTY", 0 }, 85 { DDI_HP_CN_STATE_PORT_PRESENT, "PORT-PRESENT", 1 }, 86 { DDI_HP_CN_STATE_OFFLINE, "OFFLINE", 1 }, 87 { DDI_HP_CN_STATE_ATTACHED, "ATTACHED", 0 }, 88 { DDI_HP_CN_STATE_MAINTENANCE, "MAINTENANCE", 0 }, 89 { DDI_HP_CN_STATE_ONLINE, "ONLINE", 1 }, 90 { 0, 0, 0 } 91 }; 92 93 /* 94 * Define tables of supported subcommands. 95 */ 96 typedef struct { 97 char *usage_str; 98 char *cmd_str; 99 int (*func)(int argc, char *argv[], const char *usage_str); 100 } subcmd_t; 101 102 static subcmd_t subcmds[] = { 103 { "list [-l] [-v] [<path> [<connection>]]", "list", cmd_list }, 104 { "online <path> <port>", "online", cmd_online }, 105 { "offline [-f] [-q] <path> <port>", "offline", cmd_offline }, 106 { "enable <path> <connector>", "enable", cmd_enable }, 107 { "disable [-f] [-q] <path> <connector>", "disable", cmd_disable }, 108 { "poweron <path> <connector>", "poweron", cmd_poweron }, 109 { "poweroff [-f] [-q] <path> <connector>", "poweroff", cmd_poweroff }, 110 { "get -o <options> <path> <connector>", "get", cmd_getpriv }, 111 { "set -o <options> <path> <connector>", "set", cmd_setpriv } 112 }; 113 114 static subcmd_t hidden_subcmds[] = { 115 { "changestate [-f] [-q] -s <state> <path> <connection>", 116 "changestate", cmd_changestate } 117 }; 118 119 /* 120 * Define tables of command line options. 121 */ 122 static const struct option common_opts[] = { 123 { "help", no_argument, 0, '?' }, 124 { "version", no_argument, 0, 'V' }, 125 { 0, 0, 0, 0 } 126 }; 127 128 static const struct option list_opts[] = { 129 { "list-path", no_argument, 0, 'l' }, 130 { "verbose", no_argument, 0, 'v' }, 131 { 0, 0, 0, 0 } 132 }; 133 134 static const struct option flag_opts[] = { 135 { "force", no_argument, 0, 'f' }, 136 { "query", no_argument, 0, 'q' }, 137 { 0, 0, 0, 0 } 138 }; 139 140 static const struct option private_opts[] = { 141 { "options", required_argument, 0, 'o' }, 142 { 0, 0, 0, 0 } 143 }; 144 145 static const struct option changestate_opts[] = { 146 { "force", no_argument, 0, 'f' }, 147 { "query", no_argument, 0, 'q' }, 148 { "state", required_argument, 0, 's' }, 149 { 0, 0, 0, 0 } 150 }; 151 152 /* 153 * Define exit codes. 154 */ 155 #define EXIT_OK 0 156 #define EXIT_EINVAL 1 /* invalid arguments */ 157 #define EXIT_ENOENT 2 /* path or connection doesn't exist */ 158 #define EXIT_FAILED 3 /* operation failed */ 159 #define EXIT_UNAVAIL 4 /* service not available */ 160 161 /* 162 * Global variables. 163 */ 164 static char *prog; 165 static char version[] = "1.0"; 166 extern int errno; 167 168 /* 169 * main() 170 * 171 * The main routine determines which subcommand is used, 172 * and dispatches control to the corresponding function. 173 */ 174 int 175 main(int argc, char *argv[]) 176 { 177 int i, rv; 178 179 (void) setlocale(LC_ALL, ""); 180 (void) textdomain(TEXT_DOMAIN); 181 182 if ((prog = strrchr(argv[0], '/')) == NULL) 183 prog = argv[0]; 184 else 185 prog++; 186 187 if (argc < 2) { 188 usage(NULL); 189 return (EXIT_EINVAL); 190 } 191 192 parse_common(argc, argv, NULL); 193 194 /* Check the list of defined subcommands. */ 195 for (i = 0; i < (sizeof (subcmds) / sizeof (subcmd_t)); i++) { 196 if (strcmp(argv[1], subcmds[i].cmd_str) == 0) { 197 rv = subcmds[i].func(argc - 1, &argv[1], 198 subcmds[i].usage_str); 199 goto finished; 200 } 201 } 202 203 /* Check the list of hidden subcommands. */ 204 for (i = 0; i < (sizeof (hidden_subcmds) / sizeof (subcmd_t)); i++) { 205 if (strcmp(argv[1], hidden_subcmds[i].cmd_str) == 0) { 206 rv = hidden_subcmds[i].func(argc - 1, &argv[1], 207 hidden_subcmds[i].usage_str); 208 goto finished; 209 } 210 } 211 212 /* No matching subcommand found. */ 213 (void) fprintf(stderr, gettext("ERROR: %s: unknown subcommand '%s'\n"), 214 prog, argv[1]); 215 usage(NULL); 216 exit(EXIT_EINVAL); 217 218 finished: 219 /* Determine exit code */ 220 switch (rv) { 221 case 0: 222 break; 223 case EINVAL: 224 return (EXIT_EINVAL); 225 case ENXIO: 226 case ENOENT: 227 return (EXIT_ENOENT); 228 case EBADF: 229 return (EXIT_UNAVAIL); 230 default: 231 return (EXIT_FAILED); 232 } 233 234 return (EXIT_OK); 235 } 236 237 /* 238 * cmd_list() 239 * 240 * Subcommand to list hotplug information. 241 */ 242 static int 243 cmd_list(int argc, char *argv[], const char *usage_str) 244 { 245 hp_node_t root; 246 char *path = NULL; 247 char *connection = NULL; 248 boolean_t long_flag = B_FALSE; 249 int flags = 0; 250 int opt; 251 252 /* Parse command line options */ 253 parse_common(argc, argv, usage_str); 254 while ((opt = getopt_clip(argc, argv, "lv", list_opts, NULL)) != -1) { 255 switch (opt) { 256 case 'l': 257 long_flag = B_TRUE; 258 break; 259 case 'v': 260 flags |= HPINFOUSAGE; 261 break; 262 default: 263 bad_option(opt, optopt, usage_str); 264 break; 265 } 266 } 267 parse_target(argc, argv, &path, &connection, usage_str); 268 269 /* Default path is "/" */ 270 if (path == NULL) 271 path = "/"; 272 273 /* Get hotplug information snapshot */ 274 if ((root = hp_init(path, connection, flags)) == NULL) { 275 print_error(errno); 276 return (errno); 277 } 278 279 /* Display hotplug information */ 280 (void) hp_traverse(root, NULL, long_flag ? list_long_cb : list_cb); 281 282 /* Discard hotplug information snapshot */ 283 hp_fini(root); 284 285 return (0); 286 } 287 288 /* 289 * cmd_online() 290 * 291 * Subcommand to online a hotplug port. 292 */ 293 static int 294 cmd_online(int argc, char *argv[], const char *usage_str) 295 { 296 hp_node_t root; 297 hp_node_t results = NULL; 298 char *path = NULL; 299 char *connection = NULL; 300 int rv; 301 302 /* Parse command line options */ 303 parse_common(argc, argv, usage_str); 304 parse_target(argc, argv, &path, &connection, usage_str); 305 306 /* Path and connection are required */ 307 if ((path == NULL) || (connection == NULL)) { 308 (void) fprintf(stderr, gettext("ERROR: too few arguments.\n")); 309 usage(usage_str); 310 return (EINVAL); 311 } 312 313 /* Get hotplug information snapshot */ 314 if ((root = hp_init(path, connection, 0)) == NULL) { 315 print_error(errno); 316 return (errno); 317 } 318 319 /* Verify target is a port */ 320 if (hp_type(root) != HP_NODE_PORT) { 321 (void) fprintf(stderr, 322 gettext("ERROR: invalid target (must be a port).\n")); 323 hp_fini(root); 324 return (EINVAL); 325 } 326 327 /* Do state change */ 328 rv = hp_set_state(root, 0, DDI_HP_CN_STATE_ONLINE, &results); 329 330 /* Display results */ 331 if (rv == EIO) { 332 (void) fprintf(stderr, gettext("ERROR: failed to attach device " 333 "drivers or other internal errors.\n")); 334 } else if (rv != 0) { 335 print_error(rv); 336 } 337 if (results != NULL) { 338 (void) hp_traverse(results, NULL, error_cb); 339 hp_fini(results); 340 } 341 342 /* Discard hotplug information snapshot */ 343 hp_fini(root); 344 345 return (rv); 346 } 347 348 /* 349 * cmd_offline() 350 * 351 * Subcommand to offline a hotplug port. 352 */ 353 static int 354 cmd_offline(int argc, char *argv[], const char *usage_str) 355 { 356 hp_node_t root; 357 hp_node_t results = NULL; 358 char *path = NULL; 359 char *connection = NULL; 360 int flags = 0; 361 int rv; 362 363 /* Parse command line options */ 364 parse_common(argc, argv, usage_str); 365 parse_flags(argc, argv, &flags, usage_str); 366 parse_target(argc, argv, &path, &connection, usage_str); 367 368 /* Path and connection are required */ 369 if ((path == NULL) || (connection == NULL)) { 370 (void) fprintf(stderr, gettext("ERROR: too few arguments.\n")); 371 usage(usage_str); 372 return (EINVAL); 373 } 374 375 /* Get hotplug information snapshot */ 376 if ((root = hp_init(path, connection, 0)) == NULL) { 377 print_error(errno); 378 return (errno); 379 } 380 381 /* Verify target is a port */ 382 if (hp_type(root) != HP_NODE_PORT) { 383 (void) fprintf(stderr, 384 gettext("ERROR: invalid target (must be a port).\n")); 385 hp_fini(root); 386 return (EINVAL); 387 } 388 389 /* Do state change */ 390 rv = hp_set_state(root, flags, DDI_HP_CN_STATE_OFFLINE, &results); 391 392 /* Display results */ 393 print_error(rv); 394 if (results != NULL) { 395 (void) hp_traverse(results, NULL, error_cb); 396 hp_fini(results); 397 } 398 399 /* Discard hotplug information snapshot */ 400 hp_fini(root); 401 402 return (rv); 403 } 404 405 /* 406 * cmd_enable() 407 * 408 * Subcommand to enable a hotplug connector. 409 */ 410 static int 411 cmd_enable(int argc, char *argv[], const char *usage_str) 412 { 413 hp_node_t root; 414 hp_node_t results = NULL; 415 char *path = NULL; 416 char *connection = NULL; 417 int rv; 418 419 /* Parse command line options */ 420 parse_common(argc, argv, usage_str); 421 parse_target(argc, argv, &path, &connection, usage_str); 422 423 /* Path and connection are required */ 424 if ((path == NULL) || (connection == NULL)) { 425 (void) fprintf(stderr, gettext("ERROR: too few arguments.\n")); 426 usage(usage_str); 427 return (EINVAL); 428 } 429 430 /* Get hotplug information snapshot */ 431 if ((root = hp_init(path, connection, 0)) == NULL) { 432 print_error(errno); 433 return (errno); 434 } 435 436 /* Verify target is a connector */ 437 if (hp_type(root) != HP_NODE_CONNECTOR) { 438 (void) fprintf(stderr, 439 gettext("ERROR: invalid target (must be a connector).\n")); 440 hp_fini(root); 441 return (EINVAL); 442 } 443 444 /* Do state change */ 445 rv = hp_set_state(root, 0, DDI_HP_CN_STATE_ENABLED, &results); 446 447 /* Display results */ 448 print_error(rv); 449 if (results != NULL) { 450 (void) hp_traverse(results, NULL, error_cb); 451 hp_fini(results); 452 } 453 454 /* Discard hotplug information snapshot */ 455 hp_fini(root); 456 457 return (rv); 458 } 459 460 /* 461 * cmd_disable() 462 * 463 * Subcommand to disable a hotplug connector. 464 */ 465 static int 466 cmd_disable(int argc, char *argv[], const char *usage_str) 467 { 468 hp_node_t root; 469 hp_node_t results = NULL; 470 char *path = NULL; 471 char *connection = NULL; 472 int flags = 0; 473 int rv; 474 475 /* Parse command line options */ 476 parse_common(argc, argv, usage_str); 477 parse_flags(argc, argv, &flags, usage_str); 478 parse_target(argc, argv, &path, &connection, usage_str); 479 480 /* Path and connection are required */ 481 if ((path == NULL) || (connection == NULL)) { 482 (void) fprintf(stderr, gettext("ERROR: too few arguments.\n")); 483 usage(usage_str); 484 return (EINVAL); 485 } 486 487 /* Get hotplug information snapshot */ 488 if ((root = hp_init(path, connection, 0)) == NULL) { 489 print_error(errno); 490 return (errno); 491 } 492 493 /* Verify target is a connector */ 494 if (hp_type(root) != HP_NODE_CONNECTOR) { 495 (void) fprintf(stderr, 496 gettext("ERROR: invalid target (must be a connector).\n")); 497 hp_fini(root); 498 return (EINVAL); 499 } 500 501 /* 502 * Do nothing unless the connector is in the ENABLED state. 503 * Otherwise this subcommand becomes an alias for 'poweron.' 504 */ 505 if (hp_state(root) != DDI_HP_CN_STATE_ENABLED) { 506 hp_fini(root); 507 return (0); 508 } 509 510 /* Do state change */ 511 rv = hp_set_state(root, flags, DDI_HP_CN_STATE_POWERED, &results); 512 513 /* Display results */ 514 print_error(rv); 515 if (results != NULL) { 516 (void) hp_traverse(results, NULL, error_cb); 517 hp_fini(results); 518 } 519 520 /* Discard hotplug information snapshot */ 521 hp_fini(root); 522 523 return (rv); 524 } 525 526 /* 527 * cmd_poweron() 528 * 529 * Subcommand to power on a hotplug connector. 530 */ 531 static int 532 cmd_poweron(int argc, char *argv[], const char *usage_str) 533 { 534 hp_node_t root; 535 hp_node_t results = NULL; 536 char *path = NULL; 537 char *connection = NULL; 538 int rv; 539 540 /* Parse command line options */ 541 parse_common(argc, argv, usage_str); 542 parse_target(argc, argv, &path, &connection, usage_str); 543 544 /* Path and connection are required */ 545 if ((path == NULL) || (connection == NULL)) { 546 (void) fprintf(stderr, gettext("ERROR: too few arguments.\n")); 547 usage(usage_str); 548 return (EINVAL); 549 } 550 551 /* Get hotplug information snapshot */ 552 if ((root = hp_init(path, connection, 0)) == NULL) { 553 print_error(errno); 554 return (errno); 555 } 556 557 /* Verify target is a connector */ 558 if (hp_type(root) != HP_NODE_CONNECTOR) { 559 (void) fprintf(stderr, 560 gettext("ERROR: invalid target (must be a connector).\n")); 561 hp_fini(root); 562 return (EINVAL); 563 } 564 565 /* 566 * Do nothing if the connector is already powered. 567 * Otherwise this subcommand becomes an alias for 'disable.' 568 */ 569 if (hp_state(root) >= DDI_HP_CN_STATE_POWERED) { 570 hp_fini(root); 571 return (0); 572 } 573 574 /* Do state change */ 575 rv = hp_set_state(root, 0, DDI_HP_CN_STATE_POWERED, &results); 576 577 /* Display results */ 578 print_error(rv); 579 if (results != NULL) { 580 (void) hp_traverse(results, NULL, error_cb); 581 hp_fini(results); 582 } 583 584 /* Discard hotplug information snapshot */ 585 hp_fini(root); 586 587 return (rv); 588 } 589 590 /* 591 * cmd_poweroff() 592 * 593 * Subcommand to power off a hotplug connector. 594 */ 595 static int 596 cmd_poweroff(int argc, char *argv[], const char *usage_str) 597 { 598 hp_node_t root; 599 hp_node_t results = NULL; 600 char *path = NULL; 601 char *connection = NULL; 602 int flags = 0; 603 int rv; 604 605 /* Parse command line options */ 606 parse_common(argc, argv, usage_str); 607 parse_flags(argc, argv, &flags, usage_str); 608 parse_target(argc, argv, &path, &connection, usage_str); 609 610 /* Path and connection are required */ 611 if ((path == NULL) || (connection == NULL)) { 612 (void) fprintf(stderr, gettext("ERROR: too few arguments.\n")); 613 usage(usage_str); 614 return (EINVAL); 615 } 616 617 /* Get hotplug information snapshot */ 618 if ((root = hp_init(path, connection, 0)) == NULL) { 619 print_error(errno); 620 return (errno); 621 } 622 623 /* Verify target is a connector */ 624 if (hp_type(root) != HP_NODE_CONNECTOR) { 625 (void) fprintf(stderr, 626 gettext("ERROR: invalid target (must be a connector).\n")); 627 hp_fini(root); 628 return (EINVAL); 629 } 630 631 /* Do state change */ 632 rv = hp_set_state(root, flags, DDI_HP_CN_STATE_PRESENT, &results); 633 634 /* Display results */ 635 print_error(rv); 636 if (results != NULL) { 637 (void) hp_traverse(results, NULL, error_cb); 638 hp_fini(results); 639 } 640 641 /* Discard hotplug information snapshot */ 642 hp_fini(root); 643 644 return (rv); 645 } 646 647 /* 648 * cmd_getpriv() 649 * 650 * Subcommand to get and display bus private options. 651 */ 652 static int 653 cmd_getpriv(int argc, char *argv[], const char *usage_str) 654 { 655 hp_node_t root; 656 char *path = NULL; 657 char *connection = NULL; 658 char *options = NULL; 659 char *results = NULL; 660 int rv; 661 662 /* Parse command line options */ 663 parse_common(argc, argv, usage_str); 664 parse_options(argc, argv, &options, usage_str); 665 parse_target(argc, argv, &path, &connection, usage_str); 666 667 /* Options, path, and connection are all required */ 668 if ((options == NULL) || (path == NULL) || (connection == NULL)) { 669 (void) fprintf(stderr, gettext("ERROR: too few arguments.\n")); 670 usage(usage_str); 671 return (EINVAL); 672 } 673 674 /* Get hotplug information snapshot */ 675 if ((root = hp_init(path, connection, 0)) == NULL) { 676 print_error(errno); 677 return (errno); 678 } 679 680 /* Verify target is a connector */ 681 if (hp_type(root) != HP_NODE_CONNECTOR) { 682 (void) fprintf(stderr, 683 gettext("ERROR: invalid target (must be a connector).\n")); 684 hp_fini(root); 685 return (EINVAL); 686 } 687 688 /* Do the operation */ 689 rv = hp_get_private(root, options, &results); 690 691 /* Display results */ 692 if (rv == ENOTSUP) { 693 (void) fprintf(stderr, 694 gettext("ERROR: unsupported property name or value.\n")); 695 (void) fprintf(stderr, 696 gettext("(Properties may depend upon connector state.)\n")); 697 } else if (rv != 0) { 698 print_error(rv); 699 } 700 if (results != NULL) { 701 print_options(results); 702 free(results); 703 } 704 705 /* Discard hotplug information snapshot */ 706 hp_fini(root); 707 708 return (rv); 709 } 710 711 /* 712 * cmd_setpriv() 713 * 714 * Subcommand to set bus private options. 715 */ 716 static int 717 cmd_setpriv(int argc, char *argv[], const char *usage_str) 718 { 719 hp_node_t root; 720 char *path = NULL; 721 char *connection = NULL; 722 char *options = NULL; 723 char *results = NULL; 724 int rv; 725 726 /* Parse command line options */ 727 parse_common(argc, argv, usage_str); 728 parse_options(argc, argv, &options, usage_str); 729 parse_target(argc, argv, &path, &connection, usage_str); 730 731 /* Options, path, and connection are all required */ 732 if ((options == NULL) || (path == NULL) || (connection == NULL)) { 733 (void) fprintf(stderr, gettext("ERROR: too few arguments.\n")); 734 usage(usage_str); 735 return (EINVAL); 736 } 737 738 /* Get hotplug information snapshot */ 739 if ((root = hp_init(path, connection, 0)) == NULL) { 740 print_error(errno); 741 return (errno); 742 } 743 744 /* Verify target is a connector */ 745 if (hp_type(root) != HP_NODE_CONNECTOR) { 746 (void) fprintf(stderr, 747 gettext("ERROR: invalid target (must be a connector).\n")); 748 hp_fini(root); 749 return (EINVAL); 750 } 751 752 /* Do the operation */ 753 rv = hp_set_private(root, options, &results); 754 755 /* Display results */ 756 if (rv == ENOTSUP) { 757 (void) fprintf(stderr, 758 gettext("ERROR: unsupported property name or value.\n")); 759 (void) fprintf(stderr, 760 gettext("(Properties may depend upon connector state.)\n")); 761 } else if (rv != 0) { 762 print_error(rv); 763 } 764 if (results != NULL) { 765 print_options(results); 766 free(results); 767 } 768 769 /* Discard hotplug information snapshot */ 770 hp_fini(root); 771 772 return (rv); 773 } 774 775 /* 776 * cmd_changestate() 777 * 778 * Subcommand to initiate a state change operation. This is 779 * a hidden subcommand to directly set a connector or port to 780 * a specific target state. 781 */ 782 static int 783 cmd_changestate(int argc, char *argv[], const char *usage_str) 784 { 785 hp_node_t root; 786 hp_node_t results = NULL; 787 char *path = NULL; 788 char *connection = NULL; 789 int state = -1; 790 int flags = 0; 791 int opt, rv; 792 793 /* Parse command line options */ 794 parse_common(argc, argv, usage_str); 795 while ((opt = getopt_clip(argc, argv, "fqs:", changestate_opts, 796 NULL)) != -1) { 797 switch (opt) { 798 case 'f': 799 flags |= HPFORCE; 800 break; 801 case 'q': 802 flags |= HPQUERY; 803 break; 804 case 's': 805 if ((state = state_atoi(optarg)) == -1) { 806 (void) printf("ERROR: invalid target state\n"); 807 return (EINVAL); 808 } 809 break; 810 default: 811 bad_option(opt, optopt, usage_str); 812 break; 813 } 814 } 815 parse_target(argc, argv, &path, &connection, usage_str); 816 817 /* State, path, and connection are all required */ 818 if ((state == -1) || (path == NULL) || (connection == NULL)) { 819 (void) fprintf(stderr, gettext("ERROR: too few arguments.\n")); 820 usage(usage_str); 821 return (EINVAL); 822 } 823 824 /* Check that target state is valid */ 825 if (valid_target(state) == 0) { 826 (void) fprintf(stderr, 827 gettext("ERROR: invalid target state\n")); 828 return (EINVAL); 829 } 830 831 /* Get hotplug information snapshot */ 832 if ((root = hp_init(path, connection, 0)) == NULL) { 833 print_error(errno); 834 return (errno); 835 } 836 837 /* Initiate state change operation on root of snapshot */ 838 rv = hp_set_state(root, flags, state, &results); 839 840 /* Display results */ 841 print_error(rv); 842 if (results) { 843 (void) hp_traverse(results, NULL, error_cb); 844 hp_fini(results); 845 } 846 847 /* Discard hotplug information snapshot */ 848 hp_fini(root); 849 850 return (rv); 851 } 852 853 /* 854 * parse_common() 855 * 856 * Parse command line options that are common to the 857 * entire program, and to each of its subcommands. 858 */ 859 static void 860 parse_common(int argc, char *argv[], const char *usage_str) 861 { 862 int opt; 863 extern int opterr; 864 extern int optind; 865 866 /* Turn off error reporting */ 867 opterr = 0; 868 869 while ((opt = getopt_clip(argc, argv, "?V", common_opts, NULL)) != -1) { 870 switch (opt) { 871 case '?': 872 if (optopt == '?') { 873 usage(usage_str); 874 exit(0); 875 } 876 break; 877 case 'V': 878 (void) printf(gettext("%s: Version %s\n"), 879 prog, version); 880 exit(0); 881 default: 882 break; 883 } 884 } 885 886 /* Reset option index */ 887 optind = 1; 888 } 889 890 /* 891 * parse_flags() 892 * 893 * Parse command line flags common to all downward state 894 * change operations (offline, disable, poweoff). 895 */ 896 static void 897 parse_flags(int argc, char *argv[], int *flagsp, const char *usage_str) 898 { 899 int opt; 900 int flags = 0; 901 902 while ((opt = getopt_clip(argc, argv, "fq", flag_opts, NULL)) != -1) { 903 switch (opt) { 904 case 'f': 905 flags |= HPFORCE; 906 break; 907 case 'q': 908 flags |= HPQUERY; 909 break; 910 default: 911 bad_option(opt, optopt, usage_str); 912 break; 913 } 914 } 915 916 *flagsp = flags; 917 } 918 919 /* 920 * parse_options() 921 * 922 * Parse command line options common to the bus private set and 923 * get subcommands. 924 */ 925 static void 926 parse_options(int argc, char *argv[], char **optionsp, const char *usage_str) 927 { 928 int opt; 929 930 while ((opt = getopt_clip(argc, argv, "o:", private_opts, 931 NULL)) != -1) { 932 switch (opt) { 933 case 'o': 934 *optionsp = optarg; 935 break; 936 default: 937 bad_option(opt, optopt, usage_str); 938 break; 939 } 940 } 941 } 942 943 /* 944 * parse_target() 945 * 946 * Parse the target path and connection name from the command line. 947 */ 948 static void 949 parse_target(int argc, char *argv[], char **pathp, char **connectionp, 950 const char *usage_str) 951 { 952 extern int optind; 953 954 if (optind < argc) 955 *pathp = argv[optind++]; 956 957 if (optind < argc) 958 *connectionp = argv[optind++]; 959 960 if (optind < argc) { 961 (void) fprintf(stderr, gettext("ERROR: too many arguments.\n")); 962 usage(usage_str); 963 exit(EINVAL); 964 } 965 } 966 967 /* 968 * bad_option() 969 * 970 * Routine to handle bad command line options. 971 */ 972 static void 973 bad_option(int opt, int optopt, const char *usage_str) 974 { 975 switch (opt) { 976 case ':': 977 (void) fprintf(stderr, 978 gettext("ERROR: option '%c' requires an argument.\n"), 979 optopt); 980 break; 981 default: 982 if (optopt == '?') { 983 usage(usage_str); 984 exit(EXIT_OK); 985 } 986 (void) fprintf(stderr, 987 gettext("ERROR: unrecognized option '%c'.\n"), optopt); 988 break; 989 } 990 991 usage(usage_str); 992 993 exit(EXIT_EINVAL); 994 } 995 996 /* 997 * usage() 998 * 999 * Display general usage of the command. Including 1000 * the usage synopsis of each defined subcommand. 1001 */ 1002 static void 1003 usage(const char *usage_str) 1004 { 1005 int i; 1006 1007 if (usage_str != NULL) { 1008 (void) fprintf(stderr, gettext("Usage: %s %s\n\n"), 1009 prog, usage_str); 1010 return; 1011 } 1012 1013 (void) fprintf(stderr, gettext("Usage: %s <subcommand> [<args>]\n\n"), 1014 prog); 1015 1016 (void) fprintf(stderr, gettext("Subcommands:\n\n")); 1017 1018 for (i = 0; i < (sizeof (subcmds) / sizeof (subcmd_t)); i++) 1019 (void) fprintf(stderr, " %s\n\n", subcmds[i].usage_str); 1020 } 1021 1022 /* 1023 * list_cb() 1024 * 1025 * Callback function for hp_traverse(), to display nodes 1026 * of a hotplug information snapshot. (Short version.) 1027 */ 1028 /*ARGSUSED*/ 1029 static int 1030 list_cb(hp_node_t node, void *arg) 1031 { 1032 hp_node_t parent; 1033 1034 /* Indent */ 1035 for (parent = hp_parent(node); parent; parent = hp_parent(parent)) 1036 if (hp_type(parent) == HP_NODE_DEVICE) 1037 (void) printf(" "); 1038 1039 switch (hp_type(node)) { 1040 case HP_NODE_DEVICE: 1041 (void) printf("%s\n", hp_name(node)); 1042 break; 1043 1044 case HP_NODE_CONNECTOR: 1045 (void) printf("[%s]", hp_name(node)); 1046 (void) printf(" (%s)", state_itoa(hp_state(node))); 1047 (void) printf("\n"); 1048 break; 1049 1050 case HP_NODE_PORT: 1051 (void) printf("<%s>", hp_name(node)); 1052 (void) printf(" (%s)", state_itoa(hp_state(node))); 1053 (void) printf("\n"); 1054 break; 1055 1056 case HP_NODE_USAGE: 1057 (void) printf("{ %s }\n", hp_usage(node)); 1058 break; 1059 } 1060 1061 return (HP_WALK_CONTINUE); 1062 } 1063 1064 /* 1065 * list_long_cb() 1066 * 1067 * Callback function for hp_traverse(), to display nodes 1068 * of a hotplug information snapshot. (Long version.) 1069 */ 1070 /*ARGSUSED*/ 1071 static int 1072 list_long_cb(hp_node_t node, void *arg) 1073 { 1074 char path[MAXPATHLEN]; 1075 char connection[MAXPATHLEN]; 1076 1077 if (hp_type(node) != HP_NODE_USAGE) { 1078 if (hp_path(node, path, connection) != 0) 1079 return (HP_WALK_CONTINUE); 1080 (void) printf("%s", path); 1081 } 1082 1083 switch (hp_type(node)) { 1084 case HP_NODE_CONNECTOR: 1085 (void) printf(" [%s]", connection); 1086 (void) printf(" (%s)", state_itoa(hp_state(node))); 1087 break; 1088 1089 case HP_NODE_PORT: 1090 (void) printf(" <%s>", connection); 1091 (void) printf(" (%s)", state_itoa(hp_state(node))); 1092 break; 1093 1094 case HP_NODE_USAGE: 1095 (void) printf(" { %s }", hp_usage(node)); 1096 break; 1097 } 1098 1099 (void) printf("\n"); 1100 1101 return (HP_WALK_CONTINUE); 1102 } 1103 1104 /* 1105 * error_cb() 1106 * 1107 * Callback function for hp_traverse(), to display 1108 * error results from a state change operation. 1109 */ 1110 /*ARGSUSED*/ 1111 static int 1112 error_cb(hp_node_t node, void *arg) 1113 { 1114 hp_node_t child; 1115 char *usage_str; 1116 static char path[MAXPATHLEN]; 1117 static char connection[MAXPATHLEN]; 1118 1119 if (((child = hp_child(node)) != NULL) && 1120 (hp_type(child) == HP_NODE_USAGE)) { 1121 if (hp_path(node, path, connection) == 0) 1122 (void) printf("%s:\n", path); 1123 return (HP_WALK_CONTINUE); 1124 } 1125 1126 if ((hp_type(node) == HP_NODE_USAGE) && 1127 ((usage_str = hp_usage(node)) != NULL)) 1128 (void) printf(" { %s }\n", usage_str); 1129 1130 return (HP_WALK_CONTINUE); 1131 } 1132 1133 /* 1134 * print_options() 1135 * 1136 * Parse and display bus private options. The options are 1137 * formatted as a string which conforms to the getsubopt(3C) 1138 * format. This routine only splits the string elements as 1139 * separated by commas, and displays each portion on its own 1140 * separate line of output. 1141 */ 1142 static void 1143 print_options(const char *options) 1144 { 1145 char *buf, *curr, *next; 1146 size_t len; 1147 1148 /* Do nothing if options string is empty */ 1149 if ((len = strlen(options)) == 0) 1150 return; 1151 1152 /* To avoid modifying the input string, make a copy on the stack */ 1153 if ((buf = (char *)alloca(len + 1)) == NULL) { 1154 (void) printf("%s\n", options); 1155 return; 1156 } 1157 (void) strlcpy(buf, options, len + 1); 1158 1159 /* Iterate through each comma-separated name/value pair */ 1160 curr = buf; 1161 do { 1162 if ((next = strchr(curr, ',')) != NULL) { 1163 *next = '\0'; 1164 next++; 1165 } 1166 (void) printf("%s\n", curr); 1167 } while ((curr = next) != NULL); 1168 } 1169 1170 /* 1171 * print_error() 1172 * 1173 * Common routine to print error numbers in an appropriate way. 1174 * Prints nothing if error code is 0. 1175 */ 1176 static void 1177 print_error(int error) 1178 { 1179 switch (error) { 1180 case 0: 1181 /* No error */ 1182 return; 1183 case EACCES: 1184 (void) fprintf(stderr, 1185 gettext("ERROR: operation not authorized.\n")); 1186 break; 1187 case EBADF: 1188 (void) fprintf(stderr, 1189 gettext("ERROR: hotplug service is not available.\n")); 1190 break; 1191 case EBUSY: 1192 (void) fprintf(stderr, 1193 gettext("ERROR: devices or resources are busy.\n")); 1194 break; 1195 case EEXIST: 1196 (void) fprintf(stderr, 1197 gettext("ERROR: resource already exists.\n")); 1198 break; 1199 case EFAULT: 1200 (void) fprintf(stderr, 1201 gettext("ERROR: internal failure in hotplug service.\n")); 1202 break; 1203 case EINVAL: 1204 (void) fprintf(stderr, 1205 gettext("ERROR: invalid arguments.\n")); 1206 break; 1207 case ENOENT: 1208 (void) fprintf(stderr, 1209 gettext("ERROR: there are no connections to display.\n")); 1210 (void) fprintf(stderr, 1211 gettext("(See hotplug(8) for more information.)\n")); 1212 break; 1213 case ENXIO: 1214 (void) fprintf(stderr, 1215 gettext("ERROR: no such path or connection.\n")); 1216 break; 1217 case ENOMEM: 1218 (void) fprintf(stderr, 1219 gettext("ERROR: not enough memory.\n")); 1220 break; 1221 case ENOTSUP: 1222 (void) fprintf(stderr, 1223 gettext("ERROR: operation not supported.\n")); 1224 break; 1225 case EIO: 1226 (void) fprintf(stderr, 1227 gettext("ERROR: hardware or driver specific failure.\n")); 1228 break; 1229 default: 1230 (void) fprintf(stderr, gettext("ERROR: operation failed: %s\n"), 1231 strerror(error)); 1232 break; 1233 } 1234 } 1235 1236 /* 1237 * state_atoi() 1238 * 1239 * Convert a hotplug state from a string to an integer. 1240 */ 1241 static int 1242 state_atoi(char *state) 1243 { 1244 int i; 1245 1246 for (i = 0; hpstates[i].state_str != NULL; i++) 1247 if (strcasecmp(state, hpstates[i].state_str) == 0) 1248 return (hpstates[i].state); 1249 1250 return (-1); 1251 } 1252 1253 /* 1254 * state_itoa() 1255 * 1256 * Convert a hotplug state from an integer to a string. 1257 */ 1258 static char * 1259 state_itoa(int state) 1260 { 1261 static char unknown[] = "UNKNOWN"; 1262 int i; 1263 1264 for (i = 0; hpstates[i].state_str != NULL; i++) 1265 if (state == hpstates[i].state) 1266 return (hpstates[i].state_str); 1267 1268 return (unknown); 1269 } 1270 1271 /* 1272 * valid_target() 1273 * 1274 * Check if a state is a valid target for a changestate command. 1275 */ 1276 static short 1277 valid_target(int state) 1278 { 1279 int i; 1280 1281 for (i = 0; hpstates[i].state_str != NULL; i++) 1282 if (state == hpstates[i].state) 1283 return (hpstates[i].valid_target); 1284 1285 return (0); 1286 } 1287