Home | History | Annotate | Download | only in iscsitadm
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #include <stdlib.h>
     28 #include <stdio.h>
     29 #include <sys/types.h>
     30 #include <sys/param.h>
     31 #include <unistd.h>
     32 #include <libintl.h>
     33 #include <limits.h>
     34 #include <string.h>
     35 #include <syslog.h>
     36 #include <errno.h>
     37 #include <sys/stat.h>
     38 #include <zone.h>
     39 #include <netdb.h>
     40 
     41 #include <iscsitgt_impl.h>
     42 #include "cmdparse.h"
     43 #include "helper.h"
     44 
     45 #define	CREATE	SUBCOMMAND(0)
     46 #define	LIST	SUBCOMMAND(1)
     47 #define	MODIFY	SUBCOMMAND(2)
     48 #define	DELETE	SUBCOMMAND(3)
     49 #define	SHOW	SUBCOMMAND(4)
     50 
     51 #define	TARGET		OBJECT(0)
     52 #define	INITIATOR	OBJECT(1)
     53 #define	ADMIN		OBJECT(2)
     54 #define	TPGT		OBJECT(3)
     55 #define	STATS		OBJECT(4)
     56 
     57 #define	VERSION_STRING_MAX_LEN	10
     58 #define	MAX_IPADDRESS_LEN	128
     59 
     60 /*
     61  * Version number:
     62  *  MAJOR - This should only change when there is an incompatible change made
     63  *  to the interfaces or the output.
     64  *
     65  *  MINOR - This should change whenever there is a new command or new feature
     66  *  with no incompatible change.
     67  */
     68 #define	VERSION_STRING_MAJOR	    "1"
     69 #define	VERSION_STRING_MINOR	    "0"
     70 
     71 #define	OPT_ENABLE	"enable"
     72 #define	OPT_DISABLE	"disable"
     73 #define	OPT_TRUE	"true"
     74 #define	OPT_FALSE	"false"
     75 
     76 /* subcommand functions */
     77 static int createFunc(int, char **, int, cmdOptions_t *, void *);
     78 static int listFunc(int, char **, int, cmdOptions_t *, void *);
     79 static int modifyFunc(int, char **, int, cmdOptions_t *, void *);
     80 static int deleteFunc(int, char **, int, cmdOptions_t *, void *);
     81 static int showFunc(int, char **, int, cmdOptions_t *, void *);
     82 
     83 /* object functions per subcommand */
     84 static int createTarget(int, char *[], cmdOptions_t *);
     85 static int createInitiator(int, char *[], cmdOptions_t *);
     86 static int createTpgt(int, char *[], cmdOptions_t *);
     87 static int modifyTarget(int, char *[], cmdOptions_t *);
     88 static int modifyInitiator(int, char *[], cmdOptions_t *);
     89 static int modifyTpgt(int, char *[], cmdOptions_t *);
     90 static int modifyAdmin(int, char *[], cmdOptions_t *);
     91 static int deleteTarget(int, char *[], cmdOptions_t *);
     92 static int deleteInitiator(int, char *[], cmdOptions_t *);
     93 static int deleteTpgt(int, char *[], cmdOptions_t *);
     94 static int listTarget(int, char *[], cmdOptions_t *);
     95 static int listInitiator(int, char *[], cmdOptions_t *);
     96 static int listTpgt(int, char *[], cmdOptions_t *);
     97 static int showAdmin(int, char *[], cmdOptions_t *);
     98 static int showStats(int, char *[], cmdOptions_t *);
     99 
    100 /* globals */
    101 char *cmdName;
    102 
    103 /*
    104  * Add new options here
    105  */
    106 optionTbl_t longOptions[] = {
    107 	{"size", required_arg, 'z', "size k/m/g/t"},
    108 	{"type", required_arg, 't', "disk/tape/osd/raw"},
    109 	{"lun", required_arg, 'u', "number"},
    110 	{"alias", required_arg, 'a', "value"},
    111 	{"backing-store", required_arg, 'b', "pathname"},
    112 	{"tpgt", required_arg, 'p', "tpgt number"},
    113 	{"acl", required_arg, 'l', "local initiator"},
    114 	{"maxrecv", required_arg, 'm', "max recv data segment length"},
    115 	{"chap-secret", no_arg, 'C', NULL},
    116 	{"chap-name", required_arg, 'H', "chap username"},
    117 	{"iqn", required_arg, 'n', "iSCSI node name"},
    118 	{"ip-address", required_arg, 'i', "ip address"},
    119 	{"base-directory", required_arg, 'd', "directory"},
    120 	{"radius-access", required_arg, 'R', "enable/disable"},
    121 	{"radius-server", required_arg, 'r', "hostname[:port]"},
    122 	{"radius-secret", no_arg, 'P', NULL},
    123 	{"isns-access", required_arg, 'S', "enable/disable"},
    124 	{"isns-server", required_arg, 's', "hostname[:port]"},
    125 	{"fast-write-ack", required_arg, 'f', "enable/disable"},
    126 	{"verbose", no_arg, 'v', NULL},
    127 	{"interval", required_arg, 'I', "seconds"},
    128 	{"count", required_arg, 'N', "number"},
    129 	{"all", no_arg, 'A', NULL},
    130 	{NULL, 0, 0, 0}
    131 };
    132 
    133 /*
    134  * Add new subcommands here
    135  */
    136 subcommand_t subcommands[] = {
    137 	{"create", CREATE, createFunc},
    138 	{"list", LIST, listFunc},
    139 	{"modify", MODIFY, modifyFunc},
    140 	{"delete", DELETE, deleteFunc},
    141 	{"show", SHOW, showFunc},
    142 	{NULL, 0, NULL}
    143 };
    144 
    145 /*
    146  * Add objects here
    147  */
    148 object_t objects[] = {
    149 	{"target", TARGET},
    150 	{"initiator", INITIATOR},
    151 	{"admin", ADMIN},
    152 	{"tpgt", TPGT},
    153 	{"stats", STATS},
    154 	{NULL, 0}
    155 };
    156 
    157 /*
    158  * Rules for subcommands and objects
    159  * ReqiredOp, OptioalOp, NoOp, InvalidOp, MultiOp
    160  */
    161 objectRules_t objectRules[] = {
    162 	/*
    163 	 * create/modify/delete subcmd requires an operand
    164 	 * list subcmd optionally requires an operand
    165 	 * no subcmd requires no operand
    166 	 * no subcmd is invalid for this operand
    167 	 * no subcmd can accept multiple operands
    168 	 */
    169 	{TARGET, CREATE|MODIFY|DELETE, LIST, 0, SHOW, 0, "local-target"},
    170 	/*
    171 	 * create/modify/delete subcmd requires an operand
    172 	 * list subcmd optionally requires an operand
    173 	 * no subcmd requires no operand
    174 	 * no subcmd is invalid for this operand
    175 	 * no subcmd can accept multiple operands
    176 	 */
    177 	{INITIATOR, CREATE|MODIFY|DELETE, LIST, 0, SHOW, 0, "local-initiator"},
    178 	/*
    179 	 * no subcmd requires an operand
    180 	 * no subcmd optionally requires an operand
    181 	 * modify/list subcmd requires no operand
    182 	 * create/delete subcmd are invlaid for this operand
    183 	 * no subcmd can accept multiple operands
    184 	 */
    185 	{ADMIN, 0, 0, MODIFY|SHOW, CREATE|DELETE|LIST, 0, NULL},
    186 	/*
    187 	 * create/modify/delete subcmd requires an operand
    188 	 * list subcmd optionally requires an operand
    189 	 * no subcmd requires no operand
    190 	 * no subcmd is invalid for this operand
    191 	 * no subcmd can accept multiple operands
    192 	 */
    193 	{TPGT, CREATE|MODIFY|DELETE, LIST, 0, SHOW, 0, "local-tpgt"},
    194 	/*
    195 	 * no subcmd requires an operand
    196 	 * list subcmd optionally requires an operand
    197 	 * no subcmd requires no operand
    198 	 * create/delete/modify subcmd are invalid for this operand
    199 	 * no subcmd can accept multiple operands
    200 	 */
    201 	{STATS, 0, SHOW, 0, CREATE|MODIFY|DELETE|LIST, 0, "local-target"},
    202 	{0, 0, 0, 0, 0, NULL}
    203 };
    204 
    205 /*
    206  * list of objects, subcommands, valid short options, required flag and
    207  * exclusive option string
    208  *
    209  * If it's not here, there are no options for that object.
    210  */
    211 optionRules_t optionRules[] = {
    212 	{TARGET, CREATE, "tuzab", B_TRUE, NULL},
    213 	{TARGET, MODIFY, "plamzu", B_TRUE, NULL},
    214 	{TARGET, DELETE, "ulp", B_TRUE, NULL},
    215 	{TARGET, LIST,   "v", B_FALSE, NULL},
    216 	{INITIATOR, CREATE, "n", B_TRUE, NULL},
    217 	{INITIATOR, MODIFY, "CH", B_TRUE, NULL},
    218 	{INITIATOR, DELETE, "A", B_TRUE, NULL},
    219 	{INITIATOR, LIST,   "v", B_FALSE, NULL},
    220 	{TPGT, MODIFY, "i", B_TRUE, NULL},
    221 	{TPGT, DELETE, "Ai", B_TRUE, NULL},
    222 	{TPGT, LIST,   "v", B_FALSE, NULL},
    223 	{ADMIN, MODIFY, "dHCRrPSsf", B_TRUE, NULL},
    224 	{STATS, SHOW, "IN", B_FALSE, NULL},
    225 };
    226 
    227 
    228 
    229 /*ARGSUSED*/
    230 static int
    231 createFunc(int operandLen, char *operand[], int object, cmdOptions_t *options,
    232     void *addArgs)
    233 {
    234 	int ret;
    235 
    236 	switch (object) {
    237 		case TARGET:
    238 			ret = createTarget(operandLen, operand, options);
    239 			break;
    240 		case INITIATOR:
    241 			ret = createInitiator(operandLen, operand, options);
    242 			break;
    243 		case TPGT:
    244 			ret = createTpgt(operandLen, operand, options);
    245 			break;
    246 		default:
    247 			(void) fprintf(stderr, "%s: %s\n",
    248 			    cmdName, gettext("unknown object"));
    249 			ret = 1;
    250 			break;
    251 	}
    252 	return (ret);
    253 }
    254 
    255 /*ARGSUSED*/
    256 static int
    257 listFunc(int operandLen, char *operand[], int object, cmdOptions_t *options,
    258     void *addArgs)
    259 {
    260 	int ret;
    261 
    262 	switch (object) {
    263 		case TARGET:
    264 			ret = listTarget(operandLen, operand, options);
    265 			break;
    266 		case INITIATOR:
    267 			ret = listInitiator(operandLen, operand, options);
    268 			break;
    269 		case TPGT:
    270 			ret = listTpgt(operandLen, operand, options);
    271 			break;
    272 		default:
    273 			(void) fprintf(stderr, "%s: %s\n",
    274 			    cmdName, gettext("unknown object"));
    275 			ret = 1;
    276 			break;
    277 	}
    278 	return (ret);
    279 }
    280 
    281 /*ARGSUSED*/
    282 static int
    283 showFunc(int operandLen, char *operand[], int object, cmdOptions_t *options,
    284     void *addArgs)
    285 {
    286 	int ret;
    287 
    288 	switch (object) {
    289 		case STATS:
    290 			ret = showStats(operandLen, operand, options);
    291 			break;
    292 		case ADMIN:
    293 			ret = showAdmin(operandLen, operand, options);
    294 			break;
    295 		default:
    296 			(void) fprintf(stderr, "%s: %s\n",
    297 			    cmdName, gettext("unknown object"));
    298 			ret = 1;
    299 			break;
    300 	}
    301 	return (ret);
    302 }
    303 
    304 /*ARGSUSED*/
    305 static int
    306 modifyFunc(int operandLen, char *operand[], int object, cmdOptions_t *options,
    307     void *addArgs)
    308 {
    309 	int ret;
    310 
    311 	switch (object) {
    312 		case TARGET:
    313 			ret = modifyTarget(operandLen, operand, options);
    314 			break;
    315 		case INITIATOR:
    316 			ret = modifyInitiator(operandLen, operand, options);
    317 			break;
    318 		case TPGT:
    319 			ret = modifyTpgt(operandLen, operand, options);
    320 			break;
    321 		case ADMIN:
    322 			ret = modifyAdmin(operandLen, operand, options);
    323 			break;
    324 		default:
    325 			(void) fprintf(stderr, "%s: %s\n",
    326 			    cmdName, gettext("unknown object"));
    327 			ret = 1;
    328 			break;
    329 	}
    330 	return (ret);
    331 }
    332 
    333 /*ARGSUSED*/
    334 static int
    335 deleteFunc(int operandLen, char *operand[], int object, cmdOptions_t *options,
    336     void *addArgs)
    337 {
    338 	int ret;
    339 
    340 	switch (object) {
    341 		case TARGET:
    342 			ret = deleteTarget(operandLen, operand, options);
    343 			break;
    344 		case INITIATOR:
    345 			ret = deleteInitiator(operandLen, operand, options);
    346 			break;
    347 		case TPGT:
    348 			ret = deleteTpgt(operandLen, operand, options);
    349 			break;
    350 		default:
    351 			(void) fprintf(stderr, "%s: %s\n",
    352 			    cmdName, gettext("unknown object"));
    353 			ret = 1;
    354 			break;
    355 	}
    356 	return (ret);
    357 }
    358 
    359 static int
    360 formatErrString(tgt_node_t *node)
    361 {
    362 	int	code	= 0;
    363 	int	rtn	= 0;
    364 	char	*msg	= NULL;
    365 
    366 	if (node == NULL) {
    367 		(void) fprintf(stderr, "%s: %s\n", cmdName,
    368 		    gettext("Unable to contact target daemon"));
    369 		return (1);
    370 	}
    371 	if ((strcmp(node->x_name, XML_ELEMENT_ERROR) == 0) &&
    372 	    (tgt_find_value_int(node, XML_ELEMENT_CODE, &code) == B_TRUE) &&
    373 	    (tgt_find_value_str(node, XML_ELEMENT_MESSAGE, &msg) == B_TRUE)) {
    374 
    375 		/*
    376 		 * 1000 is the success code, so we don't need to display
    377 		 * the success message.
    378 		 */
    379 		if (code != 1000) {
    380 			(void) fprintf(stderr, "%s: %s %s\n",
    381 			    cmdName, gettext("Error"), msg);
    382 			rtn = 1;
    383 		}
    384 	} else {
    385 		(void) fprintf(stderr, "%s: %s\n", cmdName,
    386 		    gettext("Bad XML response"));
    387 		rtn = 1;
    388 	}
    389 	if (msg)
    390 		free(msg);
    391 	return (rtn);
    392 }
    393 
    394 /*ARGSUSED*/
    395 static int
    396 createTarget(int operandLen, char *operand[], cmdOptions_t *options)
    397 {
    398 	char		*first_str	= NULL;
    399 	tgt_node_t	*node;
    400 	cmdOptions_t	*optionList = options;
    401 
    402 	if (operand == NULL)
    403 		return (1);
    404 
    405 	tgt_buf_add_tag(&first_str, "create", Tag_Start);
    406 	tgt_buf_add_tag(&first_str, XML_ELEMENT_TARG, Tag_Start);
    407 	tgt_buf_add(&first_str, XML_ELEMENT_NAME, operand[0]);
    408 
    409 	for (; optionList->optval; optionList++) {
    410 		switch (optionList->optval) {
    411 			case 't': /* type */
    412 				if ((strcmp(optionList->optarg, "disk")) &&
    413 				    (strcmp(optionList->optarg, "tape")) &&
    414 				    (strcmp(optionList->optarg, "raw")) &&
    415 				    (strcmp(optionList->optarg, "osd"))) {
    416 					(void) fprintf(stderr, "%s: %c: %s\n",
    417 					    cmdName, optionList->optval,
    418 					    gettext("unknown type"));
    419 					free(first_str);
    420 					return (1);
    421 				} else {
    422 					tgt_buf_add(&first_str,
    423 					    XML_ELEMENT_TYPE,
    424 					    optionList->optarg);
    425 				}
    426 				break;
    427 			case 'z': /* size */
    428 				tgt_buf_add(&first_str, XML_ELEMENT_SIZE,
    429 				    optionList->optarg);
    430 				break;
    431 			case 'u': /* lun number */
    432 				tgt_buf_add(&first_str, XML_ELEMENT_LUN,
    433 				    optionList->optarg);
    434 				break;
    435 			case 'a': /* alias */
    436 				tgt_buf_add(&first_str, XML_ELEMENT_ALIAS,
    437 				    optionList->optarg);
    438 				break;
    439 			case 'b': /* backing store */
    440 				tgt_buf_add(&first_str, XML_ELEMENT_BACK,
    441 				    optionList->optarg);
    442 				break;
    443 			default:
    444 				(void) fprintf(stderr, "%s: %c: %s\n",
    445 				    cmdName, optionList->optval,
    446 				    gettext("unknown option"));
    447 				free(first_str);
    448 				return (1);
    449 		}
    450 	}
    451 
    452 	tgt_buf_add_tag(&first_str, XML_ELEMENT_TARG, Tag_End);
    453 	tgt_buf_add_tag(&first_str, "create", Tag_End);
    454 
    455 	node = tgt_door_call(first_str, 0);
    456 	free(first_str);
    457 	return (formatErrString(node));
    458 }
    459 
    460 /*ARGSUSED*/
    461 static int
    462 createInitiator(int operandLen, char *operand[], cmdOptions_t *options)
    463 {
    464 	char		*first_str	= NULL;
    465 	tgt_node_t	*node;
    466 	cmdOptions_t	*optionList	= options;
    467 
    468 	if (operand == NULL)
    469 		return (1);
    470 	if (options == NULL)
    471 		return (1);
    472 
    473 	tgt_buf_add_tag(&first_str, "create", Tag_Start);
    474 	tgt_buf_add_tag(&first_str, XML_ELEMENT_INIT, Tag_Start);
    475 	tgt_buf_add(&first_str, XML_ELEMENT_NAME, operand[0]);
    476 
    477 	switch (optionList->optval) {
    478 	case 'n': /* iqn */
    479 		tgt_buf_add(&first_str, XML_ELEMENT_INAME, optionList->optarg);
    480 		break;
    481 	default:
    482 		(void) fprintf(stderr, "%s: %c: %s\n",
    483 		    cmdName, optionList->optval,
    484 		    gettext("unknown option"));
    485 		free(first_str);
    486 		return (1);
    487 	}
    488 
    489 	tgt_buf_add_tag(&first_str, XML_ELEMENT_INIT, Tag_End);
    490 	tgt_buf_add_tag(&first_str, "create", Tag_End);
    491 
    492 	node = tgt_door_call(first_str, 0);
    493 	free(first_str);
    494 	return (formatErrString(node));
    495 }
    496 
    497 /*ARGSUSED*/
    498 static int
    499 createTpgt(int operandLen, char *operand[], cmdOptions_t *options)
    500 {
    501 	char		*first_str	= NULL;
    502 	tgt_node_t	*node;
    503 
    504 	if (operand == NULL)
    505 		return (1);
    506 
    507 	tgt_buf_add_tag(&first_str, "create", Tag_Start);
    508 	tgt_buf_add_tag(&first_str, XML_ELEMENT_TPGT, Tag_Start);
    509 	tgt_buf_add(&first_str, XML_ELEMENT_NAME, operand[0]);
    510 	tgt_buf_add_tag(&first_str, XML_ELEMENT_TPGT, Tag_End);
    511 	tgt_buf_add_tag(&first_str, "create", Tag_End);
    512 
    513 	node = tgt_door_call(first_str, 0);
    514 	free(first_str);
    515 	return (formatErrString(node));
    516 }
    517 
    518 /*ARGSUSED*/
    519 static int
    520 modifyTarget(int operandLen, char *operand[], cmdOptions_t *options)
    521 {
    522 	char		*first_str	= NULL;
    523 	tgt_node_t	*node;
    524 	cmdOptions_t	*optionList	= options;
    525 
    526 	if (operand == NULL)
    527 		return (1);
    528 
    529 	tgt_buf_add_tag(&first_str, "modify", Tag_Start);
    530 	tgt_buf_add_tag(&first_str, XML_ELEMENT_TARG, Tag_Start);
    531 	tgt_buf_add(&first_str, XML_ELEMENT_NAME, operand[0]);
    532 
    533 	for (; optionList->optval; optionList++) {
    534 		switch (optionList->optval) {
    535 			case 'p': /* tpgt number */
    536 				tgt_buf_add(&first_str, XML_ELEMENT_TPGT,
    537 				    optionList->optarg);
    538 				break;
    539 			case 'l': /* acl */
    540 				tgt_buf_add(&first_str, XML_ELEMENT_ACL,
    541 				    optionList->optarg);
    542 				break;
    543 			case 'a': /* alias */
    544 				tgt_buf_add(&first_str, XML_ELEMENT_ALIAS,
    545 				    optionList->optarg);
    546 				break;
    547 			case 'm': /* max recv */
    548 				tgt_buf_add(&first_str, XML_ELEMENT_MAXRECV,
    549 				    optionList->optarg);
    550 				break;
    551 			case 'z': /* grow lun size */
    552 				tgt_buf_add(&first_str, XML_ELEMENT_SIZE,
    553 				    optionList->optarg);
    554 				break;
    555 			case 'u':
    556 				tgt_buf_add(&first_str, XML_ELEMENT_LUN,
    557 				    optionList->optarg);
    558 				break;
    559 			default:
    560 				(void) fprintf(stderr, "%s: %c: %s\n",
    561 				    cmdName, optionList->optval,
    562 				    gettext("unknown option"));
    563 				free(first_str);
    564 				return (1);
    565 		}
    566 	}
    567 
    568 	tgt_buf_add_tag(&first_str, XML_ELEMENT_TARG, Tag_End);
    569 	tgt_buf_add_tag(&first_str, "modify", Tag_End);
    570 
    571 	node = tgt_door_call(first_str, 0);
    572 	free(first_str);
    573 	return (formatErrString(node));
    574 }
    575 
    576 /*ARGSUSED*/
    577 static int
    578 modifyInitiator(int operandLen, char *operand[], cmdOptions_t *options)
    579 {
    580 	char		*first_str	= NULL;
    581 	tgt_node_t	*node;
    582 	cmdOptions_t	*optionList	= options;
    583 	char		chapSecret[MAX_CHAP_SECRET_LEN+1];
    584 	int		secretLen	= 0;
    585 	int		ret		= 0;
    586 
    587 	if (operand == NULL)
    588 		return (1);
    589 	if (options == NULL)
    590 		return (1);
    591 
    592 	tgt_buf_add_tag(&first_str, "modify", Tag_Start);
    593 	tgt_buf_add_tag(&first_str, XML_ELEMENT_INIT, Tag_Start);
    594 	tgt_buf_add(&first_str, XML_ELEMENT_NAME, operand[0]);
    595 
    596 	for (; optionList->optval; optionList++) {
    597 		switch (optionList->optval) {
    598 		case 'H': /* chap-name */
    599 			if (strlen(optionList->optarg) != 0) {
    600 				tgt_buf_add(&first_str, XML_ELEMENT_CHAPNAME,
    601 				    optionList->optarg);
    602 			} else {
    603 				tgt_buf_add(&first_str,
    604 				    XML_ELEMENT_DELETE_CHAPNAME,
    605 				    OPT_TRUE);
    606 			}
    607 			break;
    608 		case 'C': /* chap-secret */
    609 			ret = getSecret((char *)&chapSecret[0], &secretLen,
    610 			    MIN_CHAP_SECRET_LEN, MAX_CHAP_SECRET_LEN);
    611 			if (ret != 0) {
    612 				(void) fprintf(stderr, "%s: %s\n", cmdName,
    613 				    gettext("Cannot read CHAP secret"));
    614 				return (ret);
    615 			}
    616 			chapSecret[secretLen] = '\0';
    617 			if (secretLen != 0) {
    618 				tgt_buf_add(&first_str, XML_ELEMENT_CHAPSECRET,
    619 				    chapSecret);
    620 			} else {
    621 				tgt_buf_add(&first_str,
    622 				    XML_ELEMENT_DELETE_CHAPSECRET,
    623 				    OPT_TRUE);
    624 			}
    625 			break;
    626 		default:
    627 			(void) fprintf(stderr, "%s: %c: %s\n",
    628 			    cmdName, optionList->optval,
    629 			    gettext("unknown option"));
    630 			free(first_str);
    631 			return (1);
    632 		}
    633 	}
    634 	tgt_buf_add_tag(&first_str, XML_ELEMENT_INIT, Tag_End);
    635 	tgt_buf_add_tag(&first_str, "modify", Tag_End);
    636 
    637 	node = tgt_door_call(first_str, 0);
    638 	free(first_str);
    639 	return (formatErrString(node));
    640 }
    641 
    642 /*ARGSUSED*/
    643 static int
    644 modifyTpgt(int operandLen, char *operand[], cmdOptions_t *options)
    645 {
    646 	char		*first_str	= NULL;
    647 	tgt_node_t	*node;
    648 	cmdOptions_t	*optionList	= options;
    649 	boolean_t	isIpv6 = B_FALSE;
    650 	uint16_t	port;
    651 	char		IpAddress[MAX_IPADDRESS_LEN];
    652 
    653 	if (operand == NULL)
    654 		return (1);
    655 	if (optionList == NULL)
    656 		return (1);
    657 
    658 	tgt_buf_add_tag(&first_str, "modify", Tag_Start);
    659 	tgt_buf_add_tag(&first_str, XML_ELEMENT_TPGT, Tag_Start);
    660 	tgt_buf_add(&first_str, XML_ELEMENT_NAME, operand[0]);
    661 
    662 	switch (optionList->optval) {
    663 	case 'i': /* ip address */
    664 		if (parseAddress(optionList->optarg, 0,
    665 		    IpAddress, 256, &port, &isIpv6) !=
    666 		    PARSE_ADDR_OK) {
    667 			return (1);
    668 		}
    669 		tgt_buf_add(&first_str, XML_ELEMENT_IPADDR, IpAddress);
    670 		break;
    671 	default:
    672 		(void) fprintf(stderr, "%s: %c: %s\n",
    673 		    cmdName, optionList->optval,
    674 		    gettext("unknown option"));
    675 		free(first_str);
    676 		return (1);
    677 	}
    678 
    679 	tgt_buf_add_tag(&first_str, XML_ELEMENT_TPGT, Tag_End);
    680 	tgt_buf_add_tag(&first_str, "modify", Tag_End);
    681 
    682 	node = tgt_door_call(first_str, 0);
    683 	free(first_str);
    684 	return (formatErrString(node));
    685 }
    686 
    687 /*ARGSUSED*/
    688 static int
    689 modifyAdmin(int operandLen, char *operand[], cmdOptions_t *options)
    690 {
    691 	char		*first_str	= NULL;
    692 	tgt_node_t	*node;
    693 	cmdOptions_t	*optionList	= options;
    694 	char		chapSecret[MAX_CHAP_SECRET_LEN+1];
    695 	char		olddir[MAXPATHLEN];
    696 	char		newdir[MAXPATHLEN];
    697 	int		secretLen	= 0;
    698 	int		ret		= 0;
    699 
    700 	if (operand == NULL)
    701 		return (1);
    702 	if (options == NULL)
    703 		return (1);
    704 
    705 	tgt_buf_add_tag(&first_str, "modify", Tag_Start);
    706 	tgt_buf_add_tag(&first_str, XML_ELEMENT_ADMIN, Tag_Start);
    707 	tgt_buf_add(&first_str, XML_ELEMENT_NAME, operand[0]);
    708 
    709 	for (; optionList->optval; optionList++) {
    710 		switch (optionList->optval) {
    711 			case 'd': /* base directory */
    712 				(void) getcwd(olddir, sizeof (olddir));
    713 
    714 				/*
    715 				 * Attempt to create the new base directory.
    716 				 * This may fail for one of two reasons.
    717 				 * (a) The path given is invalid or (b) it
    718 				 * already exists. If (a) is true then then
    719 				 * following chdir() will fail and the user
    720 				 * notified. If (b) is true, then chdir() will
    721 				 * succeed.
    722 				 */
    723 				(void) mkdir(optionList->optarg, 0700);
    724 
    725 				if (chdir(optionList->optarg) == -1) {
    726 					(void) fprintf(stderr, "%s: %s\n",
    727 					    cmdName, gettext("Invalid path"));
    728 					free(first_str);
    729 					return (1);
    730 				}
    731 				(void) getcwd(newdir, sizeof (newdir));
    732 				tgt_buf_add(&first_str, XML_ELEMENT_BASEDIR,
    733 				    newdir);
    734 				(void) chdir(olddir);
    735 				break;
    736 			case 'H': /* chap name */
    737 				if (strlen(optionList->optarg) != 0) {
    738 					tgt_buf_add(&first_str,
    739 					    XML_ELEMENT_CHAPNAME,
    740 					    optionList->optarg);
    741 				} else {
    742 					tgt_buf_add(&first_str,
    743 					    XML_ELEMENT_DELETE_CHAPNAME,
    744 					    OPT_TRUE);
    745 				}
    746 				break;
    747 			case 'C': /* chap secert */
    748 				ret = getSecret((char *)&chapSecret[0],
    749 				    &secretLen,
    750 				    MIN_CHAP_SECRET_LEN,
    751 				    MAX_CHAP_SECRET_LEN);
    752 				if (ret != 0) {
    753 					(void) fprintf(stderr, "%s: %s\n",
    754 					    cmdName,
    755 					    gettext("Cannot read CHAP secret"));
    756 					free(first_str);
    757 					return (ret);
    758 				}
    759 				chapSecret[secretLen] = '\0';
    760 				if (secretLen != 0) {
    761 					tgt_buf_add(&first_str,
    762 					    XML_ELEMENT_CHAPSECRET,
    763 					    chapSecret);
    764 				} else {
    765 					tgt_buf_add(&first_str,
    766 					    XML_ELEMENT_DELETE_CHAPSECRET,
    767 					    OPT_TRUE);
    768 				}
    769 				break;
    770 			case 'R': /* radius access */
    771 				if (strcmp(optionList->optarg,
    772 				    OPT_ENABLE) == 0) {
    773 					tgt_buf_add(&first_str,
    774 					    XML_ELEMENT_RAD_ACCESS, OPT_TRUE);
    775 				} else
    776 					if (strcmp(optionList->optarg,
    777 					    OPT_DISABLE) == 0) {
    778 					tgt_buf_add(&first_str,
    779 					    XML_ELEMENT_RAD_ACCESS, OPT_FALSE);
    780 				} else {
    781 					(void) fprintf(stderr, "%s: %s\n",
    782 					    cmdName,
    783 					    gettext("Option value should be"
    784 					    "enable/disable"));
    785 					free(first_str);
    786 					return (1);
    787 				}
    788 				break;
    789 			case 'r': /* radius server */
    790 				if (strlen(optionList->optarg) != 0) {
    791 					tgt_buf_add(&first_str,
    792 					    XML_ELEMENT_RAD_SERV,
    793 					    optionList->optarg);
    794 				} else {
    795 					tgt_buf_add(&first_str,
    796 					    XML_ELEMENT_DELETE_RAD_SERV,
    797 					    OPT_TRUE);
    798 				}
    799 				break;
    800 			case 'P': /* radius secret */
    801 				ret = getSecret((char *)&chapSecret[0],
    802 				    &secretLen, MIN_CHAP_SECRET_LEN,
    803 				    MAX_CHAP_SECRET_LEN);
    804 				if (ret != 0) {
    805 					(void) fprintf(stderr, "%s: %s\n",
    806 					    cmdName,
    807 					    gettext("Cannot read RADIUS "
    808 					    "secret"));
    809 					free(first_str);
    810 					return (ret);
    811 				}
    812 				chapSecret[secretLen] = '\0';
    813 				if (secretLen != 0) {
    814 					tgt_buf_add(&first_str,
    815 					    XML_ELEMENT_RAD_SECRET,
    816 					    chapSecret);
    817 				} else {
    818 					tgt_buf_add(&first_str,
    819 					    XML_ELEMENT_DELETE_RAD_SECRET,
    820 					    OPT_TRUE);
    821 				}
    822 				break;
    823 			case 'S': /* iSNS access */
    824 				if (strcmp(optionList->optarg,
    825 				    OPT_ENABLE) == 0) {
    826 					tgt_buf_add(&first_str,
    827 					    XML_ELEMENT_ISNS_ACCESS, OPT_TRUE);
    828 				} else
    829 					if (strcmp(optionList->optarg,
    830 					    OPT_DISABLE) == 0) {
    831 					tgt_buf_add(&first_str,
    832 					    XML_ELEMENT_ISNS_ACCESS, OPT_FALSE);
    833 				} else {
    834 					(void) fprintf(stderr, "%s: %s\n",
    835 					    cmdName,
    836 					    gettext("Option value should be"
    837 					    "enable/disable"));
    838 					free(first_str);
    839 					return (1);
    840 				}
    841 				break;
    842 			case 's': /* iSNS server */
    843 				if (strlen(optionList->optarg) >
    844 				    MAXHOSTNAMELEN) {
    845 					(void) fprintf(stderr, "%s: %s\n",
    846 					    cmdName,
    847 					    gettext("option too long"));
    848 					return (1);
    849 				}
    850 				tgt_buf_add(&first_str, XML_ELEMENT_ISNS_SERV,
    851 				    optionList->optarg);
    852 				break;
    853 			case 'f': /* fast write back */
    854 				if (strcmp(optionList->optarg,
    855 				    OPT_ENABLE) == 0) {
    856 					tgt_buf_add(&first_str,
    857 					    XML_ELEMENT_FAST, OPT_TRUE);
    858 				} else
    859 					if (strcmp(optionList->optarg,
    860 					    OPT_DISABLE) == 0) {
    861 					tgt_buf_add(&first_str,
    862 					    XML_ELEMENT_FAST, OPT_FALSE);
    863 				} else {
    864 					(void) fprintf(stderr, "%s: %s\n",
    865 					    cmdName,
    866 					    gettext("Option value should be"
    867 					    "enable/disable"));
    868 					free(first_str);
    869 					return (1);
    870 				}
    871 				break;
    872 			default:
    873 				(void) fprintf(stderr, "%s: %c: %s\n",
    874 				    cmdName, optionList->optval,
    875 				    gettext("unknown option"));
    876 				free(first_str);
    877 				return (1);
    878 		}
    879 	}
    880 
    881 	tgt_buf_add_tag(&first_str, XML_ELEMENT_ADMIN, Tag_End);
    882 	tgt_buf_add_tag(&first_str, "modify", Tag_End);
    883 
    884 	node = tgt_door_call(first_str, 0);
    885 	free(first_str);
    886 	return (formatErrString(node));
    887 }
    888 
    889 /*ARGSUSED*/
    890 static int
    891 deleteTarget(int operandLen, char *operand[], cmdOptions_t *options)
    892 {
    893 	char		*first_str	= NULL;
    894 	tgt_node_t	*node;
    895 	cmdOptions_t	*optionList = options;
    896 
    897 	if (operand == NULL)
    898 		return (1);
    899 	if (options == NULL)
    900 		return (1);
    901 
    902 	tgt_buf_add_tag(&first_str, "delete", Tag_Start);
    903 	tgt_buf_add_tag(&first_str, XML_ELEMENT_TARG, Tag_Start);
    904 	tgt_buf_add(&first_str, XML_ELEMENT_NAME, operand[0]);
    905 
    906 	switch (optionList->optval) {
    907 	case 'u': /* all */
    908 		tgt_buf_add(&first_str, XML_ELEMENT_LUN, optionList->optarg);
    909 		break;
    910 	case 'l': /* acl */
    911 		tgt_buf_add(&first_str, XML_ELEMENT_ACL, optionList->optarg);
    912 		break;
    913 	case 'p': /* tpgt number */
    914 		tgt_buf_add(&first_str, XML_ELEMENT_TPGT, optionList->optarg);
    915 		break;
    916 	default:
    917 		(void) fprintf(stderr, "%s: %c: %s\n",
    918 		    cmdName, optionList->optval,
    919 		    gettext("unknown option"));
    920 		free(first_str);
    921 		return (1);
    922 	}
    923 
    924 	tgt_buf_add_tag(&first_str, XML_ELEMENT_TARG, Tag_End);
    925 	tgt_buf_add_tag(&first_str, "delete", Tag_End);
    926 
    927 	node = tgt_door_call(first_str, 0);
    928 	free(first_str);
    929 	return (formatErrString(node));
    930 }
    931 
    932 /*ARGSUSED*/
    933 static int
    934 deleteInitiator(int operandLen, char *operand[], cmdOptions_t *options)
    935 {
    936 	char		*first_str	= NULL;
    937 	tgt_node_t	*node;
    938 	cmdOptions_t	*optionList = options;
    939 
    940 	if (operand == NULL)
    941 		return (1);
    942 	if (options == NULL)
    943 		return (1);
    944 
    945 	tgt_buf_add_tag(&first_str, "delete", Tag_Start);
    946 	tgt_buf_add_tag(&first_str, XML_ELEMENT_INIT, Tag_Start);
    947 	tgt_buf_add(&first_str, XML_ELEMENT_NAME, operand[0]);
    948 
    949 	switch (optionList->optval) {
    950 	case 'A': /* all */
    951 		tgt_buf_add(&first_str, XML_ELEMENT_ALL, optionList->optarg);
    952 		break;
    953 	default:
    954 		(void) fprintf(stderr, "%s: %c: %s\n",
    955 		    cmdName, optionList->optval,
    956 		    gettext("unknown option"));
    957 		free(first_str);
    958 		return (1);
    959 	}
    960 
    961 	tgt_buf_add_tag(&first_str, XML_ELEMENT_INIT, Tag_End);
    962 	tgt_buf_add_tag(&first_str, "delete", Tag_End);
    963 
    964 	node = tgt_door_call(first_str, 0);
    965 	free(first_str);
    966 	return (formatErrString(node));
    967 }
    968 
    969 /*ARGSUSED*/
    970 static int
    971 deleteTpgt(int operandLen, char *operand[], cmdOptions_t *options)
    972 {
    973 	char		*first_str	= NULL;
    974 	tgt_node_t	*node;
    975 	cmdOptions_t	*optionList = options;
    976 	boolean_t	isIpv6 = B_FALSE;
    977 	uint16_t	port;
    978 	char		IpAddress[MAX_IPADDRESS_LEN];
    979 
    980 	if (operand == NULL)
    981 		return (1);
    982 	if (options == NULL)
    983 		return (1);
    984 
    985 	tgt_buf_add_tag(&first_str, "delete", Tag_Start);
    986 	tgt_buf_add_tag(&first_str, XML_ELEMENT_TPGT, Tag_Start);
    987 	tgt_buf_add(&first_str, XML_ELEMENT_NAME, operand[0]);
    988 
    989 	switch (optionList->optval) {
    990 	case 'A': /* all */
    991 		tgt_buf_add(&first_str, XML_ELEMENT_ALL, optionList->optarg);
    992 		break;
    993 	case 'i': /* ip address */
    994 		if (parseAddress(optionList->optarg, 0,
    995 		    IpAddress, 256, &port, &isIpv6) !=
    996 		    PARSE_ADDR_OK) {
    997 			return (1);
    998 		}
    999 		tgt_buf_add(&first_str, XML_ELEMENT_IPADDR, IpAddress);
   1000 		break;
   1001 	default:
   1002 		(void) fprintf(stderr, "%s: %c: %s\n",
   1003 		    cmdName, optionList->optval,
   1004 		    gettext("unknown option"));
   1005 		free(first_str);
   1006 		return (1);
   1007 	}
   1008 
   1009 	tgt_buf_add_tag(&first_str, XML_ELEMENT_TPGT, Tag_End);
   1010 	tgt_buf_add_tag(&first_str, "delete", Tag_End);
   1011 
   1012 	node = tgt_door_call(first_str, 0);
   1013 	free(first_str);
   1014 	return (formatErrString(node));
   1015 }
   1016 
   1017 static int
   1018 listTarget(int operandLen, char *operand[], cmdOptions_t *options)
   1019 {
   1020 	char		*first_str	= NULL;
   1021 	tgt_node_t	*node		= NULL;
   1022 	tgt_node_t	*n1		= NULL; /* pointer to node (depth=1) */
   1023 	tgt_node_t	*n2		= NULL; /* pointer to node (depth=2) */
   1024 	tgt_node_t	*n3		= NULL; /* pointer to node (depth=3) */
   1025 	tgt_node_t	*n4		= NULL; /* pointer to node (depth=4) */
   1026 	int		conns;
   1027 	char		buf[32];
   1028 	Boolean_t	verbose		= False;
   1029 
   1030 	if (operand == NULL)
   1031 		return (1);
   1032 
   1033 	tgt_buf_add_tag(&first_str, "list", Tag_Start);
   1034 	tgt_buf_add_tag(&first_str, XML_ELEMENT_TARG, Tag_Start);
   1035 
   1036 	if (operandLen)
   1037 		tgt_buf_add(&first_str, XML_ELEMENT_NAME, operand[0]);
   1038 
   1039 	/*
   1040 	 * Always retrieve the iostats which will give us the
   1041 	 * connection count information even if we're not doing
   1042 	 * a verbose output.
   1043 	 */
   1044 	tgt_buf_add(&first_str, XML_ELEMENT_IOSTAT, OPT_TRUE);
   1045 
   1046 	if (options) {
   1047 		switch (options->optval) {
   1048 		case 0:
   1049 			break;
   1050 		case 'v':
   1051 			tgt_buf_add(&first_str, XML_ELEMENT_LUNINFO, OPT_TRUE);
   1052 			verbose = True;
   1053 			break;
   1054 		default:
   1055 			(void) fprintf(stderr, "%s: %c: %s\n", cmdName,
   1056 			    options->optval, gettext("unknown option"));
   1057 			free(first_str);
   1058 			return (1);
   1059 		}
   1060 	}
   1061 
   1062 	tgt_buf_add_tag(&first_str, XML_ELEMENT_TARG, Tag_End);
   1063 	tgt_buf_add_tag(&first_str, "list", Tag_End);
   1064 
   1065 	if ((node = tgt_door_call(first_str, 0)) == NULL) {
   1066 		(void) fprintf(stderr, "%s: %s\n", cmdName,
   1067 		    gettext("No reponse from daemon"));
   1068 		return (1);
   1069 	}
   1070 	free(first_str);
   1071 
   1072 	if (strcmp(node->x_name, XML_ELEMENT_RESULT)) {
   1073 		(void) fprintf(stderr, "%s: %s\n", cmdName,
   1074 		    gettext("Bad XML response"));
   1075 		return (1);
   1076 	}
   1077 
   1078 	n1 = NULL;
   1079 	while ((n1 = tgt_node_next_child(node, XML_ELEMENT_TARG, n1)) != NULL) {
   1080 		(void) printf("%s: %s\n", gettext("Target"), n1->x_value);
   1081 		n2 = tgt_node_next_child(n1, XML_ELEMENT_INAME, NULL);
   1082 		(void) printf("%s%s: %s\n", dospace(1), gettext("iSCSI Name"),
   1083 		    n2 ? n2->x_value : gettext("Not set"));
   1084 
   1085 		if ((n2 = tgt_node_next_child(n1, XML_ELEMENT_ALIAS, NULL)) !=
   1086 		    NULL)
   1087 			(void) printf("%s%s: %s\n", dospace(1),
   1088 			    gettext("Alias"), n2->x_value);
   1089 
   1090 		if ((n2 = tgt_node_next_child(n1, XML_ELEMENT_MAXRECV, NULL)) !=
   1091 		    NULL)
   1092 			(void) printf("%s%s: %s\n", dospace(1),
   1093 			    gettext("MaxRecv"), n2->x_value);
   1094 
   1095 		/*
   1096 		 * Count the number of connections available.
   1097 		 */
   1098 		n2 = NULL;
   1099 		conns = 0;
   1100 		while (n2 = tgt_node_next_child(n1, XML_ELEMENT_CONN, n2))
   1101 			conns++;
   1102 		(void) printf("%s%s: %d\n", dospace(1), gettext("Connections"),
   1103 		    conns);
   1104 
   1105 		if (verbose == False)
   1106 			continue;
   1107 
   1108 		/*
   1109 		 * Displaying the individual connections must be done
   1110 		 * first when verbose is turned on because you'll notice
   1111 		 * above that we've left the output hanging with a label
   1112 		 * indicating connections are coming next.
   1113 		 */
   1114 		n2 = NULL;
   1115 		while (n2 = tgt_node_next_child(n1, XML_ELEMENT_CONN, n2)) {
   1116 			(void) printf("%s%s:\n", dospace(2),
   1117 			    gettext("Initiator"));
   1118 			(void) printf("%s%s: %s\n", dospace(3),
   1119 			    gettext("iSCSI Name"), n2->x_value);
   1120 			n3 = tgt_node_next_child(n2, XML_ELEMENT_ALIAS, NULL);
   1121 			(void) printf("%s%s: %s\n", dospace(3),
   1122 			    gettext("Alias"),
   1123 			    n3 ? n3->x_value : gettext("unknown"));
   1124 		}
   1125 
   1126 		(void) printf("%s%s:\n", dospace(1), gettext("ACL list"));
   1127 		n2 = tgt_node_next_child(n1, XML_ELEMENT_ACLLIST, NULL);
   1128 		n3 = NULL;
   1129 		while (n3 = tgt_node_next_child(n2, XML_ELEMENT_INIT, n3)) {
   1130 			(void) printf("%s%s: %s\n", dospace(2),
   1131 			    gettext("Initiator"),
   1132 			    n3->x_value);
   1133 		}
   1134 
   1135 		(void) printf("%s%s:\n", dospace(1), gettext("TPGT list"));
   1136 		n2 = tgt_node_next_child(n1, XML_ELEMENT_TPGTLIST, NULL);
   1137 		n3 = NULL;
   1138 		while (n3 = tgt_node_next_child(n2, XML_ELEMENT_TPGT, n3)) {
   1139 			(void) printf("%s%s: %s\n", dospace(2),
   1140 			    gettext("TPGT"),
   1141 			    n3->x_value);
   1142 		}
   1143 
   1144 		(void) printf("%s%s:\n", dospace(1),
   1145 		    gettext("LUN information"));
   1146 		n2 = tgt_node_next_child(n1, XML_ELEMENT_LUNINFO, NULL);
   1147 		n3 = NULL;
   1148 		while (n3 = tgt_node_next_child(n2, XML_ELEMENT_LUN, n3)) {
   1149 			(void) printf("%s%s: %s\n", dospace(2), gettext("LUN"),
   1150 			    n3->x_value);
   1151 
   1152 			n4 = tgt_node_next_child(n3, XML_ELEMENT_GUID, NULL);
   1153 			(void) printf("%s%s: %s\n", dospace(3), gettext("GUID"),
   1154 			    n4 ? n4->x_value : gettext("unknown"));
   1155 
   1156 			n4 = tgt_node_next_child(n3, XML_ELEMENT_VID, NULL);
   1157 			(void) printf("%s%s: %s\n", dospace(3), gettext("VID"),
   1158 			    n4 ? n4->x_value : gettext("unknown"));
   1159 
   1160 			n4 = tgt_node_next_child(n3, XML_ELEMENT_PID, NULL);
   1161 			(void) printf("%s%s: %s\n", dospace(3), gettext("PID"),
   1162 			    n4 ? n4->x_value : gettext("unknown"));
   1163 
   1164 			n4 = tgt_node_next_child(n3, XML_ELEMENT_DTYPE, NULL);
   1165 			(void) printf("%s%s: %s\n", dospace(3), gettext("Type"),
   1166 			    n4 ? n4->x_value : gettext("unknown"));
   1167 
   1168 			n4 = tgt_node_next_child(n3, XML_ELEMENT_SIZE, NULL);
   1169 			if (n4 && (strtol(n4->x_value, NULL, 0) != 0)) {
   1170 				(void) printf("%s%s: %s\n", dospace(3),
   1171 				    gettext("Size"),
   1172 				    number_to_scaled_string(buf,
   1173 				    strtoll(n4->x_value,
   1174 				    NULL, 0), 512, 1024));
   1175 			} else {
   1176 				(void) printf("%s%s: %s\n", dospace(3),
   1177 				    gettext("Size"), gettext("unknown"));
   1178 			}
   1179 
   1180 			n4 = tgt_node_next_child(n3, XML_ELEMENT_BACK, NULL);
   1181 			if (n4) {
   1182 				(void) printf("%s%s: %s\n", dospace(3),
   1183 				    gettext("Backing store"), n4->x_value);
   1184 			}
   1185 
   1186 			n4 = tgt_node_next_child(n3, XML_ELEMENT_STATUS, NULL);
   1187 			(void) printf("%s%s: %s\n", dospace(3),
   1188 			    gettext("Status"),
   1189 			    n4 ? n4->x_value : gettext("unknown"));
   1190 		}
   1191 	}
   1192 
   1193 	return (0);
   1194 }
   1195 
   1196 static int
   1197 listInitiator(int operandLen, char *operand[], cmdOptions_t *options)
   1198 {
   1199 	char		*first_str	= NULL;
   1200 	tgt_node_t	*node;
   1201 	tgt_node_t	*n1		= NULL; /* pointer to node (depth=1) */
   1202 	tgt_node_t	*n2		= NULL; /* pointer to node (depth=2) */
   1203 	Boolean_t	verbose		= False;
   1204 	cmdOptions_t	*optionList	= options;
   1205 
   1206 	if (operand == NULL)
   1207 		return (1);
   1208 
   1209 	tgt_buf_add_tag(&first_str, "list", Tag_Start);
   1210 	tgt_buf_add_tag(&first_str, XML_ELEMENT_INIT, Tag_Start);
   1211 
   1212 	if (operandLen) {
   1213 		tgt_buf_add(&first_str, XML_ELEMENT_NAME, operand[0]);
   1214 	}
   1215 	if (optionList) {
   1216 		switch (optionList->optval) {
   1217 		case 0:
   1218 			break;
   1219 		case 'v':
   1220 			verbose = True;
   1221 			tgt_buf_add(&first_str,
   1222 			    XML_ELEMENT_VERBOSE, OPT_TRUE);
   1223 			break;
   1224 
   1225 		default:
   1226 			(void) fprintf(stderr, "%s: %c: %s\n",
   1227 			    cmdName, optionList->optval,
   1228 			    gettext("unknown option"));
   1229 			free(first_str);
   1230 			return (1);
   1231 		}
   1232 	}
   1233 
   1234 	tgt_buf_add_tag(&first_str, XML_ELEMENT_INIT, Tag_End);
   1235 	tgt_buf_add_tag(&first_str, "list", Tag_End);
   1236 
   1237 	if ((node = tgt_door_call(first_str, 0)) == NULL) {
   1238 		(void) fprintf(stderr, "%s: %s\n", cmdName,
   1239 		    gettext("No reponse from daemon"));
   1240 		return (1);
   1241 	}
   1242 	free(first_str);
   1243 
   1244 	if (strcmp(node->x_name, XML_ELEMENT_RESULT)) {
   1245 		(void) fprintf(stderr, "%s: %s\n", cmdName,
   1246 		    gettext("Bad XML response"));
   1247 		return (1);
   1248 	}
   1249 
   1250 	n1 = NULL;
   1251 	while (n1 = tgt_node_next_child(node, XML_ELEMENT_INIT, n1)) {
   1252 		(void) printf("%s: %s\n", gettext("Initiator"), n1->x_value);
   1253 
   1254 		n2 = tgt_node_next_child(n1, XML_ELEMENT_INAME, NULL);
   1255 		(void) printf("%s%s: %s\n", dospace(1), gettext("iSCSI Name"),
   1256 		    n2 ? n2->x_value : gettext("Not set"));
   1257 
   1258 		n2 = tgt_node_next_child(n1, XML_ELEMENT_CHAPNAME, NULL);
   1259 		(void) printf("%s%s: %s\n", dospace(1), gettext("CHAP Name"),
   1260 		    n2 ? n2->x_value : gettext("Not set"));
   1261 
   1262 		if (verbose == True) {
   1263 			n2 = tgt_node_next_child(n1, XML_ELEMENT_CHAPSECRET,
   1264 			    NULL);
   1265 			(void) printf("%s%s: %s\n", dospace(1),
   1266 			    gettext("CHAP Secret"),
   1267 			    n2 ? gettext("Set") : gettext("Not set"));
   1268 		}
   1269 
   1270 	}
   1271 
   1272 	return (0);
   1273 }
   1274 
   1275 static int
   1276 listTpgt(int operandLen, char *operand[], cmdOptions_t *options)
   1277 {
   1278 	char		*first_str	= NULL;
   1279 	tgt_node_t	*node		= NULL;
   1280 	tgt_node_t	*n1		= NULL; /* pointer to node (depth=1) */
   1281 	tgt_node_t	*n2		= NULL; /* pointer to node (depth=2) */
   1282 	cmdOptions_t	*optionList	= options;
   1283 	Boolean_t	verbose		= False;
   1284 	int		addrs;
   1285 
   1286 	if (operand == NULL)
   1287 		return (1);
   1288 
   1289 	tgt_buf_add_tag(&first_str, "list", Tag_Start);
   1290 	tgt_buf_add_tag(&first_str, XML_ELEMENT_TPGT, Tag_Start);
   1291 
   1292 	if (operandLen)
   1293 		tgt_buf_add(&first_str, XML_ELEMENT_NAME, operand[0]);
   1294 	if (optionList) {
   1295 		switch (optionList->optval) {
   1296 		case 0: /* no options, treat as --verbose */
   1297 			break;
   1298 		case 'v':
   1299 			verbose = True;
   1300 			tgt_buf_add(&first_str,
   1301 			    XML_ELEMENT_VERBOSE, OPT_TRUE);
   1302 			break;
   1303 		default:
   1304 			(void) fprintf(stderr, "%s: %c: %s\n",
   1305 			    cmdName, optionList->optval,
   1306 			    gettext("unknown option"));
   1307 			free(first_str);
   1308 			return (1);
   1309 		}
   1310 	}
   1311 
   1312 	tgt_buf_add_tag(&first_str, XML_ELEMENT_TPGT, Tag_End);
   1313 	tgt_buf_add_tag(&first_str, "list", Tag_End);
   1314 
   1315 	if ((node = tgt_door_call(first_str, 0)) == NULL) {
   1316 		(void) fprintf(stderr, "%s: %s\n", cmdName,
   1317 		    gettext("No reponse from daemon"));
   1318 		return (1);
   1319 	}
   1320 	free(first_str);
   1321 
   1322 	if (strcmp(node->x_name, XML_ELEMENT_RESULT)) {
   1323 		(void) fprintf(stderr, "%s: %s\n", cmdName,
   1324 		    gettext("Bad XML response"));
   1325 		return (1);
   1326 	}
   1327 
   1328 	n1 = NULL;
   1329 	while (n1 = tgt_node_next_child(node, XML_ELEMENT_TPGT, n1)) {
   1330 		(void) printf("%s: %s\n", gettext("TPGT"), n1->x_value);
   1331 		n2 = NULL;
   1332 		addrs = 0;
   1333 		while (n2 = tgt_node_next(n1, XML_ELEMENT_IPADDR, n2)) {
   1334 			if (verbose == True)
   1335 				(void) printf("%s%s: %s\n", dospace(1),
   1336 				    gettext("IP Address"),
   1337 				    n2 ? n2->x_value : gettext("Not set"));
   1338 			addrs++;
   1339 		}
   1340 
   1341 		if (verbose == False) {
   1342 			(void) printf("%s%s: %d\n", dospace(1),
   1343 			    gettext("IP Address count"), addrs);
   1344 		} else if (addrs == 0) {
   1345 
   1346 			/*
   1347 			 * Verbose is true, but there where no addresses
   1348 			 * for this TPGT. To keep the output consistent
   1349 			 * dump a "Not set" string out.
   1350 			 */
   1351 			(void) printf("%s%s: %s\n", dospace(1),
   1352 			    gettext("IP Address"), gettext("Not set"));
   1353 		}
   1354 	}
   1355 
   1356 	return (0);
   1357 }
   1358 
   1359 /*ARGSUSED*/
   1360 static int
   1361 showAdmin(int operandLen, char *operand[], cmdOptions_t *options)
   1362 {
   1363 	char		*first_str	= NULL;
   1364 	tgt_node_t	*node		= NULL;
   1365 	tgt_node_t	*n1		= NULL; /* pointer to node (depth=1) */
   1366 	tgt_node_t	*n2		= NULL; /* pointer to node (depth=2) */
   1367 
   1368 	if (operand == NULL)
   1369 		return (1);
   1370 
   1371 	tgt_buf_add_tag(&first_str, "list", Tag_Start);
   1372 	tgt_buf_add_tag(&first_str, XML_ELEMENT_ADMIN, Tag_Start);
   1373 	tgt_buf_add_tag(&first_str, XML_ELEMENT_ADMIN, Tag_End);
   1374 	tgt_buf_add_tag(&first_str, "list", Tag_End);
   1375 
   1376 	if ((node = tgt_door_call(first_str, 0)) == NULL) {
   1377 		(void) fprintf(stderr, "%s: %s\n", cmdName,
   1378 		    gettext("No reponse from daemon"));
   1379 		return (1);
   1380 	}
   1381 	free(first_str);
   1382 
   1383 	if (strcmp(node->x_name, XML_ELEMENT_RESULT)) {
   1384 		(void) fprintf(stderr, "%s: %s\n", cmdName,
   1385 		    gettext("Bad XML response"));
   1386 		return (1);
   1387 	}
   1388 
   1389 	(void) printf("%s:\n", cmdName);
   1390 
   1391 	n1 = tgt_node_next_child(node, XML_ELEMENT_ADMIN, NULL);
   1392 	if (n1 == NULL) {
   1393 		(void) fprintf(stderr, "%s: %s\n", cmdName,
   1394 		    gettext("Bad XML response"));
   1395 		return (1);
   1396 	}
   1397 
   1398 	n2 = tgt_node_next_child(n1, XML_ELEMENT_BASEDIR, NULL);
   1399 	(void) printf("%s%s: %s\n", dospace(1), gettext("Base Directory"),
   1400 	    n2 ? n2->x_value : gettext("Not set"));
   1401 
   1402 	n2 = tgt_node_next_child(n1, XML_ELEMENT_CHAPNAME, NULL);
   1403 	(void) printf("%s%s: %s\n", dospace(1), gettext("CHAP Name"),
   1404 	    n2 ? n2->x_value : gettext("Not set"));
   1405 
   1406 	n2 = tgt_node_next_child(n1, XML_ELEMENT_RAD_ACCESS, NULL);
   1407 	(void) printf("%s%s: ", dospace(1), gettext("RADIUS Access"));
   1408 	if (n2) {
   1409 		if (strcmp(n2->x_value, OPT_TRUE) == 0)
   1410 			(void) printf("%s\n", gettext("Enabled"));
   1411 		else
   1412 			(void) printf("%s\n", gettext("Disabled"));
   1413 	} else
   1414 		(void) printf("%s\n", gettext("Not set"));
   1415 
   1416 	n2 = tgt_node_next_child(n1, XML_ELEMENT_RAD_SERV, NULL);
   1417 	(void) printf("%s%s: %s\n", dospace(1), gettext("RADIUS Server"),
   1418 	    n2 ? n2->x_value : gettext("Not set"));
   1419 
   1420 	n2 = tgt_node_next_child(n1, XML_ELEMENT_ISNS_ACCESS, NULL);
   1421 	(void) printf("%s%s: ", dospace(1), gettext("iSNS Access"));
   1422 	if (n2) {
   1423 		if (strcmp(n2->x_value, OPT_TRUE) == 0)
   1424 			(void) printf("%s\n", gettext("Enabled"));
   1425 		else
   1426 			(void) printf("%s\n", gettext("Disabled"));
   1427 	} else
   1428 		(void) printf("%s\n", gettext("Not set"));
   1429 
   1430 	n2 = tgt_node_next_child(n1, XML_ELEMENT_ISNS_SERV, NULL);
   1431 	(void) printf("%s%s: %s\n", dospace(1), gettext("iSNS Server"),
   1432 	    n2 ? n2->x_value : gettext("Not set"));
   1433 
   1434 	n2 = tgt_node_next_child(n1, XML_ELEMENT_ISNS_SERVER_STATUS, NULL);
   1435 	if (n2) {
   1436 		/*
   1437 		 * if NULL, that means either the isns discovery is
   1438 		 * disabled or the server address is not set.
   1439 		 */
   1440 		if (n2->x_value != NULL) {
   1441 			(void) printf("%s%s: ", dospace(1),
   1442 			    gettext("iSNS Server Status"));
   1443 			(void) printf("%s\n", n2->x_value);
   1444 		}
   1445 	}
   1446 
   1447 	n2 = tgt_node_next_child(n1, XML_ELEMENT_FAST, NULL);
   1448 	(void) printf("%s%s: ", dospace(1), gettext("Fast Write ACK"));
   1449 	if (n2) {
   1450 		if (strcmp(n2->x_value, OPT_TRUE) == 0)
   1451 			(void) printf("%s\n", gettext("Enabled"));
   1452 		else
   1453 			(void) printf("%s\n", gettext("Disabled"));
   1454 	} else
   1455 		(void) printf("%s\n", gettext("Not set"));
   1456 
   1457 	return (0);
   1458 }
   1459 
   1460 static int
   1461 showStats(int operandLen, char *operand[], cmdOptions_t *options)
   1462 {
   1463 	char		*first_str	= NULL;
   1464 	char		scale_buf[16];
   1465 	tgt_node_t	*node, *n1;
   1466 	int		interval	= -1;
   1467 	int		count		= -1;
   1468 	int		header;
   1469 	stat_delta_t	cur_data, *pd;
   1470 
   1471 	tgt_buf_add_tag(&first_str, "list", Tag_Start);
   1472 	tgt_buf_add_tag(&first_str, XML_ELEMENT_TARG, Tag_Start);
   1473 
   1474 	tgt_buf_add(&first_str, XML_ELEMENT_IOSTAT, OPT_TRUE);
   1475 	if (operandLen)
   1476 		tgt_buf_add(&first_str, XML_ELEMENT_NAME, operand[0]);
   1477 
   1478 	for (; options->optval; options++) {
   1479 		switch (options->optval) {
   1480 		case 0:
   1481 			break;
   1482 		case 'I': /* optarg = refresh interval */
   1483 			interval = atoi(options->optarg);
   1484 			if (interval == 0) {
   1485 				(void) fprintf(stderr, "%s: %s\n", cmdName,
   1486 				    gettext("interval must be non-zero"));
   1487 				free(first_str);
   1488 				return (1);
   1489 			}
   1490 			break;
   1491 		case 'N':
   1492 			count = atoi(options->optarg);
   1493 			if (count == 0) {
   1494 				(void) fprintf(stderr, "%s: %s\n", cmdName,
   1495 				    gettext("count must be non-zero"));
   1496 				free(first_str);
   1497 				return (1);
   1498 			}
   1499 			break;
   1500 		default:
   1501 			(void) fprintf(stderr, "%s: %c: %s\n", cmdName,
   1502 			    options->optval, gettext("unknown option"));
   1503 			free(first_str);
   1504 			return (1);
   1505 		}
   1506 	}
   1507 
   1508 	tgt_buf_add_tag(&first_str, XML_ELEMENT_TARG, Tag_End);
   1509 	tgt_buf_add_tag(&first_str, "list", Tag_End);
   1510 
   1511 	header = 1;
   1512 	/*CONSTANTCONDITION*/
   1513 	while (1) {
   1514 		if (--header == 0) {
   1515 			(void) printf("%20s  %12s  %12s\n", " ",
   1516 			    gettext("operations"), gettext("bandwidth "));
   1517 			(void) printf("%-20s  %5s  %5s  %5s  %5s\n",
   1518 			    gettext("device"), gettext("read"),
   1519 			    gettext("write"), gettext("read"),
   1520 			    gettext("write"));
   1521 			(void) printf("%-20s  %5s  %5s  %5s  %5s\n",
   1522 			    "--------------------", "-----", "-----",
   1523 			    "-----", "-----");
   1524 			header = 20;
   1525 		}
   1526 		if ((node = tgt_door_call(first_str, 0)) == NULL) {
   1527 			(void) fprintf(stderr, "%s: %s\n", cmdName,
   1528 			    gettext("No reponse from daemon"));
   1529 			return (1);
   1530 		}
   1531 
   1532 		if (strcmp(node->x_name, XML_ELEMENT_RESULT)) {
   1533 			(void) fprintf(stderr, "%s: %s\n", cmdName,
   1534 			    gettext("Bad XML response"));
   1535 			free(first_str);
   1536 			tgt_node_free(node);
   1537 			stats_free();
   1538 			return (1);
   1539 		}
   1540 
   1541 		n1 = NULL;
   1542 		while (n1 = tgt_node_next_child(node, XML_ELEMENT_TARG, n1)) {
   1543 			stats_load_counts(n1, &cur_data);
   1544 			if ((pd = stats_prev_counts(&cur_data)) == NULL) {
   1545 				free(first_str);
   1546 				tgt_node_free(node);
   1547 				return (1);
   1548 			}
   1549 			(void) printf("%-20s  ", pd->device);
   1550 			(void) printf("%5s  ",
   1551 			    number_to_scaled_string(scale_buf,
   1552 			    cur_data.read_cmds - pd->read_cmds, 1, 1024));
   1553 			(void) printf("%5s  ",
   1554 			    number_to_scaled_string(scale_buf,
   1555 			    cur_data.write_cmds - pd->write_cmds, 1, 1024));
   1556 			(void) printf("%5s  ",
   1557 			    number_to_scaled_string(scale_buf,
   1558 			    cur_data.read_blks - pd->read_blks, 512, 1024));
   1559 			(void) printf("%5s\n",
   1560 			    number_to_scaled_string(scale_buf,
   1561 			    cur_data.write_blks - pd->write_blks, 512, 1024));
   1562 			stats_update_counts(pd, &cur_data);
   1563 		}
   1564 		tgt_node_free(node);
   1565 
   1566 		if (count == -1) {
   1567 			if (interval == -1)
   1568 				/* No count or internal, do it just once */
   1569 				break;
   1570 			else
   1571 				(void) sleep(interval);
   1572 		} else if (--count) {
   1573 			if (interval == -1)
   1574 				break;
   1575 			else
   1576 				(void) sleep(interval);
   1577 		} else
   1578 			break;
   1579 	}
   1580 
   1581 	stats_free();
   1582 	free(first_str);
   1583 	return (0);
   1584 }
   1585 
   1586 /*
   1587  * input:
   1588  *  execFullName - exec name of program (argv[0])
   1589  *
   1590  * Returns:
   1591  *  command name portion of execFullName
   1592  */
   1593 static char *
   1594 getExecBasename(char *execFullname)
   1595 {
   1596 	char *lastSlash, *execBasename;
   1597 
   1598 	/* guard against '/' at end of command invocation */
   1599 	for (;;) {
   1600 		lastSlash = strrchr(execFullname, '/');
   1601 		if (lastSlash == NULL) {
   1602 			execBasename = execFullname;
   1603 			break;
   1604 		} else {
   1605 			execBasename = lastSlash + 1;
   1606 			if (*execBasename == '\0') {
   1607 				*lastSlash = '\0';
   1608 				continue;
   1609 			}
   1610 			break;
   1611 		}
   1612 	}
   1613 	return (execBasename);
   1614 }
   1615 
   1616 /*
   1617  * main calls a parser that checks syntax of the input command against
   1618  * various rules tables.
   1619  *
   1620  * The parser provides usage feedback based upon same tables by calling
   1621  * two usage functions, usage and subUsage, handling command and subcommand
   1622  * usage respectively.
   1623  *
   1624  * The parser handles all printing of usage syntactical errors
   1625  *
   1626  * When syntax is successfully validated, the parser calls the associated
   1627  * function using the subcommands table functions.
   1628  *
   1629  * Syntax is as follows:
   1630  *	command subcommand [options] resource-type [<object>]
   1631  *
   1632  * The return value from the function is placed in funcRet
   1633  */
   1634 int
   1635 main(int argc, char *argv[])
   1636 {
   1637 	synTables_t synTables;
   1638 	char versionString[VERSION_STRING_MAX_LEN];
   1639 	int ret;
   1640 	int funcRet;
   1641 	void *subcommandArgs = NULL;
   1642 
   1643 	/* set global command name */
   1644 	cmdName = getExecBasename(argv[0]);
   1645 
   1646 	if (getzoneid() != GLOBAL_ZONEID) {
   1647 		(void) fprintf(stderr,
   1648 		    "%s: this command is only available in the 'global' "
   1649 		    "zone\n", cmdName);
   1650 		exit(1);
   1651 	}
   1652 
   1653 	(void) snprintf(versionString, sizeof (versionString), "%s.%s",
   1654 	    VERSION_STRING_MAJOR, VERSION_STRING_MINOR);
   1655 	synTables.versionString = versionString;
   1656 	synTables.longOptionTbl = &longOptions[0];
   1657 	synTables.subcommandTbl = &subcommands[0];
   1658 	synTables.objectTbl = &objects[0];
   1659 	synTables.objectRulesTbl = &objectRules[0];
   1660 	synTables.optionRulesTbl = &optionRules[0];
   1661 
   1662 	/* call the CLI parser */
   1663 	ret = cmdParse(argc, argv, synTables, subcommandArgs, &funcRet);
   1664 	if (ret == 1) {
   1665 		(void) printf("%s %s(1M)\n",
   1666 		    gettext("For more information, please see"), cmdName);
   1667 		return (1);
   1668 	} else if (ret == -1) {
   1669 		perror(cmdName);
   1670 		return (1);
   1671 	}
   1672 
   1673 	return (funcRet);
   1674 }
   1675