/*
* 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
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <locale.h>
#include <libintl.h>
#include <alloca.h>
#include <getopt.h>
#include <libhotplug.h>
#if !defined(TEXT_DOMAIN) /* should be defined by cc -D */
#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_long_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;
{ DDI_HP_CN_STATE_EMPTY, "EMPTY", 0 },
{ DDI_HP_CN_STATE_PORT_EMPTY, "PORT-EMPTY", 0 },
{ DDI_HP_CN_STATE_ATTACHED, "ATTACHED", 0 },
{ DDI_HP_CN_STATE_MAINTENANCE, "MAINTENANCE", 0 },
{ 0, 0, 0 }
};
/*
* Define tables of supported subcommands.
*/
typedef struct {
char *usage_str;
char *cmd_str;
} subcmd_t;
};
{ "changestate [-f] [-q] -s <state> <path> <connection>",
"changestate", cmd_changestate }
};
/*
* Define tables of command line options.
*/
{ 0, 0, 0, 0 }
};
{ 0, 0, 0, 0 }
};
{ 0, 0, 0, 0 }
};
{ 0, 0, 0, 0 }
};
{ 0, 0, 0, 0 }
};
/*
* Define exit codes.
*/
#define EXIT_OK 0
/*
* Global variables.
*/
static char *prog;
extern int errno;
/*
* main()
*
* The main routine determines which subcommand is used,
* and dispatches control to the corresponding function.
*/
int
{
int i, rv;
(void) textdomain(TEXT_DOMAIN);
else
prog++;
if (argc < 2) {
return (EXIT_EINVAL);
}
/* Check the list of defined subcommands. */
goto finished;
}
}
/* Check the list of hidden subcommands. */
for (i = 0; i < (sizeof (hidden_subcmds) / sizeof (subcmd_t)); i++) {
hidden_subcmds[i].usage_str);
goto finished;
}
}
/* No matching subcommand found. */
/* 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
{
int flags = 0;
int opt;
/* Parse command line options */
switch (opt) {
case 'l':
break;
case 'v':
flags |= HPINFOUSAGE;
break;
default:
break;
}
}
/* Default path is "/" */
path = "/";
/* Get hotplug information snapshot */
return (errno);
}
/* Display hotplug information */
/* Discard hotplug information snapshot */
return (0);
}
/*
* cmd_online()
*
* Subcommand to online a hotplug port.
*/
static int
{
int rv;
/* Parse command line options */
/* Path and connection are required */
return (EINVAL);
}
/* Get hotplug information snapshot */
return (errno);
}
/* Verify target is a port */
gettext("ERROR: invalid target (must be a port).\n"));
return (EINVAL);
}
/* Do state change */
/* Display results */
"drivers or other internal errors.\n"));
} else if (rv != 0) {
}
}
/* Discard hotplug information snapshot */
return (rv);
}
/*
* cmd_offline()
*
* Subcommand to offline a hotplug port.
*/
static int
{
int flags = 0;
int rv;
/* Parse command line options */
/* Path and connection are required */
return (EINVAL);
}
/* Get hotplug information snapshot */
return (errno);
}
/* Verify target is a port */
gettext("ERROR: invalid target (must be a port).\n"));
return (EINVAL);
}
/* Do state change */
/* Display results */
}
/* Discard hotplug information snapshot */
return (rv);
}
/*
* cmd_enable()
*
* Subcommand to enable a hotplug connector.
*/
static int
{
int rv;
/* Parse command line options */
/* Path and connection are required */
return (EINVAL);
}
/* Get hotplug information snapshot */
return (errno);
}
/* Verify target is a connector */
gettext("ERROR: invalid target (must be a connector).\n"));
return (EINVAL);
}
/* Do state change */
/* Display results */
}
/* Discard hotplug information snapshot */
return (rv);
}
/*
* cmd_disable()
*
* Subcommand to disable a hotplug connector.
*/
static int
{
int flags = 0;
int rv;
/* Parse command line options */
/* Path and connection are required */
return (EINVAL);
}
/* Get hotplug information snapshot */
return (errno);
}
/* Verify target is a connector */
gettext("ERROR: invalid target (must be a connector).\n"));
return (EINVAL);
}
/*
* Do nothing unless the connector is in the ENABLED state.
* Otherwise this subcommand becomes an alias for 'poweron.'
*/
return (0);
}
/* Do state change */
/* Display results */
}
/* Discard hotplug information snapshot */
return (rv);
}
/*
* cmd_poweron()
*
* Subcommand to power on a hotplug connector.
*/
static int
{
int rv;
/* Parse command line options */
/* Path and connection are required */
return (EINVAL);
}
/* Get hotplug information snapshot */
return (errno);
}
/* Verify target is a connector */
gettext("ERROR: invalid target (must be a connector).\n"));
return (EINVAL);
}
/*
* Do nothing if the connector is already powered.
* Otherwise this subcommand becomes an alias for 'disable.'
*/
return (0);
}
/* Do state change */
/* Display results */
}
/* Discard hotplug information snapshot */
return (rv);
}
/*
* cmd_poweroff()
*
* Subcommand to power off a hotplug connector.
*/
static int
{
int flags = 0;
int rv;
/* Parse command line options */
/* Path and connection are required */
return (EINVAL);
}
/* Get hotplug information snapshot */
return (errno);
}
/* Verify target is a connector */
gettext("ERROR: invalid target (must be a connector).\n"));
return (EINVAL);
}
/* Do state change */
/* Display results */
}
/* Discard hotplug information snapshot */
return (rv);
}
/*
* cmd_getpriv()
*
* Subcommand to get and display bus private options.
*/
static int
{
int rv;
/* Parse command line options */
/* Options, path, and connection are all required */
return (EINVAL);
}
/* Get hotplug information snapshot */
return (errno);
}
/* Verify target is a connector */
gettext("ERROR: invalid target (must be a connector).\n"));
return (EINVAL);
}
/* Do the operation */
/* Display results */
gettext("ERROR: unsupported property name or value.\n"));
gettext("(Properties may depend upon connector state.)\n"));
} else if (rv != 0) {
}
}
/* Discard hotplug information snapshot */
return (rv);
}
/*
* cmd_setpriv()
*
* Subcommand to set bus private options.
*/
static int
{
int rv;
/* Parse command line options */
/* Options, path, and connection are all required */
return (EINVAL);
}
/* Get hotplug information snapshot */
return (errno);
}
/* Verify target is a connector */
gettext("ERROR: invalid target (must be a connector).\n"));
return (EINVAL);
}
/* Do the operation */
/* Display results */
gettext("ERROR: unsupported property name or value.\n"));
gettext("(Properties may depend upon connector state.)\n"));
} else if (rv != 0) {
}
}
/* Discard hotplug information snapshot */
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
{
int flags = 0;
/* Parse command line options */
NULL)) != -1) {
switch (opt) {
case 'f':
break;
case 'q':
break;
case 's':
(void) printf("ERROR: invalid target state\n");
return (EINVAL);
}
break;
default:
break;
}
}
/* State, path, and connection are all required */
return (EINVAL);
}
/* Check that target state is valid */
if (valid_target(state) == 0) {
gettext("ERROR: invalid target state\n"));
return (EINVAL);
}
/* Get hotplug information snapshot */
return (errno);
}
/* Initiate state change operation on root of snapshot */
/* Display results */
if (results) {
}
/* Discard hotplug information snapshot */
return (rv);
}
/*
* parse_common()
*
* Parse command line options that are common to the
* entire program, and to each of its subcommands.
*/
static void
{
int opt;
extern int opterr;
extern int optind;
/* Turn off error reporting */
opterr = 0;
switch (opt) {
case '?':
if (optopt == '?') {
exit(0);
}
break;
case 'V':
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
{
int opt;
int flags = 0;
switch (opt) {
case 'f':
break;
case 'q':
break;
default:
break;
}
}
}
/*
* parse_options()
*
* Parse command line options common to the bus private set and
* get subcommands.
*/
static void
{
int opt;
NULL)) != -1) {
switch (opt) {
case 'o':
break;
default:
break;
}
}
}
/*
* parse_target()
*
* Parse the target path and connection name from the command line.
*/
static void
const char *usage_str)
{
extern int optind;
}
}
/*
* bad_option()
*
* Routine to handle bad command line options.
*/
static void
{
switch (opt) {
case ':':
gettext("ERROR: option '%c' requires an argument.\n"),
optopt);
break;
default:
if (optopt == '?') {
}
break;
}
}
/*
* usage()
*
* Display general usage of the command. Including
* the usage synopsis of each defined subcommand.
*/
static void
{
int i;
return;
}
prog);
}
/*
* list_cb()
*
* Callback function for hp_traverse(), to display nodes
* of a hotplug information snapshot. (Short version.)
*/
/*ARGSUSED*/
static int
{
/* Indent */
(void) printf(" ");
case HP_NODE_DEVICE:
break;
case HP_NODE_CONNECTOR:
(void) printf("\n");
break;
case HP_NODE_PORT:
(void) printf("\n");
break;
case HP_NODE_USAGE:
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
{
return (HP_WALK_CONTINUE);
}
case HP_NODE_CONNECTOR:
break;
case HP_NODE_PORT:
break;
case HP_NODE_USAGE:
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
{
char *usage_str;
return (HP_WALK_CONTINUE);
}
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
{
/* Do nothing if options string is empty */
return;
/* To avoid modifying the input string, make a copy on the stack */
return;
}
do {
*next = '\0';
next++;
}
}
/*
* print_error()
*
* Common routine to print error numbers in an appropriate way.
* Prints nothing if error code is 0.
*/
static void
{
switch (error) {
case 0:
/* No error */
return;
case EACCES:
gettext("ERROR: operation not authorized.\n"));
break;
case EBADF:
gettext("ERROR: hotplug service is not available.\n"));
break;
case EBUSY:
gettext("ERROR: devices or resources are busy.\n"));
break;
case EEXIST:
gettext("ERROR: resource already exists.\n"));
break;
case EFAULT:
gettext("ERROR: internal failure in hotplug service.\n"));
break;
case EINVAL:
gettext("ERROR: invalid arguments.\n"));
break;
case ENOENT:
gettext("ERROR: there are no connections to display.\n"));
gettext("(See hotplug(1m) for more information.)\n"));
break;
case ENXIO:
gettext("ERROR: no such path or connection.\n"));
break;
case ENOMEM:
gettext("ERROR: not enough memory.\n"));
break;
case ENOTSUP:
gettext("ERROR: operation not supported.\n"));
break;
case EIO:
gettext("ERROR: hardware or driver specific failure.\n"));
break;
default:
break;
}
}
/*
* state_atoi()
*
* Convert a hotplug state from a string to an integer.
*/
static int
{
int i;
return (-1);
}
/*
* state_itoa()
*
* Convert a hotplug state from an integer to a string.
*/
static char *
{
int i;
return (unknown);
}
/*
* valid_target()
*
* Check if a state is a valid target for a changestate command.
*/
static short
{
int i;
return (hpstates[i].valid_target);
return (0);
}