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