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