main.c revision 36c5fee33fa8b822175d410202aebcf592c8d342
/*
* 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 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/param.h>
#include <unistd.h>
#include <libintl.h>
#include <limits.h>
#include <string.h>
#include <syslog.h>
#include <errno.h>
#include <sys/stat.h>
#include <zone.h>
#include "cmdparse.h"
#include "xml.h"
#include "helper.h"
#define CREATE SUBCOMMAND(0)
#define LIST SUBCOMMAND(1)
#define MODIFY SUBCOMMAND(2)
#define DELETE SUBCOMMAND(3)
#define SHOW SUBCOMMAND(4)
#define TARGET OBJECT(0)
#define INITIATOR OBJECT(1)
#define ADMIN OBJECT(2)
#define TPGT OBJECT(3)
#define STATS OBJECT(4)
#define VERSION_STRING_MAX_LEN 10
#define MAX_IPADDRESS_LEN 128
/*
* Version number:
* MAJOR - This should only change when there is an incompatible change made
* to the interfaces or the output.
*
* MINOR - This should change whenever there is a new command or new feature
* with no incompatible change.
*/
#define VERSION_STRING_MAJOR "1"
#define VERSION_STRING_MINOR "0"
#define OPT_ENABLE "enable"
#define OPT_DISABLE "disable"
#define OPT_TRUE "true"
#define OPT_FALSE "false"
/* subcommand functions */
static int createFunc(int, char **, int, cmdOptions_t *, void *);
static int listFunc(int, char **, int, cmdOptions_t *, void *);
static int modifyFunc(int, char **, int, cmdOptions_t *, void *);
static int deleteFunc(int, char **, int, cmdOptions_t *, void *);
static int showFunc(int, char **, int, cmdOptions_t *, void *);
/* object functions per subcommand */
static int createTarget(int, char *[], cmdOptions_t *);
static int createInitiator(int, char *[], cmdOptions_t *);
static int createTpgt(int, char *[], cmdOptions_t *);
static int modifyTarget(int, char *[], cmdOptions_t *);
static int modifyInitiator(int, char *[], cmdOptions_t *);
static int modifyTpgt(int, char *[], cmdOptions_t *);
static int modifyAdmin(int, char *[], cmdOptions_t *);
static int deleteTarget(int, char *[], cmdOptions_t *);
static int deleteInitiator(int, char *[], cmdOptions_t *);
static int deleteTpgt(int, char *[], cmdOptions_t *);
static int listTarget(int, char *[], cmdOptions_t *);
static int listInitiator(int, char *[], cmdOptions_t *);
static int listTpgt(int, char *[], cmdOptions_t *);
static int showAdmin(int, char *[], cmdOptions_t *);
static int showStats(int, char *[], cmdOptions_t *);
/* globals */
char *cmdName;
static char *hostname = NULL;
/*
* Add new options here
*/
optionTbl_t longOptions[] = {
{"size", required_arg, 'z', "size k/m/g/t"},
{"type", required_arg, 't', "disk/tape/osd/raw"},
{"lun", required_arg, 'u', "number"},
{"alias", required_arg, 'a', "value"},
{"backing-store", required_arg, 'b', "pathname"},
{"tpgt", required_arg, 'p', "tpgt number"},
{"acl", required_arg, 'l', "local initiator"},
{"maxrecv", required_arg, 'm', "max recv data segment length"},
{"chap-secret", no_arg, 'C', NULL},
{"chap-name", required_arg, 'H', "chap username"},
{"iqn", required_arg, 'n', "iSCSI node name"},
{"ip-address", required_arg, 'i', "ip address"},
{"base-directory", required_arg, 'd', "directory"},
{"radius-access", required_arg, 'R', "enable/disable"},
{"radius-server", required_arg, 'r', "hostname[:port]"},
{"radius-secret", no_arg, 'P', NULL},
{"isns-access", required_arg, 'S', "enable/disable"},
{"fast-write-ack", required_arg, 'f', "enable/disable"},
{"verbose", no_arg, 'v', NULL},
{"interval", required_arg, 'I', "seconds"},
{"count", required_arg, 'N', "number"},
{"all", no_arg, 'A', NULL},
{NULL, 0, 0, 0}
};
/*
* Add new subcommands here
*/
subcommand_t subcommands[] = {
{"create", CREATE, createFunc},
{"list", LIST, listFunc},
{"modify", MODIFY, modifyFunc},
{"delete", DELETE, deleteFunc},
{"show", SHOW, showFunc},
{NULL, 0, NULL}
};
/*
* Add objects here
*/
object_t objects[] = {
{"target", TARGET},
{"initiator", INITIATOR},
{"admin", ADMIN},
{"tpgt", TPGT},
{"stats", STATS},
{NULL, 0}
};
/*
* Rules for subcommands and objects
* ReqiredOp, OptioalOp, NoOp, InvalidOp, MultiOp
*/
objectRules_t objectRules[] = {
/*
* create/modify/delete subcmd requires an operand
* list subcmd optionally requires an operand
* no subcmd requires no operand
* no subcmd is invalid for this operand
* no subcmd can accept multiple operands
*/
{TARGET, CREATE|MODIFY|DELETE, LIST, 0, SHOW, 0, "local-target"},
/*
* create/modify/delete subcmd requires an operand
* list subcmd optionally requires an operand
* no subcmd requires no operand
* no subcmd is invalid for this operand
* no subcmd can accept multiple operands
*/
{INITIATOR, CREATE|MODIFY|DELETE, LIST, 0, SHOW, 0, "local-initiator"},
/*
* no subcmd requires an operand
* no subcmd optionally requires an operand
* modify/list subcmd requires no operand
* create/delete subcmd are invlaid for this operand
* no subcmd can accept multiple operands
*/
{ADMIN, 0, 0, MODIFY|SHOW, CREATE|DELETE|LIST, 0, NULL},
/*
* create/modify/delete subcmd requires an operand
* list subcmd optionally requires an operand
* no subcmd requires no operand
* no subcmd is invalid for this operand
* no subcmd can accept multiple operands
*/
{TPGT, CREATE|MODIFY|DELETE, LIST, 0, SHOW, 0, "local-tpgt"},
/*
* no subcmd requires an operand
* list subcmd optionally requires an operand
* no subcmd requires no operand
* create/delete/modify subcmd are invalid for this operand
* no subcmd can accept multiple operands
*/
{STATS, 0, SHOW, 0, CREATE|MODIFY|DELETE|LIST, 0, "local-target"},
{0, 0, 0, 0, 0, NULL}
};
/*
* list of objects, subcommands, valid short options, required flag and
* exclusive option string
*
* If it's not here, there are no options for that object.
*/
optionRules_t optionRules[] = {
{TARGET, CREATE, "tuzab", B_TRUE, NULL},
{TARGET, MODIFY, "plamzu", B_TRUE, NULL},
{TARGET, DELETE, "ulp", B_TRUE, NULL},
{TARGET, LIST, "v", B_FALSE, NULL},
{INITIATOR, CREATE, "n", B_TRUE, NULL},
{INITIATOR, MODIFY, "CH", B_TRUE, NULL},
{INITIATOR, DELETE, "A", B_TRUE, NULL},
{INITIATOR, LIST, "v", B_FALSE, NULL},
{TPGT, MODIFY, "i", B_TRUE, NULL},
{TPGT, DELETE, "Ai", B_TRUE, NULL},
{TPGT, LIST, "v", B_FALSE, NULL},
{ADMIN, MODIFY, "dHCRrPSf", B_TRUE, NULL},
{STATS, SHOW, "vIN", B_FALSE, NULL},
};
/*ARGSUSED*/
static int
createFunc(int operandLen, char *operand[], int object, cmdOptions_t *options,
void *addArgs)
{
int ret;
switch (object) {
case TARGET:
ret = createTarget(operandLen, operand, options);
break;
case INITIATOR:
ret = createInitiator(operandLen, operand, options);
break;
case TPGT:
ret = createTpgt(operandLen, operand, options);
break;
default:
(void) fprintf(stderr, "%s: %s\n",
cmdName, gettext("unknown object"));
ret = 1;
break;
}
return (ret);
}
/*ARGSUSED*/
static int
listFunc(int operandLen, char *operand[], int object, cmdOptions_t *options,
void *addArgs)
{
int ret;
switch (object) {
case TARGET:
ret = listTarget(operandLen, operand, options);
break;
case INITIATOR:
ret = listInitiator(operandLen, operand, options);
break;
case TPGT:
ret = listTpgt(operandLen, operand, options);
break;
default:
(void) fprintf(stderr, "%s: %s\n",
cmdName, gettext("unknown object"));
ret = 1;
break;
}
return (ret);
}
/*ARGSUSED*/
static int
showFunc(int operandLen, char *operand[], int object, cmdOptions_t *options,
void *addArgs)
{
int ret;
switch (object) {
case STATS:
ret = showStats(operandLen, operand, options);
break;
case ADMIN:
ret = showAdmin(operandLen, operand, options);
break;
default:
(void) fprintf(stderr, "%s: %s\n",
cmdName, gettext("unknown object"));
ret = 1;
break;
}
return (ret);
}
/*ARGSUSED*/
static int
modifyFunc(int operandLen, char *operand[], int object, cmdOptions_t *options,
void *addArgs)
{
int ret;
switch (object) {
case TARGET:
ret = modifyTarget(operandLen, operand, options);
break;
case INITIATOR:
ret = modifyInitiator(operandLen, operand, options);
break;
case TPGT:
ret = modifyTpgt(operandLen, operand, options);
break;
case ADMIN:
ret = modifyAdmin(operandLen, operand, options);
break;
default:
(void) fprintf(stderr, "%s: %s\n",
cmdName, gettext("unknown object"));
ret = 1;
break;
}
return (ret);
}
/*ARGSUSED*/
static int
deleteFunc(int operandLen, char *operand[], int object, cmdOptions_t *options,
void *addArgs)
{
int ret;
switch (object) {
case TARGET:
ret = deleteTarget(operandLen, operand, options);
break;
case INITIATOR:
ret = deleteInitiator(operandLen, operand, options);
break;
case TPGT:
ret = deleteTpgt(operandLen, operand, options);
break;
default:
(void) fprintf(stderr, "%s: %s\n",
cmdName, gettext("unknown object"));
ret = 1;
break;
}
return (ret);
}
static int
formatErrString(xml_node_t *node)
{
int code = 0,
rtn = 0;
char *msg = NULL;
if ((strcmp(node->x_name, XML_ELEMENT_ERROR) == 0) &&
(xml_find_value_int(node, XML_ELEMENT_CODE, &code) == B_TRUE) &&
(xml_find_value_str(node, XML_ELEMENT_MESSAGE, &msg) == B_TRUE)) {
/*
* 1000 is the success code, so we don't need to display
* the success message.
*/
if (code != 1000) {
(void) fprintf(stderr, "%s: %s %s\n",
cmdName, gettext("Error"), msg);
rtn = 1;
}
} else {
(void) fprintf(stderr, "%s: %s\n", cmdName,
gettext("Bad XML response"));
rtn = 1;
}
if (msg)
free(msg);
return (rtn);
}
/*ARGSUSED*/
static int
createTarget(int operandLen, char *operand[], cmdOptions_t *options)
{
char *first_str = NULL;
xml_node_t *node;
cmdOptions_t *optionList = options;
if (operand == NULL)
return (1);
buf_add_tag(&first_str, "create", Tag_Start);
buf_add_tag(&first_str, XML_ELEMENT_TARG, Tag_Start);
xml_add_tag(&first_str, XML_ELEMENT_NAME, operand[0]);
for (; optionList->optval; optionList++) {
switch (optionList->optval) {
case 't': /* type */
if ((strcmp(optionList->optarg, "disk")) &&
(strcmp(optionList->optarg, "tape")) &&
(strcmp(optionList->optarg, "raw")) &&
(strcmp(optionList->optarg, "osd"))) {
(void) fprintf(stderr, "%s: %c: %s\n",
cmdName, optionList->optval,
gettext("unknown type"));
free(first_str);
return (1);
} else {
xml_add_tag(&first_str,
XML_ELEMENT_TYPE,
optionList->optarg);
}
break;
case 'z': /* size */
xml_add_tag(&first_str, XML_ELEMENT_SIZE,
optionList->optarg);
break;
case 'u': /* lun number */
xml_add_tag(&first_str, XML_ELEMENT_LUN,
optionList->optarg);
break;
case 'a': /* alias */
xml_add_tag(&first_str, XML_ELEMENT_ALIAS,
optionList->optarg);
break;
case 'b': /* backing store */
xml_add_tag(&first_str, XML_ELEMENT_BACK,
optionList->optarg);
break;
default:
(void) fprintf(stderr, "%s: %c: %s\n",
cmdName, optionList->optval,
gettext("unknown option"));
free(first_str);
return (1);
}
}
buf_add_tag(&first_str, XML_ELEMENT_TARG, Tag_End);
buf_add_tag(&first_str, "create", Tag_End);
node = send_data(hostname, first_str);
free(first_str);
return (formatErrString(node));
}
/*ARGSUSED*/
static int
createInitiator(int operandLen, char *operand[], cmdOptions_t *options)
{
char *first_str = NULL;
xml_node_t *node;
cmdOptions_t *optionList = options;
if (operand == NULL)
return (1);
if (options == NULL)
return (1);
buf_add_tag(&first_str, "create", Tag_Start);
buf_add_tag(&first_str, XML_ELEMENT_INIT, Tag_Start);
xml_add_tag(&first_str, XML_ELEMENT_NAME, operand[0]);
switch (optionList->optval) {
case 'n': /* iqn */
xml_add_tag(&first_str, XML_ELEMENT_INAME, optionList->optarg);
break;
default:
(void) fprintf(stderr, "%s: %c: %s\n",
cmdName, optionList->optval,
gettext("unknown option"));
free(first_str);
return (1);
}
buf_add_tag(&first_str, XML_ELEMENT_INIT, Tag_End);
buf_add_tag(&first_str, "create", Tag_End);
node = send_data(hostname, first_str);
free(first_str);
return (formatErrString(node));
}
/*ARGSUSED*/
static int
createTpgt(int operandLen, char *operand[], cmdOptions_t *options)
{
char *first_str = NULL;
xml_node_t *node;
if (operand == NULL)
return (1);
buf_add_tag(&first_str, "create", Tag_Start);
buf_add_tag(&first_str, XML_ELEMENT_TPGT, Tag_Start);
xml_add_tag(&first_str, XML_ELEMENT_NAME, operand[0]);
buf_add_tag(&first_str, XML_ELEMENT_TPGT, Tag_End);
buf_add_tag(&first_str, "create", Tag_End);
node = send_data(hostname, first_str);
free(first_str);
return (formatErrString(node));
}
/*ARGSUSED*/
static int
modifyTarget(int operandLen, char *operand[], cmdOptions_t *options)
{
char *first_str = NULL;
xml_node_t *node;
cmdOptions_t *optionList = options;
if (operand == NULL)
return (1);
buf_add_tag(&first_str, "modify", Tag_Start);
buf_add_tag(&first_str, XML_ELEMENT_TARG, Tag_Start);
xml_add_tag(&first_str, XML_ELEMENT_NAME, operand[0]);
for (; optionList->optval; optionList++) {
switch (optionList->optval) {
case 'p': /* tpgt number */
xml_add_tag(&first_str, XML_ELEMENT_TPGT,
optionList->optarg);
break;
case 'l': /* acl */
xml_add_tag(&first_str, XML_ELEMENT_ACL,
optionList->optarg);
break;
case 'a': /* alias */
xml_add_tag(&first_str, XML_ELEMENT_ALIAS,
optionList->optarg);
break;
case 'm': /* max recv */
xml_add_tag(&first_str, XML_ELEMENT_MAXRECV,
optionList->optarg);
break;
case 'z': /* grow lun size */
xml_add_tag(&first_str, XML_ELEMENT_SIZE,
optionList->optarg);
break;
case 'u':
xml_add_tag(&first_str, XML_ELEMENT_LUN,
optionList->optarg);
break;
default:
(void) fprintf(stderr, "%s: %c: %s\n",
cmdName, optionList->optval,
gettext("unknown option"));
free(first_str);
return (1);
}
}
buf_add_tag(&first_str, XML_ELEMENT_TARG, Tag_End);
buf_add_tag(&first_str, "modify", Tag_End);
node = send_data(hostname, first_str);
free(first_str);
return (formatErrString(node));
}
/*ARGSUSED*/
static int
modifyInitiator(int operandLen, char *operand[], cmdOptions_t *options)
{
char *first_str = NULL;
xml_node_t *node;
cmdOptions_t *optionList = options;
char chapSecret[MAX_CHAP_SECRET_LEN];
int secretLen = 0;
int ret = 0;
if (operand == NULL)
return (1);
if (options == NULL)
return (1);
buf_add_tag(&first_str, "modify", Tag_Start);
buf_add_tag(&first_str, XML_ELEMENT_INIT, Tag_Start);
xml_add_tag(&first_str, XML_ELEMENT_NAME, operand[0]);
for (; optionList->optval; optionList++) {
switch (optionList->optval) {
case 'H': /* chap-name */
xml_add_tag(&first_str, XML_ELEMENT_CHAPNAME,
optionList->optarg);
break;
case 'C': /* chap-secret */
ret = getSecret((char *)&chapSecret[0], &secretLen,
MIN_CHAP_SECRET_LEN, MAX_CHAP_SECRET_LEN);
if (ret != 0) {
(void) fprintf(stderr, "%s: %s\n", cmdName,
gettext("Cannot read CHAP secret"));
return (ret);
}
chapSecret[secretLen] = '\0';
xml_add_tag(&first_str, XML_ELEMENT_CHAPSECRET,
chapSecret);
break;
default:
(void) fprintf(stderr, "%s: %c: %s\n",
cmdName, optionList->optval,
gettext("unknown option"));
free(first_str);
return (1);
}
}
buf_add_tag(&first_str, XML_ELEMENT_INIT, Tag_End);
buf_add_tag(&first_str, "modify", Tag_End);
node = send_data(hostname, first_str);
free(first_str);
return (formatErrString(node));
}
/*ARGSUSED*/
static int
modifyTpgt(int operandLen, char *operand[], cmdOptions_t *options)
{
char *first_str = NULL;
xml_node_t *node;
cmdOptions_t *optionList = options;
boolean_t isIpv6 = B_FALSE;
uint16_t port;
char IpAddress[MAX_IPADDRESS_LEN];
if (operand == NULL)
return (1);
if (optionList == NULL)
return (1);
buf_add_tag(&first_str, "modify", Tag_Start);
buf_add_tag(&first_str, XML_ELEMENT_TPGT, Tag_Start);
xml_add_tag(&first_str, XML_ELEMENT_NAME, operand[0]);
switch (optionList->optval) {
case 'i': /* ip address */
if (parseAddress(optionList->optarg, 0,
IpAddress, 256, &port, &isIpv6) !=
PARSE_ADDR_OK) {
return (1);
}
xml_add_tag(&first_str, XML_ELEMENT_IPADDR, IpAddress);
break;
default:
(void) fprintf(stderr, "%s: %c: %s\n",
cmdName, optionList->optval,
gettext("unknown option"));
free(first_str);
return (1);
}
buf_add_tag(&first_str, XML_ELEMENT_TPGT, Tag_End);
buf_add_tag(&first_str, "modify", Tag_End);
node = send_data(hostname, first_str);
free(first_str);
return (formatErrString(node));
}
/*ARGSUSED*/
static int
modifyAdmin(int operandLen, char *operand[], cmdOptions_t *options)
{
char *first_str = NULL;
xml_node_t *node;
cmdOptions_t *optionList = options;
char chapSecret[MAX_CHAP_SECRET_LEN],
olddir[MAXPATHLEN],
newdir[MAXPATHLEN];
int secretLen = 0;
int ret = 0;
if (operand == NULL)
return (1);
if (options == NULL)
return (1);
buf_add_tag(&first_str, "modify", Tag_Start);
buf_add_tag(&first_str, XML_ELEMENT_ADMIN, Tag_Start);
xml_add_tag(&first_str, XML_ELEMENT_NAME, operand[0]);
for (; optionList->optval; optionList++) {
switch (optionList->optval) {
case 'd': /* base directory */
(void) getcwd(olddir, sizeof (olddir));
/*
* Attempt to create the new base directory.
* This may fail for one of two reasons.
* (a) The path given is invalid or (b) it
* already exists. If (a) is true then then
* following chdir() will fail and the user
* notified. If (b) is true, then chdir() will
* succeed.
*/
(void) mkdir(optionList->optarg, 0700);
if (chdir(optionList->optarg) == -1) {
(void) fprintf(stderr, "%s: %s\n",
cmdName, gettext("Invalid path"));
free(first_str);
return (1);
}
(void) getcwd(newdir, sizeof (newdir));
xml_add_tag(&first_str, XML_ELEMENT_BASEDIR,
newdir);
chdir(olddir);
break;
case 'H': /* chap name */
xml_add_tag(&first_str, XML_ELEMENT_CHAPNAME,
optionList->optarg);
break;
case 'C': /* chap secert */
ret = getSecret((char *)&chapSecret[0],
&secretLen,
MIN_CHAP_SECRET_LEN,
MAX_CHAP_SECRET_LEN);
if (ret != 0) {
(void) fprintf(stderr, "%s: %s\n",
cmdName,
gettext("Cannot read CHAP secret"));
free(first_str);
return (ret);
}
chapSecret[secretLen] = '\0';
xml_add_tag(&first_str, XML_ELEMENT_CHAPSECRET,
chapSecret);
break;
case 'R': /* radius access */
if (strcmp(optionList->optarg,
OPT_ENABLE) == 0) {
xml_add_tag(&first_str,
XML_ELEMENT_RAD_ACCESS, OPT_TRUE);
} else
if (strcmp(optionList->optarg,
OPT_DISABLE) == 0) {
xml_add_tag(&first_str,
XML_ELEMENT_RAD_ACCESS, OPT_FALSE);
} else {
(void) fprintf(stderr, "%s: %s\n",
cmdName,
gettext("Option value should be"
"enable/disable"));
free(first_str);
return (1);
}
break;
case 'r': /* radius server */
xml_add_tag(&first_str, XML_ELEMENT_RAD_SERV,
optionList->optarg);
break;
case 'P': /* radius secret */
ret = getSecret((char *)&chapSecret[0],
&secretLen, MIN_CHAP_SECRET_LEN,
MAX_CHAP_SECRET_LEN);
if (ret != 0) {
(void) fprintf(stderr, "%s: %s\n",
cmdName,
gettext("Cannot read RADIUS "
"secret"));
free(first_str);
return (ret);
}
chapSecret[secretLen] = '\0';
xml_add_tag(&first_str, XML_ELEMENT_RAD_SECRET,
chapSecret);
break;
case 'S': /* iSNS access */
if (strcmp(optionList->optarg,
OPT_ENABLE) == 0) {
xml_add_tag(&first_str,
XML_ELEMENT_ISNS_ACCESS, OPT_TRUE);
} else
if (strcmp(optionList->optarg,
OPT_DISABLE) == 0) {
xml_add_tag(&first_str,
XML_ELEMENT_ISNS_ACCESS, OPT_FALSE);
} else {
(void) fprintf(stderr, "%s: %s\n",
cmdName,
gettext("Option value should be"
"enable/disable"));
free(first_str);
return (1);
}
break;
case 'f': /* fast write back */
if (strcmp(optionList->optarg,
OPT_ENABLE) == 0) {
xml_add_tag(&first_str,
XML_ELEMENT_FAST, OPT_TRUE);
} else
if (strcmp(optionList->optarg,
OPT_DISABLE) == 0) {
xml_add_tag(&first_str,
XML_ELEMENT_FAST, OPT_FALSE);
} else {
(void) fprintf(stderr, "%s: %s\n",
cmdName,
gettext("Option value should be"
"enable/disable"));
free(first_str);
return (1);
}
break;
default:
(void) fprintf(stderr, "%s: %c: %s\n",
cmdName, optionList->optval,
gettext("unknown option"));
free(first_str);
return (1);
}
}
buf_add_tag(&first_str, XML_ELEMENT_ADMIN, Tag_End);
buf_add_tag(&first_str, "modify", Tag_End);
node = send_data(hostname, first_str);
free(first_str);
return (formatErrString(node));
}
/*ARGSUSED*/
static int
deleteTarget(int operandLen, char *operand[], cmdOptions_t *options)
{
char *first_str = NULL;
xml_node_t *node;
cmdOptions_t *optionList = options;
if (operand == NULL)
return (1);
if (options == NULL)
return (1);
buf_add_tag(&first_str, "delete", Tag_Start);
buf_add_tag(&first_str, XML_ELEMENT_TARG, Tag_Start);
xml_add_tag(&first_str, XML_ELEMENT_NAME, operand[0]);
switch (optionList->optval) {
case 'u': /* all */
xml_add_tag(&first_str, XML_ELEMENT_LUN, optionList->optarg);
break;
case 'l': /* acl */
xml_add_tag(&first_str, XML_ELEMENT_ACL, optionList->optarg);
break;
case 'p': /* tpgt number */
xml_add_tag(&first_str, XML_ELEMENT_TPGT, optionList->optarg);
break;
default:
(void) fprintf(stderr, "%s: %c: %s\n",
cmdName, optionList->optval,
gettext("unknown option"));
free(first_str);
return (1);
}
buf_add_tag(&first_str, XML_ELEMENT_TARG, Tag_End);
buf_add_tag(&first_str, "delete", Tag_End);
node = send_data(hostname, first_str);
free(first_str);
return (formatErrString(node));
}
/*ARGSUSED*/
static int
deleteInitiator(int operandLen, char *operand[], cmdOptions_t *options)
{
char *first_str = NULL;
xml_node_t *node;
cmdOptions_t *optionList = options;
if (operand == NULL)
return (1);
if (options == NULL)
return (1);
buf_add_tag(&first_str, "delete", Tag_Start);
buf_add_tag(&first_str, XML_ELEMENT_INIT, Tag_Start);
xml_add_tag(&first_str, XML_ELEMENT_NAME, operand[0]);
switch (optionList->optval) {
case 'A': /* all */
xml_add_tag(&first_str, XML_ELEMENT_ALL, optionList->optarg);
break;
default:
(void) fprintf(stderr, "%s: %c: %s\n",
cmdName, optionList->optval,
gettext("unknown option"));
free(first_str);
return (1);
}
buf_add_tag(&first_str, XML_ELEMENT_INIT, Tag_End);
buf_add_tag(&first_str, "delete", Tag_End);
node = send_data(hostname, first_str);
free(first_str);
return (formatErrString(node));
}
/*ARGSUSED*/
static int
deleteTpgt(int operandLen, char *operand[], cmdOptions_t *options)
{
char *first_str = NULL;
xml_node_t *node;
cmdOptions_t *optionList = options;
boolean_t isIpv6 = B_FALSE;
uint16_t port;
char IpAddress[MAX_IPADDRESS_LEN];
if (operand == NULL)
return (1);
if (options == NULL)
return (1);
buf_add_tag(&first_str, "delete", Tag_Start);
buf_add_tag(&first_str, XML_ELEMENT_TPGT, Tag_Start);
xml_add_tag(&first_str, XML_ELEMENT_NAME, operand[0]);
switch (optionList->optval) {
case 'A': /* all */
xml_add_tag(&first_str, XML_ELEMENT_ALL, optionList->optarg);
break;
case 'i': /* ip address */
if (parseAddress(optionList->optarg, 0,
IpAddress, 256, &port, &isIpv6) !=
PARSE_ADDR_OK) {
return (1);
}
xml_add_tag(&first_str, XML_ELEMENT_IPADDR, IpAddress);
break;
default:
(void) fprintf(stderr, "%s: %c: %s\n",
cmdName, optionList->optval,
gettext("unknown option"));
free(first_str);
return (1);
}
buf_add_tag(&first_str, XML_ELEMENT_TPGT, Tag_End);
buf_add_tag(&first_str, "delete", Tag_End);
node = send_data(hostname, first_str);
free(first_str);
return (formatErrString(node));
}
static int
listTarget(int operandLen, char *operand[], cmdOptions_t *options)
{
char *first_str = NULL;
xml_node_t *node = NULL;
xml_node_t *n1 = NULL; /* pointer to node (depth=1) */
xml_node_t *n2 = NULL; /* pointer to node (depth=2) */
xml_node_t *n3 = NULL; /* pointer to node (depth=3) */
xml_node_t *n4 = NULL; /* pointer to node (depth=4) */
int conns;
char buf[32];
Boolean_t verbose = False;
if (operand == NULL)
return (1);
buf_add_tag(&first_str, "list", Tag_Start);
buf_add_tag(&first_str, XML_ELEMENT_TARG, Tag_Start);
if (operandLen)
xml_add_tag(&first_str, XML_ELEMENT_NAME, operand[0]);
/*
* Always retrieve the iostats which will give us the
* connection count information even if we're not doing
* a verbose output.
*/
xml_add_tag(&first_str, XML_ELEMENT_IOSTAT, OPT_TRUE);
if (options) {
switch (options->optval) {
case 0:
break;
case 'v':
xml_add_tag(&first_str, XML_ELEMENT_LUNINFO, OPT_TRUE);
verbose = True;
break;
default:
(void) fprintf(stderr, "%s: %c: %s\n", cmdName,
options->optval, gettext("unknown option"));
free(first_str);
return (1);
}
}
buf_add_tag(&first_str, XML_ELEMENT_TARG, Tag_End);
buf_add_tag(&first_str, "list", Tag_End);
node = send_data(hostname, first_str);
free(first_str);
if (strcmp(node->x_name, XML_ELEMENT_RESULT)) {
(void) fprintf(stderr, "%s: %s\n", cmdName,
gettext("Bad XML response"));
return (1);
}
n1 = NULL;
while ((n1 = xml_node_next_child(node, XML_ELEMENT_TARG, n1)) != NULL) {
(void) printf("%s: %s\n", gettext("Target"), n1->x_value);
n2 = xml_node_next_child(n1, XML_ELEMENT_INAME, NULL);
(void) printf("%s%s: %s\n", dospace(1), gettext("iSCSI Name"),
n2 ? n2->x_value : gettext("Not set"));
if ((n2 = xml_node_next_child(n1, XML_ELEMENT_ALIAS, NULL)) !=
NULL)
(void) printf("%s%s: %s\n", dospace(1),
gettext("Alias"), n2->x_value);
if ((n2 = xml_node_next_child(n1, XML_ELEMENT_MAXRECV, NULL)) !=
NULL)
(void) printf("%s%s: %s\n", dospace(1),
gettext("MaxRecv"), n2->x_value);
/*
* Count the number of connections available.
*/
n2 = NULL;
conns = 0;
while (n2 = xml_node_next_child(n1, XML_ELEMENT_CONN, n2))
conns++;
(void) printf("%s%s: %d\n", dospace(1), gettext("Connections"),
conns);
if (verbose == False)
continue;
/*
* Displaying the individual connections must be done
* first when verbose is turned on because you'll notice
* above that we've left the output hanging with a label
* indicating connections are coming next.
*/
n2 = NULL;
while (n2 = xml_node_next_child(n1, XML_ELEMENT_CONN, n2)) {
(void) printf("%s%s:\n", dospace(2),
gettext("Initiator"));
(void) printf("%s%s: %s\n", dospace(3),
gettext("iSCSI Name"), n2->x_value);
n3 = xml_node_next_child(n2, XML_ELEMENT_ALIAS, NULL);
(void) printf("%s%s: %s\n", dospace(3),
gettext("Alias"),
n3 ? n3->x_value : gettext("unknown"));
}
(void) printf("%s%s:\n", dospace(1), gettext("ACL list"));
n2 = xml_node_next_child(n1, XML_ELEMENT_ACLLIST, NULL);
n3 = NULL;
while (n3 = xml_node_next_child(n2, XML_ELEMENT_INIT, n3)) {
(void) printf("%s%s: %s\n", dospace(2),
gettext("Initiator"),
n3->x_value);
}
(void) printf("%s%s:\n", dospace(1), gettext("TPGT list"));
n2 = xml_node_next_child(n1, XML_ELEMENT_TPGTLIST, NULL);
n3 = NULL;
while (n3 = xml_node_next_child(n2, XML_ELEMENT_TPGT, n3)) {
(void) printf("%s%s: %s\n", dospace(2),
gettext("TPGT"),
n3->x_value);
}
(void) printf("%s%s:\n", dospace(1),
gettext("LUN information"));
n2 = xml_node_next_child(n1, XML_ELEMENT_LUNINFO, NULL);
n3 = NULL;
while (n3 = xml_node_next_child(n2, XML_ELEMENT_LUN, n3)) {
(void) printf("%s%s: %s\n", dospace(2), gettext("LUN"),
n3->x_value);
n4 = xml_node_next_child(n3, XML_ELEMENT_GUID, NULL);
(void) printf("%s%s: %s\n", dospace(3), gettext("GUID"),
n4 ? n4->x_value : gettext("unknown"));
n4 = xml_node_next_child(n3, XML_ELEMENT_VID, NULL);
(void) printf("%s%s: %s\n", dospace(3), gettext("VID"),
n4 ? n4->x_value : gettext("unknown"));
n4 = xml_node_next_child(n3, XML_ELEMENT_PID, NULL);
(void) printf("%s%s: %s\n", dospace(3), gettext("PID"),
n4 ? n4->x_value : gettext("unknown"));
n4 = xml_node_next_child(n3, XML_ELEMENT_DTYPE, NULL);
(void) printf("%s%s: %s\n", dospace(3), gettext("Type"),
n4 ? n4->x_value : gettext("unknown"));
n4 = xml_node_next_child(n3, XML_ELEMENT_SIZE, NULL);
if (n4 && (strtol(n4->x_value, NULL, 0) != 0)) {
(void) printf("%s%s: %s\n", dospace(3),
gettext("Size"),
number_to_scaled_string(buf,
strtoll(n4->x_value,
NULL, 0), 512, 1024));
} else {
(void) printf("%s%s: %s\n", dospace(3),
gettext("Size"), gettext("unknown"));
}
n4 = xml_node_next_child(n3, XML_ELEMENT_BACK, NULL);
if (n4) {
(void) printf("%s%s: %s\n", dospace(3),
gettext("Backing store"), n4->x_value);
}
n4 = xml_node_next_child(n3, XML_ELEMENT_STATUS, NULL);
(void) printf("%s%s: %s\n", dospace(3),
gettext("Status"),
n4 ? n4->x_value : gettext("unknown"));
}
}
return (0);
}
static int
listInitiator(int operandLen, char *operand[], cmdOptions_t *options)
{
char *first_str = NULL;
xml_node_t *node;
xml_node_t *n1 = NULL; /* pointer to node (depth=1) */
xml_node_t *n2 = NULL; /* pointer to node (depth=2) */
Boolean_t verbose = False;
cmdOptions_t *optionList = options;
if (operand == NULL)
return (1);
buf_add_tag(&first_str, "list", Tag_Start);
buf_add_tag(&first_str, XML_ELEMENT_INIT, Tag_Start);
if (operandLen) {
xml_add_tag(&first_str, XML_ELEMENT_NAME, operand[0]);
}
if (optionList) {
switch (optionList->optval) {
case 0:
break;
case 'v':
verbose = True;
xml_add_tag(&first_str,
XML_ELEMENT_VERBOSE, OPT_TRUE);
break;
default:
(void) fprintf(stderr, "%s: %c: %s\n",
cmdName, optionList->optval,
gettext("unknown option"));
free(first_str);
return (1);
}
}
buf_add_tag(&first_str, XML_ELEMENT_INIT, Tag_End);
buf_add_tag(&first_str, "list", Tag_End);
node = send_data(hostname, first_str);
free(first_str);
if (strcmp(node->x_name, XML_ELEMENT_RESULT)) {
(void) fprintf(stderr, "%s: %s\n", cmdName,
gettext("Bad XML response"));
return (1);
}
n1 = NULL;
while (n1 = xml_node_next_child(node, XML_ELEMENT_INIT, n1)) {
(void) printf("%s: %s\n", gettext("Initiator"), n1->x_value);
n2 = xml_node_next_child(n1, XML_ELEMENT_INAME, NULL);
(void) printf("%s%s: %s\n", dospace(1), gettext("iSCSI Name"),
n2 ? n2->x_value : gettext("Not set"));
n2 = xml_node_next_child(n1, XML_ELEMENT_CHAPNAME, NULL);
(void) printf("%s%s: %s\n", dospace(1), gettext("CHAP Name"),
n2 ? n2->x_value : gettext("Not set"));
if (verbose == True) {
n2 = xml_node_next_child(n1, XML_ELEMENT_CHAPSECRET,
NULL);
(void) printf("%s%s: %s\n", dospace(1),
gettext("CHAP Secret"),
n2 ? gettext("Set") : gettext("Not set"));
}
}
return (0);
}
static int
listTpgt(int operandLen, char *operand[], cmdOptions_t *options)
{
char *first_str = NULL;
xml_node_t *node = NULL;
xml_node_t *n1 = NULL; /* pointer to node (depth=1) */
xml_node_t *n2 = NULL; /* pointer to node (depth=2) */
cmdOptions_t *optionList = options;
Boolean_t verbose = False;
int addrs;
if (operand == NULL)
return (1);
buf_add_tag(&first_str, "list", Tag_Start);
buf_add_tag(&first_str, XML_ELEMENT_TPGT, Tag_Start);
if (operandLen)
xml_add_tag(&first_str, XML_ELEMENT_NAME, operand[0]);
if (optionList) {
switch (optionList->optval) {
case 0: /* no options, treat as --verbose */
break;
case 'v':
verbose = True;
xml_add_tag(&first_str,
XML_ELEMENT_VERBOSE, OPT_TRUE);
break;
default:
(void) fprintf(stderr, "%s: %c: %s\n",
cmdName, optionList->optval,
gettext("unknown option"));
free(first_str);
return (1);
}
}
buf_add_tag(&first_str, XML_ELEMENT_TPGT, Tag_End);
buf_add_tag(&first_str, "list", Tag_End);
node = send_data(hostname, first_str);
free(first_str);
if (strcmp(node->x_name, XML_ELEMENT_RESULT)) {
(void) fprintf(stderr, "%s: %s\n", cmdName,
gettext("Bad XML response"));
return (1);
}
n1 = NULL;
while (n1 = xml_node_next_child(node, XML_ELEMENT_TPGT, n1)) {
(void) printf("%s: %s\n", gettext("TPGT"), n1->x_value);
n2 = NULL;
addrs = 0;
while (n2 = xml_node_next_child(n1, XML_ELEMENT_IPADDR, n2)) {
if (verbose == True)
(void) printf("%s%s: %s\n", dospace(1),
gettext("IP Address"),
n2 ? n2->x_value : gettext("Not set"));
addrs++;
}
if (verbose == False) {
(void) printf("%s%s: %d\n", dospace(1),
gettext("IP Address count"), addrs);
} else if (addrs == 0) {
/*
* Verbose is true, but there where no addresses
* for this TPGT. To keep the output consistent
* dump a "Not set" string out.
*/
(void) printf("%s%s: %s\n", dospace(1),
gettext("IP Address"), gettext("Not set"));
}
}
return (0);
}
/*ARGSUSED*/
static int
showAdmin(int operandLen, char *operand[], cmdOptions_t *options)
{
char *first_str = NULL;
xml_node_t *node = NULL;
xml_node_t *n1 = NULL; /* pointer to node (depth=1) */
xml_node_t *n2 = NULL; /* pointer to node (depth=2) */
if (operand == NULL)
return (1);
buf_add_tag(&first_str, "list", Tag_Start);
buf_add_tag(&first_str, XML_ELEMENT_ADMIN, Tag_Start);
buf_add_tag(&first_str, XML_ELEMENT_ADMIN, Tag_End);
buf_add_tag(&first_str, "list", Tag_End);
node = send_data(hostname, first_str);
free(first_str);
if (strcmp(node->x_name, XML_ELEMENT_RESULT)) {
(void) fprintf(stderr, "%s: %s\n", cmdName,
gettext("Bad XML response"));
return (1);
}
(void) printf("%s:\n", cmdName);
n1 = xml_node_next_child(node, XML_ELEMENT_ADMIN, NULL);
if (n1 == NULL) {
(void) fprintf(stderr, "%s: %s\n", cmdName,
gettext("Bad XML response"));
return (1);
}
n2 = xml_node_next_child(n1, XML_ELEMENT_BASEDIR, NULL);
(void) printf("%s%s: %s\n", dospace(1), gettext("Base Directory"),
n2 ? n2->x_value : gettext("Not set"));
n2 = xml_node_next_child(n1, XML_ELEMENT_CHAPNAME, NULL);
(void) printf("%s%s: %s\n", dospace(1), gettext("CHAP Name"),
n2 ? n2->x_value : gettext("Not set"));
n2 = xml_node_next_child(n1, XML_ELEMENT_RAD_ACCESS, NULL);
(void) printf("%s%s: ", dospace(1), gettext("RADIUS Access"));
if (n2) {
if (strcmp(n2->x_value, OPT_TRUE) == 0)
(void) printf("%s\n", gettext("Enabled"));
else
(void) printf("%s\n", gettext("Disabled"));
} else
(void) printf("%s\n", gettext("Not set"));
n2 = xml_node_next_child(n1, XML_ELEMENT_RAD_SERV, NULL);
(void) printf("%s%s: %s\n", dospace(1), gettext("RADIUS Server"),
n2 ? n2->x_value : gettext("Not set"));
n2 = xml_node_next_child(n1, XML_ELEMENT_ISNS_ACCESS, NULL);
(void) printf("%s%s: ", dospace(1), gettext("iSNS Access"));
if (n2) {
if (strcmp(n2->x_value, OPT_TRUE) == 0)
(void) printf("%s\n", gettext("Enabled"));
else
(void) printf("%s\n", gettext("Disabled"));
} else
(void) printf("%s\n", gettext("Not set"));
n2 = xml_node_next_child(n1, XML_ELEMENT_FAST, NULL);
(void) printf("%s%s: ", dospace(1), gettext("Fast Write ACK"));
if (n2) {
if (strcmp(n2->x_value, OPT_TRUE) == 0)
(void) printf("%s\n", gettext("Enabled"));
else
(void) printf("%s\n", gettext("Disabled"));
} else
(void) printf("%s\n", gettext("Not set"));
return (0);
}
static int
showStats(int operandLen, char *operand[], cmdOptions_t *options)
{
char *first_str = NULL,
scale_buf[16];
xml_node_t *node,
*n1;
int interval = -1,
count = -1,
header;
stat_delta_t cur_data,
*pd;
buf_add_tag(&first_str, "list", Tag_Start);
buf_add_tag(&first_str, XML_ELEMENT_TARG, Tag_Start);
xml_add_tag(&first_str, XML_ELEMENT_IOSTAT, OPT_TRUE);
if (operandLen)
xml_add_tag(&first_str, XML_ELEMENT_NAME, operand[0]);
for (; options->optval; options++) {
switch (options->optval) {
case 0:
break;
case 'I': /* optarg = refresh interval */
interval = atoi(options->optarg);
if (interval == 0) {
(void) fprintf(stderr, "%s: %s\n", cmdName,
gettext("interval must be non-zero"));
free(first_str);
return (1);
}
break;
case 'N':
count = atoi(options->optarg);
if (count == 0) {
(void) fprintf(stderr, "%s: %s\n", cmdName,
gettext("count must be non-zero"));
free(first_str);
return (1);
}
break;
default:
(void) fprintf(stderr, "%s: %c: %s\n", cmdName,
options->optval, gettext("unknown option"));
free(first_str);
return (1);
}
}
buf_add_tag(&first_str, XML_ELEMENT_TARG, Tag_End);
buf_add_tag(&first_str, "list", Tag_End);
header = 1;
/*CONSTANTCONDITION*/
while (1) {
if (--header == 0) {
(void) printf("%20s %12s %12s\n", " ",
gettext("operations"), gettext("bandwidth "));
(void) printf("%-20s %5s %5s %5s %5s\n",
gettext("device"), gettext("read"),
gettext("write"), gettext("read"),
gettext("write"));
(void) printf("%-20s %5s %5s %5s %5s\n",
"--------------------", "-----", "-----",
"-----", "-----");
header = 20;
}
node = send_data(hostname, first_str);
if (strcmp(node->x_name, XML_ELEMENT_RESULT)) {
(void) fprintf(stderr, "%s: %s\n", cmdName,
gettext("Bad XML response"));
free(first_str);
xml_tree_free(node);
stats_free();
return (1);
}
n1 = NULL;
while (n1 = xml_node_next_child(node, XML_ELEMENT_TARG, n1)) {
stats_load_counts(n1, &cur_data);
if ((pd = stats_prev_counts(&cur_data)) == NULL) {
free(first_str);
xml_tree_free(node);
return (1);
}
(void) printf("%-20s ", pd->device);
(void) printf("%5s ",
number_to_scaled_string(scale_buf,
cur_data.read_cmds - pd->read_cmds, 1, 1024));
(void) printf("%5s ",
number_to_scaled_string(scale_buf,
cur_data.write_cmds - pd->write_cmds, 1, 1024));
(void) printf("%5s ",
number_to_scaled_string(scale_buf,
cur_data.read_blks - pd->read_blks, 512, 1024));
(void) printf("%5s\n",
number_to_scaled_string(scale_buf,
cur_data.write_blks - pd->write_blks, 512, 1024));
stats_update_counts(pd, &cur_data);
}
xml_tree_free(node);
if (count == -1) {
if (interval == -1)
/* No count or internal, do it just once */
break;
else
(void) sleep(interval);
} else if (--count) {
if (interval == -1)
break;
else
(void) sleep(interval);
} else
break;
}
stats_free();
free(first_str);
return (0);
}
/*
* input:
* execFullName - exec name of program (argv[0])
*
* Returns:
* command name portion of execFullName
*/
static char *
getExecBasename(char *execFullname)
{
char *lastSlash, *execBasename;
/* guard against '/' at end of command invocation */
for (;;) {
lastSlash = strrchr(execFullname, '/');
if (lastSlash == NULL) {
execBasename = execFullname;
break;
} else {
execBasename = lastSlash + 1;
if (*execBasename == '\0') {
*lastSlash = '\0';
continue;
}
break;
}
}
return (execBasename);
}
/*
* main calls a parser that checks syntax of the input command against
* various rules tables.
*
* The parser provides usage feedback based upon same tables by calling
* two usage functions, usage and subUsage, handling command and subcommand
* usage respectively.
*
* The parser handles all printing of usage syntactical errors
*
* When syntax is successfully validated, the parser calls the associated
* function using the subcommands table functions.
*
* Syntax is as follows:
* command subcommand [options] resource-type [<object>]
*
* The return value from the function is placed in funcRet
*/
int
main(int argc, char *argv[])
{
synTables_t synTables;
char versionString[VERSION_STRING_MAX_LEN];
int ret;
int funcRet;
void *subcommandArgs = NULL;
/* set global command name */
cmdName = getExecBasename(argv[0]);
if (getzoneid() != GLOBAL_ZONEID) {
(void) fprintf(stderr,
"%s: this command is only available in the 'global' "
"zone\n", cmdName);
exit(1);
}
(void) snprintf(versionString, sizeof (versionString), "%s.%s",
VERSION_STRING_MAJOR, VERSION_STRING_MINOR);
synTables.versionString = versionString;
synTables.longOptionTbl = &longOptions[0];
synTables.subcommandTbl = &subcommands[0];
synTables.objectTbl = &objects[0];
synTables.objectRulesTbl = &objectRules[0];
synTables.optionRulesTbl = &optionRules[0];
/* call the CLI parser */
ret = cmdParse(argc, argv, synTables, subcommandArgs, &funcRet);
if (ret == 1) {
(void) printf("%s %s(1M)\n",
gettext("For more information, please see"), cmdName);
return (1);
} else if (ret == -1) {
perror(cmdName);
return (1);
}
return (funcRet);
}