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*)# 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 } 968