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