/* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* 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] "; static char l_tgt[] = "srptadm list-target []"; /* 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; int 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"); /* FALLTHROUGH */ 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); }