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