xref: /illumos-gate/usr/src/cmd/hotplug/hotplug.c (revision bbf21555)
126947304SEvan Yan /*
226947304SEvan Yan  * CDDL HEADER START
326947304SEvan Yan  *
426947304SEvan Yan  * The contents of this file are subject to the terms of the
526947304SEvan Yan  * Common Development and Distribution License (the "License").
626947304SEvan Yan  * You may not use this file except in compliance with the License.
726947304SEvan Yan  *
826947304SEvan Yan  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
926947304SEvan Yan  * or http://www.opensolaris.org/os/licensing.
1026947304SEvan Yan  * See the License for the specific language governing permissions
1126947304SEvan Yan  * and limitations under the License.
1226947304SEvan Yan  *
1326947304SEvan Yan  * When distributing Covered Code, include this CDDL HEADER in each
1426947304SEvan Yan  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1526947304SEvan Yan  * If applicable, add the following below this CDDL HEADER, with the
1626947304SEvan Yan  * fields enclosed by brackets "[]" replaced with your own identifying
1726947304SEvan Yan  * information: Portions Copyright [yyyy] [name of copyright owner]
1826947304SEvan Yan  *
1926947304SEvan Yan  * CDDL HEADER END
2026947304SEvan Yan  */
2126947304SEvan Yan /*
2226947304SEvan Yan  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
2326947304SEvan Yan  * Use is subject to license terms.
2426947304SEvan Yan  */
2526947304SEvan Yan 
2626947304SEvan Yan #include <stdio.h>
2726947304SEvan Yan #include <stdlib.h>
2826947304SEvan Yan #include <string.h>
2926947304SEvan Yan #include <locale.h>
3026947304SEvan Yan #include <libintl.h>
3126947304SEvan Yan #include <alloca.h>
3226947304SEvan Yan #include <getopt.h>
3326947304SEvan Yan #include <libhotplug.h>
3426947304SEvan Yan #include <sys/types.h>
3526947304SEvan Yan #include <sys/sunddi.h>
3626947304SEvan Yan #include <sys/ddi_hp.h>
3726947304SEvan Yan 
3826947304SEvan Yan #if !defined(TEXT_DOMAIN)		/* should be defined by cc -D */
3926947304SEvan Yan #define	TEXT_DOMAIN	"SYS_TEST"	/* Use this only if it wasn't */
4026947304SEvan Yan #endif
4126947304SEvan Yan 
4226947304SEvan Yan /*
4326947304SEvan Yan  * Function prototypes.
4426947304SEvan Yan  */
4526947304SEvan Yan static int	cmd_list(int, char **, const char *);
4626947304SEvan Yan static int	cmd_online(int, char **, const char *);
4726947304SEvan Yan static int	cmd_offline(int, char **, const char *);
4826947304SEvan Yan static int	cmd_enable(int, char **, const char *);
4926947304SEvan Yan static int	cmd_disable(int, char **, const char *);
5026947304SEvan Yan static int	cmd_poweron(int, char **, const char *);
5126947304SEvan Yan static int	cmd_poweroff(int, char **, const char *);
5226947304SEvan Yan static int	cmd_getpriv(int, char **, const char *);
5326947304SEvan Yan static int	cmd_setpriv(int, char **, const char *);
5426947304SEvan Yan static int	cmd_changestate(int, char **, const char *);
5526947304SEvan Yan static void	parse_common(int, char **, const char *);
5626947304SEvan Yan static void	parse_flags(int, char **, int *, const char *);
5726947304SEvan Yan static void	parse_target(int, char **, char **, char **, const char *);
5826947304SEvan Yan static void	parse_options(int, char **, char **, const char *);
5926947304SEvan Yan static void	bad_option(int, int, const char *);
6026947304SEvan Yan static void	usage(const char *);
6126947304SEvan Yan static int	list_cb(hp_node_t, void *);
6226947304SEvan Yan static int	list_long_cb(hp_node_t, void *);
6326947304SEvan Yan static int	error_cb(hp_node_t, void *);
6426947304SEvan Yan static void	print_options(const char *);
6526947304SEvan Yan static void	print_error(int);
6626947304SEvan Yan static int	state_atoi(char *);
6726947304SEvan Yan static char	*state_itoa(int);
6826947304SEvan Yan static short	valid_target(int);
6926947304SEvan Yan 
7026947304SEvan Yan /*
7126947304SEvan Yan  * Define a conversion table for hotplug states.
7226947304SEvan Yan  */
7326947304SEvan Yan typedef struct {
7426947304SEvan Yan 	int	state;
7526947304SEvan Yan 	char	*state_str;
7626947304SEvan Yan 	short	valid_target;
7726947304SEvan Yan } hpstate_t;
7826947304SEvan Yan 
7926947304SEvan Yan static hpstate_t hpstates[] = {
8026947304SEvan Yan 	{ DDI_HP_CN_STATE_EMPTY,	"EMPTY",	0 },
8126947304SEvan Yan 	{ DDI_HP_CN_STATE_PRESENT,	"PRESENT",	1 },
8226947304SEvan Yan 	{ DDI_HP_CN_STATE_POWERED,	"POWERED",	1 },
8326947304SEvan Yan 	{ DDI_HP_CN_STATE_ENABLED,	"ENABLED",	1 },
8426947304SEvan Yan 	{ DDI_HP_CN_STATE_PORT_EMPTY,	"PORT-EMPTY",	0 },
8526947304SEvan Yan 	{ DDI_HP_CN_STATE_PORT_PRESENT,	"PORT-PRESENT",	1 },
8626947304SEvan Yan 	{ DDI_HP_CN_STATE_OFFLINE,	"OFFLINE",	1 },
8726947304SEvan Yan 	{ DDI_HP_CN_STATE_ATTACHED,	"ATTACHED",	0 },
8826947304SEvan Yan 	{ DDI_HP_CN_STATE_MAINTENANCE,	"MAINTENANCE",	0 },
8926947304SEvan Yan 	{ DDI_HP_CN_STATE_ONLINE,	"ONLINE",	1 },
9026947304SEvan Yan 	{ 0, 0, 0 }
9126947304SEvan Yan };
9226947304SEvan Yan 
9326947304SEvan Yan /*
9426947304SEvan Yan  * Define tables of supported subcommands.
9526947304SEvan Yan  */
9626947304SEvan Yan typedef struct {
9726947304SEvan Yan 	char		*usage_str;
9826947304SEvan Yan 	char		*cmd_str;
9926947304SEvan Yan 	int		(*func)(int argc, char *argv[], const char *usage_str);
10026947304SEvan Yan } subcmd_t;
10126947304SEvan Yan 
10226947304SEvan Yan static subcmd_t	subcmds[] = {
10326947304SEvan Yan 	{ "list       [-l] [-v] [<path> [<connection>]]", "list", cmd_list },
10426947304SEvan Yan 	{ "online     <path> <port>", "online", cmd_online },
10526947304SEvan Yan 	{ "offline    [-f] [-q] <path> <port>", "offline", cmd_offline },
10626947304SEvan Yan 	{ "enable     <path> <connector>", "enable", cmd_enable },
10726947304SEvan Yan 	{ "disable    [-f] [-q] <path> <connector>", "disable", cmd_disable },
10826947304SEvan Yan 	{ "poweron    <path> <connector>", "poweron", cmd_poweron },
10926947304SEvan Yan 	{ "poweroff   [-f] [-q] <path> <connector>", "poweroff", cmd_poweroff },
11026947304SEvan Yan 	{ "get        -o <options> <path> <connector>", "get", cmd_getpriv },
11126947304SEvan Yan 	{ "set        -o <options> <path> <connector>", "set", cmd_setpriv }
11226947304SEvan Yan };
11326947304SEvan Yan 
11426947304SEvan Yan static subcmd_t hidden_subcmds[] = {
11526947304SEvan Yan 	{ "changestate  [-f] [-q] -s <state> <path> <connection>",
11626947304SEvan Yan 	    "changestate", cmd_changestate }
11726947304SEvan Yan };
11826947304SEvan Yan 
11926947304SEvan Yan /*
12026947304SEvan Yan  * Define tables of command line options.
12126947304SEvan Yan  */
12226947304SEvan Yan static const struct option common_opts[] = {
12326947304SEvan Yan 	{ "help",	no_argument,		0, '?' },
12426947304SEvan Yan 	{ "version",	no_argument,		0, 'V' },
12526947304SEvan Yan 	{ 0, 0, 0, 0 }
12626947304SEvan Yan };
12726947304SEvan Yan 
12826947304SEvan Yan static const struct option list_opts[] = {
12926947304SEvan Yan 	{ "list-path",	no_argument,		0, 'l' },
13026947304SEvan Yan 	{ "verbose",	no_argument,		0, 'v' },
13126947304SEvan Yan 	{ 0, 0,	0, 0 }
13226947304SEvan Yan };
13326947304SEvan Yan 
13426947304SEvan Yan static const struct option flag_opts[] = {
13526947304SEvan Yan 	{ "force",	no_argument,		0, 'f' },
13626947304SEvan Yan 	{ "query",	no_argument,		0, 'q' },
13726947304SEvan Yan 	{ 0, 0,	0, 0 }
13826947304SEvan Yan };
13926947304SEvan Yan 
14026947304SEvan Yan static const struct option private_opts[] = {
14126947304SEvan Yan 	{ "options",	required_argument,	0, 'o' },
14226947304SEvan Yan 	{ 0, 0,	0, 0 }
14326947304SEvan Yan };
14426947304SEvan Yan 
14526947304SEvan Yan static const struct option changestate_opts[] = {
14626947304SEvan Yan 	{ "force",	no_argument,		0, 'f' },
14726947304SEvan Yan 	{ "query",	no_argument,		0, 'q' },
14826947304SEvan Yan 	{ "state",	required_argument,	0, 's' },
14926947304SEvan Yan 	{ 0, 0,	0, 0 }
15026947304SEvan Yan };
15126947304SEvan Yan 
15226947304SEvan Yan /*
15326947304SEvan Yan  * Define exit codes.
15426947304SEvan Yan  */
15526947304SEvan Yan #define	EXIT_OK		0
15626947304SEvan Yan #define	EXIT_EINVAL	1	/* invalid arguments */
15726947304SEvan Yan #define	EXIT_ENOENT	2	/* path or connection doesn't exist */
15826947304SEvan Yan #define	EXIT_FAILED	3	/* operation failed */
15926947304SEvan Yan #define	EXIT_UNAVAIL	4	/* service not available */
16026947304SEvan Yan 
16126947304SEvan Yan /*
16226947304SEvan Yan  * Global variables.
16326947304SEvan Yan  */
16426947304SEvan Yan static char 	*prog;
16526947304SEvan Yan static char	version[] = "1.0";
16626947304SEvan Yan extern int	errno;
16726947304SEvan Yan 
16826947304SEvan Yan /*
16926947304SEvan Yan  * main()
17026947304SEvan Yan  *
17126947304SEvan Yan  *	The main routine determines which subcommand is used,
17226947304SEvan Yan  *	and dispatches control to the corresponding function.
17326947304SEvan Yan  */
17426947304SEvan Yan int
main(int argc,char * argv[])17526947304SEvan Yan main(int argc, char *argv[])
17626947304SEvan Yan {
17726947304SEvan Yan 	int 		i, rv;
17826947304SEvan Yan 
17926947304SEvan Yan 	(void) setlocale(LC_ALL, "");
18026947304SEvan Yan 	(void) textdomain(TEXT_DOMAIN);
18126947304SEvan Yan 
18226947304SEvan Yan 	if ((prog = strrchr(argv[0], '/')) == NULL)
18326947304SEvan Yan 		prog = argv[0];
18426947304SEvan Yan 	else
18526947304SEvan Yan 		prog++;
18626947304SEvan Yan 
18726947304SEvan Yan 	if (argc < 2) {
18826947304SEvan Yan 		usage(NULL);
18926947304SEvan Yan 		return (EXIT_EINVAL);
19026947304SEvan Yan 	}
19126947304SEvan Yan 
19226947304SEvan Yan 	parse_common(argc, argv, NULL);
19326947304SEvan Yan 
19426947304SEvan Yan 	/* Check the list of defined subcommands. */
19526947304SEvan Yan 	for (i = 0; i < (sizeof (subcmds) / sizeof (subcmd_t)); i++) {
19626947304SEvan Yan 		if (strcmp(argv[1], subcmds[i].cmd_str) == 0) {
19726947304SEvan Yan 			rv = subcmds[i].func(argc - 1, &argv[1],
19826947304SEvan Yan 			    subcmds[i].usage_str);
19926947304SEvan Yan 			goto finished;
20026947304SEvan Yan 		}
20126947304SEvan Yan 	}
20226947304SEvan Yan 
20326947304SEvan Yan 	/* Check the list of hidden subcommands. */
20426947304SEvan Yan 	for (i = 0; i < (sizeof (hidden_subcmds) / sizeof (subcmd_t)); i++) {
20526947304SEvan Yan 		if (strcmp(argv[1], hidden_subcmds[i].cmd_str) == 0) {
20626947304SEvan Yan 			rv = hidden_subcmds[i].func(argc - 1, &argv[1],
20726947304SEvan Yan 			    hidden_subcmds[i].usage_str);
20826947304SEvan Yan 			goto finished;
20926947304SEvan Yan 		}
21026947304SEvan Yan 	}
21126947304SEvan Yan 
21226947304SEvan Yan 	/* No matching subcommand found. */
21326947304SEvan Yan 	(void) fprintf(stderr, gettext("ERROR: %s: unknown subcommand '%s'\n"),
21426947304SEvan Yan 	    prog, argv[1]);
21526947304SEvan Yan 	usage(NULL);
21626947304SEvan Yan 	exit(EXIT_EINVAL);
21726947304SEvan Yan 
21826947304SEvan Yan finished:
21926947304SEvan Yan 	/* Determine exit code */
22026947304SEvan Yan 	switch (rv) {
22126947304SEvan Yan 	case 0:
22226947304SEvan Yan 		break;
22326947304SEvan Yan 	case EINVAL:
22426947304SEvan Yan 		return (EXIT_EINVAL);
22526947304SEvan Yan 	case ENXIO:
22626947304SEvan Yan 	case ENOENT:
22726947304SEvan Yan 		return (EXIT_ENOENT);
22826947304SEvan Yan 	case EBADF:
22926947304SEvan Yan 		return (EXIT_UNAVAIL);
23026947304SEvan Yan 	default:
23126947304SEvan Yan 		return (EXIT_FAILED);
23226947304SEvan Yan 	}
23326947304SEvan Yan 
23426947304SEvan Yan 	return (EXIT_OK);
23526947304SEvan Yan }
23626947304SEvan Yan 
23726947304SEvan Yan /*
23826947304SEvan Yan  * cmd_list()
23926947304SEvan Yan  *
24026947304SEvan Yan  *	Subcommand to list hotplug information.
24126947304SEvan Yan  */
24226947304SEvan Yan static int
cmd_list(int argc,char * argv[],const char * usage_str)24326947304SEvan Yan cmd_list(int argc, char *argv[], const char *usage_str)
24426947304SEvan Yan {
24526947304SEvan Yan 	hp_node_t	root;
24626947304SEvan Yan 	char		*path = NULL;
24726947304SEvan Yan 	char		*connection = NULL;
24826947304SEvan Yan 	boolean_t	long_flag = B_FALSE;
24926947304SEvan Yan 	int		flags = 0;
25026947304SEvan Yan 	int		opt;
25126947304SEvan Yan 
25226947304SEvan Yan 	/* Parse command line options */
25326947304SEvan Yan 	parse_common(argc, argv, usage_str);
25426947304SEvan Yan 	while ((opt = getopt_clip(argc, argv, "lv", list_opts, NULL)) != -1) {
25526947304SEvan Yan 		switch (opt) {
25626947304SEvan Yan 		case 'l':
25726947304SEvan Yan 			long_flag = B_TRUE;
25826947304SEvan Yan 			break;
25926947304SEvan Yan 		case 'v':
26026947304SEvan Yan 			flags |= HPINFOUSAGE;
26126947304SEvan Yan 			break;
26226947304SEvan Yan 		default:
26326947304SEvan Yan 			bad_option(opt, optopt, usage_str);
26426947304SEvan Yan 			break;
26526947304SEvan Yan 		}
26626947304SEvan Yan 	}
26726947304SEvan Yan 	parse_target(argc, argv, &path, &connection, usage_str);
26826947304SEvan Yan 
26926947304SEvan Yan 	/* Default path is "/" */
27026947304SEvan Yan 	if (path == NULL)
27126947304SEvan Yan 		path = "/";
27226947304SEvan Yan 
27326947304SEvan Yan 	/* Get hotplug information snapshot */
27426947304SEvan Yan 	if ((root = hp_init(path, connection, flags)) == NULL) {
27526947304SEvan Yan 		print_error(errno);
27626947304SEvan Yan 		return (errno);
27726947304SEvan Yan 	}
27826947304SEvan Yan 
27926947304SEvan Yan 	/* Display hotplug information */
28026947304SEvan Yan 	(void) hp_traverse(root, NULL, long_flag ? list_long_cb : list_cb);
28126947304SEvan Yan 
28226947304SEvan Yan 	/* Discard hotplug information snapshot */
28326947304SEvan Yan 	hp_fini(root);
28426947304SEvan Yan 
28526947304SEvan Yan 	return (0);
28626947304SEvan Yan }
28726947304SEvan Yan 
28826947304SEvan Yan /*
28926947304SEvan Yan  * cmd_online()
29026947304SEvan Yan  *
29126947304SEvan Yan  *	Subcommand to online a hotplug port.
29226947304SEvan Yan  */
29326947304SEvan Yan static int
cmd_online(int argc,char * argv[],const char * usage_str)29426947304SEvan Yan cmd_online(int argc, char *argv[], const char *usage_str)
29526947304SEvan Yan {
29626947304SEvan Yan 	hp_node_t	root;
29726947304SEvan Yan 	hp_node_t	results = NULL;
29826947304SEvan Yan 	char		*path = NULL;
29926947304SEvan Yan 	char		*connection = NULL;
30026947304SEvan Yan 	int		rv;
30126947304SEvan Yan 
30226947304SEvan Yan 	/* Parse command line options */
30326947304SEvan Yan 	parse_common(argc, argv, usage_str);
30426947304SEvan Yan 	parse_target(argc, argv, &path, &connection, usage_str);
30526947304SEvan Yan 
30626947304SEvan Yan 	/* Path and connection are required */
30726947304SEvan Yan 	if ((path == NULL) || (connection == NULL)) {
30826947304SEvan Yan 		(void) fprintf(stderr, gettext("ERROR: too few arguments.\n"));
30926947304SEvan Yan 		usage(usage_str);
31026947304SEvan Yan 		return (EINVAL);
31126947304SEvan Yan 	}
31226947304SEvan Yan 
31326947304SEvan Yan 	/* Get hotplug information snapshot */
31426947304SEvan Yan 	if ((root = hp_init(path, connection, 0)) == NULL) {
31526947304SEvan Yan 		print_error(errno);
31626947304SEvan Yan 		return (errno);
31726947304SEvan Yan 	}
31826947304SEvan Yan 
31926947304SEvan Yan 	/* Verify target is a port */
32026947304SEvan Yan 	if (hp_type(root) != HP_NODE_PORT) {
32126947304SEvan Yan 		(void) fprintf(stderr,
32226947304SEvan Yan 		    gettext("ERROR: invalid target (must be a port).\n"));
32326947304SEvan Yan 		hp_fini(root);
32426947304SEvan Yan 		return (EINVAL);
32526947304SEvan Yan 	}
32626947304SEvan Yan 
32726947304SEvan Yan 	/* Do state change */
32826947304SEvan Yan 	rv = hp_set_state(root, 0, DDI_HP_CN_STATE_ONLINE, &results);
32926947304SEvan Yan 
33026947304SEvan Yan 	/* Display results */
33126947304SEvan Yan 	if (rv == EIO) {
33226947304SEvan Yan 		(void) fprintf(stderr, gettext("ERROR: failed to attach device "
33326947304SEvan Yan 		    "drivers or other internal errors.\n"));
33426947304SEvan Yan 	} else if (rv != 0) {
33526947304SEvan Yan 		print_error(rv);
33626947304SEvan Yan 	}
33726947304SEvan Yan 	if (results != NULL) {
33826947304SEvan Yan 		(void) hp_traverse(results, NULL, error_cb);
33926947304SEvan Yan 		hp_fini(results);
34026947304SEvan Yan 	}
34126947304SEvan Yan 
34226947304SEvan Yan 	/* Discard hotplug information snapshot */
34326947304SEvan Yan 	hp_fini(root);
34426947304SEvan Yan 
34526947304SEvan Yan 	return (rv);
34626947304SEvan Yan }
34726947304SEvan Yan 
34826947304SEvan Yan /*
34926947304SEvan Yan  * cmd_offline()
35026947304SEvan Yan  *
35126947304SEvan Yan  *	Subcommand to offline a hotplug port.
35226947304SEvan Yan  */
35326947304SEvan Yan static int
cmd_offline(int argc,char * argv[],const char * usage_str)35426947304SEvan Yan cmd_offline(int argc, char *argv[], const char *usage_str)
35526947304SEvan Yan {
35626947304SEvan Yan 	hp_node_t	root;
35726947304SEvan Yan 	hp_node_t	results = NULL;
35826947304SEvan Yan 	char		*path = NULL;
35926947304SEvan Yan 	char		*connection = NULL;
36026947304SEvan Yan 	int		flags = 0;
36126947304SEvan Yan 	int		rv;
36226947304SEvan Yan 
36326947304SEvan Yan 	/* Parse command line options */
36426947304SEvan Yan 	parse_common(argc, argv, usage_str);
36526947304SEvan Yan 	parse_flags(argc, argv, &flags, usage_str);
36626947304SEvan Yan 	parse_target(argc, argv, &path, &connection, usage_str);
36726947304SEvan Yan 
36826947304SEvan Yan 	/* Path and connection are required */
36926947304SEvan Yan 	if ((path == NULL) || (connection == NULL)) {
37026947304SEvan Yan 		(void) fprintf(stderr, gettext("ERROR: too few arguments.\n"));
37126947304SEvan Yan 		usage(usage_str);
37226947304SEvan Yan 		return (EINVAL);
37326947304SEvan Yan 	}
37426947304SEvan Yan 
37526947304SEvan Yan 	/* Get hotplug information snapshot */
37626947304SEvan Yan 	if ((root = hp_init(path, connection, 0)) == NULL) {
37726947304SEvan Yan 		print_error(errno);
37826947304SEvan Yan 		return (errno);
37926947304SEvan Yan 	}
38026947304SEvan Yan 
38126947304SEvan Yan 	/* Verify target is a port */
38226947304SEvan Yan 	if (hp_type(root) != HP_NODE_PORT) {
38326947304SEvan Yan 		(void) fprintf(stderr,
38426947304SEvan Yan 		    gettext("ERROR: invalid target (must be a port).\n"));
38526947304SEvan Yan 		hp_fini(root);
38626947304SEvan Yan 		return (EINVAL);
38726947304SEvan Yan 	}
38826947304SEvan Yan 
38926947304SEvan Yan 	/* Do state change */
39026947304SEvan Yan 	rv = hp_set_state(root, flags, DDI_HP_CN_STATE_OFFLINE, &results);
39126947304SEvan Yan 
39226947304SEvan Yan 	/* Display results */
39326947304SEvan Yan 	print_error(rv);
39426947304SEvan Yan 	if (results != NULL) {
39526947304SEvan Yan 		(void) hp_traverse(results, NULL, error_cb);
39626947304SEvan Yan 		hp_fini(results);
39726947304SEvan Yan 	}
39826947304SEvan Yan 
39926947304SEvan Yan 	/* Discard hotplug information snapshot */
40026947304SEvan Yan 	hp_fini(root);
40126947304SEvan Yan 
40226947304SEvan Yan 	return (rv);
40326947304SEvan Yan }
40426947304SEvan Yan 
40526947304SEvan Yan /*
40626947304SEvan Yan  * cmd_enable()
40726947304SEvan Yan  *
40826947304SEvan Yan  *	Subcommand to enable a hotplug connector.
40926947304SEvan Yan  */
41026947304SEvan Yan static int
cmd_enable(int argc,char * argv[],const char * usage_str)41126947304SEvan Yan cmd_enable(int argc, char *argv[], const char *usage_str)
41226947304SEvan Yan {
41326947304SEvan Yan 	hp_node_t	root;
41426947304SEvan Yan 	hp_node_t	results = NULL;
41526947304SEvan Yan 	char		*path = NULL;
41626947304SEvan Yan 	char		*connection = NULL;
41726947304SEvan Yan 	int		rv;
41826947304SEvan Yan 
41926947304SEvan Yan 	/* Parse command line options */
42026947304SEvan Yan 	parse_common(argc, argv, usage_str);
42126947304SEvan Yan 	parse_target(argc, argv, &path, &connection, usage_str);
42226947304SEvan Yan 
42326947304SEvan Yan 	/* Path and connection are required */
42426947304SEvan Yan 	if ((path == NULL) || (connection == NULL)) {
42526947304SEvan Yan 		(void) fprintf(stderr, gettext("ERROR: too few arguments.\n"));
42626947304SEvan Yan 		usage(usage_str);
42726947304SEvan Yan 		return (EINVAL);
42826947304SEvan Yan 	}
42926947304SEvan Yan 
43026947304SEvan Yan 	/* Get hotplug information snapshot */
43126947304SEvan Yan 	if ((root = hp_init(path, connection, 0)) == NULL) {
43226947304SEvan Yan 		print_error(errno);
43326947304SEvan Yan 		return (errno);
43426947304SEvan Yan 	}
43526947304SEvan Yan 
43626947304SEvan Yan 	/* Verify target is a connector */
43726947304SEvan Yan 	if (hp_type(root) != HP_NODE_CONNECTOR) {
43826947304SEvan Yan 		(void) fprintf(stderr,
43926947304SEvan Yan 		    gettext("ERROR: invalid target (must be a connector).\n"));
44026947304SEvan Yan 		hp_fini(root);
44126947304SEvan Yan 		return (EINVAL);
44226947304SEvan Yan 	}
44326947304SEvan Yan 
44426947304SEvan Yan 	/* Do state change */
44526947304SEvan Yan 	rv = hp_set_state(root, 0, DDI_HP_CN_STATE_ENABLED, &results);
44626947304SEvan Yan 
44726947304SEvan Yan 	/* Display results */
44826947304SEvan Yan 	print_error(rv);
44926947304SEvan Yan 	if (results != NULL) {
45026947304SEvan Yan 		(void) hp_traverse(results, NULL, error_cb);
45126947304SEvan Yan 		hp_fini(results);
45226947304SEvan Yan 	}
45326947304SEvan Yan 
45426947304SEvan Yan 	/* Discard hotplug information snapshot */
45526947304SEvan Yan 	hp_fini(root);
45626947304SEvan Yan 
45726947304SEvan Yan 	return (rv);
45826947304SEvan Yan }
45926947304SEvan Yan 
46026947304SEvan Yan /*
46126947304SEvan Yan  * cmd_disable()
46226947304SEvan Yan  *
46326947304SEvan Yan  *	Subcommand to disable a hotplug connector.
46426947304SEvan Yan  */
46526947304SEvan Yan static int
cmd_disable(int argc,char * argv[],const char * usage_str)46626947304SEvan Yan cmd_disable(int argc, char *argv[], const char *usage_str)
46726947304SEvan Yan {
46826947304SEvan Yan 	hp_node_t	root;
46926947304SEvan Yan 	hp_node_t	results = NULL;
47026947304SEvan Yan 	char		*path = NULL;
47126947304SEvan Yan 	char		*connection = NULL;
47226947304SEvan Yan 	int		flags = 0;
47326947304SEvan Yan 	int		rv;
47426947304SEvan Yan 
47526947304SEvan Yan 	/* Parse command line options */
47626947304SEvan Yan 	parse_common(argc, argv, usage_str);
47726947304SEvan Yan 	parse_flags(argc, argv, &flags, usage_str);
47826947304SEvan Yan 	parse_target(argc, argv, &path, &connection, usage_str);
47926947304SEvan Yan 
48026947304SEvan Yan 	/* Path and connection are required */
48126947304SEvan Yan 	if ((path == NULL) || (connection == NULL)) {
48226947304SEvan Yan 		(void) fprintf(stderr, gettext("ERROR: too few arguments.\n"));
48326947304SEvan Yan 		usage(usage_str);
48426947304SEvan Yan 		return (EINVAL);
48526947304SEvan Yan 	}
48626947304SEvan Yan 
48726947304SEvan Yan 	/* Get hotplug information snapshot */
48826947304SEvan Yan 	if ((root = hp_init(path, connection, 0)) == NULL) {
48926947304SEvan Yan 		print_error(errno);
49026947304SEvan Yan 		return (errno);
49126947304SEvan Yan 	}
49226947304SEvan Yan 
49326947304SEvan Yan 	/* Verify target is a connector */
49426947304SEvan Yan 	if (hp_type(root) != HP_NODE_CONNECTOR) {
49526947304SEvan Yan 		(void) fprintf(stderr,
49626947304SEvan Yan 		    gettext("ERROR: invalid target (must be a connector).\n"));
49726947304SEvan Yan 		hp_fini(root);
49826947304SEvan Yan 		return (EINVAL);
49926947304SEvan Yan 	}
50026947304SEvan Yan 
50126947304SEvan Yan 	/*
50226947304SEvan Yan 	 * Do nothing unless the connector is in the ENABLED state.
50326947304SEvan Yan 	 * Otherwise this subcommand becomes an alias for 'poweron.'
50426947304SEvan Yan 	 */
50526947304SEvan Yan 	if (hp_state(root) != DDI_HP_CN_STATE_ENABLED) {
50626947304SEvan Yan 		hp_fini(root);
50726947304SEvan Yan 		return (0);
50826947304SEvan Yan 	}
50926947304SEvan Yan 
51026947304SEvan Yan 	/* Do state change */
51126947304SEvan Yan 	rv = hp_set_state(root, flags, DDI_HP_CN_STATE_POWERED, &results);
51226947304SEvan Yan 
51326947304SEvan Yan 	/* Display results */
51426947304SEvan Yan 	print_error(rv);
51526947304SEvan Yan 	if (results != NULL) {
51626947304SEvan Yan 		(void) hp_traverse(results, NULL, error_cb);
51726947304SEvan Yan 		hp_fini(results);
51826947304SEvan Yan 	}
51926947304SEvan Yan 
52026947304SEvan Yan 	/* Discard hotplug information snapshot */
52126947304SEvan Yan 	hp_fini(root);
52226947304SEvan Yan 
52326947304SEvan Yan 	return (rv);
52426947304SEvan Yan }
52526947304SEvan Yan 
52626947304SEvan Yan /*
52726947304SEvan Yan  * cmd_poweron()
52826947304SEvan Yan  *
52926947304SEvan Yan  *	Subcommand to power on a hotplug connector.
53026947304SEvan Yan  */
53126947304SEvan Yan static int
cmd_poweron(int argc,char * argv[],const char * usage_str)53226947304SEvan Yan cmd_poweron(int argc, char *argv[], const char *usage_str)
53326947304SEvan Yan {
53426947304SEvan Yan 	hp_node_t	root;
53526947304SEvan Yan 	hp_node_t	results = NULL;
53626947304SEvan Yan 	char		*path = NULL;
53726947304SEvan Yan 	char		*connection = NULL;
53826947304SEvan Yan 	int		rv;
53926947304SEvan Yan 
54026947304SEvan Yan 	/* Parse command line options */
54126947304SEvan Yan 	parse_common(argc, argv, usage_str);
54226947304SEvan Yan 	parse_target(argc, argv, &path, &connection, usage_str);
54326947304SEvan Yan 
54426947304SEvan Yan 	/* Path and connection are required */
54526947304SEvan Yan 	if ((path == NULL) || (connection == NULL)) {
54626947304SEvan Yan 		(void) fprintf(stderr, gettext("ERROR: too few arguments.\n"));
54726947304SEvan Yan 		usage(usage_str);
54826947304SEvan Yan 		return (EINVAL);
54926947304SEvan Yan 	}
55026947304SEvan Yan 
55126947304SEvan Yan 	/* Get hotplug information snapshot */
55226947304SEvan Yan 	if ((root = hp_init(path, connection, 0)) == NULL) {
55326947304SEvan Yan 		print_error(errno);
55426947304SEvan Yan 		return (errno);
55526947304SEvan Yan 	}
55626947304SEvan Yan 
55726947304SEvan Yan 	/* Verify target is a connector */
55826947304SEvan Yan 	if (hp_type(root) != HP_NODE_CONNECTOR) {
55926947304SEvan Yan 		(void) fprintf(stderr,
56026947304SEvan Yan 		    gettext("ERROR: invalid target (must be a connector).\n"));
56126947304SEvan Yan 		hp_fini(root);
56226947304SEvan Yan 		return (EINVAL);
56326947304SEvan Yan 	}
56426947304SEvan Yan 
56526947304SEvan Yan 	/*
56626947304SEvan Yan 	 * Do nothing if the connector is already powered.
56726947304SEvan Yan 	 * Otherwise this subcommand becomes an alias for 'disable.'
56826947304SEvan Yan 	 */
56926947304SEvan Yan 	if (hp_state(root) >= DDI_HP_CN_STATE_POWERED) {
57026947304SEvan Yan 		hp_fini(root);
57126947304SEvan Yan 		return (0);
57226947304SEvan Yan 	}
57326947304SEvan Yan 
57426947304SEvan Yan 	/* Do state change */
57526947304SEvan Yan 	rv = hp_set_state(root, 0, DDI_HP_CN_STATE_POWERED, &results);
57626947304SEvan Yan 
57726947304SEvan Yan 	/* Display results */
57826947304SEvan Yan 	print_error(rv);
57926947304SEvan Yan 	if (results != NULL) {
58026947304SEvan Yan 		(void) hp_traverse(results, NULL, error_cb);
58126947304SEvan Yan 		hp_fini(results);
58226947304SEvan Yan 	}
58326947304SEvan Yan 
58426947304SEvan Yan 	/* Discard hotplug information snapshot */
58526947304SEvan Yan 	hp_fini(root);
58626947304SEvan Yan 
58726947304SEvan Yan 	return (rv);
58826947304SEvan Yan }
58926947304SEvan Yan 
59026947304SEvan Yan /*
59126947304SEvan Yan  * cmd_poweroff()
59226947304SEvan Yan  *
59326947304SEvan Yan  *	Subcommand to power off a hotplug connector.
59426947304SEvan Yan  */
59526947304SEvan Yan static int
cmd_poweroff(int argc,char * argv[],const char * usage_str)59626947304SEvan Yan cmd_poweroff(int argc, char *argv[], const char *usage_str)
59726947304SEvan Yan {
59826947304SEvan Yan 	hp_node_t	root;
59926947304SEvan Yan 	hp_node_t	results = NULL;
60026947304SEvan Yan 	char		*path = NULL;
60126947304SEvan Yan 	char		*connection = NULL;
60226947304SEvan Yan 	int		flags = 0;
60326947304SEvan Yan 	int		rv;
60426947304SEvan Yan 
60526947304SEvan Yan 	/* Parse command line options */
60626947304SEvan Yan 	parse_common(argc, argv, usage_str);
60726947304SEvan Yan 	parse_flags(argc, argv, &flags, usage_str);
60826947304SEvan Yan 	parse_target(argc, argv, &path, &connection, usage_str);
60926947304SEvan Yan 
61026947304SEvan Yan 	/* Path and connection are required */
61126947304SEvan Yan 	if ((path == NULL) || (connection == NULL)) {
61226947304SEvan Yan 		(void) fprintf(stderr, gettext("ERROR: too few arguments.\n"));
61326947304SEvan Yan 		usage(usage_str);
61426947304SEvan Yan 		return (EINVAL);
61526947304SEvan Yan 	}
61626947304SEvan Yan 
61726947304SEvan Yan 	/* Get hotplug information snapshot */
61826947304SEvan Yan 	if ((root = hp_init(path, connection, 0)) == NULL) {
61926947304SEvan Yan 		print_error(errno);
62026947304SEvan Yan 		return (errno);
62126947304SEvan Yan 	}
62226947304SEvan Yan 
62326947304SEvan Yan 	/* Verify target is a connector */
62426947304SEvan Yan 	if (hp_type(root) != HP_NODE_CONNECTOR) {
62526947304SEvan Yan 		(void) fprintf(stderr,
62626947304SEvan Yan 		    gettext("ERROR: invalid target (must be a connector).\n"));
62726947304SEvan Yan 		hp_fini(root);
62826947304SEvan Yan 		return (EINVAL);
62926947304SEvan Yan 	}
63026947304SEvan Yan 
63126947304SEvan Yan 	/* Do state change */
63226947304SEvan Yan 	rv = hp_set_state(root, flags, DDI_HP_CN_STATE_PRESENT, &results);
63326947304SEvan Yan 
63426947304SEvan Yan 	/* Display results */
63526947304SEvan Yan 	print_error(rv);
63626947304SEvan Yan 	if (results != NULL) {
63726947304SEvan Yan 		(void) hp_traverse(results, NULL, error_cb);
63826947304SEvan Yan 		hp_fini(results);
63926947304SEvan Yan 	}
64026947304SEvan Yan 
64126947304SEvan Yan 	/* Discard hotplug information snapshot */
64226947304SEvan Yan 	hp_fini(root);
64326947304SEvan Yan 
64426947304SEvan Yan 	return (rv);
64526947304SEvan Yan }
64626947304SEvan Yan 
64726947304SEvan Yan /*
64826947304SEvan Yan  * cmd_getpriv()
64926947304SEvan Yan  *
65026947304SEvan Yan  *	Subcommand to get and display bus private options.
65126947304SEvan Yan  */
65226947304SEvan Yan static int
cmd_getpriv(int argc,char * argv[],const char * usage_str)65326947304SEvan Yan cmd_getpriv(int argc, char *argv[], const char *usage_str)
65426947304SEvan Yan {
65526947304SEvan Yan 	hp_node_t	root;
65626947304SEvan Yan 	char		*path = NULL;
65726947304SEvan Yan 	char		*connection = NULL;
65826947304SEvan Yan 	char		*options = NULL;
65926947304SEvan Yan 	char		*results = NULL;
66026947304SEvan Yan 	int		rv;
66126947304SEvan Yan 
66226947304SEvan Yan 	/* Parse command line options */
66326947304SEvan Yan 	parse_common(argc, argv, usage_str);
66426947304SEvan Yan 	parse_options(argc, argv, &options, usage_str);
66526947304SEvan Yan 	parse_target(argc, argv, &path, &connection, usage_str);
66626947304SEvan Yan 
66726947304SEvan Yan 	/* Options, path, and connection are all required */
66826947304SEvan Yan 	if ((options == NULL) || (path == NULL) || (connection == NULL)) {
66926947304SEvan Yan 		(void) fprintf(stderr, gettext("ERROR: too few arguments.\n"));
67026947304SEvan Yan 		usage(usage_str);
67126947304SEvan Yan 		return (EINVAL);
67226947304SEvan Yan 	}
67326947304SEvan Yan 
67426947304SEvan Yan 	/* Get hotplug information snapshot */
67526947304SEvan Yan 	if ((root = hp_init(path, connection, 0)) == NULL) {
67626947304SEvan Yan 		print_error(errno);
67726947304SEvan Yan 		return (errno);
67826947304SEvan Yan 	}
67926947304SEvan Yan 
68026947304SEvan Yan 	/* Verify target is a connector */
68126947304SEvan Yan 	if (hp_type(root) != HP_NODE_CONNECTOR) {
68226947304SEvan Yan 		(void) fprintf(stderr,
68326947304SEvan Yan 		    gettext("ERROR: invalid target (must be a connector).\n"));
68426947304SEvan Yan 		hp_fini(root);
68526947304SEvan Yan 		return (EINVAL);
68626947304SEvan Yan 	}
68726947304SEvan Yan 
68826947304SEvan Yan 	/* Do the operation */
68926947304SEvan Yan 	rv = hp_get_private(root, options, &results);
69026947304SEvan Yan 
69126947304SEvan Yan 	/* Display results */
69226947304SEvan Yan 	if (rv == ENOTSUP) {
69326947304SEvan Yan 		(void) fprintf(stderr,
69426947304SEvan Yan 		    gettext("ERROR: unsupported property name or value.\n"));
69526947304SEvan Yan 		(void) fprintf(stderr,
69626947304SEvan Yan 		    gettext("(Properties may depend upon connector state.)\n"));
69726947304SEvan Yan 	} else if (rv != 0) {
69826947304SEvan Yan 		print_error(rv);
69926947304SEvan Yan 	}
70026947304SEvan Yan 	if (results != NULL) {
70126947304SEvan Yan 		print_options(results);
70226947304SEvan Yan 		free(results);
70326947304SEvan Yan 	}
70426947304SEvan Yan 
70526947304SEvan Yan 	/* Discard hotplug information snapshot */
70626947304SEvan Yan 	hp_fini(root);
70726947304SEvan Yan 
70826947304SEvan Yan 	return (rv);
70926947304SEvan Yan }
71026947304SEvan Yan 
71126947304SEvan Yan /*
71226947304SEvan Yan  * cmd_setpriv()
71326947304SEvan Yan  *
71426947304SEvan Yan  *	Subcommand to set bus private options.
71526947304SEvan Yan  */
71626947304SEvan Yan static int
cmd_setpriv(int argc,char * argv[],const char * usage_str)71726947304SEvan Yan cmd_setpriv(int argc, char *argv[], const char *usage_str)
71826947304SEvan Yan {
71926947304SEvan Yan 	hp_node_t	root;
72026947304SEvan Yan 	char		*path = NULL;
72126947304SEvan Yan 	char		*connection = NULL;
72226947304SEvan Yan 	char		*options = NULL;
72326947304SEvan Yan 	char		*results = NULL;
72426947304SEvan Yan 	int		rv;
72526947304SEvan Yan 
72626947304SEvan Yan 	/* Parse command line options */
72726947304SEvan Yan 	parse_common(argc, argv, usage_str);
72826947304SEvan Yan 	parse_options(argc, argv, &options, usage_str);
72926947304SEvan Yan 	parse_target(argc, argv, &path, &connection, usage_str);
73026947304SEvan Yan 
73126947304SEvan Yan 	/* Options, path, and connection are all required */
73226947304SEvan Yan 	if ((options == NULL) || (path == NULL) || (connection == NULL)) {
73326947304SEvan Yan 		(void) fprintf(stderr, gettext("ERROR: too few arguments.\n"));
73426947304SEvan Yan 		usage(usage_str);
73526947304SEvan Yan 		return (EINVAL);
73626947304SEvan Yan 	}
73726947304SEvan Yan 
73826947304SEvan Yan 	/* Get hotplug information snapshot */
73926947304SEvan Yan 	if ((root = hp_init(path, connection, 0)) == NULL) {
74026947304SEvan Yan 		print_error(errno);
74126947304SEvan Yan 		return (errno);
74226947304SEvan Yan 	}
74326947304SEvan Yan 
74426947304SEvan Yan 	/* Verify target is a connector */
74526947304SEvan Yan 	if (hp_type(root) != HP_NODE_CONNECTOR) {
74626947304SEvan Yan 		(void) fprintf(stderr,
74726947304SEvan Yan 		    gettext("ERROR: invalid target (must be a connector).\n"));
74826947304SEvan Yan 		hp_fini(root);
74926947304SEvan Yan 		return (EINVAL);
75026947304SEvan Yan 	}
75126947304SEvan Yan 
75226947304SEvan Yan 	/* Do the operation */
75326947304SEvan Yan 	rv = hp_set_private(root, options, &results);
75426947304SEvan Yan 
75526947304SEvan Yan 	/* Display results */
75626947304SEvan Yan 	if (rv == ENOTSUP) {
75726947304SEvan Yan 		(void) fprintf(stderr,
75826947304SEvan Yan 		    gettext("ERROR: unsupported property name or value.\n"));
75926947304SEvan Yan 		(void) fprintf(stderr,
76026947304SEvan Yan 		    gettext("(Properties may depend upon connector state.)\n"));
76126947304SEvan Yan 	} else if (rv != 0) {
76226947304SEvan Yan 		print_error(rv);
76326947304SEvan Yan 	}
76426947304SEvan Yan 	if (results != NULL) {
76526947304SEvan Yan 		print_options(results);
76626947304SEvan Yan 		free(results);
76726947304SEvan Yan 	}
76826947304SEvan Yan 
76926947304SEvan Yan 	/* Discard hotplug information snapshot */
77026947304SEvan Yan 	hp_fini(root);
77126947304SEvan Yan 
77226947304SEvan Yan 	return (rv);
77326947304SEvan Yan }
77426947304SEvan Yan 
77526947304SEvan Yan /*
77626947304SEvan Yan  * cmd_changestate()
77726947304SEvan Yan  *
77826947304SEvan Yan  *	Subcommand to initiate a state change operation.  This is
77926947304SEvan Yan  *	a hidden subcommand to directly set a connector or port to
78026947304SEvan Yan  *	a specific target state.
78126947304SEvan Yan  */
78226947304SEvan Yan static int
cmd_changestate(int argc,char * argv[],const char * usage_str)78326947304SEvan Yan cmd_changestate(int argc, char *argv[], const char *usage_str)
78426947304SEvan Yan {
78526947304SEvan Yan 	hp_node_t	root;
78626947304SEvan Yan 	hp_node_t	results = NULL;
78726947304SEvan Yan 	char		*path = NULL;
78826947304SEvan Yan 	char		*connection = NULL;
78926947304SEvan Yan 	int		state = -1;
79026947304SEvan Yan 	int		flags = 0;
79126947304SEvan Yan 	int		opt, rv;
79226947304SEvan Yan 
79326947304SEvan Yan 	/* Parse command line options */
79426947304SEvan Yan 	parse_common(argc, argv, usage_str);
79526947304SEvan Yan 	while ((opt = getopt_clip(argc, argv, "fqs:", changestate_opts,
79626947304SEvan Yan 	    NULL)) != -1) {
79726947304SEvan Yan 		switch (opt) {
79826947304SEvan Yan 		case 'f':
79926947304SEvan Yan 			flags |= HPFORCE;
80026947304SEvan Yan 			break;
80126947304SEvan Yan 		case 'q':
80226947304SEvan Yan 			flags |= HPQUERY;
80326947304SEvan Yan 			break;
80426947304SEvan Yan 		case 's':
80526947304SEvan Yan 			if ((state = state_atoi(optarg)) == -1) {
80626947304SEvan Yan 				(void) printf("ERROR: invalid target state\n");
80726947304SEvan Yan 				return (EINVAL);
80826947304SEvan Yan 			}
80926947304SEvan Yan 			break;
81026947304SEvan Yan 		default:
81126947304SEvan Yan 			bad_option(opt, optopt, usage_str);
81226947304SEvan Yan 			break;
81326947304SEvan Yan 		}
81426947304SEvan Yan 	}
81526947304SEvan Yan 	parse_target(argc, argv, &path, &connection, usage_str);
81626947304SEvan Yan 
81726947304SEvan Yan 	/* State, path, and connection are all required */
81826947304SEvan Yan 	if ((state == -1) || (path == NULL) || (connection == NULL)) {
81926947304SEvan Yan 		(void) fprintf(stderr, gettext("ERROR: too few arguments.\n"));
82026947304SEvan Yan 		usage(usage_str);
82126947304SEvan Yan 		return (EINVAL);
82226947304SEvan Yan 	}
82326947304SEvan Yan 
82426947304SEvan Yan 	/* Check that target state is valid */
82526947304SEvan Yan 	if (valid_target(state) == 0) {
82626947304SEvan Yan 		(void) fprintf(stderr,
82726947304SEvan Yan 		    gettext("ERROR: invalid target state\n"));
82826947304SEvan Yan 		return (EINVAL);
82926947304SEvan Yan 	}
83026947304SEvan Yan 
83126947304SEvan Yan 	/* Get hotplug information snapshot */
83226947304SEvan Yan 	if ((root = hp_init(path, connection, 0)) == NULL) {
83326947304SEvan Yan 		print_error(errno);
83426947304SEvan Yan 		return (errno);
83526947304SEvan Yan 	}
83626947304SEvan Yan 
83726947304SEvan Yan 	/* Initiate state change operation on root of snapshot */
83826947304SEvan Yan 	rv = hp_set_state(root, flags, state, &results);
83926947304SEvan Yan 
84026947304SEvan Yan 	/* Display results */
84126947304SEvan Yan 	print_error(rv);
84226947304SEvan Yan 	if (results) {
84326947304SEvan Yan 		(void) hp_traverse(results, NULL, error_cb);
84426947304SEvan Yan 		hp_fini(results);
84526947304SEvan Yan 	}
84626947304SEvan Yan 
84726947304SEvan Yan 	/* Discard hotplug information snapshot */
84826947304SEvan Yan 	hp_fini(root);
84926947304SEvan Yan 
85026947304SEvan Yan 	return (rv);
85126947304SEvan Yan }
85226947304SEvan Yan 
85326947304SEvan Yan /*
85426947304SEvan Yan  * parse_common()
85526947304SEvan Yan  *
85626947304SEvan Yan  *	Parse command line options that are common to the
85726947304SEvan Yan  *	entire program, and to each of its subcommands.
85826947304SEvan Yan  */
85926947304SEvan Yan static void
parse_common(int argc,char * argv[],const char * usage_str)86026947304SEvan Yan parse_common(int argc, char *argv[], const char *usage_str)
86126947304SEvan Yan {
86226947304SEvan Yan 	int		opt;
86326947304SEvan Yan 	extern int	opterr;
86426947304SEvan Yan 	extern int	optind;
86526947304SEvan Yan 
86626947304SEvan Yan 	/* Turn off error reporting */
86726947304SEvan Yan 	opterr = 0;
86826947304SEvan Yan 
86926947304SEvan Yan 	while ((opt = getopt_clip(argc, argv, "?V", common_opts, NULL)) != -1) {
87026947304SEvan Yan 		switch (opt) {
87126947304SEvan Yan 		case '?':
87226947304SEvan Yan 			if (optopt == '?') {
87326947304SEvan Yan 				usage(usage_str);
87426947304SEvan Yan 				exit(0);
87526947304SEvan Yan 			}
87626947304SEvan Yan 			break;
87726947304SEvan Yan 		case 'V':
87826947304SEvan Yan 			(void) printf(gettext("%s: Version %s\n"),
87926947304SEvan Yan 			    prog, version);
88026947304SEvan Yan 			exit(0);
88126947304SEvan Yan 		default:
88226947304SEvan Yan 			break;
88326947304SEvan Yan 		}
88426947304SEvan Yan 	}
88526947304SEvan Yan 
88626947304SEvan Yan 	/* Reset option index */
88726947304SEvan Yan 	optind = 1;
88826947304SEvan Yan }
88926947304SEvan Yan 
89026947304SEvan Yan /*
89126947304SEvan Yan  * parse_flags()
89226947304SEvan Yan  *
89326947304SEvan Yan  *	Parse command line flags common to all downward state
89426947304SEvan Yan  *	change operations (offline, disable, poweoff).
89526947304SEvan Yan  */
89626947304SEvan Yan static void
parse_flags(int argc,char * argv[],int * flagsp,const char * usage_str)89726947304SEvan Yan parse_flags(int argc, char *argv[], int *flagsp, const char *usage_str)
89826947304SEvan Yan {
89926947304SEvan Yan 	int	opt;
90026947304SEvan Yan 	int	flags = 0;
90126947304SEvan Yan 
90226947304SEvan Yan 	while ((opt = getopt_clip(argc, argv, "fq", flag_opts, NULL)) != -1) {
90326947304SEvan Yan 		switch (opt) {
90426947304SEvan Yan 		case 'f':
90526947304SEvan Yan 			flags |= HPFORCE;
90626947304SEvan Yan 			break;
90726947304SEvan Yan 		case 'q':
90826947304SEvan Yan 			flags |= HPQUERY;
90926947304SEvan Yan 			break;
91026947304SEvan Yan 		default:
91126947304SEvan Yan 			bad_option(opt, optopt, usage_str);
91226947304SEvan Yan 			break;
91326947304SEvan Yan 		}
91426947304SEvan Yan 	}
91526947304SEvan Yan 
91626947304SEvan Yan 	*flagsp = flags;
91726947304SEvan Yan }
91826947304SEvan Yan 
91926947304SEvan Yan /*
92026947304SEvan Yan  * parse_options()
92126947304SEvan Yan  *
92226947304SEvan Yan  *	Parse command line options common to the bus private set and
92326947304SEvan Yan  *	get subcommands.
92426947304SEvan Yan  */
92526947304SEvan Yan static void
parse_options(int argc,char * argv[],char ** optionsp,const char * usage_str)92626947304SEvan Yan parse_options(int argc, char *argv[], char **optionsp, const char *usage_str)
92726947304SEvan Yan {
92826947304SEvan Yan 	int	opt;
92926947304SEvan Yan 
93026947304SEvan Yan 	while ((opt = getopt_clip(argc, argv, "o:", private_opts,
93126947304SEvan Yan 	    NULL)) != -1) {
93226947304SEvan Yan 		switch (opt) {
93326947304SEvan Yan 		case 'o':
93426947304SEvan Yan 			*optionsp = optarg;
93526947304SEvan Yan 			break;
93626947304SEvan Yan 		default:
93726947304SEvan Yan 			bad_option(opt, optopt, usage_str);
93826947304SEvan Yan 			break;
93926947304SEvan Yan 		}
94026947304SEvan Yan 	}
94126947304SEvan Yan }
94226947304SEvan Yan 
94326947304SEvan Yan /*
94426947304SEvan Yan  * parse_target()
94526947304SEvan Yan  *
94626947304SEvan Yan  *	Parse the target path and connection name from the command line.
94726947304SEvan Yan  */
94826947304SEvan Yan static void
parse_target(int argc,char * argv[],char ** pathp,char ** connectionp,const char * usage_str)94926947304SEvan Yan parse_target(int argc, char *argv[], char **pathp, char **connectionp,
95026947304SEvan Yan     const char *usage_str)
95126947304SEvan Yan {
95226947304SEvan Yan 	extern int	optind;
95326947304SEvan Yan 
95426947304SEvan Yan 	if (optind < argc)
95526947304SEvan Yan 		*pathp = argv[optind++];
95626947304SEvan Yan 
95726947304SEvan Yan 	if (optind < argc)
95826947304SEvan Yan 		*connectionp = argv[optind++];
95926947304SEvan Yan 
96026947304SEvan Yan 	if (optind < argc) {
96126947304SEvan Yan 		(void) fprintf(stderr, gettext("ERROR: too many arguments.\n"));
96226947304SEvan Yan 		usage(usage_str);
96326947304SEvan Yan 		exit(EINVAL);
96426947304SEvan Yan 	}
96526947304SEvan Yan }
96626947304SEvan Yan 
96726947304SEvan Yan /*
96826947304SEvan Yan  * bad_option()
96926947304SEvan Yan  *
97026947304SEvan Yan  *	Routine to handle bad command line options.
97126947304SEvan Yan  */
97226947304SEvan Yan static void
bad_option(int opt,int optopt,const char * usage_str)97326947304SEvan Yan bad_option(int opt, int optopt, const char *usage_str)
97426947304SEvan Yan {
97526947304SEvan Yan 	switch (opt) {
97626947304SEvan Yan 	case ':':
97726947304SEvan Yan 		(void) fprintf(stderr,
97826947304SEvan Yan 		    gettext("ERROR: option '%c' requires an argument.\n"),
97926947304SEvan Yan 		    optopt);
98026947304SEvan Yan 		break;
98126947304SEvan Yan 	default:
98226947304SEvan Yan 		if (optopt == '?') {
98326947304SEvan Yan 			usage(usage_str);
98426947304SEvan Yan 			exit(EXIT_OK);
98526947304SEvan Yan 		}
98626947304SEvan Yan 		(void) fprintf(stderr,
98726947304SEvan Yan 		    gettext("ERROR: unrecognized option '%c'.\n"), optopt);
98826947304SEvan Yan 		break;
98926947304SEvan Yan 	}
99026947304SEvan Yan 
99126947304SEvan Yan 	usage(usage_str);
99226947304SEvan Yan 
99326947304SEvan Yan 	exit(EXIT_EINVAL);
99426947304SEvan Yan }
99526947304SEvan Yan 
99626947304SEvan Yan /*
99726947304SEvan Yan  * usage()
99826947304SEvan Yan  *
99926947304SEvan Yan  *	Display general usage of the command.  Including
100026947304SEvan Yan  *	the usage synopsis of each defined subcommand.
100126947304SEvan Yan  */
100226947304SEvan Yan static void
usage(const char * usage_str)100326947304SEvan Yan usage(const char *usage_str)
100426947304SEvan Yan {
100526947304SEvan Yan 	int	i;
100626947304SEvan Yan 
100726947304SEvan Yan 	if (usage_str != NULL) {
100826947304SEvan Yan 		(void) fprintf(stderr, gettext("Usage:   %s  %s\n\n"),
100926947304SEvan Yan 		    prog, usage_str);
101026947304SEvan Yan 		return;
101126947304SEvan Yan 	}
101226947304SEvan Yan 
101326947304SEvan Yan 	(void) fprintf(stderr, gettext("Usage:  %s  <subcommand> [<args>]\n\n"),
101426947304SEvan Yan 	    prog);
101526947304SEvan Yan 
101626947304SEvan Yan 	(void) fprintf(stderr, gettext("Subcommands:\n\n"));
101726947304SEvan Yan 
101826947304SEvan Yan 	for (i = 0; i < (sizeof (subcmds) / sizeof (subcmd_t)); i++)
101926947304SEvan Yan 		(void) fprintf(stderr, "   %s\n\n", subcmds[i].usage_str);
102026947304SEvan Yan }
102126947304SEvan Yan 
102226947304SEvan Yan /*
102326947304SEvan Yan  * list_cb()
102426947304SEvan Yan  *
102526947304SEvan Yan  *	Callback function for hp_traverse(), to display nodes
102626947304SEvan Yan  *	of a hotplug information snapshot.  (Short version.)
102726947304SEvan Yan  */
102826947304SEvan Yan /*ARGSUSED*/
102926947304SEvan Yan static int
list_cb(hp_node_t node,void * arg)103026947304SEvan Yan list_cb(hp_node_t node, void *arg)
103126947304SEvan Yan {
103226947304SEvan Yan 	hp_node_t	parent;
103326947304SEvan Yan 
103426947304SEvan Yan 	/* Indent */
103526947304SEvan Yan 	for (parent = hp_parent(node); parent; parent = hp_parent(parent))
103626947304SEvan Yan 		if (hp_type(parent) == HP_NODE_DEVICE)
103726947304SEvan Yan 			(void) printf("     ");
103826947304SEvan Yan 
103926947304SEvan Yan 	switch (hp_type(node)) {
104026947304SEvan Yan 	case HP_NODE_DEVICE:
104126947304SEvan Yan 		(void) printf("%s\n", hp_name(node));
104226947304SEvan Yan 		break;
104326947304SEvan Yan 
104426947304SEvan Yan 	case HP_NODE_CONNECTOR:
104526947304SEvan Yan 		(void) printf("[%s]", hp_name(node));
104626947304SEvan Yan 		(void) printf("  (%s)", state_itoa(hp_state(node)));
104726947304SEvan Yan 		(void) printf("\n");
104826947304SEvan Yan 		break;
104926947304SEvan Yan 
105026947304SEvan Yan 	case HP_NODE_PORT:
105126947304SEvan Yan 		(void) printf("<%s>", hp_name(node));
105226947304SEvan Yan 		(void) printf("  (%s)", state_itoa(hp_state(node)));
105326947304SEvan Yan 		(void) printf("\n");
105426947304SEvan Yan 		break;
105526947304SEvan Yan 
105626947304SEvan Yan 	case HP_NODE_USAGE:
105726947304SEvan Yan 		(void) printf("{ %s }\n", hp_usage(node));
105826947304SEvan Yan 		break;
105926947304SEvan Yan 	}
106026947304SEvan Yan 
106126947304SEvan Yan 	return (HP_WALK_CONTINUE);
106226947304SEvan Yan }
106326947304SEvan Yan 
106426947304SEvan Yan /*
106526947304SEvan Yan  * list_long_cb()
106626947304SEvan Yan  *
106726947304SEvan Yan  *	Callback function for hp_traverse(), to display nodes
106826947304SEvan Yan  *	of a hotplug information snapshot.  (Long version.)
106926947304SEvan Yan  */
107026947304SEvan Yan /*ARGSUSED*/
107126947304SEvan Yan static int
list_long_cb(hp_node_t node,void * arg)107226947304SEvan Yan list_long_cb(hp_node_t node, void *arg)
107326947304SEvan Yan {
107426947304SEvan Yan 	char	path[MAXPATHLEN];
107526947304SEvan Yan 	char	connection[MAXPATHLEN];
107626947304SEvan Yan 
107726947304SEvan Yan 	if (hp_type(node) != HP_NODE_USAGE) {
107826947304SEvan Yan 		if (hp_path(node, path, connection) != 0)
107926947304SEvan Yan 			return (HP_WALK_CONTINUE);
108026947304SEvan Yan 		(void) printf("%s", path);
108126947304SEvan Yan 	}
108226947304SEvan Yan 
108326947304SEvan Yan 	switch (hp_type(node)) {
108426947304SEvan Yan 	case HP_NODE_CONNECTOR:
108526947304SEvan Yan 		(void) printf(" [%s]", connection);
108626947304SEvan Yan 		(void) printf(" (%s)", state_itoa(hp_state(node)));
108726947304SEvan Yan 		break;
108826947304SEvan Yan 
108926947304SEvan Yan 	case HP_NODE_PORT:
109026947304SEvan Yan 		(void) printf(" <%s>", connection);
109126947304SEvan Yan 		(void) printf(" (%s)", state_itoa(hp_state(node)));
109226947304SEvan Yan 		break;
109326947304SEvan Yan 
109426947304SEvan Yan 	case HP_NODE_USAGE:
109526947304SEvan Yan 		(void) printf("    { %s }", hp_usage(node));
109626947304SEvan Yan 		break;
109726947304SEvan Yan 	}
109826947304SEvan Yan 
109926947304SEvan Yan 	(void) printf("\n");
110026947304SEvan Yan 
110126947304SEvan Yan 	return (HP_WALK_CONTINUE);
110226947304SEvan Yan }
110326947304SEvan Yan 
110426947304SEvan Yan /*
110526947304SEvan Yan  * error_cb()
110626947304SEvan Yan  *
110726947304SEvan Yan  *	Callback function for hp_traverse(), to display
110826947304SEvan Yan  *	error results from a state change operation.
110926947304SEvan Yan  */
111026947304SEvan Yan /*ARGSUSED*/
111126947304SEvan Yan static int
error_cb(hp_node_t node,void * arg)111226947304SEvan Yan error_cb(hp_node_t node, void *arg)
111326947304SEvan Yan {
111426947304SEvan Yan 	hp_node_t	child;
111526947304SEvan Yan 	char		*usage_str;
111626947304SEvan Yan 	static char	path[MAXPATHLEN];
111726947304SEvan Yan 	static char	connection[MAXPATHLEN];
111826947304SEvan Yan 
111926947304SEvan Yan 	if (((child = hp_child(node)) != NULL) &&
112026947304SEvan Yan 	    (hp_type(child) == HP_NODE_USAGE)) {
112126947304SEvan Yan 		if (hp_path(node, path, connection) == 0)
112226947304SEvan Yan 			(void) printf("%s:\n", path);
112326947304SEvan Yan 		return (HP_WALK_CONTINUE);
112426947304SEvan Yan 	}
112526947304SEvan Yan 
112626947304SEvan Yan 	if ((hp_type(node) == HP_NODE_USAGE) &&
112726947304SEvan Yan 	    ((usage_str = hp_usage(node)) != NULL))
112826947304SEvan Yan 		(void) printf("   { %s }\n", usage_str);
112926947304SEvan Yan 
113026947304SEvan Yan 	return (HP_WALK_CONTINUE);
113126947304SEvan Yan }
113226947304SEvan Yan 
113326947304SEvan Yan /*
113426947304SEvan Yan  * print_options()
113526947304SEvan Yan  *
113626947304SEvan Yan  *	Parse and display bus private options.  The options are
113726947304SEvan Yan  *	formatted as a string which conforms to the getsubopt(3C)
113826947304SEvan Yan  *	format.  This routine only splits the string elements as
113926947304SEvan Yan  *	separated by commas, and displays each portion on its own
114026947304SEvan Yan  *	separate line of output.
114126947304SEvan Yan  */
114226947304SEvan Yan static void
print_options(const char * options)114326947304SEvan Yan print_options(const char *options)
114426947304SEvan Yan {
114526947304SEvan Yan 	char	*buf, *curr, *next;
114626947304SEvan Yan 	size_t	len;
114726947304SEvan Yan 
114826947304SEvan Yan 	/* Do nothing if options string is empty */
114926947304SEvan Yan 	if ((len = strlen(options)) == 0)
115026947304SEvan Yan 		return;
115126947304SEvan Yan 
115226947304SEvan Yan 	/* To avoid modifying the input string, make a copy on the stack */
115326947304SEvan Yan 	if ((buf = (char *)alloca(len + 1)) == NULL) {
115426947304SEvan Yan 		(void) printf("%s\n", options);
115526947304SEvan Yan 		return;
115626947304SEvan Yan 	}
115726947304SEvan Yan 	(void) strlcpy(buf, options, len + 1);
115826947304SEvan Yan 
115926947304SEvan Yan 	/* Iterate through each comma-separated name/value pair */
116026947304SEvan Yan 	curr = buf;
116126947304SEvan Yan 	do {
116226947304SEvan Yan 		if ((next = strchr(curr, ',')) != NULL) {
116326947304SEvan Yan 			*next = '\0';
116426947304SEvan Yan 			next++;
116526947304SEvan Yan 		}
116626947304SEvan Yan 		(void) printf("%s\n", curr);
116726947304SEvan Yan 	} while ((curr = next) != NULL);
116826947304SEvan Yan }
116926947304SEvan Yan 
117026947304SEvan Yan /*
117126947304SEvan Yan  * print_error()
117226947304SEvan Yan  *
117326947304SEvan Yan  *	Common routine to print error numbers in an appropriate way.
117426947304SEvan Yan  *	Prints nothing if error code is 0.
117526947304SEvan Yan  */
117626947304SEvan Yan static void
print_error(int error)117726947304SEvan Yan print_error(int error)
117826947304SEvan Yan {
117926947304SEvan Yan 	switch (error) {
118026947304SEvan Yan 	case 0:
118126947304SEvan Yan 		/* No error */
118226947304SEvan Yan 		return;
118326947304SEvan Yan 	case EACCES:
118426947304SEvan Yan 		(void) fprintf(stderr,
118526947304SEvan Yan 		    gettext("ERROR: operation not authorized.\n"));
118626947304SEvan Yan 		break;
118726947304SEvan Yan 	case EBADF:
118826947304SEvan Yan 		(void) fprintf(stderr,
118926947304SEvan Yan 		    gettext("ERROR: hotplug service is not available.\n"));
119026947304SEvan Yan 		break;
119126947304SEvan Yan 	case EBUSY:
119226947304SEvan Yan 		(void) fprintf(stderr,
119326947304SEvan Yan 		    gettext("ERROR: devices or resources are busy.\n"));
119426947304SEvan Yan 		break;
119526947304SEvan Yan 	case EEXIST:
119626947304SEvan Yan 		(void) fprintf(stderr,
119726947304SEvan Yan 		    gettext("ERROR: resource already exists.\n"));
119826947304SEvan Yan 		break;
119926947304SEvan Yan 	case EFAULT:
120026947304SEvan Yan 		(void) fprintf(stderr,
120126947304SEvan Yan 		    gettext("ERROR: internal failure in hotplug service.\n"));
120226947304SEvan Yan 		break;
120326947304SEvan Yan 	case EINVAL:
120426947304SEvan Yan 		(void) fprintf(stderr,
120526947304SEvan Yan 		    gettext("ERROR: invalid arguments.\n"));
120626947304SEvan Yan 		break;
120726947304SEvan Yan 	case ENOENT:
120826947304SEvan Yan 		(void) fprintf(stderr,
120926947304SEvan Yan 		    gettext("ERROR: there are no connections to display.\n"));
121026947304SEvan Yan 		(void) fprintf(stderr,
1211*bbf21555SRichard Lowe 		    gettext("(See hotplug(8) for more information.)\n"));
121226947304SEvan Yan 		break;
121326947304SEvan Yan 	case ENXIO:
121426947304SEvan Yan 		(void) fprintf(stderr,
121526947304SEvan Yan 		    gettext("ERROR: no such path or connection.\n"));
121626947304SEvan Yan 		break;
121726947304SEvan Yan 	case ENOMEM:
121826947304SEvan Yan 		(void) fprintf(stderr,
121926947304SEvan Yan 		    gettext("ERROR: not enough memory.\n"));
122026947304SEvan Yan 		break;
122126947304SEvan Yan 	case ENOTSUP:
122226947304SEvan Yan 		(void) fprintf(stderr,
122326947304SEvan Yan 		    gettext("ERROR: operation not supported.\n"));
122426947304SEvan Yan 		break;
122526947304SEvan Yan 	case EIO:
122626947304SEvan Yan 		(void) fprintf(stderr,
122726947304SEvan Yan 		    gettext("ERROR: hardware or driver specific failure.\n"));
122826947304SEvan Yan 		break;
122926947304SEvan Yan 	default:
123026947304SEvan Yan 		(void) fprintf(stderr, gettext("ERROR: operation failed: %s\n"),
123126947304SEvan Yan 		    strerror(error));
123226947304SEvan Yan 		break;
123326947304SEvan Yan 	}
123426947304SEvan Yan }
123526947304SEvan Yan 
123626947304SEvan Yan /*
123726947304SEvan Yan  * state_atoi()
123826947304SEvan Yan  *
123926947304SEvan Yan  *	Convert a hotplug state from a string to an integer.
124026947304SEvan Yan  */
124126947304SEvan Yan static int
state_atoi(char * state)124226947304SEvan Yan state_atoi(char *state)
124326947304SEvan Yan {
124426947304SEvan Yan 	int	i;
124526947304SEvan Yan 
124626947304SEvan Yan 	for (i = 0; hpstates[i].state_str != NULL; i++)
124726947304SEvan Yan 		if (strcasecmp(state, hpstates[i].state_str) == 0)
124826947304SEvan Yan 			return (hpstates[i].state);
124926947304SEvan Yan 
125026947304SEvan Yan 	return (-1);
125126947304SEvan Yan }
125226947304SEvan Yan 
125326947304SEvan Yan /*
125426947304SEvan Yan  * state_itoa()
125526947304SEvan Yan  *
125626947304SEvan Yan  *	Convert a hotplug state from an integer to a string.
125726947304SEvan Yan  */
125826947304SEvan Yan static char *
state_itoa(int state)125926947304SEvan Yan state_itoa(int state)
126026947304SEvan Yan {
126126947304SEvan Yan 	static char	unknown[] = "UNKNOWN";
126226947304SEvan Yan 	int		i;
126326947304SEvan Yan 
126426947304SEvan Yan 	for (i = 0; hpstates[i].state_str != NULL; i++)
126526947304SEvan Yan 		if (state == hpstates[i].state)
126626947304SEvan Yan 			return (hpstates[i].state_str);
126726947304SEvan Yan 
126826947304SEvan Yan 	return (unknown);
126926947304SEvan Yan }
127026947304SEvan Yan 
127126947304SEvan Yan /*
127226947304SEvan Yan  * valid_target()
127326947304SEvan Yan  *
127426947304SEvan Yan  *	Check if a state is a valid target for a changestate command.
127526947304SEvan Yan  */
127626947304SEvan Yan static short
valid_target(int state)127726947304SEvan Yan valid_target(int state)
127826947304SEvan Yan {
127926947304SEvan Yan 	int	i;
128026947304SEvan Yan 
128126947304SEvan Yan 	for (i = 0; hpstates[i].state_str != NULL; i++)
128226947304SEvan Yan 		if (state == hpstates[i].state)
128326947304SEvan Yan 			return (hpstates[i].valid_target);
128426947304SEvan Yan 
128526947304SEvan Yan 	return (0);
128626947304SEvan Yan }
1287