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 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 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 132 return (0); 133 } 134 135 static void 136 displayBinary(unsigned char *data, size_t length, fru_elemdef_t *def) 137 { 138 int i = 0; 139 uint64_t lldata; 140 uint64_t mask; 141 142 if (def->disp_type == FDISP_Hex) { 143 for (i = 0; i < length; i++) { 144 (void) printf("%02X", data[i]); 145 } 146 return; 147 } 148 149 (void) memcpy(&lldata, data, sizeof (lldata)); 150 switch (def->disp_type) { 151 case FDISP_Binary: 152 { 153 mask = 0x8000000000000000ULL; 154 for (i = 0; i < (sizeof (uint64_t) *8); i++) { 155 if (lldata & (mask >> i)) { 156 (void) printf("1"); 157 } else { 158 (void) printf("0"); 159 } 160 } 161 return; 162 } 163 case FDISP_Octal: 164 { 165 (void) printf("%llo", lldata); 166 return; 167 } 168 case FDISP_Decimal: 169 { 170 (void) printf("%lld", lldata); 171 return; 172 } 173 case FDISP_Time: 174 { 175 char buffer[PATH_MAX]; 176 time_t time; 177 time = (time_t)lldata; 178 (void) strftime(buffer, PATH_MAX, "%C", 179 localtime(&time)); 180 (void) printf("%s", buffer); 181 return; 182 } 183 } 184 } 185 186 static void 187 displayBAasBinary(unsigned char *data, size_t length) 188 { 189 int i; 190 unsigned char mask; 191 192 for (i = 0; i < length; i++) { 193 /* 194 * make a mask for the high order bit and adjust down through 195 * all the bits. 196 */ 197 for (mask = 0x80; mask > 0; mask /= 2) { 198 if ((data[i] & mask) != 0) /* bit must be on */ 199 (void) printf("1"); 200 else /* bit is off... */ 201 (void) printf("0"); 202 } 203 } 204 (void) printf("\n"); 205 } 206 207 static void 208 display_data(unsigned char *data, size_t length, fru_elemdef_t *def) 209 { 210 int i = 0; 211 uint64_t lldata; 212 213 if (data == 0x00) { 214 (void) printf("\n"); 215 return; 216 } 217 218 switch (def->data_type) { 219 case FDTYPE_Binary: 220 { 221 displayBinary(data, length, def); 222 return; 223 } 224 225 case FDTYPE_ByteArray: 226 { 227 switch (def->disp_type) { 228 case FDISP_Binary: 229 displayBAasBinary(data, length); 230 return; 231 case FDISP_Hex: 232 for (i = 0; i < length; i++) { 233 (void) printf("%02X", data[i]); 234 } 235 return; 236 } 237 return; 238 } 239 case FDTYPE_Unicode: 240 assert(gettext("Unicode not yet supported") == 0); 241 break; 242 case FDTYPE_ASCII: 243 { 244 char *disp_str = (char *)alloca(length+1); 245 for (i = 0; i < length; i++) 246 disp_str[i] = data[i]; 247 disp_str[i] = '\0'; 248 (void) printf("%s", disp_str); 249 return; 250 } 251 252 case FDTYPE_Enumeration: 253 { 254 lldata = strtoull((const char *)data, NULL, 0); 255 for (i = 0; i < def->enum_count; i++) { 256 if (def->enum_table[i].value == lldata) { 257 /* strdup such that map_... can realloc if necessary. */ 258 char *tmp = strdup(def->enum_table[i].text); 259 (void) printf("%s", tmp); 260 free(tmp); 261 return; 262 } 263 } 264 (void) printf(gettext("Unrecognized Value: 0x")); 265 for (i = 0; i < sizeof (uint64_t); i++) 266 (void) printf("%02X", data[i]); 267 break; 268 } 269 default: 270 break; 271 } 272 } 273 274 static void 275 print_node_data(fru_nodehdl_t cont_hdl) 276 { 277 int iter_cnt = 0; 278 int iter; 279 int numseg; 280 int list_cnt; 281 unsigned char *data; 282 size_t dataLen; 283 int total_cnt; 284 char *found_path = NULL; 285 fru_elemdef_t def, def1; 286 int instance = 0; 287 char **ptr; 288 char **tmp_ptr; 289 int count = 0; 290 char elem_name[PATH_MAX]; 291 292 if (service_mode) { 293 total_cnt = sizeof (serv_data_list)/sizeof (*serv_data_list); 294 ptr = serv_data_list; 295 } else { 296 total_cnt = sizeof (cust_data_list)/sizeof (*cust_data_list); 297 ptr = cust_data_list; 298 } 299 tmp_ptr = ptr; 300 301 for (numseg = 0; numseg < NUM_OF_SEGMENT; numseg++) { 302 ptr = tmp_ptr; 303 for (list_cnt = 0; list_cnt < total_cnt; list_cnt++) { 304 if ((fru_get_definition(*ptr, &def)) != FRU_SUCCESS) { 305 continue; 306 } 307 if ((fru_get_num_iterations(cont_hdl, 308 &segment_name[numseg], 0, *ptr, 309 &iter_cnt, NULL)) != FRU_SUCCESS) { 310 iter_cnt = 0; 311 } 312 iter = 0; 313 do { 314 for (count = 0; count < def.enum_count; 315 count++) { 316 if (def.iteration_type != 317 FRU_NOT_ITERATED) { 318 (void) snprintf(elem_name, 319 sizeof (elem_name), 320 "/%s[%d]/%s", *ptr, iter, def.enum_table[count].text); 321 } else { 322 (void) snprintf(elem_name, 323 sizeof (elem_name), 324 "/%s/%s", *ptr, def.enum_table[count].text); 325 } 326 327 if ((fru_read_field(cont_hdl, 328 &segment_name[numseg], instance, elem_name, (void**)&data, 329 &dataLen, &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+1)); 409 } 410 num = strtoll(field_value, (char **)NULL, 0); 411 if ((num == 0) && (errno == 0)) { 412 return (1); 413 } 414 data = (void*)# 415 dataLen = sizeof (uint64_t); 416 } 417 break; 418 case FDTYPE_ByteArray: 419 return (1); 420 case FDTYPE_Unicode: 421 return (1); 422 case FDTYPE_ASCII: 423 data = (void *) field_value; 424 dataLen = strlen(field_value); 425 if (dataLen < def.data_length) { 426 dataLen++; 427 } 428 break; 429 case FDTYPE_Enumeration: 430 for (i = 0; i < def.enum_count; i++) { 431 if (strcmp(def.enum_table[i].text, 432 field_value) == 0) { 433 data = (void *)(uintptr_t) 434 def.enum_table[i].value; 435 dataLen = sizeof (uint64_t); 436 break; 437 } 438 } 439 return (1); 440 case FDTYPE_Record: 441 if (def.iteration_count == 0) { 442 return (1); 443 } 444 data = NULL; 445 dataLen = 0; 446 break; 447 case FDTYPE_UNDEFINED: 448 return (1); 449 } 450 451 if ((err = fru_update_field(nodehdl, segment, 0, field_name, data, 452 dataLen)) != FRU_SUCCESS) { 453 (void) fprintf(stderr, gettext("fru_update_field(): %s\n"), 454 fru_strerror(err)); 455 return (1); 456 } 457 return (0); 458 } 459 /* 460 * called by update_field() when a new data element is created. 461 * it updates the UNIX_Timestamp32 field with the current system time. 462 */ 463 464 static int 465 update_unixtimestamp(fru_nodehdl_t nodehdl, char *segment, char **ptr) 466 { 467 char *field_name; 468 time_t clock; 469 struct tm *sp_tm; 470 fru_errno_t err = FRU_SUCCESS; 471 uint64_t time_data; 472 size_t len; 473 474 len = strlen(*ptr) + strlen("UNIX_Timestamp32") + 3; 475 field_name = alloca(len); 476 477 (void) snprintf(field_name, len, "/%s/UNIX_Timestamp32", *ptr); 478 479 clock = time(NULL); 480 sp_tm = localtime(&clock); 481 time_data = (uint64_t)mktime(sp_tm); 482 483 if ((err = fru_update_field(nodehdl, segment, 0, field_name, 484 (void *)&time_data, sizeof (time_data))) != FRU_SUCCESS) { 485 (void) fprintf(stderr, gettext("fru_update_field(): %s\n"), 486 fru_strerror(err)); 487 return (1); 488 } 489 return (0); 490 } 491 492 /* 493 * create segment on the specified fru represented by nodehdl. 494 */ 495 496 static int 497 create_segment(fru_nodehdl_t nodehdl) 498 { 499 fru_segdesc_t seg_desc; 500 fru_segdef_t def; 501 int cnt; 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 ((fru_create_segment(nodehdl, &def)) != FRU_SUCCESS) { 520 continue; 521 } 522 return (cnt); 523 } 524 return (1); 525 } 526 527 /* 528 * called from update_field() when service flag is ON. currently 529 * supported iterated record is InstallationR and fields supported for 530 * update are Geo_North, Geo_East, Geo_Alt, Geo_Location. 531 */ 532 533 static int 534 updateiter_record(fru_nodehdl_t nodehdl, int cnt, char **ptr, 535 char *field_name, char *field_value) 536 { 537 int iter_cnt = 0; 538 char rec_name[512]; 539 void *data = NULL; 540 char *tmpptr = NULL; 541 size_t dataLen = 0; 542 char **elem_ptr; 543 int found = 0; 544 int index; 545 int total_cnt; 546 547 static char *elem_list[] = {"/Geo_North", "/Geo_East",\ 548 "/Geo_Alt", "/Geo_Location"}; 549 550 elem_ptr = elem_list; 551 total_cnt = sizeof (elem_list)/sizeof (*elem_list); 552 553 for (index = 0; index < total_cnt; index++) { 554 tmpptr = strrchr(field_name, '/'); 555 if (tmpptr == NULL) { 556 (void) fprintf(stderr, 557 gettext("Error: Data Element not known\n")); 558 return (1); 559 } 560 if ((strncmp(*elem_ptr, tmpptr, strlen(*elem_ptr)) != 0)) { 561 elem_ptr++; 562 continue; 563 } 564 found = 1; 565 break; 566 } 567 568 if (found == 0) { 569 (void) fprintf(stderr, 570 gettext("Error: Update not allowed for field: %s\n"), 571 field_name); 572 return (1); 573 } 574 575 if ((fru_get_num_iterations(nodehdl, &segment_name[cnt], 0, 576 *ptr, &iter_cnt, NULL)) != FRU_SUCCESS) { 577 return (1); 578 } 579 580 /* add a new Iterated Record if complete path is not given */ 581 if (iter_cnt == 0) { 582 (void) snprintf(rec_name, sizeof (rec_name), "/%s[+]", *ptr); 583 if ((fru_update_field(nodehdl, segment_name[cnt], 0, 584 rec_name, data, dataLen)) != FRU_SUCCESS) { 585 return (1); 586 } 587 588 iter_cnt = 1; 589 } 590 591 (void) snprintf(rec_name, sizeof (rec_name), "/%s[%d]%s", 592 *ptr, iter_cnt-1, strrchr(field_name, '/')); 593 594 if ((convert_update(nodehdl, segment_name[cnt], rec_name, 595 field_value)) != 0) { 596 return (1); 597 } 598 599 /* update success now update the unix timestamp */ 600 601 (void) snprintf(rec_name, sizeof (rec_name), "/%s[%d]", 602 *ptr, iter_cnt-1); 603 tmpptr = rec_name; 604 605 /* update UNIX_Timestamp32 with creation time */ 606 if ((update_unixtimestamp(nodehdl, segment_name[cnt], 607 &tmpptr)) != 0) { 608 return (1); 609 } 610 611 return (0); 612 } 613 614 static int 615 update_field(fru_nodehdl_t nodehdl, char *field_name, char *field_value) 616 { 617 fru_elemdef_t def; 618 unsigned char *data; 619 size_t dataLen; 620 char *found_path = NULL; 621 int cnt; 622 char **ptr; 623 fru_strlist_t elem; 624 int elem_cnt; 625 int add_flag = 1; 626 int total_cnt; 627 628 if (service_mode) { 629 ptr = serv_data_list; 630 total_cnt = sizeof (serv_data_list)/sizeof (*serv_data_list); 631 632 for (cnt = 0; cnt < total_cnt; cnt++) { 633 if ((strncmp(*ptr, &field_name[1], strlen(*ptr)) \ 634 != 0) && (strncmp(*ptr, &field_name[0], 635 strlen(*ptr)) != 0)) { 636 ptr++; 637 add_flag = 0; 638 continue; 639 } 640 add_flag = 1; 641 break; 642 } 643 } else { 644 ptr = cust_data_list; 645 } 646 647 /* look for the field in either of the segment if found update it */ 648 for (cnt = 0; cnt < NUM_OF_SEGMENT; cnt++) { 649 if ((fru_read_field(nodehdl, &segment_name[cnt], 0, field_name, 650 (void **) &data, &dataLen, &found_path)) != FRU_SUCCESS) { 651 continue; 652 } 653 if ((fru_get_definition(*ptr, &def)) == FRU_SUCCESS) { 654 if (def.iteration_count != 0) { 655 if ((updateiter_record(nodehdl, cnt, ptr, 656 field_name, field_value)) != 0) { 657 return (1); 658 } 659 return (0); 660 } 661 } 662 663 if ((convert_update(nodehdl, segment_name[cnt], 664 field_name, field_value)) != 0) { 665 return (1); 666 } 667 668 /* update UNIX_Timestamp32 with update time */ 669 if ((update_unixtimestamp(nodehdl, segment_name[cnt], 670 ptr)) != 0) { 671 return (1); 672 } 673 return (0); 674 } 675 676 elem.num = 0; 677 678 /* field not found add the the record in one of the segment */ 679 for (cnt = 0; cnt < NUM_OF_SEGMENT; cnt++) { 680 fru_list_elems_in(nodehdl, segment_name[cnt], &elem); 681 for (elem_cnt = 0; elem_cnt < elem.num; elem_cnt++) { 682 if ((strcmp(*ptr, elem.strs[elem_cnt])) == 0) { 683 add_flag = 0; 684 } 685 } 686 687 if (add_flag) { 688 if ((fru_add_element(nodehdl, segment_name[cnt], 689 *ptr)) != FRU_SUCCESS) { 690 continue; 691 } 692 } 693 694 if ((fru_get_definition(*ptr, &def)) == FRU_SUCCESS) { 695 if (def.iteration_count != 0) { 696 if ((updateiter_record(nodehdl, cnt, ptr, 697 field_name, field_value)) != 0) { 698 return (1); 699 } 700 return (0); 701 } 702 } 703 704 /* update UNIX_Timestamp32 with creation time */ 705 if ((update_unixtimestamp(nodehdl, segment_name[cnt], 706 ptr)) != 0) { 707 return (1); 708 } 709 710 /* record added update the field with the value */ 711 if ((convert_update(nodehdl, segment_name[cnt], field_name, 712 field_value)) != 0) { 713 return (1); 714 } 715 return (0); 716 } 717 718 /* segment not present, create one and add the record */ 719 cnt = create_segment(nodehdl); 720 if (cnt == 1) { 721 return (1); 722 } 723 724 if ((fru_add_element(nodehdl, segment_name[cnt], *ptr)) 725 != FRU_SUCCESS) { 726 return (1); 727 } 728 729 if ((fru_get_definition(*ptr, &def)) == FRU_SUCCESS) { 730 if (def.iteration_count != 0) { 731 if ((updateiter_record(nodehdl, cnt, ptr, 732 field_name, field_value)) != 0) { 733 return (1); 734 } 735 return (0); 736 } 737 } 738 739 /* update UNIX_Timestamp32 with creation time */ 740 if ((update_unixtimestamp(nodehdl, segment_name[cnt], 741 ptr)) != 0) { 742 return (1); 743 } 744 745 if ((convert_update(nodehdl, segment_name[cnt], field_name, 746 field_value)) != 0) { 747 return (1); 748 } 749 return (0); 750 } 751 752 static void 753 update_node_data(fru_nodehdl_t node) 754 { 755 int i; 756 757 if (service_mode) { 758 for (i = 0; i < svcargc; i += 2) 759 (void) update_field(node, svcargv[i], svcargv[i + 1]); 760 } else { 761 (void) update_field(node, "/Customer_DataR/Cust_Data", 762 customer_data); 763 } 764 } 765 766 static void 767 walk_tree(fru_nodehdl_t node, const char *prior_path, int process_tree) 768 { 769 char *name, path[PATH_MAX]; 770 int process_self = process_tree, status; 771 fru_nodehdl_t next_node; 772 fru_node_t type; 773 774 if ((status = fru_get_node_type(node, &type)) != FRU_SUCCESS) { 775 (void) fprintf(stderr, 776 gettext("Error getting FRU tree node type: %s\n"), 777 fru_strerror(status)); 778 exit(1); 779 } 780 781 if ((status = fru_get_name_from_hdl(node, &name)) != FRU_SUCCESS) { 782 (void) fprintf(stderr, 783 gettext("Error getting name of FRU tree node: %s\n"), 784 fru_strerror(status)); 785 exit(1); 786 } 787 788 789 /* 790 * Build the current path 791 */ 792 if (snprintf(path, sizeof (path), "%s/%s", prior_path, name) 793 >= sizeof (path)) { 794 (void) fprintf(stderr, 795 gettext("FRU tree path would overflow buffer\n")); 796 exit(1); 797 } 798 799 free(name); 800 801 /* 802 * Process the node 803 */ 804 if (list_only) { 805 (void) printf("%s%s\n", path, ((type == FRU_NODE_FRU) ? 806 " (fru)" : ((type == FRU_NODE_CONTAINER) ? 807 " (container)" : ""))); 808 } else if ((process_tree || (process_self = pathmatch(path))) && 809 (type == FRU_NODE_CONTAINER)) { 810 (void) printf("%s\n", path); 811 if (update) update_node_data(node); 812 print_node_data(node); 813 if (!recursive) exit(0); 814 } else if (process_self && !recursive) { 815 (void) fprintf(stderr, 816 gettext("\"%s\" is not a container\n"), path); 817 exit(1); 818 } 819 820 821 /* 822 * Recurse 823 */ 824 if (fru_get_child(node, &next_node) == FRU_SUCCESS) 825 walk_tree(next_node, path, process_self); 826 827 if (fru_get_peer(node, &next_node) == FRU_SUCCESS) 828 walk_tree(next_node, prior_path, process_tree); 829 } 830 831 static int 832 has_system_controller() 833 { 834 char platform[PATH_MAX]; 835 836 int size; 837 838 if (((size = sysinfo(SI_PLATFORM, platform, sizeof (platform))) 839 < 0) || (size > sizeof (platform))) 840 return (-1); 841 842 if ((strcmp("SUNW,Sun-Fire", platform) == 0) || 843 (strcmp("SUNW,Sun-Fire-15000", platform) == 0)) { 844 return (1); 845 } 846 847 return (0); 848 } 849 850 int 851 main(int argc, char *argv[]) 852 { 853 int process_tree = 0, option, status; 854 855 fru_nodehdl_t root; 856 857 858 command = argv[0]; 859 860 opterr = 0; /* "getopt" should not print to "stderr" */ 861 while ((option = getopt(argc, argv, "lrs")) != EOF) { 862 switch (option) { 863 case 'l': 864 list_only = 1; 865 break; 866 case 'r': 867 recursive = 1; 868 break; 869 case 's': 870 service_mode = 1; 871 break; 872 default: 873 usage(); 874 return (1); 875 } 876 } 877 878 argc -= optind; 879 argv += optind; 880 881 if (argc == 0) { 882 process_tree = 1; 883 recursive = 1; 884 } else { 885 if (list_only) { 886 usage(); 887 return (1); 888 } 889 890 frupath = argv[0]; 891 if (*frupath == 0) { 892 usage(); 893 (void) fprintf(stderr, 894 gettext("\"frupath\" should not be empty\n")); 895 return (1); 896 } 897 898 argc--; 899 argv++; 900 901 if (argc > 0) { 902 update = 1; 903 if (service_mode) { 904 if ((argc % 2) != 0) { 905 (void) fprintf(stderr, 906 gettext("Must specify " 907 "field-value pairs " 908 "for update\n")); 909 return (1); 910 } 911 912 if (validate_fieldnames(argc, argv) != 0) { 913 return (1); 914 } 915 916 svcargc = argc; 917 svcargv = argv; 918 } else if (argc == 1) 919 customer_data = argv[0]; 920 else { 921 usage(); 922 return (1); 923 } 924 } 925 } 926 927 if ((status = fru_open_data_source("picl", NULL)) != FRU_SUCCESS) { 928 (void) fprintf(stderr, 929 gettext("Unable to access FRU data source: %s\n"), 930 fru_strerror(status)); 931 return (1); 932 } 933 934 if ((status = fru_get_root(&root)) == FRU_NODENOTFOUND) { 935 if (has_system_controller() == 1) { 936 (void) fprintf(stderr, 937 gettext("Access FRUs from the " 938 "System Controller\n")); 939 } else { 940 (void) fprintf(stderr, 941 gettext("This system does not provide " 942 "FRU ID data\n")); 943 944 } 945 return (1); 946 } else if (status != FRU_SUCCESS) { 947 (void) fprintf(stderr, 948 gettext("Unable to access FRU ID data " 949 "due to data source error\n")); 950 return (1); 951 } 952 953 walk_tree(root, "", process_tree); 954 955 if ((frupath != NULL) && (!found_frupath)) { 956 (void) fprintf(stderr, 957 gettext("\"%s\" not found\n"), 958 frupath); 959 return (1); 960 } 961 962 return (0); 963 } 964