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