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
usage(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
validate_fieldnames(int argc,char * argv[])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
pathmatch(const char * path)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
displayBinary(unsigned char * data,size_t length,fru_elemdef_t * def)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
displayBAasBinary(unsigned char * data,size_t length)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
display_data(unsigned char * data,size_t length,fru_elemdef_t * def)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
print_node_data(fru_nodehdl_t cont_hdl)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 *
convertBinaryToDecimal(char * ptr)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
convert_update(fru_nodehdl_t nodehdl,char * segment,char * field_name,char * field_value)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
update_unixtimestamp(fru_nodehdl_t nodehdl,char * segment,char ** ptr)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
create_segment(fru_nodehdl_t nodehdl)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
updateiter_record(fru_nodehdl_t nodehdl,int cnt,char ** ptr,char * field_name,char * field_value)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
update_field(fru_nodehdl_t nodehdl,char * field_name,char * field_value)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
update_node_data(fru_nodehdl_t node)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
walk_tree(fru_nodehdl_t node,const char * prior_path,int process_tree)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
main(int argc,char * argv[])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