xref: /illumos-gate/usr/src/cmd/stmfadm/stmfadm.c (revision 3e7352ae)
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 2008 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 createTargetGroupFunc(int, char **, cmdOptions_t *, void *);
50 static int deleteHostGroupFunc(int, char **, cmdOptions_t *, void *);
51 static int deleteTargetGroupFunc(int, char **, cmdOptions_t *, void *);
52 static int listLuFunc(int, char **, cmdOptions_t *, void *);
53 static int listTargetFunc(int, char **, cmdOptions_t *, void *);
54 static int listViewFunc(int, char **, cmdOptions_t *, void *);
55 static int listHostGroupFunc(int, char **, cmdOptions_t *, void *);
56 static int listStateFunc(int, char **, cmdOptions_t *, void *);
57 static int listTargetGroupFunc(int, char **, cmdOptions_t *, void *);
58 static int offlineTargetFunc(int, char **, cmdOptions_t *, void *);
59 static int offlineLuFunc(int, char **, cmdOptions_t *, void *);
60 static int onlineTargetFunc(int, char **, cmdOptions_t *, void *);
61 static int onlineLuFunc(int, char **, cmdOptions_t *, void *);
62 static int onlineOfflineTarget(char *, int);
63 static int onlineOfflineLu(char *, int);
64 static int removeHostGroupMemberFunc(int, char **, cmdOptions_t *, void *);
65 static int removeTargetGroupMemberFunc(int, char **, cmdOptions_t *, void *);
66 static int removeViewFunc(int, char **, cmdOptions_t *, void *);
67 static char *getExecBasename(char *);
68 static int parseDevid(char *input, stmfDevid *devid);
69 static void printGroupProps(stmfGroupProperties *groupProps);
70 static int checkScsiNameString(wchar_t *, stmfDevid *);
71 static int checkHexUpper(char *);
72 static int checkIscsiName(wchar_t *);
73 static void printLuProps(stmfLogicalUnitProperties *luProps);
74 static void printGuid(stmfGuid *guid, FILE *printWhere);
75 static void printTargetProps(stmfTargetProperties *);
76 static void printSessionProps(stmfSessionList *);
77 
78 
79 
80 /*
81  *  MAJOR - This should only change when there is an incompatible change made
82  *  to the interfaces or the output.
83  *
84  *  MINOR - This should change whenever there is a new command or new feature
85  *  with no incompatible change.
86  */
87 #define	VERSION_STRING_MAJOR	    "1"
88 #define	VERSION_STRING_MINOR	    "0"
89 #define	MAX_DEVID_INPUT		    256
90 #define	GUID_INPUT		    32
91 #define	MAX_LU_NBR		    16383
92 #define	ONLINE_LU		    0
93 #define	OFFLINE_LU		    1
94 #define	ONLINE_TARGET		    2
95 #define	OFFLINE_TARGET		    3
96 #define	PROPS_FORMAT		    "    %-18s: "
97 #define	VIEW_FORMAT		    "    %-13s: "
98 #define	LVL3_FORMAT		    "        %s"
99 #define	LVL4_FORMAT		    "            %s"
100 
101 /* SCSI Name String length definitions */
102 #define	SNS_EUI_16		    16
103 #define	SNS_EUI_24		    24
104 #define	SNS_EUI_32		    32
105 #define	SNS_NAA_16		    16
106 #define	SNS_NAA_32		    32
107 #define	SNS_WWN_16		    16
108 #define	SNS_IQN_223		    223
109 
110 /* tables set up based on cmdparse instructions */
111 
112 /* add new options here */
113 optionTbl_t longOptions[] = {
114 	{"all", no_arg, 'a', NULL},
115 	{"group-name", required_arg, 'g', "group-name"},
116 	{"secure-data", no_arg, 's', NULL},
117 	{"lu-name", required_arg, 'l', "LU-Name"},
118 	{"lun", required_arg, 'n', "logical-unit-number"},
119 	{"verbose", no_arg, 'v', NULL},
120 	{"target-group", required_arg, 't', "group-name"},
121 	{"host-group", required_arg, 'h', "group-name"},
122 	{"size", required_arg, 's', "size (k/M/G)"},
123 	{"force", no_arg, 'r', NULL},
124 	{"new", no_arg, 'n', NULL},
125 	{NULL, 0, 0, 0}
126 };
127 
128 /*
129  * Add new subcommands here
130  */
131 subCommandProps_t subcommands[] = {
132 	{"add-hg-member", addHostGroupMemberFunc, "g", "g", NULL,
133 		OPERAND_MANDATORY_MULTIPLE, OPERANDSTRING_GROUP_MEMBER},
134 	{"add-tg-member", addTargetGroupMemberFunc, "g", "g", NULL,
135 		OPERAND_MANDATORY_MULTIPLE, OPERANDSTRING_GROUP_MEMBER},
136 	{"add-view", addViewFunc, "nth", NULL, NULL,
137 		OPERAND_MANDATORY_SINGLE, OPERANDSTRING_LU},
138 	{"create-hg", createHostGroupFunc, NULL, NULL, NULL,
139 		OPERAND_MANDATORY_SINGLE, OPERANDSTRING_GROUP_NAME},
140 	{"create-tg", createTargetGroupFunc, NULL, NULL, NULL,
141 		OPERAND_MANDATORY_SINGLE, OPERANDSTRING_GROUP_NAME},
142 	{"delete-hg", deleteHostGroupFunc, NULL, NULL, NULL,
143 		OPERAND_MANDATORY_SINGLE, OPERANDSTRING_GROUP_NAME},
144 	{"delete-tg", deleteTargetGroupFunc, NULL, NULL, NULL,
145 		OPERAND_MANDATORY_SINGLE, OPERANDSTRING_GROUP_NAME},
146 	{"list-hg", listHostGroupFunc, "v", NULL, NULL,
147 		OPERAND_OPTIONAL_MULTIPLE, OPERANDSTRING_GROUP_NAME},
148 	{"list-lu", listLuFunc, "v", NULL, NULL, OPERAND_OPTIONAL_MULTIPLE,
149 		OPERANDSTRING_LU},
150 	{"list-state", listStateFunc, NULL, NULL, NULL, OPERAND_NONE, NULL},
151 	{"list-target", listTargetFunc, "v", NULL, NULL,
152 		OPERAND_OPTIONAL_MULTIPLE, OPERANDSTRING_TARGET},
153 	{"list-tg", listTargetGroupFunc, "v", NULL, NULL,
154 		OPERAND_OPTIONAL_MULTIPLE, OPERANDSTRING_GROUP_NAME},
155 	{"list-view", listViewFunc, "l", "l", NULL,
156 		OPERAND_OPTIONAL_MULTIPLE, OPERANDSTRING_VIEW_ENTRY},
157 	{"online-lu", onlineLuFunc, NULL, NULL, NULL,
158 		OPERAND_MANDATORY_SINGLE, OPERANDSTRING_LU},
159 	{"offline-lu", offlineLuFunc, NULL, NULL, NULL,
160 		OPERAND_MANDATORY_SINGLE, OPERANDSTRING_LU},
161 	{"online-target", onlineTargetFunc, NULL, NULL, NULL,
162 		OPERAND_MANDATORY_SINGLE, OPERANDSTRING_TARGET},
163 	{"offline-target", offlineTargetFunc, NULL, NULL, NULL,
164 		OPERAND_MANDATORY_SINGLE, OPERANDSTRING_TARGET},
165 	{"remove-hg-member", removeHostGroupMemberFunc, "g", "g", NULL,
166 		OPERAND_MANDATORY_MULTIPLE, OPERANDSTRING_GROUP_MEMBER},
167 	{"remove-tg-member", removeTargetGroupMemberFunc, "g", "g", NULL,
168 		OPERAND_MANDATORY_MULTIPLE, OPERANDSTRING_GROUP_MEMBER},
169 	{"remove-view", removeViewFunc, "la", "l", NULL,
170 		OPERAND_OPTIONAL_MULTIPLE, OPERANDSTRING_VIEW_ENTRY},
171 	{NULL, 0, NULL, NULL, 0, NULL, 0, NULL}
172 };
173 
174 /* globals */
175 char *cmdName;
176 
177 /*
178  * addHostGroupMemberFunc
179  *
180  * Add members to a host group
181  *
182  */
183 /*ARGSUSED*/
184 static int
185 addHostGroupMemberFunc(int operandLen, char *operands[], cmdOptions_t *options,
186     void *args)
187 {
188 	int i;
189 	int ret = 0;
190 	int stmfRet;
191 	stmfGroupName groupName = {0};
192 	wchar_t groupNamePrint[sizeof (stmfGroupName)] = {0};
193 	stmfDevid devid;
194 
195 	for (; options->optval; options++) {
196 		switch (options->optval) {
197 			/* host group name */
198 			case 'g':
199 				(void) mbstowcs(groupNamePrint, options->optarg,
200 				    sizeof (stmfGroupName) - 1);
201 				bcopy(options->optarg, groupName,
202 				    strlen(options->optarg));
203 				break;
204 			default:
205 				(void) fprintf(stderr, "%s: %c: %s\n",
206 				    cmdName, options->optval,
207 				    gettext("unknown option"));
208 				return (1);
209 		}
210 	}
211 
212 	for (i = 0; i < operandLen; i++) {
213 		if (parseDevid(operands[i], &devid) != 0) {
214 			(void) fprintf(stderr, "%s: %s: %s\n",
215 			    cmdName, operands[i],
216 			    gettext("unrecognized device id"));
217 			ret++;
218 			continue;
219 		}
220 		stmfRet = stmfAddToHostGroup(&groupName, &devid);
221 		switch (stmfRet) {
222 			case STMF_STATUS_SUCCESS:
223 				break;
224 			case STMF_ERROR_EXISTS:
225 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
226 				    operands[i], gettext("already exists"));
227 				ret++;
228 				break;
229 			case STMF_ERROR_GROUP_NOT_FOUND:
230 				(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
231 				    groupNamePrint, gettext("not found"));
232 				ret++;
233 				break;
234 			case STMF_ERROR_PERM:
235 				(void) fprintf(stderr, "%s: %s\n", cmdName,
236 				    gettext("permission denied"));
237 				break;
238 			case STMF_ERROR_BUSY:
239 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
240 				    operands[i], gettext("resource busy"));
241 				ret++;
242 				break;
243 			case STMF_ERROR_SERVICE_NOT_FOUND:
244 				(void) fprintf(stderr, "%s: %s\n", cmdName,
245 				    gettext("STMF service not found"));
246 				ret++;
247 				break;
248 			case STMF_ERROR_SERVICE_DATA_VERSION:
249 				(void) fprintf(stderr, "%s: %s\n", cmdName,
250 				    gettext("STMF service version incorrect"));
251 				ret++;
252 				break;
253 			default:
254 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
255 				    operands[i], gettext("unknown error"));
256 				ret++;
257 				break;
258 		}
259 	}
260 
261 	return (ret);
262 }
263 
264 /*
265  * addTargetGroupMemberFunc
266  *
267  * Add members to a target group
268  *
269  */
270 /*ARGSUSED*/
271 static int
272 addTargetGroupMemberFunc(int operandLen, char *operands[],
273     cmdOptions_t *options, void *args)
274 {
275 	int i;
276 	int ret = 0;
277 	int stmfRet;
278 	stmfGroupName groupName = {0};
279 	wchar_t groupNamePrint[sizeof (stmfGroupName)] = {0};
280 	stmfDevid devid;
281 
282 	for (; options->optval; options++) {
283 		switch (options->optval) {
284 			/* target group name */
285 			case 'g':
286 				(void) mbstowcs(groupNamePrint, options->optarg,
287 				    sizeof (stmfGroupName) - 1);
288 				bcopy(options->optarg, groupName,
289 				    strlen(options->optarg));
290 				break;
291 			default:
292 				(void) fprintf(stderr, "%s: %c: %s\n",
293 				    cmdName, options->optval,
294 				    gettext("unknown option"));
295 				return (1);
296 		}
297 	}
298 
299 	for (i = 0; i < operandLen; i++) {
300 		if (parseDevid(operands[i], &devid) != 0) {
301 			(void) fprintf(stderr, "%s: %s: %s\n",
302 			    cmdName, operands[i],
303 			    gettext("unrecognized device id"));
304 			ret++;
305 			continue;
306 		}
307 		stmfRet = stmfAddToTargetGroup(&groupName, &devid);
308 		switch (stmfRet) {
309 			case STMF_STATUS_SUCCESS:
310 				break;
311 			case STMF_ERROR_EXISTS:
312 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
313 				    operands[i], gettext("already exists"));
314 				ret++;
315 				break;
316 			case STMF_ERROR_GROUP_NOT_FOUND:
317 				(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
318 				    groupNamePrint, gettext("not found"));
319 				ret++;
320 				break;
321 			case STMF_ERROR_PERM:
322 				(void) fprintf(stderr, "%s: %s\n", cmdName,
323 				    gettext("permission denied"));
324 				break;
325 			case STMF_ERROR_BUSY:
326 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
327 				    operands[i], gettext("resource busy"));
328 				ret++;
329 				break;
330 			case STMF_ERROR_SERVICE_NOT_FOUND:
331 				(void) fprintf(stderr, "%s: %s\n", cmdName,
332 				    gettext("STMF service not found"));
333 				ret++;
334 				break;
335 			case STMF_ERROR_SERVICE_ONLINE:
336 				(void) fprintf(stderr, "%s: %s\n", cmdName,
337 				    gettext("STMF service must be offline"));
338 				ret++;
339 				break;
340 			case STMF_ERROR_SERVICE_DATA_VERSION:
341 				(void) fprintf(stderr, "%s: %s\n", cmdName,
342 				    gettext("STMF service version incorrect"));
343 				ret++;
344 				break;
345 			default:
346 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
347 				    operands[i], gettext("unknown error"));
348 				ret++;
349 				break;
350 		}
351 	}
352 
353 	return (ret);
354 }
355 
356 /*
357  * parseDevid
358  *
359  * Converts char * input to a stmfDevid
360  *
361  * input - this should be in the following format with either a
362  * wwn. iqn. or eui. representation.
363  * A name string of the format:
364  *	wwn.<WWN> (FC/SAS address)
365  *	iqn.<iSCSI name> (iSCSI iqn)
366  *	eui.<WWN> (iSCSI eui name)
367  *
368  * devid - pointer to stmfDevid structure allocated by the caller.
369  *
370  * Returns:
371  *  0 on success
372  *  non-zero on failure
373  */
374 static int
375 parseDevid(char *input, stmfDevid *devid)
376 {
377 	wchar_t inputWc[MAX_DEVID_INPUT + 1] = {0};
378 
379 	/* convert to wcs */
380 	(void) mbstowcs(inputWc, input, MAX_DEVID_INPUT);
381 
382 	/*
383 	 * Check for known scsi name string formats
384 	 * If one is found, we're done
385 	 * If not, then it's a failure to parse
386 	 */
387 	if (checkScsiNameString(inputWc, devid) == 0) {
388 		return (0);
389 	}
390 
391 	return (-1);
392 }
393 
394 /*
395  * checkScsiNameString
396  *
397  * Validates known SCSI name string formats and converts to stmfDevid
398  * format
399  *
400  * input - input SCSI name string
401  * devid - pointer to stmfDevid structure allocated by the caller
402  *         on successful return, contains the devid based on input
403  *
404  * returns:
405  *         0 on success
406  *         -1 on failure
407  */
408 static int
409 checkScsiNameString(wchar_t *input, stmfDevid *devid)
410 {
411 	char *mbString = NULL;
412 	int mbStringLen;
413 	int len;
414 	int i;
415 
416 	/*
417 	 * Convert to multi-byte string
418 	 *
419 	 * This is used for either eui or naa formats
420 	 */
421 	mbString = calloc(1, (mbStringLen = wcstombs(mbString, input, 0)) + 1);
422 	if (mbString == NULL) {
423 		(void) fprintf(stderr, "%s: %s\n",
424 		    cmdName, "Insufficient memory\n");
425 		return (-1);
426 	}
427 	if (wcstombs(mbString, input, mbStringLen) == (size_t)-1) {
428 		return (-1);
429 	}
430 
431 	/*
432 	 * check for iqn format
433 	 */
434 	if (strncmp(mbString, "iqn.", 4) == 0) {
435 		if ((len = strlen(mbString)) > (SNS_IQN_223)) {
436 			return (-1);
437 		}
438 		for (i = 0; i < len; i++) {
439 			mbString[i] = tolower(mbString[i]);
440 		}
441 		if (checkIscsiName(input + 4) != 0) {
442 			return (-1);
443 		}
444 	} else if (strncmp(mbString, "wwn.", 4) == 0) {
445 		if ((len = strlen(mbString + 4)) != SNS_WWN_16) {
446 			return (-1);
447 		} else if (checkHexUpper(mbString + 4) != 0) {
448 			return (-1);
449 		}
450 	} else if (strncmp(mbString, "eui.", 4) == 0) {
451 		if ((len = strlen(mbString + 4)) != SNS_EUI_16) {
452 			return (-1);
453 		} else if (checkHexUpper(mbString + 4) != 0) {
454 			return (-1);
455 		}
456 	} else {
457 		return (-1);
458 	}
459 
460 	/*
461 	 * We have a validated name string.
462 	 * Go ahead and set the length and copy it.
463 	 */
464 	devid->identLength = strlen(mbString);
465 	bzero(devid->ident, STMF_IDENT_LENGTH);
466 	bcopy(mbString, devid->ident, devid->identLength);
467 
468 	return (0);
469 }
470 
471 
472 /*
473  * Checks whether the entire string is in hex and converts to upper
474  */
475 static int
476 checkHexUpper(char *input)
477 {
478 	int i;
479 
480 	for (i = 0; i < strlen(input); i++) {
481 		if (isxdigit(input[i])) {
482 			input[i] = toupper(input[i]);
483 			continue;
484 		}
485 		return (-1);
486 	}
487 
488 	return (0);
489 }
490 
491 /*
492  * checkIscsiName
493  *
494  * Purpose: Basic string checking on name
495  */
496 static int
497 checkIscsiName(wchar_t *input)
498 {
499 	int i;
500 
501 	for (i = 0; input[i] != 0; i++) {
502 		if (!iswalnum(input[i]) && input[i] != '-' &&
503 		    input[i] != '.' && input[i] != ':') {
504 			return (-1);
505 		}
506 	}
507 
508 	return (0);
509 }
510 
511 
512 /*
513  * addViewFunc
514  *
515  * Adds a view entry to a logical unit
516  *
517  */
518 /*ARGSUSED*/
519 static int
520 addViewFunc(int operandLen, char *operands[], cmdOptions_t *options,
521     void *args)
522 {
523 	stmfViewEntry viewEntry;
524 	stmfGuid inGuid;
525 	unsigned int guid[sizeof (stmfGuid)];
526 	uint16_t inputLuNbr;
527 	int ret = 0;
528 	int stmfRet;
529 	int i;
530 	char sGuid[GUID_INPUT + 1];
531 
532 	bzero(&viewEntry, sizeof (viewEntry));
533 	/* init view entry structure */
534 	viewEntry.allHosts = B_TRUE;
535 	viewEntry.allTargets = B_TRUE;
536 	viewEntry.luNbrValid = B_FALSE;
537 
538 	/* check input length */
539 	if (strlen(operands[0]) != GUID_INPUT) {
540 		(void) fprintf(stderr, "%s: %s: %s%d%s\n", cmdName, operands[0],
541 		    gettext("must be "), GUID_INPUT,
542 		    gettext(" hexadecimal digits"));
543 		return (1);
544 	}
545 
546 	for (; options->optval; options++) {
547 		switch (options->optval) {
548 			/* logical unit number */
549 			case 'n':
550 				viewEntry.luNbrValid = B_TRUE;
551 				inputLuNbr = atoi(options->optarg);
552 				if (inputLuNbr > MAX_LU_NBR) {
553 					(void) fprintf(stderr, "%s: %d: %s\n",
554 					    cmdName, inputLuNbr,
555 					    gettext("Logical unit number"
556 					    " must be less than 16384"));
557 					return (1);
558 				}
559 				viewEntry.luNbr[0] = inputLuNbr >> 8;
560 				viewEntry.luNbr[1] = inputLuNbr & 0xff;
561 				break;
562 			/* host group */
563 			case 'h':
564 				viewEntry.allHosts = B_FALSE;
565 				bcopy(options->optarg, viewEntry.hostGroup,
566 				    strlen(options->optarg));
567 				break;
568 			/* target group */
569 			case 't':
570 				viewEntry.allTargets = B_FALSE;
571 				bcopy(options->optarg, viewEntry.targetGroup,
572 				    strlen(options->optarg));
573 				break;
574 			default:
575 				(void) fprintf(stderr, "%s: %c: %s\n",
576 				    cmdName, options->optval,
577 				    gettext("unknown option"));
578 				return (1);
579 		}
580 	}
581 
582 	/* convert to lower case for scan */
583 	for (i = 0; i < 32; i++)
584 		sGuid[i] = tolower(operands[0][i]);
585 	sGuid[i] = 0;
586 
587 	(void) sscanf(sGuid, "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
588 	    &guid[0], &guid[1], &guid[2], &guid[3], &guid[4], &guid[5],
589 	    &guid[6], &guid[7], &guid[8], &guid[9], &guid[10], &guid[11],
590 	    &guid[12], &guid[13], &guid[14], &guid[15]);
591 
592 	for (i = 0; i < sizeof (stmfGuid); i++) {
593 		inGuid.guid[i] = guid[i];
594 	}
595 
596 	/* add the view entry */
597 	stmfRet = stmfAddViewEntry(&inGuid, &viewEntry);
598 	switch (stmfRet) {
599 		case STMF_STATUS_SUCCESS:
600 			break;
601 		case STMF_ERROR_EXISTS:
602 			(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
603 			    operands[0], gettext("already exists"));
604 			ret++;
605 			break;
606 		case STMF_ERROR_BUSY:
607 			(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
608 			    operands[0], gettext("resource busy"));
609 			ret++;
610 			break;
611 		case STMF_ERROR_SERVICE_NOT_FOUND:
612 			(void) fprintf(stderr, "%s: %s\n", cmdName,
613 			    gettext("STMF service not found"));
614 			ret++;
615 			break;
616 		case STMF_ERROR_PERM:
617 			(void) fprintf(stderr, "%s: %s\n", cmdName,
618 			    gettext("permission denied"));
619 			ret++;
620 			break;
621 		case STMF_ERROR_LUN_IN_USE:
622 			(void) fprintf(stderr, "%s: %s\n", cmdName,
623 			    gettext("LUN already in use"));
624 			ret++;
625 			break;
626 		case STMF_ERROR_VE_CONFLICT:
627 			(void) fprintf(stderr, "%s: %s\n", cmdName,
628 			    gettext("view entry exists"));
629 			ret++;
630 			break;
631 		case STMF_ERROR_CONFIG_NONE:
632 			(void) fprintf(stderr, "%s: %s\n", cmdName,
633 			    gettext("STMF service is not initialized"));
634 			ret++;
635 			break;
636 		case STMF_ERROR_SERVICE_DATA_VERSION:
637 			(void) fprintf(stderr, "%s: %s\n", cmdName,
638 			    gettext("STMF service version incorrect"));
639 			ret++;
640 			break;
641 		case STMF_ERROR_INVALID_HG:
642 			(void) fprintf(stderr, "%s: %s\n", cmdName,
643 			    gettext("invalid host group"));
644 			ret++;
645 			break;
646 		case STMF_ERROR_INVALID_TG:
647 			(void) fprintf(stderr, "%s: %s\n", cmdName,
648 			    gettext("invalid target group"));
649 			ret++;
650 			break;
651 		default:
652 			(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
653 			    operands[0], gettext("unknown error"));
654 			ret++;
655 			break;
656 	}
657 
658 	return (ret);
659 }
660 
661 /*
662  * createHostGroupFunc
663  *
664  * Create a host group
665  *
666  */
667 /*ARGSUSED*/
668 static int
669 createHostGroupFunc(int operandLen, char *operands[],
670     cmdOptions_t *options, void *args)
671 {
672 	int ret = 0;
673 	int stmfRet;
674 	wchar_t groupNamePrint[sizeof (stmfGroupName)] = {0};
675 	stmfGroupName groupName = {0};
676 
677 	(void) strlcpy(groupName, operands[0], sizeof (groupName));
678 	(void) mbstowcs(groupNamePrint, (char *)groupName,
679 	    sizeof (stmfGroupName) - 1);
680 	/* call create group */
681 	stmfRet = stmfCreateHostGroup(&groupName);
682 	switch (stmfRet) {
683 		case STMF_STATUS_SUCCESS:
684 			break;
685 		case STMF_ERROR_EXISTS:
686 			(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
687 			    operands[0], gettext("already exists"));
688 			ret++;
689 			break;
690 		case STMF_ERROR_BUSY:
691 			(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
692 			    operands[0], gettext("resource busy"));
693 			ret++;
694 			break;
695 		case STMF_ERROR_SERVICE_NOT_FOUND:
696 			(void) fprintf(stderr, "%s: %s\n", cmdName,
697 			    gettext("STMF service not found"));
698 			ret++;
699 			break;
700 		case STMF_ERROR_PERM:
701 			(void) fprintf(stderr, "%s: %s\n", cmdName,
702 			    gettext("permission denied"));
703 			ret++;
704 			break;
705 		case STMF_ERROR_SERVICE_DATA_VERSION:
706 			(void) fprintf(stderr, "%s: %s\n", cmdName,
707 			    gettext("STMF service version incorrect"));
708 			ret++;
709 			break;
710 		default:
711 			(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
712 			    operands[0], gettext("unknown error"));
713 			ret++;
714 			break;
715 	}
716 
717 	return (ret);
718 }
719 
720 /*
721  * createTargetGroupFunc
722  *
723  * Create a target group
724  *
725  */
726 /*ARGSUSED*/
727 static int
728 createTargetGroupFunc(int operandLen, char *operands[], cmdOptions_t *options,
729     void *args)
730 {
731 	int ret = 0;
732 	int stmfRet;
733 	wchar_t groupNamePrint[sizeof (stmfGroupName)] = {0};
734 	stmfGroupName groupName = {0};
735 
736 	(void) strlcpy(groupName, operands[0], sizeof (groupName));
737 	(void) mbstowcs(groupNamePrint, (char *)groupName,
738 	    sizeof (stmfGroupName) - 1);
739 	/* call create group */
740 	stmfRet = stmfCreateTargetGroup(&groupName);
741 	switch (stmfRet) {
742 		case STMF_STATUS_SUCCESS:
743 			break;
744 		case STMF_ERROR_EXISTS:
745 			(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
746 			    groupNamePrint, gettext("already exists"));
747 			ret++;
748 			break;
749 		case STMF_ERROR_BUSY:
750 			(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
751 			    groupNamePrint, gettext("resource busy"));
752 			ret++;
753 			break;
754 		case STMF_ERROR_PERM:
755 			(void) fprintf(stderr, "%s: %s\n", cmdName,
756 			    gettext("permission denied"));
757 			ret++;
758 			break;
759 		case STMF_ERROR_SERVICE_NOT_FOUND:
760 			(void) fprintf(stderr, "%s: %s\n", cmdName,
761 			    gettext("STMF service not found"));
762 			ret++;
763 			break;
764 		case STMF_ERROR_SERVICE_DATA_VERSION:
765 			(void) fprintf(stderr, "%s: %s\n", cmdName,
766 			    gettext("STMF service version incorrect"));
767 			ret++;
768 			break;
769 		default:
770 			(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
771 			    groupNamePrint, gettext("unknown error"));
772 			ret++;
773 			break;
774 	}
775 
776 	return (ret);
777 }
778 
779 /*
780  * deleteHostGroupFunc
781  *
782  * Delete a host group
783  *
784  */
785 /*ARGSUSED*/
786 static int
787 deleteHostGroupFunc(int operandLen, char *operands[],
788     cmdOptions_t *options, void *args)
789 {
790 	int ret = 0;
791 	int stmfRet;
792 	wchar_t groupNamePrint[sizeof (stmfGroupName)] = {0};
793 	stmfGroupName groupName = {0};
794 
795 	(void) strlcpy(groupName, operands[0], sizeof (groupName));
796 	(void) mbstowcs(groupNamePrint, (char *)groupName,
797 	    sizeof (stmfGroupName) - 1);
798 	/* call delete group */
799 	stmfRet = stmfDeleteHostGroup(&groupName);
800 	switch (stmfRet) {
801 		case STMF_STATUS_SUCCESS:
802 			break;
803 		case STMF_ERROR_NOT_FOUND:
804 			(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
805 			    groupNamePrint, gettext("not found"));
806 			ret++;
807 			break;
808 		case STMF_ERROR_BUSY:
809 			(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
810 			    groupNamePrint, gettext("resource busy"));
811 			ret++;
812 			break;
813 		case STMF_ERROR_SERVICE_NOT_FOUND:
814 			(void) fprintf(stderr, "%s: %s\n", cmdName,
815 			    gettext("STMF service not found"));
816 			ret++;
817 			break;
818 		case STMF_ERROR_PERM:
819 			(void) fprintf(stderr, "%s: %s\n", cmdName,
820 			    gettext("permission denied"));
821 			ret++;
822 			break;
823 		case STMF_ERROR_GROUP_IN_USE:
824 			(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
825 			    groupNamePrint,
826 			    gettext("group is in use by existing view entry"));
827 			ret++;
828 			break;
829 		case STMF_ERROR_SERVICE_DATA_VERSION:
830 			(void) fprintf(stderr, "%s: %s\n", cmdName,
831 			    gettext("STMF service version incorrect"));
832 			ret++;
833 			break;
834 		default:
835 			(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
836 			    groupNamePrint, gettext("unknown error"));
837 			ret++;
838 			break;
839 	}
840 
841 	return (ret);
842 }
843 
844 /*
845  * deleteTargetGroupFunc
846  *
847  * Delete a target group
848  *
849  */
850 /*ARGSUSED*/
851 static int
852 deleteTargetGroupFunc(int operandLen, char *operands[], cmdOptions_t *options,
853     void *args)
854 {
855 	int ret = 0;
856 	int stmfRet;
857 	wchar_t groupNamePrint[sizeof (stmfGroupName)] = {0};
858 	stmfGroupName groupName = {0};
859 
860 	(void) strlcpy(groupName, operands[0], sizeof (groupName));
861 	(void) mbstowcs(groupNamePrint, (char *)groupName,
862 	    sizeof (stmfGroupName) - 1);
863 	/* call delete group */
864 	stmfRet = stmfDeleteTargetGroup(&groupName);
865 	switch (stmfRet) {
866 		case STMF_STATUS_SUCCESS:
867 			break;
868 		case STMF_ERROR_NOT_FOUND:
869 			(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
870 			    groupNamePrint, gettext("not found"));
871 			ret++;
872 			break;
873 		case STMF_ERROR_BUSY:
874 			(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
875 			    groupNamePrint, gettext("resource busy"));
876 			ret++;
877 			break;
878 		case STMF_ERROR_SERVICE_NOT_FOUND:
879 			(void) fprintf(stderr, "%s: %s\n", cmdName,
880 			    gettext("STMF service not found"));
881 			ret++;
882 			break;
883 		case STMF_ERROR_PERM:
884 			(void) fprintf(stderr, "%s: %s\n", cmdName,
885 			    gettext("permission denied"));
886 			ret++;
887 			break;
888 		case STMF_ERROR_GROUP_IN_USE:
889 			(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
890 			    groupNamePrint,
891 			    gettext("group is in use by existing view entry"));
892 			ret++;
893 			break;
894 		case STMF_ERROR_SERVICE_DATA_VERSION:
895 			(void) fprintf(stderr, "%s: %s\n", cmdName,
896 			    gettext("STMF service version incorrect"));
897 			ret++;
898 			break;
899 		default:
900 			(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
901 			    groupNamePrint, gettext("unknown error"));
902 			ret++;
903 			break;
904 	}
905 
906 	return (ret);
907 }
908 
909 /*
910  * listHostGroupFunc
911  *
912  * Lists the specified host groups or all if none are specified
913  *
914  */
915 /*ARGSUSED*/
916 static int
917 listHostGroupFunc(int operandLen, char *operands[], cmdOptions_t *options,
918     void *args)
919 {
920 	int ret = 0;
921 	int stmfRet;
922 	int i, j, outerLoop;
923 	boolean_t verbose = B_FALSE;
924 	boolean_t found = B_TRUE;
925 	boolean_t operandEntered;
926 	stmfGroupList *groupList;
927 	stmfGroupProperties *groupProps;
928 	wchar_t operandName[sizeof (stmfGroupName)];
929 	wchar_t groupNamePrint[sizeof (stmfGroupName)];
930 
931 	for (; options->optval; options++) {
932 		switch (options->optval) {
933 			case 'v':
934 				verbose = B_TRUE;
935 				break;
936 			default:
937 				(void) fprintf(stderr, "%s: %c: %s\n",
938 				    cmdName, options->optval,
939 				    gettext("unknown option"));
940 				return (1);
941 		}
942 	}
943 
944 	if (operandLen > 0) {
945 		outerLoop = operandLen;
946 		operandEntered = B_TRUE;
947 	} else {
948 		outerLoop = 1;
949 		operandEntered = B_FALSE;
950 	}
951 
952 	stmfRet = stmfGetHostGroupList(&groupList);
953 	if (stmfRet != STMF_STATUS_SUCCESS) {
954 		switch (stmfRet) {
955 			case STMF_ERROR_BUSY:
956 				(void) fprintf(stderr, "%s: %s\n", cmdName,
957 				    gettext("resource busy"));
958 				break;
959 			case STMF_ERROR_SERVICE_NOT_FOUND:
960 				(void) fprintf(stderr, "%s: %s\n", cmdName,
961 				    gettext("STMF service not found"));
962 				break;
963 			case STMF_ERROR_PERM:
964 				(void) fprintf(stderr, "%s: %s\n", cmdName,
965 				    gettext("permission denied"));
966 				break;
967 			case STMF_ERROR_SERVICE_DATA_VERSION:
968 				(void) fprintf(stderr, "%s: %s\n", cmdName,
969 				    gettext("STMF service version incorrect"));
970 				break;
971 			default:
972 				(void) fprintf(stderr, "%s: %s\n", cmdName,
973 				    gettext("unknown error"));
974 				break;
975 		}
976 		return (1);
977 	}
978 
979 	for (i = 0; i < outerLoop; i++) {
980 		for (found = B_FALSE, j = 0; j < groupList->cnt; j++) {
981 			(void) mbstowcs(groupNamePrint,
982 			    (char *)groupList->name[j],
983 			    sizeof (stmfGroupName) - 1);
984 			groupNamePrint[sizeof (stmfGroupName) - 1] = 0;
985 			if (operandEntered) {
986 				(void) mbstowcs(operandName, operands[i],
987 				    sizeof (stmfGroupName) - 1);
988 				operandName[sizeof (stmfGroupName) - 1] = 0;
989 				if (wcscmp(operandName, groupNamePrint)
990 				    == 0) {
991 					found = B_TRUE;
992 				}
993 			}
994 			if ((found && operandEntered) || !operandEntered) {
995 				(void) printf("Host Group: %ws\n",
996 				    groupNamePrint);
997 				if (verbose) {
998 					stmfRet = stmfGetHostGroupMembers(
999 					    &(groupList->name[j]), &groupProps);
1000 					if (stmfRet != STMF_STATUS_SUCCESS) {
1001 						return (1);
1002 					}
1003 					printGroupProps(groupProps);
1004 				}
1005 				if (found && operandEntered) {
1006 					break;
1007 				}
1008 			}
1009 
1010 		}
1011 		if (operandEntered && !found) {
1012 			(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
1013 			    operands[i], gettext("not found"));
1014 			ret = 1;
1015 		}
1016 	}
1017 	return (ret);
1018 }
1019 
1020 /*
1021  * printGroupProps
1022  *
1023  * Prints group members for target or host groups
1024  *
1025  */
1026 static void
1027 printGroupProps(stmfGroupProperties *groupProps)
1028 {
1029 	int i;
1030 	wchar_t memberIdent[sizeof (groupProps->name[0].ident) + 1] = {0};
1031 
1032 
1033 	for (i = 0; i < groupProps->cnt; i++) {
1034 		(void) mbstowcs(memberIdent, (char *)groupProps->name[i].ident,
1035 		    sizeof (groupProps->name[0].ident));
1036 		(void) printf("\tMember: %ws\n", memberIdent);
1037 	}
1038 }
1039 
1040 /*
1041  * listTargetGroupFunc
1042  *
1043  * Lists the specified target groups or all if none are specified
1044  *
1045  */
1046 /*ARGSUSED*/
1047 static int
1048 listTargetGroupFunc(int operandLen, char *operands[], cmdOptions_t *options,
1049     void *args)
1050 {
1051 	int ret = 0;
1052 	int stmfRet;
1053 	int i, j, outerLoop;
1054 	boolean_t verbose = B_FALSE;
1055 	boolean_t found = B_TRUE;
1056 	boolean_t operandEntered;
1057 	stmfGroupList *groupList;
1058 	stmfGroupProperties *groupProps;
1059 	wchar_t operandName[sizeof (stmfGroupName)];
1060 	wchar_t groupNamePrint[sizeof (stmfGroupName)];
1061 
1062 	for (; options->optval; options++) {
1063 		switch (options->optval) {
1064 			case 'v':
1065 				verbose = B_TRUE;
1066 				break;
1067 			default:
1068 				(void) fprintf(stderr, "%s: %c: %s\n",
1069 				    cmdName, options->optval,
1070 				    gettext("unknown option"));
1071 				return (1);
1072 		}
1073 	}
1074 
1075 	if (operandLen > 0) {
1076 		outerLoop = operandLen;
1077 		operandEntered = B_TRUE;
1078 	} else {
1079 		outerLoop = 1;
1080 		operandEntered = B_FALSE;
1081 	}
1082 
1083 	stmfRet = stmfGetTargetGroupList(&groupList);
1084 	if (stmfRet != STMF_STATUS_SUCCESS) {
1085 		switch (stmfRet) {
1086 			case STMF_ERROR_BUSY:
1087 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1088 				    gettext("resource busy"));
1089 				break;
1090 			case STMF_ERROR_SERVICE_NOT_FOUND:
1091 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1092 				    gettext("STMF service not found"));
1093 				break;
1094 			case STMF_ERROR_SERVICE_DATA_VERSION:
1095 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1096 				    gettext("STMF service version incorrect"));
1097 				break;
1098 			case STMF_ERROR_PERM:
1099 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1100 				    gettext("permission denied"));
1101 				break;
1102 			default:
1103 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1104 				    gettext("unknown error"));
1105 				break;
1106 		}
1107 		return (1);
1108 	}
1109 
1110 	for (i = 0; i < outerLoop; i++) {
1111 		for (found = B_FALSE, j = 0; j < groupList->cnt; j++) {
1112 			(void) mbstowcs(groupNamePrint,
1113 			    (char *)groupList->name[j],
1114 			    sizeof (stmfGroupName) - 1);
1115 			groupNamePrint[sizeof (stmfGroupName) - 1] = 0;
1116 			if (operandEntered) {
1117 				(void) mbstowcs(operandName, operands[i],
1118 				    sizeof (stmfGroupName) - 1);
1119 				operandName[sizeof (stmfGroupName) - 1] = 0;
1120 				if (wcscmp(operandName, groupNamePrint)
1121 				    == 0) {
1122 					found = B_TRUE;
1123 				}
1124 			}
1125 			if ((found && operandEntered) || !operandEntered) {
1126 				(void) printf("Target Group: %ws\n",
1127 				    groupNamePrint);
1128 				if (verbose) {
1129 					stmfRet = stmfGetTargetGroupMembers(
1130 					    &(groupList->name[j]), &groupProps);
1131 					if (stmfRet != STMF_STATUS_SUCCESS) {
1132 						return (1);
1133 					}
1134 					printGroupProps(groupProps);
1135 				}
1136 				if (found && operandEntered) {
1137 					break;
1138 				}
1139 			}
1140 
1141 		}
1142 		if (operandEntered && !found) {
1143 			(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
1144 			    operands[i], gettext("not found"));
1145 			ret = 1;
1146 		}
1147 	}
1148 	return (ret);
1149 }
1150 
1151 /*
1152  * listLuFunc
1153  *
1154  * List the logical units and optionally the properties
1155  *
1156  */
1157 /*ARGSUSED*/
1158 static int
1159 listLuFunc(int operandLen, char *operands[], cmdOptions_t *options, void *args)
1160 {
1161 	cmdOptions_t *optionList = options;
1162 	boolean_t operandEntered;
1163 	int i, j;
1164 	int ret = 0;
1165 	int stmfRet;
1166 	int outerLoop;
1167 	unsigned int inGuid[sizeof (stmfGuid)];
1168 	stmfGuid cmpGuid;
1169 	boolean_t verbose = B_FALSE;
1170 	boolean_t found;
1171 	char sGuid[GUID_INPUT + 1];
1172 	stmfGuidList *luList;
1173 	stmfLogicalUnitProperties luProps;
1174 	boolean_t invalidInput = B_FALSE;
1175 	stmfViewEntryList *viewEntryList;
1176 
1177 	for (; optionList->optval; optionList++) {
1178 		switch (optionList->optval) {
1179 			case 'v':
1180 				verbose = B_TRUE;
1181 				break;
1182 		}
1183 	}
1184 
1185 	if ((stmfRet = stmfGetLogicalUnitList(&luList))
1186 	    != STMF_STATUS_SUCCESS) {
1187 		switch (stmfRet) {
1188 			case STMF_ERROR_SERVICE_NOT_FOUND:
1189 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1190 				    gettext("STMF service not found"));
1191 				break;
1192 			case STMF_ERROR_BUSY:
1193 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1194 				    gettext("resource busy"));
1195 				break;
1196 			case STMF_ERROR_PERM:
1197 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1198 				    gettext("permission denied"));
1199 				break;
1200 			case STMF_ERROR_SERVICE_DATA_VERSION:
1201 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1202 				    gettext("STMF service version incorrect"));
1203 				break;
1204 			default:
1205 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1206 				    gettext("list failed"));
1207 				break;
1208 		}
1209 		return (1);
1210 	}
1211 
1212 	if (operandLen > 0) {
1213 		operandEntered = B_TRUE;
1214 		outerLoop = operandLen;
1215 	} else {
1216 		operandEntered = B_FALSE;
1217 		outerLoop = 1;
1218 	}
1219 
1220 
1221 	for (invalidInput = B_FALSE, i = 0; i < outerLoop; i++) {
1222 		if (operandEntered) {
1223 			if (strlen(operands[i]) != GUID_INPUT) {
1224 				invalidInput = B_TRUE;
1225 			} else {
1226 				for (j = 0; j < GUID_INPUT; j++) {
1227 					if (!isxdigit(operands[i][j])) {
1228 						invalidInput = B_TRUE;
1229 						break;
1230 					}
1231 				}
1232 			}
1233 			if (invalidInput) {
1234 				(void) fprintf(stderr, "%s: %s: %s%d%s\n",
1235 				    cmdName, operands[i], gettext("must be "),
1236 				    GUID_INPUT,
1237 				    gettext(" hexadecimal digits long"));
1238 				continue;
1239 			}
1240 
1241 			for (j = 0; j < GUID_INPUT; j++) {
1242 				sGuid[j] = tolower(operands[i][j]);
1243 			}
1244 			sGuid[j] = 0;
1245 
1246 			(void) sscanf(sGuid,
1247 			    "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
1248 			    &inGuid[0], &inGuid[1], &inGuid[2], &inGuid[3],
1249 			    &inGuid[4], &inGuid[5], &inGuid[6], &inGuid[7],
1250 			    &inGuid[8], &inGuid[9], &inGuid[10], &inGuid[11],
1251 			    &inGuid[12], &inGuid[13], &inGuid[14], &inGuid[15]);
1252 
1253 			for (j = 0; j < sizeof (stmfGuid); j++) {
1254 				cmpGuid.guid[j] = inGuid[j];
1255 			}
1256 		}
1257 
1258 		for (found = B_FALSE, j = 0; j < luList->cnt; j++) {
1259 			if (operandEntered) {
1260 				if (bcmp(luList->guid[j].guid, cmpGuid.guid,
1261 				    sizeof (stmfGuid)) == 0) {
1262 					found = B_TRUE;
1263 				}
1264 			}
1265 			if ((found && operandEntered) || !operandEntered) {
1266 				(void) printf("LU Name: ");
1267 				printGuid(&luList->guid[j], stdout);
1268 				(void) printf("\n");
1269 
1270 				if (verbose) {
1271 					stmfRet = stmfGetLogicalUnitProperties(
1272 					    &(luList->guid[j]), &luProps);
1273 					if (stmfRet == STMF_STATUS_SUCCESS) {
1274 						printLuProps(&luProps);
1275 					} else {
1276 						(void) fprintf(stderr, "%s:",
1277 						    cmdName);
1278 						printGuid(&luList->guid[j],
1279 						    stderr);
1280 						(void) fprintf(stderr, "%s\n",
1281 						    gettext(" get properties "
1282 						    "failed"));
1283 					}
1284 					stmfRet = stmfGetViewEntryList(
1285 					    &(luList->guid[j]),
1286 					    &viewEntryList);
1287 					(void) printf(PROPS_FORMAT,
1288 					    "View Entry Count");
1289 					if (stmfRet == STMF_STATUS_SUCCESS) {
1290 						(void) printf("%d",
1291 						    viewEntryList->cnt);
1292 					} else if (stmfRet ==
1293 					    STMF_ERROR_NOT_FOUND) {
1294 						(void) printf("0");
1295 					} else {
1296 						(void) printf("unknown");
1297 					}
1298 					(void) printf("\n");
1299 				}
1300 				if (found && operandEntered) {
1301 					break;
1302 				}
1303 			}
1304 
1305 		}
1306 		if (operandEntered && !found) {
1307 			(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
1308 			    operands[i], gettext("not found"));
1309 			ret = 1;
1310 		}
1311 	}
1312 
1313 	return (ret);
1314 }
1315 
1316 static void
1317 printGuid(stmfGuid *guid, FILE *stream)
1318 {
1319 	int i;
1320 	for (i = 0; i < 16; i++) {
1321 		(void) fprintf(stream, "%02X", guid->guid[i]);
1322 	}
1323 }
1324 
1325 
1326 /*
1327  * printLuProps
1328  *
1329  * Prints the properties for a logical unit
1330  *
1331  */
1332 static void
1333 printLuProps(stmfLogicalUnitProperties *luProps)
1334 {
1335 	(void) printf(PROPS_FORMAT, "Operational Status");
1336 	switch (luProps->status) {
1337 		case STMF_LOGICAL_UNIT_ONLINE:
1338 			(void) printf("Online");
1339 			break;
1340 		case STMF_LOGICAL_UNIT_OFFLINE:
1341 			(void) printf("Offline");
1342 			break;
1343 		case STMF_LOGICAL_UNIT_ONLINING:
1344 			(void) printf("Onlining");
1345 			break;
1346 		case STMF_LOGICAL_UNIT_OFFLINING:
1347 			(void) printf("Offlining");
1348 			break;
1349 		case STMF_LOGICAL_UNIT_UNREGISTERED:
1350 			(void) printf("unregistered");
1351 			(void) strncpy(luProps->providerName, "unregistered",
1352 			    sizeof (luProps->providerName));
1353 			break;
1354 		default:
1355 			(void) printf("unknown");
1356 			break;
1357 	}
1358 	(void) printf("\n");
1359 	(void) printf(PROPS_FORMAT, "Provider Name");
1360 	if (luProps->providerName[0] != 0) {
1361 		(void) printf("%s", luProps->providerName);
1362 	} else {
1363 		(void) printf("unknown");
1364 	}
1365 	(void) printf("\n");
1366 	(void) printf(PROPS_FORMAT, "Alias");
1367 	if (luProps->alias[0] != 0) {
1368 		(void) printf("%s", luProps->alias);
1369 	} else {
1370 		(void) printf("-");
1371 	}
1372 	(void) printf("\n");
1373 }
1374 
1375 /*
1376  * printTargetProps
1377  *
1378  * Prints the properties for a target
1379  *
1380  */
1381 static void
1382 printTargetProps(stmfTargetProperties *targetProps)
1383 {
1384 	(void) printf(PROPS_FORMAT, "Operational Status");
1385 	switch (targetProps->status) {
1386 		case STMF_TARGET_PORT_ONLINE:
1387 			(void) printf("Online");
1388 			break;
1389 		case STMF_TARGET_PORT_OFFLINE:
1390 			(void) printf("Offline");
1391 			break;
1392 		case STMF_TARGET_PORT_ONLINING:
1393 			(void) printf("Onlining");
1394 			break;
1395 		case STMF_TARGET_PORT_OFFLINING:
1396 			(void) printf("Offlining");
1397 			break;
1398 		default:
1399 			(void) printf("unknown");
1400 			break;
1401 	}
1402 	(void) printf("\n");
1403 	(void) printf(PROPS_FORMAT, "Provider Name");
1404 	if (targetProps->providerName[0] != 0) {
1405 		(void) printf("%s", targetProps->providerName);
1406 	}
1407 	(void) printf("\n");
1408 	(void) printf(PROPS_FORMAT, "Alias");
1409 	if (targetProps->alias[0] != 0) {
1410 		(void) printf("%s", targetProps->alias);
1411 	} else {
1412 		(void) printf("-");
1413 	}
1414 	(void) printf("\n");
1415 }
1416 
1417 /*
1418  * printSessionProps
1419  *
1420  * Prints the session data
1421  *
1422  */
1423 static void
1424 printSessionProps(stmfSessionList *sessionList)
1425 {
1426 	int i;
1427 	char *cTime;
1428 	wchar_t initiator[STMF_IDENT_LENGTH + 1];
1429 
1430 	(void) printf(PROPS_FORMAT, "Sessions");
1431 	(void) printf("%d\n", sessionList->cnt);
1432 	for (i = 0; i < sessionList->cnt; i++) {
1433 		(void) mbstowcs(initiator,
1434 		    (char *)sessionList->session[i].initiator.ident,
1435 		    STMF_IDENT_LENGTH);
1436 		initiator[STMF_IDENT_LENGTH] = 0;
1437 		(void) printf(LVL3_FORMAT, "Initiator: ");
1438 		(void) printf("%ws\n", initiator);
1439 		(void) printf(LVL4_FORMAT, "Alias: ");
1440 		if (sessionList->session[i].alias[0] != 0) {
1441 			(void) printf("%s", sessionList->session[i].alias);
1442 		} else {
1443 			(void) printf("-");
1444 		}
1445 		(void) printf("\n");
1446 		(void) printf(LVL4_FORMAT, "Logged in since: ");
1447 		cTime = ctime(&(sessionList->session[i].creationTime));
1448 		if (cTime != NULL) {
1449 			(void) printf("%s", cTime);
1450 		} else {
1451 			(void) printf("unknown\n");
1452 		}
1453 	}
1454 }
1455 
1456 /*
1457  * listStateFunc
1458  *
1459  * List the operational and config state of the stmf service
1460  *
1461  */
1462 /*ARGSUSED*/
1463 static int
1464 listStateFunc(int operandLen, char *operands[], cmdOptions_t *options,
1465     void *args)
1466 {
1467 	int ret;
1468 	stmfState state;
1469 
1470 	if ((ret = stmfGetState(&state)) != STMF_STATUS_SUCCESS) {
1471 		switch (ret) {
1472 			case STMF_ERROR_PERM:
1473 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1474 				    gettext("permission denied"));
1475 				ret++;
1476 				break;
1477 			case STMF_ERROR_SERVICE_NOT_FOUND:
1478 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1479 				    gettext("STMF service not found"));
1480 				ret++;
1481 				break;
1482 			case STMF_ERROR_BUSY:
1483 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1484 				    gettext("resource busy"));
1485 				break;
1486 			case STMF_ERROR_SERVICE_DATA_VERSION:
1487 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1488 				    gettext("STMF service version incorrect"));
1489 				ret++;
1490 				break;
1491 			default:
1492 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1493 				    gettext("unknown error"));
1494 				ret++;
1495 				break;
1496 		}
1497 		return (1);
1498 	}
1499 
1500 	(void) printf("%-18s: ", "Operational Status");
1501 	switch (state.operationalState) {
1502 		case STMF_SERVICE_STATE_ONLINE:
1503 			(void) printf("online");
1504 			break;
1505 		case STMF_SERVICE_STATE_OFFLINE:
1506 			(void) printf("offline");
1507 			break;
1508 		case STMF_SERVICE_STATE_ONLINING:
1509 			(void) printf("onlining");
1510 			break;
1511 		case STMF_SERVICE_STATE_OFFLINING:
1512 			(void) printf("offlining");
1513 			break;
1514 		default:
1515 			(void) printf("unknown");
1516 			break;
1517 	}
1518 	(void) printf("\n");
1519 	(void) printf("%-18s: ", "Config Status");
1520 	switch (state.configState) {
1521 		case STMF_CONFIG_STATE_NONE:
1522 			(void) printf("uninitialized");
1523 			break;
1524 		case STMF_CONFIG_STATE_INIT:
1525 			(void) printf("initializing");
1526 			break;
1527 		case STMF_CONFIG_STATE_INIT_DONE:
1528 			(void) printf("initialized");
1529 			break;
1530 		default:
1531 			(void) printf("unknown");
1532 			break;
1533 	}
1534 	(void) printf("\n");
1535 	return (0);
1536 }
1537 
1538 /*
1539  * listTargetFunc
1540  *
1541  * list the targets and optionally their properties
1542  *
1543  */
1544 /*ARGSUSED*/
1545 static int
1546 listTargetFunc(int operandLen, char *operands[], cmdOptions_t *options,
1547     void *args)
1548 {
1549 	cmdOptions_t *optionList = options;
1550 	int ret = 0;
1551 	int stmfRet;
1552 	int i, j;
1553 	int outerLoop;
1554 	stmfSessionList *sessionList;
1555 	stmfDevid devid;
1556 	boolean_t operandEntered, found, verbose = B_FALSE;
1557 	stmfDevidList *targetList;
1558 	wchar_t targetIdent[STMF_IDENT_LENGTH + 1];
1559 	stmfTargetProperties targetProps;
1560 
1561 	if ((stmfRet = stmfGetTargetList(&targetList)) != STMF_STATUS_SUCCESS) {
1562 		switch (stmfRet) {
1563 			case STMF_ERROR_NOT_FOUND:
1564 				ret = 0;
1565 				break;
1566 			case STMF_ERROR_SERVICE_OFFLINE:
1567 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1568 				    gettext("STMF service offline"));
1569 				break;
1570 			case STMF_ERROR_BUSY:
1571 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1572 				    gettext("resource busy"));
1573 				break;
1574 			case STMF_ERROR_SERVICE_DATA_VERSION:
1575 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1576 				    gettext("STMF service version incorrect"));
1577 				break;
1578 			case STMF_ERROR_PERM:
1579 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1580 				    gettext("permission denied"));
1581 				break;
1582 			default:
1583 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1584 				    gettext("unknown error"));
1585 				break;
1586 		}
1587 		return (1);
1588 	}
1589 
1590 	for (; optionList->optval; optionList++) {
1591 		switch (optionList->optval) {
1592 			case 'v':
1593 				verbose = B_TRUE;
1594 				break;
1595 		}
1596 	}
1597 
1598 	if (operandLen > 0) {
1599 		outerLoop = operandLen;
1600 		operandEntered = B_TRUE;
1601 	} else {
1602 		outerLoop = 1;
1603 		operandEntered = B_FALSE;
1604 	}
1605 
1606 	for (i = 0; i < outerLoop; i++) {
1607 		if (operandEntered) {
1608 			bzero(&devid, sizeof (devid));
1609 			(void) parseDevid(operands[i], &devid);
1610 		}
1611 		for (found = B_FALSE, j = 0; j < targetList->cnt; j++) {
1612 			if (operandEntered) {
1613 				if (bcmp(&devid, &(targetList->devid[j]),
1614 				    sizeof (devid)) == 0) {
1615 					found = B_TRUE;
1616 				}
1617 			}
1618 			if ((found && operandEntered) || !operandEntered) {
1619 				(void) mbstowcs(targetIdent,
1620 				    (char *)targetList->devid[j].ident,
1621 				    STMF_IDENT_LENGTH);
1622 				targetIdent[STMF_IDENT_LENGTH] = 0;
1623 				(void) printf("Target: %ws\n", targetIdent);
1624 				if (verbose) {
1625 					stmfRet = stmfGetTargetProperties(
1626 					    &(targetList->devid[j]),
1627 					    &targetProps);
1628 					if (stmfRet == STMF_STATUS_SUCCESS) {
1629 						printTargetProps(&targetProps);
1630 					} else {
1631 						(void) fprintf(stderr, "%s:",
1632 						    cmdName);
1633 						(void) fprintf(stderr, "%s\n",
1634 						    gettext(" get properties"
1635 						    " failed"));
1636 					}
1637 					stmfRet = stmfGetSessionList(
1638 					    &(targetList->devid[j]),
1639 					    &sessionList);
1640 					if (stmfRet == STMF_STATUS_SUCCESS) {
1641 						printSessionProps(sessionList);
1642 					} else {
1643 						(void) fprintf(stderr, "%s:",
1644 						    cmdName);
1645 						(void) fprintf(stderr, "%s\n",
1646 						    gettext(" get session info"
1647 						    " failed"));
1648 					}
1649 				}
1650 				if (found && operandEntered) {
1651 					break;
1652 				}
1653 			}
1654 
1655 		}
1656 		if (operandEntered && !found) {
1657 			(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
1658 			    operands[i], "not found");
1659 			ret = 1;
1660 		}
1661 	}
1662 	return (ret);
1663 }
1664 
1665 /*
1666  * listViewFunc
1667  *
1668  * list the view entries for the specified logical unit
1669  *
1670  */
1671 /*ARGSUSED*/
1672 static int
1673 listViewFunc(int operandLen, char *operands[], cmdOptions_t *options,
1674     void *args)
1675 {
1676 	stmfViewEntryList *viewEntryList;
1677 	stmfGuid inGuid;
1678 	unsigned int guid[sizeof (stmfGuid)];
1679 	int ret = 0;
1680 	int stmfRet;
1681 	int i, j, outerLoop;
1682 	boolean_t found = B_TRUE;
1683 	boolean_t operandEntered;
1684 	uint16_t outputLuNbr;
1685 	wchar_t groupName[sizeof (stmfGroupName)];
1686 	char sGuid[GUID_INPUT + 1];
1687 
1688 
1689 	for (; options->optval; options++) {
1690 		switch (options->optval) {
1691 			case 'l':
1692 				if (strlen(options->optarg) != GUID_INPUT) {
1693 					(void) fprintf(stderr,
1694 					    "%s: %s: %s%d%s\n",
1695 					    cmdName, options->optarg,
1696 					    gettext("must be "), GUID_INPUT,
1697 					    gettext(" hexadecimal digits"
1698 					    " long"));
1699 					return (1);
1700 				}
1701 				bcopy(options->optarg, sGuid, GUID_INPUT);
1702 				break;
1703 			default:
1704 				(void) fprintf(stderr, "%s: %c: %s\n",
1705 				    cmdName, options->optval,
1706 				    gettext("unknown option"));
1707 				return (1);
1708 		}
1709 	}
1710 
1711 	if (operandLen > 0) {
1712 		outerLoop = operandLen;
1713 		operandEntered = B_TRUE;
1714 	} else {
1715 		outerLoop = 1;
1716 		operandEntered = B_FALSE;
1717 	}
1718 
1719 	for (i = 0; i < 32; i++)
1720 		sGuid[i] = tolower(sGuid[i]);
1721 	sGuid[i] = 0;
1722 
1723 	(void) sscanf(sGuid, "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
1724 	    &guid[0], &guid[1], &guid[2], &guid[3], &guid[4], &guid[5],
1725 	    &guid[6], &guid[7], &guid[8], &guid[9], &guid[10], &guid[11],
1726 	    &guid[12], &guid[13], &guid[14], &guid[15]);
1727 
1728 	for (i = 0; i < sizeof (stmfGuid); i++) {
1729 		inGuid.guid[i] = guid[i];
1730 	}
1731 
1732 	if ((stmfRet = stmfGetViewEntryList(&inGuid, &viewEntryList))
1733 	    != STMF_STATUS_SUCCESS) {
1734 
1735 		switch (stmfRet) {
1736 			case STMF_ERROR_BUSY:
1737 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
1738 				    sGuid, gettext("resource busy"));
1739 				break;
1740 			case STMF_ERROR_NOT_FOUND:
1741 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
1742 				    sGuid, gettext("no views found"));
1743 				break;
1744 			case STMF_ERROR_SERVICE_NOT_FOUND:
1745 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1746 				    gettext("STMF service not found"));
1747 				break;
1748 			case STMF_ERROR_SERVICE_DATA_VERSION:
1749 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1750 				    gettext("STMF service version incorrect"));
1751 				break;
1752 			case STMF_ERROR_PERM:
1753 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1754 				    gettext("permission denied"));
1755 				break;
1756 			default:
1757 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
1758 				    sGuid, gettext("unknown error"));
1759 				break;
1760 		}
1761 		return (1);
1762 	}
1763 
1764 	for (i = 0; i < outerLoop; i++) {
1765 		for (found = B_FALSE, j = 0; j < viewEntryList->cnt; j++) {
1766 			if (operandEntered) {
1767 				if (atoi(operands[i]) ==
1768 				    viewEntryList->ve[j].veIndex) {
1769 					found = B_TRUE;
1770 				}
1771 			}
1772 			if ((found && operandEntered) || !operandEntered) {
1773 				(void) printf("View Entry: %d\n",
1774 				    viewEntryList->ve[j].veIndex);
1775 				(void) printf(VIEW_FORMAT, "Host group");
1776 				if (viewEntryList->ve[j].allHosts) {
1777 					(void) printf("All\n");
1778 				} else {
1779 					(void) mbstowcs(groupName,
1780 					    viewEntryList->ve[j].hostGroup,
1781 					    sizeof (stmfGroupName) - 1);
1782 					groupName[sizeof (stmfGroupName) - 1]
1783 					    = 0;
1784 					(void) printf("%ws\n", groupName);
1785 				}
1786 				(void) printf(VIEW_FORMAT, "Target group");
1787 				if (viewEntryList->ve[j].allTargets) {
1788 					(void) printf("All\n");
1789 				} else {
1790 					(void) mbstowcs(groupName,
1791 					    viewEntryList->ve[j].targetGroup,
1792 					    sizeof (stmfGroupName) - 1);
1793 					groupName[sizeof (stmfGroupName) - 1]
1794 					    = 0;
1795 					(void) printf("%ws\n", groupName);
1796 				}
1797 				outputLuNbr = ((viewEntryList->ve[j].luNbr[0] &
1798 				    0x3F) << 8) | viewEntryList->ve[j].luNbr[1];
1799 				(void) printf(VIEW_FORMAT, "LUN");
1800 				(void) printf("%d\n", outputLuNbr);
1801 				if (found && operandEntered) {
1802 					break;
1803 				}
1804 			}
1805 		}
1806 		if (operandEntered && !found) {
1807 			(void) fprintf(stderr, "%s: %s, %s: %s\n", cmdName,
1808 			    sGuid, operands[i], gettext("not found"));
1809 			ret = 1;
1810 		}
1811 	}
1812 
1813 	return (ret);
1814 }
1815 
1816 
1817 /*
1818  * onlineOfflineLu
1819  *
1820  * Purpose: Online or offline a logical unit
1821  *
1822  * lu - logical unit to online or offline
1823  *
1824  * state - ONLINE_LU
1825  *         OFFLINE_LU
1826  */
1827 static int
1828 onlineOfflineLu(char *lu, int state)
1829 {
1830 	char sGuid[GUID_INPUT + 1];
1831 	stmfGuid inGuid;
1832 	unsigned int guid[sizeof (stmfGuid)];
1833 	int i;
1834 	int ret = 0;
1835 
1836 	if (strlen(lu) != GUID_INPUT) {
1837 		(void) fprintf(stderr, "%s: %s: %s %d %s\n", cmdName, lu,
1838 		    gettext("must be"), GUID_INPUT,
1839 		    gettext("hexadecimal digits long"));
1840 		return (1);
1841 	}
1842 
1843 	bcopy(lu, sGuid, GUID_INPUT);
1844 
1845 	for (i = 0; i < 32; i++)
1846 		sGuid[i] = tolower(sGuid[i]);
1847 	sGuid[i] = 0;
1848 
1849 	(void) sscanf(sGuid, "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
1850 	    &guid[0], &guid[1], &guid[2], &guid[3], &guid[4], &guid[5],
1851 	    &guid[6], &guid[7], &guid[8], &guid[9], &guid[10], &guid[11],
1852 	    &guid[12], &guid[13], &guid[14], &guid[15]);
1853 
1854 	for (i = 0; i < sizeof (stmfGuid); i++) {
1855 		inGuid.guid[i] = guid[i];
1856 	}
1857 
1858 	if (state == ONLINE_LU) {
1859 		ret = stmfOnlineLogicalUnit(&inGuid);
1860 	} else if (state == OFFLINE_LU) {
1861 		ret = stmfOfflineLogicalUnit(&inGuid);
1862 	}
1863 	if (ret != STMF_STATUS_SUCCESS) {
1864 		switch (ret) {
1865 			case STMF_ERROR_PERM:
1866 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1867 				    gettext("permission denied"));
1868 				break;
1869 			case STMF_ERROR_SERVICE_NOT_FOUND:
1870 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1871 				    gettext("STMF service not found"));
1872 				break;
1873 			case STMF_ERROR_NOT_FOUND:
1874 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
1875 				    lu, gettext("not found"));
1876 				break;
1877 			case STMF_ERROR_SERVICE_DATA_VERSION:
1878 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1879 				    gettext("STMF service version incorrect"));
1880 				break;
1881 			default:
1882 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1883 				    gettext("unknown error"));
1884 				break;
1885 		}
1886 	}
1887 	return (ret);
1888 }
1889 
1890 /*
1891  * onlineLuFunc
1892  *
1893  * Purpose: Online a logical unit
1894  *
1895  */
1896 /*ARGSUSED*/
1897 static int
1898 onlineLuFunc(int operandLen, char *operands[], cmdOptions_t *options,
1899     void *args)
1900 {
1901 	return (onlineOfflineLu(operands[0], ONLINE_LU));
1902 }
1903 
1904 /*
1905  * offlineLuFunc
1906  *
1907  * Purpose: Offline a logical unit
1908  *
1909  */
1910 /*ARGSUSED*/
1911 static int
1912 offlineLuFunc(int operandLen, char *operands[], cmdOptions_t *options,
1913     void *args)
1914 {
1915 	return (onlineOfflineLu(operands[0], OFFLINE_LU));
1916 }
1917 
1918 /*
1919  * onlineOfflineTarget
1920  *
1921  * Purpose: Online or offline a target
1922  *
1923  * target - target to online or offline
1924  *
1925  * state - ONLINE_TARGET
1926  *         OFFLINE_TARGET
1927  */
1928 static int
1929 onlineOfflineTarget(char *target, int state)
1930 {
1931 	int ret = 0;
1932 	stmfDevid devid;
1933 
1934 	if (parseDevid(target, &devid) != 0) {
1935 		(void) fprintf(stderr, "%s: %s: %s\n",
1936 		    cmdName, target, gettext("unrecognized device id"));
1937 		return (1);
1938 	}
1939 	if (state == ONLINE_TARGET) {
1940 		ret = stmfOnlineTarget(&devid);
1941 	} else if (state == OFFLINE_TARGET) {
1942 		ret = stmfOfflineTarget(&devid);
1943 	}
1944 	if (ret != STMF_STATUS_SUCCESS) {
1945 		switch (ret) {
1946 			case STMF_ERROR_PERM:
1947 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1948 				    gettext("permission denied"));
1949 				break;
1950 			case STMF_ERROR_SERVICE_NOT_FOUND:
1951 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1952 				    gettext("STMF service not found"));
1953 				break;
1954 			case STMF_ERROR_NOT_FOUND:
1955 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
1956 				    target, gettext("not found"));
1957 				break;
1958 			case STMF_ERROR_SERVICE_DATA_VERSION:
1959 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1960 				    gettext("STMF service version incorrect"));
1961 				break;
1962 			default:
1963 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1964 				    gettext("unknown error"));
1965 				break;
1966 		}
1967 	}
1968 	return (ret);
1969 }
1970 
1971 /*
1972  * onlineTargetFunc
1973  *
1974  * Purpose: Online a target
1975  *
1976  */
1977 /*ARGSUSED*/
1978 static int
1979 onlineTargetFunc(int operandLen, char *operands[], cmdOptions_t *options,
1980     void *args)
1981 {
1982 	return (onlineOfflineTarget(operands[0], ONLINE_TARGET));
1983 }
1984 
1985 /*
1986  * offlineTargetFunc
1987  *
1988  * Purpose: Offline a target
1989  *
1990  */
1991 /*ARGSUSED*/
1992 static int
1993 offlineTargetFunc(int operandLen, char *operands[], cmdOptions_t *options,
1994     void *args)
1995 {
1996 	return (onlineOfflineTarget(operands[0], OFFLINE_TARGET));
1997 }
1998 
1999 
2000 /*ARGSUSED*/
2001 static int
2002 removeHostGroupMemberFunc(int operandLen, char *operands[],
2003     cmdOptions_t *options, void *args)
2004 {
2005 	int i;
2006 	int ret = 0;
2007 	int stmfRet;
2008 	stmfGroupName groupName = {0};
2009 	stmfDevid devid;
2010 	wchar_t groupNamePrint[sizeof (stmfGroupName)] = {0};
2011 
2012 	for (; options->optval; options++) {
2013 		switch (options->optval) {
2014 			case 'g':
2015 				(void) mbstowcs(groupNamePrint, options->optarg,
2016 				    sizeof (stmfGroupName) - 1);
2017 				bcopy(options->optarg, groupName,
2018 				    strlen(options->optarg));
2019 				break;
2020 			default:
2021 				(void) fprintf(stderr, "%s: %c: %s\n",
2022 				    cmdName, options->optval,
2023 				    gettext("unknown option"));
2024 				return (1);
2025 		}
2026 	}
2027 
2028 	for (i = 0; i < operandLen; i++) {
2029 		if (parseDevid(operands[i], &devid) != 0) {
2030 			(void) fprintf(stderr, "%s: %s: %s\n",
2031 			    cmdName, operands[i],
2032 			    gettext("unrecognized device id"));
2033 			ret++;
2034 			continue;
2035 		}
2036 		stmfRet = stmfRemoveFromHostGroup(&groupName, &devid);
2037 		switch (stmfRet) {
2038 			case STMF_STATUS_SUCCESS:
2039 				break;
2040 			case STMF_ERROR_MEMBER_NOT_FOUND:
2041 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
2042 				    operands[i], gettext("not found"));
2043 				ret++;
2044 				break;
2045 			case STMF_ERROR_GROUP_NOT_FOUND:
2046 				(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
2047 				    groupNamePrint, gettext("not found"));
2048 				ret++;
2049 				break;
2050 			case STMF_ERROR_BUSY:
2051 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
2052 				    operands[i], "resource busy");
2053 				ret++;
2054 				break;
2055 			case STMF_ERROR_SERVICE_NOT_FOUND:
2056 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2057 				    gettext("STMF service not found"));
2058 				ret++;
2059 				break;
2060 			case STMF_ERROR_SERVICE_DATA_VERSION:
2061 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2062 				    gettext("STMF service version incorrect"));
2063 				ret++;
2064 				break;
2065 			case STMF_ERROR_PERM:
2066 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2067 				    gettext("permission denied"));
2068 				ret++;
2069 				break;
2070 			default:
2071 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
2072 				    operands[i], gettext("unknown error"));
2073 				ret++;
2074 				break;
2075 		}
2076 	}
2077 
2078 	return (ret);
2079 }
2080 
2081 /*
2082  * removeTargetGroupMemberFunc
2083  *
2084  * Removes one or more members from a target group
2085  *
2086  */
2087 /*ARGSUSED*/
2088 static int
2089 removeTargetGroupMemberFunc(int operandLen, char *operands[],
2090     cmdOptions_t *options, void *args)
2091 {
2092 	int i;
2093 	int ret = 0;
2094 	int stmfRet;
2095 	stmfGroupName groupName = {0};
2096 	stmfDevid devid;
2097 	wchar_t groupNamePrint[sizeof (stmfGroupName)] = {0};
2098 
2099 	for (; options->optval; options++) {
2100 		switch (options->optval) {
2101 			case 'g':
2102 				(void) mbstowcs(groupNamePrint, options->optarg,
2103 				    sizeof (stmfGroupName) - 1);
2104 				bcopy(options->optarg, groupName,
2105 				    strlen(options->optarg));
2106 				break;
2107 			default:
2108 				(void) fprintf(stderr, "%s: %c: %s\n",
2109 				    cmdName, options->optval,
2110 				    gettext("unknown option"));
2111 				return (1);
2112 		}
2113 	}
2114 
2115 	for (i = 0; i < operandLen; i++) {
2116 		if (parseDevid(operands[i], &devid) != 0) {
2117 			(void) fprintf(stderr, "%s: %s: %s\n",
2118 			    cmdName, operands[i],
2119 			    gettext("unrecognized device id"));
2120 			ret++;
2121 			continue;
2122 		}
2123 		stmfRet = stmfRemoveFromTargetGroup(&groupName, &devid);
2124 		switch (stmfRet) {
2125 			case STMF_STATUS_SUCCESS:
2126 				break;
2127 			case STMF_ERROR_MEMBER_NOT_FOUND:
2128 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
2129 				    operands[i], gettext("not found"));
2130 				ret++;
2131 				break;
2132 			case STMF_ERROR_GROUP_NOT_FOUND:
2133 				(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
2134 				    groupNamePrint, gettext("not found"));
2135 				ret++;
2136 				break;
2137 			case STMF_ERROR_BUSY:
2138 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
2139 				    operands[i], gettext("resource busy"));
2140 				ret++;
2141 				break;
2142 			case STMF_ERROR_SERVICE_NOT_FOUND:
2143 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2144 				    gettext("STMF service not found"));
2145 				ret++;
2146 				break;
2147 			case STMF_ERROR_PERM:
2148 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2149 				    gettext("permission denied"));
2150 				ret++;
2151 				break;
2152 			case STMF_ERROR_SERVICE_DATA_VERSION:
2153 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2154 				    gettext("STMF service version incorrect"));
2155 				ret++;
2156 				break;
2157 			default:
2158 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
2159 				    operands[i], gettext("unknown error"));
2160 				ret++;
2161 				break;
2162 		}
2163 	}
2164 
2165 	return (ret);
2166 }
2167 
2168 /*
2169  * removeViewFunc
2170  *
2171  * Removes one or more view entries from a logical unit
2172  *
2173  */
2174 /*ARGSUSED*/
2175 static int
2176 removeViewFunc(int operandLen, char *operands[], cmdOptions_t *options,
2177     void *args)
2178 {
2179 	char sGuid[GUID_INPUT + 1];
2180 	stmfViewEntryList *viewEntryList;
2181 	stmfGuid inGuid;
2182 	uint32_t count;
2183 	unsigned int guid[sizeof (stmfGuid)];
2184 	char *endPtr;
2185 	uint32_t veNbr;
2186 	int i;
2187 	boolean_t all = B_FALSE;
2188 	boolean_t luInput = B_FALSE;
2189 	int ret = 0;
2190 	int stmfRet;
2191 
2192 	/* Note: 'l' is required */
2193 	for (; options->optval; options++) {
2194 		switch (options->optval) {
2195 			case 'l':
2196 				if (strlen(options->optarg) != GUID_INPUT) {
2197 					(void) fprintf(stderr,
2198 					    "%s: %s: %s %d %s\n",
2199 					    cmdName, options->optarg,
2200 					    gettext("must be"), GUID_INPUT,
2201 					    gettext("hexadecimal digits long"));
2202 					return (1);
2203 				}
2204 				bcopy(options->optarg, sGuid, GUID_INPUT);
2205 				luInput = B_TRUE;
2206 				break;
2207 			case 'a':
2208 				/* removing all view entries for this GUID */
2209 				all = B_TRUE;
2210 				break;
2211 			default:
2212 				(void) fprintf(stderr, "%s: %c: %s\n",
2213 				    cmdName, options->optval,
2214 				    "unknown option");
2215 				return (1);
2216 		}
2217 	}
2218 
2219 	if (!all && operandLen == 0) {
2220 		(void) fprintf(stderr, "%s: %s\n", cmdName,
2221 		    gettext("no view entries specified"));
2222 		return (1);
2223 	}
2224 
2225 	if (!luInput) {
2226 		(void) fprintf(stderr, "%s: %s\n", cmdName,
2227 		    gettext("logical unit (-l) not specified"));
2228 		return (1);
2229 	}
2230 
2231 	for (i = 0; i < 32; i++)
2232 		sGuid[i] = tolower(sGuid[i]);
2233 	sGuid[i] = 0;
2234 
2235 	(void) sscanf(sGuid, "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
2236 	    &guid[0], &guid[1], &guid[2], &guid[3], &guid[4], &guid[5],
2237 	    &guid[6], &guid[7], &guid[8], &guid[9], &guid[10], &guid[11],
2238 	    &guid[12], &guid[13], &guid[14], &guid[15]);
2239 
2240 	for (i = 0; i < sizeof (stmfGuid); i++) {
2241 		inGuid.guid[i] = guid[i];
2242 	}
2243 
2244 	if ((stmfRet = stmfGetViewEntryList(&inGuid, &viewEntryList))
2245 	    != STMF_STATUS_SUCCESS) {
2246 
2247 		switch (stmfRet) {
2248 			case STMF_ERROR_BUSY:
2249 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
2250 				    sGuid, gettext("resource busy"));
2251 				break;
2252 			case STMF_ERROR_NOT_FOUND:
2253 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
2254 				    sGuid, gettext("no views found"));
2255 				break;
2256 			case STMF_ERROR_SERVICE_NOT_FOUND:
2257 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2258 				    gettext("STMF service not found"));
2259 				break;
2260 			case STMF_ERROR_SERVICE_DATA_VERSION:
2261 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2262 				    gettext("STMF service version incorrect"));
2263 				break;
2264 			case STMF_ERROR_PERM:
2265 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2266 				    gettext("permission denied"));
2267 				break;
2268 			default:
2269 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
2270 				    sGuid, gettext("unknown error"));
2271 				break;
2272 		}
2273 		return (1);
2274 	}
2275 
2276 	if (all) {
2277 		count = viewEntryList->cnt;
2278 	} else {
2279 		count = operandLen;
2280 	}
2281 
2282 	for (i = 0; i < count; i++) {
2283 		if (all) {
2284 			veNbr = viewEntryList->ve[i].veIndex;
2285 		} else {
2286 			endPtr = NULL;
2287 			veNbr = strtol(operands[i], &endPtr, 10);
2288 			if (endPtr && *endPtr != 0) {
2289 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
2290 				    operands[i], gettext("invalid input"));
2291 				continue;
2292 			}
2293 		}
2294 		stmfRet = stmfRemoveViewEntry(&inGuid, veNbr);
2295 		switch (stmfRet) {
2296 			case STMF_STATUS_SUCCESS:
2297 				break;
2298 			case STMF_ERROR_NOT_FOUND:
2299 				(void) fprintf(stderr, "%s: %s: %d: %s\n",
2300 				    cmdName, sGuid, veNbr,
2301 				    gettext("not found"));
2302 				ret++;
2303 				break;
2304 			case STMF_ERROR_BUSY:
2305 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
2306 				    sGuid, gettext("resource busy"));
2307 				ret++;
2308 				break;
2309 			case STMF_ERROR_SERVICE_NOT_FOUND:
2310 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2311 				    gettext("STMF service not found"));
2312 				ret++;
2313 				break;
2314 			case STMF_ERROR_CONFIG_NONE:
2315 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2316 				    gettext("STMF service is not initialized"));
2317 				ret++;
2318 				break;
2319 			case STMF_ERROR_SERVICE_DATA_VERSION:
2320 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2321 				    gettext("STMF service version incorrect"));
2322 				ret++;
2323 				break;
2324 			default:
2325 				(void) fprintf(stderr, "%s: %s, %d: %s",
2326 				    cmdName, sGuid, veNbr,
2327 				    gettext("unknown error"));
2328 				ret++;
2329 				break;
2330 		}
2331 	}
2332 
2333 	return (ret);
2334 }
2335 
2336 /*
2337  * input:
2338  *  execFullName - exec name of program (argv[0])
2339  *
2340  *  copied from usr/src/cmd/zoneadm/zoneadm.c in OS/Net
2341  *  (changed name to lowerCamelCase to keep consistent with this file)
2342  *
2343  * Returns:
2344  *  command name portion of execFullName
2345  */
2346 static char *
2347 getExecBasename(char *execFullname)
2348 {
2349 	char *lastSlash, *execBasename;
2350 
2351 	/* guard against '/' at end of command invocation */
2352 	for (;;) {
2353 		lastSlash = strrchr(execFullname, '/');
2354 		if (lastSlash == NULL) {
2355 			execBasename = execFullname;
2356 			break;
2357 		} else {
2358 			execBasename = lastSlash + 1;
2359 			if (*execBasename == '\0') {
2360 				*lastSlash = '\0';
2361 				continue;
2362 			}
2363 			break;
2364 		}
2365 	}
2366 	return (execBasename);
2367 }
2368 
2369 int
2370 main(int argc, char *argv[])
2371 {
2372 	synTables_t synTables;
2373 	char versionString[VERSION_STRING_MAX_LEN];
2374 	int ret;
2375 	int funcRet;
2376 	void *subcommandArgs = NULL;
2377 
2378 	(void) setlocale(LC_ALL, "");
2379 	(void) textdomain(TEXT_DOMAIN);
2380 	/* set global command name */
2381 	cmdName = getExecBasename(argv[0]);
2382 
2383 	(void) snprintf(versionString, VERSION_STRING_MAX_LEN, "%s.%s",
2384 	    VERSION_STRING_MAJOR, VERSION_STRING_MINOR);
2385 	synTables.versionString = versionString;
2386 	synTables.longOptionTbl = &longOptions[0];
2387 	synTables.subCommandPropsTbl = &subcommands[0];
2388 
2389 	ret = cmdParse(argc, argv, synTables, subcommandArgs, &funcRet);
2390 	if (ret != 0) {
2391 		return (ret);
2392 	}
2393 
2394 	return (funcRet);
2395 } /* end main */
2396