Merge commit 'a058d1cc571af5fbcfe7f1d719df1abbfdb722f3' into merges
[unleashed.git] / usr / src / cmd / fruadm / fruadm.c
blob0efb6c5539dcd478810190e321268d222378b336
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
23 * Copyright (c) 2014 Gary Mills
25 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
26 * Use is subject to license terms.
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>
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;
61 static void
62 usage(void)
64 (void) fprintf(stderr,
65 gettext("Usage: %s [ -l ] | [ [ -r ] frupath [ text ] ]\n"),
66 command);
69 static int
70 validate_fieldnames(int argc, char *argv[])
72 static int num = sizeof (serv_data_list)/sizeof (*serv_data_list);
74 char *fieldname;
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];
84 } else {
85 fieldname = &argv[i][0];
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;
95 if (!match) {
96 (void) fprintf(stderr,
97 gettext("\"%s\" is not a supported field\n"),
98 argv[i]);
99 return (1);
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);
116 return (0);
119 static int
120 pathmatch(const char *path)
122 char *match;
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);
131 return (0);
134 static void
135 displayBinary(unsigned char *data, size_t length, fru_elemdef_t *def)
137 int i = 0;
138 uint64_t lldata;
139 uint64_t mask;
141 if (def->disp_type == FDISP_Hex) {
142 for (i = 0; i < length; i++) {
143 (void) printf("%02X", data[i]);
145 return;
148 (void) memcpy(&lldata, data, sizeof (lldata));
149 switch (def->disp_type) {
150 case FDISP_Binary:
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");
160 return;
162 case FDISP_Octal:
164 (void) printf("%llo", lldata);
165 return;
167 case FDISP_Decimal:
169 (void) printf("%lld", lldata);
170 return;
172 case FDISP_Time:
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;
185 static void
186 displayBAasBinary(unsigned char *data, size_t length)
188 int i;
189 unsigned char mask;
191 for (i = 0; i < length; i++) {
193 * make a mask for the high order bit and adjust down through
194 * all the bits.
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");
203 (void) printf("\n");
206 static void
207 display_data(unsigned char *data, size_t length, fru_elemdef_t *def)
209 int i = 0;
210 uint64_t lldata;
212 if (data == 0x00) {
213 (void) printf("\n");
214 return;
217 switch (def->data_type) {
218 case FDTYPE_Binary:
220 displayBinary(data, length, def);
221 return;
224 case FDTYPE_ByteArray:
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]);
234 return;
236 return;
238 case FDTYPE_Unicode:
239 assert(gettext("Unicode not yet supported") == 0);
240 break;
241 case FDTYPE_ASCII:
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;
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);
259 free(tmp);
260 return;
263 (void) printf(gettext("Unrecognized Value: 0x"));
264 for (i = 0; i < sizeof (uint64_t); i++)
265 (void) printf("%02X", data[i]);
266 break;
268 default:
269 break;
273 static void
274 print_node_data(fru_nodehdl_t cont_hdl)
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];
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;
298 tmp_ptr = ptr;
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;
306 if ((fru_get_num_iterations(cont_hdl,
307 &segment_name[numseg], 0, *ptr,
308 &iter_cnt, NULL)) != FRU_SUCCESS) {
309 iter_cnt = 0;
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);
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;
333 if ((fru_get_definition(
334 def.enum_table[count].text, &def1)) != FRU_SUCCESS) {
335 break;
337 (void) printf(" %s: ",\
338 elem_name);
339 display_data(data, dataLen, &def1);
340 (void) printf("\n");
342 iter ++;
343 } while (iter < iter_cnt);
344 ptr++;
349 static char *
350 convertBinaryToDecimal(char *ptr)
352 int cnt = 0;
353 char *data;
354 int str_len;
355 char *ret = NULL;
356 uint64_t result = 0;
358 str_len = strlen(ptr);
359 data = ptr;
361 while (str_len >= 1) {
362 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));
369 cnt++;
371 ret = (char *)lltostr(result, "\n");
372 return (ret);
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.
381 static int
382 convert_update(fru_nodehdl_t nodehdl, char *segment, char *field_name,
383 char *field_value)
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;
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);
399 if (field_value == NULL) {
400 return (1);
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));
411 num = strtoll(field_value, (char **)NULL, 0);
412 if ((num == 0) && (errno == 0)) {
413 return (1);
415 data = (void*)&num;
416 dataLen = sizeof (uint64_t);
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++;
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;
440 return (1);
441 case FDTYPE_Record:
442 if (def.iteration_count == 0) {
443 return (1);
445 data = NULL;
446 dataLen = 0;
447 break;
448 case FDTYPE_UNDEFINED:
449 return (1);
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);
458 return (0);
461 * called by update_field() when a new data element is created.
462 * it updates the UNIX_Timestamp32 field with the current system time.
465 static int
466 update_unixtimestamp(fru_nodehdl_t nodehdl, char *segment, char **ptr)
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;
475 len = strlen(*ptr) + strlen("UNIX_Timestamp32") + 3;
476 field_name = alloca(len);
478 (void) snprintf(field_name, len, "/%s/UNIX_Timestamp32", *ptr);
480 clock = time(NULL);
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"),
487 fru_strerror(err));
488 return (1);
490 return (0);
494 * create segment on the specified fru represented by nodehdl.
497 static int
498 create_segment(fru_nodehdl_t nodehdl)
500 fru_segdesc_t seg_desc;
501 fru_segdef_t def;
502 int cnt;
503 int status;
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));
512 def.address = 0;
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);
518 if (cnt == 0) {
519 def.size = FD_SEGMENT_SIZE;
521 if ((status = fru_create_segment(nodehdl, &def))
522 != FRU_SUCCESS) {
523 continue;
525 return (cnt);
527 if (status != FRU_SUCCESS)
528 (void) fprintf(stderr, gettext("fru_create_segment(): %s\n"),
529 fru_strerror(status));
530 return (1);
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.
539 static int
540 updateiter_record(fru_nodehdl_t nodehdl, int cnt, char **ptr,
541 char *field_name, char *field_value)
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;
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"));
565 return (1);
567 if ((strncmp(*elem_ptr, tmpptr, strlen(*elem_ptr)) != 0)) {
568 elem_ptr++;
569 continue;
571 found = 1;
572 break;
575 if (found == 0) {
576 (void) fprintf(stderr,
577 gettext("Error: Update not allowed for field: %s\n"),
578 field_name);
579 return (1);
582 if ((fru_get_num_iterations(nodehdl, &segment_name[cnt], 0,
583 *ptr, &iter_cnt, NULL)) != FRU_SUCCESS) {
584 return (1);
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);
598 iter_cnt = 1;
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) {
606 return (1);
609 /* update success now update the unix timestamp */
611 (void) snprintf(rec_name, sizeof (rec_name), "/%s[%d]",
612 *ptr, iter_cnt-1);
613 tmpptr = rec_name;
615 /* update UNIX_Timestamp32 with creation time */
616 if ((update_unixtimestamp(nodehdl, segment_name[cnt],
617 &tmpptr)) != 0) {
618 return (1);
621 return (0);
624 static int
625 update_field(fru_nodehdl_t nodehdl, char *field_name, char *field_value)
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;
639 if (service_mode) {
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)) {
647 ptr++;
648 add_flag = 0;
649 continue;
651 add_flag = 1;
652 break;
654 } else {
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) {
662 continue;
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);
670 return (0);
674 if ((convert_update(nodehdl, segment_name[cnt],
675 field_name, field_value)) != 0) {
676 return (1);
679 /* update UNIX_Timestamp32 with update time */
680 if ((update_unixtimestamp(nodehdl, segment_name[cnt],
681 ptr)) != 0) {
682 return (1);
684 return (0);
687 elem.num = 0;
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;
698 if (add_flag) {
699 if ((fru_add_element(nodehdl, segment_name[cnt],
700 *ptr)) != FRU_SUCCESS) {
701 continue;
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);
711 return (0);
715 /* update UNIX_Timestamp32 with creation time */
716 if ((update_unixtimestamp(nodehdl, segment_name[cnt],
717 ptr)) != 0) {
718 return (1);
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);
726 return (0);
729 /* segment not present, create one and add the record */
730 cnt = create_segment(nodehdl);
731 if (cnt == 1) {
732 return (1);
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);
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);
748 return (0);
752 /* update UNIX_Timestamp32 with creation time */
753 if ((update_unixtimestamp(nodehdl, segment_name[cnt],
754 ptr)) != 0) {
755 return (1);
758 if ((convert_update(nodehdl, segment_name[cnt], field_name,
759 field_value)) != 0) {
760 return (1);
762 return (0);
765 static int
766 update_node_data(fru_nodehdl_t node)
768 int i;
769 int status = 0;
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;
776 } else {
777 status = update_field(node, "/Customer_DataR/Cust_Data",
778 customer_data);
780 return (status);
783 static void
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;
789 fru_node_t type;
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);
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);
807 * Build the current path
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);
816 free(name);
819 * Process the node
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;
832 print_node_data(node);
833 if (!recursive) {
834 exit(status);
836 } else if (process_self && !recursive) {
837 (void) fprintf(stderr,
838 gettext("\"%s\" is not a container\n"), path);
839 exit(1);
844 * Recurse
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
855 if (update_status)
856 exit(1);
860 main(int argc, char *argv[])
862 int process_tree = 0, option, status;
864 fru_nodehdl_t root;
867 command = argv[0];
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);
887 argc -= optind;
888 argv += optind;
890 if (argc == 0) {
891 process_tree = 1;
892 recursive = 1;
893 } else {
894 if (list_only) {
895 usage();
896 return (1);
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);
907 argc--;
908 argv++;
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);
921 if (validate_fieldnames(argc, argv) != 0) {
922 return (1);
925 svcargc = argc;
926 svcargv = argv;
927 } else if (argc == 1)
928 customer_data = argv[0];
929 else {
930 usage();
931 return (1);
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);
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);
957 walk_tree(root, "", process_tree);
959 if ((frupath != NULL) && (!found_frupath)) {
960 (void) fprintf(stderr,
961 gettext("\"%s\" not found\n"),
962 frupath);
963 return (1);
966 return (0);