xref: /illumos-gate/usr/src/cmd/sbdadm/sbdadm.c (revision 46b592853d0f4f11781b6b0a7533f267c6aee132)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 #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 	char sGuid[GUID_INPUT + 1];
294 	stmfViewEntryList *viewEntryList = NULL;
295 
296 	for (; options->optval; options++) {
297 		switch (options->optval) {
298 			/* Keep views for logical unit */
299 			case 'k':
300 				keepViews = B_TRUE;
301 				break;
302 			default:
303 				(void) fprintf(stderr, "%s: %c: %s\n",
304 				    cmdName, options->optval,
305 				    gettext("unknown option"));
306 				return (1);
307 		}
308 	}
309 
310 
311 	for (i = 0; i < operandLen; i++) {
312 		for (j = 0; j < GUID_INPUT; j++) {
313 			if (!isxdigit(operands[i][j])) {
314 				break;
315 			}
316 			sGuid[j] = tolower(operands[i][j]);
317 		}
318 		if (j != GUID_INPUT) {
319 			(void) fprintf(stderr, "%s: %s: %s%d%s\n",
320 			    cmdName, operands[i], gettext("must be "),
321 			    GUID_INPUT,
322 			    gettext(" hexadecimal digits long"));
323 			ret++;
324 			continue;
325 		}
326 
327 		sGuid[j] = 0;
328 
329 		(void) sscanf(sGuid,
330 		    "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
331 		    &inGuid[0], &inGuid[1], &inGuid[2], &inGuid[3],
332 		    &inGuid[4], &inGuid[5], &inGuid[6], &inGuid[7],
333 		    &inGuid[8], &inGuid[9], &inGuid[10], &inGuid[11],
334 		    &inGuid[12], &inGuid[13], &inGuid[14], &inGuid[15]);
335 
336 		for (j = 0; j < sizeof (stmfGuid); j++) {
337 			delGuid.guid[j] = inGuid[j];
338 		}
339 
340 		stmfRet = stmfDeleteLu(&delGuid);
341 		switch (stmfRet) {
342 			case STMF_STATUS_SUCCESS:
343 				break;
344 			case STMF_ERROR_NOT_FOUND:
345 				noLunFound = B_TRUE;
346 				break;
347 			case STMF_ERROR_BUSY:
348 				(void) fprintf(stderr, "%s: %s\n", cmdName,
349 				    gettext("resource busy"));
350 				ret++;
351 				break;
352 			case STMF_ERROR_PERM:
353 				(void) fprintf(stderr, "%s: %s\n", cmdName,
354 				    gettext("permission denied"));
355 				ret++;
356 				break;
357 			default:
358 				(void) fprintf(stderr, "%s: %s\n", cmdName,
359 				    gettext("unknown error"));
360 				ret++;
361 				break;
362 		}
363 
364 		if (!keepViews) {
365 			stmfRet = stmfGetViewEntryList(&delGuid,
366 			    &viewEntryList);
367 			if (stmfRet == STMF_STATUS_SUCCESS) {
368 				for (j = 0; j < viewEntryList->cnt; j++) {
369 					(void) stmfRemoveViewEntry(&delGuid,
370 					    viewEntryList->ve[j].veIndex);
371 				}
372 				viewEntriesRemoved = B_TRUE;
373 				stmfFreeMemory(viewEntryList);
374 			} else if (stmfRet != STMF_ERROR_NOT_FOUND) {
375 				(void) fprintf(stderr, "%s: %s\n", cmdName,
376 				    gettext("unable to remove view entries\n"));
377 				ret++;
378 			} /* No view entries to remove */
379 		}
380 		if (keepViews) {
381 			stmfRet = stmfGetViewEntryList(&delGuid,
382 			    &viewEntryList);
383 			if (stmfRet == STMF_STATUS_SUCCESS) {
384 				views = B_TRUE;
385 				stmfFreeMemory(viewEntryList);
386 			}
387 		}
388 
389 		if ((!viewEntriesRemoved && noLunFound && !views) ||
390 		    (!views && keepViews && noLunFound)) {
391 			(void) fprintf(stderr, "%s: %s: %s\n",
392 			    cmdName, sGuid,
393 			    gettext("not found"));
394 			ret++;
395 		}
396 		noLunFound = viewEntriesRemoved = views = B_FALSE;
397 	}
398 	return (ret);
399 }
400 
401 /*ARGSUSED*/
402 int
403 modify_lu(int operandLen, char *operands[], cmdOptions_t *options,
404     void *callData)
405 {
406 	stmfGuid inGuid;
407 	unsigned int guid[sizeof (stmfGuid)];
408 	int ret = 0;
409 	int i;
410 	char *fname = NULL;
411 	char sGuid[GUID_INPUT + 1];
412 	boolean_t fnameUsed = B_FALSE;
413 
414 	if (operands[0][0] == '/') {
415 		fnameUsed = B_TRUE;
416 		fname = operands[0];
417 	}
418 
419 	/* check input length */
420 	if (!fnameUsed && strlen(operands[0]) != GUID_INPUT) {
421 		(void) fprintf(stderr, "%s: %s: %s%d%s\n", cmdName, operands[0],
422 		    gettext("must be "), GUID_INPUT,
423 		    gettext(" hexadecimal digits"));
424 		return (1);
425 	}
426 
427 	if (!fnameUsed) {
428 		/* convert to lower case for scan */
429 		for (i = 0; i < 32; i++)
430 			sGuid[i] = tolower(operands[0][i]);
431 		sGuid[i] = 0;
432 		(void) sscanf(sGuid,
433 		    "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
434 		    &guid[0], &guid[1], &guid[2], &guid[3], &guid[4], &guid[5],
435 		    &guid[6], &guid[7], &guid[8], &guid[9], &guid[10],
436 		    &guid[11], &guid[12], &guid[13], &guid[14], &guid[15]);
437 
438 		for (i = 0; i < sizeof (stmfGuid); i++) {
439 			inGuid.guid[i] = guid[i];
440 		}
441 	}
442 
443 	for (; options->optval; options++) {
444 		switch (options->optval) {
445 			case 's':
446 				if (callModify(fname, &inGuid,
447 				    STMF_LU_PROP_SIZE, options->optarg,
448 				    "size") != 0) {
449 					return (1);
450 				}
451 				break;
452 			default:
453 				(void) fprintf(stderr, "%s: %c: %s\n",
454 				    cmdName, options->optval,
455 				    gettext("unknown option"));
456 				return (1);
457 		}
458 	}
459 	return (ret);
460 }
461 
462 static int
463 callModify(char *fname, stmfGuid *luGuid, uint32_t prop, const char *propVal,
464     const char *propString)
465 {
466 	int ret = 0;
467 	int stmfRet = 0;
468 
469 	if (!fname) {
470 		stmfRet = stmfModifyLu(luGuid, prop, propVal);
471 	} else {
472 		stmfRet = stmfModifyLuByFname(STMF_DISK, fname, prop,
473 		    propVal);
474 	}
475 	switch (stmfRet) {
476 		case STMF_STATUS_SUCCESS:
477 			break;
478 		case STMF_ERROR_BUSY:
479 		case STMF_ERROR_LU_BUSY:
480 			(void) fprintf(stderr, "%s: %s\n", cmdName,
481 			    gettext("resource busy"));
482 			ret++;
483 			break;
484 		case STMF_ERROR_PERM:
485 			(void) fprintf(stderr, "%s: %s\n", cmdName,
486 			    gettext("permission denied"));
487 			ret++;
488 			break;
489 		case STMF_ERROR_INVALID_BLKSIZE:
490 			(void) fprintf(stderr, "%s: %s\n", cmdName,
491 			    gettext("invalid block size"));
492 			ret++;
493 			break;
494 		case STMF_ERROR_GUID_IN_USE:
495 			(void) fprintf(stderr, "%s: %s\n", cmdName,
496 			    gettext("guid in use"));
497 			ret++;
498 			break;
499 		case STMF_ERROR_META_FILE_NAME:
500 			(void) fprintf(stderr, "%s: %s\n", cmdName,
501 			    gettext("meta file error"));
502 			ret++;
503 			break;
504 		case STMF_ERROR_DATA_FILE_NAME:
505 			(void) fprintf(stderr, "%s: %s\n", cmdName,
506 			    gettext("data file error"));
507 			ret++;
508 			break;
509 		case STMF_ERROR_FILE_SIZE_INVALID:
510 			(void) fprintf(stderr, "%s: %s\n", cmdName,
511 			    gettext("file size invalid"));
512 			ret++;
513 			break;
514 		case STMF_ERROR_SIZE_OUT_OF_RANGE:
515 			(void) fprintf(stderr, "%s: %s\n", cmdName,
516 			    gettext("invalid size"));
517 			ret++;
518 			break;
519 		case STMF_ERROR_META_CREATION:
520 			(void) fprintf(stderr, "%s: %s\n", cmdName,
521 			    gettext("could not create meta file"));
522 			ret++;
523 			break;
524 		default:
525 			(void) fprintf(stderr, "%s: %s: %s: %d\n", cmdName,
526 			    gettext("could not set property"), propString,
527 			    stmfRet);
528 			ret++;
529 			break;
530 	}
531 
532 	return (ret);
533 }
534 
535 
536 /*ARGSUSED*/
537 int
538 list_lus(int argc, char *argv[], cmdOptions_t *options, void *callData)
539 {
540 	int stmfRet;
541 	stmfGuidList *luList;
542 	stmfLogicalUnitProperties luProps;
543 	int sbdLuCnt = 0;
544 	int i;
545 
546 	if ((stmfRet = stmfGetLogicalUnitList(&luList))
547 	    != STMF_STATUS_SUCCESS) {
548 		switch (stmfRet) {
549 			case STMF_ERROR_SERVICE_NOT_FOUND:
550 				(void) fprintf(stderr, "%s: %s\n", cmdName,
551 				    gettext("STMF service not found"));
552 				break;
553 			case STMF_ERROR_BUSY:
554 				(void) fprintf(stderr, "%s: %s\n", cmdName,
555 				    gettext("resource busy"));
556 				break;
557 			case STMF_ERROR_PERM:
558 				(void) fprintf(stderr, "%s: %s\n", cmdName,
559 				    gettext("permission denied"));
560 				break;
561 			case STMF_ERROR_SERVICE_DATA_VERSION:
562 				(void) fprintf(stderr, "%s: %s\n", cmdName,
563 				    gettext("STMF service version incorrect"));
564 				break;
565 			default:
566 				(void) fprintf(stderr, "%s: %s\n", cmdName,
567 				    gettext("list failed"));
568 				break;
569 		}
570 		return (1);
571 	}
572 
573 	for (i = 0; i < luList->cnt; i++) {
574 		stmfRet = stmfGetLogicalUnitProperties(&luList->guid[i],
575 		    &luProps);
576 		if (stmfRet != STMF_STATUS_SUCCESS) {
577 			(void) fprintf(stderr, "%s: %s\n", cmdName,
578 			    gettext("list failed"));
579 			return (1);
580 		}
581 		if (strcmp(luProps.providerName, "sbd") == 0) {
582 			sbdLuCnt++;
583 		}
584 	}
585 
586 
587 	if (sbdLuCnt == 0)
588 		return (0);
589 
590 	(void) printf("\nFound %d LU(s)\n", sbdLuCnt);
591 	print_attr_header();
592 
593 	for (i = 0; i < luList->cnt; i++) {
594 		stmfRet = stmfGetLogicalUnitProperties(&luList->guid[i],
595 		    &luProps);
596 		if (stmfRet != STMF_STATUS_SUCCESS) {
597 			(void) fprintf(stderr, "%s: %s\n", cmdName,
598 			    gettext("list failed"));
599 			return (1);
600 		}
601 		if (strcmp(luProps.providerName, "sbd") == 0) {
602 			(void) print_lu_attr(&luList->guid[i]);
603 		}
604 	}
605 	return (0);
606 }
607 
608 void
609 print_attr_header()
610 {
611 	(void) printf("\n");
612 	(void) printf("	      GUID                    DATA SIZE      "
613 	    "     SOURCE\n");
614 	(void) printf("--------------------------------  -------------------"
615 	    "  ----------------\n");
616 }
617 
618 void
619 print_guid(uint8_t *g, FILE *f)
620 {
621 	int i;
622 
623 	for (i = 0; i < 16; i++) {
624 		(void) fprintf(f, "%02x", g[i]);
625 	}
626 }
627 
628 int
629 print_lu_attr(stmfGuid *guid)
630 {
631 	luResource hdl = NULL;
632 	int stmfRet = 0;
633 	int ret = 0;
634 	char propVal[MAXPATHLEN];
635 	size_t propValSize = sizeof (propVal);
636 
637 	if ((stmfRet = stmfGetLuResource(guid, &hdl)) != STMF_STATUS_SUCCESS) {
638 		switch (stmfRet) {
639 			case STMF_ERROR_BUSY:
640 				(void) fprintf(stderr, "%s: %s\n", cmdName,
641 				    gettext("resource busy"));
642 				break;
643 			case STMF_ERROR_PERM:
644 				(void) fprintf(stderr, "%s: %s\n", cmdName,
645 				    gettext("permission denied"));
646 				break;
647 			case STMF_ERROR_NOT_FOUND:
648 				/* No error here */
649 				return (0);
650 				break;
651 			default:
652 				(void) fprintf(stderr, "%s: %s\n", cmdName,
653 				    gettext("get extended properties failed"));
654 				break;
655 		}
656 		return (1);
657 	}
658 
659 	print_guid((uint8_t *)guid, stdout);
660 
661 	stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_SIZE, propVal,
662 	    &propValSize);
663 	if (stmfRet == STMF_STATUS_SUCCESS) {
664 		(void) printf("  %-19s  ", propVal);
665 	} else if (stmfRet == STMF_ERROR_NO_PROP) {
666 		(void) printf("not set\n");
667 	} else {
668 		(void) printf("<error retrieving property>\n");
669 		ret++;
670 	}
671 
672 	stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_FILENAME, propVal,
673 	    &propValSize);
674 	if (stmfRet == STMF_STATUS_SUCCESS) {
675 		(void) printf("%s\n", propVal);
676 	} else if (stmfRet == STMF_ERROR_NO_PROP) {
677 		(void) printf("not set\n");
678 	} else {
679 		(void) printf("<error retrieving property>\n");
680 		ret++;
681 	}
682 
683 
684 	(void) stmfFreeLuResource(hdl);
685 	return (ret);
686 }
687 
688 /*
689  * input:
690  *  execFullName - exec name of program (argv[0])
691  *
692  *  copied from usr/src/cmd/zoneadm/zoneadm.c in OS/Net
693  *  (changed name to lowerCamelCase to keep consistent with this file)
694  *
695  * Returns:
696  *  command name portion of execFullName
697  */
698 static char *
699 getExecBasename(char *execFullname)
700 {
701 	char *lastSlash, *execBasename;
702 
703 	/* guard against '/' at end of command invocation */
704 	for (;;) {
705 		lastSlash = strrchr(execFullname, '/');
706 		if (lastSlash == NULL) {
707 			execBasename = execFullname;
708 			break;
709 		} else {
710 			execBasename = lastSlash + 1;
711 			if (*execBasename == '\0') {
712 				*lastSlash = '\0';
713 				continue;
714 			}
715 			break;
716 		}
717 	}
718 	return (execBasename);
719 }
720 int
721 main(int argc, char *argv[])
722 {
723 	synTables_t synTables;
724 	char versionString[VERSION_STRING_MAX_LEN];
725 	int ret;
726 	int funcRet;
727 	void *subcommandArgs = NULL;
728 
729 	(void) setlocale(LC_ALL, "");
730 	(void) textdomain(TEXT_DOMAIN);
731 	/* set global command name */
732 	cmdName = getExecBasename(argv[0]);
733 
734 	(void) snprintf(versionString, VERSION_STRING_MAX_LEN, "%s.%s",
735 	    VERSION_STRING_MAJOR, VERSION_STRING_MINOR);
736 	synTables.versionString = versionString;
737 	synTables.longOptionTbl = options;
738 	synTables.subCommandPropsTbl = subCommands;
739 
740 	ret = cmdParse(argc, argv, synTables, subcommandArgs, &funcRet);
741 	if (ret != 0) {
742 		return (ret);
743 	}
744 
745 	return (funcRet);
746 } /* end main */
747