#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <locale.h>
#include <libintl.h>
#include <alloca.h>
#include <getopt.h>
#include <libhotplug.h>
#include <sys/types.h>
#include <sys/sunddi.h>
#include <sys/ddi_hp.h>
#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
#endif
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);
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 }
};
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] [<path> [<connection>]]", "list", cmd_list },
{ "online <path> <port>", "online", cmd_online },
{ "offline [-f] [-q] <path> <port>", "offline", cmd_offline },
{ "enable <path> <connector>", "enable", cmd_enable },
{ "disable [-f] [-q] <path> <connector>", "disable", cmd_disable },
{ "poweron <path> <connector>", "poweron", cmd_poweron },
{ "poweroff [-f] [-q] <path> <connector>", "poweroff", cmd_poweroff },
{ "get -o <options> <path> <connector>", "get", cmd_getpriv },
{ "set -o <options> <path> <connector>", "set", cmd_setpriv }
};
static subcmd_t hidden_subcmds[] = {
{ "changestate [-f] [-q] -s <state> <path> <connection>",
"changestate", cmd_changestate }
};
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_OK 0
#define EXIT_EINVAL 1
#define EXIT_ENOENT 2
#define EXIT_FAILED 3
#define EXIT_UNAVAIL 4
static char *prog;
static char version[] = "1.0";
extern int errno;
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);
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;
}
}
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;
}
}
(void) fprintf(stderr, gettext("ERROR: %s: unknown subcommand '%s'\n"),
prog, argv[1]);
usage(NULL);
exit(EXIT_EINVAL);
finished:
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);
}
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_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);
if (path == NULL)
path = "/";
if ((root = hp_init(path, connection, flags)) == NULL) {
print_error(errno);
return (errno);
}
(void) hp_traverse(root, NULL, long_flag ? list_long_cb : list_cb);
hp_fini(root);
return (0);
}
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_common(argc, argv, usage_str);
parse_target(argc, argv, &path, &connection, usage_str);
if ((path == NULL) || (connection == NULL)) {
(void) fprintf(stderr, gettext("ERROR: too few arguments.\n"));
usage(usage_str);
return (EINVAL);
}
if ((root = hp_init(path, connection, 0)) == NULL) {
print_error(errno);
return (errno);
}
if (hp_type(root) != HP_NODE_PORT) {
(void) fprintf(stderr,
gettext("ERROR: invalid target (must be a port).\n"));
hp_fini(root);
return (EINVAL);
}
rv = hp_set_state(root, 0, DDI_HP_CN_STATE_ONLINE, &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);
}
hp_fini(root);
return (rv);
}
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_common(argc, argv, usage_str);
parse_flags(argc, argv, &flags, usage_str);
parse_target(argc, argv, &path, &connection, usage_str);
if ((path == NULL) || (connection == NULL)) {
(void) fprintf(stderr, gettext("ERROR: too few arguments.\n"));
usage(usage_str);
return (EINVAL);
}
if ((root = hp_init(path, connection, 0)) == NULL) {
print_error(errno);
return (errno);
}
if (hp_type(root) != HP_NODE_PORT) {
(void) fprintf(stderr,
gettext("ERROR: invalid target (must be a port).\n"));
hp_fini(root);
return (EINVAL);
}
rv = hp_set_state(root, flags, DDI_HP_CN_STATE_OFFLINE, &results);
print_error(rv);
if (results != NULL) {
(void) hp_traverse(results, NULL, error_cb);
hp_fini(results);
}
hp_fini(root);
return (rv);
}
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_common(argc, argv, usage_str);
parse_target(argc, argv, &path, &connection, usage_str);
if ((path == NULL) || (connection == NULL)) {
(void) fprintf(stderr, gettext("ERROR: too few arguments.\n"));
usage(usage_str);
return (EINVAL);
}
if ((root = hp_init(path, connection, 0)) == NULL) {
print_error(errno);
return (errno);
}
if (hp_type(root) != HP_NODE_CONNECTOR) {
(void) fprintf(stderr,
gettext("ERROR: invalid target (must be a connector).\n"));
hp_fini(root);
return (EINVAL);
}
rv = hp_set_state(root, 0, DDI_HP_CN_STATE_ENABLED, &results);
print_error(rv);
if (results != NULL) {
(void) hp_traverse(results, NULL, error_cb);
hp_fini(results);
}
hp_fini(root);
return (rv);
}
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_common(argc, argv, usage_str);
parse_flags(argc, argv, &flags, usage_str);
parse_target(argc, argv, &path, &connection, usage_str);
if ((path == NULL) || (connection == NULL)) {
(void) fprintf(stderr, gettext("ERROR: too few arguments.\n"));
usage(usage_str);
return (EINVAL);
}
if ((root = hp_init(path, connection, 0)) == NULL) {
print_error(errno);
return (errno);
}
if (hp_type(root) != HP_NODE_CONNECTOR) {
(void) fprintf(stderr,
gettext("ERROR: invalid target (must be a connector).\n"));
hp_fini(root);
return (EINVAL);
}
if (hp_state(root) != DDI_HP_CN_STATE_ENABLED) {
hp_fini(root);
return (0);
}
rv = hp_set_state(root, flags, DDI_HP_CN_STATE_POWERED, &results);
print_error(rv);
if (results != NULL) {
(void) hp_traverse(results, NULL, error_cb);
hp_fini(results);
}
hp_fini(root);
return (rv);
}
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_common(argc, argv, usage_str);
parse_target(argc, argv, &path, &connection, usage_str);
if ((path == NULL) || (connection == NULL)) {
(void) fprintf(stderr, gettext("ERROR: too few arguments.\n"));
usage(usage_str);
return (EINVAL);
}
if ((root = hp_init(path, connection, 0)) == NULL) {
print_error(errno);
return (errno);
}
if (hp_type(root) != HP_NODE_CONNECTOR) {
(void) fprintf(stderr,
gettext("ERROR: invalid target (must be a connector).\n"));
hp_fini(root);
return (EINVAL);
}
if (hp_state(root) >= DDI_HP_CN_STATE_POWERED) {
hp_fini(root);
return (0);
}
rv = hp_set_state(root, 0, DDI_HP_CN_STATE_POWERED, &results);
print_error(rv);
if (results != NULL) {
(void) hp_traverse(results, NULL, error_cb);
hp_fini(results);
}
hp_fini(root);
return (rv);
}
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_common(argc, argv, usage_str);
parse_flags(argc, argv, &flags, usage_str);
parse_target(argc, argv, &path, &connection, usage_str);
if ((path == NULL) || (connection == NULL)) {
(void) fprintf(stderr, gettext("ERROR: too few arguments.\n"));
usage(usage_str);
return (EINVAL);
}
if ((root = hp_init(path, connection, 0)) == NULL) {
print_error(errno);
return (errno);
}
if (hp_type(root) != HP_NODE_CONNECTOR) {
(void) fprintf(stderr,
gettext("ERROR: invalid target (must be a connector).\n"));
hp_fini(root);
return (EINVAL);
}
rv = hp_set_state(root, flags, DDI_HP_CN_STATE_PRESENT, &results);
print_error(rv);
if (results != NULL) {
(void) hp_traverse(results, NULL, error_cb);
hp_fini(results);
}
hp_fini(root);
return (rv);
}
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_common(argc, argv, usage_str);
parse_options(argc, argv, &options, usage_str);
parse_target(argc, argv, &path, &connection, usage_str);
if ((options == NULL) || (path == NULL) || (connection == NULL)) {
(void) fprintf(stderr, gettext("ERROR: too few arguments.\n"));
usage(usage_str);
return (EINVAL);
}
if ((root = hp_init(path, connection, 0)) == NULL) {
print_error(errno);
return (errno);
}
if (hp_type(root) != HP_NODE_CONNECTOR) {
(void) fprintf(stderr,
gettext("ERROR: invalid target (must be a connector).\n"));
hp_fini(root);
return (EINVAL);
}
rv = hp_get_private(root, options, &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);
}
hp_fini(root);
return (rv);
}
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_common(argc, argv, usage_str);
parse_options(argc, argv, &options, usage_str);
parse_target(argc, argv, &path, &connection, usage_str);
if ((options == NULL) || (path == NULL) || (connection == NULL)) {
(void) fprintf(stderr, gettext("ERROR: too few arguments.\n"));
usage(usage_str);
return (EINVAL);
}
if ((root = hp_init(path, connection, 0)) == NULL) {
print_error(errno);
return (errno);
}
if (hp_type(root) != HP_NODE_CONNECTOR) {
(void) fprintf(stderr,
gettext("ERROR: invalid target (must be a connector).\n"));
hp_fini(root);
return (EINVAL);
}
rv = hp_set_private(root, options, &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);
}
hp_fini(root);
return (rv);
}
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_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);
if ((state == -1) || (path == NULL) || (connection == NULL)) {
(void) fprintf(stderr, gettext("ERROR: too few arguments.\n"));
usage(usage_str);
return (EINVAL);
}
if (valid_target(state) == 0) {
(void) fprintf(stderr,
gettext("ERROR: invalid target state\n"));
return (EINVAL);
}
if ((root = hp_init(path, connection, 0)) == NULL) {
print_error(errno);
return (errno);
}
rv = hp_set_state(root, flags, state, &results);
print_error(rv);
if (results) {
(void) hp_traverse(results, NULL, error_cb);
hp_fini(results);
}
hp_fini(root);
return (rv);
}
static void
parse_common(int argc, char *argv[], const char *usage_str)
{
int opt;
extern int opterr;
extern int optind;
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;
}
}
optind = 1;
}
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;
}
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;
}
}
}
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);
}
}
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);
}
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 <subcommand> [<args>]\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);
}
static int
list_cb(hp_node_t node, void *arg)
{
hp_node_t parent;
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);
}
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);
}
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);
}
static void
print_options(const char *options)
{
char *buf, *curr, *next;
size_t len;
if ((len = strlen(options)) == 0)
return;
if ((buf = (char *)alloca(len + 1)) == NULL) {
(void) printf("%s\n", options);
return;
}
(void) strlcpy(buf, options, len + 1);
curr = buf;
do {
if ((next = strchr(curr, ',')) != NULL) {
*next = '\0';
next++;
}
(void) printf("%s\n", curr);
} while ((curr = next) != NULL);
}
static void
print_error(int error)
{
switch (error) {
case 0:
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;
}
}
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);
}
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);
}
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);
}