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
* 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 <unistd.h>
#include <libintl.h>
#include <limits.h>
#include <string.h>
#include <syslog.h>
#include <errno.h>
#include <zone.h>
#include "cmdparse.h"
#include "xml.h"
#include "helper.h"
#define CREATE SUBCOMMAND(0)
#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;
/*
* Add new options here
*/
optionTbl_t longOptions[] = {
{NULL, 0, 0, 0}
};
/*
* Add new subcommands here
*/
subcommand_t subcommands[] = {
};
/*
* Add objects here
*/
{"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[] = {
/*
* list subcmd optionally requires an operand
* no subcmd requires no operand
* no subcmd is invalid for this operand
* no subcmd can accept multiple operands
*/
/*
* list subcmd optionally requires an operand
* no subcmd requires no operand
* no subcmd is invalid for this operand
* no subcmd can accept multiple operands
*/
/*
* no subcmd requires an operand
* no subcmd optionally requires an operand
* no subcmd can accept multiple operands
*/
/*
* list subcmd optionally requires an operand
* no subcmd requires no operand
* no subcmd is invalid for this operand
* no subcmd can accept multiple operands
*/
/*
* no subcmd requires an operand
* list subcmd optionally requires an operand
* no subcmd requires no operand
* no subcmd can accept multiple operands
*/
{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[] = {
};
/*ARGSUSED*/
static int
void *addArgs)
{
int ret;
switch (object) {
case TARGET:
break;
case INITIATOR:
break;
case TPGT:
break;
default:
ret = 1;
break;
}
return (ret);
}
/*ARGSUSED*/
static int
void *addArgs)
{
int ret;
switch (object) {
case TARGET:
break;
case INITIATOR:
break;
case TPGT:
break;
default:
ret = 1;
break;
}
return (ret);
}
/*ARGSUSED*/
static int
void *addArgs)
{
int ret;
switch (object) {
case STATS:
break;
case ADMIN:
break;
default:
ret = 1;
break;
}
return (ret);
}
/*ARGSUSED*/
static int
void *addArgs)
{
int ret;
switch (object) {
case TARGET:
break;
case INITIATOR:
break;
case TPGT:
break;
case ADMIN:
break;
default:
ret = 1;
break;
}
return (ret);
}
/*ARGSUSED*/
static int
void *addArgs)
{
int ret;
switch (object) {
case TARGET:
break;
case INITIATOR:
break;
case TPGT:
break;
default:
ret = 1;
break;
}
return (ret);
}
static int
{
int code = 0,
rtn = 0;
/*
* 1000 is the success code, so we don't need to display
* the success message.
*/
if (code != 1000) {
rtn = 1;
}
} else {
gettext("Bad XML response"));
rtn = 1;
}
if (msg)
return (rtn);
}
/*ARGSUSED*/
static int
{
return (1);
switch (optionList->optval) {
case 't': /* type */
gettext("unknown type"));
return (1);
} else {
optionList->optarg);
}
break;
case 'z': /* size */
optionList->optarg);
break;
case 'u': /* lun number */
optionList->optarg);
break;
case 'a': /* alias */
optionList->optarg);
break;
case 'b': /* backing store */
optionList->optarg);
break;
default:
gettext("unknown option"));
return (1);
}
}
return (formatErrString(node));
}
/*ARGSUSED*/
static int
{
return (1);
return (1);
switch (optionList->optval) {
case 'n': /* iqn */
break;
default:
gettext("unknown option"));
return (1);
}
return (formatErrString(node));
}
/*ARGSUSED*/
static int
{
return (1);
return (formatErrString(node));
}
/*ARGSUSED*/
static int
{
return (1);
switch (optionList->optval) {
case 'p': /* tpgt number */
optionList->optarg);
break;
case 'l': /* acl */
optionList->optarg);
break;
case 'a': /* alias */
optionList->optarg);
break;
case 'm': /* max recv */
optionList->optarg);
break;
case 'z': /* grow lun size */
optionList->optarg);
break;
case 'u':
optionList->optarg);
break;
default:
gettext("unknown option"));
return (1);
}
}
return (formatErrString(node));
}
/*ARGSUSED*/
static int
{
char chapSecret[MAX_CHAP_SECRET_LEN];
int secretLen = 0;
int ret = 0;
return (1);
return (1);
switch (optionList->optval) {
case 'H': /* chap-name */
optionList->optarg);
break;
case 'C': /* chap-secret */
if (ret != 0) {
gettext("Cannot read CHAP secret"));
return (ret);
}
break;
default:
gettext("unknown option"));
return (1);
}
}
return (formatErrString(node));
}
/*ARGSUSED*/
static int
{
char IpAddress[MAX_IPADDRESS_LEN];
return (1);
if (optionList == NULL)
return (1);
switch (optionList->optval) {
case 'i': /* ip address */
return (1);
}
break;
default:
gettext("unknown option"));
return (1);
}
return (formatErrString(node));
}
/*ARGSUSED*/
static int
{
char chapSecret[MAX_CHAP_SECRET_LEN],
int secretLen = 0;
int ret = 0;
return (1);
return (1);
switch (optionList->optval) {
case 'd': /* base directory */
/*
* 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.
*/
return (1);
}
newdir);
break;
case 'H': /* chap name */
optionList->optarg);
break;
case 'C': /* chap secert */
if (ret != 0) {
gettext("Cannot read CHAP secret"));
return (ret);
}
break;
case 'R': /* radius access */
OPT_ENABLE) == 0) {
} else
OPT_DISABLE) == 0) {
} else {
gettext("Option value should be"
return (1);
}
break;
case 'r': /* radius server */
optionList->optarg);
break;
case 'P': /* radius secret */
if (ret != 0) {
gettext("Cannot read RADIUS "
"secret"));
return (ret);
}
break;
case 'S': /* iSNS access */
OPT_ENABLE) == 0) {
} else
OPT_DISABLE) == 0) {
} else {
gettext("Option value should be"
return (1);
}
break;
case 'f': /* fast write back */
OPT_ENABLE) == 0) {
} else
OPT_DISABLE) == 0) {
} else {
gettext("Option value should be"
return (1);
}
break;
default:
gettext("unknown option"));
return (1);
}
}
return (formatErrString(node));
}
/*ARGSUSED*/
static int
{
return (1);
return (1);
switch (optionList->optval) {
case 'u': /* all */
break;
case 'l': /* acl */
break;
case 'p': /* tpgt number */
break;
default:
gettext("unknown option"));
return (1);
}
return (formatErrString(node));
}
/*ARGSUSED*/
static int
{
return (1);
return (1);
switch (optionList->optval) {
case 'A': /* all */
break;
default:
gettext("unknown option"));
return (1);
}
return (formatErrString(node));
}
/*ARGSUSED*/
static int
{
char IpAddress[MAX_IPADDRESS_LEN];
return (1);
return (1);
switch (optionList->optval) {
case 'A': /* all */
break;
case 'i': /* ip address */
return (1);
}
break;
default:
gettext("unknown option"));
return (1);
}
return (formatErrString(node));
}
static int
{
int conns;
char buf[32];
return (1);
if (operandLen)
/*
* Always retrieve the iostats which will give us the
* connection count information even if we're not doing
* a verbose output.
*/
if (options) {
case 0:
break;
case 'v':
break;
default:
return (1);
}
}
gettext("Bad XML response"));
return (1);
}
NULL)
NULL)
/*
* Count the number of connections available.
*/
conns = 0;
conns++;
conns);
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.
*/
gettext("Initiator"));
gettext("Alias"),
}
gettext("Initiator"),
}
gettext("TPGT"),
}
gettext("LUN information"));
gettext("Size"),
} else {
}
if (n4) {
}
gettext("Status"),
}
}
return (0);
}
static int
{
return (1);
if (operandLen) {
}
if (optionList) {
switch (optionList->optval) {
case 0:
break;
case 'v':
break;
default:
gettext("unknown option"));
return (1);
}
}
gettext("Bad XML response"));
return (1);
}
NULL);
gettext("CHAP Secret"),
}
}
return (0);
}
static int
{
int addrs;
return (1);
if (operandLen)
if (optionList) {
switch (optionList->optval) {
case 0: /* no options, treat as --verbose */
break;
case 'v':
break;
default:
gettext("unknown option"));
return (1);
}
}
gettext("Bad XML response"));
return (1);
}
addrs = 0;
gettext("IP Address"),
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.
*/
}
}
return (0);
}
/*ARGSUSED*/
static int
{
return (1);
gettext("Bad XML response"));
return (1);
}
gettext("Bad XML response"));
return (1);
}
if (n2) {
else
} else
if (n2) {
else
} else
if (n2) {
else
} else
return (0);
}
static int
{
scale_buf[16];
*n1;
int interval = -1,
count = -1,
*pd;
if (operandLen)
case 0:
break;
case 'I': /* optarg = refresh interval */
if (interval == 0) {
gettext("interval must be non-zero"));
return (1);
}
break;
case 'N':
if (count == 0) {
gettext("count must be non-zero"));
return (1);
}
break;
default:
return (1);
}
}
header = 1;
/*CONSTANTCONDITION*/
while (1) {
if (--header == 0) {
(void) printf("%-20s %5s %5s %5s %5s\n",
gettext("write"));
(void) printf("%-20s %5s %5s %5s %5s\n",
"--------------------", "-----", "-----",
"-----", "-----");
header = 20;
}
gettext("Bad XML response"));
stats_free();
return (1);
}
return (1);
}
(void) printf("%5s ",
(void) printf("%5s ",
(void) printf("%5s ",
(void) printf("%5s\n",
}
if (count == -1) {
if (interval == -1)
/* No count or internal, do it just once */
break;
else
} else if (--count) {
if (interval == -1)
break;
else
} else
break;
}
stats_free();
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 (;;) {
break;
} else {
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
{
int ret;
int funcRet;
void *subcommandArgs = NULL;
/* set global command name */
if (getzoneid() != GLOBAL_ZONEID) {
"%s: this command is only available in the 'global' "
"zone\n", cmdName);
exit(1);
}
/* call the CLI parser */
if (ret == 1) {
(void) printf("%s %s(1M)\n",
return (1);
} else if (ret == -1) {
return (1);
}
return (funcRet);
}