/*
* 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 (c) 2010, Oracle and/or its affiliates. All rights reserved.
*/
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <getopt.h>
#include <strings.h>
#include <ctype.h>
#include <libnvpair.h>
#include <libintl.h>
#include <libgen.h>
#include <pwd.h>
#include <auth_attr.h>
#include <secdb.h>
#include <libscf.h>
#include <limits.h>
#include <locale.h>
#include <dirent.h>
#include <libstmf.h>
#include <libsrpt.h>
/* SMF service info */
#define STMF_SVC "svc:/system/stmf:default"
#define STMF_STALE(ret) {\
if (ret == STMF_ERROR_PROV_DATA_STALE) {\
(void) fprintf(stderr, "%s\n",\
gettext("Configuration changed during processing. "\
"Check the configuration, then retry this command "\
"if appropriate."));\
}\
}
#define SRPTADM_CHKAUTH(sec) {\
if (!chkauthattr(sec, srptadm_uname)) {\
(void) fprintf(stderr,\
gettext("Error, operation requires authorization %s"),\
sec);\
(void) fprintf(stderr, "\n");\
return (1);\
}\
}
#define PROPS_FORMAT " %-20s: "
static struct option srptadm_long[] = {
{"enable", no_argument, NULL, 'e'},
{"disable", no_argument, NULL, 'd'},
{"reset", no_argument, NULL, 'r'},
{"help", no_argument, NULL, '?'},
{"help", no_argument, NULL, 'h'},
{NULL, 0, NULL, 0}
};
static char m_def[] = "srptadm modify-defaults [-e] [-d]";
static char l_def[] = "srptadm list-defaults";
static char s_tgt[] = "srptadm modify-target [-e] [-d] [-r] <hca>";
static char l_tgt[] = "srptadm list-target [<hca>]";
/* keep the order of this enum in the same order as the 'subcmds' struct */
typedef enum {
MODIFY_DEFAULT,
LIST_DEFAULT,
MODIFY_TARGET,
LIST_TARGET,
NULL_SUBCMD /* must always be last! */
} srptadm_sub_t;
typedef struct {
char *name;
char *shortopts;
char *usemsg;
} srptadm_subcmds_t;
static srptadm_subcmds_t subcmds[] = {
{"modify-defaults", "edh?", m_def},
{"list-defaults", "h?", l_def},
{"modify-target", "edrh?", s_tgt},
{"list-target", "h?", l_tgt},
{NULL, ":h?", NULL},
};
/* used for checking if user is authorized */
static char *srptadm_uname = NULL;
/* prototypes */
static int get_local_hcas(char **hcaArray, int count);
static int print_target_props(char *hca);
static int list_target(char *hca);
static int disable_target(char *hca);
static int reset_target(char *hca);
static int list_defaults(void);
static int enable_target(char *hca);
static int set_default_state(boolean_t enabled);
int
main(int argc, char *argv[])
{
int ret = 0;
int idx = NULL_SUBCMD;
char c;
int newargc = argc;
char **newargv = NULL;
char *objp;
int srptind = 0;
struct passwd *pwd = NULL;
char *smfstate = NULL;
boolean_t reset = B_FALSE;
int dflag = 0;
int eflag = 0;
(void) setlocale(LC_ALL, "");
(void) textdomain(TEXT_DOMAIN);
if (argc < 2) {
ret = 1;
goto usage_error;
}
for (idx = 0; subcmds[idx].name != NULL; idx++) {
if (strcmp(argv[1], subcmds[idx].name) == 0) {
break;
}
}
/* get the caller's user name for subsequent chkauthattr() calls */
pwd = getpwuid(getuid());
if (pwd == NULL) {
(void) fprintf(stderr, "%s\n",
gettext("Could not determine callers user name."));
return (1);
}
srptadm_uname = strdup(pwd->pw_name);
/* increment past command & subcommand */
newargc--;
newargv = &(argv[1]);
while ((ret == 0) && (newargv)) {
c = getopt_long(newargc, newargv, subcmds[idx].shortopts,
srptadm_long, &srptind);
if (c == -1) {
break;
}
switch (c) {
case 0:
/* flag set by getopt */
break;
case 'd':
dflag++;
break;
case 'e':
eflag++;
break;
case 'r':
reset = B_TRUE;
break;
case '?':
/*
* '?' is returned for both unrecognized
* options and if explicitly provided on
* the command line. The latter should
* be handled the same as -h.
*/
if (strcmp(newargv[optind-1], "-?") != 0) {
(void) fprintf(stderr,
gettext("Unrecognized option %s"),
newargv[optind-1]);
(void) fprintf(stderr, "\n");
ret = 1;
}
goto usage_error;
case 'h':
goto usage_error;
case ':':
(void) fprintf(stderr,
gettext("Option %s requires an operand."),
newargv[optind-1]);
(void) fprintf(stderr, "\n");
/* fall through to default */
default:
ret = 1;
break;
}
}
if (ret != 0) {
goto usage_error;
}
/* after getopt() to allow handling of -h option */
if ((srptadm_sub_t)idx == NULL_SUBCMD) {
(void) fprintf(stderr, "%s\n",
gettext("Error, no subcommand specified"));
ret = 1;
goto usage_error;
}
newargc -= optind;
if (newargc == 0) {
newargv = NULL;
objp = NULL;
} else {
newargv = &(newargv[optind]);
objp = newargv[0];
}
if (objp == NULL) {
switch ((srptadm_sub_t)idx) {
case MODIFY_TARGET:
/* These subcommands need operands */
ret = 1;
goto usage_error;
default:
break;
}
}
if (newargc > 1) {
switch ((srptadm_sub_t)idx) {
case MODIFY_TARGET:
case LIST_TARGET:
/* These subcommands should have at most one operand */
ret = 1;
goto usage_error;
default:
break;
}
}
/*
* Make sure STMF service is enabled before proceeding.
*/
smfstate = smf_get_state(STMF_SVC);
if (!smfstate ||
(strcmp(smfstate, SCF_STATE_STRING_ONLINE) != 0)) {
(void) fprintf(stderr, "%s\n",
gettext("The STMF service must be online "
"before running this command."));
(void) fprintf(stderr,
gettext("Use 'svcadm enable -r %s'"), STMF_SVC);
(void) fprintf(stderr, "\n");
(void) fprintf(stderr, "%s\n",
gettext("to enable the service and its prerequisite "
"services and/or"));
(void) fprintf(stderr,
gettext("'svcs -x %s' to determine why it is not online."),
STMF_SVC);
(void) fprintf(stderr, "\n");
return (1);
}
switch ((srptadm_sub_t)idx) {
case MODIFY_DEFAULT:
if (eflag) {
ret = set_default_state(B_TRUE);
} else if (dflag) {
ret = set_default_state(B_FALSE);
} else {
ret = 1;
goto usage_error;
}
break;
case LIST_DEFAULT:
ret = list_defaults();
break;
case MODIFY_TARGET:
if (reset) {
ret = reset_target(objp);
} else if (eflag) {
ret = enable_target(objp);
} else if (dflag) {
ret = disable_target(objp);
} else {
ret = 1;
goto usage_error;
}
break;
case LIST_TARGET:
ret = list_target(objp);
break;
default:
ret = 1;
goto usage_error;
}
if (ret != 0) {
(void) fprintf(stderr,
gettext("srptadm %s failed with error %d"),
subcmds[idx].name, ret);
(void) fprintf(stderr, "\n");
}
return (ret);
usage_error:
if (subcmds[idx].name) {
(void) printf("%s\n", gettext(subcmds[idx].usemsg));
} else {
/* overall usage */
(void) printf("%s\n\n", gettext("srptadm usage:"));
for (idx = 0; subcmds[idx].name != NULL; idx++) {
if (!subcmds[idx].usemsg) {
continue;
}
(void) printf("\t%s\n", gettext(subcmds[idx].usemsg));
}
}
return (ret);
}
static int
set_default_state(boolean_t enabled)
{
int ret;
char *sec = "solaris.smf.modify.stmf";
SRPTADM_CHKAUTH(sec);
ret = srpt_SetDefaultState(enabled);
return (ret);
}
static int
enable_target(char *hca)
{
int ret;
char *sec = "solaris.smf.modify.stmf";
SRPTADM_CHKAUTH(sec);
ret = srpt_SetTargetState(hca, B_TRUE);
return (ret);
}
static int
disable_target(char *hca)
{
int ret;
char *sec = "solaris.smf.modify.stmf";
SRPTADM_CHKAUTH(sec);
ret = srpt_SetTargetState(hca, B_FALSE);
return (ret);
}
static int
reset_target(char *hca)
{
int ret;
char *sec = "solaris.smf.modify.stmf";
SRPTADM_CHKAUTH(sec);
ret = srpt_ResetTarget(hca);
return (ret);
}
static int
list_defaults(void)
{
int ret;
char *sec = "solaris.smf.read.stmf";
boolean_t enabled;
SRPTADM_CHKAUTH(sec);
/* only state set as default for now */
ret = srpt_GetDefaultState(&enabled);
if (ret == 0) {
(void) printf("%s:\n\n",
gettext("SRP Target Service Default Properties"));
(void) printf(" %s:\t",
gettext("Target creation enabled by default"));
if (enabled) {
(void) printf("%s\n", gettext("true"));
} else {
(void) printf("%s\n", gettext("false"));
}
}
return (ret);
}
static int
list_target(char *hca)
{
int ret;
char *sec = "solaris.smf.read.stmf";
char *hcaArr[1024]; /* way bigger than we'll ever see */
int i;
SRPTADM_CHKAUTH(sec);
if (hca != NULL) {
ret = print_target_props(hca);
return (ret);
}
/* get list of HCAs configured on this system, from /dev/cfg */
(void) memset(&hcaArr, 0, 1024 * sizeof (char *));
ret = get_local_hcas(hcaArr, sizeof (hcaArr));
if (ret == ETOOMANYREFS) {
(void) fprintf(stderr, "Internal error: too many HCAs\n");
goto done;
} else if (ret != 0) {
(void) fprintf(stderr, "Error getting list of HCAs: %d\n", ret);
goto done;
}
for (i = 0; i < 1024; i++) {
if (hcaArr[i] == NULL) {
break;
}
ret = print_target_props(hcaArr[i]);
}
done:
for (i = 0; i < 1024; i++) {
if (hcaArr[i] == NULL) {
break;
}
free(hcaArr[i]);
}
return (ret);
}
static int
print_target_props(char *hca)
{
int ret;
boolean_t enabled;
char buf[32];
char euibuf[64];
uint64_t hcaguid;
stmfDevid devid;
stmfTargetProperties props;
char *state;
ret = srpt_NormalizeGuid(hca, buf, sizeof (buf), &hcaguid);
if (ret != 0) {
(void) fprintf(stderr, "Invalid target HCA: %s\n",
hca);
return (ret);
}
/* only property set is enabled */
ret = srpt_GetTargetState(buf, &enabled);
if (ret != 0) {
(void) fprintf(stderr,
"Could not get enabled state for %s: %d\n",
buf, ret);
return (ret);
}
(void) printf("Target HCA %s:\n", buf);
(void) printf(PROPS_FORMAT, gettext("Enabled"));
if (enabled) {
(void) printf("%s\n", gettext("true"));
} else {
(void) printf("%s\n", gettext("false"));
}
state = "-";
(void) snprintf(euibuf, sizeof (euibuf), "eui.%016llX", hcaguid);
ret = stmfDevidFromIscsiName(euibuf, &devid);
if (ret == STMF_STATUS_SUCCESS) {
ret = stmfGetTargetProperties(&devid, &props);
if (ret == STMF_STATUS_SUCCESS) {
if (props.status == STMF_TARGET_PORT_ONLINE) {
state = "online";
} else {
state = "offline";
}
}
}
(void) printf(PROPS_FORMAT, gettext("SRP Target Name"));
(void) printf("%s\n", euibuf);
(void) printf(PROPS_FORMAT, gettext("Operational Status"));
(void) printf("%s\n", state);
(void) printf("\n");
return (0);
}
static int
get_local_hcas(char **hcaArray, int count)
{
int ret = 0;
char *cfgdir = "/dev/cfg";
DIR *dirp = NULL;
struct dirent *entry;
int idx = 0;
char *bufp;
if ((hcaArray == NULL) || (count == 0)) {
return (EINVAL);
}
dirp = opendir(cfgdir);
if (dirp == NULL) {
ret = errno;
(void) fprintf(stderr, "Could not open %s: errno %d\n",
cfgdir, ret);
return (ret);
}
while ((entry = readdir(dirp)) != NULL) {
bufp = &entry->d_name[0];
if (strncmp(bufp, "hca:", 4) != 0) {
continue;
}
bufp += 4;
hcaArray[idx] = strdup(bufp);
if (hcaArray[idx] == NULL) {
ret = ENOMEM;
break;
}
idx++;
if (idx >= count) {
ret = ETOOMANYREFS;
break;
}
}
return (ret);
}