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