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
create_lu(int argc,char * operands[],cmdOptions_t * options,void * callData)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
import_lu(int argc,char * operands[],cmdOptions_t * options,void * callData)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
delete_lu(int operandLen,char * operands[],cmdOptions_t * options,void * callData)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
modify_lu(int operandLen,char * operands[],cmdOptions_t * options,void * callData)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
callModify(char * fname,stmfGuid * luGuid,uint32_t prop,const char * propVal,const char * propString)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
list_lus(int argc,char * argv[],cmdOptions_t * options,void * callData)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
print_attr_header()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
print_guid(uint8_t * g,FILE * f)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
print_lu_attr(stmfGuid * guid)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 *
getExecBasename(char * execFullname)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
main(int argc,char * argv[])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