Home | History | Annotate | Download | only in fruadm
      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*)&num;
    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 }
    966