xref: /illumos-gate/usr/src/cmd/sbdadm/sbdadm.c (revision 6d02032db7b674f185405d42cc8bf10a46a9ab3a)
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 2010 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
30 #include <unistd.h>
31 #include <libintl.h>
32 #include <errno.h>
33 #include <string.h>
34 #include <assert.h>
35 #include <getopt.h>
36 #include <strings.h>
37 #include <ctype.h>
38 #include <libnvpair.h>
39 #include <locale.h>
40 
41 #include <cmdparse.h>
42 #include <sys/stmf_defines.h>
43 #include <libstmf.h>
44 #include <sys/stmf_sbd_ioctl.h>
45 
46 #define	MAX_LU_LIST	8192
47 #define	LU_LIST_MAX_RETRIES 3
48 #define	GUID_INPUT  32
49 
50 #define	VERSION_STRING_MAJOR	    "1"
51 #define	VERSION_STRING_MINOR	    "0"
52 #define	VERSION_STRING_MAX_LEN	    10
53 
54 
55 char *cmdName;
56 
57 static char *getExecBasename(char *);
58 int delete_lu(int argc, char *argv[], cmdOptions_t *options,
59     void *callData);
60 int create_lu(int argc, char *argv[], cmdOptions_t *options, void *callData);
61 int list_lus(int argc, char *argv[], cmdOptions_t *options, void *callData);
62 int modify_lu(int argc, char *argv[], cmdOptions_t *options, void *callData);
63 int import_lu(int argc, char *argv[], cmdOptions_t *options, void *callData);
64 static int callModify(char *, stmfGuid *, uint32_t, const char *, const char *);
65 int print_lu_attr(stmfGuid *);
66 void print_guid(uint8_t *g, FILE *f);
67 void print_attr_header();
68 
69 optionTbl_t options[] = {
70 	{ "disk-size", required_argument, 's',
71 			"Size with <none>/k/m/g/t/p/e modifier" },
72 	{ "keep-views", no_arg, 'k',
73 			"Dont delete view entries related to the LU" },
74 	{ NULL, 0, 0 }
75 };
76 
77 subCommandProps_t subCommands[] = {
78 	{ "create-lu", create_lu, "s", NULL, NULL,
79 		OPERAND_MANDATORY_SINGLE,
80 		"Full path of the file to initialize" },
81 	{ "delete-lu", delete_lu, "k", NULL, NULL,
82 		OPERAND_MANDATORY_SINGLE, "GUID of the LU to deregister" },
83 	{ "import-lu", import_lu, NULL, NULL, NULL,
84 		OPERAND_MANDATORY_SINGLE, "filename of the LU to import" },
85 	{ "list-lu", list_lus, NULL, NULL, NULL,
86 		OPERAND_NONE, "List all the exported LUs" },
87 	{ "modify-lu", modify_lu, "s", "s", NULL,
88 		OPERAND_MANDATORY_SINGLE,
89 		"Full path of the LU or GUID of a registered LU" },
90 	{ NULL, 0, 0, NULL, 0, NULL}
91 };
92 
93 /*ARGSUSED*/
94 int
95 create_lu(int argc, char *operands[], cmdOptions_t *options, void *callData)
96 {
97 	luResource hdl = NULL;
98 	int ret = 0;
99 	stmfGuid createdGuid;
100 
101 	ret = stmfCreateLuResource(STMF_DISK, &hdl);
102 
103 	if (ret != STMF_STATUS_SUCCESS) {
104 		(void) fprintf(stderr, "%s: %s\n",
105 		    cmdName, gettext("Failure to create lu resource\n"));
106 		return (1);
107 	}
108 
109 	for (; options->optval; options++) {
110 		switch (options->optval) {
111 			case 's':
112 				ret = stmfSetLuProp(hdl, STMF_LU_PROP_SIZE,
113 				    options->optarg);
114 				if (ret != STMF_STATUS_SUCCESS) {
115 					(void) fprintf(stderr, "%s: %c: %s\n",
116 					    cmdName, options->optval,
117 					    gettext("size param invalid"));
118 					(void) stmfFreeLuResource(hdl);
119 					return (1);
120 				}
121 				break;
122 			default:
123 				(void) fprintf(stderr, "%s: %c: %s\n",
124 				    cmdName, options->optval,
125 				    gettext("unknown option"));
126 				return (1);
127 		}
128 	}
129 
130 	ret = stmfSetLuProp(hdl, STMF_LU_PROP_FILENAME, operands[0]);
131 
132 	if (ret != STMF_STATUS_SUCCESS) {
133 		(void) fprintf(stderr, "%s: %s\n",
134 		    cmdName, gettext("could not set filename"));
135 		return (1);
136 	}
137 
138 	ret = stmfCreateLu(hdl, &createdGuid);
139 	switch (ret) {
140 		case STMF_STATUS_SUCCESS:
141 			break;
142 		case STMF_ERROR_BUSY:
143 		case STMF_ERROR_LU_BUSY:
144 			(void) fprintf(stderr, "%s: %s\n", cmdName,
145 			    gettext("resource busy"));
146 			ret++;
147 			break;
148 		case STMF_ERROR_PERM:
149 			(void) fprintf(stderr, "%s: %s\n", cmdName,
150 			    gettext("permission denied"));
151 			ret++;
152 			break;
153 		case STMF_ERROR_FILE_IN_USE:
154 			(void) fprintf(stderr, "%s: filename %s: %s\n", cmdName,
155 			    operands[0], gettext("in use"));
156 			ret++;
157 			break;
158 		case STMF_ERROR_INVALID_BLKSIZE:
159 			(void) fprintf(stderr, "%s: %s\n", cmdName,
160 			    gettext("invalid block size"));
161 			ret++;
162 			break;
163 		case STMF_ERROR_GUID_IN_USE:
164 			(void) fprintf(stderr, "%s: %s\n", cmdName,
165 			    gettext("guid in use"));
166 			ret++;
167 			break;
168 		case STMF_ERROR_META_FILE_NAME:
169 			(void) fprintf(stderr, "%s: %s\n", cmdName,
170 			    gettext("meta file error"));
171 			ret++;
172 			break;
173 		case STMF_ERROR_DATA_FILE_NAME:
174 			(void) fprintf(stderr, "%s: %s\n", cmdName,
175 			    gettext("data file error"));
176 			ret++;
177 			break;
178 		case STMF_ERROR_SIZE_OUT_OF_RANGE:
179 			(void) fprintf(stderr, "%s: %s\n", cmdName,
180 			    gettext("invalid size"));
181 			ret++;
182 			break;
183 		case STMF_ERROR_META_CREATION:
184 			(void) fprintf(stderr, "%s: %s\n", cmdName,
185 			    gettext("could not create meta file"));
186 			ret++;
187 			break;
188 		default:
189 			(void) fprintf(stderr, "%s: %s\n", cmdName,
190 			    gettext("unknown error"));
191 			ret++;
192 			break;
193 	}
194 
195 	if (ret != STMF_STATUS_SUCCESS) {
196 		goto done;
197 	}
198 
199 	(void) printf("Created the following LU:\n");
200 	print_attr_header();
201 	ret = print_lu_attr(&createdGuid);
202 
203 done:
204 	(void) stmfFreeLuResource(hdl);
205 	return (ret);
206 }
207 
208 /*ARGSUSED*/
209 int
210 import_lu(int argc, char *operands[], cmdOptions_t *options, void *callData)
211 {
212 	int ret = 0;
213 	stmfGuid createdGuid;
214 
215 	ret = stmfImportLu(STMF_DISK, operands[0], &createdGuid);
216 	switch (ret) {
217 		case STMF_STATUS_SUCCESS:
218 			break;
219 		case STMF_ERROR_BUSY:
220 		case STMF_ERROR_LU_BUSY:
221 			(void) fprintf(stderr, "%s: %s\n", cmdName,
222 			    gettext("resource busy"));
223 			ret++;
224 			break;
225 		case STMF_ERROR_PERM:
226 			(void) fprintf(stderr, "%s: %s\n", cmdName,
227 			    gettext("permission denied"));
228 			ret++;
229 			break;
230 		case STMF_ERROR_FILE_IN_USE:
231 			(void) fprintf(stderr, "%s: filename %s: %s\n", cmdName,
232 			    operands[0], gettext("in use"));
233 			ret++;
234 			break;
235 		case STMF_ERROR_GUID_IN_USE:
236 			(void) fprintf(stderr, "%s: %s\n", cmdName,
237 			    gettext("guid in use"));
238 			ret++;
239 			break;
240 		case STMF_ERROR_META_FILE_NAME:
241 			(void) fprintf(stderr, "%s: %s\n", cmdName,
242 			    gettext("meta file error"));
243 			ret++;
244 			break;
245 		case STMF_ERROR_DATA_FILE_NAME:
246 			(void) fprintf(stderr, "%s: %s\n", cmdName,
247 			    gettext("data file error"));
248 			ret++;
249 			break;
250 		case STMF_ERROR_SIZE_OUT_OF_RANGE:
251 			(void) fprintf(stderr, "%s: %s\n", cmdName,
252 			    gettext("invalid size"));
253 			ret++;
254 			break;
255 		case STMF_ERROR_META_CREATION:
256 			(void) fprintf(stderr, "%s: %s\n", cmdName,
257 			    gettext("could not create meta file"));
258 			ret++;
259 			break;
260 		default:
261 			(void) fprintf(stderr, "%s: %s\n", cmdName,
262 			    gettext("unknown error"));
263 			ret++;
264 			break;
265 	}
266 
267 	if (ret != STMF_STATUS_SUCCESS) {
268 		goto done;
269 	}
270 
271 	(void) printf("Imported the following LU:\n");
272 	print_attr_header();
273 	ret = print_lu_attr(&createdGuid);
274 
275 done:
276 	return (ret);
277 }
278 
279 /*ARGSUSED*/
280 int
281 delete_lu(int operandLen, char *operands[], cmdOptions_t *options,
282     void *callData)
283 {
284 	int i, j;
285 	int ret = 0;
286 	int stmfRet;
287 	unsigned int inGuid[sizeof (stmfGuid)];
288 	stmfGuid delGuid;
289 	boolean_t keepViews = B_FALSE;
290 	boolean_t viewEntriesRemoved = B_FALSE;
291 	boolean_t noLunFound = B_FALSE;
292 	boolean_t views = B_FALSE;
293 	boolean_t notValidHexNumber = B_FALSE;
294 	char sGuid[GUID_INPUT + 1];
295 	stmfViewEntryList *viewEntryList = NULL;
296 
297 	for (; options->optval; options++) {
298 		switch (options->optval) {
299 			/* Keep views for logical unit */
300 			case 'k':
301 				keepViews = B_TRUE;
302 				break;
303 			default:
304 				(void) fprintf(stderr, "%s: %c: %s\n",
305 				    cmdName, options->optval,
306 				    gettext("unknown option"));
307 				return (1);
308 		}
309 	}
310 
311 
312 	for (i = 0; i < operandLen; i++) {
313 		for (j = 0; j < GUID_INPUT; j++) {
314 			if (!isxdigit(operands[i][j])) {
315 				notValidHexNumber = B_TRUE;
316 				break;
317 			}
318 		sGuid[j] = tolower(operands[i][j]);
319 		}
320 		if ((notValidHexNumber == B_TRUE) ||
321 		    (strlen(operands[i]) != GUID_INPUT)) {
322 			(void) fprintf(stderr, "%s: %s: %s%d%s\n",
323 			    cmdName, operands[i], gettext("must be "),
324 			    GUID_INPUT,
325 			    gettext(" hexadecimal digits long"));
326 			notValidHexNumber = B_FALSE;
327 			ret++;
328 			continue;
329 		}
330 
331 		sGuid[j] = 0;
332 
333 		(void) sscanf(sGuid,
334 		    "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
335 		    &inGuid[0], &inGuid[1], &inGuid[2], &inGuid[3],
336 		    &inGuid[4], &inGuid[5], &inGuid[6], &inGuid[7],
337 		    &inGuid[8], &inGuid[9], &inGuid[10], &inGuid[11],
338 		    &inGuid[12], &inGuid[13], &inGuid[14], &inGuid[15]);
339 
340 		for (j = 0; j < sizeof (stmfGuid); j++) {
341 			delGuid.guid[j] = inGuid[j];
342 		}
343 
344 		stmfRet = stmfDeleteLu(&delGuid);
345 		switch (stmfRet) {
346 			case STMF_STATUS_SUCCESS:
347 				break;
348 			case STMF_ERROR_NOT_FOUND:
349 				noLunFound = B_TRUE;
350 				break;
351 			case STMF_ERROR_BUSY:
352 				(void) fprintf(stderr, "%s: %s\n", cmdName,
353 				    gettext("resource busy"));
354 				ret++;
355 				break;
356 			case STMF_ERROR_PERM:
357 				(void) fprintf(stderr, "%s: %s\n", cmdName,
358 				    gettext("permission denied"));
359 				ret++;
360 				break;
361 			default:
362 				(void) fprintf(stderr, "%s: %s\n", cmdName,
363 				    gettext("unknown error"));
364 				ret++;
365 				break;
366 		}
367 
368 		if (!keepViews) {
369 			stmfRet = stmfGetViewEntryList(&delGuid,
370 			    &viewEntryList);
371 			if (stmfRet == STMF_STATUS_SUCCESS) {
372 				for (j = 0; j < viewEntryList->cnt; j++) {
373 					(void) stmfRemoveViewEntry(&delGuid,
374 					    viewEntryList->ve[j].veIndex);
375 				}
376 				/* check if viewEntryList is empty */
377 				if (viewEntryList->cnt != 0)
378 					viewEntriesRemoved = B_TRUE;
379 				stmfFreeMemory(viewEntryList);
380 			} else {
381 				(void) fprintf(stderr, "%s: %s\n", cmdName,
382 				    gettext("unable to remove view entries\n"));
383 				ret++;
384 			}
385 		}
386 		if (keepViews) {
387 			stmfRet = stmfGetViewEntryList(&delGuid,
388 			    &viewEntryList);
389 			if (stmfRet == STMF_STATUS_SUCCESS) {
390 				views = B_TRUE;
391 				stmfFreeMemory(viewEntryList);
392 			}
393 		}
394 
395 		if ((!viewEntriesRemoved && noLunFound && !views) ||
396 		    (!views && keepViews && noLunFound)) {
397 			(void) fprintf(stderr, "%s: %s: %s\n",
398 			    cmdName, sGuid,
399 			    gettext("not found"));
400 			ret++;
401 		}
402 		noLunFound = viewEntriesRemoved = views = B_FALSE;
403 	}
404 	return (ret);
405 }
406 
407 /*ARGSUSED*/
408 int
409 modify_lu(int operandLen, char *operands[], cmdOptions_t *options,
410     void *callData)
411 {
412 	stmfGuid inGuid;
413 	unsigned int guid[sizeof (stmfGuid)];
414 	int ret = 0;
415 	int i;
416 	char *fname = NULL;
417 	char sGuid[GUID_INPUT + 1];
418 	boolean_t fnameUsed = B_FALSE;
419 
420 	if (operands[0][0] == '/') {
421 		fnameUsed = B_TRUE;
422 		fname = operands[0];
423 	}
424 
425 	/* check input length */
426 	if (!fnameUsed && strlen(operands[0]) != GUID_INPUT) {
427 		(void) fprintf(stderr, "%s: %s: %s%d%s\n", cmdName, operands[0],
428 		    gettext("must be "), GUID_INPUT,
429 		    gettext(" hexadecimal digits"));
430 		return (1);
431 	}
432 
433 	if (!fnameUsed) {
434 		/* convert to lower case for scan */
435 		for (i = 0; i < 32; i++)
436 			sGuid[i] = tolower(operands[0][i]);
437 		sGuid[i] = 0;
438 		(void) sscanf(sGuid,
439 		    "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
440 		    &guid[0], &guid[1], &guid[2], &guid[3], &guid[4], &guid[5],
441 		    &guid[6], &guid[7], &guid[8], &guid[9], &guid[10],
442 		    &guid[11], &guid[12], &guid[13], &guid[14], &guid[15]);
443 
444 		for (i = 0; i < sizeof (stmfGuid); i++) {
445 			inGuid.guid[i] = guid[i];
446 		}
447 	}
448 
449 	for (; options->optval; options++) {
450 		switch (options->optval) {
451 			case 's':
452 				if (callModify(fname, &inGuid,
453 				    STMF_LU_PROP_SIZE, options->optarg,
454 				    "size") != 0) {
455 					return (1);
456 				}
457 				break;
458 			default:
459 				(void) fprintf(stderr, "%s: %c: %s\n",
460 				    cmdName, options->optval,
461 				    gettext("unknown option"));
462 				return (1);
463 		}
464 	}
465 	return (ret);
466 }
467 
468 static int
469 callModify(char *fname, stmfGuid *luGuid, uint32_t prop, const char *propVal,
470     const char *propString)
471 {
472 	int ret = 0;
473 	int stmfRet = 0;
474 
475 	if (!fname) {
476 		stmfRet = stmfModifyLu(luGuid, prop, propVal);
477 	} else {
478 		stmfRet = stmfModifyLuByFname(STMF_DISK, fname, prop,
479 		    propVal);
480 	}
481 	switch (stmfRet) {
482 		case STMF_STATUS_SUCCESS:
483 			break;
484 		case STMF_ERROR_BUSY:
485 		case STMF_ERROR_LU_BUSY:
486 			(void) fprintf(stderr, "%s: %s\n", cmdName,
487 			    gettext("resource busy"));
488 			ret++;
489 			break;
490 		case STMF_ERROR_PERM:
491 			(void) fprintf(stderr, "%s: %s\n", cmdName,
492 			    gettext("permission denied"));
493 			ret++;
494 			break;
495 		case STMF_ERROR_INVALID_BLKSIZE:
496 			(void) fprintf(stderr, "%s: %s\n", cmdName,
497 			    gettext("invalid block size"));
498 			ret++;
499 			break;
500 		case STMF_ERROR_GUID_IN_USE:
501 			(void) fprintf(stderr, "%s: %s\n", cmdName,
502 			    gettext("guid in use"));
503 			ret++;
504 			break;
505 		case STMF_ERROR_META_FILE_NAME:
506 			(void) fprintf(stderr, "%s: %s\n", cmdName,
507 			    gettext("meta file error"));
508 			ret++;
509 			break;
510 		case STMF_ERROR_DATA_FILE_NAME:
511 			(void) fprintf(stderr, "%s: %s\n", cmdName,
512 			    gettext("data file error"));
513 			ret++;
514 			break;
515 		case STMF_ERROR_FILE_SIZE_INVALID:
516 			(void) fprintf(stderr, "%s: %s\n", cmdName,
517 			    gettext("file size invalid"));
518 			ret++;
519 			break;
520 		case STMF_ERROR_SIZE_OUT_OF_RANGE:
521 			(void) fprintf(stderr, "%s: %s\n", cmdName,
522 			    gettext("invalid size"));
523 			ret++;
524 			break;
525 		case STMF_ERROR_META_CREATION:
526 			(void) fprintf(stderr, "%s: %s\n", cmdName,
527 			    gettext("could not create meta file"));
528 			ret++;
529 			break;
530 		default:
531 			(void) fprintf(stderr, "%s: %s: %s: %d\n", cmdName,
532 			    gettext("could not set property"), propString,
533 			    stmfRet);
534 			ret++;
535 			break;
536 	}
537 
538 	return (ret);
539 }
540 
541 
542 /*ARGSUSED*/
543 int
544 list_lus(int argc, char *argv[], cmdOptions_t *options, void *callData)
545 {
546 	int stmfRet;
547 	stmfGuidList *luList;
548 	stmfLogicalUnitProperties luProps;
549 	int sbdLuCnt = 0;
550 	int i;
551 
552 	if ((stmfRet = stmfGetLogicalUnitList(&luList))
553 	    != STMF_STATUS_SUCCESS) {
554 		switch (stmfRet) {
555 			case STMF_ERROR_SERVICE_NOT_FOUND:
556 				(void) fprintf(stderr, "%s: %s\n", cmdName,
557 				    gettext("STMF service not found"));
558 				break;
559 			case STMF_ERROR_BUSY:
560 				(void) fprintf(stderr, "%s: %s\n", cmdName,
561 				    gettext("resource busy"));
562 				break;
563 			case STMF_ERROR_PERM:
564 				(void) fprintf(stderr, "%s: %s\n", cmdName,
565 				    gettext("permission denied"));
566 				break;
567 			case STMF_ERROR_SERVICE_DATA_VERSION:
568 				(void) fprintf(stderr, "%s: %s\n", cmdName,
569 				    gettext("STMF service version incorrect"));
570 				break;
571 			default:
572 				(void) fprintf(stderr, "%s: %s\n", cmdName,
573 				    gettext("list failed"));
574 				break;
575 		}
576 		return (1);
577 	}
578 
579 	for (i = 0; i < luList->cnt; i++) {
580 		stmfRet = stmfGetLogicalUnitProperties(&luList->guid[i],
581 		    &luProps);
582 		if (stmfRet != STMF_STATUS_SUCCESS) {
583 			(void) fprintf(stderr, "%s: %s\n", cmdName,
584 			    gettext("list failed"));
585 			return (1);
586 		}
587 		if (strcmp(luProps.providerName, "sbd") == 0) {
588 			sbdLuCnt++;
589 		}
590 	}
591 
592 
593 	if (sbdLuCnt == 0)
594 		return (0);
595 
596 	(void) printf("\nFound %d LU(s)\n", sbdLuCnt);
597 	print_attr_header();
598 
599 	for (i = 0; i < luList->cnt; i++) {
600 		stmfRet = stmfGetLogicalUnitProperties(&luList->guid[i],
601 		    &luProps);
602 		if (stmfRet != STMF_STATUS_SUCCESS) {
603 			(void) fprintf(stderr, "%s: %s\n", cmdName,
604 			    gettext("list failed"));
605 			return (1);
606 		}
607 		if (strcmp(luProps.providerName, "sbd") == 0) {
608 			(void) print_lu_attr(&luList->guid[i]);
609 		}
610 	}
611 	return (0);
612 }
613 
614 void
615 print_attr_header()
616 {
617 	(void) printf("\n");
618 	(void) printf("	      GUID                    DATA SIZE      "
619 	    "     SOURCE\n");
620 	(void) printf("--------------------------------  -------------------"
621 	    "  ----------------\n");
622 }
623 
624 void
625 print_guid(uint8_t *g, FILE *f)
626 {
627 	int i;
628 
629 	for (i = 0; i < 16; i++) {
630 		(void) fprintf(f, "%02x", g[i]);
631 	}
632 }
633 
634 int
635 print_lu_attr(stmfGuid *guid)
636 {
637 	luResource hdl = NULL;
638 	int stmfRet = 0;
639 	int ret = 0;
640 	char propVal[MAXPATHLEN];
641 	size_t propValSize = sizeof (propVal);
642 
643 	if ((stmfRet = stmfGetLuResource(guid, &hdl)) != STMF_STATUS_SUCCESS) {
644 		switch (stmfRet) {
645 			case STMF_ERROR_BUSY:
646 				(void) fprintf(stderr, "%s: %s\n", cmdName,
647 				    gettext("resource busy"));
648 				break;
649 			case STMF_ERROR_PERM:
650 				(void) fprintf(stderr, "%s: %s\n", cmdName,
651 				    gettext("permission denied"));
652 				break;
653 			case STMF_ERROR_NOT_FOUND:
654 				/* No error here */
655 				return (0);
656 				break;
657 			default:
658 				(void) fprintf(stderr, "%s: %s\n", cmdName,
659 				    gettext("get extended properties failed"));
660 				break;
661 		}
662 		return (1);
663 	}
664 
665 	print_guid((uint8_t *)guid, stdout);
666 
667 	stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_SIZE, propVal,
668 	    &propValSize);
669 	if (stmfRet == STMF_STATUS_SUCCESS) {
670 		(void) printf("  %-19s  ", propVal);
671 	} else if (stmfRet == STMF_ERROR_NO_PROP) {
672 		(void) printf("not set\n");
673 	} else {
674 		(void) printf("<error retrieving property>\n");
675 		ret++;
676 	}
677 
678 	stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_FILENAME, propVal,
679 	    &propValSize);
680 	if (stmfRet == STMF_STATUS_SUCCESS) {
681 		(void) printf("%s\n", propVal);
682 	} else if (stmfRet == STMF_ERROR_NO_PROP) {
683 		(void) printf("not set\n");
684 	} else {
685 		(void) printf("<error retrieving property>\n");
686 		ret++;
687 	}
688 
689 
690 	(void) stmfFreeLuResource(hdl);
691 	return (ret);
692 }
693 
694 /*
695  * input:
696  *  execFullName - exec name of program (argv[0])
697  *
698  *  copied from usr/src/cmd/zoneadm/zoneadm.c in OS/Net
699  *  (changed name to lowerCamelCase to keep consistent with this file)
700  *
701  * Returns:
702  *  command name portion of execFullName
703  */
704 static char *
705 getExecBasename(char *execFullname)
706 {
707 	char *lastSlash, *execBasename;
708 
709 	/* guard against '/' at end of command invocation */
710 	for (;;) {
711 		lastSlash = strrchr(execFullname, '/');
712 		if (lastSlash == NULL) {
713 			execBasename = execFullname;
714 			break;
715 		} else {
716 			execBasename = lastSlash + 1;
717 			if (*execBasename == '\0') {
718 				*lastSlash = '\0';
719 				continue;
720 			}
721 			break;
722 		}
723 	}
724 	return (execBasename);
725 }
726 int
727 main(int argc, char *argv[])
728 {
729 	synTables_t synTables;
730 	char versionString[VERSION_STRING_MAX_LEN];
731 	int ret;
732 	int funcRet;
733 	void *subcommandArgs = NULL;
734 
735 	(void) setlocale(LC_ALL, "");
736 	(void) textdomain(TEXT_DOMAIN);
737 	/* set global command name */
738 	cmdName = getExecBasename(argv[0]);
739 
740 	(void) snprintf(versionString, VERSION_STRING_MAX_LEN, "%s.%s",
741 	    VERSION_STRING_MAJOR, VERSION_STRING_MINOR);
742 	synTables.versionString = versionString;
743 	synTables.longOptionTbl = options;
744 	synTables.subCommandPropsTbl = subCommands;
745 
746 	ret = cmdParse(argc, argv, synTables, subcommandArgs, &funcRet);
747 	if (ret != 0) {
748 		return (ret);
749 	}
750 
751 	return (funcRet);
752 } /* end main */
753