summaryrefslogtreecommitdiff
path: root/usr/src/cmd/fruadm
diff options
context:
space:
mode:
authorstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
committerstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
commit7c478bd95313f5f23a4c958a745db2134aa03244 (patch)
treec871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/cmd/fruadm
downloadillumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz
OpenSolaris Launch
Diffstat (limited to 'usr/src/cmd/fruadm')
-rw-r--r--usr/src/cmd/fruadm/Makefile60
-rw-r--r--usr/src/cmd/fruadm/fruadm.c960
2 files changed, 1020 insertions, 0 deletions
diff --git a/usr/src/cmd/fruadm/Makefile b/usr/src/cmd/fruadm/Makefile
new file mode 100644
index 0000000000..c41aab5218
--- /dev/null
+++ b/usr/src/cmd/fruadm/Makefile
@@ -0,0 +1,60 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+PROG = fruadm
+PLATFORM = sun4u
+CLASS = 32 # so ParallelMake isn't confused by empty rules
+
+include $(SRC)/cmd/Makefile.cmd
+include $(SRC)/Makefile.psm
+
+FRULIBS = -L$(SRC)/lib/libfru/$(MACH) -lfru
+
+CFLAGS += $(CCVERBOSE)
+CPPFLAGS += -I$(SRC)/lib/libfru/include
+LINTFLAGS += -u
+LDLIBS += $(FRULIBS) -lm
+
+lint := FRULIBS =
+
+FILEMODE = 755
+OWNER = root
+GROUP = sys
+
+.KEEP_STATE:
+
+all: $(PROG)
+
+install: all $(USR_PSM_SBIN_DIR) $(USR_PSM_SBIN_PROG)
+
+clean:
+
+lint: lint_PROG
+
+include $(SRC)/cmd/Makefile.targ
+include $(SRC)/Makefile.psm.targ
diff --git a/usr/src/cmd/fruadm/fruadm.c b/usr/src/cmd/fruadm/fruadm.c
new file mode 100644
index 0000000000..6a1e533c08
--- /dev/null
+++ b/usr/src/cmd/fruadm/fruadm.c
@@ -0,0 +1,960 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2002-2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libintl.h>
+#include <libfru.h>
+#include <errno.h>
+#include <math.h>
+#include <alloca.h>
+#include <assert.h>
+#include <sys/systeminfo.h>
+
+#define NUM_OF_SEGMENT 1
+#define SEGMENT_NAME_SIZE 2
+
+#define FD_SEGMENT_SIZE 2949
+
+static char *command, *customer_data = NULL, *frupath = NULL, **svcargv;
+
+/* DataElement supported in the customer operation */
+static char *cust_data_list[] = {"Customer_DataR"};
+
+/* DataElement supported in the service operation */
+static char *serv_data_list[] = {"InstallationR", "ECO_CurrentR"};
+
+/* currently supported segment name */
+static char *segment_name[] = {"FD"};
+
+static int found_frupath = 0, list_only = 0, recursive = 0,
+ service_mode = 0, svcargc, update = 0;
+
+
+static void
+usage(void)
+{
+ (void) fprintf(stderr,
+ gettext("Usage: %s [ -l ] | [ [ -r ] frupath [ text ] ]\n"),
+ command);
+}
+
+static int
+validate_fieldnames(int argc, char *argv[])
+{
+ static int num = sizeof (serv_data_list)/sizeof (*serv_data_list);
+
+ char *fieldname;
+
+ int i, j, match, status;
+
+ fru_elemdef_t definition;
+
+
+ for (i = 0; i < argc; i += 2) {
+ if (argv[i][0] == '/') {
+ fieldname = &argv[i][1];
+ } else {
+ fieldname = &argv[i][0];
+ }
+
+ match = 0;
+ for (j = 0; j < num; j++) {
+ if (strncmp(fieldname, serv_data_list[j],
+ strlen(serv_data_list[j])) == 0) {
+ match = 1;
+ }
+ }
+ if (!match) {
+ (void) fprintf(stderr,
+ gettext("\"%s\" is not a supported field\n"),
+ argv[i]);
+ return (1);
+ }
+
+ if ((status = fru_get_definition(argv[i], &definition))
+ != FRU_SUCCESS) {
+ (void) fprintf(stderr, gettext("\"%s\": %s\n"),
+ argv[i],
+ fru_strerror(status));
+ return (1);
+ } else if ((definition.data_type == FDTYPE_Record) ||
+ (definition.data_type == FDTYPE_UNDEFINED)) {
+ (void) fprintf(stderr,
+ gettext("\"%s\" is not a field\n"), argv[i]);
+ return (1);
+ }
+ }
+
+ return (0);
+}
+
+static int
+pathmatch(const char *path)
+{
+ char *match;
+
+ if ((frupath != NULL) &&
+ ((match = strstr(path, frupath)) != NULL) &&
+ ((match + strlen(frupath)) == (path + strlen(path))) &&
+ ((match == path) || (*(match - 1) == '/'))) {
+ found_frupath = 1;
+ return (1);
+ }
+
+ return (0);
+}
+
+static void
+displayBinary(unsigned char *data, size_t length, fru_elemdef_t *def)
+{
+ int i = 0;
+ uint64_t lldata;
+ uint64_t mask;
+
+ if (def->disp_type == FDISP_Hex) {
+ for (i = 0; i < length; i++) {
+ (void) printf("%02X", data[i]);
+ }
+ return;
+ }
+
+ (void) memcpy(&lldata, data, sizeof (lldata));
+ switch (def->disp_type) {
+ case FDISP_Binary:
+ {
+ mask = 0x8000000000000000;
+ for (i = 0; i < (sizeof (uint64_t) *8); i++) {
+ if (lldata & (mask >> i)) {
+ (void) printf("1");
+ } else {
+ (void) printf("0");
+ }
+ }
+ return;
+ }
+ case FDISP_Octal:
+ {
+ (void) printf("%llo", lldata);
+ return;
+ }
+ case FDISP_Decimal:
+ {
+ (void) printf("%lld", lldata);
+ return;
+ }
+ case FDISP_Time:
+ {
+ char buffer[PATH_MAX];
+ time_t time;
+ time = (time_t)lldata;
+ (void) strftime(buffer, PATH_MAX, "%C",
+ localtime(&time));
+ (void) printf("%s", buffer);
+ return;
+ }
+ }
+}
+
+static void
+displayBAasBinary(unsigned char *data, size_t length)
+{
+ int i;
+ unsigned char mask;
+
+ for (i = 0; i < length; i++) {
+ /*
+ * make a mask for the high order bit and adjust down through
+ * all the bits.
+ */
+ for (mask = 0x80; mask > 0; mask /= 2) {
+ if ((data[i] & mask) != 0) /* bit must be on */
+ (void) printf("1");
+ else /* bit is off... */
+ (void) printf("0");
+ }
+ }
+ (void) printf("\n");
+}
+
+static void
+display_data(unsigned char *data, size_t length, fru_elemdef_t *def)
+{
+ int i = 0;
+ uint64_t lldata;
+
+ if (data == 0x00) {
+ (void) printf("\n");
+ return;
+ }
+
+ switch (def->data_type) {
+ case FDTYPE_Binary:
+ {
+ displayBinary(data, length, def);
+ return;
+ }
+
+ case FDTYPE_ByteArray:
+ {
+ switch (def->disp_type) {
+ case FDISP_Binary:
+ displayBAasBinary(data, length);
+ return;
+ case FDISP_Hex:
+ for (i = 0; i < length; i++) {
+ (void) printf("%02X", data[i]);
+ }
+ return;
+ }
+ return;
+ }
+ case FDTYPE_Unicode:
+ assert(gettext("Unicode not yet supported") == 0);
+ break;
+ case FDTYPE_ASCII:
+ {
+ char *disp_str = (char *)alloca(length+1);
+ for (i = 0; i < length; i++)
+ disp_str[i] = data[i];
+ disp_str[i] = '\0';
+ (void) printf("%s", disp_str);
+ return;
+ }
+
+ case FDTYPE_Enumeration:
+ {
+ lldata = strtoull((const char *)data, NULL, 0);
+ for (i = 0; i < def->enum_count; i++) {
+ if (def->enum_table[i].value == lldata) {
+ /* strdup such that map_... can realloc if necessary. */
+ char *tmp = strdup(def->enum_table[i].text);
+ (void) printf("%s", tmp);
+ free(tmp);
+ return;
+ }
+ }
+ (void) printf(gettext("Unrecognized Value: 0x"));
+ for (i = 0; i < sizeof (uint64_t); i++)
+ (void) printf("%02X", data[i]);
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+static void
+print_node_data(fru_nodehdl_t cont_hdl)
+{
+ int iter_cnt = 0;
+ int iter;
+ int numseg;
+ int list_cnt;
+ unsigned char *data;
+ size_t dataLen;
+ int total_cnt;
+ char *found_path = NULL;
+ fru_elemdef_t def, def1;
+ int instance = 0;
+ char **ptr;
+ char **tmp_ptr;
+ int count = 0;
+ char elem_name[PATH_MAX];
+
+ if (service_mode) {
+ total_cnt = sizeof (serv_data_list)/sizeof (*serv_data_list);
+ ptr = serv_data_list;
+ } else {
+ total_cnt = sizeof (cust_data_list)/sizeof (*cust_data_list);
+ ptr = cust_data_list;
+ }
+ tmp_ptr = ptr;
+
+ for (numseg = 0; numseg < NUM_OF_SEGMENT; numseg++) {
+ ptr = tmp_ptr;
+ for (list_cnt = 0; list_cnt < total_cnt; list_cnt++) {
+ if ((fru_get_definition(*ptr, &def)) != FRU_SUCCESS) {
+ continue;
+ }
+ if ((fru_get_num_iterations(cont_hdl,
+ &segment_name[numseg], 0, *ptr,
+ &iter_cnt, NULL)) != FRU_SUCCESS) {
+ iter_cnt = 0;
+ }
+ iter = 0;
+ do {
+ for (count = 0; count < def.enum_count;
+ count++) {
+ if (def.iteration_type !=
+ FRU_NOT_ITERATED) {
+ (void) snprintf(elem_name,
+ sizeof (elem_name),
+ "/%s[%d]/%s", *ptr, iter, def.enum_table[count].text);
+ } else {
+ (void) snprintf(elem_name,
+ sizeof (elem_name),
+ "/%s/%s", *ptr, def.enum_table[count].text);
+ }
+
+ if ((fru_read_field(cont_hdl,
+ &segment_name[numseg], instance, elem_name, (void**)&data,
+ &dataLen, &found_path)) != FRU_SUCCESS) {
+ break;
+ }
+
+ if ((fru_get_definition(
+ def.enum_table[count].text, &def1)) != FRU_SUCCESS) {
+ break;
+ }
+ (void) printf(" %s: ",\
+ elem_name);
+ display_data(data, dataLen, &def1);
+ (void) printf("\n");
+ }
+ iter ++;
+ } while (iter < iter_cnt);
+ ptr++;
+ }
+ }
+}
+
+static char *
+convertBinaryToDecimal(char *ptr)
+{
+ int cnt = 0;
+ char *data;
+ int str_len;
+ char *ret = NULL;
+ uint64_t result = 0;
+
+ str_len = strlen(ptr);
+ data = ptr;
+
+ while (str_len >= 1) {
+ str_len -= 1;
+ if (data[str_len] == '0') {
+ result += (0 * pow(2, cnt));
+ }
+ if (data[str_len] == '1') {
+ result += (1 * pow(2, cnt));
+ }
+ cnt++;
+ }
+ ret = (char *)lltostr(result, "\n");
+ return (ret);
+}
+
+/*
+ * called update_field() to update the field with specific field value.
+ * nodehdl represents the fru, segment represents the segment name in the fru.
+ * field_name represents the field to be updated with the value field_value.
+ */
+
+static int
+convert_update(fru_nodehdl_t nodehdl, char *segment, char *field_name,
+ char *field_value)
+{
+ uint64_t num = 0;
+ fru_elemdef_t def;
+ fru_errno_t err;
+ void *data = NULL;
+ size_t dataLen = 0;
+ int i;
+
+ if ((err = fru_get_definition(field_name, &def)) != FRU_SUCCESS) {
+ (void) fprintf(stderr,
+ gettext("Failed to get definition %s: %s\n"),
+ field_name, fru_strerror(err));
+ return (1);
+ }
+
+ if (field_value == NULL) {
+ return (1);
+ }
+
+ switch (def.data_type) {
+ case FDTYPE_Binary:
+ if (def.disp_type != FDISP_Time) {
+ if (field_value[0] == 'b') {
+ field_value =
+ convertBinaryToDecimal((field_value+1));
+ }
+ num = strtoll(field_value, (char **)NULL, 0);
+ if ((num == 0) && (errno == 0)) {
+ return (1);
+ }
+ data = (void*)&num;
+ dataLen = sizeof (uint64_t);
+ }
+ break;
+ case FDTYPE_ByteArray:
+ return (1);
+ case FDTYPE_Unicode:
+ return (1);
+ case FDTYPE_ASCII:
+ data = (void *) field_value;
+ dataLen = strlen(field_value);
+ if (dataLen < def.data_length) {
+ dataLen++;
+ }
+ break;
+ case FDTYPE_Enumeration:
+ for (i = 0; i < def.enum_count; i++) {
+ if (strcmp(def.enum_table[i].text,
+ field_value) == 0) {
+ data = (void *)def.enum_table[i].value;
+ dataLen = sizeof (uint64_t);
+ break;
+ }
+ }
+ return (1);
+ case FDTYPE_Record:
+ if (def.iteration_count == 0) {
+ return (1);
+ }
+ data = NULL;
+ dataLen = 0;
+ break;
+ case FDTYPE_UNDEFINED:
+ return (1);
+ }
+
+ if ((err = fru_update_field(nodehdl, segment, 0, field_name, data,
+ dataLen)) != FRU_SUCCESS) {
+ (void) fprintf(stderr, gettext("fru_update_field(): %s\n"),
+ fru_strerror(err));
+ return (1);
+ }
+ return (0);
+}
+/*
+ * called by update_field() when a new data element is created.
+ * it updates the UNIX_Timestamp32 field with the current system time.
+ */
+
+static int
+update_unixtimestamp(fru_nodehdl_t nodehdl, char *segment, char **ptr)
+{
+ char *field_name;
+ time_t clock;
+ struct tm *sp_tm;
+ fru_errno_t err = FRU_SUCCESS;
+ uint64_t time_data;
+ size_t len;
+
+ len = strlen(*ptr) + strlen("UNIX_Timestamp32") + 3;
+ field_name = alloca(len);
+
+ (void) snprintf(field_name, len, "/%s/UNIX_Timestamp32", *ptr);
+
+ clock = time(NULL);
+ sp_tm = localtime(&clock);
+ time_data = (uint64_t)mktime(sp_tm);
+
+ if ((err = fru_update_field(nodehdl, segment, 0, field_name,
+ (void *)&time_data, sizeof (time_data))) != FRU_SUCCESS) {
+ (void) fprintf(stderr, gettext("fru_update_field(): %s\n"),
+ fru_strerror(err));
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * create segment on the specified fru represented by nodehdl.
+ */
+
+static int
+create_segment(fru_nodehdl_t nodehdl)
+{
+ fru_segdesc_t seg_desc;
+ fru_segdef_t def;
+ int cnt;
+
+ seg_desc.field.field_perm = 0x6;
+ seg_desc.field.operations_perm = 0x6;
+ seg_desc.field.engineering_perm = 0x6;
+ seg_desc.field.repair_perm = 0x6;
+
+ def.address = 0;
+ def.desc.raw_data = seg_desc.raw_data;
+ def.hw_desc.all_bits = 0;
+
+ for (cnt = 0; cnt < NUM_OF_SEGMENT; cnt++) {
+ (void) strncpy(def.name, segment_name[cnt], SEGMENT_NAME_SIZE);
+ if (cnt == 0) {
+ def.size = FD_SEGMENT_SIZE;
+ }
+ if ((fru_create_segment(nodehdl, &def)) != FRU_SUCCESS) {
+ continue;
+ }
+ return (cnt);
+ }
+ return (1);
+}
+
+/*
+ * called from update_field() when service flag is ON. currently
+ * supported iterated record is InstallationR and fields supported for
+ * update are Geo_North, Geo_East, Geo_Alt, Geo_Location.
+ */
+
+static int
+updateiter_record(fru_nodehdl_t nodehdl, int cnt, char **ptr,
+ char *field_name, char *field_value)
+{
+ int iter_cnt = 0;
+ char rec_name[512];
+ void *data = NULL;
+ char *tmpptr = NULL;
+ size_t dataLen = 0;
+ char **elem_ptr;
+ int found = 0;
+ int index;
+ int total_cnt;
+
+ static char *elem_list[] = {"/Geo_North", "/Geo_East",\
+ "/Geo_Alt", "/Geo_Location"};
+
+ elem_ptr = elem_list;
+ total_cnt = sizeof (elem_list)/sizeof (*elem_list);
+
+ for (index = 0; index < total_cnt; index++) {
+ tmpptr = strrchr(field_name, '/');
+ if (tmpptr == NULL) {
+ (void) fprintf(stderr,
+ gettext("Error: Data Element not known\n"));
+ return (1);
+ }
+ if ((strncmp(*elem_ptr, tmpptr, strlen(*elem_ptr)) != 0)) {
+ elem_ptr++;
+ continue;
+ }
+ found = 1;
+ break;
+ }
+
+ if (found == 0) {
+ (void) fprintf(stderr,
+ gettext("Error: Update not allowed for field: %s\n"),
+ field_name);
+ return (1);
+ }
+
+ if ((fru_get_num_iterations(nodehdl, &segment_name[cnt], 0,
+ *ptr, &iter_cnt, NULL)) != FRU_SUCCESS) {
+ return (1);
+ }
+
+ /* add a new Iterated Record if complete path is not given */
+ if (iter_cnt == 0) {
+ (void) snprintf(rec_name, sizeof (rec_name), "/%s[+]", *ptr);
+ if ((fru_update_field(nodehdl, segment_name[cnt], 0,
+ rec_name, data, dataLen)) != FRU_SUCCESS) {
+ return (1);
+ }
+
+ iter_cnt = 1;
+ }
+
+ (void) snprintf(rec_name, sizeof (rec_name), "/%s[%d]%s",
+ *ptr, iter_cnt-1, strrchr(field_name, '/'));
+
+ if ((convert_update(nodehdl, segment_name[cnt], rec_name,
+ field_value)) != 0) {
+ return (1);
+ }
+
+ /* update success now update the unix timestamp */
+
+ (void) snprintf(rec_name, sizeof (rec_name), "/%s[%d]",
+ *ptr, iter_cnt-1);
+ tmpptr = rec_name;
+
+ /* update UNIX_Timestamp32 with creation time */
+ if ((update_unixtimestamp(nodehdl, segment_name[cnt],
+ &tmpptr)) != 0) {
+ return (1);
+ }
+
+ return (0);
+}
+
+static int
+update_field(fru_nodehdl_t nodehdl, char *field_name, char *field_value)
+{
+ fru_elemdef_t def;
+ unsigned char *data;
+ size_t dataLen;
+ char *found_path = NULL;
+ int cnt;
+ char **ptr;
+ fru_strlist_t elem;
+ int elem_cnt;
+ int add_flag = 1;
+ int total_cnt;
+
+ if (service_mode) {
+ ptr = serv_data_list;
+ total_cnt = sizeof (serv_data_list)/sizeof (*serv_data_list);
+
+ for (cnt = 0; cnt < total_cnt; cnt++) {
+ if ((strncmp(*ptr, &field_name[1], strlen(*ptr)) \
+ != 0) && (strncmp(*ptr, &field_name[0],
+ strlen(*ptr)) != 0)) {
+ ptr++;
+ add_flag = 0;
+ continue;
+ }
+ add_flag = 1;
+ break;
+ }
+ } else {
+ ptr = cust_data_list;
+ }
+
+ /* look for the field in either of the segment if found update it */
+ for (cnt = 0; cnt < NUM_OF_SEGMENT; cnt++) {
+ if ((fru_read_field(nodehdl, &segment_name[cnt], 0, field_name,
+ (void **) &data, &dataLen, &found_path)) != FRU_SUCCESS) {
+ continue;
+ }
+ if ((fru_get_definition(*ptr, &def)) == FRU_SUCCESS) {
+ if (def.iteration_count != 0) {
+ if ((updateiter_record(nodehdl, cnt, ptr,
+ field_name, field_value)) != 0) {
+ return (1);
+ }
+ return (0);
+ }
+ }
+
+ if ((convert_update(nodehdl, segment_name[cnt],
+ field_name, field_value)) != 0) {
+ return (1);
+ }
+
+ /* update UNIX_Timestamp32 with update time */
+ if ((update_unixtimestamp(nodehdl, segment_name[cnt],
+ ptr)) != 0) {
+ return (1);
+ }
+ return (0);
+ }
+
+ elem.num = 0;
+
+ /* field not found add the the record in one of the segment */
+ for (cnt = 0; cnt < NUM_OF_SEGMENT; cnt++) {
+ fru_list_elems_in(nodehdl, segment_name[cnt], &elem);
+ for (elem_cnt = 0; elem_cnt < elem.num; elem_cnt++) {
+ if ((strcmp(*ptr, elem.strs[elem_cnt])) == 0) {
+ add_flag = 0;
+ }
+ }
+
+ if (add_flag) {
+ if ((fru_add_element(nodehdl, segment_name[cnt],
+ *ptr)) != FRU_SUCCESS) {
+ continue;
+ }
+ }
+
+ if ((fru_get_definition(*ptr, &def)) == FRU_SUCCESS) {
+ if (def.iteration_count != 0) {
+ if ((updateiter_record(nodehdl, cnt, ptr,
+ field_name, field_value)) != 0) {
+ return (1);
+ }
+ return (0);
+ }
+ }
+
+ /* update UNIX_Timestamp32 with creation time */
+ if ((update_unixtimestamp(nodehdl, segment_name[cnt],
+ ptr)) != 0) {
+ return (1);
+ }
+
+ /* record added update the field with the value */
+ if ((convert_update(nodehdl, segment_name[cnt], field_name,
+ field_value)) != 0) {
+ return (1);
+ }
+ return (0);
+ }
+
+ /* segment not present, create one and add the record */
+ cnt = create_segment(nodehdl);
+ if (cnt == 1) {
+ return (1);
+ }
+
+ if ((fru_add_element(nodehdl, segment_name[cnt], *ptr))
+ != FRU_SUCCESS) {
+ return (1);
+ }
+
+ if ((fru_get_definition(*ptr, &def)) == FRU_SUCCESS) {
+ if (def.iteration_count != 0) {
+ if ((updateiter_record(nodehdl, cnt, ptr,
+ field_name, field_value)) != 0) {
+ return (1);
+ }
+ return (0);
+ }
+ }
+
+ /* update UNIX_Timestamp32 with creation time */
+ if ((update_unixtimestamp(nodehdl, segment_name[cnt],
+ ptr)) != 0) {
+ return (1);
+ }
+
+ if ((convert_update(nodehdl, segment_name[cnt], field_name,
+ field_value)) != 0) {
+ return (1);
+ }
+ return (0);
+}
+
+static void
+update_node_data(fru_nodehdl_t node)
+{
+ int i;
+
+ if (service_mode) {
+ for (i = 0; i < svcargc; i += 2)
+ (void) update_field(node, svcargv[i], svcargv[i + 1]);
+ } else {
+ (void) update_field(node, "/Customer_DataR/Cust_Data",
+ customer_data);
+ }
+}
+
+static void
+walk_tree(fru_nodehdl_t node, const char *prior_path, int process_tree)
+{
+ char *name, path[PATH_MAX];
+ int process_self = process_tree, status;
+ fru_nodehdl_t next_node;
+ fru_node_t type;
+
+ if ((status = fru_get_node_type(node, &type)) != FRU_SUCCESS) {
+ (void) fprintf(stderr,
+ gettext("Error getting FRU tree node type: %s\n"),
+ fru_strerror(status));
+ exit(1);
+ }
+
+ if ((status = fru_get_name_from_hdl(node, &name)) != FRU_SUCCESS) {
+ (void) fprintf(stderr,
+ gettext("Error getting name of FRU tree node: %s\n"),
+ fru_strerror(status));
+ exit(1);
+ }
+
+
+ /*
+ * Build the current path
+ */
+ if (snprintf(path, sizeof (path), "%s/%s", prior_path, name)
+ >= sizeof (path)) {
+ (void) fprintf(stderr,
+ gettext("FRU tree path would overflow buffer\n"));
+ exit(1);
+ }
+
+ free(name);
+
+ /*
+ * Process the node
+ */
+ if (list_only) {
+ (void) printf("%s%s\n", path, ((type == FRU_NODE_FRU) ?
+ " (fru)" : ((type == FRU_NODE_CONTAINER) ?
+ " (container)" : "")));
+ } else if ((process_tree || (process_self = pathmatch(path))) &&
+ (type == FRU_NODE_CONTAINER)) {
+ (void) printf("%s\n", path);
+ if (update) update_node_data(node);
+ print_node_data(node);
+ if (!recursive) exit(0);
+ } else if (process_self && !recursive) {
+ (void) fprintf(stderr,
+ gettext("\"%s\" is not a container\n"), path);
+ exit(1);
+ }
+
+
+ /*
+ * Recurse
+ */
+ if (fru_get_child(node, &next_node) == FRU_SUCCESS)
+ walk_tree(next_node, path, process_self);
+
+ if (fru_get_peer(node, &next_node) == FRU_SUCCESS)
+ walk_tree(next_node, prior_path, process_tree);
+}
+
+static int
+has_system_controller()
+{
+ char platform[PATH_MAX];
+
+ int size;
+
+ if (((size = sysinfo(SI_PLATFORM, platform, sizeof (platform)))
+ < 0) || (size > sizeof (platform)))
+ return (-1);
+
+ if ((strcmp("SUNW,Sun-Fire", platform) == 0) ||
+ (strcmp("SUNW,Sun-Fire-15000", platform) == 0)) {
+ return (1);
+ }
+
+ return (0);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int process_tree = 0, option, status;
+
+ fru_nodehdl_t root;
+
+
+ command = argv[0];
+
+ opterr = 0; /* "getopt" should not print to "stderr" */
+ while ((option = getopt(argc, argv, "lrs")) != EOF) {
+ switch (option) {
+ case 'l':
+ list_only = 1;
+ break;
+ case 'r':
+ recursive = 1;
+ break;
+ case 's':
+ service_mode = 1;
+ break;
+ default:
+ usage();
+ return (1);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 0) {
+ process_tree = 1;
+ recursive = 1;
+ } else {
+ if (list_only) {
+ usage();
+ return (1);
+ }
+
+ frupath = argv[0];
+ if (*frupath == 0) {
+ usage();
+ (void) fprintf(stderr,
+ gettext("\"frupath\" should not be empty\n"));
+ return (1);
+ }
+
+ argc--;
+ argv++;
+
+ if (argc > 0) {
+ update = 1;
+ if (service_mode) {
+ if ((argc % 2) != 0) {
+ (void) fprintf(stderr,
+ gettext("Must specify "
+ "field-value pairs "
+ "for update\n"));
+ return (1);
+ }
+
+ if (validate_fieldnames(argc, argv) != 0) {
+ return (1);
+ }
+
+ svcargc = argc;
+ svcargv = argv;
+ } else if (argc == 1)
+ customer_data = argv[0];
+ else {
+ usage();
+ return (1);
+ }
+ }
+ }
+
+ if ((status = fru_open_data_source("picl", NULL)) != FRU_SUCCESS) {
+ (void) fprintf(stderr,
+ gettext("Unable to access FRU data source: %s\n"),
+ fru_strerror(status));
+ return (1);
+ }
+
+ if ((status = fru_get_root(&root)) == FRU_NODENOTFOUND) {
+ if (has_system_controller() == 1) {
+ (void) fprintf(stderr,
+ gettext("Access FRUs from the "
+ "System Controller\n"));
+ } else {
+ (void) fprintf(stderr,
+ gettext("This system does not provide "
+ "FRU ID data\n"));
+
+ }
+ return (1);
+ } else if (status != FRU_SUCCESS) {
+ (void) fprintf(stderr,
+ gettext("Unable to access FRU ID data "
+ "due to data source error\n"));
+ return (1);
+ }
+
+ walk_tree(root, "", process_tree);
+
+ if ((frupath != NULL) && (!found_frupath)) {
+ (void) fprintf(stderr,
+ gettext("\"%s\" not found\n"),
+ frupath);
+ return (1);
+ }
+
+ return (0);
+}