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