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 }