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