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 /*
  23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 #include <limits.h>
  28 #include <stdio.h>
  29 #include <stdlib.h>
  30 #include <string.h>
  31 #include <libintl.h>
  32 #include <libfru.h>
  33 #include <errno.h>
  34 #include <math.h>
  35 #include <alloca.h>
  36 #include <assert.h>
  37 #include <sys/systeminfo.h>
  38 
  39 #define NUM_OF_SEGMENT  1
  40 #define SEGMENT_NAME_SIZE       2
  41 
  42 #define FD_SEGMENT_SIZE 2949
  43 
  44 static char  *command, *customer_data = NULL, *frupath = NULL, **svcargv;
  45 
  46 /* DataElement supported in the customer operation */
  47 static  char    *cust_data_list[] = {"Customer_DataR"};
  48 
  49 /* DataElement supported in the service operation */
  50 static  char    *serv_data_list[] = {"InstallationR", "ECO_CurrentR"};
  51 
  52 /* currently supported segment name */
  53 static  char    *segment_name[] = {"FD"};
  54 
  55 static int   found_frupath = 0, list_only = 0, recursive = 0,
  56     service_mode = 0, svcargc, update = 0;
  57 
  58 
  59 static void
  60 usage(void)
  61 {
  62         (void) fprintf(stderr,
  63             gettext("Usage:  %s [ -l ] | [ [ -r ] frupath [ text ] ]\n"),
  64             command);
  65 }
  66 
  67 static int
  68 validate_fieldnames(int argc, char *argv[])
  69 {
  70         static int      num = sizeof (serv_data_list)/sizeof (*serv_data_list);
  71 
  72         char            *fieldname;
  73 
  74         int             i, j, match, status;
  75 
  76         fru_elemdef_t   definition;
  77 
  78 
  79         for (i = 0; i < argc; i += 2) {
  80                 if (argv[i][0] == '/') {
  81                         fieldname = &argv[i][1];
  82                 } else {
  83                         fieldname = &argv[i][0];
  84                 }
  85 
  86                 match = 0;
  87                 for (j = 0; j < num; j++) {
  88                         if (strncmp(fieldname, serv_data_list[j],
  89                             strlen(serv_data_list[j])) == 0) {
  90                                 match = 1;
  91                         }
  92                 }
  93                 if (!match) {
  94                         (void) fprintf(stderr,
  95                             gettext("\"%s\" is not a supported field\n"),
  96                             argv[i]);
  97                         return (1);
  98                 }
  99 
 100                 if ((status = fru_get_definition(argv[i], &definition))
 101                     != FRU_SUCCESS) {
 102                         (void) fprintf(stderr, gettext("\"%s\":  %s\n"),
 103                             argv[i],
 104                             fru_strerror(status));
 105                         return (1);
 106                 } else if ((definition.data_type == FDTYPE_Record) ||
 107                     (definition.data_type == FDTYPE_UNDEFINED)) {
 108                         (void) fprintf(stderr,
 109                             gettext("\"%s\" is not a field\n"), argv[i]);
 110                         return (1);
 111                 }
 112         }
 113 
 114         return (0);
 115 }
 116 
 117 static int
 118 pathmatch(const char *path)
 119 {
 120         char  *match;
 121 
 122         if ((frupath != NULL) &&
 123             ((match = strstr(path, frupath)) != NULL) &&
 124             ((match + strlen(frupath)) == (path + strlen(path))) &&
 125             ((match == path) || (*(match - 1) == '/'))) {
 126                 found_frupath = 1;
 127                 return (1);
 128         }
 129         return (0);
 130 }
 131 
 132 static void
 133 displayBinary(unsigned char *data, size_t length, fru_elemdef_t *def)
 134 {
 135         int     i = 0;
 136         uint64_t        lldata;
 137         uint64_t        mask;
 138 
 139         if (def->disp_type == FDISP_Hex) {
 140                 for (i = 0; i < length; i++) {
 141                         (void) printf("%02X", data[i]);
 142                 }
 143                 return;
 144         }
 145 
 146         (void) memcpy(&lldata, data, sizeof (lldata));
 147         switch (def->disp_type) {
 148                 case FDISP_Binary:
 149                 {
 150                         mask = 0x8000000000000000ULL;
 151                         for (i = 0; i < (sizeof (uint64_t) *8); i++) {
 152                                 if (lldata & (mask >> i)) {
 153                                         (void) printf("1");
 154                                 } else {
 155                                         (void) printf("0");
 156                                 }
 157                         }
 158                         return;
 159                 }
 160                 case FDISP_Octal:
 161                 {
 162                         (void) printf("%llo", lldata);
 163                         return;
 164                 }
 165                 case FDISP_Decimal:
 166                 {
 167                         (void) printf("%lld", lldata);
 168                         return;
 169                 }
 170                 case FDISP_Time:
 171                 {
 172                         char buffer[PATH_MAX];
 173                         time_t time;
 174                         time = (time_t)lldata;
 175                         (void) strftime(buffer, PATH_MAX, "%C",
 176                             localtime(&time));
 177                         (void) printf("%s", buffer);
 178                         return;
 179                 }
 180         }
 181 }
 182 
 183 static void
 184 displayBAasBinary(unsigned char *data, size_t length)
 185 {
 186         int i;
 187         unsigned char mask;
 188 
 189         for (i = 0; i < length; i++) {
 190                 /*
 191                  * make a mask for the high order bit and adjust down through
 192                  * all the bits.
 193                  */
 194                 for (mask = 0x80; mask > 0; mask /= 2) {
 195                         if ((data[i] & mask) != 0) /* bit must be on */
 196                                 (void) printf("1");
 197                         else /* bit is off... */
 198                                 (void) printf("0");
 199                 }
 200         }
 201         (void) printf("\n");
 202 }
 203 
 204 static void
 205 display_data(unsigned char *data, size_t length, fru_elemdef_t *def)
 206 {
 207         int i = 0;
 208         uint64_t        lldata;
 209 
 210         if (data == 0x00) {
 211                 (void) printf("\n");
 212                 return;
 213         }
 214 
 215         switch (def->data_type) {
 216         case FDTYPE_Binary:
 217         {
 218                 displayBinary(data, length, def);
 219                 return;
 220         }
 221 
 222         case FDTYPE_ByteArray:
 223         {
 224                 switch (def->disp_type) {
 225                 case FDISP_Binary:
 226                         displayBAasBinary(data, length);
 227                         return;
 228                 case FDISP_Hex:
 229                         for (i = 0; i < length; i++) {
 230                                 (void) printf("%02X", data[i]);
 231                         }
 232                         return;
 233                 }
 234                 return;
 235         }
 236         case FDTYPE_Unicode:
 237                 assert(gettext("Unicode not yet supported") == 0);
 238                 break;
 239         case FDTYPE_ASCII:
 240         {
 241                 char *disp_str = (char *)alloca(length+1);
 242                 for (i = 0; i < length; i++)
 243                         disp_str[i] = data[i];
 244                         disp_str[i] = '\0';
 245                         (void) printf("%s", disp_str);
 246                         return;
 247         }
 248 
 249         case FDTYPE_Enumeration:
 250         {
 251                 lldata = strtoull((const char *)data, NULL, 0);
 252                 for (i = 0; i < def->enum_count; i++) {
 253                         if (def->enum_table[i].value == lldata) {
 254                         /* strdup such that map_... can realloc if necessary. */
 255                                 char *tmp = strdup(def->enum_table[i].text);
 256                                 (void) printf("%s", tmp);
 257                                 free(tmp);
 258                                 return;
 259                         }
 260                 }
 261                 (void) printf(gettext("Unrecognized Value:  0x"));
 262                 for (i = 0; i < sizeof (uint64_t); i++)
 263                         (void) printf("%02X", data[i]);
 264                 break;
 265         }
 266         default:
 267                 break;
 268         }
 269 }
 270 
 271 static void
 272 print_node_data(fru_nodehdl_t cont_hdl)
 273 {
 274         int     iter_cnt = 0;
 275         int     iter;
 276         int     numseg;
 277         int     list_cnt;
 278         unsigned char   *data;
 279         size_t  dataLen;
 280         int     total_cnt;
 281         char    *found_path = NULL;
 282         fru_elemdef_t    def, def1;
 283         int     instance = 0;
 284         char    **ptr;
 285         char    **tmp_ptr;
 286         int     count = 0;
 287         char    elem_name[PATH_MAX];
 288 
 289         if (service_mode) {
 290                 total_cnt = sizeof (serv_data_list)/sizeof (*serv_data_list);
 291                 ptr = serv_data_list;
 292         } else {
 293                 total_cnt = sizeof (cust_data_list)/sizeof (*cust_data_list);
 294                 ptr = cust_data_list;
 295         }
 296         tmp_ptr = ptr;
 297 
 298         for (numseg = 0; numseg < NUM_OF_SEGMENT; numseg++) {
 299                 ptr = tmp_ptr;
 300                 for (list_cnt = 0; list_cnt < total_cnt; list_cnt++) {
 301                         if ((fru_get_definition(*ptr, &def)) != FRU_SUCCESS) {
 302                                 continue;
 303                         }
 304                         if ((fru_get_num_iterations(cont_hdl,
 305                             &segment_name[numseg], 0, *ptr,
 306                             &iter_cnt, NULL)) != FRU_SUCCESS) {
 307                                 iter_cnt = 0;
 308                         }
 309                         iter = 0;
 310                         do {
 311                                 for (count = 0; count < def.enum_count;
 312                                     count++) {
 313                                         if (def.iteration_type !=
 314                                             FRU_NOT_ITERATED) {
 315                                                 (void) snprintf(elem_name,
 316                                                     sizeof (elem_name),
 317                         "/%s[%d]/%s", *ptr, iter, def.enum_table[count].text);
 318                                         } else {
 319                                                 (void) snprintf(elem_name,
 320                                                     sizeof (elem_name),
 321                         "/%s/%s", *ptr, def.enum_table[count].text);
 322                                         }
 323 
 324                                         if ((fru_read_field(cont_hdl,
 325                                             &segment_name[numseg], instance,
 326                                             elem_name, (void**)&data, &dataLen,
 327                                             &found_path)) != FRU_SUCCESS) {
 328                                                 break;
 329                                         }
 330 
 331                                         if ((fru_get_definition(
 332                         def.enum_table[count].text, &def1)) != FRU_SUCCESS) {
 333                                                 break;
 334                                         }
 335                                         (void) printf(" %s:  ",\
 336                                             elem_name);
 337                                         display_data(data, dataLen, &def1);
 338                                         (void) printf("\n");
 339                                 }
 340                                 iter ++;
 341                         } while (iter < iter_cnt);
 342                         ptr++;
 343                 }
 344         }
 345 }
 346 
 347 static char *
 348 convertBinaryToDecimal(char *ptr)
 349 {
 350         int     cnt = 0;
 351         char    *data;
 352         int     str_len;
 353         char    *ret = NULL;
 354         uint64_t        result = 0;
 355 
 356         str_len = strlen(ptr);
 357         data = ptr;
 358 
 359         while (str_len >= 1) {
 360                 str_len -= 1;
 361                 if (data[str_len] == '0') {
 362                         result += (0 * pow(2, cnt));
 363                 }
 364                 if (data[str_len] == '1') {
 365                         result += (1 * pow(2, cnt));
 366                 }
 367                 cnt++;
 368         }
 369         ret = (char *)lltostr(result, "\n");
 370         return (ret);
 371 }
 372 
 373 /*
 374  * called update_field() to update the field with specific field value.
 375  * nodehdl represents the fru, segment represents the segment name in the fru.
 376  * field_name represents the field to be updated with the value field_value.
 377  */
 378 
 379 static int
 380 convert_update(fru_nodehdl_t nodehdl, char *segment, char *field_name,
 381                                                         char *field_value)
 382 {
 383         uint64_t num = 0;
 384         fru_elemdef_t def;
 385         fru_errno_t     err;
 386         void    *data = NULL;
 387         size_t  dataLen = 0;
 388         int     i;
 389 
 390         if ((err = fru_get_definition(field_name, &def)) != FRU_SUCCESS) {
 391                 (void) fprintf(stderr,
 392                     gettext("Failed to get definition %s:  %s\n"),
 393                     field_name, fru_strerror(err));
 394                 return (1);
 395         }
 396 
 397         if (field_value == NULL) {
 398                 return (1);
 399         }
 400 
 401         switch (def.data_type) {
 402                 case    FDTYPE_Binary:
 403                         if (def.disp_type != FDISP_Time) {
 404                                 if (field_value[0] == 'b') {
 405                                         field_value =
 406                                             convertBinaryToDecimal((field_value
 407                                             +1));
 408                                 }
 409                                 num = strtoll(field_value, (char **)NULL, 0);
 410                                 if ((num == 0) && (errno == 0)) {
 411                                         return (1);
 412                                 }
 413                                 data = (void*)&num;
 414                                 dataLen = sizeof (uint64_t);
 415                         }
 416                         break;
 417                 case    FDTYPE_ByteArray:
 418                         return (1);
 419                 case    FDTYPE_Unicode:
 420                         return (1);
 421                 case    FDTYPE_ASCII:
 422                         data = (void *) field_value;
 423                         dataLen = strlen(field_value);
 424                         if (dataLen < def.data_length) {
 425                                 dataLen++;
 426                         }
 427                         break;
 428                 case    FDTYPE_Enumeration:
 429                         for (i = 0; i < def.enum_count; i++) {
 430                                 if (strcmp(def.enum_table[i].text,
 431                                     field_value) == 0) {
 432                                         data = (void *)(uintptr_t)
 433                                             def.enum_table[i].value;
 434                                         dataLen = sizeof (uint64_t);
 435                                         break;
 436                                 }
 437                         }
 438                         return (1);
 439                 case    FDTYPE_Record:
 440                         if (def.iteration_count == 0) {
 441                                 return (1);
 442                         }
 443                         data = NULL;
 444                         dataLen = 0;
 445                         break;
 446                 case    FDTYPE_UNDEFINED:
 447                         return (1);
 448         }
 449 
 450         if ((err = fru_update_field(nodehdl, segment, 0, field_name, data,
 451             dataLen)) != FRU_SUCCESS) {
 452                 (void) fprintf(stderr, gettext("fru_update_field():  %s\n"),
 453                     fru_strerror(err));
 454                 return (1);
 455         }
 456         return (0);
 457 }
 458 /*
 459  * called by update_field() when a new data element is created.
 460  * it updates the UNIX_Timestamp32 field with the current system time.
 461  */
 462 
 463 static int
 464 update_unixtimestamp(fru_nodehdl_t nodehdl, char *segment, char **ptr)
 465 {
 466         char    *field_name;
 467         time_t  clock;
 468         struct  tm *sp_tm;
 469         fru_errno_t     err = FRU_SUCCESS;
 470         uint64_t        time_data;
 471         size_t          len;
 472 
 473         len = strlen(*ptr) + strlen("UNIX_Timestamp32") + 3;
 474         field_name = alloca(len);
 475 
 476         (void) snprintf(field_name, len, "/%s/UNIX_Timestamp32", *ptr);
 477 
 478         clock = time(NULL);
 479         sp_tm = localtime(&clock);
 480         time_data = (uint64_t)mktime(sp_tm);
 481 
 482         if ((err = fru_update_field(nodehdl, segment, 0, field_name,
 483             (void *)&time_data, sizeof (time_data))) != FRU_SUCCESS) {
 484                 (void) fprintf(stderr, gettext("fru_update_field():  %s\n"),
 485                     fru_strerror(err));
 486                 return (1);
 487         }
 488         return (0);
 489 }
 490 
 491 /*
 492  * create segment on the specified fru represented by nodehdl.
 493  */
 494 
 495 static int
 496 create_segment(fru_nodehdl_t nodehdl)
 497 {
 498         fru_segdesc_t   seg_desc;
 499         fru_segdef_t    def;
 500         int     cnt;
 501         int     status;
 502 
 503         (void) memset(&seg_desc, 0, sizeof (seg_desc));
 504         seg_desc.field.field_perm = 0x6;
 505         seg_desc.field.operations_perm = 0x6;
 506         seg_desc.field.engineering_perm = 0x6;
 507         seg_desc.field.repair_perm = 0x6;
 508 
 509         (void) memset(&def, 0, sizeof (def));
 510         def.address = 0;
 511         def.desc.raw_data = seg_desc.raw_data;
 512         def.hw_desc.all_bits = 0;
 513 
 514         for (cnt = 0; cnt < NUM_OF_SEGMENT; cnt++) {
 515                 (void) strncpy(def.name, segment_name[cnt], SEGMENT_NAME_SIZE);
 516                 if (cnt == 0) {
 517                         def.size = FD_SEGMENT_SIZE;
 518                 }
 519                 if ((status = fru_create_segment(nodehdl, &def))
 520                     != FRU_SUCCESS) {
 521                         continue;
 522                 }
 523                 return (cnt);
 524         }
 525         if (status != FRU_SUCCESS)
 526                 (void) fprintf(stderr, gettext("fru_create_segment():  %s\n"),
 527                     fru_strerror(status));
 528         return (1);
 529 }
 530 
 531 /*
 532  * called from update_field() when service flag is ON. currently
 533  * supported iterated record is InstallationR and fields supported for
 534  * update are Geo_North, Geo_East, Geo_Alt, Geo_Location.
 535  */
 536 
 537 static int
 538 updateiter_record(fru_nodehdl_t nodehdl, int cnt, char **ptr,
 539                         char *field_name, char  *field_value)
 540 {
 541         int     iter_cnt  = 0;
 542         char    rec_name[512];
 543         void    *data = NULL;
 544         char    *tmpptr = NULL;
 545         size_t  dataLen = 0;
 546         char    **elem_ptr;
 547         int     found = 0;
 548         int     index;
 549         int     total_cnt;
 550         fru_errno_t     err;
 551 
 552         static  char    *elem_list[] = {"/Geo_North", "/Geo_East",\
 553                                 "/Geo_Alt", "/Geo_Location"};
 554 
 555         elem_ptr = elem_list;
 556         total_cnt = sizeof (elem_list)/sizeof (*elem_list);
 557 
 558         for (index = 0; index < total_cnt; index++) {
 559                 tmpptr = strrchr(field_name, '/');
 560                 if (tmpptr == NULL) {
 561                         (void) fprintf(stderr,
 562                             gettext("Error:  Data Element not known\n"));
 563                         return (1);
 564                 }
 565                 if ((strncmp(*elem_ptr, tmpptr, strlen(*elem_ptr)) != 0)) {
 566                         elem_ptr++;
 567                         continue;
 568                 }
 569                 found = 1;
 570                 break;
 571         }
 572 
 573         if (found == 0) {
 574                 (void) fprintf(stderr,
 575                     gettext("Error:  Update not allowed for field:  %s\n"),
 576                     field_name);
 577                 return (1);
 578         }
 579 
 580         if ((fru_get_num_iterations(nodehdl, &segment_name[cnt], 0,
 581             *ptr, &iter_cnt, NULL)) != FRU_SUCCESS) {
 582                 return (1);
 583         }
 584 
 585         /* add a new Iterated Record if complete path is not given */
 586         if (iter_cnt == 0) {
 587                 (void) snprintf(rec_name, sizeof (rec_name), "/%s[+]", *ptr);
 588                 if ((err = fru_update_field(nodehdl, segment_name[cnt], 0,
 589                     rec_name, data, dataLen)) != FRU_SUCCESS) {
 590                         (void) fprintf(stderr,
 591                         gettext("fru_update_field():  %s\n"),
 592                             fru_strerror(err));
 593                 return (1);
 594                 }
 595 
 596                 iter_cnt = 1;
 597         }
 598 
 599         (void) snprintf(rec_name, sizeof (rec_name), "/%s[%d]%s",
 600             *ptr, iter_cnt-1, strrchr(field_name, '/'));
 601 
 602         if ((convert_update(nodehdl, segment_name[cnt], rec_name,
 603             field_value)) != 0) {
 604                 return (1);
 605         }
 606 
 607         /* update success  now update the unix timestamp */
 608 
 609         (void) snprintf(rec_name, sizeof (rec_name), "/%s[%d]",
 610             *ptr, iter_cnt-1);
 611         tmpptr = rec_name;
 612 
 613         /* update UNIX_Timestamp32 with creation time */
 614         if ((update_unixtimestamp(nodehdl, segment_name[cnt],
 615             &tmpptr)) != 0) {
 616                 return (1);
 617         }
 618 
 619         return (0);
 620 }
 621 
 622 static int
 623 update_field(fru_nodehdl_t nodehdl, char *field_name, char *field_value)
 624 {
 625         fru_elemdef_t   def;
 626         unsigned char   *data;
 627         size_t  dataLen;
 628         char    *found_path = NULL;
 629         int     cnt;
 630         char    **ptr;
 631         fru_strlist_t   elem;
 632         int     elem_cnt;
 633         int     add_flag = 1;
 634         int     total_cnt;
 635         int     status;
 636 
 637         if (service_mode) {
 638                 ptr = serv_data_list;
 639                 total_cnt = sizeof (serv_data_list)/sizeof (*serv_data_list);
 640 
 641                 for (cnt = 0; cnt < total_cnt; cnt++) {
 642                         if ((strncmp(*ptr, &field_name[1], strlen(*ptr)) \
 643                             != 0) && (strncmp(*ptr, &field_name[0],
 644                             strlen(*ptr)) != 0)) {
 645                                 ptr++;
 646                                 add_flag = 0;
 647                                 continue;
 648                         }
 649                         add_flag = 1;
 650                         break;
 651                 }
 652         } else {
 653                 ptr = cust_data_list;
 654         }
 655 
 656         /* look for the field in either of the segment if found update it */
 657         for (cnt = 0; cnt < NUM_OF_SEGMENT; cnt++) {
 658                 if ((fru_read_field(nodehdl, &segment_name[cnt], 0, field_name,
 659                     (void **) &data, &dataLen, &found_path)) != FRU_SUCCESS) {
 660                         continue;
 661                 }
 662                 if ((fru_get_definition(*ptr, &def)) == FRU_SUCCESS) {
 663                         if (def.iteration_count != 0) {
 664                                 if ((updateiter_record(nodehdl, cnt, ptr,
 665                                     field_name, field_value)) != 0) {
 666                                         return (1);
 667                                 }
 668                                 return (0);
 669                         }
 670                 }
 671 
 672                 if ((convert_update(nodehdl, segment_name[cnt],
 673                     field_name, field_value)) != 0) {
 674                         return (1);
 675                 }
 676 
 677                 /* update UNIX_Timestamp32 with update time */
 678                 if ((update_unixtimestamp(nodehdl, segment_name[cnt],
 679                     ptr)) != 0) {
 680                         return (1);
 681                 }
 682                 return (0);
 683         }
 684 
 685         elem.num = 0;
 686 
 687         /* field not found add the the record in one of the segment */
 688         for (cnt = 0; cnt < NUM_OF_SEGMENT; cnt++) {
 689                 (void) fru_list_elems_in(nodehdl, segment_name[cnt], &elem);
 690                 for (elem_cnt = 0; elem_cnt < elem.num; elem_cnt++) {
 691                         if ((strcmp(*ptr, elem.strs[elem_cnt])) == 0) {
 692                                 add_flag = 0;
 693                         }
 694                 }
 695 
 696                 if (add_flag) {
 697                         if ((fru_add_element(nodehdl, segment_name[cnt],
 698                             *ptr)) != FRU_SUCCESS) {
 699                                 continue;
 700                         }
 701                 }
 702 
 703                 if ((fru_get_definition(*ptr, &def)) == FRU_SUCCESS) {
 704                         if (def.iteration_count != 0) {
 705                                 if ((updateiter_record(nodehdl, cnt, ptr,
 706                                     field_name, field_value)) != 0) {
 707                                         return (1);
 708                                 }
 709                                 return (0);
 710                         }
 711                 }
 712 
 713                 /* update UNIX_Timestamp32 with creation time */
 714                 if ((update_unixtimestamp(nodehdl, segment_name[cnt],
 715                     ptr)) != 0) {
 716                         return (1);
 717                 }
 718 
 719                 /* record added update the field with the value */
 720                 if ((convert_update(nodehdl, segment_name[cnt], field_name,
 721                     field_value)) != 0) {
 722                         return (1);
 723                 }
 724                 return (0);
 725         }
 726 
 727         /* segment not present, create one and add the record */
 728         cnt = create_segment(nodehdl);
 729         if (cnt == 1) {
 730                 return (1);
 731         }
 732 
 733         if ((status = fru_add_element(nodehdl, segment_name[cnt], *ptr))
 734             != FRU_SUCCESS) {
 735                 (void) fprintf(stderr, gettext("fru_add_element():  %s\n"),
 736                     fru_strerror(status));
 737                 return (1);
 738         }
 739 
 740         if ((fru_get_definition(*ptr, &def)) == FRU_SUCCESS) {
 741                 if (def.iteration_count != 0) {
 742                         if ((updateiter_record(nodehdl,  cnt, ptr,
 743                             field_name, field_value)) != 0) {
 744                                 return (1);
 745                         }
 746                         return (0);
 747                 }
 748         }
 749 
 750         /* update UNIX_Timestamp32 with creation time */
 751         if ((update_unixtimestamp(nodehdl, segment_name[cnt],
 752             ptr)) != 0) {
 753                 return (1);
 754         }
 755 
 756         if ((convert_update(nodehdl, segment_name[cnt], field_name,
 757             field_value)) != 0) {
 758                 return (1);
 759         }
 760         return (0);
 761 }
 762 
 763 static int
 764 update_node_data(fru_nodehdl_t node)
 765 {
 766         int     i;
 767         int     status = 0;
 768 
 769         if (service_mode) {
 770                 for (i = 0; i < svcargc; i += 2)
 771                         if (update_field(node, svcargv[i], svcargv[i + 1])) {
 772                                 status = 1;
 773                         }
 774         } else {
 775                 status = update_field(node, "/Customer_DataR/Cust_Data",
 776                     customer_data);
 777         }
 778         return (status);
 779 }
 780 
 781 static void
 782 walk_tree(fru_nodehdl_t node, const char *prior_path, int process_tree)
 783 {
 784         char    *name, path[PATH_MAX];
 785         int     process_self = process_tree, status, update_status = 0;
 786         fru_nodehdl_t    next_node;
 787         fru_node_t      type;
 788 
 789         if ((status = fru_get_node_type(node, &type)) != FRU_SUCCESS) {
 790                 (void) fprintf(stderr,
 791                     gettext("Error getting FRU tree node type:  %s\n"),
 792                     fru_strerror(status));
 793                 exit(1);
 794         }
 795 
 796         if ((status = fru_get_name_from_hdl(node, &name)) != FRU_SUCCESS) {
 797                 (void) fprintf(stderr,
 798                     gettext("Error getting name of FRU tree node:  %s\n"),
 799                     fru_strerror(status));
 800                 exit(1);
 801         }
 802 
 803 
 804         /*
 805          * Build the current path
 806          */
 807         if (snprintf(path, sizeof (path), "%s/%s", prior_path, name)
 808             >= sizeof (path)) {
 809                 (void) fprintf(stderr,
 810                     gettext("FRU tree path would overflow buffer\n"));
 811                 exit(1);
 812         }
 813 
 814         free(name);
 815 
 816         /*
 817          * Process the node
 818          */
 819         if (list_only) {
 820                 (void) printf("%s%s\n", path, ((type == FRU_NODE_FRU) ?
 821                     " (fru)" : ((type == FRU_NODE_CONTAINER) ?
 822                     " (container)" : "")));
 823         } else if ((process_tree || (process_self = pathmatch(path))) &&
 824             (type == FRU_NODE_CONTAINER)) {
 825                 (void) printf("%s\n", path);
 826                 if (update) {
 827                         status = update_node_data(node);
 828                         update_status = status;
 829                 }
 830                 print_node_data(node);
 831                 if (!recursive) {
 832                         exit(status);
 833                 }
 834         } else if (process_self && !recursive) {
 835                 (void) fprintf(stderr,
 836                     gettext("\"%s\" is not a container\n"), path);
 837                 exit(1);
 838         }
 839 
 840 
 841         /*
 842          * Recurse
 843          */
 844         if (fru_get_child(node, &next_node) == FRU_SUCCESS)
 845                 walk_tree(next_node, path, process_self);
 846 
 847         if (fru_get_peer(node, &next_node) == FRU_SUCCESS)
 848                 walk_tree(next_node, prior_path, process_tree);
 849 
 850         /*
 851          * when update_node_data failed, need to exit with return value 1
 852          */
 853         if (update_status)
 854                 exit(1);
 855 }
 856 
 857 int
 858 main(int argc, char *argv[])
 859 {
 860         int     process_tree = 0, option, status;
 861 
 862         fru_nodehdl_t  root;
 863 
 864 
 865         command = argv[0];
 866 
 867         opterr = 0;     /*  "getopt" should not print to "stderr"  */
 868         while ((option = getopt(argc, argv, "lrs")) != EOF) {
 869         switch (option) {
 870                 case 'l':
 871                         list_only = 1;
 872                         break;
 873                 case 'r':
 874                         recursive = 1;
 875                         break;
 876                 case 's':
 877                         service_mode = 1;
 878                         break;
 879                 default:
 880                         usage();
 881                         return (1);
 882                 }
 883         }
 884 
 885         argc -= optind;
 886         argv += optind;
 887 
 888         if (argc == 0) {
 889                 process_tree   = 1;
 890                 recursive = 1;
 891         } else {
 892                 if (list_only) {
 893                         usage();
 894                         return (1);
 895                 }
 896 
 897                 frupath = argv[0];
 898                 if (*frupath == 0) {
 899                         usage();
 900                         (void) fprintf(stderr,
 901                             gettext("\"frupath\" should not be empty\n"));
 902                         return (1);
 903                 }
 904 
 905                 argc--;
 906                 argv++;
 907 
 908                 if (argc > 0) {
 909                         update = 1;
 910                         if (service_mode) {
 911                                 if ((argc % 2) != 0) {
 912                                         (void) fprintf(stderr,
 913                                             gettext("Must specify "
 914                                             "field-value pairs "
 915                                             "for update\n"));
 916                                         return (1);
 917                                 }
 918 
 919                                 if (validate_fieldnames(argc, argv) != 0) {
 920                                         return (1);
 921                                 }
 922 
 923                                 svcargc = argc;
 924                                 svcargv = argv;
 925                         } else if (argc == 1)
 926                                 customer_data = argv[0];
 927                         else {
 928                                 usage();
 929                                 return (1);
 930                         }
 931                 }
 932         }
 933 
 934         if ((status = fru_open_data_source("picl", NULL)) != FRU_SUCCESS) {
 935                 (void) fprintf(stderr,
 936                     gettext("Unable to access FRU data source:  %s\n"),
 937                     fru_strerror(status));
 938                 return (1);
 939         }
 940 
 941         if ((status = fru_get_root(&root)) == FRU_NODENOTFOUND) {
 942                 (void) fprintf(stderr,
 943                     gettext("This system does not support PICL "
 944                     "infrastructure to provide FRUID data\n"
 945                     "Please use the platform SP to access the FRUID "
 946                     "information\n"));
 947                 return (1);
 948         } else if (status != FRU_SUCCESS) {
 949                 (void) fprintf(stderr,
 950                     gettext("Unable to access FRU ID data "
 951                     "due to data source error\n"));
 952                 return (1);
 953         }
 954 
 955         walk_tree(root, "", process_tree);
 956 
 957         if ((frupath != NULL) && (!found_frupath)) {
 958                 (void) fprintf(stderr,
 959                     gettext("\"%s\" not found\n"),
 960                     frupath);
 961                 return (1);
 962         }
 963 
 964         return (0);
 965 }