xref: /titanic_52/usr/src/cmd/stmfadm/stmfadm.c (revision aca118b711d5dc86653e0b3c1a122a6b93a0112d)
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 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 static int
1457 getStmfState(stmfState *state)
1458 {
1459 	int ret;
1460 
1461 	ret = stmfGetState(state);
1462 	switch (ret) {
1463 		case STMF_STATUS_SUCCESS:
1464 			break;
1465 		case STMF_ERROR_PERM:
1466 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1467 			    gettext("permission denied"));
1468 			break;
1469 		case STMF_ERROR_SERVICE_NOT_FOUND:
1470 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1471 			    gettext("STMF service not found"));
1472 			break;
1473 		case STMF_ERROR_BUSY:
1474 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1475 			    gettext("resource busy"));
1476 			break;
1477 		case STMF_ERROR_SERVICE_DATA_VERSION:
1478 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1479 			    gettext("STMF service version incorrect"));
1480 			break;
1481 		default:
1482 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1483 			    gettext("unknown error"));
1484 			break;
1485 	}
1486 	return (ret);
1487 }
1488 
1489 /*
1490  * listStateFunc
1491  *
1492  * List the operational and config state of the stmf service
1493  *
1494  */
1495 /*ARGSUSED*/
1496 static int
1497 listStateFunc(int operandLen, char *operands[], cmdOptions_t *options,
1498     void *args)
1499 {
1500 	int ret;
1501 	stmfState state;
1502 
1503 	if ((ret = getStmfState(&state)) != STMF_STATUS_SUCCESS)
1504 		return (ret);
1505 
1506 	(void) printf("%-18s: ", "Operational Status");
1507 	switch (state.operationalState) {
1508 		case STMF_SERVICE_STATE_ONLINE:
1509 			(void) printf("online");
1510 			break;
1511 		case STMF_SERVICE_STATE_OFFLINE:
1512 			(void) printf("offline");
1513 			break;
1514 		case STMF_SERVICE_STATE_ONLINING:
1515 			(void) printf("onlining");
1516 			break;
1517 		case STMF_SERVICE_STATE_OFFLINING:
1518 			(void) printf("offlining");
1519 			break;
1520 		default:
1521 			(void) printf("unknown");
1522 			break;
1523 	}
1524 	(void) printf("\n");
1525 	(void) printf("%-18s: ", "Config Status");
1526 	switch (state.configState) {
1527 		case STMF_CONFIG_STATE_NONE:
1528 			(void) printf("uninitialized");
1529 			break;
1530 		case STMF_CONFIG_STATE_INIT:
1531 			(void) printf("initializing");
1532 			break;
1533 		case STMF_CONFIG_STATE_INIT_DONE:
1534 			(void) printf("initialized");
1535 			break;
1536 		default:
1537 			(void) printf("unknown");
1538 			break;
1539 	}
1540 	(void) printf("\n");
1541 	return (0);
1542 }
1543 
1544 /*
1545  * listTargetFunc
1546  *
1547  * list the targets and optionally their properties
1548  *
1549  */
1550 /*ARGSUSED*/
1551 static int
1552 listTargetFunc(int operandLen, char *operands[], cmdOptions_t *options,
1553     void *args)
1554 {
1555 	cmdOptions_t *optionList = options;
1556 	int ret = 0;
1557 	int stmfRet;
1558 	int i, j;
1559 	int outerLoop;
1560 	stmfSessionList *sessionList;
1561 	stmfDevid devid;
1562 	boolean_t operandEntered, found, verbose = B_FALSE;
1563 	stmfDevidList *targetList;
1564 	wchar_t targetIdent[STMF_IDENT_LENGTH + 1];
1565 	stmfTargetProperties targetProps;
1566 
1567 	if ((stmfRet = stmfGetTargetList(&targetList)) != STMF_STATUS_SUCCESS) {
1568 		switch (stmfRet) {
1569 			case STMF_ERROR_NOT_FOUND:
1570 				ret = 0;
1571 				break;
1572 			case STMF_ERROR_SERVICE_OFFLINE:
1573 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1574 				    gettext("STMF service offline"));
1575 				break;
1576 			case STMF_ERROR_BUSY:
1577 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1578 				    gettext("resource busy"));
1579 				break;
1580 			case STMF_ERROR_SERVICE_DATA_VERSION:
1581 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1582 				    gettext("STMF service version incorrect"));
1583 				break;
1584 			case STMF_ERROR_PERM:
1585 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1586 				    gettext("permission denied"));
1587 				break;
1588 			default:
1589 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1590 				    gettext("unknown error"));
1591 				break;
1592 		}
1593 		return (1);
1594 	}
1595 
1596 	for (; optionList->optval; optionList++) {
1597 		switch (optionList->optval) {
1598 			case 'v':
1599 				verbose = B_TRUE;
1600 				break;
1601 		}
1602 	}
1603 
1604 	if (operandLen > 0) {
1605 		outerLoop = operandLen;
1606 		operandEntered = B_TRUE;
1607 	} else {
1608 		outerLoop = 1;
1609 		operandEntered = B_FALSE;
1610 	}
1611 
1612 	for (i = 0; i < outerLoop; i++) {
1613 		if (operandEntered) {
1614 			bzero(&devid, sizeof (devid));
1615 			(void) parseDevid(operands[i], &devid);
1616 		}
1617 		for (found = B_FALSE, j = 0; j < targetList->cnt; j++) {
1618 			if (operandEntered) {
1619 				if (bcmp(&devid, &(targetList->devid[j]),
1620 				    sizeof (devid)) == 0) {
1621 					found = B_TRUE;
1622 				}
1623 			}
1624 			if ((found && operandEntered) || !operandEntered) {
1625 				(void) mbstowcs(targetIdent,
1626 				    (char *)targetList->devid[j].ident,
1627 				    STMF_IDENT_LENGTH);
1628 				targetIdent[STMF_IDENT_LENGTH] = 0;
1629 				(void) printf("Target: %ws\n", targetIdent);
1630 				if (verbose) {
1631 					stmfRet = stmfGetTargetProperties(
1632 					    &(targetList->devid[j]),
1633 					    &targetProps);
1634 					if (stmfRet == STMF_STATUS_SUCCESS) {
1635 						printTargetProps(&targetProps);
1636 					} else {
1637 						(void) fprintf(stderr, "%s:",
1638 						    cmdName);
1639 						(void) fprintf(stderr, "%s\n",
1640 						    gettext(" get properties"
1641 						    " failed"));
1642 					}
1643 					stmfRet = stmfGetSessionList(
1644 					    &(targetList->devid[j]),
1645 					    &sessionList);
1646 					if (stmfRet == STMF_STATUS_SUCCESS) {
1647 						printSessionProps(sessionList);
1648 					} else {
1649 						(void) fprintf(stderr, "%s:",
1650 						    cmdName);
1651 						(void) fprintf(stderr, "%s\n",
1652 						    gettext(" get session info"
1653 						    " failed"));
1654 					}
1655 				}
1656 				if (found && operandEntered) {
1657 					break;
1658 				}
1659 			}
1660 
1661 		}
1662 		if (operandEntered && !found) {
1663 			(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
1664 			    operands[i], "not found");
1665 			ret = 1;
1666 		}
1667 	}
1668 	return (ret);
1669 }
1670 
1671 /*
1672  * listViewFunc
1673  *
1674  * list the view entries for the specified logical unit
1675  *
1676  */
1677 /*ARGSUSED*/
1678 static int
1679 listViewFunc(int operandLen, char *operands[], cmdOptions_t *options,
1680     void *args)
1681 {
1682 	stmfViewEntryList *viewEntryList;
1683 	stmfGuid inGuid;
1684 	unsigned int guid[sizeof (stmfGuid)];
1685 	int ret = 0;
1686 	int stmfRet;
1687 	int i, j, outerLoop;
1688 	boolean_t found = B_TRUE;
1689 	boolean_t operandEntered;
1690 	uint16_t outputLuNbr;
1691 	wchar_t groupName[sizeof (stmfGroupName)];
1692 	char sGuid[GUID_INPUT + 1];
1693 
1694 
1695 	for (; options->optval; options++) {
1696 		switch (options->optval) {
1697 			case 'l':
1698 				if (strlen(options->optarg) != GUID_INPUT) {
1699 					(void) fprintf(stderr,
1700 					    "%s: %s: %s%d%s\n",
1701 					    cmdName, options->optarg,
1702 					    gettext("must be "), GUID_INPUT,
1703 					    gettext(" hexadecimal digits"
1704 					    " long"));
1705 					return (1);
1706 				}
1707 				bcopy(options->optarg, sGuid, GUID_INPUT);
1708 				break;
1709 			default:
1710 				(void) fprintf(stderr, "%s: %c: %s\n",
1711 				    cmdName, options->optval,
1712 				    gettext("unknown option"));
1713 				return (1);
1714 		}
1715 	}
1716 
1717 	if (operandLen > 0) {
1718 		outerLoop = operandLen;
1719 		operandEntered = B_TRUE;
1720 	} else {
1721 		outerLoop = 1;
1722 		operandEntered = B_FALSE;
1723 	}
1724 
1725 	for (i = 0; i < 32; i++)
1726 		sGuid[i] = tolower(sGuid[i]);
1727 	sGuid[i] = 0;
1728 
1729 	(void) sscanf(sGuid, "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
1730 	    &guid[0], &guid[1], &guid[2], &guid[3], &guid[4], &guid[5],
1731 	    &guid[6], &guid[7], &guid[8], &guid[9], &guid[10], &guid[11],
1732 	    &guid[12], &guid[13], &guid[14], &guid[15]);
1733 
1734 	for (i = 0; i < sizeof (stmfGuid); i++) {
1735 		inGuid.guid[i] = guid[i];
1736 	}
1737 
1738 	if ((stmfRet = stmfGetViewEntryList(&inGuid, &viewEntryList))
1739 	    != STMF_STATUS_SUCCESS) {
1740 
1741 		switch (stmfRet) {
1742 			case STMF_ERROR_BUSY:
1743 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
1744 				    sGuid, gettext("resource busy"));
1745 				break;
1746 			case STMF_ERROR_NOT_FOUND:
1747 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
1748 				    sGuid, gettext("no views found"));
1749 				break;
1750 			case STMF_ERROR_SERVICE_NOT_FOUND:
1751 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1752 				    gettext("STMF service not found"));
1753 				break;
1754 			case STMF_ERROR_SERVICE_DATA_VERSION:
1755 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1756 				    gettext("STMF service version incorrect"));
1757 				break;
1758 			case STMF_ERROR_PERM:
1759 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1760 				    gettext("permission denied"));
1761 				break;
1762 			default:
1763 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
1764 				    sGuid, gettext("unknown error"));
1765 				break;
1766 		}
1767 		return (1);
1768 	}
1769 
1770 	for (i = 0; i < outerLoop; i++) {
1771 		for (found = B_FALSE, j = 0; j < viewEntryList->cnt; j++) {
1772 			if (operandEntered) {
1773 				if (atoi(operands[i]) ==
1774 				    viewEntryList->ve[j].veIndex) {
1775 					found = B_TRUE;
1776 				}
1777 			}
1778 			if ((found && operandEntered) || !operandEntered) {
1779 				(void) printf("View Entry: %d\n",
1780 				    viewEntryList->ve[j].veIndex);
1781 				(void) printf(VIEW_FORMAT, "Host group");
1782 				if (viewEntryList->ve[j].allHosts) {
1783 					(void) printf("All\n");
1784 				} else {
1785 					(void) mbstowcs(groupName,
1786 					    viewEntryList->ve[j].hostGroup,
1787 					    sizeof (stmfGroupName) - 1);
1788 					groupName[sizeof (stmfGroupName) - 1]
1789 					    = 0;
1790 					(void) printf("%ws\n", groupName);
1791 				}
1792 				(void) printf(VIEW_FORMAT, "Target group");
1793 				if (viewEntryList->ve[j].allTargets) {
1794 					(void) printf("All\n");
1795 				} else {
1796 					(void) mbstowcs(groupName,
1797 					    viewEntryList->ve[j].targetGroup,
1798 					    sizeof (stmfGroupName) - 1);
1799 					groupName[sizeof (stmfGroupName) - 1]
1800 					    = 0;
1801 					(void) printf("%ws\n", groupName);
1802 				}
1803 				outputLuNbr = ((viewEntryList->ve[j].luNbr[0] &
1804 				    0x3F) << 8) | viewEntryList->ve[j].luNbr[1];
1805 				(void) printf(VIEW_FORMAT, "LUN");
1806 				(void) printf("%d\n", outputLuNbr);
1807 				if (found && operandEntered) {
1808 					break;
1809 				}
1810 			}
1811 		}
1812 		if (operandEntered && !found) {
1813 			(void) fprintf(stderr, "%s: %s, %s: %s\n", cmdName,
1814 			    sGuid, operands[i], gettext("not found"));
1815 			ret = 1;
1816 		}
1817 	}
1818 
1819 	return (ret);
1820 }
1821 
1822 
1823 /*
1824  * onlineOfflineLu
1825  *
1826  * Purpose: Online or offline a logical unit
1827  *
1828  * lu - logical unit to online or offline
1829  *
1830  * state - ONLINE_LU
1831  *         OFFLINE_LU
1832  */
1833 static int
1834 onlineOfflineLu(char *lu, int state)
1835 {
1836 	char sGuid[GUID_INPUT + 1];
1837 	stmfGuid inGuid;
1838 	unsigned int guid[sizeof (stmfGuid)];
1839 	int i;
1840 	int ret = 0;
1841 
1842 	if (strlen(lu) != GUID_INPUT) {
1843 		(void) fprintf(stderr, "%s: %s: %s %d %s\n", cmdName, lu,
1844 		    gettext("must be"), GUID_INPUT,
1845 		    gettext("hexadecimal digits long"));
1846 		return (1);
1847 	}
1848 
1849 	bcopy(lu, sGuid, GUID_INPUT);
1850 
1851 	for (i = 0; i < 32; i++)
1852 		sGuid[i] = tolower(sGuid[i]);
1853 	sGuid[i] = 0;
1854 
1855 	(void) sscanf(sGuid, "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
1856 	    &guid[0], &guid[1], &guid[2], &guid[3], &guid[4], &guid[5],
1857 	    &guid[6], &guid[7], &guid[8], &guid[9], &guid[10], &guid[11],
1858 	    &guid[12], &guid[13], &guid[14], &guid[15]);
1859 
1860 	for (i = 0; i < sizeof (stmfGuid); i++) {
1861 		inGuid.guid[i] = guid[i];
1862 	}
1863 
1864 	if (state == ONLINE_LU) {
1865 		ret = stmfOnlineLogicalUnit(&inGuid);
1866 	} else if (state == OFFLINE_LU) {
1867 		ret = stmfOfflineLogicalUnit(&inGuid);
1868 	}
1869 	if (ret != STMF_STATUS_SUCCESS) {
1870 		switch (ret) {
1871 			case STMF_ERROR_PERM:
1872 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1873 				    gettext("permission denied"));
1874 				break;
1875 			case STMF_ERROR_SERVICE_NOT_FOUND:
1876 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1877 				    gettext("STMF service not found"));
1878 				break;
1879 			case STMF_ERROR_NOT_FOUND:
1880 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
1881 				    lu, gettext("not found"));
1882 				break;
1883 			case STMF_ERROR_SERVICE_DATA_VERSION:
1884 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1885 				    gettext("STMF service version incorrect"));
1886 				break;
1887 			default:
1888 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1889 				    gettext("unknown error"));
1890 				break;
1891 		}
1892 	}
1893 	return (ret);
1894 }
1895 
1896 /*
1897  * onlineLuFunc
1898  *
1899  * Purpose: Online a logical unit
1900  *
1901  */
1902 /*ARGSUSED*/
1903 static int
1904 onlineLuFunc(int operandLen, char *operands[], cmdOptions_t *options,
1905     void *args)
1906 {
1907 	int ret;
1908 	stmfState state;
1909 
1910 	ret = getStmfState(&state);
1911 	if (ret != STMF_STATUS_SUCCESS)
1912 		return (ret);
1913 	if (state.operationalState == STMF_SERVICE_STATE_OFFLINE ||
1914 	    state.operationalState == STMF_SERVICE_STATE_OFFLINING) {
1915 		(void) fprintf(stderr, "%s: %s\n", cmdName,
1916 		    gettext("STMF service is offline"));
1917 		return (1);
1918 	}
1919 	return (onlineOfflineLu(operands[0], ONLINE_LU));
1920 }
1921 
1922 /*
1923  * offlineLuFunc
1924  *
1925  * Purpose: Offline a logical unit
1926  *
1927  */
1928 /*ARGSUSED*/
1929 static int
1930 offlineLuFunc(int operandLen, char *operands[], cmdOptions_t *options,
1931     void *args)
1932 {
1933 	return (onlineOfflineLu(operands[0], OFFLINE_LU));
1934 }
1935 
1936 /*
1937  * onlineOfflineTarget
1938  *
1939  * Purpose: Online or offline a target
1940  *
1941  * target - target to online or offline
1942  *
1943  * state - ONLINE_TARGET
1944  *         OFFLINE_TARGET
1945  */
1946 static int
1947 onlineOfflineTarget(char *target, int state)
1948 {
1949 	int ret = 0;
1950 	stmfDevid devid;
1951 
1952 	if (parseDevid(target, &devid) != 0) {
1953 		(void) fprintf(stderr, "%s: %s: %s\n",
1954 		    cmdName, target, gettext("unrecognized device id"));
1955 		return (1);
1956 	}
1957 	if (state == ONLINE_TARGET) {
1958 		ret = stmfOnlineTarget(&devid);
1959 	} else if (state == OFFLINE_TARGET) {
1960 		ret = stmfOfflineTarget(&devid);
1961 	}
1962 	if (ret != STMF_STATUS_SUCCESS) {
1963 		switch (ret) {
1964 			case STMF_ERROR_PERM:
1965 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1966 				    gettext("permission denied"));
1967 				break;
1968 			case STMF_ERROR_SERVICE_NOT_FOUND:
1969 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1970 				    gettext("STMF service not found"));
1971 				break;
1972 			case STMF_ERROR_NOT_FOUND:
1973 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
1974 				    target, gettext("not found"));
1975 				break;
1976 			case STMF_ERROR_SERVICE_DATA_VERSION:
1977 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1978 				    gettext("STMF service version incorrect"));
1979 				break;
1980 			default:
1981 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1982 				    gettext("unknown error"));
1983 				break;
1984 		}
1985 	}
1986 	return (ret);
1987 }
1988 
1989 /*
1990  * onlineTargetFunc
1991  *
1992  * Purpose: Online a target
1993  *
1994  */
1995 /*ARGSUSED*/
1996 static int
1997 onlineTargetFunc(int operandLen, char *operands[], cmdOptions_t *options,
1998     void *args)
1999 {
2000 	int ret;
2001 	stmfState state;
2002 
2003 	ret = getStmfState(&state);
2004 	if (ret != STMF_STATUS_SUCCESS)
2005 		return (ret);
2006 	if (state.operationalState == STMF_SERVICE_STATE_OFFLINE ||
2007 	    state.operationalState == STMF_SERVICE_STATE_OFFLINING) {
2008 		(void) fprintf(stderr, "%s: %s\n", cmdName,
2009 		    gettext("STMF service is offline"));
2010 		return (1);
2011 	}
2012 	return (onlineOfflineTarget(operands[0], ONLINE_TARGET));
2013 }
2014 
2015 /*
2016  * offlineTargetFunc
2017  *
2018  * Purpose: Offline a target
2019  *
2020  */
2021 /*ARGSUSED*/
2022 static int
2023 offlineTargetFunc(int operandLen, char *operands[], cmdOptions_t *options,
2024     void *args)
2025 {
2026 	return (onlineOfflineTarget(operands[0], OFFLINE_TARGET));
2027 }
2028 
2029 
2030 /*ARGSUSED*/
2031 static int
2032 removeHostGroupMemberFunc(int operandLen, char *operands[],
2033     cmdOptions_t *options, void *args)
2034 {
2035 	int i;
2036 	int ret = 0;
2037 	int stmfRet;
2038 	stmfGroupName groupName = {0};
2039 	stmfDevid devid;
2040 	wchar_t groupNamePrint[sizeof (stmfGroupName)] = {0};
2041 
2042 	for (; options->optval; options++) {
2043 		switch (options->optval) {
2044 			case 'g':
2045 				(void) mbstowcs(groupNamePrint, options->optarg,
2046 				    sizeof (stmfGroupName) - 1);
2047 				bcopy(options->optarg, groupName,
2048 				    strlen(options->optarg));
2049 				break;
2050 			default:
2051 				(void) fprintf(stderr, "%s: %c: %s\n",
2052 				    cmdName, options->optval,
2053 				    gettext("unknown option"));
2054 				return (1);
2055 		}
2056 	}
2057 
2058 	for (i = 0; i < operandLen; i++) {
2059 		if (parseDevid(operands[i], &devid) != 0) {
2060 			(void) fprintf(stderr, "%s: %s: %s\n",
2061 			    cmdName, operands[i],
2062 			    gettext("unrecognized device id"));
2063 			ret++;
2064 			continue;
2065 		}
2066 		stmfRet = stmfRemoveFromHostGroup(&groupName, &devid);
2067 		switch (stmfRet) {
2068 			case STMF_STATUS_SUCCESS:
2069 				break;
2070 			case STMF_ERROR_MEMBER_NOT_FOUND:
2071 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
2072 				    operands[i], gettext("not found"));
2073 				ret++;
2074 				break;
2075 			case STMF_ERROR_GROUP_NOT_FOUND:
2076 				(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
2077 				    groupNamePrint, gettext("not found"));
2078 				ret++;
2079 				break;
2080 			case STMF_ERROR_BUSY:
2081 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
2082 				    operands[i], "resource busy");
2083 				ret++;
2084 				break;
2085 			case STMF_ERROR_SERVICE_NOT_FOUND:
2086 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2087 				    gettext("STMF service not found"));
2088 				ret++;
2089 				break;
2090 			case STMF_ERROR_SERVICE_DATA_VERSION:
2091 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2092 				    gettext("STMF service version incorrect"));
2093 				ret++;
2094 				break;
2095 			case STMF_ERROR_PERM:
2096 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2097 				    gettext("permission denied"));
2098 				ret++;
2099 				break;
2100 			default:
2101 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
2102 				    operands[i], gettext("unknown error"));
2103 				ret++;
2104 				break;
2105 		}
2106 	}
2107 
2108 	return (ret);
2109 }
2110 
2111 /*
2112  * removeTargetGroupMemberFunc
2113  *
2114  * Removes one or more members from a target group
2115  *
2116  */
2117 /*ARGSUSED*/
2118 static int
2119 removeTargetGroupMemberFunc(int operandLen, char *operands[],
2120     cmdOptions_t *options, void *args)
2121 {
2122 	int i;
2123 	int ret = 0;
2124 	int stmfRet;
2125 	stmfGroupName groupName = {0};
2126 	stmfDevid devid;
2127 	wchar_t groupNamePrint[sizeof (stmfGroupName)] = {0};
2128 
2129 	for (; options->optval; options++) {
2130 		switch (options->optval) {
2131 			case 'g':
2132 				(void) mbstowcs(groupNamePrint, options->optarg,
2133 				    sizeof (stmfGroupName) - 1);
2134 				bcopy(options->optarg, groupName,
2135 				    strlen(options->optarg));
2136 				break;
2137 			default:
2138 				(void) fprintf(stderr, "%s: %c: %s\n",
2139 				    cmdName, options->optval,
2140 				    gettext("unknown option"));
2141 				return (1);
2142 		}
2143 	}
2144 
2145 	for (i = 0; i < operandLen; i++) {
2146 		if (parseDevid(operands[i], &devid) != 0) {
2147 			(void) fprintf(stderr, "%s: %s: %s\n",
2148 			    cmdName, operands[i],
2149 			    gettext("unrecognized device id"));
2150 			ret++;
2151 			continue;
2152 		}
2153 		stmfRet = stmfRemoveFromTargetGroup(&groupName, &devid);
2154 		switch (stmfRet) {
2155 			case STMF_STATUS_SUCCESS:
2156 				break;
2157 			case STMF_ERROR_MEMBER_NOT_FOUND:
2158 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
2159 				    operands[i], gettext("not found"));
2160 				ret++;
2161 				break;
2162 			case STMF_ERROR_GROUP_NOT_FOUND:
2163 				(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
2164 				    groupNamePrint, gettext("not found"));
2165 				ret++;
2166 				break;
2167 			case STMF_ERROR_BUSY:
2168 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
2169 				    operands[i], gettext("resource busy"));
2170 				ret++;
2171 				break;
2172 			case STMF_ERROR_SERVICE_NOT_FOUND:
2173 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2174 				    gettext("STMF service not found"));
2175 				ret++;
2176 				break;
2177 			case STMF_ERROR_PERM:
2178 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2179 				    gettext("permission denied"));
2180 				ret++;
2181 				break;
2182 			case STMF_ERROR_SERVICE_DATA_VERSION:
2183 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2184 				    gettext("STMF service version incorrect"));
2185 				ret++;
2186 				break;
2187 			default:
2188 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
2189 				    operands[i], gettext("unknown error"));
2190 				ret++;
2191 				break;
2192 		}
2193 	}
2194 
2195 	return (ret);
2196 }
2197 
2198 /*
2199  * removeViewFunc
2200  *
2201  * Removes one or more view entries from a logical unit
2202  *
2203  */
2204 /*ARGSUSED*/
2205 static int
2206 removeViewFunc(int operandLen, char *operands[], cmdOptions_t *options,
2207     void *args)
2208 {
2209 	char sGuid[GUID_INPUT + 1];
2210 	stmfViewEntryList *viewEntryList;
2211 	stmfGuid inGuid;
2212 	uint32_t count;
2213 	unsigned int guid[sizeof (stmfGuid)];
2214 	char *endPtr;
2215 	uint32_t veNbr;
2216 	int i;
2217 	boolean_t all = B_FALSE;
2218 	boolean_t luInput = B_FALSE;
2219 	int ret = 0;
2220 	int stmfRet;
2221 
2222 	/* Note: 'l' is required */
2223 	for (; options->optval; options++) {
2224 		switch (options->optval) {
2225 			case 'l':
2226 				if (strlen(options->optarg) != GUID_INPUT) {
2227 					(void) fprintf(stderr,
2228 					    "%s: %s: %s %d %s\n",
2229 					    cmdName, options->optarg,
2230 					    gettext("must be"), GUID_INPUT,
2231 					    gettext("hexadecimal digits long"));
2232 					return (1);
2233 				}
2234 				bcopy(options->optarg, sGuid, GUID_INPUT);
2235 				luInput = B_TRUE;
2236 				break;
2237 			case 'a':
2238 				/* removing all view entries for this GUID */
2239 				all = B_TRUE;
2240 				break;
2241 			default:
2242 				(void) fprintf(stderr, "%s: %c: %s\n",
2243 				    cmdName, options->optval,
2244 				    "unknown option");
2245 				return (1);
2246 		}
2247 	}
2248 
2249 	if (!all && operandLen == 0) {
2250 		(void) fprintf(stderr, "%s: %s\n", cmdName,
2251 		    gettext("no view entries specified"));
2252 		return (1);
2253 	}
2254 
2255 	if (!luInput) {
2256 		(void) fprintf(stderr, "%s: %s\n", cmdName,
2257 		    gettext("logical unit (-l) not specified"));
2258 		return (1);
2259 	}
2260 
2261 	for (i = 0; i < 32; i++)
2262 		sGuid[i] = tolower(sGuid[i]);
2263 	sGuid[i] = 0;
2264 
2265 	(void) sscanf(sGuid, "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
2266 	    &guid[0], &guid[1], &guid[2], &guid[3], &guid[4], &guid[5],
2267 	    &guid[6], &guid[7], &guid[8], &guid[9], &guid[10], &guid[11],
2268 	    &guid[12], &guid[13], &guid[14], &guid[15]);
2269 
2270 	for (i = 0; i < sizeof (stmfGuid); i++) {
2271 		inGuid.guid[i] = guid[i];
2272 	}
2273 
2274 	if ((stmfRet = stmfGetViewEntryList(&inGuid, &viewEntryList))
2275 	    != STMF_STATUS_SUCCESS) {
2276 
2277 		switch (stmfRet) {
2278 			case STMF_ERROR_BUSY:
2279 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
2280 				    sGuid, gettext("resource busy"));
2281 				break;
2282 			case STMF_ERROR_NOT_FOUND:
2283 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
2284 				    sGuid, gettext("no views found"));
2285 				break;
2286 			case STMF_ERROR_SERVICE_NOT_FOUND:
2287 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2288 				    gettext("STMF service not found"));
2289 				break;
2290 			case STMF_ERROR_SERVICE_DATA_VERSION:
2291 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2292 				    gettext("STMF service version incorrect"));
2293 				break;
2294 			case STMF_ERROR_PERM:
2295 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2296 				    gettext("permission denied"));
2297 				break;
2298 			default:
2299 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
2300 				    sGuid, gettext("unknown error"));
2301 				break;
2302 		}
2303 		return (1);
2304 	}
2305 
2306 	if (all) {
2307 		count = viewEntryList->cnt;
2308 	} else {
2309 		count = operandLen;
2310 	}
2311 
2312 	for (i = 0; i < count; i++) {
2313 		if (all) {
2314 			veNbr = viewEntryList->ve[i].veIndex;
2315 		} else {
2316 			endPtr = NULL;
2317 			veNbr = strtol(operands[i], &endPtr, 10);
2318 			if (endPtr && *endPtr != 0) {
2319 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
2320 				    operands[i], gettext("invalid input"));
2321 				continue;
2322 			}
2323 		}
2324 		stmfRet = stmfRemoveViewEntry(&inGuid, veNbr);
2325 		switch (stmfRet) {
2326 			case STMF_STATUS_SUCCESS:
2327 				break;
2328 			case STMF_ERROR_NOT_FOUND:
2329 				(void) fprintf(stderr, "%s: %s: %d: %s\n",
2330 				    cmdName, sGuid, veNbr,
2331 				    gettext("not found"));
2332 				ret++;
2333 				break;
2334 			case STMF_ERROR_BUSY:
2335 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
2336 				    sGuid, gettext("resource busy"));
2337 				ret++;
2338 				break;
2339 			case STMF_ERROR_SERVICE_NOT_FOUND:
2340 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2341 				    gettext("STMF service not found"));
2342 				ret++;
2343 				break;
2344 			case STMF_ERROR_CONFIG_NONE:
2345 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2346 				    gettext("STMF service is not initialized"));
2347 				ret++;
2348 				break;
2349 			case STMF_ERROR_SERVICE_DATA_VERSION:
2350 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2351 				    gettext("STMF service version incorrect"));
2352 				ret++;
2353 				break;
2354 			default:
2355 				(void) fprintf(stderr, "%s: %s, %d: %s",
2356 				    cmdName, sGuid, veNbr,
2357 				    gettext("unknown error"));
2358 				ret++;
2359 				break;
2360 		}
2361 	}
2362 
2363 	return (ret);
2364 }
2365 
2366 /*
2367  * input:
2368  *  execFullName - exec name of program (argv[0])
2369  *
2370  *  copied from usr/src/cmd/zoneadm/zoneadm.c in OS/Net
2371  *  (changed name to lowerCamelCase to keep consistent with this file)
2372  *
2373  * Returns:
2374  *  command name portion of execFullName
2375  */
2376 static char *
2377 getExecBasename(char *execFullname)
2378 {
2379 	char *lastSlash, *execBasename;
2380 
2381 	/* guard against '/' at end of command invocation */
2382 	for (;;) {
2383 		lastSlash = strrchr(execFullname, '/');
2384 		if (lastSlash == NULL) {
2385 			execBasename = execFullname;
2386 			break;
2387 		} else {
2388 			execBasename = lastSlash + 1;
2389 			if (*execBasename == '\0') {
2390 				*lastSlash = '\0';
2391 				continue;
2392 			}
2393 			break;
2394 		}
2395 	}
2396 	return (execBasename);
2397 }
2398 
2399 int
2400 main(int argc, char *argv[])
2401 {
2402 	synTables_t synTables;
2403 	char versionString[VERSION_STRING_MAX_LEN];
2404 	int ret;
2405 	int funcRet;
2406 	void *subcommandArgs = NULL;
2407 
2408 	(void) setlocale(LC_ALL, "");
2409 	(void) textdomain(TEXT_DOMAIN);
2410 	/* set global command name */
2411 	cmdName = getExecBasename(argv[0]);
2412 
2413 	(void) snprintf(versionString, VERSION_STRING_MAX_LEN, "%s.%s",
2414 	    VERSION_STRING_MAJOR, VERSION_STRING_MINOR);
2415 	synTables.versionString = versionString;
2416 	synTables.longOptionTbl = &longOptions[0];
2417 	synTables.subCommandPropsTbl = &subcommands[0];
2418 
2419 	ret = cmdParse(argc, argv, synTables, subcommandArgs, &funcRet);
2420 	if (ret != 0) {
2421 		return (ret);
2422 	}
2423 
2424 	return (funcRet);
2425 } /* end main */
2426