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 */