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