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, 0, 0, NULL, 0, NULL}
  93 };
  94 
  95 /*ARGSUSED*/
  96 int
  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
 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
 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
 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
 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
 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
 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
 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
 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 *
 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
 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 */