/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include #if !defined(TEXT_DOMAIN) /* should be defined by cc -D */ #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it wasn't */ #endif /* * Function prototypes. */ static int cmd_list(int, char **, const char *); static int cmd_online(int, char **, const char *); static int cmd_offline(int, char **, const char *); static int cmd_enable(int, char **, const char *); static int cmd_disable(int, char **, const char *); static int cmd_poweron(int, char **, const char *); static int cmd_poweroff(int, char **, const char *); static int cmd_getpriv(int, char **, const char *); static int cmd_setpriv(int, char **, const char *); static int cmd_changestate(int, char **, const char *); static void parse_common(int, char **, const char *); static void parse_flags(int, char **, int *, const char *); static void parse_target(int, char **, char **, char **, const char *); static void parse_options(int, char **, char **, const char *); static void bad_option(int, int, const char *); static void usage(const char *); static int list_cb(hp_node_t, void *); static int list_long_cb(hp_node_t, void *); static int error_cb(hp_node_t, void *); static void print_options(const char *); static void print_error(int); static int state_atoi(char *); static char *state_itoa(int); static short valid_target(int); /* * Define a conversion table for hotplug states. */ typedef struct { int state; char *state_str; short valid_target; } hpstate_t; static hpstate_t hpstates[] = { { DDI_HP_CN_STATE_EMPTY, "EMPTY", 0 }, { DDI_HP_CN_STATE_PRESENT, "PRESENT", 1 }, { DDI_HP_CN_STATE_POWERED, "POWERED", 1 }, { DDI_HP_CN_STATE_ENABLED, "ENABLED", 1 }, { DDI_HP_CN_STATE_PORT_EMPTY, "PORT-EMPTY", 0 }, { DDI_HP_CN_STATE_PORT_PRESENT, "PORT-PRESENT", 1 }, { DDI_HP_CN_STATE_OFFLINE, "OFFLINE", 1 }, { DDI_HP_CN_STATE_ATTACHED, "ATTACHED", 0 }, { DDI_HP_CN_STATE_MAINTENANCE, "MAINTENANCE", 0 }, { DDI_HP_CN_STATE_ONLINE, "ONLINE", 1 }, { 0, 0, 0 } }; /* * Define tables of supported subcommands. */ typedef struct { char *usage_str; char *cmd_str; int (*func)(int argc, char *argv[], const char *usage_str); } subcmd_t; static subcmd_t subcmds[] = { { "list [-l] [-v] [ []]", "list", cmd_list }, { "online ", "online", cmd_online }, { "offline [-f] [-q] ", "offline", cmd_offline }, { "enable ", "enable", cmd_enable }, { "disable [-f] [-q] ", "disable", cmd_disable }, { "poweron ", "poweron", cmd_poweron }, { "poweroff [-f] [-q] ", "poweroff", cmd_poweroff }, { "get -o ", "get", cmd_getpriv }, { "set -o ", "set", cmd_setpriv } }; static subcmd_t hidden_subcmds[] = { { "changestate [-f] [-q] -s ", "changestate", cmd_changestate } }; /* * Define tables of command line options. */ static const struct option common_opts[] = { { "help", no_argument, 0, '?' }, { "version", no_argument, 0, 'V' }, { 0, 0, 0, 0 } }; static const struct option list_opts[] = { { "list-path", no_argument, 0, 'l' }, { "verbose", no_argument, 0, 'v' }, { 0, 0, 0, 0 } }; static const struct option flag_opts[] = { { "force", no_argument, 0, 'f' }, { "query", no_argument, 0, 'q' }, { 0, 0, 0, 0 } }; static const struct option private_opts[] = { { "options", required_argument, 0, 'o' }, { 0, 0, 0, 0 } }; static const struct option changestate_opts[] = { { "force", no_argument, 0, 'f' }, { "query", no_argument, 0, 'q' }, { "state", required_argument, 0, 's' }, { 0, 0, 0, 0 } }; /* * Define exit codes. */ #define EXIT_OK 0 #define EXIT_EINVAL 1 /* invalid arguments */ #define EXIT_ENOENT 2 /* path or connection doesn't exist */ #define EXIT_FAILED 3 /* operation failed */ #define EXIT_UNAVAIL 4 /* service not available */ /* * Global variables. */ static char *prog; static char version[] = "1.0"; extern int errno; /* * main() * * The main routine determines which subcommand is used, * and dispatches control to the corresponding function. */ int main(int argc, char *argv[]) { int i, rv; (void) setlocale(LC_ALL, ""); (void) textdomain(TEXT_DOMAIN); if ((prog = strrchr(argv[0], '/')) == NULL) prog = argv[0]; else prog++; if (argc < 2) { usage(NULL); return (EXIT_EINVAL); } parse_common(argc, argv, NULL); /* Check the list of defined subcommands. */ for (i = 0; i < (sizeof (subcmds) / sizeof (subcmd_t)); i++) { if (strcmp(argv[1], subcmds[i].cmd_str) == 0) { rv = subcmds[i].func(argc - 1, &argv[1], subcmds[i].usage_str); goto finished; } } /* Check the list of hidden subcommands. */ for (i = 0; i < (sizeof (hidden_subcmds) / sizeof (subcmd_t)); i++) { if (strcmp(argv[1], hidden_subcmds[i].cmd_str) == 0) { rv = hidden_subcmds[i].func(argc - 1, &argv[1], hidden_subcmds[i].usage_str); goto finished; } } /* No matching subcommand found. */ (void) fprintf(stderr, gettext("ERROR: %s: unknown subcommand '%s'\n"), prog, argv[1]); usage(NULL); exit(EXIT_EINVAL); finished: /* Determine exit code */ switch (rv) { case 0: break; case EINVAL: return (EXIT_EINVAL); case ENXIO: case ENOENT: return (EXIT_ENOENT); case EBADF: return (EXIT_UNAVAIL); default: return (EXIT_FAILED); } return (EXIT_OK); } /* * cmd_list() * * Subcommand to list hotplug information. */ static int cmd_list(int argc, char *argv[], const char *usage_str) { hp_node_t root; char *path = NULL; char *connection = NULL; boolean_t long_flag = B_FALSE; int flags = 0; int opt; /* Parse command line options */ parse_common(argc, argv, usage_str); while ((opt = getopt_clip(argc, argv, "lv", list_opts, NULL)) != -1) { switch (opt) { case 'l': long_flag = B_TRUE; break; case 'v': flags |= HPINFOUSAGE; break; default: bad_option(opt, optopt, usage_str); break; } } parse_target(argc, argv, &path, &connection, usage_str); /* Default path is "/" */ if (path == NULL) path = "/"; /* Get hotplug information snapshot */ if ((root = hp_init(path, connection, flags)) == NULL) { print_error(errno); return (errno); } /* Display hotplug information */ (void) hp_traverse(root, NULL, long_flag ? list_long_cb : list_cb); /* Discard hotplug information snapshot */ hp_fini(root); return (0); } /* * cmd_online() * * Subcommand to online a hotplug port. */ static int cmd_online(int argc, char *argv[], const char *usage_str) { hp_node_t root; hp_node_t results = NULL; char *path = NULL; char *connection = NULL; int rv; /* Parse command line options */ parse_common(argc, argv, usage_str); parse_target(argc, argv, &path, &connection, usage_str); /* Path and connection are required */ if ((path == NULL) || (connection == NULL)) { (void) fprintf(stderr, gettext("ERROR: too few arguments.\n")); usage(usage_str); return (EINVAL); } /* Get hotplug information snapshot */ if ((root = hp_init(path, connection, 0)) == NULL) { print_error(errno); return (errno); } /* Verify target is a port */ if (hp_type(root) != HP_NODE_PORT) { (void) fprintf(stderr, gettext("ERROR: invalid target (must be a port).\n")); hp_fini(root); return (EINVAL); } /* Do state change */ rv = hp_set_state(root, 0, DDI_HP_CN_STATE_ONLINE, &results); /* Display results */ if (rv == EIO) { (void) fprintf(stderr, gettext("ERROR: failed to attach device " "drivers or other internal errors.\n")); } else if (rv != 0) { print_error(rv); } if (results != NULL) { (void) hp_traverse(results, NULL, error_cb); hp_fini(results); } /* Discard hotplug information snapshot */ hp_fini(root); return (rv); } /* * cmd_offline() * * Subcommand to offline a hotplug port. */ static int cmd_offline(int argc, char *argv[], const char *usage_str) { hp_node_t root; hp_node_t results = NULL; char *path = NULL; char *connection = NULL; int flags = 0; int rv; /* Parse command line options */ parse_common(argc, argv, usage_str); parse_flags(argc, argv, &flags, usage_str); parse_target(argc, argv, &path, &connection, usage_str); /* Path and connection are required */ if ((path == NULL) || (connection == NULL)) { (void) fprintf(stderr, gettext("ERROR: too few arguments.\n")); usage(usage_str); return (EINVAL); } /* Get hotplug information snapshot */ if ((root = hp_init(path, connection, 0)) == NULL) { print_error(errno); return (errno); } /* Verify target is a port */ if (hp_type(root) != HP_NODE_PORT) { (void) fprintf(stderr, gettext("ERROR: invalid target (must be a port).\n")); hp_fini(root); return (EINVAL); } /* Do state change */ rv = hp_set_state(root, flags, DDI_HP_CN_STATE_OFFLINE, &results); /* Display results */ print_error(rv); if (results != NULL) { (void) hp_traverse(results, NULL, error_cb); hp_fini(results); } /* Discard hotplug information snapshot */ hp_fini(root); return (rv); } /* * cmd_enable() * * Subcommand to enable a hotplug connector. */ static int cmd_enable(int argc, char *argv[], const char *usage_str) { hp_node_t root; hp_node_t results = NULL; char *path = NULL; char *connection = NULL; int rv; /* Parse command line options */ parse_common(argc, argv, usage_str); parse_target(argc, argv, &path, &connection, usage_str); /* Path and connection are required */ if ((path == NULL) || (connection == NULL)) { (void) fprintf(stderr, gettext("ERROR: too few arguments.\n")); usage(usage_str); return (EINVAL); } /* Get hotplug information snapshot */ if ((root = hp_init(path, connection, 0)) == NULL) { print_error(errno); return (errno); } /* Verify target is a connector */ if (hp_type(root) != HP_NODE_CONNECTOR) { (void) fprintf(stderr, gettext("ERROR: invalid target (must be a connector).\n")); hp_fini(root); return (EINVAL); } /* Do state change */ rv = hp_set_state(root, 0, DDI_HP_CN_STATE_ENABLED, &results); /* Display results */ print_error(rv); if (results != NULL) { (void) hp_traverse(results, NULL, error_cb); hp_fini(results); } /* Discard hotplug information snapshot */ hp_fini(root); return (rv); } /* * cmd_disable() * * Subcommand to disable a hotplug connector. */ static int cmd_disable(int argc, char *argv[], const char *usage_str) { hp_node_t root; hp_node_t results = NULL; char *path = NULL; char *connection = NULL; int flags = 0; int rv; /* Parse command line options */ parse_common(argc, argv, usage_str); parse_flags(argc, argv, &flags, usage_str); parse_target(argc, argv, &path, &connection, usage_str); /* Path and connection are required */ if ((path == NULL) || (connection == NULL)) { (void) fprintf(stderr, gettext("ERROR: too few arguments.\n")); usage(usage_str); return (EINVAL); } /* Get hotplug information snapshot */ if ((root = hp_init(path, connection, 0)) == NULL) { print_error(errno); return (errno); } /* Verify target is a connector */ if (hp_type(root) != HP_NODE_CONNECTOR) { (void) fprintf(stderr, gettext("ERROR: invalid target (must be a connector).\n")); hp_fini(root); return (EINVAL); } /* * Do nothing unless the connector is in the ENABLED state. * Otherwise this subcommand becomes an alias for 'poweron.' */ if (hp_state(root) != DDI_HP_CN_STATE_ENABLED) { hp_fini(root); return (0); } /* Do state change */ rv = hp_set_state(root, flags, DDI_HP_CN_STATE_POWERED, &results); /* Display results */ print_error(rv); if (results != NULL) { (void) hp_traverse(results, NULL, error_cb); hp_fini(results); } /* Discard hotplug information snapshot */ hp_fini(root); return (rv); } /* * cmd_poweron() * * Subcommand to power on a hotplug connector. */ static int cmd_poweron(int argc, char *argv[], const char *usage_str) { hp_node_t root; hp_node_t results = NULL; char *path = NULL; char *connection = NULL; int rv; /* Parse command line options */ parse_common(argc, argv, usage_str); parse_target(argc, argv, &path, &connection, usage_str); /* Path and connection are required */ if ((path == NULL) || (connection == NULL)) { (void) fprintf(stderr, gettext("ERROR: too few arguments.\n")); usage(usage_str); return (EINVAL); } /* Get hotplug information snapshot */ if ((root = hp_init(path, connection, 0)) == NULL) { print_error(errno); return (errno); } /* Verify target is a connector */ if (hp_type(root) != HP_NODE_CONNECTOR) { (void) fprintf(stderr, gettext("ERROR: invalid target (must be a connector).\n")); hp_fini(root); return (EINVAL); } /* * Do nothing if the connector is already powered. * Otherwise this subcommand becomes an alias for 'disable.' */ if (hp_state(root) >= DDI_HP_CN_STATE_POWERED) { hp_fini(root); return (0); } /* Do state change */ rv = hp_set_state(root, 0, DDI_HP_CN_STATE_POWERED, &results); /* Display results */ print_error(rv); if (results != NULL) { (void) hp_traverse(results, NULL, error_cb); hp_fini(results); } /* Discard hotplug information snapshot */ hp_fini(root); return (rv); } /* * cmd_poweroff() * * Subcommand to power off a hotplug connector. */ static int cmd_poweroff(int argc, char *argv[], const char *usage_str) { hp_node_t root; hp_node_t results = NULL; char *path = NULL; char *connection = NULL; int flags = 0; int rv; /* Parse command line options */ parse_common(argc, argv, usage_str); parse_flags(argc, argv, &flags, usage_str); parse_target(argc, argv, &path, &connection, usage_str); /* Path and connection are required */ if ((path == NULL) || (connection == NULL)) { (void) fprintf(stderr, gettext("ERROR: too few arguments.\n")); usage(usage_str); return (EINVAL); } /* Get hotplug information snapshot */ if ((root = hp_init(path, connection, 0)) == NULL) { print_error(errno); return (errno); } /* Verify target is a connector */ if (hp_type(root) != HP_NODE_CONNECTOR) { (void) fprintf(stderr, gettext("ERROR: invalid target (must be a connector).\n")); hp_fini(root); return (EINVAL); } /* Do state change */ rv = hp_set_state(root, flags, DDI_HP_CN_STATE_PRESENT, &results); /* Display results */ print_error(rv); if (results != NULL) { (void) hp_traverse(results, NULL, error_cb); hp_fini(results); } /* Discard hotplug information snapshot */ hp_fini(root); return (rv); } /* * cmd_getpriv() * * Subcommand to get and display bus private options. */ static int cmd_getpriv(int argc, char *argv[], const char *usage_str) { hp_node_t root; char *path = NULL; char *connection = NULL; char *options = NULL; char *results = NULL; int rv; /* Parse command line options */ parse_common(argc, argv, usage_str); parse_options(argc, argv, &options, usage_str); parse_target(argc, argv, &path, &connection, usage_str); /* Options, path, and connection are all required */ if ((options == NULL) || (path == NULL) || (connection == NULL)) { (void) fprintf(stderr, gettext("ERROR: too few arguments.\n")); usage(usage_str); return (EINVAL); } /* Get hotplug information snapshot */ if ((root = hp_init(path, connection, 0)) == NULL) { print_error(errno); return (errno); } /* Verify target is a connector */ if (hp_type(root) != HP_NODE_CONNECTOR) { (void) fprintf(stderr, gettext("ERROR: invalid target (must be a connector).\n")); hp_fini(root); return (EINVAL); } /* Do the operation */ rv = hp_get_private(root, options, &results); /* Display results */ if (rv == ENOTSUP) { (void) fprintf(stderr, gettext("ERROR: unsupported property name or value.\n")); (void) fprintf(stderr, gettext("(Properties may depend upon connector state.)\n")); } else if (rv != 0) { print_error(rv); } if (results != NULL) { print_options(results); free(results); } /* Discard hotplug information snapshot */ hp_fini(root); return (rv); } /* * cmd_setpriv() * * Subcommand to set bus private options. */ static int cmd_setpriv(int argc, char *argv[], const char *usage_str) { hp_node_t root; char *path = NULL; char *connection = NULL; char *options = NULL; char *results = NULL; int rv; /* Parse command line options */ parse_common(argc, argv, usage_str); parse_options(argc, argv, &options, usage_str); parse_target(argc, argv, &path, &connection, usage_str); /* Options, path, and connection are all required */ if ((options == NULL) || (path == NULL) || (connection == NULL)) { (void) fprintf(stderr, gettext("ERROR: too few arguments.\n")); usage(usage_str); return (EINVAL); } /* Get hotplug information snapshot */ if ((root = hp_init(path, connection, 0)) == NULL) { print_error(errno); return (errno); } /* Verify target is a connector */ if (hp_type(root) != HP_NODE_CONNECTOR) { (void) fprintf(stderr, gettext("ERROR: invalid target (must be a connector).\n")); hp_fini(root); return (EINVAL); } /* Do the operation */ rv = hp_set_private(root, options, &results); /* Display results */ if (rv == ENOTSUP) { (void) fprintf(stderr, gettext("ERROR: unsupported property name or value.\n")); (void) fprintf(stderr, gettext("(Properties may depend upon connector state.)\n")); } else if (rv != 0) { print_error(rv); } if (results != NULL) { print_options(results); free(results); } /* Discard hotplug information snapshot */ hp_fini(root); return (rv); } /* * cmd_changestate() * * Subcommand to initiate a state change operation. This is * a hidden subcommand to directly set a connector or port to * a specific target state. */ static int cmd_changestate(int argc, char *argv[], const char *usage_str) { hp_node_t root; hp_node_t results = NULL; char *path = NULL; char *connection = NULL; int state = -1; int flags = 0; int opt, rv; /* Parse command line options */ parse_common(argc, argv, usage_str); while ((opt = getopt_clip(argc, argv, "fqs:", changestate_opts, NULL)) != -1) { switch (opt) { case 'f': flags |= HPFORCE; break; case 'q': flags |= HPQUERY; break; case 's': if ((state = state_atoi(optarg)) == -1) { (void) printf("ERROR: invalid target state\n"); return (EINVAL); } break; default: bad_option(opt, optopt, usage_str); break; } } parse_target(argc, argv, &path, &connection, usage_str); /* State, path, and connection are all required */ if ((state == -1) || (path == NULL) || (connection == NULL)) { (void) fprintf(stderr, gettext("ERROR: too few arguments.\n")); usage(usage_str); return (EINVAL); } /* Check that target state is valid */ if (valid_target(state) == 0) { (void) fprintf(stderr, gettext("ERROR: invalid target state\n")); return (EINVAL); } /* Get hotplug information snapshot */ if ((root = hp_init(path, connection, 0)) == NULL) { print_error(errno); return (errno); } /* Initiate state change operation on root of snapshot */ rv = hp_set_state(root, flags, state, &results); /* Display results */ print_error(rv); if (results) { (void) hp_traverse(results, NULL, error_cb); hp_fini(results); } /* Discard hotplug information snapshot */ hp_fini(root); return (rv); } /* * parse_common() * * Parse command line options that are common to the * entire program, and to each of its subcommands. */ static void parse_common(int argc, char *argv[], const char *usage_str) { int opt; extern int opterr; extern int optind; /* Turn off error reporting */ opterr = 0; while ((opt = getopt_clip(argc, argv, "?V", common_opts, NULL)) != -1) { switch (opt) { case '?': if (optopt == '?') { usage(usage_str); exit(0); } break; case 'V': (void) printf(gettext("%s: Version %s\n"), prog, version); exit(0); default: break; } } /* Reset option index */ optind = 1; } /* * parse_flags() * * Parse command line flags common to all downward state * change operations (offline, disable, poweoff). */ static void parse_flags(int argc, char *argv[], int *flagsp, const char *usage_str) { int opt; int flags = 0; while ((opt = getopt_clip(argc, argv, "fq", flag_opts, NULL)) != -1) { switch (opt) { case 'f': flags |= HPFORCE; break; case 'q': flags |= HPQUERY; break; default: bad_option(opt, optopt, usage_str); break; } } *flagsp = flags; } /* * parse_options() * * Parse command line options common to the bus private set and * get subcommands. */ static void parse_options(int argc, char *argv[], char **optionsp, const char *usage_str) { int opt; while ((opt = getopt_clip(argc, argv, "o:", private_opts, NULL)) != -1) { switch (opt) { case 'o': *optionsp = optarg; break; default: bad_option(opt, optopt, usage_str); break; } } } /* * parse_target() * * Parse the target path and connection name from the command line. */ static void parse_target(int argc, char *argv[], char **pathp, char **connectionp, const char *usage_str) { extern int optind; if (optind < argc) *pathp = argv[optind++]; if (optind < argc) *connectionp = argv[optind++]; if (optind < argc) { (void) fprintf(stderr, gettext("ERROR: too many arguments.\n")); usage(usage_str); exit(EINVAL); } } /* * bad_option() * * Routine to handle bad command line options. */ static void bad_option(int opt, int optopt, const char *usage_str) { switch (opt) { case ':': (void) fprintf(stderr, gettext("ERROR: option '%c' requires an argument.\n"), optopt); break; default: if (optopt == '?') { usage(usage_str); exit(EXIT_OK); } (void) fprintf(stderr, gettext("ERROR: unrecognized option '%c'.\n"), optopt); break; } usage(usage_str); exit(EXIT_EINVAL); } /* * usage() * * Display general usage of the command. Including * the usage synopsis of each defined subcommand. */ static void usage(const char *usage_str) { int i; if (usage_str != NULL) { (void) fprintf(stderr, gettext("Usage: %s %s\n\n"), prog, usage_str); return; } (void) fprintf(stderr, gettext("Usage: %s []\n\n"), prog); (void) fprintf(stderr, gettext("Subcommands:\n\n")); for (i = 0; i < (sizeof (subcmds) / sizeof (subcmd_t)); i++) (void) fprintf(stderr, " %s\n\n", subcmds[i].usage_str); } /* * list_cb() * * Callback function for hp_traverse(), to display nodes * of a hotplug information snapshot. (Short version.) */ /*ARGSUSED*/ static int list_cb(hp_node_t node, void *arg) { hp_node_t parent; /* Indent */ for (parent = hp_parent(node); parent; parent = hp_parent(parent)) if (hp_type(parent) == HP_NODE_DEVICE) (void) printf(" "); switch (hp_type(node)) { case HP_NODE_DEVICE: (void) printf("%s\n", hp_name(node)); break; case HP_NODE_CONNECTOR: (void) printf("[%s]", hp_name(node)); (void) printf(" (%s)", state_itoa(hp_state(node))); (void) printf("\n"); break; case HP_NODE_PORT: (void) printf("<%s>", hp_name(node)); (void) printf(" (%s)", state_itoa(hp_state(node))); (void) printf("\n"); break; case HP_NODE_USAGE: (void) printf("{ %s }\n", hp_usage(node)); break; } return (HP_WALK_CONTINUE); } /* * list_long_cb() * * Callback function for hp_traverse(), to display nodes * of a hotplug information snapshot. (Long version.) */ /*ARGSUSED*/ static int list_long_cb(hp_node_t node, void *arg) { char path[MAXPATHLEN]; char connection[MAXPATHLEN]; if (hp_type(node) != HP_NODE_USAGE) { if (hp_path(node, path, connection) != 0) return (HP_WALK_CONTINUE); (void) printf("%s", path); } switch (hp_type(node)) { case HP_NODE_CONNECTOR: (void) printf(" [%s]", connection); (void) printf(" (%s)", state_itoa(hp_state(node))); break; case HP_NODE_PORT: (void) printf(" <%s>", connection); (void) printf(" (%s)", state_itoa(hp_state(node))); break; case HP_NODE_USAGE: (void) printf(" { %s }", hp_usage(node)); break; } (void) printf("\n"); return (HP_WALK_CONTINUE); } /* * error_cb() * * Callback function for hp_traverse(), to display * error results from a state change operation. */ /*ARGSUSED*/ static int error_cb(hp_node_t node, void *arg) { hp_node_t child; char *usage_str; static char path[MAXPATHLEN]; static char connection[MAXPATHLEN]; if (((child = hp_child(node)) != NULL) && (hp_type(child) == HP_NODE_USAGE)) { if (hp_path(node, path, connection) == 0) (void) printf("%s:\n", path); return (HP_WALK_CONTINUE); } if ((hp_type(node) == HP_NODE_USAGE) && ((usage_str = hp_usage(node)) != NULL)) (void) printf(" { %s }\n", usage_str); return (HP_WALK_CONTINUE); } /* * print_options() * * Parse and display bus private options. The options are * formatted as a string which conforms to the getsubopt(3C) * format. This routine only splits the string elements as * separated by commas, and displays each portion on its own * separate line of output. */ static void print_options(const char *options) { char *buf, *curr, *next; size_t len; /* Do nothing if options string is empty */ if ((len = strlen(options)) == 0) return; /* To avoid modifying the input string, make a copy on the stack */ if ((buf = (char *)alloca(len + 1)) == NULL) { (void) printf("%s\n", options); return; } (void) strlcpy(buf, options, len + 1); /* Iterate through each comma-separated name/value pair */ curr = buf; do { if ((next = strchr(curr, ',')) != NULL) { *next = '\0'; next++; } (void) printf("%s\n", curr); } while ((curr = next) != NULL); } /* * print_error() * * Common routine to print error numbers in an appropriate way. * Prints nothing if error code is 0. */ static void print_error(int error) { switch (error) { case 0: /* No error */ return; case EACCES: (void) fprintf(stderr, gettext("ERROR: operation not authorized.\n")); break; case EBADF: (void) fprintf(stderr, gettext("ERROR: hotplug service is not available.\n")); break; case EBUSY: (void) fprintf(stderr, gettext("ERROR: devices or resources are busy.\n")); break; case EEXIST: (void) fprintf(stderr, gettext("ERROR: resource already exists.\n")); break; case EFAULT: (void) fprintf(stderr, gettext("ERROR: internal failure in hotplug service.\n")); break; case EINVAL: (void) fprintf(stderr, gettext("ERROR: invalid arguments.\n")); break; case ENOENT: (void) fprintf(stderr, gettext("ERROR: there are no connections to display.\n")); (void) fprintf(stderr, gettext("(See hotplug(8) for more information.)\n")); break; case ENXIO: (void) fprintf(stderr, gettext("ERROR: no such path or connection.\n")); break; case ENOMEM: (void) fprintf(stderr, gettext("ERROR: not enough memory.\n")); break; case ENOTSUP: (void) fprintf(stderr, gettext("ERROR: operation not supported.\n")); break; case EIO: (void) fprintf(stderr, gettext("ERROR: hardware or driver specific failure.\n")); break; default: (void) fprintf(stderr, gettext("ERROR: operation failed: %s\n"), strerror(error)); break; } } /* * state_atoi() * * Convert a hotplug state from a string to an integer. */ static int state_atoi(char *state) { int i; for (i = 0; hpstates[i].state_str != NULL; i++) if (strcasecmp(state, hpstates[i].state_str) == 0) return (hpstates[i].state); return (-1); } /* * state_itoa() * * Convert a hotplug state from an integer to a string. */ static char * state_itoa(int state) { static char unknown[] = "UNKNOWN"; int i; for (i = 0; hpstates[i].state_str != NULL; i++) if (state == hpstates[i].state) return (hpstates[i].state_str); return (unknown); } /* * valid_target() * * Check if a state is a valid target for a changestate command. */ static short valid_target(int state) { int i; for (i = 0; hpstates[i].state_str != NULL; i++) if (state == hpstates[i].state) return (hpstates[i].valid_target); return (0); }