8672 proc_t changes broke genunix dmods and walker
[unleashed.git] / usr / src / cmd / hotplug / hotplug.c
blob8ffb8d48dd71ca6eca4e30daf78c76d0a386ae17
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
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>
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
43 * Function prototypes.
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);
71 * Define a conversion table for hotplug states.
73 typedef struct {
74 int state;
75 char *state_str;
76 short valid_target;
77 } hpstate_t;
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 }
94 * Define tables of supported subcommands.
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;
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 }
114 static subcmd_t hidden_subcmds[] = {
115 { "changestate [-f] [-q] -s <state> <path> <connection>",
116 "changestate", cmd_changestate }
120 * Define tables of command line options.
122 static const struct option common_opts[] = {
123 { "help", no_argument, 0, '?' },
124 { "version", no_argument, 0, 'V' },
125 { 0, 0, 0, 0 }
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 }
134 static const struct option flag_opts[] = {
135 { "force", no_argument, 0, 'f' },
136 { "query", no_argument, 0, 'q' },
137 { 0, 0, 0, 0 }
140 static const struct option private_opts[] = {
141 { "options", required_argument, 0, 'o' },
142 { 0, 0, 0, 0 }
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 }
153 * Define exit codes.
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 */
162 * Global variables.
164 static char *prog;
165 static char version[] = "1.0";
166 extern int errno;
169 * main()
171 * The main routine determines which subcommand is used,
172 * and dispatches control to the corresponding function.
175 main(int argc, char *argv[])
177 int i, rv;
179 (void) setlocale(LC_ALL, "");
180 (void) textdomain(TEXT_DOMAIN);
182 if ((prog = strrchr(argv[0], '/')) == NULL)
183 prog = argv[0];
184 else
185 prog++;
187 if (argc < 2) {
188 usage(NULL);
189 return (EXIT_EINVAL);
192 parse_common(argc, argv, NULL);
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;
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;
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);
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);
234 return (EXIT_OK);
238 * cmd_list()
240 * Subcommand to list hotplug information.
242 static int
243 cmd_list(int argc, char *argv[], const char *usage_str)
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;
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;
267 parse_target(argc, argv, &path, &connection, usage_str);
269 /* Default path is "/" */
270 if (path == NULL)
271 path = "/";
273 /* Get hotplug information snapshot */
274 if ((root = hp_init(path, connection, flags)) == NULL) {
275 print_error(errno);
276 return (errno);
279 /* Display hotplug information */
280 (void) hp_traverse(root, NULL, long_flag ? list_long_cb : list_cb);
282 /* Discard hotplug information snapshot */
283 hp_fini(root);
285 return (0);
289 * cmd_online()
291 * Subcommand to online a hotplug port.
293 static int
294 cmd_online(int argc, char *argv[], const char *usage_str)
296 hp_node_t root;
297 hp_node_t results = NULL;
298 char *path = NULL;
299 char *connection = NULL;
300 int rv;
302 /* Parse command line options */
303 parse_common(argc, argv, usage_str);
304 parse_target(argc, argv, &path, &connection, usage_str);
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);
313 /* Get hotplug information snapshot */
314 if ((root = hp_init(path, connection, 0)) == NULL) {
315 print_error(errno);
316 return (errno);
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);
327 /* Do state change */
328 rv = hp_set_state(root, 0, DDI_HP_CN_STATE_ONLINE, &results);
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);
337 if (results != NULL) {
338 (void) hp_traverse(results, NULL, error_cb);
339 hp_fini(results);
342 /* Discard hotplug information snapshot */
343 hp_fini(root);
345 return (rv);
349 * cmd_offline()
351 * Subcommand to offline a hotplug port.
353 static int
354 cmd_offline(int argc, char *argv[], const char *usage_str)
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;
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);
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);
375 /* Get hotplug information snapshot */
376 if ((root = hp_init(path, connection, 0)) == NULL) {
377 print_error(errno);
378 return (errno);
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);
389 /* Do state change */
390 rv = hp_set_state(root, flags, DDI_HP_CN_STATE_OFFLINE, &results);
392 /* Display results */
393 print_error(rv);
394 if (results != NULL) {
395 (void) hp_traverse(results, NULL, error_cb);
396 hp_fini(results);
399 /* Discard hotplug information snapshot */
400 hp_fini(root);
402 return (rv);
406 * cmd_enable()
408 * Subcommand to enable a hotplug connector.
410 static int
411 cmd_enable(int argc, char *argv[], const char *usage_str)
413 hp_node_t root;
414 hp_node_t results = NULL;
415 char *path = NULL;
416 char *connection = NULL;
417 int rv;
419 /* Parse command line options */
420 parse_common(argc, argv, usage_str);
421 parse_target(argc, argv, &path, &connection, usage_str);
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);
430 /* Get hotplug information snapshot */
431 if ((root = hp_init(path, connection, 0)) == NULL) {
432 print_error(errno);
433 return (errno);
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);
444 /* Do state change */
445 rv = hp_set_state(root, 0, DDI_HP_CN_STATE_ENABLED, &results);
447 /* Display results */
448 print_error(rv);
449 if (results != NULL) {
450 (void) hp_traverse(results, NULL, error_cb);
451 hp_fini(results);
454 /* Discard hotplug information snapshot */
455 hp_fini(root);
457 return (rv);
461 * cmd_disable()
463 * Subcommand to disable a hotplug connector.
465 static int
466 cmd_disable(int argc, char *argv[], const char *usage_str)
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;
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);
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);
487 /* Get hotplug information snapshot */
488 if ((root = hp_init(path, connection, 0)) == NULL) {
489 print_error(errno);
490 return (errno);
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);
502 * Do nothing unless the connector is in the ENABLED state.
503 * Otherwise this subcommand becomes an alias for 'poweron.'
505 if (hp_state(root) != DDI_HP_CN_STATE_ENABLED) {
506 hp_fini(root);
507 return (0);
510 /* Do state change */
511 rv = hp_set_state(root, flags, DDI_HP_CN_STATE_POWERED, &results);
513 /* Display results */
514 print_error(rv);
515 if (results != NULL) {
516 (void) hp_traverse(results, NULL, error_cb);
517 hp_fini(results);
520 /* Discard hotplug information snapshot */
521 hp_fini(root);
523 return (rv);
527 * cmd_poweron()
529 * Subcommand to power on a hotplug connector.
531 static int
532 cmd_poweron(int argc, char *argv[], const char *usage_str)
534 hp_node_t root;
535 hp_node_t results = NULL;
536 char *path = NULL;
537 char *connection = NULL;
538 int rv;
540 /* Parse command line options */
541 parse_common(argc, argv, usage_str);
542 parse_target(argc, argv, &path, &connection, usage_str);
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);
551 /* Get hotplug information snapshot */
552 if ((root = hp_init(path, connection, 0)) == NULL) {
553 print_error(errno);
554 return (errno);
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);
566 * Do nothing if the connector is already powered.
567 * Otherwise this subcommand becomes an alias for 'disable.'
569 if (hp_state(root) >= DDI_HP_CN_STATE_POWERED) {
570 hp_fini(root);
571 return (0);
574 /* Do state change */
575 rv = hp_set_state(root, 0, DDI_HP_CN_STATE_POWERED, &results);
577 /* Display results */
578 print_error(rv);
579 if (results != NULL) {
580 (void) hp_traverse(results, NULL, error_cb);
581 hp_fini(results);
584 /* Discard hotplug information snapshot */
585 hp_fini(root);
587 return (rv);
591 * cmd_poweroff()
593 * Subcommand to power off a hotplug connector.
595 static int
596 cmd_poweroff(int argc, char *argv[], const char *usage_str)
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;
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);
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);
617 /* Get hotplug information snapshot */
618 if ((root = hp_init(path, connection, 0)) == NULL) {
619 print_error(errno);
620 return (errno);
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);
631 /* Do state change */
632 rv = hp_set_state(root, flags, DDI_HP_CN_STATE_PRESENT, &results);
634 /* Display results */
635 print_error(rv);
636 if (results != NULL) {
637 (void) hp_traverse(results, NULL, error_cb);
638 hp_fini(results);
641 /* Discard hotplug information snapshot */
642 hp_fini(root);
644 return (rv);
648 * cmd_getpriv()
650 * Subcommand to get and display bus private options.
652 static int
653 cmd_getpriv(int argc, char *argv[], const char *usage_str)
655 hp_node_t root;
656 char *path = NULL;
657 char *connection = NULL;
658 char *options = NULL;
659 char *results = NULL;
660 int rv;
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);
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);
674 /* Get hotplug information snapshot */
675 if ((root = hp_init(path, connection, 0)) == NULL) {
676 print_error(errno);
677 return (errno);
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);
688 /* Do the operation */
689 rv = hp_get_private(root, options, &results);
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);
700 if (results != NULL) {
701 print_options(results);
702 free(results);
705 /* Discard hotplug information snapshot */
706 hp_fini(root);
708 return (rv);
712 * cmd_setpriv()
714 * Subcommand to set bus private options.
716 static int
717 cmd_setpriv(int argc, char *argv[], const char *usage_str)
719 hp_node_t root;
720 char *path = NULL;
721 char *connection = NULL;
722 char *options = NULL;
723 char *results = NULL;
724 int rv;
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);
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);
738 /* Get hotplug information snapshot */
739 if ((root = hp_init(path, connection, 0)) == NULL) {
740 print_error(errno);
741 return (errno);
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);
752 /* Do the operation */
753 rv = hp_set_private(root, options, &results);
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);
764 if (results != NULL) {
765 print_options(results);
766 free(results);
769 /* Discard hotplug information snapshot */
770 hp_fini(root);
772 return (rv);
776 * cmd_changestate()
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.
782 static int
783 cmd_changestate(int argc, char *argv[], const char *usage_str)
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;
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);
809 break;
810 default:
811 bad_option(opt, optopt, usage_str);
812 break;
815 parse_target(argc, argv, &path, &connection, usage_str);
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);
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);
831 /* Get hotplug information snapshot */
832 if ((root = hp_init(path, connection, 0)) == NULL) {
833 print_error(errno);
834 return (errno);
837 /* Initiate state change operation on root of snapshot */
838 rv = hp_set_state(root, flags, state, &results);
840 /* Display results */
841 print_error(rv);
842 if (results) {
843 (void) hp_traverse(results, NULL, error_cb);
844 hp_fini(results);
847 /* Discard hotplug information snapshot */
848 hp_fini(root);
850 return (rv);
854 * parse_common()
856 * Parse command line options that are common to the
857 * entire program, and to each of its subcommands.
859 static void
860 parse_common(int argc, char *argv[], const char *usage_str)
862 int opt;
863 extern int opterr;
864 extern int optind;
866 /* Turn off error reporting */
867 opterr = 0;
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);
876 break;
877 case 'V':
878 (void) printf(gettext("%s: Version %s\n"),
879 prog, version);
880 exit(0);
881 default:
882 break;
886 /* Reset option index */
887 optind = 1;
891 * parse_flags()
893 * Parse command line flags common to all downward state
894 * change operations (offline, disable, poweoff).
896 static void
897 parse_flags(int argc, char *argv[], int *flagsp, const char *usage_str)
899 int opt;
900 int flags = 0;
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;
916 *flagsp = flags;
920 * parse_options()
922 * Parse command line options common to the bus private set and
923 * get subcommands.
925 static void
926 parse_options(int argc, char *argv[], char **optionsp, const char *usage_str)
928 int opt;
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;
944 * parse_target()
946 * Parse the target path and connection name from the command line.
948 static void
949 parse_target(int argc, char *argv[], char **pathp, char **connectionp,
950 const char *usage_str)
952 extern int optind;
954 if (optind < argc)
955 *pathp = argv[optind++];
957 if (optind < argc)
958 *connectionp = argv[optind++];
960 if (optind < argc) {
961 (void) fprintf(stderr, gettext("ERROR: too many arguments.\n"));
962 usage(usage_str);
963 exit(EINVAL);
968 * bad_option()
970 * Routine to handle bad command line options.
972 static void
973 bad_option(int opt, int optopt, const char *usage_str)
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);
986 (void) fprintf(stderr,
987 gettext("ERROR: unrecognized option '%c'.\n"), optopt);
988 break;
991 usage(usage_str);
993 exit(EXIT_EINVAL);
997 * usage()
999 * Display general usage of the command. Including
1000 * the usage synopsis of each defined subcommand.
1002 static void
1003 usage(const char *usage_str)
1005 int i;
1007 if (usage_str != NULL) {
1008 (void) fprintf(stderr, gettext("Usage: %s %s\n\n"),
1009 prog, usage_str);
1010 return;
1013 (void) fprintf(stderr, gettext("Usage: %s <subcommand> [<args>]\n\n"),
1014 prog);
1016 (void) fprintf(stderr, gettext("Subcommands:\n\n"));
1018 for (i = 0; i < (sizeof (subcmds) / sizeof (subcmd_t)); i++)
1019 (void) fprintf(stderr, " %s\n\n", subcmds[i].usage_str);
1023 * list_cb()
1025 * Callback function for hp_traverse(), to display nodes
1026 * of a hotplug information snapshot. (Short version.)
1028 /*ARGSUSED*/
1029 static int
1030 list_cb(hp_node_t node, void *arg)
1032 hp_node_t parent;
1034 /* Indent */
1035 for (parent = hp_parent(node); parent; parent = hp_parent(parent))
1036 if (hp_type(parent) == HP_NODE_DEVICE)
1037 (void) printf(" ");
1039 switch (hp_type(node)) {
1040 case HP_NODE_DEVICE:
1041 (void) printf("%s\n", hp_name(node));
1042 break;
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;
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;
1056 case HP_NODE_USAGE:
1057 (void) printf("{ %s }\n", hp_usage(node));
1058 break;
1061 return (HP_WALK_CONTINUE);
1065 * list_long_cb()
1067 * Callback function for hp_traverse(), to display nodes
1068 * of a hotplug information snapshot. (Long version.)
1070 /*ARGSUSED*/
1071 static int
1072 list_long_cb(hp_node_t node, void *arg)
1074 char path[MAXPATHLEN];
1075 char connection[MAXPATHLEN];
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);
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;
1089 case HP_NODE_PORT:
1090 (void) printf(" <%s>", connection);
1091 (void) printf(" (%s)", state_itoa(hp_state(node)));
1092 break;
1094 case HP_NODE_USAGE:
1095 (void) printf(" { %s }", hp_usage(node));
1096 break;
1099 (void) printf("\n");
1101 return (HP_WALK_CONTINUE);
1105 * error_cb()
1107 * Callback function for hp_traverse(), to display
1108 * error results from a state change operation.
1110 /*ARGSUSED*/
1111 static int
1112 error_cb(hp_node_t node, void *arg)
1114 hp_node_t child;
1115 char *usage_str;
1116 static char path[MAXPATHLEN];
1117 static char connection[MAXPATHLEN];
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);
1126 if ((hp_type(node) == HP_NODE_USAGE) &&
1127 ((usage_str = hp_usage(node)) != NULL))
1128 (void) printf(" { %s }\n", usage_str);
1130 return (HP_WALK_CONTINUE);
1134 * print_options()
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.
1142 static void
1143 print_options(const char *options)
1145 char *buf, *curr, *next;
1146 size_t len;
1148 /* Do nothing if options string is empty */
1149 if ((len = strlen(options)) == 0)
1150 return;
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;
1157 (void) strlcpy(buf, options, len + 1);
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++;
1166 (void) printf("%s\n", curr);
1167 } while ((curr = next) != NULL);
1171 * print_error()
1173 * Common routine to print error numbers in an appropriate way.
1174 * Prints nothing if error code is 0.
1176 static void
1177 print_error(int error)
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(1m) 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;
1237 * state_atoi()
1239 * Convert a hotplug state from a string to an integer.
1241 static int
1242 state_atoi(char *state)
1244 int i;
1246 for (i = 0; hpstates[i].state_str != NULL; i++)
1247 if (strcasecmp(state, hpstates[i].state_str) == 0)
1248 return (hpstates[i].state);
1250 return (-1);
1254 * state_itoa()
1256 * Convert a hotplug state from an integer to a string.
1258 static char *
1259 state_itoa(int state)
1261 static char unknown[] = "UNKNOWN";
1262 int i;
1264 for (i = 0; hpstates[i].state_str != NULL; i++)
1265 if (state == hpstates[i].state)
1266 return (hpstates[i].state_str);
1268 return (unknown);
1272 * valid_target()
1274 * Check if a state is a valid target for a changestate command.
1276 static short
1277 valid_target(int state)
1279 int i;
1281 for (i = 0; hpstates[i].state_str != NULL; i++)
1282 if (state == hpstates[i].state)
1283 return (hpstates[i].valid_target);
1285 return (0);