xref: /titanic_52/usr/src/cmd/stmfadm/stmfadm.c (revision 49d3bc91e27cd871b950d56c01398fa2f2e12ab4)
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  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <strings.h>
29 #include <sys/types.h>
30 #include <unistd.h>
31 #include <wchar.h>
32 #include <libintl.h>
33 #include <errno.h>
34 #include <time.h>
35 #include <string.h>
36 #include <assert.h>
37 #include <getopt.h>
38 #include <cmdparse.h>
39 #include <stmfadm.h>
40 #include <libstmf.h>
41 #include <signal.h>
42 #include <pthread.h>
43 #include <locale.h>
44 
45 static int addHostGroupMemberFunc(int, char **, cmdOptions_t *, void *);
46 static int addTargetGroupMemberFunc(int, char **, cmdOptions_t *, void *);
47 static int addViewFunc(int, char **, cmdOptions_t *, void *);
48 static int createHostGroupFunc(int, char **, cmdOptions_t *, void *);
49 static int createLuFunc(int, char **, cmdOptions_t *, void *);
50 static int modifyLuFunc(int, char **, cmdOptions_t *, void *);
51 static int importLuFunc(int, char **, cmdOptions_t *, void *);
52 static int deleteLuFunc(int, char **, cmdOptions_t *, void *);
53 static int createTargetGroupFunc(int, char **, cmdOptions_t *, void *);
54 static int deleteHostGroupFunc(int, char **, cmdOptions_t *, void *);
55 static int deleteTargetGroupFunc(int, char **, cmdOptions_t *, void *);
56 static int listLuFunc(int, char **, cmdOptions_t *, void *);
57 static int listTargetFunc(int, char **, cmdOptions_t *, void *);
58 static int listViewFunc(int, char **, cmdOptions_t *, void *);
59 static int listHostGroupFunc(int, char **, cmdOptions_t *, void *);
60 static int listStateFunc(int, char **, cmdOptions_t *, void *);
61 static int listTargetGroupFunc(int, char **, cmdOptions_t *, void *);
62 static int offlineTargetFunc(int, char **, cmdOptions_t *, void *);
63 static int offlineLuFunc(int, char **, cmdOptions_t *, void *);
64 static int onlineTargetFunc(int, char **, cmdOptions_t *, void *);
65 static int onlineLuFunc(int, char **, cmdOptions_t *, void *);
66 static int onlineOfflineTarget(char *, int);
67 static int onlineOfflineLu(char *, int);
68 static int removeHostGroupMemberFunc(int, char **, cmdOptions_t *, void *);
69 static int removeTargetGroupMemberFunc(int, char **, cmdOptions_t *, void *);
70 static int callModify(char *, stmfGuid *, uint32_t, const char *, const char *);
71 static int removeViewFunc(int, char **, cmdOptions_t *, void *);
72 static char *getExecBasename(char *);
73 static int parseDevid(char *input, stmfDevid *devid);
74 static void printGroupProps(stmfGroupProperties *groupProps);
75 static int checkScsiNameString(wchar_t *, stmfDevid *);
76 static int checkHexUpper(char *);
77 static int checkIscsiName(wchar_t *);
78 static void printLuProps(stmfLogicalUnitProperties *luProps);
79 static int printExtLuProps(stmfGuid *guid);
80 static void printGuid(stmfGuid *guid, FILE *printWhere);
81 static void printTargetProps(stmfTargetProperties *);
82 static void printSessionProps(stmfSessionList *);
83 static int setLuPropFromInput(luResource, char *);
84 static int convertCharToPropId(char *, uint32_t *);
85 
86 
87 
88 /*
89  *  MAJOR - This should only change when there is an incompatible change made
90  *  to the interfaces or the output.
91  *
92  *  MINOR - This should change whenever there is a new command or new feature
93  *  with no incompatible change.
94  */
95 #define	VERSION_STRING_MAJOR	    "1"
96 #define	VERSION_STRING_MINOR	    "0"
97 #define	MAX_DEVID_INPUT		    256
98 #define	GUID_INPUT		    32
99 #define	MAX_LU_NBR		    16383
100 #define	ONLINE_LU		    0
101 #define	OFFLINE_LU		    1
102 #define	ONLINE_TARGET		    2
103 #define	OFFLINE_TARGET		    3
104 #define	PROPS_FORMAT		    "    %-18s: "
105 #define	VIEW_FORMAT		    "    %-13s: "
106 #define	LVL3_FORMAT		    "        %s"
107 #define	LVL4_FORMAT		    "            %s"
108 #define	DELAYED_EXEC_WAIT_INTERVAL  300 * 1000 * 1000	/* in nano sec */
109 #define	DELAYED_EXEC_WAIT_MAX	    30	/* Maximum number of interval times */
110 
111 /* SCSI Name String length definitions */
112 #define	SNS_EUI_16		    16
113 #define	SNS_EUI_24		    24
114 #define	SNS_EUI_32		    32
115 #define	SNS_NAA_16		    16
116 #define	SNS_NAA_32		    32
117 #define	SNS_WWN_16		    16
118 #define	SNS_IQN_223		    223
119 
120 /* LU Property strings */
121 #define	GUID			    "GUID"
122 #define	ALIAS			    "ALIAS"
123 #define	VID			    "VID"
124 #define	PID			    "PID"
125 #define	META_FILE		    "META"
126 #define	WRITE_PROTECT		    "WP"
127 #define	WRITEBACK_CACHE_DISABLE	    "WCD"
128 #define	COMPANY_ID		    "OUI"
129 #define	BLOCK_SIZE		    "BLK"
130 #define	SERIAL_NUMBER		    "SERIAL"
131 #define	MGMT_URL		    "MGMT-URL"
132 #define	HOST_ID			    "HOST-ID"
133 
134 #define	STMFADM_SUCCESS		    0
135 #define	STMFADM_FAILURE		    1
136 
137 #define	MODIFY_HELP "\n"\
138 "Description: Modify properties of a logical unit. \n" \
139 "Valid properties for -p, --lu-prop are: \n" \
140 "     alias    - alias for logical unit (up to 255 chars)\n" \
141 "     mgmt-url - Management URL address\n" \
142 "     wcd      - write cache disabled (true, false)\n" \
143 "     wp       - write protect (true, false)\n\n" \
144 "-f alters the meaning of the operand to be a file name\n" \
145 "rather than a LU name. This allows for modification\n" \
146 "of a logical unit that is not yet imported into stmf\n"
147 
148 #define	CREATE_HELP "\n"\
149 "Description: Create a logical unit. \n" \
150 "Valid properties for -p, --lu-prop are: \n" \
151 "     alias    - alias for logical unit (up to 255 chars)\n" \
152 "     blk      - block size in bytes in 2^n\n" \
153 "     guid     - 32 ascii hex characters in NAA format \n" \
154 "     host-id  - host identifier to be used for GUID generation \n" \
155 "                8 ascii hex characters\n" \
156 "     meta     - separate meta data file name\n" \
157 "     mgmt-url - Management URL address\n" \
158 "     oui      - organizational unique identifier\n" \
159 "                6 ascii hex characters of valid format\n" \
160 "     pid      - product identifier (up to 16 chars)\n" \
161 "     serial   - serial number (up to 252 chars)\n" \
162 "     vid      - vendor identifier (up to 8 chars)\n" \
163 "     wcd      - write cache disabled (true, false)\n" \
164 "     wp       - write protect (true, false)\n"
165 #define	ADD_VIEW_HELP "\n"\
166 "Description: Add a view entry to a logical unit. \n" \
167 "A view entry is comprised of three elements; the \n" \
168 "logical unit number, the target group name and the\n" \
169 "host group name. These three elements combine together\n" \
170 "to form a view for a given COMSTAR logical unit.\n" \
171 "This view is realized by a client, a SCSI initiator,\n" \
172 "via a REPORT LUNS command. \n"
173 
174 
175 
176 /* tables set up based on cmdparse instructions */
177 
178 /* add new options here */
179 optionTbl_t longOptions[] = {
180 	{"all", no_arg, 'a', NULL},
181 	{"group-name", required_arg, 'g', "group-name"},
182 	{"keep-views", no_arg, 'k', NULL},
183 	{"lu-name", required_arg, 'l', "LU-Name"},
184 	{"lun", required_arg, 'n', "logical-unit-number"},
185 	{"lu-prop", required_arg, 'p', "logical-unit-property=value"},
186 	{"file", no_arg, 'f', "filename"},
187 	{"size", required_arg, 's', "size K/M/G/T/P"},
188 	{"target-group", required_arg, 't', "group-name"},
189 	{"host-group", required_arg, 'h', "group-name"},
190 	{"verbose", no_arg, 'v', NULL},
191 	{NULL, 0, 0, 0}
192 };
193 
194 /*
195  * Add new subcommands here
196  */
197 subCommandProps_t subcommands[] = {
198 	{"add-hg-member", addHostGroupMemberFunc, "g", "g", NULL,
199 		OPERAND_MANDATORY_MULTIPLE, OPERANDSTRING_GROUP_MEMBER, NULL},
200 	{"add-tg-member", addTargetGroupMemberFunc, "g", "g", NULL,
201 		OPERAND_MANDATORY_MULTIPLE, OPERANDSTRING_GROUP_MEMBER, NULL},
202 	{"add-view", addViewFunc, "nth", NULL, NULL,
203 		OPERAND_MANDATORY_SINGLE, OPERANDSTRING_LU, ADD_VIEW_HELP},
204 	{"create-hg", createHostGroupFunc, NULL, NULL, NULL,
205 		OPERAND_MANDATORY_SINGLE, OPERANDSTRING_GROUP_NAME, NULL},
206 	{"create-tg", createTargetGroupFunc, NULL, NULL, NULL,
207 		OPERAND_MANDATORY_SINGLE, OPERANDSTRING_GROUP_NAME, NULL},
208 	{"create-lu", createLuFunc, "ps", NULL, NULL, OPERAND_MANDATORY_SINGLE,
209 		"lu file", CREATE_HELP},
210 	{"delete-hg", deleteHostGroupFunc, NULL, NULL, NULL,
211 		OPERAND_MANDATORY_SINGLE, OPERANDSTRING_GROUP_NAME, NULL},
212 	{"modify-lu", modifyLuFunc, "psf", NULL, NULL, OPERAND_MANDATORY_SINGLE,
213 		OPERANDSTRING_LU, MODIFY_HELP},
214 	{"delete-lu", deleteLuFunc, "k", NULL, NULL,
215 		OPERAND_MANDATORY_MULTIPLE, OPERANDSTRING_LU, NULL},
216 	{"delete-tg", deleteTargetGroupFunc, NULL, NULL, NULL,
217 		OPERAND_MANDATORY_SINGLE, OPERANDSTRING_GROUP_NAME, NULL},
218 	{"import-lu", importLuFunc, NULL, NULL, NULL,
219 		OPERAND_MANDATORY_SINGLE, "file name", NULL},
220 	{"list-hg", listHostGroupFunc, "v", NULL, NULL,
221 		OPERAND_OPTIONAL_MULTIPLE, OPERANDSTRING_GROUP_NAME, NULL},
222 	{"list-lu", listLuFunc, "v", NULL, NULL, OPERAND_OPTIONAL_MULTIPLE,
223 		OPERANDSTRING_LU, NULL},
224 	{"list-state", listStateFunc, NULL, NULL, NULL, OPERAND_NONE, NULL},
225 	{"list-target", listTargetFunc, "v", NULL, NULL,
226 		OPERAND_OPTIONAL_MULTIPLE, OPERANDSTRING_TARGET, NULL},
227 	{"list-tg", listTargetGroupFunc, "v", NULL, NULL,
228 		OPERAND_OPTIONAL_MULTIPLE, OPERANDSTRING_GROUP_NAME, NULL},
229 	{"list-view", listViewFunc, "l", "l", NULL,
230 		OPERAND_OPTIONAL_MULTIPLE, OPERANDSTRING_VIEW_ENTRY, NULL},
231 	{"online-lu", onlineLuFunc, NULL, NULL, NULL,
232 		OPERAND_MANDATORY_SINGLE, OPERANDSTRING_LU, NULL},
233 	{"offline-lu", offlineLuFunc, NULL, NULL, NULL,
234 		OPERAND_MANDATORY_SINGLE, OPERANDSTRING_LU, NULL},
235 	{"online-target", onlineTargetFunc, NULL, NULL, NULL,
236 		OPERAND_MANDATORY_SINGLE, OPERANDSTRING_TARGET, NULL},
237 	{"offline-target", offlineTargetFunc, NULL, NULL, NULL,
238 		OPERAND_MANDATORY_SINGLE, OPERANDSTRING_TARGET, NULL},
239 	{"remove-hg-member", removeHostGroupMemberFunc, "g", "g", NULL,
240 		OPERAND_MANDATORY_MULTIPLE, OPERANDSTRING_GROUP_MEMBER, NULL},
241 	{"remove-tg-member", removeTargetGroupMemberFunc, "g", "g", NULL,
242 		OPERAND_MANDATORY_MULTIPLE, OPERANDSTRING_GROUP_MEMBER, NULL},
243 	{"remove-view", removeViewFunc, "la", "l", NULL,
244 		OPERAND_OPTIONAL_MULTIPLE, OPERANDSTRING_VIEW_ENTRY, NULL},
245 	{NULL, 0, NULL, NULL, 0, NULL, 0, NULL, NULL}
246 };
247 
248 /* globals */
249 char *cmdName;
250 
251 /*
252  * addHostGroupMemberFunc
253  *
254  * Add members to a host group
255  *
256  */
257 /*ARGSUSED*/
258 static int
259 addHostGroupMemberFunc(int operandLen, char *operands[], cmdOptions_t *options,
260     void *args)
261 {
262 	int i;
263 	int ret = 0;
264 	int stmfRet;
265 	stmfGroupName groupName = {0};
266 	wchar_t groupNamePrint[sizeof (stmfGroupName)] = {0};
267 	stmfDevid devid;
268 
269 	for (; options->optval; options++) {
270 		switch (options->optval) {
271 			/* host group name */
272 			case 'g':
273 				(void) mbstowcs(groupNamePrint, options->optarg,
274 				    sizeof (stmfGroupName) - 1);
275 				bcopy(options->optarg, groupName,
276 				    strlen(options->optarg));
277 				break;
278 			default:
279 				(void) fprintf(stderr, "%s: %c: %s\n",
280 				    cmdName, options->optval,
281 				    gettext("unknown option"));
282 				return (1);
283 		}
284 	}
285 
286 	for (i = 0; i < operandLen; i++) {
287 		if (parseDevid(operands[i], &devid) != 0) {
288 			(void) fprintf(stderr, "%s: %s: %s\n",
289 			    cmdName, operands[i],
290 			    gettext("unrecognized device id"));
291 			ret++;
292 			continue;
293 		}
294 		stmfRet = stmfAddToHostGroup(&groupName, &devid);
295 		switch (stmfRet) {
296 			case STMF_STATUS_SUCCESS:
297 				break;
298 			case STMF_ERROR_EXISTS:
299 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
300 				    operands[i], gettext("already exists"));
301 				ret++;
302 				break;
303 			case STMF_ERROR_GROUP_NOT_FOUND:
304 				(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
305 				    groupNamePrint, gettext("not found"));
306 				ret++;
307 				break;
308 			case STMF_ERROR_PERM:
309 				(void) fprintf(stderr, "%s: %s\n", cmdName,
310 				    gettext("permission denied"));
311 				ret++;
312 				break;
313 			case STMF_ERROR_BUSY:
314 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
315 				    operands[i], gettext("resource busy"));
316 				ret++;
317 				break;
318 			case STMF_ERROR_SERVICE_NOT_FOUND:
319 				(void) fprintf(stderr, "%s: %s\n", cmdName,
320 				    gettext("STMF service not found"));
321 				ret++;
322 				break;
323 			case STMF_ERROR_SERVICE_DATA_VERSION:
324 				(void) fprintf(stderr, "%s: %s\n", cmdName,
325 				    gettext("STMF service version incorrect"));
326 				ret++;
327 				break;
328 			default:
329 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
330 				    operands[i], gettext("unknown error"));
331 				ret++;
332 				break;
333 		}
334 	}
335 
336 	return (ret);
337 }
338 
339 /*
340  * addTargetGroupMemberFunc
341  *
342  * Add members to a target group
343  *
344  */
345 /*ARGSUSED*/
346 static int
347 addTargetGroupMemberFunc(int operandLen, char *operands[],
348     cmdOptions_t *options, void *args)
349 {
350 	int i;
351 	int ret = 0;
352 	int stmfRet;
353 	stmfGroupName groupName = {0};
354 	wchar_t groupNamePrint[sizeof (stmfGroupName)] = {0};
355 	stmfDevid devid;
356 
357 	for (; options->optval; options++) {
358 		switch (options->optval) {
359 			/* target group name */
360 			case 'g':
361 				(void) mbstowcs(groupNamePrint, options->optarg,
362 				    sizeof (stmfGroupName) - 1);
363 				bcopy(options->optarg, groupName,
364 				    strlen(options->optarg));
365 				break;
366 			default:
367 				(void) fprintf(stderr, "%s: %c: %s\n",
368 				    cmdName, options->optval,
369 				    gettext("unknown option"));
370 				return (1);
371 		}
372 	}
373 
374 	for (i = 0; i < operandLen; i++) {
375 		if (parseDevid(operands[i], &devid) != 0) {
376 			(void) fprintf(stderr, "%s: %s: %s\n",
377 			    cmdName, operands[i],
378 			    gettext("unrecognized device id"));
379 			ret++;
380 			continue;
381 		}
382 		stmfRet = stmfAddToTargetGroup(&groupName, &devid);
383 		switch (stmfRet) {
384 			case STMF_STATUS_SUCCESS:
385 				break;
386 			case STMF_ERROR_EXISTS:
387 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
388 				    operands[i], gettext("already exists"));
389 				ret++;
390 				break;
391 			case STMF_ERROR_GROUP_NOT_FOUND:
392 				(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
393 				    groupNamePrint, gettext("not found"));
394 				ret++;
395 				break;
396 			case STMF_ERROR_PERM:
397 				(void) fprintf(stderr, "%s: %s\n", cmdName,
398 				    gettext("permission denied"));
399 				ret++;
400 				break;
401 			case STMF_ERROR_BUSY:
402 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
403 				    operands[i], gettext("resource busy"));
404 				ret++;
405 				break;
406 			case STMF_ERROR_SERVICE_NOT_FOUND:
407 				(void) fprintf(stderr, "%s: %s\n", cmdName,
408 				    gettext("STMF service not found"));
409 				ret++;
410 				break;
411 			case STMF_ERROR_SERVICE_ONLINE:
412 				(void) fprintf(stderr, "%s: %s\n", cmdName,
413 				    gettext("STMF service must be offline"));
414 				ret++;
415 				break;
416 			case STMF_ERROR_SERVICE_DATA_VERSION:
417 				(void) fprintf(stderr, "%s: %s\n", cmdName,
418 				    gettext("STMF service version incorrect"));
419 				ret++;
420 				break;
421 			case STMF_ERROR_TG_ONLINE:
422 				(void) fprintf(stderr, "%s: %s\n", cmdName,
423 				    gettext("STMF target must be offline"));
424 				ret++;
425 				break;
426 			default:
427 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
428 				    operands[i], gettext("unknown error"));
429 				ret++;
430 				break;
431 		}
432 	}
433 
434 	return (ret);
435 }
436 
437 /*
438  * parseDevid
439  *
440  * Converts char * input to a stmfDevid
441  *
442  * input - this should be in the following format with either a
443  * wwn. iqn. or eui. representation.
444  * A name string of the format:
445  *	wwn.<WWN> (FC/SAS address)
446  *	iqn.<iSCSI name> (iSCSI iqn)
447  *	eui.<WWN> (iSCSI eui name)
448  *
449  * devid - pointer to stmfDevid structure allocated by the caller.
450  *
451  * Returns:
452  *  0 on success
453  *  non-zero on failure
454  */
455 static int
456 parseDevid(char *input, stmfDevid *devid)
457 {
458 	wchar_t inputWc[MAX_DEVID_INPUT + 1] = {0};
459 
460 	/* convert to wcs */
461 	(void) mbstowcs(inputWc, input, MAX_DEVID_INPUT);
462 
463 	/*
464 	 * Check for known scsi name string formats
465 	 * If one is found, we're done
466 	 * If not, then it's a failure to parse
467 	 */
468 	if (checkScsiNameString(inputWc, devid) == 0) {
469 		return (0);
470 	}
471 
472 	return (-1);
473 }
474 
475 /*
476  * checkScsiNameString
477  *
478  * Validates known SCSI name string formats and converts to stmfDevid
479  * format
480  *
481  * input - input SCSI name string
482  * devid - pointer to stmfDevid structure allocated by the caller
483  *         on successful return, contains the devid based on input
484  *
485  * returns:
486  *         0 on success
487  *         -1 on failure
488  */
489 static int
490 checkScsiNameString(wchar_t *input, stmfDevid *devid)
491 {
492 	char *mbString = NULL;
493 	int mbStringLen;
494 	int len;
495 	int i;
496 
497 	/*
498 	 * Convert to multi-byte string
499 	 *
500 	 * This is used for either eui or naa formats
501 	 */
502 	mbString = calloc(1, (mbStringLen = wcstombs(mbString, input, 0)) + 1);
503 	if (mbString == NULL) {
504 		(void) fprintf(stderr, "%s: %s\n",
505 		    cmdName, "Insufficient memory\n");
506 		return (-1);
507 	}
508 	if (wcstombs(mbString, input, mbStringLen) == (size_t)-1) {
509 		return (-1);
510 	}
511 
512 	/*
513 	 * check for iqn format
514 	 */
515 	if (strncmp(mbString, "iqn.", 4) == 0) {
516 		if ((len = strlen(mbString)) > (SNS_IQN_223)) {
517 			return (-1);
518 		}
519 		for (i = 0; i < len; i++) {
520 			mbString[i] = tolower(mbString[i]);
521 		}
522 		if (checkIscsiName(input + 4) != 0) {
523 			return (-1);
524 		}
525 	} else if (strncmp(mbString, "wwn.", 4) == 0) {
526 		if ((len = strlen(mbString + 4)) != SNS_WWN_16) {
527 			return (-1);
528 		} else if (checkHexUpper(mbString + 4) != 0) {
529 			return (-1);
530 		}
531 	} else if (strncmp(mbString, "eui.", 4) == 0) {
532 		if ((len = strlen(mbString + 4)) != SNS_EUI_16) {
533 			return (-1);
534 		} else if (checkHexUpper(mbString + 4) != 0) {
535 			return (-1);
536 		}
537 	} else {
538 		return (-1);
539 	}
540 
541 	/*
542 	 * We have a validated name string.
543 	 * Go ahead and set the length and copy it.
544 	 */
545 	devid->identLength = strlen(mbString);
546 	bzero(devid->ident, STMF_IDENT_LENGTH);
547 	bcopy(mbString, devid->ident, devid->identLength);
548 
549 	return (0);
550 }
551 
552 
553 /*
554  * Checks whether the entire string is in hex and converts to upper
555  */
556 static int
557 checkHexUpper(char *input)
558 {
559 	int i;
560 
561 	for (i = 0; i < strlen(input); i++) {
562 		if (isxdigit(input[i])) {
563 			input[i] = toupper(input[i]);
564 			continue;
565 		}
566 		return (-1);
567 	}
568 
569 	return (0);
570 }
571 
572 /*
573  * checkIscsiName
574  *
575  * Purpose: Basic string checking on name
576  */
577 static int
578 checkIscsiName(wchar_t *input)
579 {
580 	int i;
581 
582 	for (i = 0; input[i] != 0; i++) {
583 		if (!iswalnum(input[i]) && input[i] != '-' &&
584 		    input[i] != '.' && input[i] != ':') {
585 			return (-1);
586 		}
587 	}
588 
589 	return (0);
590 }
591 
592 
593 /*
594  * addViewFunc
595  *
596  * Adds a view entry to a logical unit
597  *
598  */
599 /*ARGSUSED*/
600 static int
601 addViewFunc(int operandLen, char *operands[], cmdOptions_t *options,
602     void *args)
603 {
604 	stmfViewEntry viewEntry;
605 	stmfGuid inGuid;
606 	unsigned int guid[sizeof (stmfGuid)];
607 	uint16_t inputLuNbr;
608 	int ret = 0;
609 	int stmfRet;
610 	int i;
611 	char sGuid[GUID_INPUT + 1];
612 
613 	bzero(&viewEntry, sizeof (viewEntry));
614 	/* init view entry structure */
615 	viewEntry.allHosts = B_TRUE;
616 	viewEntry.allTargets = B_TRUE;
617 	viewEntry.luNbrValid = B_FALSE;
618 
619 	/* check input length */
620 	if (strlen(operands[0]) != GUID_INPUT) {
621 		(void) fprintf(stderr, "%s: %s: %s%d%s\n", cmdName, operands[0],
622 		    gettext("must be "), GUID_INPUT,
623 		    gettext(" hexadecimal digits"));
624 		return (1);
625 	}
626 
627 	for (; options->optval; options++) {
628 		switch (options->optval) {
629 			/* logical unit number */
630 			case 'n':
631 				viewEntry.luNbrValid = B_TRUE;
632 				inputLuNbr = atoi(options->optarg);
633 				if (inputLuNbr > MAX_LU_NBR) {
634 					(void) fprintf(stderr, "%s: %d: %s\n",
635 					    cmdName, inputLuNbr,
636 					    gettext("Logical unit number"
637 					    " must be less than 16384"));
638 					return (1);
639 				}
640 				viewEntry.luNbr[0] = inputLuNbr >> 8;
641 				viewEntry.luNbr[1] = inputLuNbr & 0xff;
642 				break;
643 			/* host group */
644 			case 'h':
645 				viewEntry.allHosts = B_FALSE;
646 				bcopy(options->optarg, viewEntry.hostGroup,
647 				    strlen(options->optarg));
648 				break;
649 			/* target group */
650 			case 't':
651 				viewEntry.allTargets = B_FALSE;
652 				bcopy(options->optarg, viewEntry.targetGroup,
653 				    strlen(options->optarg));
654 				break;
655 			default:
656 				(void) fprintf(stderr, "%s: %c: %s\n",
657 				    cmdName, options->optval,
658 				    gettext("unknown option"));
659 				return (1);
660 		}
661 	}
662 
663 	/* convert to lower case for scan */
664 	for (i = 0; i < 32; i++)
665 		sGuid[i] = tolower(operands[0][i]);
666 	sGuid[i] = 0;
667 
668 	(void) sscanf(sGuid, "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
669 	    &guid[0], &guid[1], &guid[2], &guid[3], &guid[4], &guid[5],
670 	    &guid[6], &guid[7], &guid[8], &guid[9], &guid[10], &guid[11],
671 	    &guid[12], &guid[13], &guid[14], &guid[15]);
672 
673 	for (i = 0; i < sizeof (stmfGuid); i++) {
674 		inGuid.guid[i] = guid[i];
675 	}
676 
677 	/* add the view entry */
678 	stmfRet = stmfAddViewEntry(&inGuid, &viewEntry);
679 	switch (stmfRet) {
680 		case STMF_STATUS_SUCCESS:
681 			break;
682 		case STMF_ERROR_EXISTS:
683 			(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
684 			    operands[0], gettext("already exists"));
685 			ret++;
686 			break;
687 		case STMF_ERROR_BUSY:
688 			(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
689 			    operands[0], gettext("resource busy"));
690 			ret++;
691 			break;
692 		case STMF_ERROR_SERVICE_NOT_FOUND:
693 			(void) fprintf(stderr, "%s: %s\n", cmdName,
694 			    gettext("STMF service not found"));
695 			ret++;
696 			break;
697 		case STMF_ERROR_PERM:
698 			(void) fprintf(stderr, "%s: %s\n", cmdName,
699 			    gettext("permission denied"));
700 			ret++;
701 			break;
702 		case STMF_ERROR_LUN_IN_USE:
703 			(void) fprintf(stderr, "%s: %s\n", cmdName,
704 			    gettext("LUN already in use"));
705 			ret++;
706 			break;
707 		case STMF_ERROR_VE_CONFLICT:
708 			(void) fprintf(stderr, "%s: %s\n", cmdName,
709 			    gettext("view entry exists"));
710 			ret++;
711 			break;
712 		case STMF_ERROR_CONFIG_NONE:
713 			(void) fprintf(stderr, "%s: %s\n", cmdName,
714 			    gettext("STMF service is not initialized"));
715 			ret++;
716 			break;
717 		case STMF_ERROR_SERVICE_DATA_VERSION:
718 			(void) fprintf(stderr, "%s: %s\n", cmdName,
719 			    gettext("STMF service version incorrect"));
720 			ret++;
721 			break;
722 		case STMF_ERROR_INVALID_HG:
723 			(void) fprintf(stderr, "%s: %s\n", cmdName,
724 			    gettext("invalid host group"));
725 			ret++;
726 			break;
727 		case STMF_ERROR_INVALID_TG:
728 			(void) fprintf(stderr, "%s: %s\n", cmdName,
729 			    gettext("invalid target group"));
730 			ret++;
731 			break;
732 		default:
733 			(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
734 			    operands[0], gettext("unknown error"));
735 			ret++;
736 			break;
737 	}
738 
739 	return (ret);
740 }
741 
742 /*
743  * createHostGroupFunc
744  *
745  * Create a host group
746  *
747  */
748 /*ARGSUSED*/
749 static int
750 createHostGroupFunc(int operandLen, char *operands[],
751     cmdOptions_t *options, void *args)
752 {
753 	int ret = 0;
754 	int stmfRet;
755 	wchar_t groupNamePrint[sizeof (stmfGroupName)] = {0};
756 	stmfGroupName groupName = {0};
757 
758 	(void) strlcpy(groupName, operands[0], sizeof (groupName));
759 	(void) mbstowcs(groupNamePrint, (char *)groupName,
760 	    sizeof (stmfGroupName) - 1);
761 	/* call create group */
762 	stmfRet = stmfCreateHostGroup(&groupName);
763 	switch (stmfRet) {
764 		case STMF_STATUS_SUCCESS:
765 			break;
766 		case STMF_ERROR_EXISTS:
767 			(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
768 			    operands[0], gettext("already exists"));
769 			ret++;
770 			break;
771 		case STMF_ERROR_BUSY:
772 			(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
773 			    operands[0], gettext("resource busy"));
774 			ret++;
775 			break;
776 		case STMF_ERROR_SERVICE_NOT_FOUND:
777 			(void) fprintf(stderr, "%s: %s\n", cmdName,
778 			    gettext("STMF service not found"));
779 			ret++;
780 			break;
781 		case STMF_ERROR_PERM:
782 			(void) fprintf(stderr, "%s: %s\n", cmdName,
783 			    gettext("permission denied"));
784 			ret++;
785 			break;
786 		case STMF_ERROR_SERVICE_DATA_VERSION:
787 			(void) fprintf(stderr, "%s: %s\n", cmdName,
788 			    gettext("STMF service version incorrect"));
789 			ret++;
790 			break;
791 		default:
792 			(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
793 			    operands[0], gettext("unknown error"));
794 			ret++;
795 			break;
796 	}
797 
798 	return (ret);
799 }
800 
801 /*
802  * createLuFunc
803  *
804  * Create a logical unit
805  *
806  */
807 /*ARGSUSED*/
808 static int
809 createLuFunc(int operandLen, char *operands[], cmdOptions_t *options,
810     void *args)
811 {
812 	luResource hdl = NULL;
813 	int ret = 0;
814 	int stmfRet = 0;
815 	char guidAsciiBuf[33];
816 	stmfGuid createdGuid;
817 
818 	stmfRet = stmfCreateLuResource(STMF_DISK, &hdl);
819 
820 	if (stmfRet != STMF_STATUS_SUCCESS) {
821 		(void) fprintf(stderr, "%s: %s\n",
822 		    cmdName, gettext("Failure to create lu resource\n"));
823 		return (1);
824 	}
825 
826 	for (; options->optval; options++) {
827 		switch (options->optval) {
828 			case 'p':
829 				ret = setLuPropFromInput(hdl, options->optarg);
830 				if (ret != 0) {
831 					(void) stmfFreeLuResource(hdl);
832 					return (1);
833 				}
834 				break;
835 			case 's':
836 				stmfRet = stmfSetLuProp(hdl, STMF_LU_PROP_SIZE,
837 				    options->optarg);
838 				if (stmfRet != STMF_STATUS_SUCCESS) {
839 					(void) fprintf(stderr, "%s: %c: %s\n",
840 					    cmdName, options->optval,
841 					    gettext("size param invalid"));
842 					(void) stmfFreeLuResource(hdl);
843 					return (1);
844 				}
845 				break;
846 			default:
847 				(void) fprintf(stderr, "%s: %c: %s\n",
848 				    cmdName, options->optval,
849 				    gettext("unknown option"));
850 				return (1);
851 		}
852 	}
853 
854 	stmfRet = stmfSetLuProp(hdl, STMF_LU_PROP_FILENAME, operands[0]);
855 
856 	if (stmfRet != STMF_STATUS_SUCCESS) {
857 		(void) fprintf(stderr, "%s: %s\n",
858 		    cmdName, gettext("could not set filename"));
859 		return (1);
860 	}
861 
862 	stmfRet = stmfCreateLu(hdl, &createdGuid);
863 	switch (stmfRet) {
864 		case STMF_STATUS_SUCCESS:
865 			break;
866 		case STMF_ERROR_BUSY:
867 		case STMF_ERROR_LU_BUSY:
868 			(void) fprintf(stderr, "%s: %s\n", cmdName,
869 			    gettext("resource busy"));
870 			ret++;
871 			break;
872 		case STMF_ERROR_PERM:
873 			(void) fprintf(stderr, "%s: %s\n", cmdName,
874 			    gettext("permission denied"));
875 			ret++;
876 			break;
877 		case STMF_ERROR_FILE_IN_USE:
878 			(void) fprintf(stderr, "%s: filename %s: %s\n", cmdName,
879 			    operands[0], gettext("in use"));
880 			ret++;
881 			break;
882 		case STMF_ERROR_INVALID_BLKSIZE:
883 			(void) fprintf(stderr, "%s: %s\n", cmdName,
884 			    gettext("invalid block size"));
885 			ret++;
886 			break;
887 		case STMF_ERROR_GUID_IN_USE:
888 			(void) fprintf(stderr, "%s: %s\n", cmdName,
889 			    gettext("guid in use"));
890 			ret++;
891 			break;
892 		case STMF_ERROR_META_FILE_NAME:
893 			(void) fprintf(stderr, "%s: %s\n", cmdName,
894 			    gettext("meta file error"));
895 			ret++;
896 			break;
897 		case STMF_ERROR_DATA_FILE_NAME:
898 			(void) fprintf(stderr, "%s: %s\n", cmdName,
899 			    gettext("data file error"));
900 			ret++;
901 			break;
902 		case STMF_ERROR_FILE_SIZE_INVALID:
903 			(void) fprintf(stderr, "%s: %s\n", cmdName,
904 			    gettext("file size invalid"));
905 			ret++;
906 			break;
907 		case STMF_ERROR_SIZE_OUT_OF_RANGE:
908 			(void) fprintf(stderr, "%s: %s\n", cmdName,
909 			    gettext("invalid size"));
910 			ret++;
911 			break;
912 		case STMF_ERROR_META_CREATION:
913 			(void) fprintf(stderr, "%s: %s\n", cmdName,
914 			    gettext("could not create meta file"));
915 			ret++;
916 			break;
917 		case STMF_ERROR_WRITE_CACHE_SET:
918 			(void) fprintf(stderr, "%s: %s\n", cmdName,
919 			    gettext("could not set write cache"));
920 			ret++;
921 			break;
922 		default:
923 			(void) fprintf(stderr, "%s: %s\n", cmdName,
924 			    gettext("unknown error"));
925 			ret++;
926 			break;
927 	}
928 
929 	if (ret != 0) {
930 		goto done;
931 	}
932 
933 	(void) snprintf(guidAsciiBuf, sizeof (guidAsciiBuf),
934 	    "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X"
935 	    "%02X%02X%02X%02X%02X%02X",
936 	    createdGuid.guid[0], createdGuid.guid[1], createdGuid.guid[2],
937 	    createdGuid.guid[3], createdGuid.guid[4], createdGuid.guid[5],
938 	    createdGuid.guid[6], createdGuid.guid[7], createdGuid.guid[8],
939 	    createdGuid.guid[9], createdGuid.guid[10], createdGuid.guid[11],
940 	    createdGuid.guid[12], createdGuid.guid[13], createdGuid.guid[14],
941 	    createdGuid.guid[15]);
942 	(void) printf("Logical unit created: %s\n", guidAsciiBuf);
943 
944 done:
945 	(void) stmfFreeLuResource(hdl);
946 	return (ret);
947 }
948 
949 /*
950  * createLuFunc
951  *
952  * Create a logical unit
953  *
954  */
955 /*ARGSUSED*/
956 static int
957 modifyLuFunc(int operandLen, char *operands[], cmdOptions_t *options,
958     void *args)
959 {
960 	stmfGuid inGuid;
961 	unsigned int guid[sizeof (stmfGuid)];
962 	int ret = 0;
963 	int i;
964 	char *fname = NULL;
965 	char *lasts = NULL;
966 	char sGuid[GUID_INPUT + 1];
967 	char *prop = NULL;
968 	char *propVal = NULL;
969 	boolean_t fnameUsed = B_FALSE;
970 	uint32_t propId;
971 	cmdOptions_t *optionStart = options;
972 
973 
974 	for (; options->optval; options++) {
975 		switch (options->optval) {
976 			case 'f':
977 				fnameUsed = B_TRUE;
978 				fname = operands[0];
979 				break;
980 		}
981 	}
982 	options = optionStart;
983 
984 	/* check input length */
985 	if (!fnameUsed && strlen(operands[0]) != GUID_INPUT) {
986 		(void) fprintf(stderr, "%s: %s: %s%d%s\n", cmdName, operands[0],
987 		    gettext("must be "), GUID_INPUT,
988 		    gettext(" hexadecimal digits"));
989 		return (1);
990 	}
991 
992 	if (!fnameUsed) {
993 		/* convert to lower case for scan */
994 		for (i = 0; i < 32; i++)
995 			sGuid[i] = tolower(operands[0][i]);
996 		sGuid[i] = 0;
997 		(void) sscanf(sGuid,
998 		    "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
999 		    &guid[0], &guid[1], &guid[2], &guid[3], &guid[4], &guid[5],
1000 		    &guid[6], &guid[7], &guid[8], &guid[9], &guid[10],
1001 		    &guid[11], &guid[12], &guid[13], &guid[14], &guid[15]);
1002 
1003 		for (i = 0; i < sizeof (stmfGuid); i++) {
1004 			inGuid.guid[i] = guid[i];
1005 		}
1006 	}
1007 
1008 	for (; options->optval; options++) {
1009 		switch (options->optval) {
1010 			case 'p':
1011 				prop = strtok_r(options->optarg, "=", &lasts);
1012 				propVal = strtok_r(NULL, "=", &lasts);
1013 				ret = convertCharToPropId(prop, &propId);
1014 				if (ret != 0) {
1015 					(void) fprintf(stderr, "%s: %s: %s\n",
1016 					    cmdName,
1017 					gettext("invalid property specified"),
1018 					    prop);
1019 					return (1);
1020 				}
1021 				if (propVal ==  NULL &&
1022 				    propId != STMF_LU_PROP_MGMT_URL) {
1023 					(void) fprintf(stderr, "%s: %s: %s\n",
1024 					    cmdName, options->optarg,
1025 					    gettext("invalid property specifier"
1026 					    "- prop=val\n"));
1027 					return (1);
1028 				}
1029 				if (propVal ==  NULL) {
1030 					ret = callModify(fname, &inGuid, propId,
1031 					    "", prop);
1032 				} else {
1033 					ret = callModify(fname, &inGuid, propId,
1034 					    propVal, prop);
1035 				}
1036 				if (ret != 0) {
1037 					return (1);
1038 				}
1039 				break;
1040 			case 's':
1041 				if (callModify(fname, &inGuid,
1042 				    STMF_LU_PROP_SIZE, options->optarg,
1043 				    "size") != 0) {
1044 					return (1);
1045 				}
1046 				break;
1047 			case 'f':
1048 				break;
1049 			default:
1050 				(void) fprintf(stderr, "%s: %c: %s\n",
1051 				    cmdName, options->optval,
1052 				    gettext("unknown option"));
1053 				return (1);
1054 		}
1055 	}
1056 	return (ret);
1057 }
1058 
1059 static int
1060 callModify(char *fname, stmfGuid *luGuid, uint32_t prop, const char *propVal,
1061     const char *propString)
1062 {
1063 	int ret = 0;
1064 	int stmfRet = 0;
1065 
1066 	if (!fname) {
1067 		stmfRet = stmfModifyLu(luGuid, prop, propVal);
1068 	} else {
1069 		stmfRet = stmfModifyLuByFname(STMF_DISK, fname, prop,
1070 		    propVal);
1071 	}
1072 	switch (stmfRet) {
1073 		case STMF_STATUS_SUCCESS:
1074 			break;
1075 		case STMF_ERROR_BUSY:
1076 		case STMF_ERROR_LU_BUSY:
1077 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1078 			    gettext("resource busy"));
1079 			ret++;
1080 			break;
1081 		case STMF_ERROR_PERM:
1082 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1083 			    gettext("permission denied"));
1084 			ret++;
1085 			break;
1086 		case STMF_ERROR_INVALID_BLKSIZE:
1087 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1088 			    gettext("invalid block size"));
1089 			ret++;
1090 			break;
1091 		case STMF_ERROR_GUID_IN_USE:
1092 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1093 			    gettext("guid in use"));
1094 			ret++;
1095 			break;
1096 		case STMF_ERROR_META_FILE_NAME:
1097 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1098 			    gettext("meta file error"));
1099 			ret++;
1100 			break;
1101 		case STMF_ERROR_DATA_FILE_NAME:
1102 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1103 			    gettext("data file error"));
1104 			ret++;
1105 			break;
1106 		case STMF_ERROR_FILE_SIZE_INVALID:
1107 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1108 			    gettext("file size invalid"));
1109 			ret++;
1110 			break;
1111 		case STMF_ERROR_SIZE_OUT_OF_RANGE:
1112 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1113 			    gettext("invalid size"));
1114 			ret++;
1115 			break;
1116 		case STMF_ERROR_META_CREATION:
1117 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1118 			    gettext("could not create meta file"));
1119 			ret++;
1120 			break;
1121 		case STMF_ERROR_INVALID_PROP:
1122 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1123 			    gettext("invalid property for modify"));
1124 			ret++;
1125 			break;
1126 		case STMF_ERROR_WRITE_CACHE_SET:
1127 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1128 			    gettext("could not set write cache"));
1129 			ret++;
1130 			break;
1131 		case STMF_ERROR_ACCESS_STATE_SET:
1132 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1133 			    gettext("cannot modify while in standby mode"));
1134 			ret++;
1135 			break;
1136 		default:
1137 			(void) fprintf(stderr, "%s: %s: %s: %d\n", cmdName,
1138 			    gettext("could not set property"), propString,
1139 			    stmfRet);
1140 			ret++;
1141 			break;
1142 	}
1143 
1144 	return (ret);
1145 }
1146 
1147 
1148 /*
1149  * importLuFunc
1150  *
1151  * Create a logical unit
1152  *
1153  */
1154 /*ARGSUSED*/
1155 static int
1156 importLuFunc(int operandLen, char *operands[], cmdOptions_t *options,
1157     void *args)
1158 {
1159 	int stmfRet = 0;
1160 	int ret = 0;
1161 	char guidAsciiBuf[33];
1162 	stmfGuid createdGuid;
1163 
1164 	stmfRet = stmfImportLu(STMF_DISK, operands[0], &createdGuid);
1165 	switch (stmfRet) {
1166 		case STMF_STATUS_SUCCESS:
1167 			break;
1168 		case STMF_ERROR_BUSY:
1169 		case STMF_ERROR_LU_BUSY:
1170 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1171 			    gettext("resource busy"));
1172 			ret++;
1173 			break;
1174 		case STMF_ERROR_PERM:
1175 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1176 			    gettext("permission denied"));
1177 			ret++;
1178 			break;
1179 		case STMF_ERROR_FILE_IN_USE:
1180 			(void) fprintf(stderr, "%s: filename %s: %s\n", cmdName,
1181 			    operands[0], gettext("in use"));
1182 			ret++;
1183 			break;
1184 		case STMF_ERROR_GUID_IN_USE:
1185 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1186 			    gettext("guid in use"));
1187 			ret++;
1188 			break;
1189 		case STMF_ERROR_META_FILE_NAME:
1190 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1191 			    gettext("meta file error"));
1192 			ret++;
1193 			break;
1194 		case STMF_ERROR_DATA_FILE_NAME:
1195 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1196 			    gettext("data file error"));
1197 			ret++;
1198 			break;
1199 		case STMF_ERROR_META_CREATION:
1200 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1201 			    gettext("could not create meta file"));
1202 			ret++;
1203 			break;
1204 		case STMF_ERROR_WRITE_CACHE_SET:
1205 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1206 			    gettext("could not set write cache"));
1207 			ret++;
1208 			break;
1209 		default:
1210 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1211 			    gettext("unknown error"));
1212 			ret++;
1213 			break;
1214 	}
1215 
1216 	if (ret != STMF_STATUS_SUCCESS) {
1217 		goto done;
1218 	}
1219 
1220 	(void) snprintf(guidAsciiBuf, sizeof (guidAsciiBuf),
1221 	    "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X"
1222 	    "%02X%02X%02X%02X%02X%02X",
1223 	    createdGuid.guid[0], createdGuid.guid[1], createdGuid.guid[2],
1224 	    createdGuid.guid[3], createdGuid.guid[4], createdGuid.guid[5],
1225 	    createdGuid.guid[6], createdGuid.guid[7], createdGuid.guid[8],
1226 	    createdGuid.guid[9], createdGuid.guid[10], createdGuid.guid[11],
1227 	    createdGuid.guid[12], createdGuid.guid[13], createdGuid.guid[14],
1228 	    createdGuid.guid[15]);
1229 	(void) printf("Logical unit imported: %s\n", guidAsciiBuf);
1230 
1231 done:
1232 	return (ret);
1233 }
1234 
1235 static int
1236 setLuPropFromInput(luResource hdl, char *optarg)
1237 {
1238 	char *prop = NULL;
1239 	char *propVal = NULL;
1240 	char *lasts = NULL;
1241 	uint32_t propId;
1242 	int ret = 0;
1243 
1244 	prop = strtok_r(optarg, "=", &lasts);
1245 	if ((propVal = strtok_r(NULL, "=", &lasts)) == NULL) {
1246 		(void) fprintf(stderr, "%s: %s: %s\n",
1247 		    cmdName, optarg,
1248 		    gettext("invalid property specifier - prop=val\n"));
1249 		return (1);
1250 	}
1251 
1252 	ret = convertCharToPropId(prop, &propId);
1253 	if (ret != 0) {
1254 		(void) fprintf(stderr, "%s: %s: %s\n",
1255 		    cmdName, gettext("invalid property specified"), prop);
1256 		return (1);
1257 	}
1258 
1259 	ret = stmfSetLuProp(hdl, propId, propVal);
1260 	if (ret != STMF_STATUS_SUCCESS) {
1261 		(void) fprintf(stderr, "%s: %s %s: ",
1262 		    cmdName, gettext("unable to set"), prop);
1263 		switch (ret) {
1264 			case STMF_ERROR_INVALID_PROPSIZE:
1265 				(void) fprintf(stderr, "invalid length\n");
1266 				break;
1267 			case STMF_ERROR_INVALID_ARG:
1268 				(void) fprintf(stderr, "bad format\n");
1269 				break;
1270 			default:
1271 				(void) fprintf(stderr, "\n");
1272 				break;
1273 		}
1274 		return (1);
1275 	}
1276 
1277 	return (0);
1278 }
1279 
1280 static int
1281 convertCharToPropId(char *prop, uint32_t *propId)
1282 {
1283 	if (strcasecmp(prop, GUID) == 0) {
1284 		*propId = STMF_LU_PROP_GUID;
1285 	} else if (strcasecmp(prop, ALIAS) == 0) {
1286 		*propId = STMF_LU_PROP_ALIAS;
1287 	} else if (strcasecmp(prop, VID) == 0) {
1288 		*propId = STMF_LU_PROP_VID;
1289 	} else if (strcasecmp(prop, PID) == 0) {
1290 		*propId = STMF_LU_PROP_PID;
1291 	} else if (strcasecmp(prop, WRITE_PROTECT) == 0) {
1292 		*propId = STMF_LU_PROP_WRITE_PROTECT;
1293 	} else if (strcasecmp(prop, WRITEBACK_CACHE_DISABLE) == 0) {
1294 		*propId = STMF_LU_PROP_WRITE_CACHE_DISABLE;
1295 	} else if (strcasecmp(prop, BLOCK_SIZE) == 0) {
1296 		*propId = STMF_LU_PROP_BLOCK_SIZE;
1297 	} else if (strcasecmp(prop, SERIAL_NUMBER) == 0) {
1298 		*propId = STMF_LU_PROP_SERIAL_NUM;
1299 	} else if (strcasecmp(prop, COMPANY_ID) == 0) {
1300 		*propId = STMF_LU_PROP_COMPANY_ID;
1301 	} else if (strcasecmp(prop, META_FILE) == 0) {
1302 		*propId = STMF_LU_PROP_META_FILENAME;
1303 	} else if (strcasecmp(prop, MGMT_URL) == 0) {
1304 		*propId = STMF_LU_PROP_MGMT_URL;
1305 	} else if (strcasecmp(prop, HOST_ID) == 0) {
1306 		*propId = STMF_LU_PROP_HOST_ID;
1307 	} else {
1308 		return (1);
1309 	}
1310 	return (0);
1311 }
1312 
1313 /*
1314  * deleteLuFunc
1315  *
1316  * Delete a logical unit
1317  *
1318  */
1319 /*ARGSUSED*/
1320 static int
1321 deleteLuFunc(int operandLen, char *operands[], cmdOptions_t *options,
1322     void *args)
1323 {
1324 	int i, j;
1325 	int ret = 0;
1326 	int stmfRet;
1327 	unsigned int inGuid[sizeof (stmfGuid)];
1328 	stmfGuid delGuid;
1329 	boolean_t keepViews = B_FALSE;
1330 	boolean_t viewEntriesRemoved = B_FALSE;
1331 	boolean_t noLunFound = B_FALSE;
1332 	boolean_t views = B_FALSE;
1333 	boolean_t notValidHexNumber = B_FALSE;
1334 	char sGuid[GUID_INPUT + 1];
1335 	stmfViewEntryList *viewEntryList = NULL;
1336 
1337 	for (; options->optval; options++) {
1338 		switch (options->optval) {
1339 			/* Keep views for logical unit */
1340 			case 'k':
1341 				keepViews = B_TRUE;
1342 				break;
1343 			default:
1344 				(void) fprintf(stderr, "%s: %c: %s\n",
1345 				    cmdName, options->optval,
1346 				    gettext("unknown option"));
1347 				return (1);
1348 		}
1349 	}
1350 
1351 
1352 	for (i = 0; i < operandLen; i++) {
1353 		for (j = 0; j < GUID_INPUT; j++) {
1354 			if (!isxdigit(operands[i][j])) {
1355 				notValidHexNumber = B_TRUE;
1356 				break;
1357 			}
1358 			sGuid[j] = tolower(operands[i][j]);
1359 		}
1360 		if ((notValidHexNumber == B_TRUE) ||
1361 		    (strlen(operands[i]) != GUID_INPUT)) {
1362 			(void) fprintf(stderr, "%s: %s: %s%d%s\n",
1363 			    cmdName, operands[i], gettext("must be "),
1364 			    GUID_INPUT,
1365 			    gettext(" hexadecimal digits long"));
1366 			notValidHexNumber = B_FALSE;
1367 			ret++;
1368 			continue;
1369 		}
1370 
1371 		sGuid[j] = 0;
1372 
1373 		(void) sscanf(sGuid,
1374 		    "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
1375 		    &inGuid[0], &inGuid[1], &inGuid[2], &inGuid[3],
1376 		    &inGuid[4], &inGuid[5], &inGuid[6], &inGuid[7],
1377 		    &inGuid[8], &inGuid[9], &inGuid[10], &inGuid[11],
1378 		    &inGuid[12], &inGuid[13], &inGuid[14], &inGuid[15]);
1379 
1380 		for (j = 0; j < sizeof (stmfGuid); j++) {
1381 			delGuid.guid[j] = inGuid[j];
1382 		}
1383 
1384 		stmfRet = stmfDeleteLu(&delGuid);
1385 		switch (stmfRet) {
1386 			case STMF_STATUS_SUCCESS:
1387 				break;
1388 			case STMF_ERROR_NOT_FOUND:
1389 				noLunFound = B_TRUE;
1390 				break;
1391 			case STMF_ERROR_BUSY:
1392 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1393 				    gettext("resource busy"));
1394 				ret++;
1395 				break;
1396 			case STMF_ERROR_PERM:
1397 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1398 				    gettext("permission denied"));
1399 				ret++;
1400 				break;
1401 			default:
1402 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1403 				    gettext("unknown error"));
1404 				ret++;
1405 				break;
1406 		}
1407 
1408 		if (!keepViews) {
1409 			stmfRet = stmfGetViewEntryList(&delGuid,
1410 			    &viewEntryList);
1411 			if (stmfRet == STMF_STATUS_SUCCESS) {
1412 				for (j = 0; j < viewEntryList->cnt; j++) {
1413 					(void) stmfRemoveViewEntry(&delGuid,
1414 					    viewEntryList->ve[j].veIndex);
1415 				}
1416 				/* check if viewEntryList is empty */
1417 				if (viewEntryList->cnt != 0)
1418 					viewEntriesRemoved = B_TRUE;
1419 				stmfFreeMemory(viewEntryList);
1420 			} else {
1421 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1422 				    gettext("unable to remove view entries\n"));
1423 				ret++;
1424 			}
1425 
1426 		}
1427 		if (keepViews) {
1428 			stmfRet = stmfGetViewEntryList(&delGuid,
1429 			    &viewEntryList);
1430 			if (stmfRet == STMF_STATUS_SUCCESS) {
1431 				views = B_TRUE;
1432 				stmfFreeMemory(viewEntryList);
1433 			}
1434 		}
1435 
1436 		if ((!viewEntriesRemoved && noLunFound && !views) ||
1437 		    (!views && keepViews && noLunFound)) {
1438 			(void) fprintf(stderr, "%s: %s: %s\n",
1439 			    cmdName, sGuid,
1440 			    gettext("not found"));
1441 			ret++;
1442 		}
1443 		noLunFound = viewEntriesRemoved = views = B_FALSE;
1444 	}
1445 	return (ret);
1446 }
1447 
1448 
1449 /*
1450  * createTargetGroupFunc
1451  *
1452  * Create a target group
1453  *
1454  */
1455 /*ARGSUSED*/
1456 static int
1457 createTargetGroupFunc(int operandLen, char *operands[], cmdOptions_t *options,
1458     void *args)
1459 {
1460 	int ret = 0;
1461 	int stmfRet;
1462 	wchar_t groupNamePrint[sizeof (stmfGroupName)] = {0};
1463 	stmfGroupName groupName = {0};
1464 
1465 	(void) strlcpy(groupName, operands[0], sizeof (groupName));
1466 	(void) mbstowcs(groupNamePrint, (char *)groupName,
1467 	    sizeof (stmfGroupName) - 1);
1468 	/* call create group */
1469 	stmfRet = stmfCreateTargetGroup(&groupName);
1470 	switch (stmfRet) {
1471 		case STMF_STATUS_SUCCESS:
1472 			break;
1473 		case STMF_ERROR_EXISTS:
1474 			(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
1475 			    groupNamePrint, gettext("already exists"));
1476 			ret++;
1477 			break;
1478 		case STMF_ERROR_BUSY:
1479 			(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
1480 			    groupNamePrint, gettext("resource busy"));
1481 			ret++;
1482 			break;
1483 		case STMF_ERROR_PERM:
1484 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1485 			    gettext("permission denied"));
1486 			ret++;
1487 			break;
1488 		case STMF_ERROR_SERVICE_NOT_FOUND:
1489 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1490 			    gettext("STMF service not found"));
1491 			ret++;
1492 			break;
1493 		case STMF_ERROR_SERVICE_DATA_VERSION:
1494 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1495 			    gettext("STMF service version incorrect"));
1496 			ret++;
1497 			break;
1498 		default:
1499 			(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
1500 			    groupNamePrint, gettext("unknown error"));
1501 			ret++;
1502 			break;
1503 	}
1504 
1505 	return (ret);
1506 }
1507 
1508 /*
1509  * deleteHostGroupFunc
1510  *
1511  * Delete a host group
1512  *
1513  */
1514 /*ARGSUSED*/
1515 static int
1516 deleteHostGroupFunc(int operandLen, char *operands[],
1517     cmdOptions_t *options, void *args)
1518 {
1519 	int ret = 0;
1520 	int stmfRet;
1521 	wchar_t groupNamePrint[sizeof (stmfGroupName)] = {0};
1522 	stmfGroupName groupName = {0};
1523 
1524 	(void) strlcpy(groupName, operands[0], sizeof (groupName));
1525 	(void) mbstowcs(groupNamePrint, (char *)groupName,
1526 	    sizeof (stmfGroupName) - 1);
1527 	/* call delete group */
1528 	stmfRet = stmfDeleteHostGroup(&groupName);
1529 	switch (stmfRet) {
1530 		case STMF_STATUS_SUCCESS:
1531 			break;
1532 		case STMF_ERROR_NOT_FOUND:
1533 			(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
1534 			    groupNamePrint, gettext("not found"));
1535 			ret++;
1536 			break;
1537 		case STMF_ERROR_BUSY:
1538 			(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
1539 			    groupNamePrint, gettext("resource busy"));
1540 			ret++;
1541 			break;
1542 		case STMF_ERROR_SERVICE_NOT_FOUND:
1543 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1544 			    gettext("STMF service not found"));
1545 			ret++;
1546 			break;
1547 		case STMF_ERROR_PERM:
1548 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1549 			    gettext("permission denied"));
1550 			ret++;
1551 			break;
1552 		case STMF_ERROR_GROUP_IN_USE:
1553 			(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
1554 			    groupNamePrint,
1555 			    gettext("group is in use by existing view entry"));
1556 			ret++;
1557 			break;
1558 		case STMF_ERROR_SERVICE_DATA_VERSION:
1559 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1560 			    gettext("STMF service version incorrect"));
1561 			ret++;
1562 			break;
1563 		default:
1564 			(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
1565 			    groupNamePrint, gettext("unknown error"));
1566 			ret++;
1567 			break;
1568 	}
1569 
1570 	return (ret);
1571 }
1572 
1573 /*
1574  * deleteTargetGroupFunc
1575  *
1576  * Delete a target group
1577  *
1578  */
1579 /*ARGSUSED*/
1580 static int
1581 deleteTargetGroupFunc(int operandLen, char *operands[], cmdOptions_t *options,
1582     void *args)
1583 {
1584 	int ret = 0;
1585 	int stmfRet;
1586 	wchar_t groupNamePrint[sizeof (stmfGroupName)] = {0};
1587 	stmfGroupName groupName = {0};
1588 
1589 	(void) strlcpy(groupName, operands[0], sizeof (groupName));
1590 	(void) mbstowcs(groupNamePrint, (char *)groupName,
1591 	    sizeof (stmfGroupName) - 1);
1592 	/* call delete group */
1593 	stmfRet = stmfDeleteTargetGroup(&groupName);
1594 	switch (stmfRet) {
1595 		case STMF_STATUS_SUCCESS:
1596 			break;
1597 		case STMF_ERROR_NOT_FOUND:
1598 			(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
1599 			    groupNamePrint, gettext("not found"));
1600 			ret++;
1601 			break;
1602 		case STMF_ERROR_BUSY:
1603 			(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
1604 			    groupNamePrint, gettext("resource busy"));
1605 			ret++;
1606 			break;
1607 		case STMF_ERROR_SERVICE_NOT_FOUND:
1608 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1609 			    gettext("STMF service not found"));
1610 			ret++;
1611 			break;
1612 		case STMF_ERROR_PERM:
1613 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1614 			    gettext("permission denied"));
1615 			ret++;
1616 			break;
1617 		case STMF_ERROR_GROUP_IN_USE:
1618 			(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
1619 			    groupNamePrint,
1620 			    gettext("group is in use by existing view entry"));
1621 			ret++;
1622 			break;
1623 		case STMF_ERROR_SERVICE_DATA_VERSION:
1624 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1625 			    gettext("STMF service version incorrect"));
1626 			ret++;
1627 			break;
1628 		default:
1629 			(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
1630 			    groupNamePrint, gettext("unknown error"));
1631 			ret++;
1632 			break;
1633 	}
1634 
1635 	return (ret);
1636 }
1637 
1638 /*
1639  * listHostGroupFunc
1640  *
1641  * Lists the specified host groups or all if none are specified
1642  *
1643  */
1644 /*ARGSUSED*/
1645 static int
1646 listHostGroupFunc(int operandLen, char *operands[], cmdOptions_t *options,
1647     void *args)
1648 {
1649 	int ret = 0;
1650 	int stmfRet;
1651 	int i, j, outerLoop;
1652 	boolean_t verbose = B_FALSE;
1653 	boolean_t found = B_TRUE;
1654 	boolean_t operandEntered;
1655 	stmfGroupList *groupList;
1656 	stmfGroupProperties *groupProps;
1657 	wchar_t operandName[sizeof (stmfGroupName)];
1658 	wchar_t groupNamePrint[sizeof (stmfGroupName)];
1659 
1660 	for (; options->optval; options++) {
1661 		switch (options->optval) {
1662 			case 'v':
1663 				verbose = B_TRUE;
1664 				break;
1665 			default:
1666 				(void) fprintf(stderr, "%s: %c: %s\n",
1667 				    cmdName, options->optval,
1668 				    gettext("unknown option"));
1669 				return (1);
1670 		}
1671 	}
1672 
1673 	if (operandLen > 0) {
1674 		outerLoop = operandLen;
1675 		operandEntered = B_TRUE;
1676 	} else {
1677 		outerLoop = 1;
1678 		operandEntered = B_FALSE;
1679 	}
1680 
1681 	stmfRet = stmfGetHostGroupList(&groupList);
1682 	if (stmfRet != STMF_STATUS_SUCCESS) {
1683 		switch (stmfRet) {
1684 			case STMF_ERROR_BUSY:
1685 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1686 				    gettext("resource busy"));
1687 				break;
1688 			case STMF_ERROR_SERVICE_NOT_FOUND:
1689 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1690 				    gettext("STMF service not found"));
1691 				break;
1692 			case STMF_ERROR_PERM:
1693 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1694 				    gettext("permission denied"));
1695 				break;
1696 			case STMF_ERROR_SERVICE_DATA_VERSION:
1697 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1698 				    gettext("STMF service version incorrect"));
1699 				break;
1700 			default:
1701 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1702 				    gettext("unknown error"));
1703 				break;
1704 		}
1705 		return (1);
1706 	}
1707 
1708 	for (i = 0; i < outerLoop; i++) {
1709 		for (found = B_FALSE, j = 0; j < groupList->cnt; j++) {
1710 			(void) mbstowcs(groupNamePrint,
1711 			    (char *)groupList->name[j],
1712 			    sizeof (stmfGroupName) - 1);
1713 			groupNamePrint[sizeof (stmfGroupName) - 1] = 0;
1714 			if (operandEntered) {
1715 				(void) mbstowcs(operandName, operands[i],
1716 				    sizeof (stmfGroupName) - 1);
1717 				operandName[sizeof (stmfGroupName) - 1] = 0;
1718 				if (wcscmp(operandName, groupNamePrint)
1719 				    == 0) {
1720 					found = B_TRUE;
1721 				}
1722 			}
1723 			if ((found && operandEntered) || !operandEntered) {
1724 				(void) printf("Host Group: %ws\n",
1725 				    groupNamePrint);
1726 				if (verbose) {
1727 					stmfRet = stmfGetHostGroupMembers(
1728 					    &(groupList->name[j]), &groupProps);
1729 					if (stmfRet != STMF_STATUS_SUCCESS) {
1730 						return (1);
1731 					}
1732 					printGroupProps(groupProps);
1733 				}
1734 				if (found && operandEntered) {
1735 					break;
1736 				}
1737 			}
1738 
1739 		}
1740 		if (operandEntered && !found) {
1741 			(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
1742 			    operands[i], gettext("not found"));
1743 			ret = 1;
1744 		}
1745 	}
1746 	return (ret);
1747 }
1748 
1749 /*
1750  * printGroupProps
1751  *
1752  * Prints group members for target or host groups
1753  *
1754  */
1755 static void
1756 printGroupProps(stmfGroupProperties *groupProps)
1757 {
1758 	int i;
1759 	wchar_t memberIdent[sizeof (groupProps->name[0].ident) + 1] = {0};
1760 
1761 
1762 	for (i = 0; i < groupProps->cnt; i++) {
1763 		(void) mbstowcs(memberIdent, (char *)groupProps->name[i].ident,
1764 		    sizeof (groupProps->name[0].ident));
1765 		(void) printf("\tMember: %ws\n", memberIdent);
1766 	}
1767 }
1768 
1769 /*
1770  * listTargetGroupFunc
1771  *
1772  * Lists the specified target groups or all if none are specified
1773  *
1774  */
1775 /*ARGSUSED*/
1776 static int
1777 listTargetGroupFunc(int operandLen, char *operands[], cmdOptions_t *options,
1778     void *args)
1779 {
1780 	int ret = 0;
1781 	int stmfRet;
1782 	int i, j, outerLoop;
1783 	boolean_t verbose = B_FALSE;
1784 	boolean_t found = B_TRUE;
1785 	boolean_t operandEntered;
1786 	stmfGroupList *groupList;
1787 	stmfGroupProperties *groupProps;
1788 	wchar_t operandName[sizeof (stmfGroupName)];
1789 	wchar_t groupNamePrint[sizeof (stmfGroupName)];
1790 
1791 	for (; options->optval; options++) {
1792 		switch (options->optval) {
1793 			case 'v':
1794 				verbose = B_TRUE;
1795 				break;
1796 			default:
1797 				(void) fprintf(stderr, "%s: %c: %s\n",
1798 				    cmdName, options->optval,
1799 				    gettext("unknown option"));
1800 				return (1);
1801 		}
1802 	}
1803 
1804 	if (operandLen > 0) {
1805 		outerLoop = operandLen;
1806 		operandEntered = B_TRUE;
1807 	} else {
1808 		outerLoop = 1;
1809 		operandEntered = B_FALSE;
1810 	}
1811 
1812 	stmfRet = stmfGetTargetGroupList(&groupList);
1813 	if (stmfRet != STMF_STATUS_SUCCESS) {
1814 		switch (stmfRet) {
1815 			case STMF_ERROR_BUSY:
1816 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1817 				    gettext("resource busy"));
1818 				break;
1819 			case STMF_ERROR_SERVICE_NOT_FOUND:
1820 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1821 				    gettext("STMF service not found"));
1822 				break;
1823 			case STMF_ERROR_SERVICE_DATA_VERSION:
1824 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1825 				    gettext("STMF service version incorrect"));
1826 				break;
1827 			case STMF_ERROR_PERM:
1828 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1829 				    gettext("permission denied"));
1830 				break;
1831 			default:
1832 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1833 				    gettext("unknown error"));
1834 				break;
1835 		}
1836 		return (1);
1837 	}
1838 
1839 	for (i = 0; i < outerLoop; i++) {
1840 		for (found = B_FALSE, j = 0; j < groupList->cnt; j++) {
1841 			(void) mbstowcs(groupNamePrint,
1842 			    (char *)groupList->name[j],
1843 			    sizeof (stmfGroupName) - 1);
1844 			groupNamePrint[sizeof (stmfGroupName) - 1] = 0;
1845 			if (operandEntered) {
1846 				(void) mbstowcs(operandName, operands[i],
1847 				    sizeof (stmfGroupName) - 1);
1848 				operandName[sizeof (stmfGroupName) - 1] = 0;
1849 				if (wcscmp(operandName, groupNamePrint)
1850 				    == 0) {
1851 					found = B_TRUE;
1852 				}
1853 			}
1854 			if ((found && operandEntered) || !operandEntered) {
1855 				(void) printf("Target Group: %ws\n",
1856 				    groupNamePrint);
1857 				if (verbose) {
1858 					stmfRet = stmfGetTargetGroupMembers(
1859 					    &(groupList->name[j]), &groupProps);
1860 					if (stmfRet != STMF_STATUS_SUCCESS) {
1861 						return (1);
1862 					}
1863 					printGroupProps(groupProps);
1864 				}
1865 				if (found && operandEntered) {
1866 					break;
1867 				}
1868 			}
1869 
1870 		}
1871 		if (operandEntered && !found) {
1872 			(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
1873 			    operands[i], gettext("not found"));
1874 			ret = 1;
1875 		}
1876 	}
1877 	return (ret);
1878 }
1879 
1880 /*
1881  * listLuFunc
1882  *
1883  * List the logical units and optionally the properties
1884  *
1885  */
1886 /*ARGSUSED*/
1887 static int
1888 listLuFunc(int operandLen, char *operands[], cmdOptions_t *options, void *args)
1889 {
1890 	cmdOptions_t *optionList = options;
1891 	boolean_t operandEntered;
1892 	int i, j;
1893 	int ret = 0;
1894 	int stmfRet;
1895 	int outerLoop;
1896 	unsigned int inGuid[sizeof (stmfGuid)];
1897 	stmfGuid cmpGuid;
1898 	boolean_t verbose = B_FALSE;
1899 	boolean_t found;
1900 	char sGuid[GUID_INPUT + 1];
1901 	stmfGuidList *luList;
1902 	stmfLogicalUnitProperties luProps;
1903 	boolean_t invalidInput = B_FALSE;
1904 	stmfViewEntryList *viewEntryList;
1905 
1906 	for (; optionList->optval; optionList++) {
1907 		switch (optionList->optval) {
1908 			case 'v':
1909 				verbose = B_TRUE;
1910 				break;
1911 		}
1912 	}
1913 
1914 	if ((stmfRet = stmfGetLogicalUnitList(&luList))
1915 	    != STMF_STATUS_SUCCESS) {
1916 		switch (stmfRet) {
1917 			case STMF_ERROR_SERVICE_NOT_FOUND:
1918 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1919 				    gettext("STMF service not found"));
1920 				break;
1921 			case STMF_ERROR_BUSY:
1922 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1923 				    gettext("resource busy"));
1924 				break;
1925 			case STMF_ERROR_PERM:
1926 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1927 				    gettext("permission denied"));
1928 				break;
1929 			case STMF_ERROR_SERVICE_DATA_VERSION:
1930 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1931 				    gettext("STMF service version incorrect"));
1932 				break;
1933 			default:
1934 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1935 				    gettext("list failed"));
1936 				break;
1937 		}
1938 		return (1);
1939 	}
1940 
1941 	if (operandLen > 0) {
1942 		operandEntered = B_TRUE;
1943 		outerLoop = operandLen;
1944 	} else {
1945 		operandEntered = B_FALSE;
1946 		outerLoop = 1;
1947 	}
1948 
1949 
1950 	for (invalidInput = B_FALSE, i = 0; i < outerLoop; i++) {
1951 		if (operandEntered) {
1952 			if (strlen(operands[i]) != GUID_INPUT) {
1953 				invalidInput = B_TRUE;
1954 			} else {
1955 				for (j = 0; j < GUID_INPUT; j++) {
1956 					if (!isxdigit(operands[i][j])) {
1957 						invalidInput = B_TRUE;
1958 						break;
1959 					}
1960 				}
1961 			}
1962 			if (invalidInput) {
1963 				(void) fprintf(stderr, "%s: %s: %s%d%s\n",
1964 				    cmdName, operands[i], gettext("must be "),
1965 				    GUID_INPUT,
1966 				    gettext(" hexadecimal digits long"));
1967 				invalidInput = B_FALSE;
1968 				continue;
1969 			}
1970 
1971 			for (j = 0; j < GUID_INPUT; j++) {
1972 				sGuid[j] = tolower(operands[i][j]);
1973 			}
1974 			sGuid[j] = 0;
1975 
1976 			(void) sscanf(sGuid,
1977 			    "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
1978 			    &inGuid[0], &inGuid[1], &inGuid[2], &inGuid[3],
1979 			    &inGuid[4], &inGuid[5], &inGuid[6], &inGuid[7],
1980 			    &inGuid[8], &inGuid[9], &inGuid[10], &inGuid[11],
1981 			    &inGuid[12], &inGuid[13], &inGuid[14], &inGuid[15]);
1982 
1983 			for (j = 0; j < sizeof (stmfGuid); j++) {
1984 				cmpGuid.guid[j] = inGuid[j];
1985 			}
1986 		}
1987 
1988 		for (found = B_FALSE, j = 0; j < luList->cnt; j++) {
1989 			if (operandEntered) {
1990 				if (bcmp(luList->guid[j].guid, cmpGuid.guid,
1991 				    sizeof (stmfGuid)) == 0) {
1992 					found = B_TRUE;
1993 				}
1994 			}
1995 			if ((found && operandEntered) || !operandEntered) {
1996 				(void) printf("LU Name: ");
1997 				printGuid(&luList->guid[j], stdout);
1998 				(void) printf("\n");
1999 
2000 				if (verbose) {
2001 					stmfRet = stmfGetLogicalUnitProperties(
2002 					    &(luList->guid[j]), &luProps);
2003 					if (stmfRet == STMF_STATUS_SUCCESS) {
2004 						printLuProps(&luProps);
2005 					} else {
2006 						(void) fprintf(stderr, "%s:",
2007 						    cmdName);
2008 						printGuid(&luList->guid[j],
2009 						    stderr);
2010 						(void) fprintf(stderr, "%s\n",
2011 						    gettext(" get properties "
2012 						    "failed"));
2013 					}
2014 					stmfRet = stmfGetViewEntryList(
2015 					    &(luList->guid[j]),
2016 					    &viewEntryList);
2017 					(void) printf(PROPS_FORMAT,
2018 					    "View Entry Count");
2019 					if (stmfRet == STMF_STATUS_SUCCESS) {
2020 						(void) printf("%d",
2021 						    viewEntryList->cnt);
2022 					} else {
2023 						(void) printf("unknown");
2024 					}
2025 					(void) printf("\n");
2026 					ret = printExtLuProps(
2027 					    &(luList->guid[j]));
2028 				}
2029 				if (found && operandEntered) {
2030 					break;
2031 				}
2032 			}
2033 
2034 		}
2035 		if (operandEntered && !found) {
2036 			(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
2037 			    operands[i], gettext("not found"));
2038 			ret = 1;
2039 		}
2040 	}
2041 
2042 	return (ret);
2043 }
2044 
2045 static void
2046 printGuid(stmfGuid *guid, FILE *stream)
2047 {
2048 	int i;
2049 	for (i = 0; i < 16; i++) {
2050 		(void) fprintf(stream, "%02X", guid->guid[i]);
2051 	}
2052 }
2053 
2054 static int
2055 printExtLuProps(stmfGuid *guid)
2056 {
2057 	int stmfRet;
2058 	luResource hdl = NULL;
2059 	int ret = 0;
2060 	char propVal[MAXNAMELEN];
2061 	size_t propValSize = sizeof (propVal);
2062 
2063 	if ((stmfRet = stmfGetLuResource(guid, &hdl))
2064 	    != STMF_STATUS_SUCCESS) {
2065 		switch (stmfRet) {
2066 			case STMF_ERROR_BUSY:
2067 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2068 				    gettext("resource busy"));
2069 				break;
2070 			case STMF_ERROR_PERM:
2071 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2072 				    gettext("permission denied"));
2073 				break;
2074 			case STMF_ERROR_NOT_FOUND:
2075 				/* No error here */
2076 				return (0);
2077 				break;
2078 			default:
2079 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2080 				    gettext("get extended properties failed"));
2081 				break;
2082 		}
2083 		return (1);
2084 	}
2085 
2086 	stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_FILENAME, propVal,
2087 	    &propValSize);
2088 	(void) printf(PROPS_FORMAT, "Data File");
2089 	if (stmfRet == STMF_STATUS_SUCCESS) {
2090 		(void) printf("%s\n", propVal);
2091 	} else if (stmfRet == STMF_ERROR_NO_PROP) {
2092 		(void) printf("not set\n");
2093 	} else if (stmfRet == STMF_ERROR_NO_PROP_STANDBY) {
2094 		(void) printf("prop unavailable in standby\n");
2095 	} else {
2096 		(void) printf("<error retrieving property>\n");
2097 		ret++;
2098 	}
2099 
2100 	stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_META_FILENAME, propVal,
2101 	    &propValSize);
2102 	(void) printf(PROPS_FORMAT, "Meta File");
2103 	if (stmfRet == STMF_STATUS_SUCCESS) {
2104 		(void) printf("%s\n", propVal);
2105 	} else if (stmfRet == STMF_ERROR_NO_PROP) {
2106 		(void) printf("not set\n");
2107 	} else if (stmfRet == STMF_ERROR_NO_PROP_STANDBY) {
2108 		(void) printf("prop unavailable in standby\n");
2109 	} else {
2110 		(void) printf("<error retrieving property>\n");
2111 		ret++;
2112 	}
2113 
2114 	stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_SIZE, propVal,
2115 	    &propValSize);
2116 	(void) printf(PROPS_FORMAT, "Size");
2117 	if (stmfRet == STMF_STATUS_SUCCESS) {
2118 		(void) printf("%s\n", propVal);
2119 	} else if (stmfRet == STMF_ERROR_NO_PROP) {
2120 		(void) printf("not set\n");
2121 	} else if (stmfRet == STMF_ERROR_NO_PROP_STANDBY) {
2122 		(void) printf("prop unavailable in standby\n");
2123 	} else {
2124 		(void) printf("<error retrieving property>\n");
2125 		ret++;
2126 	}
2127 
2128 	stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_BLOCK_SIZE, propVal,
2129 	    &propValSize);
2130 	(void) printf(PROPS_FORMAT, "Block Size");
2131 	if (stmfRet == STMF_STATUS_SUCCESS) {
2132 		(void) printf("%s\n", propVal);
2133 	} else if (stmfRet == STMF_ERROR_NO_PROP) {
2134 		(void) printf("not set\n");
2135 	} else if (stmfRet == STMF_ERROR_NO_PROP_STANDBY) {
2136 		(void) printf("prop unavailable in standby\n");
2137 	} else {
2138 		(void) printf("<error retrieving property>\n");
2139 		ret++;
2140 	}
2141 
2142 	stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_MGMT_URL, propVal,
2143 	    &propValSize);
2144 	(void) printf(PROPS_FORMAT, "Management URL");
2145 	if (stmfRet == STMF_STATUS_SUCCESS) {
2146 		(void) printf("%s\n", propVal);
2147 	} else if (stmfRet == STMF_ERROR_NO_PROP) {
2148 		(void) printf("not set\n");
2149 	} else if (stmfRet == STMF_ERROR_NO_PROP_STANDBY) {
2150 		(void) printf("prop unavailable in standby\n");
2151 	} else {
2152 		(void) printf("<error retrieving property>\n");
2153 		ret++;
2154 	}
2155 
2156 	stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_VID, propVal,
2157 	    &propValSize);
2158 	(void) printf(PROPS_FORMAT, "Vendor ID");
2159 	if (stmfRet == STMF_STATUS_SUCCESS) {
2160 		(void) printf("%s\n", propVal);
2161 	} else if (stmfRet == STMF_ERROR_NO_PROP) {
2162 		(void) printf("not set\n");
2163 	} else if (stmfRet == STMF_ERROR_NO_PROP_STANDBY) {
2164 		(void) printf("prop unavailable in standby\n");
2165 	} else {
2166 		(void) printf("<error retrieving property>\n");
2167 		ret++;
2168 	}
2169 
2170 	stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_PID, propVal,
2171 	    &propValSize);
2172 	(void) printf(PROPS_FORMAT, "Product ID");
2173 	if (stmfRet == STMF_STATUS_SUCCESS) {
2174 		(void) printf("%s\n", propVal);
2175 	} else if (stmfRet == STMF_ERROR_NO_PROP) {
2176 		(void) printf("not set\n");
2177 	} else if (stmfRet == STMF_ERROR_NO_PROP_STANDBY) {
2178 		(void) printf("prop unavailable in standby\n");
2179 	} else {
2180 		(void) printf("<error retrieving property>\n");
2181 		ret++;
2182 	}
2183 
2184 	stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_SERIAL_NUM, propVal,
2185 	    &propValSize);
2186 	(void) printf(PROPS_FORMAT, "Serial Num");
2187 	if (stmfRet == STMF_STATUS_SUCCESS) {
2188 		(void) printf("%s\n", propVal);
2189 	} else if (stmfRet == STMF_ERROR_NO_PROP) {
2190 		(void) printf("not set\n");
2191 	} else if (stmfRet == STMF_ERROR_NO_PROP_STANDBY) {
2192 		(void) printf("prop unavailable in standby\n");
2193 	} else {
2194 		(void) printf("<error retrieving property>\n");
2195 		ret++;
2196 	}
2197 
2198 	stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_WRITE_PROTECT, propVal,
2199 	    &propValSize);
2200 	(void) printf(PROPS_FORMAT, "Write Protect");
2201 	if (stmfRet == STMF_STATUS_SUCCESS) {
2202 		(void) printf("%s\n",
2203 		    strcasecmp(propVal, "true") ? "Disabled" : "Enabled");
2204 	} else if (stmfRet == STMF_ERROR_NO_PROP) {
2205 		(void) printf("not set\n");
2206 	} else if (stmfRet == STMF_ERROR_NO_PROP_STANDBY) {
2207 		(void) printf("prop unavailable in standby\n");
2208 	} else {
2209 		(void) printf("<error retrieving property>\n");
2210 		ret++;
2211 	}
2212 
2213 	stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_WRITE_CACHE_DISABLE, propVal,
2214 	    &propValSize);
2215 	(void) printf(PROPS_FORMAT, "Writeback Cache");
2216 	if (stmfRet == STMF_STATUS_SUCCESS) {
2217 		(void) printf("%s\n",
2218 		    strcasecmp(propVal, "true") ? "Enabled" : "Disabled");
2219 	} else if (stmfRet == STMF_ERROR_NO_PROP) {
2220 		(void) printf("not set\n");
2221 	} else if (stmfRet == STMF_ERROR_NO_PROP_STANDBY) {
2222 		(void) printf("prop unavailable in standby\n");
2223 	} else {
2224 		(void) printf("<error retrieving property>\n");
2225 		ret++;
2226 	}
2227 
2228 	stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_ACCESS_STATE, propVal,
2229 	    &propValSize);
2230 	(void) printf(PROPS_FORMAT, "Access State");
2231 	if (stmfRet == STMF_STATUS_SUCCESS) {
2232 		if (strcmp(propVal, STMF_ACCESS_ACTIVE) == 0) {
2233 			(void) printf("%s\n", "Active");
2234 		} else if (strcmp(propVal,
2235 		    STMF_ACCESS_ACTIVE_TO_STANDBY) == 0) {
2236 			(void) printf("%s\n", "Active->Standby");
2237 		} else if (strcmp(propVal, STMF_ACCESS_STANDBY) == 0) {
2238 			(void) printf("%s\n", "Standby");
2239 		} else if (strcmp(propVal,
2240 		    STMF_ACCESS_STANDBY_TO_ACTIVE) == 0) {
2241 			(void) printf("%s\n", "Standby->Active");
2242 		} else {
2243 			(void) printf("%s\n", "Unknown");
2244 		}
2245 	} else if (stmfRet == STMF_ERROR_NO_PROP) {
2246 		(void) printf("not set\n");
2247 	} else {
2248 		(void) printf("<error retrieving property>\n");
2249 		ret++;
2250 	}
2251 
2252 done:
2253 	(void) stmfFreeLuResource(hdl);
2254 	return (ret);
2255 
2256 }
2257 
2258 
2259 /*
2260  * printLuProps
2261  *
2262  * Prints the properties for a logical unit
2263  *
2264  */
2265 static void
2266 printLuProps(stmfLogicalUnitProperties *luProps)
2267 {
2268 	(void) printf(PROPS_FORMAT, "Operational Status");
2269 	switch (luProps->status) {
2270 		case STMF_LOGICAL_UNIT_ONLINE:
2271 			(void) printf("Online");
2272 			break;
2273 		case STMF_LOGICAL_UNIT_OFFLINE:
2274 			(void) printf("Offline");
2275 			break;
2276 		case STMF_LOGICAL_UNIT_ONLINING:
2277 			(void) printf("Onlining");
2278 			break;
2279 		case STMF_LOGICAL_UNIT_OFFLINING:
2280 			(void) printf("Offlining");
2281 			break;
2282 		case STMF_LOGICAL_UNIT_UNREGISTERED:
2283 			(void) printf("unregistered");
2284 			(void) strncpy(luProps->providerName, "unregistered",
2285 			    sizeof (luProps->providerName));
2286 			break;
2287 		default:
2288 			(void) printf("unknown");
2289 			break;
2290 	}
2291 	(void) printf("\n");
2292 	(void) printf(PROPS_FORMAT, "Provider Name");
2293 	if (luProps->providerName[0] != 0) {
2294 		(void) printf("%s", luProps->providerName);
2295 	} else {
2296 		(void) printf("unknown");
2297 	}
2298 	(void) printf("\n");
2299 	(void) printf(PROPS_FORMAT, "Alias");
2300 	if (luProps->alias[0] != 0) {
2301 		(void) printf("%s", luProps->alias);
2302 	} else {
2303 		(void) printf("-");
2304 	}
2305 	(void) printf("\n");
2306 }
2307 
2308 /*
2309  * printTargetProps
2310  *
2311  * Prints the properties for a target
2312  *
2313  */
2314 static void
2315 printTargetProps(stmfTargetProperties *targetProps)
2316 {
2317 	(void) printf(PROPS_FORMAT, "Operational Status");
2318 	switch (targetProps->status) {
2319 		case STMF_TARGET_PORT_ONLINE:
2320 			(void) printf("Online");
2321 			break;
2322 		case STMF_TARGET_PORT_OFFLINE:
2323 			(void) printf("Offline");
2324 			break;
2325 		case STMF_TARGET_PORT_ONLINING:
2326 			(void) printf("Onlining");
2327 			break;
2328 		case STMF_TARGET_PORT_OFFLINING:
2329 			(void) printf("Offlining");
2330 			break;
2331 		default:
2332 			(void) printf("unknown");
2333 			break;
2334 	}
2335 	(void) printf("\n");
2336 	(void) printf(PROPS_FORMAT, "Provider Name");
2337 	if (targetProps->providerName[0] != 0) {
2338 		(void) printf("%s", targetProps->providerName);
2339 	}
2340 	(void) printf("\n");
2341 	(void) printf(PROPS_FORMAT, "Alias");
2342 	if (targetProps->alias[0] != 0) {
2343 		(void) printf("%s", targetProps->alias);
2344 	} else {
2345 		(void) printf("-");
2346 	}
2347 	(void) printf("\n");
2348 	(void) printf(PROPS_FORMAT, "Protocol");
2349 	switch (targetProps->protocol) {
2350 		case STMF_PROTOCOL_FIBRE_CHANNEL:
2351 			(void) printf("%s", "Fibre Channel");
2352 			break;
2353 		case STMF_PROTOCOL_ISCSI:
2354 			(void) printf("%s", "iSCSI");
2355 			break;
2356 		case STMF_PROTOCOL_SRP:
2357 			(void) printf("%s", "SRP");
2358 			break;
2359 		case STMF_PROTOCOL_SAS:
2360 			(void) printf("%s", "SAS");
2361 			break;
2362 		default:
2363 			(void) printf("%s", "unknown");
2364 			break;
2365 	}
2366 
2367 	(void) printf("\n");
2368 }
2369 
2370 /*
2371  * printSessionProps
2372  *
2373  * Prints the session data
2374  *
2375  */
2376 static void
2377 printSessionProps(stmfSessionList *sessionList)
2378 {
2379 	int i;
2380 	char *cTime;
2381 	wchar_t initiator[STMF_IDENT_LENGTH + 1];
2382 
2383 	(void) printf(PROPS_FORMAT, "Sessions");
2384 	(void) printf("%d\n", sessionList->cnt);
2385 	for (i = 0; i < sessionList->cnt; i++) {
2386 		(void) mbstowcs(initiator,
2387 		    (char *)sessionList->session[i].initiator.ident,
2388 		    STMF_IDENT_LENGTH);
2389 		initiator[STMF_IDENT_LENGTH] = 0;
2390 		(void) printf(LVL3_FORMAT, "Initiator: ");
2391 		(void) printf("%ws\n", initiator);
2392 		(void) printf(LVL4_FORMAT, "Alias: ");
2393 		if (sessionList->session[i].alias[0] != 0) {
2394 			(void) printf("%s", sessionList->session[i].alias);
2395 		} else {
2396 			(void) printf("-");
2397 		}
2398 		(void) printf("\n");
2399 		(void) printf(LVL4_FORMAT, "Logged in since: ");
2400 		cTime = ctime(&(sessionList->session[i].creationTime));
2401 		if (cTime != NULL) {
2402 			(void) printf("%s", cTime);
2403 		} else {
2404 			(void) printf("unknown\n");
2405 		}
2406 	}
2407 }
2408 
2409 static int
2410 getStmfState(stmfState *state)
2411 {
2412 	int ret;
2413 
2414 	ret = stmfGetState(state);
2415 	switch (ret) {
2416 		case STMF_STATUS_SUCCESS:
2417 			break;
2418 		case STMF_ERROR_PERM:
2419 			(void) fprintf(stderr, "%s: %s\n", cmdName,
2420 			    gettext("permission denied"));
2421 			break;
2422 		case STMF_ERROR_SERVICE_NOT_FOUND:
2423 			(void) fprintf(stderr, "%s: %s\n", cmdName,
2424 			    gettext("STMF service not found"));
2425 			break;
2426 		case STMF_ERROR_BUSY:
2427 			(void) fprintf(stderr, "%s: %s\n", cmdName,
2428 			    gettext("resource busy"));
2429 			break;
2430 		case STMF_ERROR_SERVICE_DATA_VERSION:
2431 			(void) fprintf(stderr, "%s: %s\n", cmdName,
2432 			    gettext("STMF service version incorrect"));
2433 			break;
2434 		default:
2435 			(void) fprintf(stderr, "%s: %s: %d\n", cmdName,
2436 			    gettext("unknown error"), ret);
2437 			break;
2438 	}
2439 	return (ret);
2440 }
2441 
2442 /*
2443  * listStateFunc
2444  *
2445  * List the operational and config state of the stmf service
2446  *
2447  */
2448 /*ARGSUSED*/
2449 static int
2450 listStateFunc(int operandLen, char *operands[], cmdOptions_t *options,
2451     void *args)
2452 {
2453 	int ret;
2454 	stmfState state;
2455 	boolean_t aluaEnabled;
2456 	uint32_t node;
2457 
2458 	if ((ret = getStmfState(&state)) != STMF_STATUS_SUCCESS)
2459 		return (ret);
2460 
2461 	(void) printf("%-18s: ", "Operational Status");
2462 	switch (state.operationalState) {
2463 		case STMF_SERVICE_STATE_ONLINE:
2464 			(void) printf("online");
2465 			break;
2466 		case STMF_SERVICE_STATE_OFFLINE:
2467 			(void) printf("offline");
2468 			break;
2469 		case STMF_SERVICE_STATE_ONLINING:
2470 			(void) printf("onlining");
2471 			break;
2472 		case STMF_SERVICE_STATE_OFFLINING:
2473 			(void) printf("offlining");
2474 			break;
2475 		default:
2476 			(void) printf("unknown");
2477 			break;
2478 	}
2479 	(void) printf("\n");
2480 	(void) printf("%-18s: ", "Config Status");
2481 	switch (state.configState) {
2482 		case STMF_CONFIG_STATE_NONE:
2483 			(void) printf("uninitialized");
2484 			break;
2485 		case STMF_CONFIG_STATE_INIT:
2486 			(void) printf("initializing");
2487 			break;
2488 		case STMF_CONFIG_STATE_INIT_DONE:
2489 			(void) printf("initialized");
2490 			break;
2491 		default:
2492 			(void) printf("unknown");
2493 			break;
2494 	}
2495 	(void) printf("\n");
2496 	ret = stmfGetAluaState(&aluaEnabled, &node);
2497 	switch (ret) {
2498 		case STMF_STATUS_SUCCESS:
2499 			break;
2500 		case STMF_ERROR_PERM:
2501 			(void) fprintf(stderr, "%s: %s\n", cmdName,
2502 			    gettext("permission denied"));
2503 			break;
2504 		case STMF_ERROR_BUSY:
2505 			(void) fprintf(stderr, "%s: %s\n", cmdName,
2506 			    gettext("resource busy"));
2507 			break;
2508 		default:
2509 			(void) fprintf(stderr, "%s: %s: %d\n", cmdName,
2510 			    gettext("unknown error"), ret);
2511 			break;
2512 	}
2513 	(void) printf("%-18s: ", "ALUA Status");
2514 	if (ret == STMF_STATUS_SUCCESS) {
2515 		if (aluaEnabled == B_TRUE) {
2516 			(void) printf("enabled");
2517 		} else {
2518 			(void) printf("disabled");
2519 		}
2520 	} else {
2521 		(void) printf("unknown");
2522 	}
2523 
2524 	(void) printf("\n");
2525 	(void) printf("%-18s: ", "ALUA Node");
2526 	if (ret == STMF_STATUS_SUCCESS) {
2527 		(void) printf("%d", node);
2528 	} else {
2529 		(void) printf("unknown");
2530 	}
2531 	(void) printf("\n");
2532 	return (ret);
2533 }
2534 
2535 /*
2536  * listTargetFunc
2537  *
2538  * list the targets and optionally their properties
2539  *
2540  */
2541 /*ARGSUSED*/
2542 static int
2543 listTargetFunc(int operandLen, char *operands[], cmdOptions_t *options,
2544     void *args)
2545 {
2546 	cmdOptions_t *optionList = options;
2547 	int ret = 0;
2548 	int stmfRet;
2549 	int i, j;
2550 	int outerLoop;
2551 	stmfSessionList *sessionList;
2552 	stmfDevid devid;
2553 	boolean_t operandEntered, found, verbose = B_FALSE;
2554 	stmfDevidList *targetList;
2555 	wchar_t targetIdent[STMF_IDENT_LENGTH + 1];
2556 	stmfTargetProperties targetProps;
2557 
2558 	if ((stmfRet = stmfGetTargetList(&targetList)) != STMF_STATUS_SUCCESS) {
2559 		switch (stmfRet) {
2560 			case STMF_ERROR_NOT_FOUND:
2561 				ret = 0;
2562 				break;
2563 			case STMF_ERROR_SERVICE_OFFLINE:
2564 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2565 				    gettext("STMF service offline"));
2566 				break;
2567 			case STMF_ERROR_BUSY:
2568 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2569 				    gettext("resource busy"));
2570 				break;
2571 			case STMF_ERROR_SERVICE_DATA_VERSION:
2572 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2573 				    gettext("STMF service version incorrect"));
2574 				break;
2575 			case STMF_ERROR_PERM:
2576 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2577 				    gettext("permission denied"));
2578 				break;
2579 			default:
2580 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2581 				    gettext("unknown error"));
2582 				break;
2583 		}
2584 		return (1);
2585 	}
2586 
2587 	for (; optionList->optval; optionList++) {
2588 		switch (optionList->optval) {
2589 			case 'v':
2590 				verbose = B_TRUE;
2591 				break;
2592 		}
2593 	}
2594 
2595 	if (operandLen > 0) {
2596 		outerLoop = operandLen;
2597 		operandEntered = B_TRUE;
2598 	} else {
2599 		outerLoop = 1;
2600 		operandEntered = B_FALSE;
2601 	}
2602 
2603 	for (i = 0; i < outerLoop; i++) {
2604 		if (operandEntered) {
2605 			bzero(&devid, sizeof (devid));
2606 			(void) parseDevid(operands[i], &devid);
2607 		}
2608 		for (found = B_FALSE, j = 0; j < targetList->cnt; j++) {
2609 			if (operandEntered) {
2610 				if (bcmp(&devid, &(targetList->devid[j]),
2611 				    sizeof (devid)) == 0) {
2612 					found = B_TRUE;
2613 				}
2614 			}
2615 			if ((found && operandEntered) || !operandEntered) {
2616 				(void) mbstowcs(targetIdent,
2617 				    (char *)targetList->devid[j].ident,
2618 				    STMF_IDENT_LENGTH);
2619 				targetIdent[STMF_IDENT_LENGTH] = 0;
2620 				(void) printf("Target: %ws\n", targetIdent);
2621 				if (verbose) {
2622 					stmfRet = stmfGetTargetProperties(
2623 					    &(targetList->devid[j]),
2624 					    &targetProps);
2625 					if (stmfRet == STMF_STATUS_SUCCESS) {
2626 						printTargetProps(&targetProps);
2627 					} else {
2628 						(void) fprintf(stderr, "%s:",
2629 						    cmdName);
2630 						(void) fprintf(stderr, "%s\n",
2631 						    gettext(" get properties"
2632 						    " failed"));
2633 					}
2634 					stmfRet = stmfGetSessionList(
2635 					    &(targetList->devid[j]),
2636 					    &sessionList);
2637 					if (stmfRet == STMF_STATUS_SUCCESS) {
2638 						printSessionProps(sessionList);
2639 					} else {
2640 						(void) fprintf(stderr, "%s:",
2641 						    cmdName);
2642 						(void) fprintf(stderr, "%s\n",
2643 						    gettext(" get session info"
2644 						    " failed"));
2645 					}
2646 				}
2647 				if (found && operandEntered) {
2648 					break;
2649 				}
2650 			}
2651 
2652 		}
2653 		if (operandEntered && !found) {
2654 			(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
2655 			    operands[i], "not found");
2656 			ret = 1;
2657 		}
2658 	}
2659 	return (ret);
2660 }
2661 
2662 /*
2663  * listViewFunc
2664  *
2665  * list the view entries for the specified logical unit
2666  *
2667  */
2668 /*ARGSUSED*/
2669 static int
2670 listViewFunc(int operandLen, char *operands[], cmdOptions_t *options,
2671     void *args)
2672 {
2673 	stmfViewEntryList *viewEntryList;
2674 	stmfGuid inGuid;
2675 	unsigned int guid[sizeof (stmfGuid)];
2676 	int ret = 0;
2677 	int stmfRet;
2678 	int i, j, outerLoop;
2679 	boolean_t found = B_TRUE;
2680 	boolean_t operandEntered;
2681 	uint16_t outputLuNbr;
2682 	wchar_t groupName[sizeof (stmfGroupName)];
2683 	char sGuid[GUID_INPUT + 1];
2684 
2685 
2686 	for (; options->optval; options++) {
2687 		switch (options->optval) {
2688 			case 'l':
2689 				if (strlen(options->optarg) != GUID_INPUT) {
2690 					(void) fprintf(stderr,
2691 					    "%s: %s: %s%d%s\n",
2692 					    cmdName, options->optarg,
2693 					    gettext("must be "), GUID_INPUT,
2694 					    gettext(" hexadecimal digits"
2695 					    " long"));
2696 					return (1);
2697 				}
2698 				bcopy(options->optarg, sGuid, GUID_INPUT);
2699 				break;
2700 			default:
2701 				(void) fprintf(stderr, "%s: %c: %s\n",
2702 				    cmdName, options->optval,
2703 				    gettext("unknown option"));
2704 				return (1);
2705 		}
2706 	}
2707 
2708 	if (operandLen > 0) {
2709 		outerLoop = operandLen;
2710 		operandEntered = B_TRUE;
2711 	} else {
2712 		outerLoop = 1;
2713 		operandEntered = B_FALSE;
2714 	}
2715 
2716 	for (i = 0; i < 32; i++)
2717 		sGuid[i] = tolower(sGuid[i]);
2718 	sGuid[i] = 0;
2719 
2720 	(void) sscanf(sGuid, "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
2721 	    &guid[0], &guid[1], &guid[2], &guid[3], &guid[4], &guid[5],
2722 	    &guid[6], &guid[7], &guid[8], &guid[9], &guid[10], &guid[11],
2723 	    &guid[12], &guid[13], &guid[14], &guid[15]);
2724 
2725 	for (i = 0; i < sizeof (stmfGuid); i++) {
2726 		inGuid.guid[i] = guid[i];
2727 	}
2728 
2729 	if ((stmfRet = stmfGetViewEntryList(&inGuid, &viewEntryList))
2730 	    != STMF_STATUS_SUCCESS) {
2731 
2732 		switch (stmfRet) {
2733 			case STMF_ERROR_BUSY:
2734 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
2735 				    sGuid, gettext("resource busy"));
2736 				break;
2737 			case STMF_ERROR_SERVICE_NOT_FOUND:
2738 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2739 				    gettext("STMF service not found"));
2740 				break;
2741 			case STMF_ERROR_SERVICE_DATA_VERSION:
2742 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2743 				    gettext("STMF service version incorrect"));
2744 				break;
2745 			case STMF_ERROR_PERM:
2746 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2747 				    gettext("permission denied"));
2748 				break;
2749 			default:
2750 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
2751 				    sGuid, gettext("unknown error"));
2752 				break;
2753 		}
2754 		return (1);
2755 	}
2756 
2757 	if (viewEntryList->cnt == 0) {
2758 		(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
2759 		    sGuid, gettext("no views found"));
2760 		return (1);
2761 	}
2762 
2763 	for (i = 0; i < outerLoop; i++) {
2764 		for (found = B_FALSE, j = 0; j < viewEntryList->cnt; j++) {
2765 			if (operandEntered) {
2766 				if (atoi(operands[i]) ==
2767 				    viewEntryList->ve[j].veIndex) {
2768 					found = B_TRUE;
2769 				}
2770 			}
2771 			if ((found && operandEntered) || !operandEntered) {
2772 				(void) printf("View Entry: %d\n",
2773 				    viewEntryList->ve[j].veIndex);
2774 				(void) printf(VIEW_FORMAT, "Host group");
2775 				if (viewEntryList->ve[j].allHosts) {
2776 					(void) printf("All\n");
2777 				} else {
2778 					(void) mbstowcs(groupName,
2779 					    viewEntryList->ve[j].hostGroup,
2780 					    sizeof (stmfGroupName) - 1);
2781 					groupName[sizeof (stmfGroupName) - 1]
2782 					    = 0;
2783 					(void) printf("%ws\n", groupName);
2784 				}
2785 				(void) printf(VIEW_FORMAT, "Target group");
2786 				if (viewEntryList->ve[j].allTargets) {
2787 					(void) printf("All\n");
2788 				} else {
2789 					(void) mbstowcs(groupName,
2790 					    viewEntryList->ve[j].targetGroup,
2791 					    sizeof (stmfGroupName) - 1);
2792 					groupName[sizeof (stmfGroupName) - 1]
2793 					    = 0;
2794 					(void) printf("%ws\n", groupName);
2795 				}
2796 				outputLuNbr = ((viewEntryList->ve[j].luNbr[0] &
2797 				    0x3F) << 8) | viewEntryList->ve[j].luNbr[1];
2798 				(void) printf(VIEW_FORMAT, "LUN");
2799 				(void) printf("%d\n", outputLuNbr);
2800 				if (found && operandEntered) {
2801 					break;
2802 				}
2803 			}
2804 		}
2805 		if (operandEntered && !found) {
2806 			(void) fprintf(stderr, "%s: %s, %s: %s\n", cmdName,
2807 			    sGuid, operands[i], gettext("not found"));
2808 			ret = 1;
2809 		}
2810 	}
2811 
2812 	return (ret);
2813 }
2814 
2815 
2816 /*
2817  * onlineOfflineLu
2818  *
2819  * Purpose: Online or offline a logical unit
2820  *
2821  * lu - logical unit to online or offline
2822  *
2823  * state - ONLINE_LU
2824  *         OFFLINE_LU
2825  */
2826 static int
2827 onlineOfflineLu(char *lu, int state)
2828 {
2829 	char sGuid[GUID_INPUT + 1];
2830 	stmfGuid inGuid;
2831 	unsigned int guid[sizeof (stmfGuid)];
2832 	int i;
2833 	int ret = 0, stmfRet;
2834 	stmfLogicalUnitProperties luProps;
2835 
2836 	if (strlen(lu) != GUID_INPUT) {
2837 		(void) fprintf(stderr, "%s: %s: %s %d %s\n", cmdName, lu,
2838 		    gettext("must be"), GUID_INPUT,
2839 		    gettext("hexadecimal digits long"));
2840 		return (1);
2841 	}
2842 
2843 	bcopy(lu, sGuid, GUID_INPUT);
2844 
2845 	for (i = 0; i < 32; i++)
2846 		sGuid[i] = tolower(sGuid[i]);
2847 	sGuid[i] = 0;
2848 
2849 	(void) sscanf(sGuid, "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
2850 	    &guid[0], &guid[1], &guid[2], &guid[3], &guid[4], &guid[5],
2851 	    &guid[6], &guid[7], &guid[8], &guid[9], &guid[10], &guid[11],
2852 	    &guid[12], &guid[13], &guid[14], &guid[15]);
2853 
2854 	for (i = 0; i < sizeof (stmfGuid); i++) {
2855 		inGuid.guid[i] = guid[i];
2856 	}
2857 
2858 	if (state == ONLINE_LU) {
2859 		ret = stmfOnlineLogicalUnit(&inGuid);
2860 	} else if (state == OFFLINE_LU) {
2861 		ret = stmfOfflineLogicalUnit(&inGuid);
2862 	} else {
2863 		return (STMFADM_FAILURE);
2864 	}
2865 	if (ret != STMF_STATUS_SUCCESS) {
2866 		switch (ret) {
2867 			case STMF_ERROR_PERM:
2868 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2869 				    gettext("permission denied"));
2870 				break;
2871 			case STMF_ERROR_SERVICE_NOT_FOUND:
2872 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2873 				    gettext("STMF service not found"));
2874 				break;
2875 			case STMF_ERROR_BUSY:
2876 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2877 				    gettext("resource busy"));
2878 				break;
2879 			case STMF_ERROR_NOT_FOUND:
2880 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
2881 				    lu, gettext("not found"));
2882 				break;
2883 			case STMF_ERROR_SERVICE_DATA_VERSION:
2884 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2885 				    gettext("STMF service version incorrect"));
2886 				break;
2887 			default:
2888 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2889 				    gettext("unknown error"));
2890 				break;
2891 		}
2892 	} else {
2893 		struct timespec	ts = {0};
2894 		unsigned int	count = 0;
2895 		uint32_t	ret_state;
2896 
2897 		ret_state = (state == ONLINE_LU) ?
2898 		    STMF_LOGICAL_UNIT_ONLINING : STMF_LOGICAL_UNIT_OFFLINING;
2899 		ts.tv_nsec = DELAYED_EXEC_WAIT_INTERVAL;
2900 
2901 		/* CONSTCOND */
2902 		while (1) {
2903 			stmfRet = stmfGetLogicalUnitProperties(&inGuid,
2904 			    &luProps);
2905 			if (stmfRet == STMF_STATUS_SUCCESS)
2906 				ret_state = luProps.status;
2907 
2908 			if ((state == ONLINE_LU &&
2909 			    ret_state == STMF_LOGICAL_UNIT_ONLINE) ||
2910 			    (state == OFFLINE_LU &&
2911 			    ret_state == STMF_LOGICAL_UNIT_OFFLINE))
2912 				return (STMFADM_SUCCESS);
2913 
2914 			if ((state == ONLINE_LU &&
2915 			    ret_state == STMF_LOGICAL_UNIT_OFFLINE) ||
2916 			    (state == OFFLINE_LU &&
2917 			    ret_state == STMF_LOGICAL_UNIT_ONLINE))
2918 				return (STMFADM_FAILURE);
2919 
2920 			if (++count ==  DELAYED_EXEC_WAIT_MAX) {
2921 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2922 				    gettext("Logical Unit state change request "
2923 				    "submitted. Waiting for completion "
2924 				    "timed out"));
2925 				return (STMFADM_FAILURE);
2926 			}
2927 			(void) nanosleep(&ts, NULL);
2928 		}
2929 	}
2930 	return (STMFADM_FAILURE);
2931 }
2932 
2933 /*
2934  * onlineLuFunc
2935  *
2936  * Purpose: Online a logical unit
2937  *
2938  */
2939 /*ARGSUSED*/
2940 static int
2941 onlineLuFunc(int operandLen, char *operands[], cmdOptions_t *options,
2942     void *args)
2943 {
2944 	int ret;
2945 	stmfState state;
2946 
2947 	ret = getStmfState(&state);
2948 	if (ret != STMF_STATUS_SUCCESS)
2949 		return (ret);
2950 	if (state.operationalState == STMF_SERVICE_STATE_OFFLINE ||
2951 	    state.operationalState == STMF_SERVICE_STATE_OFFLINING) {
2952 		(void) fprintf(stderr, "%s: %s\n", cmdName,
2953 		    gettext("STMF service is offline"));
2954 		return (1);
2955 	}
2956 	return (onlineOfflineLu(operands[0], ONLINE_LU));
2957 }
2958 
2959 /*
2960  * offlineLuFunc
2961  *
2962  * Purpose: Offline a logical unit
2963  *
2964  */
2965 /*ARGSUSED*/
2966 static int
2967 offlineLuFunc(int operandLen, char *operands[], cmdOptions_t *options,
2968     void *args)
2969 {
2970 	return (onlineOfflineLu(operands[0], OFFLINE_LU));
2971 }
2972 
2973 /*
2974  * onlineOfflineTarget
2975  *
2976  * Purpose: Online or offline a target
2977  *
2978  * target - target to online or offline
2979  *
2980  * state - ONLINE_TARGET
2981  *         OFFLINE_TARGET
2982  */
2983 static int
2984 onlineOfflineTarget(char *target, int state)
2985 {
2986 	int ret = 0, stmfRet = 0;
2987 	stmfDevid devid;
2988 	stmfTargetProperties targetProps;
2989 
2990 	if (parseDevid(target, &devid) != 0) {
2991 		(void) fprintf(stderr, "%s: %s: %s\n",
2992 		    cmdName, target, gettext("unrecognized device id"));
2993 		return (1);
2994 	}
2995 	if (state == ONLINE_TARGET) {
2996 		ret = stmfOnlineTarget(&devid);
2997 	} else if (state == OFFLINE_TARGET) {
2998 		ret = stmfOfflineTarget(&devid);
2999 	} else {
3000 		return (STMFADM_FAILURE);
3001 	}
3002 	if (ret != STMF_STATUS_SUCCESS) {
3003 		switch (ret) {
3004 			case STMF_ERROR_PERM:
3005 				(void) fprintf(stderr, "%s: %s\n", cmdName,
3006 				    gettext("permission denied"));
3007 				break;
3008 			case STMF_ERROR_SERVICE_NOT_FOUND:
3009 				(void) fprintf(stderr, "%s: %s\n", cmdName,
3010 				    gettext("STMF service not found"));
3011 				break;
3012 			case STMF_ERROR_BUSY:
3013 				(void) fprintf(stderr, "%s: %s\n", cmdName,
3014 				    gettext("resource busy"));
3015 				break;
3016 			case STMF_ERROR_NOT_FOUND:
3017 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
3018 				    target, gettext("not found"));
3019 				break;
3020 			case STMF_ERROR_SERVICE_DATA_VERSION:
3021 				(void) fprintf(stderr, "%s: %s\n", cmdName,
3022 				    gettext("STMF service version incorrect"));
3023 				break;
3024 			default:
3025 				(void) fprintf(stderr, "%s: %s\n", cmdName,
3026 				    gettext("unknown error"));
3027 				break;
3028 		}
3029 	} else {
3030 		struct timespec  ts = {0};
3031 		unsigned int count = 0;
3032 		uint32_t	ret_state;
3033 
3034 		ret_state = (state == ONLINE_TARGET) ?
3035 		    STMF_TARGET_PORT_ONLINING : STMF_TARGET_PORT_OFFLINING;
3036 		ts.tv_nsec = DELAYED_EXEC_WAIT_INTERVAL;
3037 
3038 		/* CONSTCOND */
3039 		while (1) {
3040 			stmfRet = stmfGetTargetProperties(&devid, &targetProps);
3041 			if (stmfRet == STMF_STATUS_SUCCESS)
3042 				ret_state = targetProps.status;
3043 
3044 			if ((state == ONLINE_TARGET &&
3045 			    ret_state == STMF_TARGET_PORT_ONLINE) ||
3046 			    (state == OFFLINE_TARGET &&
3047 			    ret_state == STMF_TARGET_PORT_OFFLINE)) {
3048 				return (STMFADM_SUCCESS);
3049 			}
3050 
3051 			if ((state == ONLINE_TARGET &&
3052 			    ret_state == STMF_TARGET_PORT_OFFLINE) ||
3053 			    (state == OFFLINE_TARGET &&
3054 			    ret_state == STMF_TARGET_PORT_ONLINE)) {
3055 				return (STMFADM_FAILURE);
3056 			}
3057 
3058 			if (++count ==  DELAYED_EXEC_WAIT_MAX) {
3059 				(void) fprintf(stderr, "%s: %s\n", cmdName,
3060 				    gettext("Target state change request "
3061 				    "submitted. Waiting for completion "
3062 				    "timed out."));
3063 				return (STMFADM_FAILURE);
3064 			}
3065 			(void) nanosleep(&ts, NULL);
3066 		}
3067 	}
3068 	return (STMFADM_FAILURE);
3069 }
3070 
3071 /*
3072  * onlineTargetFunc
3073  *
3074  * Purpose: Online a target
3075  *
3076  */
3077 /*ARGSUSED*/
3078 static int
3079 onlineTargetFunc(int operandLen, char *operands[], cmdOptions_t *options,
3080     void *args)
3081 {
3082 	int ret;
3083 	stmfState state;
3084 
3085 	ret = getStmfState(&state);
3086 	if (ret != STMF_STATUS_SUCCESS)
3087 		return (ret);
3088 	if (state.operationalState == STMF_SERVICE_STATE_OFFLINE ||
3089 	    state.operationalState == STMF_SERVICE_STATE_OFFLINING) {
3090 		(void) fprintf(stderr, "%s: %s\n", cmdName,
3091 		    gettext("STMF service is offline"));
3092 		return (1);
3093 	}
3094 	return (onlineOfflineTarget(operands[0], ONLINE_TARGET));
3095 }
3096 
3097 /*
3098  * offlineTargetFunc
3099  *
3100  * Purpose: Offline a target
3101  *
3102  */
3103 /*ARGSUSED*/
3104 static int
3105 offlineTargetFunc(int operandLen, char *operands[], cmdOptions_t *options,
3106     void *args)
3107 {
3108 	return (onlineOfflineTarget(operands[0], OFFLINE_TARGET));
3109 }
3110 
3111 
3112 /*ARGSUSED*/
3113 static int
3114 removeHostGroupMemberFunc(int operandLen, char *operands[],
3115     cmdOptions_t *options, void *args)
3116 {
3117 	int i;
3118 	int ret = 0;
3119 	int stmfRet;
3120 	stmfGroupName groupName = {0};
3121 	stmfDevid devid;
3122 	wchar_t groupNamePrint[sizeof (stmfGroupName)] = {0};
3123 
3124 	for (; options->optval; options++) {
3125 		switch (options->optval) {
3126 			case 'g':
3127 				(void) mbstowcs(groupNamePrint, options->optarg,
3128 				    sizeof (stmfGroupName) - 1);
3129 				bcopy(options->optarg, groupName,
3130 				    strlen(options->optarg));
3131 				break;
3132 			default:
3133 				(void) fprintf(stderr, "%s: %c: %s\n",
3134 				    cmdName, options->optval,
3135 				    gettext("unknown option"));
3136 				return (1);
3137 		}
3138 	}
3139 
3140 	for (i = 0; i < operandLen; i++) {
3141 		if (parseDevid(operands[i], &devid) != 0) {
3142 			(void) fprintf(stderr, "%s: %s: %s\n",
3143 			    cmdName, operands[i],
3144 			    gettext("unrecognized device id"));
3145 			ret++;
3146 			continue;
3147 		}
3148 		stmfRet = stmfRemoveFromHostGroup(&groupName, &devid);
3149 		switch (stmfRet) {
3150 			case STMF_STATUS_SUCCESS:
3151 				break;
3152 			case STMF_ERROR_MEMBER_NOT_FOUND:
3153 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
3154 				    operands[i], gettext("not found"));
3155 				ret++;
3156 				break;
3157 			case STMF_ERROR_GROUP_NOT_FOUND:
3158 				(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
3159 				    groupNamePrint, gettext("not found"));
3160 				ret++;
3161 				break;
3162 			case STMF_ERROR_BUSY:
3163 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
3164 				    operands[i], "resource busy");
3165 				ret++;
3166 				break;
3167 			case STMF_ERROR_SERVICE_NOT_FOUND:
3168 				(void) fprintf(stderr, "%s: %s\n", cmdName,
3169 				    gettext("STMF service not found"));
3170 				ret++;
3171 				break;
3172 			case STMF_ERROR_SERVICE_DATA_VERSION:
3173 				(void) fprintf(stderr, "%s: %s\n", cmdName,
3174 				    gettext("STMF service version incorrect"));
3175 				ret++;
3176 				break;
3177 			case STMF_ERROR_PERM:
3178 				(void) fprintf(stderr, "%s: %s\n", cmdName,
3179 				    gettext("permission denied"));
3180 				ret++;
3181 				break;
3182 			default:
3183 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
3184 				    operands[i], gettext("unknown error"));
3185 				ret++;
3186 				break;
3187 		}
3188 	}
3189 
3190 	return (ret);
3191 }
3192 
3193 /*
3194  * removeTargetGroupMemberFunc
3195  *
3196  * Removes one or more members from a target group
3197  *
3198  */
3199 /*ARGSUSED*/
3200 static int
3201 removeTargetGroupMemberFunc(int operandLen, char *operands[],
3202     cmdOptions_t *options, void *args)
3203 {
3204 	int i;
3205 	int ret = 0;
3206 	int stmfRet;
3207 	stmfGroupName groupName = {0};
3208 	stmfDevid devid;
3209 	wchar_t groupNamePrint[sizeof (stmfGroupName)] = {0};
3210 
3211 	for (; options->optval; options++) {
3212 		switch (options->optval) {
3213 			case 'g':
3214 				(void) mbstowcs(groupNamePrint, options->optarg,
3215 				    sizeof (stmfGroupName) - 1);
3216 				bcopy(options->optarg, groupName,
3217 				    strlen(options->optarg));
3218 				break;
3219 			default:
3220 				(void) fprintf(stderr, "%s: %c: %s\n",
3221 				    cmdName, options->optval,
3222 				    gettext("unknown option"));
3223 				return (1);
3224 		}
3225 	}
3226 
3227 	for (i = 0; i < operandLen; i++) {
3228 		if (parseDevid(operands[i], &devid) != 0) {
3229 			(void) fprintf(stderr, "%s: %s: %s\n",
3230 			    cmdName, operands[i],
3231 			    gettext("unrecognized device id"));
3232 			ret++;
3233 			continue;
3234 		}
3235 		stmfRet = stmfRemoveFromTargetGroup(&groupName, &devid);
3236 		switch (stmfRet) {
3237 			case STMF_STATUS_SUCCESS:
3238 				break;
3239 			case STMF_ERROR_MEMBER_NOT_FOUND:
3240 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
3241 				    operands[i], gettext("not found"));
3242 				ret++;
3243 				break;
3244 			case STMF_ERROR_GROUP_NOT_FOUND:
3245 				(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
3246 				    groupNamePrint, gettext("not found"));
3247 				ret++;
3248 				break;
3249 			case STMF_ERROR_BUSY:
3250 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
3251 				    operands[i], gettext("resource busy"));
3252 				ret++;
3253 				break;
3254 			case STMF_ERROR_SERVICE_NOT_FOUND:
3255 				(void) fprintf(stderr, "%s: %s\n", cmdName,
3256 				    gettext("STMF service not found"));
3257 				ret++;
3258 				break;
3259 			case STMF_ERROR_PERM:
3260 				(void) fprintf(stderr, "%s: %s\n", cmdName,
3261 				    gettext("permission denied"));
3262 				ret++;
3263 				break;
3264 			case STMF_ERROR_SERVICE_DATA_VERSION:
3265 				(void) fprintf(stderr, "%s: %s\n", cmdName,
3266 				    gettext("STMF service version incorrect"));
3267 				ret++;
3268 				break;
3269 			case STMF_ERROR_TG_ONLINE:
3270 				(void) fprintf(stderr, "%s: %s\n", cmdName,
3271 				    gettext("STMF target must be offline"));
3272 				ret++;
3273 				break;
3274 			default:
3275 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
3276 				    operands[i], gettext("unknown error"));
3277 				ret++;
3278 				break;
3279 		}
3280 	}
3281 
3282 	return (ret);
3283 }
3284 
3285 /*
3286  * removeViewFunc
3287  *
3288  * Removes one or more view entries from a logical unit
3289  *
3290  */
3291 /*ARGSUSED*/
3292 static int
3293 removeViewFunc(int operandLen, char *operands[], cmdOptions_t *options,
3294     void *args)
3295 {
3296 	char sGuid[GUID_INPUT + 1];
3297 	stmfViewEntryList *viewEntryList;
3298 	stmfGuid inGuid;
3299 	uint32_t count;
3300 	unsigned int guid[sizeof (stmfGuid)];
3301 	char *endPtr;
3302 	uint32_t veNbr;
3303 	int i;
3304 	boolean_t all = B_FALSE;
3305 	boolean_t luInput = B_FALSE;
3306 	int ret = 0;
3307 	int stmfRet;
3308 
3309 	/* Note: 'l' is required */
3310 	for (; options->optval; options++) {
3311 		switch (options->optval) {
3312 			case 'l':
3313 				if (strlen(options->optarg) != GUID_INPUT) {
3314 					(void) fprintf(stderr,
3315 					    "%s: %s: %s %d %s\n",
3316 					    cmdName, options->optarg,
3317 					    gettext("must be"), GUID_INPUT,
3318 					    gettext("hexadecimal digits long"));
3319 					return (1);
3320 				}
3321 				bcopy(options->optarg, sGuid, GUID_INPUT);
3322 				luInput = B_TRUE;
3323 				break;
3324 			case 'a':
3325 				/* removing all view entries for this GUID */
3326 				all = B_TRUE;
3327 				break;
3328 			default:
3329 				(void) fprintf(stderr, "%s: %c: %s\n",
3330 				    cmdName, options->optval,
3331 				    "unknown option");
3332 				return (1);
3333 		}
3334 	}
3335 
3336 	if (!all && operandLen == 0) {
3337 		(void) fprintf(stderr, "%s: %s\n", cmdName,
3338 		    gettext("no view entries specified"));
3339 		return (1);
3340 	}
3341 
3342 	if (!luInput) {
3343 		(void) fprintf(stderr, "%s: %s\n", cmdName,
3344 		    gettext("logical unit (-l) not specified"));
3345 		return (1);
3346 	}
3347 
3348 	for (i = 0; i < 32; i++)
3349 		sGuid[i] = tolower(sGuid[i]);
3350 	sGuid[i] = 0;
3351 
3352 	(void) sscanf(sGuid, "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
3353 	    &guid[0], &guid[1], &guid[2], &guid[3], &guid[4], &guid[5],
3354 	    &guid[6], &guid[7], &guid[8], &guid[9], &guid[10], &guid[11],
3355 	    &guid[12], &guid[13], &guid[14], &guid[15]);
3356 
3357 	for (i = 0; i < sizeof (stmfGuid); i++) {
3358 		inGuid.guid[i] = guid[i];
3359 	}
3360 
3361 	if ((stmfRet = stmfGetViewEntryList(&inGuid, &viewEntryList))
3362 	    != STMF_STATUS_SUCCESS) {
3363 
3364 		switch (stmfRet) {
3365 			case STMF_ERROR_BUSY:
3366 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
3367 				    sGuid, gettext("resource busy"));
3368 				break;
3369 			case STMF_ERROR_SERVICE_NOT_FOUND:
3370 				(void) fprintf(stderr, "%s: %s\n", cmdName,
3371 				    gettext("STMF service not found"));
3372 				break;
3373 			case STMF_ERROR_SERVICE_DATA_VERSION:
3374 				(void) fprintf(stderr, "%s: %s\n", cmdName,
3375 				    gettext("STMF service version incorrect"));
3376 				break;
3377 			case STMF_ERROR_PERM:
3378 				(void) fprintf(stderr, "%s: %s\n", cmdName,
3379 				    gettext("permission denied"));
3380 				break;
3381 			default:
3382 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
3383 				    sGuid, gettext("unknown error"));
3384 				break;
3385 		}
3386 		return (1);
3387 	}
3388 
3389 	if (viewEntryList->cnt == 0) {
3390 		(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
3391 		    sGuid, gettext("no views found"));
3392 		return (1);
3393 	}
3394 
3395 	if (all) {
3396 		count = viewEntryList->cnt;
3397 	} else {
3398 		count = operandLen;
3399 	}
3400 
3401 	for (i = 0; i < count; i++) {
3402 		if (all) {
3403 			veNbr = viewEntryList->ve[i].veIndex;
3404 		} else {
3405 			endPtr = NULL;
3406 			veNbr = strtol(operands[i], &endPtr, 10);
3407 			if (endPtr && *endPtr != 0) {
3408 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
3409 				    operands[i], gettext("invalid input"));
3410 				continue;
3411 			}
3412 		}
3413 		stmfRet = stmfRemoveViewEntry(&inGuid, veNbr);
3414 		switch (stmfRet) {
3415 			case STMF_STATUS_SUCCESS:
3416 				break;
3417 			case STMF_ERROR_NOT_FOUND:
3418 				(void) fprintf(stderr, "%s: %s: %d: %s\n",
3419 				    cmdName, sGuid, veNbr,
3420 				    gettext("not found"));
3421 				ret++;
3422 				break;
3423 			case STMF_ERROR_BUSY:
3424 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
3425 				    sGuid, gettext("resource busy"));
3426 				ret++;
3427 				break;
3428 			case STMF_ERROR_SERVICE_NOT_FOUND:
3429 				(void) fprintf(stderr, "%s: %s\n", cmdName,
3430 				    gettext("STMF service not found"));
3431 				ret++;
3432 				break;
3433 			case STMF_ERROR_CONFIG_NONE:
3434 				(void) fprintf(stderr, "%s: %s\n", cmdName,
3435 				    gettext("STMF service is not initialized"));
3436 				ret++;
3437 				break;
3438 			case STMF_ERROR_SERVICE_DATA_VERSION:
3439 				(void) fprintf(stderr, "%s: %s\n", cmdName,
3440 				    gettext("STMF service version incorrect"));
3441 				ret++;
3442 				break;
3443 			default:
3444 				(void) fprintf(stderr, "%s: %s, %d: %s",
3445 				    cmdName, sGuid, veNbr,
3446 				    gettext("unknown error"));
3447 				ret++;
3448 				break;
3449 		}
3450 	}
3451 
3452 	return (ret);
3453 }
3454 
3455 /*
3456  * input:
3457  *  execFullName - exec name of program (argv[0])
3458  *
3459  *  copied from usr/src/cmd/zoneadm/zoneadm.c in OS/Net
3460  *  (changed name to lowerCamelCase to keep consistent with this file)
3461  *
3462  * Returns:
3463  *  command name portion of execFullName
3464  */
3465 static char *
3466 getExecBasename(char *execFullname)
3467 {
3468 	char *lastSlash, *execBasename;
3469 
3470 	/* guard against '/' at end of command invocation */
3471 	for (;;) {
3472 		lastSlash = strrchr(execFullname, '/');
3473 		if (lastSlash == NULL) {
3474 			execBasename = execFullname;
3475 			break;
3476 		} else {
3477 			execBasename = lastSlash + 1;
3478 			if (*execBasename == '\0') {
3479 				*lastSlash = '\0';
3480 				continue;
3481 			}
3482 			break;
3483 		}
3484 	}
3485 	return (execBasename);
3486 }
3487 
3488 int
3489 main(int argc, char *argv[])
3490 {
3491 	synTables_t synTables;
3492 	char versionString[VERSION_STRING_MAX_LEN];
3493 	int ret;
3494 	int funcRet;
3495 	void *subcommandArgs = NULL;
3496 
3497 	(void) setlocale(LC_ALL, "");
3498 	(void) textdomain(TEXT_DOMAIN);
3499 	/* set global command name */
3500 	cmdName = getExecBasename(argv[0]);
3501 
3502 	(void) snprintf(versionString, VERSION_STRING_MAX_LEN, "%s.%s",
3503 	    VERSION_STRING_MAJOR, VERSION_STRING_MINOR);
3504 	synTables.versionString = versionString;
3505 	synTables.longOptionTbl = &longOptions[0];
3506 	synTables.subCommandPropsTbl = &subcommands[0];
3507 
3508 	ret = cmdParse(argc, argv, synTables, subcommandArgs, &funcRet);
3509 	if (ret != 0) {
3510 		return (ret);
3511 	}
3512 
3513 	return (funcRet);
3514 } /* end main */
3515