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.
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.
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]
23 * Copyright (c) 2014 Gary Mills
25 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
26 * Use is subject to license terms.
39 #include <sys/systeminfo.h>
41 #define NUM_OF_SEGMENT 1
42 #define SEGMENT_NAME_SIZE 2
44 #define FD_SEGMENT_SIZE 2949
46 static char *command
, *customer_data
= NULL
, *frupath
= NULL
, **svcargv
;
48 /* DataElement supported in the customer operation */
49 static char *cust_data_list
[] = {"Customer_DataR"};
51 /* DataElement supported in the service operation */
52 static char *serv_data_list
[] = {"InstallationR", "ECO_CurrentR"};
54 /* currently supported segment name */
55 static char *segment_name
[] = {"FD"};
57 static int found_frupath
= 0, list_only
= 0, recursive
= 0,
58 service_mode
= 0, svcargc
, update
= 0;
64 (void) fprintf(stderr
,
65 gettext("Usage: %s [ -l ] | [ [ -r ] frupath [ text ] ]\n"),
70 validate_fieldnames(int argc
, char *argv
[])
72 static int num
= sizeof (serv_data_list
)/sizeof (*serv_data_list
);
76 int i
, j
, match
, status
;
78 fru_elemdef_t definition
;
81 for (i
= 0; i
< argc
; i
+= 2) {
82 if (argv
[i
][0] == '/') {
83 fieldname
= &argv
[i
][1];
85 fieldname
= &argv
[i
][0];
89 for (j
= 0; j
< num
; j
++) {
90 if (strncmp(fieldname
, serv_data_list
[j
],
91 strlen(serv_data_list
[j
])) == 0) {
96 (void) fprintf(stderr
,
97 gettext("\"%s\" is not a supported field\n"),
102 if ((status
= fru_get_definition(argv
[i
], &definition
))
104 (void) fprintf(stderr
, gettext("\"%s\": %s\n"),
106 fru_strerror(status
));
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
]);
120 pathmatch(const char *path
)
124 if ((frupath
!= NULL
) &&
125 ((match
= strstr(path
, frupath
)) != NULL
) &&
126 ((match
+ strlen(frupath
)) == (path
+ strlen(path
))) &&
127 ((match
== path
) || (*(match
- 1) == '/'))) {
135 displayBinary(unsigned char *data
, size_t length
, fru_elemdef_t
*def
)
141 if (def
->disp_type
== FDISP_Hex
) {
142 for (i
= 0; i
< length
; i
++) {
143 (void) printf("%02X", data
[i
]);
148 (void) memcpy(&lldata
, data
, sizeof (lldata
));
149 switch (def
->disp_type
) {
152 mask
= 0x8000000000000000ULL
;
153 for (i
= 0; i
< (sizeof (uint64_t) *8); i
++) {
154 if (lldata
& (mask
>> i
)) {
164 (void) printf("%llo", lldata
);
169 (void) printf("%lld", lldata
);
174 char buffer
[PATH_MAX
];
176 time
= (time_t)lldata
;
177 (void) strftime(buffer
, PATH_MAX
, "%+",
179 (void) printf("%s", buffer
);
186 displayBAasBinary(unsigned char *data
, size_t length
)
191 for (i
= 0; i
< length
; i
++) {
193 * make a mask for the high order bit and adjust down through
196 for (mask
= 0x80; mask
> 0; mask
/= 2) {
197 if ((data
[i
] & mask
) != 0) /* bit must be on */
199 else /* bit is off... */
207 display_data(unsigned char *data
, size_t length
, fru_elemdef_t
*def
)
217 switch (def
->data_type
) {
220 displayBinary(data
, length
, def
);
224 case FDTYPE_ByteArray
:
226 switch (def
->disp_type
) {
228 displayBAasBinary(data
, length
);
231 for (i
= 0; i
< length
; i
++) {
232 (void) printf("%02X", data
[i
]);
239 assert(gettext("Unicode not yet supported") == 0);
243 char *disp_str
= (char *)alloca(length
+1);
244 for (i
= 0; i
< length
; i
++)
245 disp_str
[i
] = data
[i
];
247 (void) printf("%s", disp_str
);
251 case FDTYPE_Enumeration
:
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
);
263 (void) printf(gettext("Unrecognized Value: 0x"));
264 for (i
= 0; i
< sizeof (uint64_t); i
++)
265 (void) printf("%02X", data
[i
]);
274 print_node_data(fru_nodehdl_t cont_hdl
)
283 char *found_path
= NULL
;
284 fru_elemdef_t def
, def1
;
289 char elem_name
[PATH_MAX
];
292 total_cnt
= sizeof (serv_data_list
)/sizeof (*serv_data_list
);
293 ptr
= serv_data_list
;
295 total_cnt
= sizeof (cust_data_list
)/sizeof (*cust_data_list
);
296 ptr
= cust_data_list
;
300 for (numseg
= 0; numseg
< NUM_OF_SEGMENT
; numseg
++) {
302 for (list_cnt
= 0; list_cnt
< total_cnt
; list_cnt
++) {
303 if ((fru_get_definition(*ptr
, &def
)) != FRU_SUCCESS
) {
306 if ((fru_get_num_iterations(cont_hdl
,
307 &segment_name
[numseg
], 0, *ptr
,
308 &iter_cnt
, NULL
)) != FRU_SUCCESS
) {
313 for (count
= 0; count
< def
.enum_count
;
315 if (def
.iteration_type
!=
317 (void) snprintf(elem_name
,
319 "/%s[%d]/%s", *ptr
, iter
, def
.enum_table
[count
].text
);
321 (void) snprintf(elem_name
,
323 "/%s/%s", *ptr
, def
.enum_table
[count
].text
);
326 if ((fru_read_field(cont_hdl
,
327 &segment_name
[numseg
], instance
,
328 elem_name
, (void**)&data
, &dataLen
,
329 &found_path
)) != FRU_SUCCESS
) {
333 if ((fru_get_definition(
334 def
.enum_table
[count
].text
, &def1
)) != FRU_SUCCESS
) {
337 (void) printf(" %s: ",\
339 display_data(data
, dataLen
, &def1
);
343 } while (iter
< iter_cnt
);
350 convertBinaryToDecimal(char *ptr
)
358 str_len
= strlen(ptr
);
361 while (str_len
>= 1) {
363 if (data
[str_len
] == '0') {
364 result
+= (0 * pow(2, cnt
));
366 if (data
[str_len
] == '1') {
367 result
+= (1 * pow(2, cnt
));
371 ret
= (char *)lltostr(result
, "\n");
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.
382 convert_update(fru_nodehdl_t nodehdl
, char *segment
, char *field_name
,
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
));
399 if (field_value
== NULL
) {
403 switch (def
.data_type
) {
405 if (def
.disp_type
!= FDISP_Time
) {
406 if (field_value
[0] == 'b') {
408 convertBinaryToDecimal((field_value
411 num
= strtoll(field_value
, (char **)NULL
, 0);
412 if ((num
== 0) && (errno
== 0)) {
416 dataLen
= sizeof (uint64_t);
419 case FDTYPE_ByteArray
:
424 data
= (void *) field_value
;
425 dataLen
= strlen(field_value
);
426 if (dataLen
< def
.data_length
) {
430 case FDTYPE_Enumeration
:
431 for (i
= 0; i
< def
.enum_count
; i
++) {
432 if (strcmp(def
.enum_table
[i
].text
,
434 data
= (void *)(uintptr_t)
435 def
.enum_table
[i
].value
;
436 dataLen
= sizeof (uint64_t);
442 if (def
.iteration_count
== 0) {
448 case FDTYPE_UNDEFINED
:
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"),
461 * called by update_field() when a new data element is created.
462 * it updates the UNIX_Timestamp32 field with the current system time.
466 update_unixtimestamp(fru_nodehdl_t nodehdl
, char *segment
, char **ptr
)
471 fru_errno_t err
= FRU_SUCCESS
;
475 len
= strlen(*ptr
) + strlen("UNIX_Timestamp32") + 3;
476 field_name
= alloca(len
);
478 (void) snprintf(field_name
, len
, "/%s/UNIX_Timestamp32", *ptr
);
481 sp_tm
= localtime(&clock
);
482 time_data
= (uint64_t)mktime(sp_tm
);
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"),
494 * create segment on the specified fru represented by nodehdl.
498 create_segment(fru_nodehdl_t nodehdl
)
500 fru_segdesc_t seg_desc
;
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;
511 (void) memset(&def
, 0, sizeof (def
));
513 def
.desc
.raw_data
= seg_desc
.raw_data
;
514 def
.hw_desc
.all_bits
= 0;
516 for (cnt
= 0; cnt
< NUM_OF_SEGMENT
; cnt
++) {
517 (void) strncpy(def
.name
, segment_name
[cnt
], SEGMENT_NAME_SIZE
);
519 def
.size
= FD_SEGMENT_SIZE
;
521 if ((status
= fru_create_segment(nodehdl
, &def
))
527 if (status
!= FRU_SUCCESS
)
528 (void) fprintf(stderr
, gettext("fru_create_segment(): %s\n"),
529 fru_strerror(status
));
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.
540 updateiter_record(fru_nodehdl_t nodehdl
, int cnt
, char **ptr
,
541 char *field_name
, char *field_value
)
554 static char *elem_list
[] = {"/Geo_North", "/Geo_East",\
555 "/Geo_Alt", "/Geo_Location"};
557 elem_ptr
= elem_list
;
558 total_cnt
= sizeof (elem_list
)/sizeof (*elem_list
);
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"));
567 if ((strncmp(*elem_ptr
, tmpptr
, strlen(*elem_ptr
)) != 0)) {
576 (void) fprintf(stderr
,
577 gettext("Error: Update not allowed for field: %s\n"),
582 if ((fru_get_num_iterations(nodehdl
, &segment_name
[cnt
], 0,
583 *ptr
, &iter_cnt
, NULL
)) != FRU_SUCCESS
) {
587 /* add a new Iterated Record if complete path is not given */
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"),
601 (void) snprintf(rec_name
, sizeof (rec_name
), "/%s[%d]%s",
602 *ptr
, iter_cnt
-1, strrchr(field_name
, '/'));
604 if ((convert_update(nodehdl
, segment_name
[cnt
], rec_name
,
605 field_value
)) != 0) {
609 /* update success now update the unix timestamp */
611 (void) snprintf(rec_name
, sizeof (rec_name
), "/%s[%d]",
615 /* update UNIX_Timestamp32 with creation time */
616 if ((update_unixtimestamp(nodehdl
, segment_name
[cnt
],
625 update_field(fru_nodehdl_t nodehdl
, char *field_name
, char *field_value
)
630 char *found_path
= NULL
;
640 ptr
= serv_data_list
;
641 total_cnt
= sizeof (serv_data_list
)/sizeof (*serv_data_list
);
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)) {
655 ptr
= cust_data_list
;
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
) {
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) {
674 if ((convert_update(nodehdl
, segment_name
[cnt
],
675 field_name
, field_value
)) != 0) {
679 /* update UNIX_Timestamp32 with update time */
680 if ((update_unixtimestamp(nodehdl
, segment_name
[cnt
],
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) {
699 if ((fru_add_element(nodehdl
, segment_name
[cnt
],
700 *ptr
)) != FRU_SUCCESS
) {
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) {
715 /* update UNIX_Timestamp32 with creation time */
716 if ((update_unixtimestamp(nodehdl
, segment_name
[cnt
],
721 /* record added update the field with the value */
722 if ((convert_update(nodehdl
, segment_name
[cnt
], field_name
,
723 field_value
)) != 0) {
729 /* segment not present, create one and add the record */
730 cnt
= create_segment(nodehdl
);
735 if ((status
= fru_add_element(nodehdl
, segment_name
[cnt
], *ptr
))
737 (void) fprintf(stderr
, gettext("fru_add_element(): %s\n"),
738 fru_strerror(status
));
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) {
752 /* update UNIX_Timestamp32 with creation time */
753 if ((update_unixtimestamp(nodehdl
, segment_name
[cnt
],
758 if ((convert_update(nodehdl
, segment_name
[cnt
], field_name
,
759 field_value
)) != 0) {
766 update_node_data(fru_nodehdl_t node
)
772 for (i
= 0; i
< svcargc
; i
+= 2)
773 if (update_field(node
, svcargv
[i
], svcargv
[i
+ 1])) {
777 status
= update_field(node
, "/Customer_DataR/Cust_Data",
784 walk_tree(fru_nodehdl_t node
, const char *prior_path
, int process_tree
)
786 char *name
, path
[PATH_MAX
];
787 int process_self
= process_tree
, status
, update_status
= 0;
788 fru_nodehdl_t next_node
;
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
));
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
));
807 * Build the current path
809 if (snprintf(path
, sizeof (path
), "%s/%s", prior_path
, name
)
811 (void) fprintf(stderr
,
812 gettext("FRU tree path would overflow buffer\n"));
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
);
829 status
= update_node_data(node
);
830 update_status
= status
;
832 print_node_data(node
);
836 } else if (process_self
&& !recursive
) {
837 (void) fprintf(stderr
,
838 gettext("\"%s\" is not a container\n"), path
);
846 if (fru_get_child(node
, &next_node
) == FRU_SUCCESS
)
847 walk_tree(next_node
, path
, process_self
);
849 if (fru_get_peer(node
, &next_node
) == FRU_SUCCESS
)
850 walk_tree(next_node
, prior_path
, process_tree
);
853 * when update_node_data failed, need to exit with return value 1
860 main(int argc
, char *argv
[])
862 int process_tree
= 0, option
, status
;
869 opterr
= 0; /* "getopt" should not print to "stderr" */
870 while ((option
= getopt(argc
, argv
, "lrs")) != EOF
) {
902 (void) fprintf(stderr
,
903 gettext("\"frupath\" should not be empty\n"));
913 if ((argc
% 2) != 0) {
914 (void) fprintf(stderr
,
915 gettext("Must specify "
921 if (validate_fieldnames(argc
, argv
) != 0) {
927 } else if (argc
== 1)
928 customer_data
= argv
[0];
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
));
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 "
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"));
957 walk_tree(root
, "", process_tree
);
959 if ((frupath
!= NULL
) && (!found_frupath
)) {
960 (void) fprintf(stderr
,
961 gettext("\"%s\" not found\n"),