17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
57aec1d6eScindi * Common Development and Distribution License (the "License").
67aec1d6eScindi * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
2244ed9dbbSStephen Hanson * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
237c478bd9Sstevel@tonic-gate *
247c478bd9Sstevel@tonic-gate * platform.c -- interfaces to the platform's configuration information
257c478bd9Sstevel@tonic-gate *
267c478bd9Sstevel@tonic-gate * this platform.c allows eft to run on Solaris systems.
277c478bd9Sstevel@tonic-gate */
287c478bd9Sstevel@tonic-gate
297c478bd9Sstevel@tonic-gate #include <stdio.h>
307c478bd9Sstevel@tonic-gate #include <stdlib.h>
317c478bd9Sstevel@tonic-gate #include <string.h>
327c478bd9Sstevel@tonic-gate #include <strings.h>
337c478bd9Sstevel@tonic-gate #include <ctype.h>
347c478bd9Sstevel@tonic-gate #include <dirent.h>
357c478bd9Sstevel@tonic-gate #include <libnvpair.h>
367c478bd9Sstevel@tonic-gate #include <dlfcn.h>
377c478bd9Sstevel@tonic-gate #include <unistd.h>
387c478bd9Sstevel@tonic-gate #include <errno.h>
397c478bd9Sstevel@tonic-gate #include <stropts.h>
407c478bd9Sstevel@tonic-gate #include <sys/types.h>
413e8d8e18Sdb #include <sys/stat.h>
427c478bd9Sstevel@tonic-gate #include <sys/wait.h>
437c478bd9Sstevel@tonic-gate #include <sys/filio.h>
447c478bd9Sstevel@tonic-gate #include <sys/param.h>
457c478bd9Sstevel@tonic-gate #include <sys/fm/protocol.h>
467c478bd9Sstevel@tonic-gate #include <fm/fmd_api.h>
470eb822a1Scindi #include <fm/fmd_fmri.h>
487aec1d6eScindi #include <fm/libtopo.h>
490eb822a1Scindi #include <fm/topo_hc.h>
507c478bd9Sstevel@tonic-gate #include "alloc.h"
517c478bd9Sstevel@tonic-gate #include "out.h"
527c478bd9Sstevel@tonic-gate #include "tree.h"
537c478bd9Sstevel@tonic-gate #include "itree.h"
547c478bd9Sstevel@tonic-gate #include "ipath.h"
557c478bd9Sstevel@tonic-gate #include "ptree.h"
567c478bd9Sstevel@tonic-gate #include "fme.h"
577c478bd9Sstevel@tonic-gate #include "stable.h"
587c478bd9Sstevel@tonic-gate #include "eval.h"
597c478bd9Sstevel@tonic-gate #include "config.h"
607c478bd9Sstevel@tonic-gate #include "platform.h"
617c478bd9Sstevel@tonic-gate
627c478bd9Sstevel@tonic-gate extern fmd_hdl_t *Hdl; /* handle from eft.c */
637c478bd9Sstevel@tonic-gate
647c478bd9Sstevel@tonic-gate /*
65b5016cbbSstephh * Lastcfg points to the last configuration snapshot we made.
667c478bd9Sstevel@tonic-gate */
677c478bd9Sstevel@tonic-gate static struct cfgdata *Lastcfg;
68b5016cbbSstephh static fmd_hdl_t *Lasthdl;
69b5016cbbSstephh static fmd_case_t *Lastfmcase;
70b5016cbbSstephh static const char *lastcomp;
71b5016cbbSstephh static int in_getpath;
72b5016cbbSstephh extern struct lut *Usednames;
73b5016cbbSstephh int prune_raw_config = 0;
747c478bd9Sstevel@tonic-gate
75b5016cbbSstephh static topo_hdl_t *Eft_topo_hdl;
767c478bd9Sstevel@tonic-gate
777c478bd9Sstevel@tonic-gate void *
topo_use_alloc(size_t bytes)787c478bd9Sstevel@tonic-gate topo_use_alloc(size_t bytes)
797c478bd9Sstevel@tonic-gate {
807c478bd9Sstevel@tonic-gate void *p = alloc_malloc(bytes, NULL, 0);
817c478bd9Sstevel@tonic-gate
827c478bd9Sstevel@tonic-gate bzero(p, bytes);
837c478bd9Sstevel@tonic-gate return (p);
847c478bd9Sstevel@tonic-gate }
857c478bd9Sstevel@tonic-gate
867c478bd9Sstevel@tonic-gate void
topo_use_free(void * p)877c478bd9Sstevel@tonic-gate topo_use_free(void *p)
887c478bd9Sstevel@tonic-gate {
897c478bd9Sstevel@tonic-gate alloc_free(p, NULL, 0);
907c478bd9Sstevel@tonic-gate }
917c478bd9Sstevel@tonic-gate
927c478bd9Sstevel@tonic-gate /*ARGSUSED*/
937c478bd9Sstevel@tonic-gate static void *
alloc_nv_alloc(nv_alloc_t * nva,size_t size)947c478bd9Sstevel@tonic-gate alloc_nv_alloc(nv_alloc_t *nva, size_t size)
957c478bd9Sstevel@tonic-gate {
967c478bd9Sstevel@tonic-gate return (alloc_malloc(size, NULL, 0));
977c478bd9Sstevel@tonic-gate }
987c478bd9Sstevel@tonic-gate
997c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1007c478bd9Sstevel@tonic-gate static void
alloc_nv_free(nv_alloc_t * nva,void * p,size_t sz)1017c478bd9Sstevel@tonic-gate alloc_nv_free(nv_alloc_t *nva, void *p, size_t sz)
1027c478bd9Sstevel@tonic-gate {
1037c478bd9Sstevel@tonic-gate alloc_free(p, NULL, 0);
1047c478bd9Sstevel@tonic-gate }
1057c478bd9Sstevel@tonic-gate
1067c478bd9Sstevel@tonic-gate const nv_alloc_ops_t Eft_nv_alloc_ops = {
1077c478bd9Sstevel@tonic-gate NULL, /* nv_ao_init() */
1087c478bd9Sstevel@tonic-gate NULL, /* nv_ao_fini() */
1097c478bd9Sstevel@tonic-gate alloc_nv_alloc, /* nv_ao_alloc() */
1107c478bd9Sstevel@tonic-gate alloc_nv_free, /* nv_ao_free() */
1117c478bd9Sstevel@tonic-gate NULL /* nv_ao_reset() */
1127c478bd9Sstevel@tonic-gate };
1137c478bd9Sstevel@tonic-gate
1147c478bd9Sstevel@tonic-gate nv_alloc_t Eft_nv_hdl;
1157c478bd9Sstevel@tonic-gate
1167c478bd9Sstevel@tonic-gate static char *Root;
1177c478bd9Sstevel@tonic-gate static char *Mach;
1187c478bd9Sstevel@tonic-gate static char *Plat;
1197aec1d6eScindi static char tmpbuf[MAXPATHLEN];
1207aec1d6eScindi static char numbuf[MAXPATHLEN];
1217c478bd9Sstevel@tonic-gate
1227c478bd9Sstevel@tonic-gate /*
1237c478bd9Sstevel@tonic-gate * platform_globals -- set global variables based on sysinfo() calls
1247c478bd9Sstevel@tonic-gate */
1257c478bd9Sstevel@tonic-gate static void
platform_globals()1267c478bd9Sstevel@tonic-gate platform_globals()
1277c478bd9Sstevel@tonic-gate {
1287c478bd9Sstevel@tonic-gate Root = fmd_prop_get_string(Hdl, "fmd.rootdir");
1297c478bd9Sstevel@tonic-gate Mach = fmd_prop_get_string(Hdl, "fmd.machine");
1307c478bd9Sstevel@tonic-gate Plat = fmd_prop_get_string(Hdl, "fmd.platform");
1317c478bd9Sstevel@tonic-gate }
1327c478bd9Sstevel@tonic-gate
1337c478bd9Sstevel@tonic-gate static void
platform_free_globals()1347c478bd9Sstevel@tonic-gate platform_free_globals()
1357c478bd9Sstevel@tonic-gate {
1367c478bd9Sstevel@tonic-gate fmd_prop_free_string(Hdl, Root);
1377c478bd9Sstevel@tonic-gate fmd_prop_free_string(Hdl, Mach);
1387c478bd9Sstevel@tonic-gate fmd_prop_free_string(Hdl, Plat);
1397c478bd9Sstevel@tonic-gate }
1407c478bd9Sstevel@tonic-gate
1417c478bd9Sstevel@tonic-gate /*
1427c478bd9Sstevel@tonic-gate * platform_init -- perform any platform-specific initialization
1437c478bd9Sstevel@tonic-gate */
1447c478bd9Sstevel@tonic-gate void
platform_init(void)1457c478bd9Sstevel@tonic-gate platform_init(void)
1467c478bd9Sstevel@tonic-gate {
1477c478bd9Sstevel@tonic-gate (void) nv_alloc_init(&Eft_nv_hdl, &Eft_nv_alloc_ops);
14824db4641Seschrock Eft_topo_hdl = fmd_hdl_topo_hold(Hdl, TOPO_VERSION);
1497c478bd9Sstevel@tonic-gate platform_globals();
1507aec1d6eScindi
1517aec1d6eScindi out(O_ALTFP, "platform_init() sucessful");
1527c478bd9Sstevel@tonic-gate }
1537c478bd9Sstevel@tonic-gate
1547c478bd9Sstevel@tonic-gate void
platform_fini(void)1557c478bd9Sstevel@tonic-gate platform_fini(void)
1567c478bd9Sstevel@tonic-gate {
1577c478bd9Sstevel@tonic-gate if (Lastcfg != NULL) {
1587c478bd9Sstevel@tonic-gate config_free(Lastcfg);
1597c478bd9Sstevel@tonic-gate Lastcfg = NULL;
1607c478bd9Sstevel@tonic-gate }
16124db4641Seschrock fmd_hdl_topo_rele(Hdl, Eft_topo_hdl);
1627c478bd9Sstevel@tonic-gate platform_free_globals();
1637c478bd9Sstevel@tonic-gate (void) nv_alloc_fini(&Eft_nv_hdl);
1647aec1d6eScindi
1657aec1d6eScindi out(O_ALTFP, "platform_fini() sucessful");
1667c478bd9Sstevel@tonic-gate }
1677c478bd9Sstevel@tonic-gate
1687c478bd9Sstevel@tonic-gate /*
1697c478bd9Sstevel@tonic-gate * hc_fmri_nodeize -- convert hc-scheme FMRI to eft compatible format
1707c478bd9Sstevel@tonic-gate *
1717c478bd9Sstevel@tonic-gate * this is an internal platform.c helper routine
1727c478bd9Sstevel@tonic-gate */
1737c478bd9Sstevel@tonic-gate static struct node *
hc_fmri_nodeize(nvlist_t * hcfmri)1747c478bd9Sstevel@tonic-gate hc_fmri_nodeize(nvlist_t *hcfmri)
1757c478bd9Sstevel@tonic-gate {
1767c478bd9Sstevel@tonic-gate struct node *pathtree = NULL;
1777c478bd9Sstevel@tonic-gate struct node *tmpn;
1787c478bd9Sstevel@tonic-gate nvlist_t **hc_prs;
1797c478bd9Sstevel@tonic-gate uint_t hc_nprs;
1807c478bd9Sstevel@tonic-gate const char *sname;
1817c478bd9Sstevel@tonic-gate char *ename;
1827c478bd9Sstevel@tonic-gate char *eid;
1837c478bd9Sstevel@tonic-gate int e, r;
1847c478bd9Sstevel@tonic-gate
1857c478bd9Sstevel@tonic-gate /*
1867c478bd9Sstevel@tonic-gate * What to do with/about hc-root? Would we have any clue what
1877c478bd9Sstevel@tonic-gate * to do with it if it weren't /? For now, we don't bother
1887c478bd9Sstevel@tonic-gate * even looking it up.
1897c478bd9Sstevel@tonic-gate */
1907c478bd9Sstevel@tonic-gate
1917c478bd9Sstevel@tonic-gate /*
1927c478bd9Sstevel@tonic-gate * Get the hc-list of elements in the FMRI
1937c478bd9Sstevel@tonic-gate */
1947c478bd9Sstevel@tonic-gate if (nvlist_lookup_nvlist_array(hcfmri, FM_FMRI_HC_LIST,
1957c478bd9Sstevel@tonic-gate &hc_prs, &hc_nprs) != 0) {
1967c478bd9Sstevel@tonic-gate out(O_ALTFP, "XFILE: hc FMRI missing %s", FM_FMRI_HC_LIST);
1977c478bd9Sstevel@tonic-gate return (NULL);
1987c478bd9Sstevel@tonic-gate }
1997c478bd9Sstevel@tonic-gate
2007c478bd9Sstevel@tonic-gate for (e = 0; e < hc_nprs; e++) {
2017c478bd9Sstevel@tonic-gate ename = NULL;
2027c478bd9Sstevel@tonic-gate eid = NULL;
2037c478bd9Sstevel@tonic-gate r = nvlist_lookup_string(hc_prs[e], FM_FMRI_HC_NAME, &ename);
2047c478bd9Sstevel@tonic-gate r |= nvlist_lookup_string(hc_prs[e], FM_FMRI_HC_ID, &eid);
2057c478bd9Sstevel@tonic-gate if (r != 0) {
2067c478bd9Sstevel@tonic-gate /* probably should bail */
2077c478bd9Sstevel@tonic-gate continue;
2087c478bd9Sstevel@tonic-gate }
2097c478bd9Sstevel@tonic-gate sname = stable(ename);
2107c478bd9Sstevel@tonic-gate tmpn = tree_name_iterator(
21124db4641Seschrock tree_name(sname, IT_VERTICAL, NULL, 0),
21224db4641Seschrock tree_num(eid, NULL, 0));
2137c478bd9Sstevel@tonic-gate
2147c478bd9Sstevel@tonic-gate if (pathtree == NULL)
2157c478bd9Sstevel@tonic-gate pathtree = tmpn;
2167c478bd9Sstevel@tonic-gate else
2177c478bd9Sstevel@tonic-gate (void) tree_name_append(pathtree, tmpn);
2187c478bd9Sstevel@tonic-gate }
2197c478bd9Sstevel@tonic-gate
2207c478bd9Sstevel@tonic-gate return (pathtree);
2217c478bd9Sstevel@tonic-gate }
2227c478bd9Sstevel@tonic-gate
2237c478bd9Sstevel@tonic-gate /*
2247c478bd9Sstevel@tonic-gate * platform_getpath -- extract eft-compatible path from ereport
2257c478bd9Sstevel@tonic-gate */
2267c478bd9Sstevel@tonic-gate struct node *
platform_getpath(nvlist_t * nvl)2277c478bd9Sstevel@tonic-gate platform_getpath(nvlist_t *nvl)
2287c478bd9Sstevel@tonic-gate {
229602ca9eaScth struct node *ret;
23044ed9dbbSStephen Hanson nvlist_t *dfmri, *real_fmri, *resource;
231602ca9eaScth char *scheme;
232602ca9eaScth char *path;
233602ca9eaScth char *devid;
23444ed9dbbSStephen Hanson char *tp;
235602ca9eaScth uint32_t cpuid;
23644ed9dbbSStephen Hanson int err;
23744ed9dbbSStephen Hanson enum {DT_HC, DT_DEVID, DT_TP, DT_DEV, DT_CPU, DT_UNKNOWN} type =
23844ed9dbbSStephen Hanson DT_UNKNOWN;
239602ca9eaScth
240602ca9eaScth /* Find the detector */
2417c478bd9Sstevel@tonic-gate if (nvlist_lookup_nvlist(nvl, FM_EREPORT_DETECTOR, &dfmri) != 0) {
2427c478bd9Sstevel@tonic-gate out(O_ALTFP, "XFILE: ereport has no detector FMRI");
2437c478bd9Sstevel@tonic-gate return (NULL);
2447c478bd9Sstevel@tonic-gate }
2457c478bd9Sstevel@tonic-gate
246602ca9eaScth /* get the scheme from the detector */
2477c478bd9Sstevel@tonic-gate if (nvlist_lookup_string(dfmri, FM_FMRI_SCHEME, &scheme) != 0) {
2487c478bd9Sstevel@tonic-gate out(O_ALTFP, "XFILE: detector FMRI missing scheme");
2497c478bd9Sstevel@tonic-gate return (NULL);
2507c478bd9Sstevel@tonic-gate }
2517c478bd9Sstevel@tonic-gate
252602ca9eaScth /* based on scheme, determine type */
253602ca9eaScth if (strcmp(scheme, FM_FMRI_SCHEME_HC) == 0) {
254602ca9eaScth /* already in hc scheme */
25544ed9dbbSStephen Hanson type = DT_HC;
256602ca9eaScth } else if (strcmp(scheme, FM_FMRI_SCHEME_DEV) == 0) {
25744ed9dbbSStephen Hanson /*
25844ed9dbbSStephen Hanson * devid takes precedence over tp which takes precedence over
25944ed9dbbSStephen Hanson * path
26044ed9dbbSStephen Hanson */
261602ca9eaScth if (nvlist_lookup_string(dfmri,
262602ca9eaScth FM_FMRI_DEV_ID, &devid) == 0)
263602ca9eaScth type = DT_DEVID;
264392e836bSGavin Maltby else if (nvlist_lookup_string(dfmri,
26544ed9dbbSStephen Hanson TOPO_STORAGE_TARGET_PORT_L0ID, &tp) == 0)
26644ed9dbbSStephen Hanson type = DT_TP;
267602ca9eaScth else if (nvlist_lookup_string(dfmri,
268602ca9eaScth FM_FMRI_DEV_PATH, &path) == 0)
269602ca9eaScth type = DT_DEV;
270602ca9eaScth else {
271602ca9eaScth out(O_ALTFP, "XFILE: detector FMRI missing %s or %s",
272602ca9eaScth FM_FMRI_DEV_ID, FM_FMRI_DEV_PATH);
2737c478bd9Sstevel@tonic-gate return (NULL);
2747c478bd9Sstevel@tonic-gate }
275c7d6cfd6SStephen Hanson } else if (strcmp(scheme, FM_FMRI_SCHEME_CPU) == 0) {
276602ca9eaScth if (nvlist_lookup_uint32(dfmri, FM_FMRI_CPU_ID, &cpuid) == 0)
277602ca9eaScth type = DT_CPU;
278602ca9eaScth else {
2797c478bd9Sstevel@tonic-gate out(O_ALTFP, "XFILE: detector FMRI missing %s",
2807c478bd9Sstevel@tonic-gate FM_FMRI_CPU_ID);
2817c478bd9Sstevel@tonic-gate return (NULL);
2827c478bd9Sstevel@tonic-gate }
283602ca9eaScth } else {
284602ca9eaScth out(O_ALTFP, "XFILE: detector FMRI not recognized "
285602ca9eaScth "(scheme is %s, expect %s or %s or %s)",
286602ca9eaScth scheme, FM_FMRI_SCHEME_HC, FM_FMRI_SCHEME_DEV,
287602ca9eaScth FM_FMRI_SCHEME_CPU);
288602ca9eaScth return (NULL);
289602ca9eaScth }
2907c478bd9Sstevel@tonic-gate
291602ca9eaScth out(O_ALTFP|O_VERB, "Received ereport in scheme %s", scheme);
2927c478bd9Sstevel@tonic-gate
293602ca9eaScth /* take a config snapshot */
294602ca9eaScth lut_free(Usednames, NULL, NULL);
295602ca9eaScth Usednames = NULL;
296602ca9eaScth in_getpath = 1;
297602ca9eaScth if (config_snapshot() == NULL) {
29844ed9dbbSStephen Hanson if (type == DT_HC) {
29944ed9dbbSStephen Hanson /*
30044ed9dbbSStephen Hanson * If hc-scheme use the fmri that was passed in.
30144ed9dbbSStephen Hanson */
30244ed9dbbSStephen Hanson in_getpath = 0;
30344ed9dbbSStephen Hanson return (hc_fmri_nodeize(dfmri));
30444ed9dbbSStephen Hanson }
305602ca9eaScth out(O_ALTFP, "XFILE: cannot snapshot configuration");
306b5016cbbSstephh in_getpath = 0;
307602ca9eaScth return (NULL);
308602ca9eaScth }
309602ca9eaScth
31044ed9dbbSStephen Hanson /*
31144ed9dbbSStephen Hanson * For hc scheme, if we can find the resource from the tolopogy, use
31244ed9dbbSStephen Hanson * that - otherwise use the fmri that was passed in. For other schemes
31344ed9dbbSStephen Hanson * look up the path, cpuid, tp or devid in the topology.
31444ed9dbbSStephen Hanson */
315602ca9eaScth switch (type) {
31644ed9dbbSStephen Hanson case DT_HC:
31744ed9dbbSStephen Hanson if (topo_fmri_getprop(Eft_topo_hdl, dfmri, TOPO_PGROUP_PROTOCOL,
318015ed3f8SRobert Johnston TOPO_PROP_RESOURCE, NULL, &resource, &err) == -1) {
31944ed9dbbSStephen Hanson ret = hc_fmri_nodeize(dfmri);
320015ed3f8SRobert Johnston break;
321015ed3f8SRobert Johnston } else if (nvlist_lookup_nvlist(resource,
32244ed9dbbSStephen Hanson TOPO_PROP_VAL_VAL, &real_fmri) != 0)
32344ed9dbbSStephen Hanson ret = hc_fmri_nodeize(dfmri);
32444ed9dbbSStephen Hanson else
32544ed9dbbSStephen Hanson ret = hc_fmri_nodeize(real_fmri);
326015ed3f8SRobert Johnston
327015ed3f8SRobert Johnston nvlist_free(resource);
32844ed9dbbSStephen Hanson break;
32944ed9dbbSStephen Hanson
330602ca9eaScth case DT_DEV:
331602ca9eaScth if ((ret = config_bydev_lookup(Lastcfg, path)) == NULL)
332602ca9eaScth out(O_ALTFP, "platform_getpath: no configuration node "
333602ca9eaScth "has device path matching \"%s\".", path);
334602ca9eaScth
335602ca9eaScth break;
336602ca9eaScth
33744ed9dbbSStephen Hanson case DT_TP:
33844ed9dbbSStephen Hanson if ((ret = config_bytp_lookup(Lastcfg, tp)) == NULL)
33944ed9dbbSStephen Hanson out(O_ALTFP, "platform_getpath: no configuration node "
34044ed9dbbSStephen Hanson "has tp matching \"%s\".", tp);
34144ed9dbbSStephen Hanson break;
34244ed9dbbSStephen Hanson
343602ca9eaScth case DT_DEVID:
344602ca9eaScth if ((ret = config_bydevid_lookup(Lastcfg, devid)) == NULL)
345602ca9eaScth out(O_ALTFP, "platform_getpath: no configuration node "
346602ca9eaScth "has devid matching \"%s\".", devid);
347602ca9eaScth break;
348602ca9eaScth
349602ca9eaScth case DT_CPU:
350602ca9eaScth if ((ret = config_bycpuid_lookup(Lastcfg, cpuid)) == NULL)
351602ca9eaScth out(O_ALTFP, "platform_getpath: no configuration node "
352602ca9eaScth "has cpu-id matching %u.", cpuid);
353602ca9eaScth break;
3547c478bd9Sstevel@tonic-gate }
3557c478bd9Sstevel@tonic-gate
356602ca9eaScth /* free the snapshot */
357602ca9eaScth structconfig_free(Lastcfg->cooked);
358602ca9eaScth config_free(Lastcfg);
359602ca9eaScth in_getpath = 0;
360602ca9eaScth return (ret);
3617c478bd9Sstevel@tonic-gate }
3627c478bd9Sstevel@tonic-gate
3637c478bd9Sstevel@tonic-gate /* Allocate space for raw config strings in chunks of this size */
3647c478bd9Sstevel@tonic-gate #define STRSBUFLEN 512
3657c478bd9Sstevel@tonic-gate
3667c478bd9Sstevel@tonic-gate /*
3677c478bd9Sstevel@tonic-gate * cfgadjust -- Make sure the amount we want to add to the raw config string
3687c478bd9Sstevel@tonic-gate * buffer will fit, and if not, increase the size of the buffer.
3697c478bd9Sstevel@tonic-gate */
3707c478bd9Sstevel@tonic-gate static void
cfgadjust(struct cfgdata * rawdata,int addlen)3717c478bd9Sstevel@tonic-gate cfgadjust(struct cfgdata *rawdata, int addlen)
3727c478bd9Sstevel@tonic-gate {
3737c478bd9Sstevel@tonic-gate int curnext, newlen;
3747c478bd9Sstevel@tonic-gate
3757c478bd9Sstevel@tonic-gate if (rawdata->nextfree + addlen >= rawdata->end) {
3767c478bd9Sstevel@tonic-gate newlen = (((rawdata->nextfree - rawdata->begin + 1 + addlen)
3777c478bd9Sstevel@tonic-gate / STRSBUFLEN) + 1) * STRSBUFLEN;
3787c478bd9Sstevel@tonic-gate curnext = rawdata->nextfree - rawdata->begin;
3797c478bd9Sstevel@tonic-gate rawdata->begin = REALLOC(rawdata->begin, newlen);
3807c478bd9Sstevel@tonic-gate rawdata->nextfree = rawdata->begin + curnext;
3817c478bd9Sstevel@tonic-gate rawdata->end = rawdata->begin + newlen;
3827c478bd9Sstevel@tonic-gate }
3837c478bd9Sstevel@tonic-gate }
3847c478bd9Sstevel@tonic-gate
3857aec1d6eScindi static char *
hc_path(tnode_t * node)3867aec1d6eScindi hc_path(tnode_t *node)
3877aec1d6eScindi {
3887aec1d6eScindi int i, err;
3897aec1d6eScindi char *name, *instance, *estr;
3907aec1d6eScindi nvlist_t *fmri, **hcl;
3917aec1d6eScindi ulong_t ul;
3927aec1d6eScindi uint_t nhc;
3937aec1d6eScindi
3947aec1d6eScindi if (topo_prop_get_fmri(node, TOPO_PGROUP_PROTOCOL, TOPO_PROP_RESOURCE,
3957aec1d6eScindi &fmri, &err) < 0)
3967aec1d6eScindi return (NULL);
3977aec1d6eScindi
3987aec1d6eScindi if (nvlist_lookup_nvlist_array(fmri, FM_FMRI_HC_LIST, &hcl, &nhc)
3997aec1d6eScindi != 0) {
4007aec1d6eScindi nvlist_free(fmri);
4017aec1d6eScindi return (NULL);
4027aec1d6eScindi }
4037aec1d6eScindi
4047aec1d6eScindi tmpbuf[0] = '\0';
4057aec1d6eScindi for (i = 0; i < nhc; ++i) {
4067aec1d6eScindi err = nvlist_lookup_string(hcl[i], FM_FMRI_HC_NAME, &name);
4077aec1d6eScindi err |= nvlist_lookup_string(hcl[i], FM_FMRI_HC_ID, &instance);
4087aec1d6eScindi if (err) {
4097aec1d6eScindi nvlist_free(fmri);
4107aec1d6eScindi return (NULL);
4117aec1d6eScindi }
4127aec1d6eScindi
4137aec1d6eScindi ul = strtoul(instance, &estr, 10);
4147aec1d6eScindi /* conversion to number failed? */
4157aec1d6eScindi if (estr == instance) {
4167aec1d6eScindi nvlist_free(fmri);
4177aec1d6eScindi return (NULL);
4187aec1d6eScindi }
4197aec1d6eScindi
4207aec1d6eScindi (void) strlcat(tmpbuf, "/", MAXPATHLEN);
4217aec1d6eScindi (void) strlcat(tmpbuf, name, MAXPATHLEN);
422837416c3Scy (void) snprintf(numbuf, MAXPATHLEN, "%lu", ul);
4237aec1d6eScindi (void) strlcat(tmpbuf, numbuf, MAXPATHLEN);
424b5016cbbSstephh lastcomp = stable(name);
4257aec1d6eScindi }
4267aec1d6eScindi
4277aec1d6eScindi nvlist_free(fmri);
4287aec1d6eScindi
4297aec1d6eScindi return (tmpbuf);
4307aec1d6eScindi }
4317aec1d6eScindi
4327aec1d6eScindi static void
add_prop_val(topo_hdl_t * thp,struct cfgdata * rawdata,char * propn,nvpair_t * pv_nvp)4337aec1d6eScindi add_prop_val(topo_hdl_t *thp, struct cfgdata *rawdata, char *propn,
4347aec1d6eScindi nvpair_t *pv_nvp)
4357aec1d6eScindi {
4367aec1d6eScindi int addlen, err;
4377aec1d6eScindi char *propv, *fmristr = NULL;
4387aec1d6eScindi nvlist_t *fmri;
439b5016cbbSstephh uint32_t ui32;
440b5016cbbSstephh int64_t i64;
441b5016cbbSstephh int32_t i32;
442b5016cbbSstephh boolean_t bool;
4438a40a695Sgavinm uint64_t ui64;
4448a40a695Sgavinm char buf[32]; /* big enough for any 64-bit int */
44544ed9dbbSStephen Hanson uint_t nelem;
44644ed9dbbSStephen Hanson int i, j, sz;
44744ed9dbbSStephen Hanson char **propvv;
4487aec1d6eScindi
4490eb822a1Scindi /*
4500eb822a1Scindi * malformed prop nvpair
4510eb822a1Scindi */
4520eb822a1Scindi if (propn == NULL)
4530eb822a1Scindi return;
4540eb822a1Scindi
4558a40a695Sgavinm switch (nvpair_type(pv_nvp)) {
45644ed9dbbSStephen Hanson case DATA_TYPE_STRING_ARRAY:
45744ed9dbbSStephen Hanson /*
45844ed9dbbSStephen Hanson * Convert string array into single space-separated string
45944ed9dbbSStephen Hanson */
46044ed9dbbSStephen Hanson (void) nvpair_value_string_array(pv_nvp, &propvv, &nelem);
46144ed9dbbSStephen Hanson for (sz = 0, i = 0; i < nelem; i++)
46244ed9dbbSStephen Hanson sz += strlen(propvv[i]) + 1;
46344ed9dbbSStephen Hanson propv = MALLOC(sz);
46444ed9dbbSStephen Hanson for (j = 0, i = 0; i < nelem; j++, i++) {
46544ed9dbbSStephen Hanson (void) strcpy(&propv[j], propvv[i]);
46644ed9dbbSStephen Hanson j += strlen(propvv[i]);
46744ed9dbbSStephen Hanson if (i < nelem - 1)
46844ed9dbbSStephen Hanson propv[j] = ' ';
46944ed9dbbSStephen Hanson }
47044ed9dbbSStephen Hanson break;
47144ed9dbbSStephen Hanson
4728a40a695Sgavinm case DATA_TYPE_STRING:
4738a40a695Sgavinm (void) nvpair_value_string(pv_nvp, &propv);
4748a40a695Sgavinm break;
4758a40a695Sgavinm
4768a40a695Sgavinm case DATA_TYPE_NVLIST:
4778a40a695Sgavinm /*
4788a40a695Sgavinm * At least try to collect the protocol
4798a40a695Sgavinm * properties
4808a40a695Sgavinm */
4817aec1d6eScindi (void) nvpair_value_nvlist(pv_nvp, &fmri);
4827aec1d6eScindi if (topo_fmri_nvl2str(thp, fmri, &fmristr, &err) < 0) {
4837aec1d6eScindi out(O_ALTFP, "cfgcollect: failed to convert fmri to "
4847aec1d6eScindi "string");
4857aec1d6eScindi return;
4867aec1d6eScindi } else {
4877aec1d6eScindi propv = fmristr;
4887aec1d6eScindi }
4898a40a695Sgavinm break;
4907aec1d6eScindi
4918a40a695Sgavinm case DATA_TYPE_UINT64:
4928a40a695Sgavinm /*
4938a40a695Sgavinm * Convert uint64 to hex strings
4948a40a695Sgavinm */
4958a40a695Sgavinm (void) nvpair_value_uint64(pv_nvp, &ui64);
4968a40a695Sgavinm (void) snprintf(buf, sizeof (buf), "0x%llx", ui64);
4978a40a695Sgavinm propv = buf;
4988a40a695Sgavinm break;
4998a40a695Sgavinm
500b5016cbbSstephh case DATA_TYPE_BOOLEAN_VALUE:
501b5016cbbSstephh /*
502b5016cbbSstephh * Convert boolean_t to hex strings
503b5016cbbSstephh */
504b5016cbbSstephh (void) nvpair_value_boolean_value(pv_nvp, &bool);
505b5016cbbSstephh (void) snprintf(buf, sizeof (buf), "0x%llx", (uint64_t)bool);
506b5016cbbSstephh propv = buf;
507b5016cbbSstephh break;
508b5016cbbSstephh
509b5016cbbSstephh case DATA_TYPE_INT32:
510b5016cbbSstephh /*
511b5016cbbSstephh * Convert int32 to hex strings
512b5016cbbSstephh */
513b5016cbbSstephh (void) nvpair_value_int32(pv_nvp, &i32);
514b5016cbbSstephh (void) snprintf(buf, sizeof (buf), "0x%llx",
515b5016cbbSstephh (uint64_t)(int64_t)i32);
516b5016cbbSstephh propv = buf;
517b5016cbbSstephh break;
518b5016cbbSstephh
519b5016cbbSstephh case DATA_TYPE_INT64:
520b5016cbbSstephh /*
521b5016cbbSstephh * Convert int64 to hex strings
522b5016cbbSstephh */
523b5016cbbSstephh (void) nvpair_value_int64(pv_nvp, &i64);
524b5016cbbSstephh (void) snprintf(buf, sizeof (buf), "0x%llx", (uint64_t)i64);
525b5016cbbSstephh propv = buf;
526b5016cbbSstephh break;
527b5016cbbSstephh
528b5016cbbSstephh case DATA_TYPE_UINT32:
529b5016cbbSstephh /*
530b5016cbbSstephh * Convert uint32 to hex strings
531b5016cbbSstephh */
532b5016cbbSstephh (void) nvpair_value_uint32(pv_nvp, &ui32);
533b5016cbbSstephh (void) snprintf(buf, sizeof (buf), "0x%llx", (uint64_t)ui32);
534b5016cbbSstephh propv = buf;
535b5016cbbSstephh break;
536b5016cbbSstephh
5378a40a695Sgavinm default:
5380eb822a1Scindi out(O_ALTFP, "cfgcollect: failed to get property value for "
5390eb822a1Scindi "%s", propn);
5407aec1d6eScindi return;
5417aec1d6eScindi }
5427aec1d6eScindi
5437aec1d6eScindi /* = & NULL */
5447aec1d6eScindi addlen = strlen(propn) + strlen(propv) + 2;
5457aec1d6eScindi cfgadjust(rawdata, addlen);
5467aec1d6eScindi (void) snprintf(rawdata->nextfree,
5477aec1d6eScindi rawdata->end - rawdata->nextfree, "%s=%s",
5487aec1d6eScindi propn, propv);
5490eb822a1Scindi if (strcmp(propn, TOPO_PROP_RESOURCE) == 0)
550b5016cbbSstephh out(O_ALTFP|O_VERB3, "cfgcollect: %s", propv);
5510eb822a1Scindi
55244ed9dbbSStephen Hanson if (nvpair_type(pv_nvp) == DATA_TYPE_STRING_ARRAY)
55344ed9dbbSStephen Hanson FREE(propv);
55444ed9dbbSStephen Hanson
5557aec1d6eScindi rawdata->nextfree += addlen;
5567aec1d6eScindi
5577aec1d6eScindi if (fmristr != NULL)
5587aec1d6eScindi topo_hdl_strfree(thp, fmristr);
5597aec1d6eScindi }
5607aec1d6eScindi
5617c478bd9Sstevel@tonic-gate /*
5627c478bd9Sstevel@tonic-gate * cfgcollect -- Assemble raw configuration data in string form suitable
5637c478bd9Sstevel@tonic-gate * for checkpointing.
5647c478bd9Sstevel@tonic-gate */
5657aec1d6eScindi static int
cfgcollect(topo_hdl_t * thp,tnode_t * node,void * arg)5667aec1d6eScindi cfgcollect(topo_hdl_t *thp, tnode_t *node, void *arg)
5677c478bd9Sstevel@tonic-gate {
5687c478bd9Sstevel@tonic-gate struct cfgdata *rawdata = (struct cfgdata *)arg;
5690eb822a1Scindi int err, addlen;
5707aec1d6eScindi char *propn, *path = NULL;
5717aec1d6eScindi nvlist_t *p_nv, *pg_nv, *pv_nv;
5727aec1d6eScindi nvpair_t *nvp, *pg_nvp, *pv_nvp;
5737aec1d6eScindi
574c7d6cfd6SStephen Hanson if (topo_node_flags(node) == TOPO_NODE_FACILITY)
575c7d6cfd6SStephen Hanson return (TOPO_WALK_NEXT);
576c7d6cfd6SStephen Hanson
5777aec1d6eScindi path = hc_path(node);
5787aec1d6eScindi if (path == NULL)
5797aec1d6eScindi return (TOPO_WALK_ERR);
5807c478bd9Sstevel@tonic-gate
5817c478bd9Sstevel@tonic-gate addlen = strlen(path) + 1;
5827c478bd9Sstevel@tonic-gate
5837c478bd9Sstevel@tonic-gate cfgadjust(rawdata, addlen);
5847c478bd9Sstevel@tonic-gate (void) strcpy(rawdata->nextfree, path);
5857c478bd9Sstevel@tonic-gate rawdata->nextfree += addlen;
5867c478bd9Sstevel@tonic-gate
587b5016cbbSstephh /*
588b5016cbbSstephh * If the prune_raw_config flag is set then we will only include in the
589b5016cbbSstephh * raw config those nodes that are used by the rules remaining after
590b5016cbbSstephh * prune_propagations() has been run - ie only those that could possibly
591b5016cbbSstephh * be relevant to the incoming ereport given the current rules. This
592b5016cbbSstephh * means that any other parts of the config will not get saved to the
593b5016cbbSstephh * checkpoint file (even if they may theoretically be used if the
594b5016cbbSstephh * rules are subsequently modified).
595b5016cbbSstephh *
596b5016cbbSstephh * For now prune_raw_config is 0 for Solaris, though it is expected to
597b5016cbbSstephh * be set to 1 for fmsp.
598b5016cbbSstephh *
599b5016cbbSstephh * Note we only prune the raw config like this if we have been called
600b5016cbbSstephh * from newfme(), not if we have been called when handling dev or cpu
601b5016cbbSstephh * scheme ereports from platform_getpath(), as this is called before
602b5016cbbSstephh * prune_propagations() - again this is not an issue on fmsp as the
603b5016cbbSstephh * ereports are all in hc scheme.
604b5016cbbSstephh */
605b5016cbbSstephh if (!in_getpath && prune_raw_config &&
606b5016cbbSstephh lut_lookup(Usednames, (void *)lastcomp, NULL) == NULL)
607b5016cbbSstephh return (TOPO_WALK_NEXT);
608b5016cbbSstephh
6097aec1d6eScindi /*
6107aec1d6eScindi * Collect properties
6117aec1d6eScindi *
6127aec1d6eScindi * eversholt should support alternate property types
6137aec1d6eScindi * Better yet, topo properties could be represented as
6147aec1d6eScindi * a packed nvlist
6157aec1d6eScindi */
6160eb822a1Scindi p_nv = topo_prop_getprops(node, &err);
6177aec1d6eScindi for (nvp = nvlist_next_nvpair(p_nv, NULL); nvp != NULL;
6187aec1d6eScindi nvp = nvlist_next_nvpair(p_nv, nvp)) {
6197aec1d6eScindi if (strcmp(TOPO_PROP_GROUP, nvpair_name(nvp)) != 0 ||
6207aec1d6eScindi nvpair_type(nvp) != DATA_TYPE_NVLIST)
6217aec1d6eScindi continue;
6227aec1d6eScindi
6237aec1d6eScindi (void) nvpair_value_nvlist(nvp, &pg_nv);
6247aec1d6eScindi
6257aec1d6eScindi for (pg_nvp = nvlist_next_nvpair(pg_nv, NULL); pg_nvp != NULL;
6267aec1d6eScindi pg_nvp = nvlist_next_nvpair(pg_nv, pg_nvp)) {
6277aec1d6eScindi
6287aec1d6eScindi if (strcmp(TOPO_PROP_VAL, nvpair_name(pg_nvp)) != 0 ||
6297aec1d6eScindi nvpair_type(pg_nvp) != DATA_TYPE_NVLIST)
6307aec1d6eScindi continue;
6317aec1d6eScindi
6327aec1d6eScindi (void) nvpair_value_nvlist(pg_nvp, &pv_nv);
6337aec1d6eScindi
6340eb822a1Scindi propn = NULL;
6357aec1d6eScindi for (pv_nvp = nvlist_next_nvpair(pv_nv, NULL);
6367aec1d6eScindi pv_nvp != NULL;
6377aec1d6eScindi pv_nvp = nvlist_next_nvpair(pv_nv, pv_nvp)) {
6387aec1d6eScindi
6397aec1d6eScindi /* Get property name */
6400eb822a1Scindi if (strcmp(TOPO_PROP_VAL_NAME,
6410eb822a1Scindi nvpair_name(pv_nvp)) == 0)
6420eb822a1Scindi (void) nvpair_value_string(pv_nvp,
6430eb822a1Scindi &propn);
6447aec1d6eScindi
6457aec1d6eScindi /*
6467aec1d6eScindi * Get property value
6477aec1d6eScindi */
6480eb822a1Scindi if (strcmp(TOPO_PROP_VAL_VAL,
6490eb822a1Scindi nvpair_name(pv_nvp)) == 0)
6500eb822a1Scindi add_prop_val(thp, rawdata, propn,
6510eb822a1Scindi pv_nvp);
6527aec1d6eScindi }
6537aec1d6eScindi
6547aec1d6eScindi }
6557c478bd9Sstevel@tonic-gate }
6567aec1d6eScindi
6577aec1d6eScindi nvlist_free(p_nv);
6587aec1d6eScindi
6597aec1d6eScindi return (TOPO_WALK_NEXT);
6607c478bd9Sstevel@tonic-gate }
6617c478bd9Sstevel@tonic-gate
662b5016cbbSstephh void
platform_restore_config(fmd_hdl_t * hdl,fmd_case_t * fmcase)663b5016cbbSstephh platform_restore_config(fmd_hdl_t *hdl, fmd_case_t *fmcase)
664b5016cbbSstephh {
665b5016cbbSstephh if (hdl == Lasthdl && fmcase == Lastfmcase) {
666b5016cbbSstephh size_t cfglen;
667b5016cbbSstephh
668b5016cbbSstephh fmd_buf_read(Lasthdl, Lastfmcase, WOBUF_CFGLEN, (void *)&cfglen,
669b5016cbbSstephh sizeof (size_t));
670b5016cbbSstephh Lastcfg->begin = MALLOC(cfglen);
671b5016cbbSstephh Lastcfg->end = Lastcfg->nextfree = Lastcfg->begin + cfglen;
672b5016cbbSstephh fmd_buf_read(Lasthdl, Lastfmcase, WOBUF_CFG, Lastcfg->begin,
673b5016cbbSstephh cfglen);
674b5016cbbSstephh Lasthdl = NULL;
675b5016cbbSstephh Lastfmcase = NULL;
676b5016cbbSstephh }
677b5016cbbSstephh }
678b5016cbbSstephh
679b5016cbbSstephh void
platform_save_config(fmd_hdl_t * hdl,fmd_case_t * fmcase)680b5016cbbSstephh platform_save_config(fmd_hdl_t *hdl, fmd_case_t *fmcase)
681b5016cbbSstephh {
682b5016cbbSstephh size_t cfglen;
683b5016cbbSstephh
684b5016cbbSstephh /*
685b5016cbbSstephh * Put the raw config into an fmd_buf. Then we can free it to
686b5016cbbSstephh * save space.
687b5016cbbSstephh */
688b5016cbbSstephh Lastfmcase = fmcase;
689b5016cbbSstephh Lasthdl = hdl;
690b5016cbbSstephh cfglen = Lastcfg->nextfree - Lastcfg->begin;
691b5016cbbSstephh fmd_buf_create(hdl, fmcase, WOBUF_CFGLEN, sizeof (cfglen));
692b5016cbbSstephh fmd_buf_write(hdl, fmcase, WOBUF_CFGLEN, (void *)&cfglen,
693b5016cbbSstephh sizeof (cfglen));
694b5016cbbSstephh if (cfglen != 0) {
695b5016cbbSstephh fmd_buf_create(hdl, fmcase, WOBUF_CFG, cfglen);
696b5016cbbSstephh fmd_buf_write(hdl, fmcase, WOBUF_CFG, Lastcfg->begin, cfglen);
697b5016cbbSstephh }
698b5016cbbSstephh FREE(Lastcfg->begin);
699b5016cbbSstephh Lastcfg->begin = NULL;
700b5016cbbSstephh Lastcfg->end = NULL;
701b5016cbbSstephh Lastcfg->nextfree = NULL;
702b5016cbbSstephh }
703b5016cbbSstephh
7047c478bd9Sstevel@tonic-gate /*
7057c478bd9Sstevel@tonic-gate * platform_config_snapshot -- gather a snapshot of the current configuration
7067c478bd9Sstevel@tonic-gate */
7077c478bd9Sstevel@tonic-gate struct cfgdata *
platform_config_snapshot(void)7087c478bd9Sstevel@tonic-gate platform_config_snapshot(void)
7097c478bd9Sstevel@tonic-gate {
7107aec1d6eScindi int err;
7117aec1d6eScindi topo_walk_t *twp;
7120eb822a1Scindi static uint64_t lastgen;
7130eb822a1Scindi uint64_t curgen;
7147c478bd9Sstevel@tonic-gate
7157c478bd9Sstevel@tonic-gate /*
7167c478bd9Sstevel@tonic-gate * If the DR generation number has changed,
7177c478bd9Sstevel@tonic-gate * we need to grab a new snapshot, otherwise we
7187c478bd9Sstevel@tonic-gate * can simply point them at the last config.
7197c478bd9Sstevel@tonic-gate */
720b5016cbbSstephh if (prune_raw_config == 0 && (curgen = fmd_fmri_get_drgen()) <=
721b5016cbbSstephh lastgen && Lastcfg != NULL) {
722b5016cbbSstephh Lastcfg->raw_refcnt++;
723b5016cbbSstephh /*
724b5016cbbSstephh * if config has been backed away to an fmd_buf, restore it
725b5016cbbSstephh */
726b5016cbbSstephh if (Lastcfg->begin == NULL)
727b5016cbbSstephh platform_restore_config(Lasthdl, Lastfmcase);
7280eb822a1Scindi return (Lastcfg);
7290eb822a1Scindi }
7307c478bd9Sstevel@tonic-gate
7310eb822a1Scindi lastgen = curgen;
7327c478bd9Sstevel@tonic-gate /* we're getting a new config, so clean up the last one */
733b5016cbbSstephh if (Lastcfg != NULL) {
73435f59e50SStephen Hanson config_free(Lastcfg);
735b5016cbbSstephh }
7367c478bd9Sstevel@tonic-gate
7377c478bd9Sstevel@tonic-gate Lastcfg = MALLOC(sizeof (struct cfgdata));
738b5016cbbSstephh Lastcfg->raw_refcnt = 2; /* caller + Lastcfg */
7397c478bd9Sstevel@tonic-gate Lastcfg->begin = Lastcfg->nextfree = Lastcfg->end = NULL;
7407c478bd9Sstevel@tonic-gate Lastcfg->cooked = NULL;
7417c478bd9Sstevel@tonic-gate Lastcfg->devcache = NULL;
742602ca9eaScth Lastcfg->devidcache = NULL;
74344ed9dbbSStephen Hanson Lastcfg->tpcache = NULL;
7447c478bd9Sstevel@tonic-gate Lastcfg->cpucache = NULL;
7457c478bd9Sstevel@tonic-gate
7460eb822a1Scindi
74724db4641Seschrock fmd_hdl_topo_rele(Hdl, Eft_topo_hdl);
74824db4641Seschrock Eft_topo_hdl = fmd_hdl_topo_hold(Hdl, TOPO_VERSION);
7497c478bd9Sstevel@tonic-gate
7507aec1d6eScindi if ((twp = topo_walk_init(Eft_topo_hdl, FM_FMRI_SCHEME_HC, cfgcollect,
7517aec1d6eScindi Lastcfg, &err)) == NULL) {
7527aec1d6eScindi out(O_DIE, "platform_config_snapshot: NULL topology tree: %s",
7537aec1d6eScindi topo_strerror(err));
7547c478bd9Sstevel@tonic-gate }
7557c478bd9Sstevel@tonic-gate
7567aec1d6eScindi if (topo_walk_step(twp, TOPO_WALK_CHILD) == TOPO_WALK_ERR) {
7577aec1d6eScindi topo_walk_fini(twp);
7587aec1d6eScindi out(O_DIE, "platform_config_snapshot: error walking topology "
7597aec1d6eScindi "tree");
7607c478bd9Sstevel@tonic-gate }
7617c478bd9Sstevel@tonic-gate
7627aec1d6eScindi topo_walk_fini(twp);
763b5016cbbSstephh out(O_ALTFP|O_STAMP, "raw config complete");
7647c478bd9Sstevel@tonic-gate
7657c478bd9Sstevel@tonic-gate
7667aec1d6eScindi return (Lastcfg);
7677c478bd9Sstevel@tonic-gate }
7687c478bd9Sstevel@tonic-gate
7697aec1d6eScindi static const char *
cfgstrprop_lookup(struct config * croot,char * path,const char * pname)770*da40b264SAlex Wilson cfgstrprop_lookup(struct config *croot, char *path, const char *pname)
7717c478bd9Sstevel@tonic-gate {
7727aec1d6eScindi struct config *cresource;
7737aec1d6eScindi const char *fmristr;
7747c478bd9Sstevel@tonic-gate
7757aec1d6eScindi /*
7767aec1d6eScindi * The first order of business is to find the resource in the
7777aec1d6eScindi * config database so we can examine properties associated with
7787aec1d6eScindi * that node.
7797aec1d6eScindi */
7807aec1d6eScindi if ((cresource = config_lookup(croot, path, 0)) == NULL) {
7817aec1d6eScindi out(O_ALTFP, "Cannot find config info for %s.", path);
7827c478bd9Sstevel@tonic-gate return (NULL);
7837c478bd9Sstevel@tonic-gate }
7847aec1d6eScindi if ((fmristr = config_getprop(cresource, pname)) == NULL) {
7857aec1d6eScindi out(O_ALTFP, "Cannot find %s property for %s resource "
7867aec1d6eScindi "re-write", pname, path);
7877c478bd9Sstevel@tonic-gate return (NULL);
7887c478bd9Sstevel@tonic-gate }
7897aec1d6eScindi return (fmristr);
7907c478bd9Sstevel@tonic-gate }
7917c478bd9Sstevel@tonic-gate
7927c478bd9Sstevel@tonic-gate /*
793*da40b264SAlex Wilson * Get FMRI for a particular unit from libtopo. The unit is specified by the
794*da40b264SAlex Wilson * "path" argument (a stringified ipath). "prop" argument should be one
795*da40b264SAlex Wilson * of the constants TOPO_PROP_RESOURCE, TOPO_PROP_ASRU, TOPO_PROP_FRU, etc.
7967c478bd9Sstevel@tonic-gate */
7977c478bd9Sstevel@tonic-gate /*ARGSUSED*/
7987c478bd9Sstevel@tonic-gate void
platform_unit_translate(int isdefect,struct config * croot,const char * prop,nvlist_t ** fmrip,char * path)799*da40b264SAlex Wilson platform_unit_translate(int isdefect, struct config *croot, const char *prop,
800*da40b264SAlex Wilson nvlist_t **fmrip, char *path)
8017c478bd9Sstevel@tonic-gate {
802b7d3956bSstephh const char *fmristr;
803b0daa853SStephen Hanson char *serial;
804*da40b264SAlex Wilson nvlist_t *fmri;
805b7d3956bSstephh int err;
8067c478bd9Sstevel@tonic-gate
807*da40b264SAlex Wilson fmristr = cfgstrprop_lookup(croot, path, prop);
808b7d3956bSstephh if (fmristr == NULL) {
809*da40b264SAlex Wilson out(O_ALTFP, "Cannot rewrite unit FMRI for %s.", path);
8107c478bd9Sstevel@tonic-gate return;
8117c478bd9Sstevel@tonic-gate }
812*da40b264SAlex Wilson if (topo_fmri_str2nvl(Eft_topo_hdl, fmristr, &fmri, &err) < 0) {
813b7d3956bSstephh out(O_ALTFP, "Can not convert config info: %s",
814b7d3956bSstephh topo_strerror(err));
815*da40b264SAlex Wilson out(O_ALTFP, "Cannot rewrite unit FMRI for %s.", path);
816b7d3956bSstephh return;
8177c478bd9Sstevel@tonic-gate }
818b0daa853SStephen Hanson
819b0daa853SStephen Hanson /*
820*da40b264SAlex Wilson * If we don't have a serial number in the unit then check if it
821b0daa853SStephen Hanson * is available as a separate property and if so then add it.
822b0daa853SStephen Hanson */
823*da40b264SAlex Wilson if (nvlist_lookup_string(fmri, FM_FMRI_HC_SERIAL_ID, &serial) != 0) {
824b0daa853SStephen Hanson serial = (char *)cfgstrprop_lookup(croot, path,
825b0daa853SStephen Hanson FM_FMRI_HC_SERIAL_ID);
826b0daa853SStephen Hanson if (serial != NULL)
827*da40b264SAlex Wilson (void) nvlist_add_string(fmri, FM_FMRI_HC_SERIAL_ID,
828b0daa853SStephen Hanson serial);
829b0daa853SStephen Hanson }
830b0daa853SStephen Hanson
831*da40b264SAlex Wilson *fmrip = fmri;
8327c478bd9Sstevel@tonic-gate }
8337c478bd9Sstevel@tonic-gate
8347c478bd9Sstevel@tonic-gate /*
8357c478bd9Sstevel@tonic-gate * platform_get_files -- return names of all files we should load
8367c478bd9Sstevel@tonic-gate *
8377c478bd9Sstevel@tonic-gate * search directories in dirname[] for all files with names ending with the
8387c478bd9Sstevel@tonic-gate * substring fnstr. dirname[] should be a NULL-terminated array. fnstr
8397c478bd9Sstevel@tonic-gate * may be set to "*" to indicate all files in a directory.
8407c478bd9Sstevel@tonic-gate *
8417c478bd9Sstevel@tonic-gate * if nodups is non-zero, then the first file of a given name found is
8427c478bd9Sstevel@tonic-gate * the only file added to the list of names. for example if nodups is
8437c478bd9Sstevel@tonic-gate * set and we're looking for .efts, and find a pci.eft in the dirname[0],
8447c478bd9Sstevel@tonic-gate * then no pci.eft found in any of the other dirname[] entries will be
8457c478bd9Sstevel@tonic-gate * included in the final list of names.
8467c478bd9Sstevel@tonic-gate *
8477c478bd9Sstevel@tonic-gate * this routine doesn't return NULL, even if no files are found (in that
8487c478bd9Sstevel@tonic-gate * case, a char ** is returned with the first element NULL).
8497c478bd9Sstevel@tonic-gate */
8507c478bd9Sstevel@tonic-gate static char **
platform_get_files(const char * dirname[],const char * fnstr,int nodups)8517c478bd9Sstevel@tonic-gate platform_get_files(const char *dirname[], const char *fnstr, int nodups)
8527c478bd9Sstevel@tonic-gate {
8537c478bd9Sstevel@tonic-gate DIR *dirp;
8547c478bd9Sstevel@tonic-gate struct dirent *dp;
8557c478bd9Sstevel@tonic-gate struct lut *foundnames = NULL;
8567c478bd9Sstevel@tonic-gate char **files = NULL; /* char * array of filenames found */
8577c478bd9Sstevel@tonic-gate int nfiles = 0; /* files found so far */
8587c478bd9Sstevel@tonic-gate int slots = 0; /* char * slots allocated in files */
8597c478bd9Sstevel@tonic-gate size_t fnlen, d_namelen;
8607c478bd9Sstevel@tonic-gate size_t totlen;
8617c478bd9Sstevel@tonic-gate int i;
8627c478bd9Sstevel@tonic-gate static char *nullav;
8637c478bd9Sstevel@tonic-gate
8647c478bd9Sstevel@tonic-gate ASSERT(fnstr != NULL);
8657c478bd9Sstevel@tonic-gate fnlen = strlen(fnstr);
8667c478bd9Sstevel@tonic-gate
8677c478bd9Sstevel@tonic-gate for (i = 0; dirname[i] != NULL; i++) {
868f6e214c7SGavin Maltby out(O_VERB, "Looking for %s files in %s", fnstr, dirname[i]);
8697c478bd9Sstevel@tonic-gate if ((dirp = opendir(dirname[i])) == NULL) {
8707c478bd9Sstevel@tonic-gate out(O_DEBUG|O_SYS,
8717c478bd9Sstevel@tonic-gate "platform_get_files: opendir failed for %s",
8727c478bd9Sstevel@tonic-gate dirname[i]);
8737c478bd9Sstevel@tonic-gate continue;
8747c478bd9Sstevel@tonic-gate }
8757c478bd9Sstevel@tonic-gate while ((dp = readdir(dirp)) != NULL) {
8767c478bd9Sstevel@tonic-gate if ((fnlen == 1 && *fnstr == '*') ||
8777c478bd9Sstevel@tonic-gate ((d_namelen = strlen(dp->d_name)) >= fnlen &&
8787c478bd9Sstevel@tonic-gate strncmp(dp->d_name + d_namelen - fnlen,
8797c478bd9Sstevel@tonic-gate fnstr, fnlen) == 0)) {
8807c478bd9Sstevel@tonic-gate
8817c478bd9Sstevel@tonic-gate if (nodups != 0) {
8827c478bd9Sstevel@tonic-gate const char *snm = stable(dp->d_name);
8837c478bd9Sstevel@tonic-gate
8847c478bd9Sstevel@tonic-gate if (lut_lookup(foundnames,
8857c478bd9Sstevel@tonic-gate (void *)snm,
8867c478bd9Sstevel@tonic-gate NULL) != NULL) {
887f6e214c7SGavin Maltby out(O_VERB,
8887c478bd9Sstevel@tonic-gate "platform_get_files: "
8897c478bd9Sstevel@tonic-gate "skipping repeated name "
8907c478bd9Sstevel@tonic-gate "%s/%s",
8917c478bd9Sstevel@tonic-gate dirname[i],
8927c478bd9Sstevel@tonic-gate snm);
8937c478bd9Sstevel@tonic-gate continue;
8947c478bd9Sstevel@tonic-gate }
8957c478bd9Sstevel@tonic-gate foundnames = lut_add(foundnames,
8967c478bd9Sstevel@tonic-gate (void *)snm,
8977c478bd9Sstevel@tonic-gate (void *)snm,
8987c478bd9Sstevel@tonic-gate NULL);
8997c478bd9Sstevel@tonic-gate }
9007c478bd9Sstevel@tonic-gate
9017c478bd9Sstevel@tonic-gate if (nfiles > slots - 2) {
9027c478bd9Sstevel@tonic-gate /* allocate ten more slots */
9037c478bd9Sstevel@tonic-gate slots += 10;
9047c478bd9Sstevel@tonic-gate files = (char **)REALLOC(files,
90524db4641Seschrock slots * sizeof (char *));
9067c478bd9Sstevel@tonic-gate }
9077c478bd9Sstevel@tonic-gate /* prepend directory name and / */
9087c478bd9Sstevel@tonic-gate totlen = strlen(dirname[i]) + 1;
9097c478bd9Sstevel@tonic-gate totlen += strlen(dp->d_name) + 1;
9107c478bd9Sstevel@tonic-gate files[nfiles] = MALLOC(totlen);
911f6e214c7SGavin Maltby out(O_VERB, "File %d: \"%s/%s\"", nfiles,
9127aec1d6eScindi dirname[i], dp->d_name);
9137c478bd9Sstevel@tonic-gate (void) snprintf(files[nfiles++], totlen,
9147c478bd9Sstevel@tonic-gate "%s/%s", dirname[i], dp->d_name);
9157c478bd9Sstevel@tonic-gate }
9167c478bd9Sstevel@tonic-gate }
9177c478bd9Sstevel@tonic-gate (void) closedir(dirp);
9187c478bd9Sstevel@tonic-gate }
9197c478bd9Sstevel@tonic-gate
9207c478bd9Sstevel@tonic-gate if (foundnames != NULL)
9217c478bd9Sstevel@tonic-gate lut_free(foundnames, NULL, NULL);
9227c478bd9Sstevel@tonic-gate
9237c478bd9Sstevel@tonic-gate if (nfiles == 0)
9247c478bd9Sstevel@tonic-gate return (&nullav);
9257c478bd9Sstevel@tonic-gate
9267c478bd9Sstevel@tonic-gate files[nfiles] = NULL;
9277c478bd9Sstevel@tonic-gate return (files);
9287c478bd9Sstevel@tonic-gate }
9297c478bd9Sstevel@tonic-gate
9303e8d8e18Sdb /*
9313e8d8e18Sdb * search for files in a standard set of directories
9323e8d8e18Sdb */
9333e8d8e18Sdb static char **
platform_get_files_stddirs(char * fname,int nodups)9343e8d8e18Sdb platform_get_files_stddirs(char *fname, int nodups)
9353e8d8e18Sdb {
9363e8d8e18Sdb const char *dirlist[4];
9373e8d8e18Sdb char **flist;
9383e8d8e18Sdb char *eftgendir, *eftmachdir, *eftplatdir;
9393e8d8e18Sdb
9403e8d8e18Sdb eftgendir = MALLOC(MAXPATHLEN);
9413e8d8e18Sdb eftmachdir = MALLOC(MAXPATHLEN);
9423e8d8e18Sdb eftplatdir = MALLOC(MAXPATHLEN);
9433e8d8e18Sdb
9443e8d8e18Sdb /* Generic files that apply to any machine */
9453e8d8e18Sdb (void) snprintf(eftgendir, MAXPATHLEN, "%s/usr/lib/fm/eft", Root);
9463e8d8e18Sdb
9473e8d8e18Sdb (void) snprintf(eftmachdir,
9483e8d8e18Sdb MAXPATHLEN, "%s/usr/platform/%s/lib/fm/eft", Root, Mach);
9493e8d8e18Sdb
9503e8d8e18Sdb (void) snprintf(eftplatdir,
9513e8d8e18Sdb MAXPATHLEN, "%s/usr/platform/%s/lib/fm/eft", Root, Plat);
9523e8d8e18Sdb
9533e8d8e18Sdb dirlist[0] = eftplatdir;
9543e8d8e18Sdb dirlist[1] = eftmachdir;
9553e8d8e18Sdb dirlist[2] = eftgendir;
9563e8d8e18Sdb dirlist[3] = NULL;
9573e8d8e18Sdb
9583e8d8e18Sdb flist = platform_get_files(dirlist, fname, nodups);
9593e8d8e18Sdb
9603e8d8e18Sdb FREE(eftplatdir);
9613e8d8e18Sdb FREE(eftmachdir);
9623e8d8e18Sdb FREE(eftgendir);
9633e8d8e18Sdb
9643e8d8e18Sdb return (flist);
9653e8d8e18Sdb }
9663e8d8e18Sdb
9677c478bd9Sstevel@tonic-gate /*
9687c478bd9Sstevel@tonic-gate * platform_run_poller -- execute a poller
9697c478bd9Sstevel@tonic-gate *
9707c478bd9Sstevel@tonic-gate * when eft needs to know if a polled ereport exists this routine
9717c478bd9Sstevel@tonic-gate * is called so the poller code may be run in a platform-specific way.
9727c478bd9Sstevel@tonic-gate * there's no return value from this routine -- either the polled ereport
9737c478bd9Sstevel@tonic-gate * is generated (and delivered *before* this routine returns) or not.
9747c478bd9Sstevel@tonic-gate * any errors, like "poller unknown" are considered platform-specific
9757c478bd9Sstevel@tonic-gate * should be handled here rather than passing an error back up.
9767c478bd9Sstevel@tonic-gate */
9777c478bd9Sstevel@tonic-gate /*ARGSUSED*/
9787c478bd9Sstevel@tonic-gate void
platform_run_poller(const char * poller)9797c478bd9Sstevel@tonic-gate platform_run_poller(const char *poller)
9807c478bd9Sstevel@tonic-gate {
9817c478bd9Sstevel@tonic-gate }
9827c478bd9Sstevel@tonic-gate
9837c478bd9Sstevel@tonic-gate /*
9847c478bd9Sstevel@tonic-gate * fork and execve path with argument array argv and environment array
9857c478bd9Sstevel@tonic-gate * envp. data from stdout and stderr are placed in outbuf and errbuf,
9867c478bd9Sstevel@tonic-gate * respectively.
9877c478bd9Sstevel@tonic-gate *
9887c478bd9Sstevel@tonic-gate * see execve(2) for more descriptions for path, argv and envp.
9897c478bd9Sstevel@tonic-gate */
9907c478bd9Sstevel@tonic-gate static int
forkandexecve(const char * path,char * const argv[],char * const envp[],char * outbuf,size_t outbuflen,char * errbuf,size_t errbuflen)9917c478bd9Sstevel@tonic-gate forkandexecve(const char *path, char *const argv[], char *const envp[],
9927c478bd9Sstevel@tonic-gate char *outbuf, size_t outbuflen, char *errbuf, size_t errbuflen)
9937c478bd9Sstevel@tonic-gate {
9947c478bd9Sstevel@tonic-gate pid_t pid;
9957c478bd9Sstevel@tonic-gate int outpipe[2], errpipe[2];
9967c478bd9Sstevel@tonic-gate int rt = 0;
9977c478bd9Sstevel@tonic-gate
9987c478bd9Sstevel@tonic-gate /*
9997c478bd9Sstevel@tonic-gate * run the cmd and see if it failed. this function is *not* a
10007c478bd9Sstevel@tonic-gate * generic command runner -- we depend on some knowledge we
10017c478bd9Sstevel@tonic-gate * have about the commands we run. first of all, we expect
10027c478bd9Sstevel@tonic-gate * errors to spew something to stdout, and that something is
10037c478bd9Sstevel@tonic-gate * typically short enough to fit into a pipe so we can wait()
10047c478bd9Sstevel@tonic-gate * for the command to complete and then fetch the error text
10057c478bd9Sstevel@tonic-gate * from the pipe.
10067c478bd9Sstevel@tonic-gate */
10077c478bd9Sstevel@tonic-gate if (pipe(outpipe) < 0)
10087c478bd9Sstevel@tonic-gate if (strlcat(errbuf, ": pipe(outpipe) failed",
100924db4641Seschrock errbuflen) >= errbuflen)
10107c478bd9Sstevel@tonic-gate return (1);
10117c478bd9Sstevel@tonic-gate if (pipe(errpipe) < 0)
10127c478bd9Sstevel@tonic-gate if (strlcat(errbuf, ": pipe(errpipe) failed",
101324db4641Seschrock errbuflen) >= errbuflen)
10147c478bd9Sstevel@tonic-gate return (1);
10157c478bd9Sstevel@tonic-gate
101624db4641Seschrock if ((pid = fork()) < 0) {
10177c478bd9Sstevel@tonic-gate rt = (int)strlcat(errbuf, ": fork() failed", errbuflen);
101824db4641Seschrock } else if (pid) {
10197c478bd9Sstevel@tonic-gate int wstat, count;
10207c478bd9Sstevel@tonic-gate
10217c478bd9Sstevel@tonic-gate /* parent */
10227c478bd9Sstevel@tonic-gate (void) close(errpipe[1]);
10237c478bd9Sstevel@tonic-gate (void) close(outpipe[1]);
10247c478bd9Sstevel@tonic-gate
10257c478bd9Sstevel@tonic-gate /* PHASE2 need to guard against hang in child? */
10267c478bd9Sstevel@tonic-gate if (waitpid(pid, &wstat, 0) < 0)
10277c478bd9Sstevel@tonic-gate if (strlcat(errbuf, ": waitpid() failed",
102824db4641Seschrock errbuflen) >= errbuflen)
10297c478bd9Sstevel@tonic-gate return (1);
10307c478bd9Sstevel@tonic-gate
10317c478bd9Sstevel@tonic-gate /* check for stderr contents */
10327c478bd9Sstevel@tonic-gate if (ioctl(errpipe[0], FIONREAD, &count) >= 0 && count) {
10337c478bd9Sstevel@tonic-gate if (read(errpipe[0], errbuf, errbuflen) <= 0) {
10347c478bd9Sstevel@tonic-gate /*
10357c478bd9Sstevel@tonic-gate * read failed even though ioctl indicated
10367c478bd9Sstevel@tonic-gate * that nonzero bytes were available for
10377c478bd9Sstevel@tonic-gate * reading
10387c478bd9Sstevel@tonic-gate */
10397c478bd9Sstevel@tonic-gate if (strlcat(errbuf, ": read(errpipe) failed",
104024db4641Seschrock errbuflen) >= errbuflen)
10417c478bd9Sstevel@tonic-gate return (1);
10427c478bd9Sstevel@tonic-gate }
10437c478bd9Sstevel@tonic-gate /*
10447c478bd9Sstevel@tonic-gate * handle case where errbuf is not properly
10457c478bd9Sstevel@tonic-gate * terminated
10467c478bd9Sstevel@tonic-gate */
10477c478bd9Sstevel@tonic-gate if (count > errbuflen - 1)
10487c478bd9Sstevel@tonic-gate count = errbuflen - 1;
10497c478bd9Sstevel@tonic-gate if (errbuf[count - 1] != '\0' &&
10507c478bd9Sstevel@tonic-gate errbuf[count - 1] != '\n')
10517c478bd9Sstevel@tonic-gate errbuf[count] = '\0';
10527c478bd9Sstevel@tonic-gate } else if (WIFSIGNALED(wstat))
10537c478bd9Sstevel@tonic-gate if (strlcat(errbuf, ": signaled",
105424db4641Seschrock errbuflen) >= errbuflen)
10557c478bd9Sstevel@tonic-gate return (1);
10567c478bd9Sstevel@tonic-gate else if (WIFEXITED(wstat) && WEXITSTATUS(wstat))
10577c478bd9Sstevel@tonic-gate if (strlcat(errbuf, ": abnormal exit",
105824db4641Seschrock errbuflen) >= errbuflen)
10597c478bd9Sstevel@tonic-gate return (1);
10607c478bd9Sstevel@tonic-gate
10617c478bd9Sstevel@tonic-gate /* check for stdout contents */
10627c478bd9Sstevel@tonic-gate if (ioctl(outpipe[0], FIONREAD, &count) >= 0 && count) {
10637c478bd9Sstevel@tonic-gate if (read(outpipe[0], outbuf, outbuflen) <= 0) {
10647c478bd9Sstevel@tonic-gate /*
10657c478bd9Sstevel@tonic-gate * read failed even though ioctl indicated
10667c478bd9Sstevel@tonic-gate * that nonzero bytes were available for
10677c478bd9Sstevel@tonic-gate * reading
10687c478bd9Sstevel@tonic-gate */
10697c478bd9Sstevel@tonic-gate if (strlcat(errbuf, ": read(outpipe) failed",
107024db4641Seschrock errbuflen) >= errbuflen)
10717c478bd9Sstevel@tonic-gate return (1);
10727c478bd9Sstevel@tonic-gate }
10737c478bd9Sstevel@tonic-gate /*
10747c478bd9Sstevel@tonic-gate * handle case where outbuf is not properly
10757c478bd9Sstevel@tonic-gate * terminated
10767c478bd9Sstevel@tonic-gate */
10777c478bd9Sstevel@tonic-gate if (count > outbuflen - 1)
10787c478bd9Sstevel@tonic-gate count = outbuflen - 1;
10797c478bd9Sstevel@tonic-gate if (outbuf[count - 1] != '\0' &&
10807c478bd9Sstevel@tonic-gate outbuf[count - 1] != '\n')
10817c478bd9Sstevel@tonic-gate outbuf[count] = '\0';
10827c478bd9Sstevel@tonic-gate }
10837c478bd9Sstevel@tonic-gate
10847c478bd9Sstevel@tonic-gate (void) close(errpipe[0]);
10857c478bd9Sstevel@tonic-gate (void) close(outpipe[0]);
10867c478bd9Sstevel@tonic-gate } else {
10877c478bd9Sstevel@tonic-gate /* child */
10887c478bd9Sstevel@tonic-gate (void) dup2(errpipe[1], fileno(stderr));
10897c478bd9Sstevel@tonic-gate (void) close(errpipe[0]);
10907c478bd9Sstevel@tonic-gate (void) dup2(outpipe[1], fileno(stdout));
10917c478bd9Sstevel@tonic-gate (void) close(outpipe[0]);
10927c478bd9Sstevel@tonic-gate
10937c478bd9Sstevel@tonic-gate if (execve(path, argv, envp))
10947c478bd9Sstevel@tonic-gate perror(path);
10957c478bd9Sstevel@tonic-gate _exit(1);
10967c478bd9Sstevel@tonic-gate }
10977c478bd9Sstevel@tonic-gate
10987c478bd9Sstevel@tonic-gate return (rt);
10997c478bd9Sstevel@tonic-gate }
11007c478bd9Sstevel@tonic-gate
11017c478bd9Sstevel@tonic-gate #define MAXDIGITIDX 23
11027c478bd9Sstevel@tonic-gate
11037c478bd9Sstevel@tonic-gate static int
arglist2argv(struct node * np,struct lut ** globals,struct config * croot,struct arrow * arrowp,char *** argv,int * argc,int * argvlen)11047c478bd9Sstevel@tonic-gate arglist2argv(struct node *np, struct lut **globals, struct config *croot,
11057c478bd9Sstevel@tonic-gate struct arrow *arrowp, char ***argv, int *argc, int *argvlen)
11067c478bd9Sstevel@tonic-gate {
11077c478bd9Sstevel@tonic-gate struct node *namep;
11087c478bd9Sstevel@tonic-gate char numbuf[MAXDIGITIDX + 1];
11097c478bd9Sstevel@tonic-gate char *numstr, *nullbyte;
11107c478bd9Sstevel@tonic-gate char *addthisarg = NULL;
11117c478bd9Sstevel@tonic-gate
11127c478bd9Sstevel@tonic-gate if (np == NULL)
11137c478bd9Sstevel@tonic-gate return (0);
11147c478bd9Sstevel@tonic-gate
11157c478bd9Sstevel@tonic-gate switch (np->t) {
11167c478bd9Sstevel@tonic-gate case T_QUOTE:
11177c478bd9Sstevel@tonic-gate addthisarg = STRDUP(np->u.func.s);
11187c478bd9Sstevel@tonic-gate break;
11197c478bd9Sstevel@tonic-gate case T_LIST:
11207c478bd9Sstevel@tonic-gate if (arglist2argv(np->u.expr.left, globals, croot, arrowp,
112124db4641Seschrock argv, argc, argvlen))
11227c478bd9Sstevel@tonic-gate return (1);
11237c478bd9Sstevel@tonic-gate /*
11247c478bd9Sstevel@tonic-gate * only leftmost element of a list can provide the command
11257c478bd9Sstevel@tonic-gate * name (after which *argc becomes 1)
11267c478bd9Sstevel@tonic-gate */
11277c478bd9Sstevel@tonic-gate ASSERT(*argc > 0);
11287c478bd9Sstevel@tonic-gate if (arglist2argv(np->u.expr.right, globals, croot, arrowp,
112924db4641Seschrock argv, argc, argvlen))
11307c478bd9Sstevel@tonic-gate return (1);
11317c478bd9Sstevel@tonic-gate break;
11327c478bd9Sstevel@tonic-gate case T_FUNC:
11337c478bd9Sstevel@tonic-gate case T_GLOBID:
11347c478bd9Sstevel@tonic-gate case T_ASSIGN:
11357c478bd9Sstevel@tonic-gate case T_CONDIF:
11367c478bd9Sstevel@tonic-gate case T_CONDELSE:
11377c478bd9Sstevel@tonic-gate case T_EQ:
11387c478bd9Sstevel@tonic-gate case T_NE:
11397c478bd9Sstevel@tonic-gate case T_LT:
11407c478bd9Sstevel@tonic-gate case T_LE:
11417c478bd9Sstevel@tonic-gate case T_GT:
11427c478bd9Sstevel@tonic-gate case T_GE:
11437c478bd9Sstevel@tonic-gate case T_BITAND:
11447c478bd9Sstevel@tonic-gate case T_BITOR:
11457c478bd9Sstevel@tonic-gate case T_BITXOR:
11467c478bd9Sstevel@tonic-gate case T_BITNOT:
11477c478bd9Sstevel@tonic-gate case T_LSHIFT:
11487c478bd9Sstevel@tonic-gate case T_RSHIFT:
11497c478bd9Sstevel@tonic-gate case T_AND:
11507c478bd9Sstevel@tonic-gate case T_OR:
11517c478bd9Sstevel@tonic-gate case T_NOT:
11527c478bd9Sstevel@tonic-gate case T_ADD:
11537c478bd9Sstevel@tonic-gate case T_SUB:
11547c478bd9Sstevel@tonic-gate case T_MUL:
11557c478bd9Sstevel@tonic-gate case T_DIV:
11567c478bd9Sstevel@tonic-gate case T_MOD: {
11577c478bd9Sstevel@tonic-gate struct evalue value;
11587c478bd9Sstevel@tonic-gate
11597c478bd9Sstevel@tonic-gate if (!eval_expr(np, NULL, NULL, globals, croot, arrowp,
116024db4641Seschrock 0, &value))
11617c478bd9Sstevel@tonic-gate return (1);
11627c478bd9Sstevel@tonic-gate
11637c478bd9Sstevel@tonic-gate switch (value.t) {
11647c478bd9Sstevel@tonic-gate case UINT64:
11657c478bd9Sstevel@tonic-gate numbuf[MAXDIGITIDX] = '\0';
11667c478bd9Sstevel@tonic-gate nullbyte = &numbuf[MAXDIGITIDX];
11677c478bd9Sstevel@tonic-gate numstr = ulltostr(value.v, nullbyte);
11687c478bd9Sstevel@tonic-gate addthisarg = STRDUP(numstr);
11697c478bd9Sstevel@tonic-gate break;
11707c478bd9Sstevel@tonic-gate case STRING:
117180ab886dSwesolows addthisarg = STRDUP((const char *)(uintptr_t)value.v);
11727c478bd9Sstevel@tonic-gate break;
11737c478bd9Sstevel@tonic-gate case NODEPTR :
117480ab886dSwesolows namep = (struct node *)(uintptr_t)value.v;
11757c478bd9Sstevel@tonic-gate addthisarg = ipath2str(NULL, ipath(namep));
11767c478bd9Sstevel@tonic-gate break;
11777c478bd9Sstevel@tonic-gate default:
11787c478bd9Sstevel@tonic-gate out(O_ERR,
11797c478bd9Sstevel@tonic-gate "call: arglist2argv: unexpected result from"
11807c478bd9Sstevel@tonic-gate " operation %s",
11817c478bd9Sstevel@tonic-gate ptree_nodetype2str(np->t));
11827c478bd9Sstevel@tonic-gate return (1);
11837c478bd9Sstevel@tonic-gate }
11847c478bd9Sstevel@tonic-gate break;
11857c478bd9Sstevel@tonic-gate }
11867c478bd9Sstevel@tonic-gate case T_NUM:
11877c478bd9Sstevel@tonic-gate case T_TIMEVAL:
11887c478bd9Sstevel@tonic-gate numbuf[MAXDIGITIDX] = '\0';
11897c478bd9Sstevel@tonic-gate nullbyte = &numbuf[MAXDIGITIDX];
11907c478bd9Sstevel@tonic-gate numstr = ulltostr(np->u.ull, nullbyte);
11917c478bd9Sstevel@tonic-gate addthisarg = STRDUP(numstr);
11927c478bd9Sstevel@tonic-gate break;
11937c478bd9Sstevel@tonic-gate case T_NAME:
11947c478bd9Sstevel@tonic-gate addthisarg = ipath2str(NULL, ipath(np));
11957c478bd9Sstevel@tonic-gate break;
11967c478bd9Sstevel@tonic-gate case T_EVENT:
11977c478bd9Sstevel@tonic-gate addthisarg = ipath2str(np->u.event.ename->u.name.s,
11987c478bd9Sstevel@tonic-gate ipath(np->u.event.epname));
11997c478bd9Sstevel@tonic-gate break;
12007c478bd9Sstevel@tonic-gate default:
12017c478bd9Sstevel@tonic-gate out(O_ERR, "call: arglist2argv: node type %s is unsupported",
12027c478bd9Sstevel@tonic-gate ptree_nodetype2str(np->t));
12037c478bd9Sstevel@tonic-gate return (1);
12047c478bd9Sstevel@tonic-gate /*NOTREACHED*/
12057c478bd9Sstevel@tonic-gate break;
12067c478bd9Sstevel@tonic-gate }
12077c478bd9Sstevel@tonic-gate
12087c478bd9Sstevel@tonic-gate if (*argc == 0 && addthisarg != NULL) {
12097c478bd9Sstevel@tonic-gate /*
12107c478bd9Sstevel@tonic-gate * first argument added is the command name.
12117c478bd9Sstevel@tonic-gate */
12127c478bd9Sstevel@tonic-gate char **files;
12137c478bd9Sstevel@tonic-gate
12143e8d8e18Sdb files = platform_get_files_stddirs(addthisarg, 0);
12157c478bd9Sstevel@tonic-gate
12167c478bd9Sstevel@tonic-gate /* do not proceed if number of files found != 1 */
12177c478bd9Sstevel@tonic-gate if (files[0] == NULL)
12187c478bd9Sstevel@tonic-gate out(O_DIE, "call: function %s not found", addthisarg);
12197c478bd9Sstevel@tonic-gate if (files[1] != NULL)
12207c478bd9Sstevel@tonic-gate out(O_DIE, "call: multiple functions %s found",
12217c478bd9Sstevel@tonic-gate addthisarg);
12227c478bd9Sstevel@tonic-gate FREE(addthisarg);
12237c478bd9Sstevel@tonic-gate
12247c478bd9Sstevel@tonic-gate addthisarg = STRDUP(files[0]);
12257c478bd9Sstevel@tonic-gate FREE(files[0]);
12267c478bd9Sstevel@tonic-gate FREE(files);
12277c478bd9Sstevel@tonic-gate }
12287c478bd9Sstevel@tonic-gate
12297c478bd9Sstevel@tonic-gate if (addthisarg != NULL) {
12307c478bd9Sstevel@tonic-gate if (*argc >= *argvlen - 2) {
12317c478bd9Sstevel@tonic-gate /*
12327c478bd9Sstevel@tonic-gate * make sure argv is long enough so it has a
12337c478bd9Sstevel@tonic-gate * terminating element set to NULL
12347c478bd9Sstevel@tonic-gate */
12357c478bd9Sstevel@tonic-gate *argvlen += 10;
12367c478bd9Sstevel@tonic-gate *argv = (char **)REALLOC(*argv,
123724db4641Seschrock sizeof (char *) * *argvlen);
12387c478bd9Sstevel@tonic-gate }
12397c478bd9Sstevel@tonic-gate (*argv)[*argc] = addthisarg;
12407c478bd9Sstevel@tonic-gate (*argc)++;
12417c478bd9Sstevel@tonic-gate (*argv)[*argc] = NULL;
12427c478bd9Sstevel@tonic-gate }
12437c478bd9Sstevel@tonic-gate
12447c478bd9Sstevel@tonic-gate return (0);
12457c478bd9Sstevel@tonic-gate }
12467c478bd9Sstevel@tonic-gate
12477c478bd9Sstevel@tonic-gate static int
generate_envp(struct arrow * arrowp,char *** envp,int * envc,int * envplen)12487c478bd9Sstevel@tonic-gate generate_envp(struct arrow *arrowp, char ***envp, int *envc, int *envplen)
12497c478bd9Sstevel@tonic-gate {
12507c478bd9Sstevel@tonic-gate char *envnames[] = { "EFT_FROM_EVENT", "EFT_TO_EVENT",
12517c478bd9Sstevel@tonic-gate "EFT_FILE", "EFT_LINE", NULL };
12527c478bd9Sstevel@tonic-gate char *envvalues[4];
12537c478bd9Sstevel@tonic-gate char *none = "(none)";
12547c478bd9Sstevel@tonic-gate size_t elen;
12557c478bd9Sstevel@tonic-gate int i;
12567c478bd9Sstevel@tonic-gate
12577c478bd9Sstevel@tonic-gate *envc = 4;
12587c478bd9Sstevel@tonic-gate
12597c478bd9Sstevel@tonic-gate /*
12607c478bd9Sstevel@tonic-gate * make sure envp is long enough so it has a terminating element
12617c478bd9Sstevel@tonic-gate * set to NULL
12627c478bd9Sstevel@tonic-gate */
12637c478bd9Sstevel@tonic-gate *envplen = *envc + 1;
12647c478bd9Sstevel@tonic-gate *envp = (char **)MALLOC(sizeof (char *) * *envplen);
12657c478bd9Sstevel@tonic-gate
12667c478bd9Sstevel@tonic-gate envvalues[0] = ipath2str(
12677c478bd9Sstevel@tonic-gate arrowp->tail->myevent->enode->u.event.ename->u.name.s,
12687c478bd9Sstevel@tonic-gate arrowp->tail->myevent->ipp);
12697c478bd9Sstevel@tonic-gate envvalues[1] = ipath2str(
12707c478bd9Sstevel@tonic-gate arrowp->head->myevent->enode->u.event.ename->u.name.s,
12717c478bd9Sstevel@tonic-gate arrowp->head->myevent->ipp);
12727c478bd9Sstevel@tonic-gate
12737c478bd9Sstevel@tonic-gate if (arrowp->head->myevent->enode->file == NULL) {
12747c478bd9Sstevel@tonic-gate envvalues[2] = STRDUP(none);
12757c478bd9Sstevel@tonic-gate envvalues[3] = STRDUP(none);
12767c478bd9Sstevel@tonic-gate } else {
12777c478bd9Sstevel@tonic-gate envvalues[2] = STRDUP(arrowp->head->myevent->enode->file);
12787c478bd9Sstevel@tonic-gate
12797c478bd9Sstevel@tonic-gate /* large enough for max int */
12807c478bd9Sstevel@tonic-gate envvalues[3] = MALLOC(sizeof (char) * 25);
12817c478bd9Sstevel@tonic-gate (void) snprintf(envvalues[3], sizeof (envvalues[3]), "%d",
128224db4641Seschrock arrowp->head->myevent->enode->line);
12837c478bd9Sstevel@tonic-gate }
12847c478bd9Sstevel@tonic-gate
12857c478bd9Sstevel@tonic-gate for (i = 0; envnames[i] != NULL && i < *envc; i++) {
12867c478bd9Sstevel@tonic-gate elen = strlen(envnames[i]) + strlen(envvalues[i]) + 2;
12877c478bd9Sstevel@tonic-gate (*envp)[i] = MALLOC(elen);
12887c478bd9Sstevel@tonic-gate (void) snprintf((*envp)[i], elen, "%s=%s",
12897c478bd9Sstevel@tonic-gate envnames[i], envvalues[i]);
12907c478bd9Sstevel@tonic-gate FREE(envvalues[i]);
12917c478bd9Sstevel@tonic-gate }
12927c478bd9Sstevel@tonic-gate (*envp)[*envc] = NULL;
12937c478bd9Sstevel@tonic-gate
12947c478bd9Sstevel@tonic-gate return (0);
12957c478bd9Sstevel@tonic-gate }
12967c478bd9Sstevel@tonic-gate
12977c478bd9Sstevel@tonic-gate /*
12987c478bd9Sstevel@tonic-gate * platform_call -- call an external function
12997c478bd9Sstevel@tonic-gate *
13007c478bd9Sstevel@tonic-gate * evaluate a user-defined function and place result in valuep. return 0
13017c478bd9Sstevel@tonic-gate * if function evaluation was successful; 1 if otherwise.
13027c478bd9Sstevel@tonic-gate */
13037c478bd9Sstevel@tonic-gate int
platform_call(struct node * np,struct lut ** globals,struct config * croot,struct arrow * arrowp,struct evalue * valuep)13047c478bd9Sstevel@tonic-gate platform_call(struct node *np, struct lut **globals, struct config *croot,
13057c478bd9Sstevel@tonic-gate struct arrow *arrowp, struct evalue *valuep)
13067c478bd9Sstevel@tonic-gate {
13077c478bd9Sstevel@tonic-gate /*
13087c478bd9Sstevel@tonic-gate * use rather short buffers. only the first string on outbuf[] is
13097c478bd9Sstevel@tonic-gate * taken as output from the called function. any message in
13107c478bd9Sstevel@tonic-gate * errbuf[] is echoed out as an error message.
13117c478bd9Sstevel@tonic-gate */
13127c478bd9Sstevel@tonic-gate char outbuf[256], errbuf[512];
13133e8d8e18Sdb struct stat buf;
13147c478bd9Sstevel@tonic-gate char **argv, **envp;
13157c478bd9Sstevel@tonic-gate int argc, argvlen, envc, envplen;
13167c478bd9Sstevel@tonic-gate int i, ret;
13177c478bd9Sstevel@tonic-gate
13187c478bd9Sstevel@tonic-gate /*
13197c478bd9Sstevel@tonic-gate * np is the argument list. the user-defined function is the first
13207c478bd9Sstevel@tonic-gate * element of the list.
13217c478bd9Sstevel@tonic-gate */
13227c478bd9Sstevel@tonic-gate ASSERT(np->t == T_LIST);
13237c478bd9Sstevel@tonic-gate
13247c478bd9Sstevel@tonic-gate argv = NULL;
13257c478bd9Sstevel@tonic-gate argc = 0;
13267c478bd9Sstevel@tonic-gate argvlen = 0;
13277c478bd9Sstevel@tonic-gate if (arglist2argv(np, globals, croot, arrowp, &argv, &argc, &argvlen) ||
13287c478bd9Sstevel@tonic-gate argc == 0)
13297c478bd9Sstevel@tonic-gate return (1);
13307c478bd9Sstevel@tonic-gate
13313e8d8e18Sdb /*
13323e8d8e18Sdb * make sure program has executable bit set
13333e8d8e18Sdb */
13343e8d8e18Sdb if (stat(argv[0], &buf) == 0) {
13353e8d8e18Sdb int exec_bit_set = 0;
13363e8d8e18Sdb
13373e8d8e18Sdb if (buf.st_uid == geteuid() && buf.st_mode & S_IXUSR)
13383e8d8e18Sdb exec_bit_set = 1;
13393e8d8e18Sdb else if (buf.st_gid == getegid() && buf.st_mode & S_IXGRP)
13403e8d8e18Sdb exec_bit_set = 1;
13413e8d8e18Sdb else if (buf.st_mode & S_IXOTH)
13423e8d8e18Sdb exec_bit_set = 1;
13433e8d8e18Sdb
13443e8d8e18Sdb if (exec_bit_set == 0)
13453e8d8e18Sdb out(O_DIE, "call: executable bit not set on %s",
13463e8d8e18Sdb argv[0]);
13473e8d8e18Sdb } else {
13483e8d8e18Sdb out(O_DIE, "call: failure in stat(), errno = %d\n", errno);
13493e8d8e18Sdb }
13503e8d8e18Sdb
13517c478bd9Sstevel@tonic-gate envp = NULL;
13527c478bd9Sstevel@tonic-gate envc = 0;
13537c478bd9Sstevel@tonic-gate envplen = 0;
13547c478bd9Sstevel@tonic-gate if (generate_envp(arrowp, &envp, &envc, &envplen))
13557c478bd9Sstevel@tonic-gate return (1);
13567c478bd9Sstevel@tonic-gate
13577c478bd9Sstevel@tonic-gate outbuf[0] = '\0';
13587c478bd9Sstevel@tonic-gate errbuf[0] = '\0';
13597c478bd9Sstevel@tonic-gate
13607c478bd9Sstevel@tonic-gate ret = forkandexecve((const char *) argv[0], (char *const *) argv,
136124db4641Seschrock (char *const *) envp, outbuf, sizeof (outbuf),
136224db4641Seschrock errbuf, sizeof (errbuf));
13637c478bd9Sstevel@tonic-gate
13647c478bd9Sstevel@tonic-gate for (i = 0; i < envc; i++)
13657c478bd9Sstevel@tonic-gate FREE(envp[i]);
13667c478bd9Sstevel@tonic-gate if (envp)
13677c478bd9Sstevel@tonic-gate FREE(envp);
13687c478bd9Sstevel@tonic-gate
13697c478bd9Sstevel@tonic-gate if (ret) {
13707c478bd9Sstevel@tonic-gate outfl(O_OK, np->file, np->line,
137124db4641Seschrock "call: failure in fork + exec of %s", argv[0]);
13727c478bd9Sstevel@tonic-gate } else {
13737aec1d6eScindi char *ptr;
13747aec1d6eScindi
13757aec1d6eScindi /* chomp the result */
13767aec1d6eScindi for (ptr = outbuf; *ptr; ptr++)
13777aec1d6eScindi if (*ptr == '\n' || *ptr == '\r') {
13787aec1d6eScindi *ptr = '\0';
13797aec1d6eScindi break;
13807aec1d6eScindi }
13817aec1d6eScindi valuep->t = STRING;
138280ab886dSwesolows valuep->v = (uintptr_t)stable(outbuf);
13837c478bd9Sstevel@tonic-gate }
13847c478bd9Sstevel@tonic-gate
13857c478bd9Sstevel@tonic-gate if (errbuf[0] != '\0') {
13867c478bd9Sstevel@tonic-gate ret = 1;
13877c478bd9Sstevel@tonic-gate outfl(O_OK, np->file, np->line,
138824db4641Seschrock "call: unexpected stderr output from %s: %s",
138924db4641Seschrock argv[0], errbuf);
13907c478bd9Sstevel@tonic-gate }
13917c478bd9Sstevel@tonic-gate
13927c478bd9Sstevel@tonic-gate for (i = 0; i < argc; i++)
13937c478bd9Sstevel@tonic-gate FREE(argv[i]);
13947c478bd9Sstevel@tonic-gate FREE(argv);
13957c478bd9Sstevel@tonic-gate
13967c478bd9Sstevel@tonic-gate return (ret);
13977c478bd9Sstevel@tonic-gate }
13987c478bd9Sstevel@tonic-gate
13997aec1d6eScindi /*
14007aec1d6eScindi * platform_confcall -- call a configuration database function
14017aec1d6eScindi *
14027aec1d6eScindi * returns result in *valuep, return 0 on success
14037aec1d6eScindi */
14047aec1d6eScindi /*ARGSUSED*/
14057aec1d6eScindi int
platform_confcall(struct node * np,struct lut ** globals,struct config * croot,struct arrow * arrowp,struct evalue * valuep)14067aec1d6eScindi platform_confcall(struct node *np, struct lut **globals, struct config *croot,
14077aec1d6eScindi struct arrow *arrowp, struct evalue *valuep)
14087aec1d6eScindi {
1409b7d3956bSstephh outfl(O_ALTFP|O_VERB, np->file, np->line, "unknown confcall");
14107aec1d6eScindi return (0);
14117aec1d6eScindi }
14127aec1d6eScindi
14137c478bd9Sstevel@tonic-gate /*
14147c478bd9Sstevel@tonic-gate * platform_get_eft_files -- return names of all eft files we should load
14157c478bd9Sstevel@tonic-gate *
14167c478bd9Sstevel@tonic-gate * this routine doesn't return NULL, even if no files are found (in that
14177c478bd9Sstevel@tonic-gate * case, a char ** is returned with the first element NULL).
14187c478bd9Sstevel@tonic-gate */
14197c478bd9Sstevel@tonic-gate char **
platform_get_eft_files(void)14207c478bd9Sstevel@tonic-gate platform_get_eft_files(void)
14217c478bd9Sstevel@tonic-gate {
14223e8d8e18Sdb return (platform_get_files_stddirs(".eft", 1));
14237c478bd9Sstevel@tonic-gate }
14247c478bd9Sstevel@tonic-gate
14257c478bd9Sstevel@tonic-gate void
platform_free_eft_files(char ** flist)14267c478bd9Sstevel@tonic-gate platform_free_eft_files(char **flist)
14277c478bd9Sstevel@tonic-gate {
14287c478bd9Sstevel@tonic-gate char **f;
14297c478bd9Sstevel@tonic-gate
14307c478bd9Sstevel@tonic-gate if (flist == NULL || *flist == NULL)
14317c478bd9Sstevel@tonic-gate return; /* no files were found so we're done */
14327c478bd9Sstevel@tonic-gate
14337c478bd9Sstevel@tonic-gate f = flist;
14347c478bd9Sstevel@tonic-gate while (*f != NULL) {
14357c478bd9Sstevel@tonic-gate FREE(*f);
14367c478bd9Sstevel@tonic-gate f++;
14377c478bd9Sstevel@tonic-gate }
14387c478bd9Sstevel@tonic-gate FREE(flist);
14397c478bd9Sstevel@tonic-gate }
14407c478bd9Sstevel@tonic-gate
14417c478bd9Sstevel@tonic-gate static nvlist_t *payloadnvp = NULL;
14427c478bd9Sstevel@tonic-gate
14437c478bd9Sstevel@tonic-gate void
platform_set_payloadnvp(nvlist_t * nvlp)14447c478bd9Sstevel@tonic-gate platform_set_payloadnvp(nvlist_t *nvlp)
14457c478bd9Sstevel@tonic-gate {
14467c478bd9Sstevel@tonic-gate /*
14477c478bd9Sstevel@tonic-gate * cannot replace a non-NULL payloadnvp with a non-NULL nvlp
14487c478bd9Sstevel@tonic-gate */
14497c478bd9Sstevel@tonic-gate ASSERT(payloadnvp != NULL ? nvlp == NULL : 1);
14507c478bd9Sstevel@tonic-gate payloadnvp = nvlp;
14517c478bd9Sstevel@tonic-gate }
14527c478bd9Sstevel@tonic-gate
14537c478bd9Sstevel@tonic-gate /*
14547c478bd9Sstevel@tonic-gate * given array notation in inputstr such as "foo[1]" or "foo [ 1 ]" (spaces
14557c478bd9Sstevel@tonic-gate * allowed), figure out the array name and index. return 0 if successful,
14567c478bd9Sstevel@tonic-gate * nonzero if otherwise.
14577c478bd9Sstevel@tonic-gate */
14587c478bd9Sstevel@tonic-gate static int
get_array_info(const char * inputstr,const char ** name,unsigned int * index)14597c478bd9Sstevel@tonic-gate get_array_info(const char *inputstr, const char **name, unsigned int *index)
14607c478bd9Sstevel@tonic-gate {
14617c478bd9Sstevel@tonic-gate char *indexptr, *indexend, *dupname, *endname;
14627c478bd9Sstevel@tonic-gate
14637c478bd9Sstevel@tonic-gate if (strchr(inputstr, '[') == NULL)
14647c478bd9Sstevel@tonic-gate return (1);
14657c478bd9Sstevel@tonic-gate
14667c478bd9Sstevel@tonic-gate dupname = STRDUP(inputstr);
14677c478bd9Sstevel@tonic-gate indexptr = strchr(dupname, '[');
14687c478bd9Sstevel@tonic-gate indexend = strchr(dupname, ']');
14697c478bd9Sstevel@tonic-gate
14707c478bd9Sstevel@tonic-gate /*
14717c478bd9Sstevel@tonic-gate * return if array notation is not complete or if index is negative
14727c478bd9Sstevel@tonic-gate */
14737c478bd9Sstevel@tonic-gate if (indexend == NULL || indexptr >= indexend ||
14747c478bd9Sstevel@tonic-gate strchr(indexptr, '-') != NULL) {
14757c478bd9Sstevel@tonic-gate FREE(dupname);
14767c478bd9Sstevel@tonic-gate return (1);
14777c478bd9Sstevel@tonic-gate }
14787c478bd9Sstevel@tonic-gate
14797c478bd9Sstevel@tonic-gate /*
14807c478bd9Sstevel@tonic-gate * search past any spaces between the name string and '['
14817c478bd9Sstevel@tonic-gate */
14827c478bd9Sstevel@tonic-gate endname = indexptr;
14837c478bd9Sstevel@tonic-gate while (isspace(*(endname - 1)) && dupname < endname)
14847c478bd9Sstevel@tonic-gate endname--;
14857c478bd9Sstevel@tonic-gate *endname = '\0';
14867c478bd9Sstevel@tonic-gate ASSERT(dupname < endname);
14877c478bd9Sstevel@tonic-gate
14887c478bd9Sstevel@tonic-gate /*
14897c478bd9Sstevel@tonic-gate * search until indexptr points to the first digit and indexend
14907c478bd9Sstevel@tonic-gate * points to the last digit
14917c478bd9Sstevel@tonic-gate */
14927c478bd9Sstevel@tonic-gate while (!isdigit(*indexptr) && indexptr < indexend)
14937c478bd9Sstevel@tonic-gate indexptr++;
14947c478bd9Sstevel@tonic-gate while (!isdigit(*indexend) && indexptr <= indexend)
14957c478bd9Sstevel@tonic-gate indexend--;
14967c478bd9Sstevel@tonic-gate
14977c478bd9Sstevel@tonic-gate *(indexend + 1) = '\0';
14987c478bd9Sstevel@tonic-gate *index = (unsigned int)atoi(indexptr);
14997c478bd9Sstevel@tonic-gate
15007c478bd9Sstevel@tonic-gate *name = stable(dupname);
15017c478bd9Sstevel@tonic-gate FREE(dupname);
15027c478bd9Sstevel@tonic-gate
15037c478bd9Sstevel@tonic-gate return (0);
15047c478bd9Sstevel@tonic-gate }
15057c478bd9Sstevel@tonic-gate
15067aec1d6eScindi /*
15077aec1d6eScindi * platform_payloadprop -- fetch a payload value
15087aec1d6eScindi *
15097aec1d6eScindi * XXX this function should be replaced and eval_func() should be
15107aec1d6eScindi * XXX changed to use the more general platform_payloadprop_values().
15117aec1d6eScindi */
15127c478bd9Sstevel@tonic-gate int
platform_payloadprop(struct node * np,struct evalue * valuep)15137c478bd9Sstevel@tonic-gate platform_payloadprop(struct node *np, struct evalue *valuep)
15147c478bd9Sstevel@tonic-gate {
15153e8d8e18Sdb nvlist_t *basenvp;
15167aec1d6eScindi nvlist_t *embnvp = NULL;
15177c478bd9Sstevel@tonic-gate nvpair_t *nvpair;
15183e8d8e18Sdb const char *nameptr, *propstr, *lastnameptr;
15197c478bd9Sstevel@tonic-gate int not_array = 0;
15207c478bd9Sstevel@tonic-gate unsigned int index = 0;
15217c478bd9Sstevel@tonic-gate uint_t nelem;
15223e8d8e18Sdb char *nvpname, *nameslist = NULL;
15237aec1d6eScindi char *scheme = NULL;
15247c478bd9Sstevel@tonic-gate
15257c478bd9Sstevel@tonic-gate ASSERT(np->t == T_QUOTE);
15267c478bd9Sstevel@tonic-gate
15273e8d8e18Sdb propstr = np->u.quote.s;
15287c478bd9Sstevel@tonic-gate if (payloadnvp == NULL) {
15298a40a695Sgavinm out(O_ALTFP | O_VERB2, "platform_payloadprop: no nvp for %s",
15303e8d8e18Sdb propstr);
15317c478bd9Sstevel@tonic-gate return (1);
15327c478bd9Sstevel@tonic-gate }
15333e8d8e18Sdb basenvp = payloadnvp;
15343e8d8e18Sdb
15353e8d8e18Sdb /*
15363e8d8e18Sdb * first handle any embedded nvlists. if propstr is "foo.bar[2]"
15373e8d8e18Sdb * then lastnameptr should end up being "bar[2]" with basenvp set
15383e8d8e18Sdb * to the nvlist for "foo". (the search for "bar" within "foo"
15393e8d8e18Sdb * will be done later.)
15403e8d8e18Sdb */
15413e8d8e18Sdb if (strchr(propstr, '.') != NULL) {
15423e8d8e18Sdb nvlist_t **arraynvp;
15433e8d8e18Sdb uint_t nelem;
15443e8d8e18Sdb char *w;
15453e8d8e18Sdb int ier;
15463e8d8e18Sdb
15473e8d8e18Sdb nameslist = STRDUP(propstr);
15483e8d8e18Sdb lastnameptr = strtok(nameslist, ".");
15493e8d8e18Sdb
15503e8d8e18Sdb /*
15513e8d8e18Sdb * decompose nameslist into its component names while
15523e8d8e18Sdb * extracting the embedded nvlist
15533e8d8e18Sdb */
15543e8d8e18Sdb while ((w = strtok(NULL, ".")) != NULL) {
15553e8d8e18Sdb if (get_array_info(lastnameptr, &nameptr, &index)) {
15563e8d8e18Sdb ier = nvlist_lookup_nvlist(basenvp,
155724db4641Seschrock lastnameptr, &basenvp);
15583e8d8e18Sdb } else {
15593e8d8e18Sdb /* handle array of nvlists */
15603e8d8e18Sdb ier = nvlist_lookup_nvlist_array(basenvp,
156124db4641Seschrock nameptr, &arraynvp, &nelem);
15623e8d8e18Sdb if (ier == 0) {
15633e8d8e18Sdb if ((uint_t)index > nelem - 1)
15643e8d8e18Sdb ier = 1;
15653e8d8e18Sdb else
15663e8d8e18Sdb basenvp = arraynvp[index];
15673e8d8e18Sdb }
15683e8d8e18Sdb }
15693e8d8e18Sdb
15703e8d8e18Sdb if (ier) {
15713e8d8e18Sdb out(O_ALTFP, "platform_payloadprop: "
15723e8d8e18Sdb " invalid list for %s (in %s)",
15733e8d8e18Sdb lastnameptr, propstr);
15743e8d8e18Sdb FREE(nameslist);
15753e8d8e18Sdb return (1);
15763e8d8e18Sdb }
15773e8d8e18Sdb
15783e8d8e18Sdb lastnameptr = w;
15793e8d8e18Sdb }
15803e8d8e18Sdb } else {
15813e8d8e18Sdb lastnameptr = propstr;
15823e8d8e18Sdb }
15833e8d8e18Sdb
15843e8d8e18Sdb /* if property is an array reference, extract array name and index */
15853e8d8e18Sdb not_array = get_array_info(lastnameptr, &nameptr, &index);
15863e8d8e18Sdb if (not_array)
15873e8d8e18Sdb nameptr = stable(lastnameptr);
15887c478bd9Sstevel@tonic-gate
15893e8d8e18Sdb if (nameslist != NULL)
15903e8d8e18Sdb FREE(nameslist);
15917c478bd9Sstevel@tonic-gate
15927c478bd9Sstevel@tonic-gate /* search for nvpair entry */
15937c478bd9Sstevel@tonic-gate nvpair = NULL;
15943e8d8e18Sdb while ((nvpair = nvlist_next_nvpair(basenvp, nvpair)) != NULL) {
15957c478bd9Sstevel@tonic-gate nvpname = nvpair_name(nvpair);
15967c478bd9Sstevel@tonic-gate ASSERT(nvpname != NULL);
15977c478bd9Sstevel@tonic-gate
15983e8d8e18Sdb if (nameptr == stable(nvpname))
15997c478bd9Sstevel@tonic-gate break;
16007c478bd9Sstevel@tonic-gate }
16017c478bd9Sstevel@tonic-gate
16027c478bd9Sstevel@tonic-gate if (nvpair == NULL) {
16033e8d8e18Sdb out(O_ALTFP, "platform_payloadprop: no entry for %s", propstr);
16047c478bd9Sstevel@tonic-gate return (1);
16057aec1d6eScindi } else if (valuep == NULL) {
16067aec1d6eScindi /*
16077aec1d6eScindi * caller is interested in the existence of a property with
16087aec1d6eScindi * this name, regardless of type or value
16097aec1d6eScindi */
16107aec1d6eScindi return (0);
16117c478bd9Sstevel@tonic-gate }
16127c478bd9Sstevel@tonic-gate
16137aec1d6eScindi valuep->t = UNDEFINED;
16147aec1d6eScindi
16157c478bd9Sstevel@tonic-gate /*
16167c478bd9Sstevel@tonic-gate * get to this point if we found an entry. figure out its data
16177c478bd9Sstevel@tonic-gate * type and copy its value.
16187c478bd9Sstevel@tonic-gate */
16197aec1d6eScindi (void) nvpair_value_nvlist(nvpair, &embnvp);
16207aec1d6eScindi if (nvlist_lookup_string(embnvp, FM_FMRI_SCHEME, &scheme) == 0) {
16217aec1d6eScindi if (strcmp(scheme, FM_FMRI_SCHEME_HC) == 0) {
16227aec1d6eScindi valuep->t = NODEPTR;
162380ab886dSwesolows valuep->v = (uintptr_t)hc_fmri_nodeize(embnvp);
16247aec1d6eScindi return (0);
16257aec1d6eScindi }
16267aec1d6eScindi }
16277c478bd9Sstevel@tonic-gate switch (nvpair_type(nvpair)) {
16287c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN:
16297c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN_VALUE: {
16307c478bd9Sstevel@tonic-gate boolean_t val;
16317c478bd9Sstevel@tonic-gate (void) nvpair_value_boolean_value(nvpair, &val);
16327c478bd9Sstevel@tonic-gate valuep->t = UINT64;
16337c478bd9Sstevel@tonic-gate valuep->v = (unsigned long long)val;
16347c478bd9Sstevel@tonic-gate break;
16357c478bd9Sstevel@tonic-gate }
16367c478bd9Sstevel@tonic-gate case DATA_TYPE_BYTE: {
16377c478bd9Sstevel@tonic-gate uchar_t val;
16387c478bd9Sstevel@tonic-gate (void) nvpair_value_byte(nvpair, &val);
16397c478bd9Sstevel@tonic-gate valuep->t = UINT64;
16407c478bd9Sstevel@tonic-gate valuep->v = (unsigned long long)val;
16417c478bd9Sstevel@tonic-gate break;
16427c478bd9Sstevel@tonic-gate }
16437c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING: {
16447c478bd9Sstevel@tonic-gate char *val;
16457c478bd9Sstevel@tonic-gate valuep->t = STRING;
16467c478bd9Sstevel@tonic-gate (void) nvpair_value_string(nvpair, &val);
164780ab886dSwesolows valuep->v = (uintptr_t)stable(val);
16487c478bd9Sstevel@tonic-gate break;
16497c478bd9Sstevel@tonic-gate }
16507c478bd9Sstevel@tonic-gate
16517c478bd9Sstevel@tonic-gate case DATA_TYPE_INT8: {
16527c478bd9Sstevel@tonic-gate int8_t val;
16537c478bd9Sstevel@tonic-gate (void) nvpair_value_int8(nvpair, &val);
16547c478bd9Sstevel@tonic-gate valuep->t = UINT64;
16557c478bd9Sstevel@tonic-gate valuep->v = (unsigned long long)val;
16567c478bd9Sstevel@tonic-gate break;
16577c478bd9Sstevel@tonic-gate }
16587c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT8: {
16597c478bd9Sstevel@tonic-gate uint8_t val;
16607c478bd9Sstevel@tonic-gate (void) nvpair_value_uint8(nvpair, &val);
16617c478bd9Sstevel@tonic-gate valuep->t = UINT64;
16627c478bd9Sstevel@tonic-gate valuep->v = (unsigned long long)val;
16637c478bd9Sstevel@tonic-gate break;
16647c478bd9Sstevel@tonic-gate }
16657c478bd9Sstevel@tonic-gate
16667c478bd9Sstevel@tonic-gate case DATA_TYPE_INT16: {
16677c478bd9Sstevel@tonic-gate int16_t val;
16687c478bd9Sstevel@tonic-gate (void) nvpair_value_int16(nvpair, &val);
16697c478bd9Sstevel@tonic-gate valuep->t = UINT64;
16707c478bd9Sstevel@tonic-gate valuep->v = (unsigned long long)val;
16717c478bd9Sstevel@tonic-gate break;
16727c478bd9Sstevel@tonic-gate }
16737c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT16: {
16747c478bd9Sstevel@tonic-gate uint16_t val;
16757c478bd9Sstevel@tonic-gate (void) nvpair_value_uint16(nvpair, &val);
16767c478bd9Sstevel@tonic-gate valuep->t = UINT64;
16777c478bd9Sstevel@tonic-gate valuep->v = (unsigned long long)val;
16787c478bd9Sstevel@tonic-gate break;
16797c478bd9Sstevel@tonic-gate }
16807c478bd9Sstevel@tonic-gate
16817c478bd9Sstevel@tonic-gate case DATA_TYPE_INT32: {
16827c478bd9Sstevel@tonic-gate int32_t val;
16837c478bd9Sstevel@tonic-gate (void) nvpair_value_int32(nvpair, &val);
16847c478bd9Sstevel@tonic-gate valuep->t = UINT64;
16857c478bd9Sstevel@tonic-gate valuep->v = (unsigned long long)val;
16867c478bd9Sstevel@tonic-gate break;
16877c478bd9Sstevel@tonic-gate }
16887c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT32: {
16897c478bd9Sstevel@tonic-gate uint32_t val;
16907c478bd9Sstevel@tonic-gate (void) nvpair_value_uint32(nvpair, &val);
16917c478bd9Sstevel@tonic-gate valuep->t = UINT64;
16927c478bd9Sstevel@tonic-gate valuep->v = (unsigned long long)val;
16937c478bd9Sstevel@tonic-gate break;
16947c478bd9Sstevel@tonic-gate }
16957c478bd9Sstevel@tonic-gate
16967c478bd9Sstevel@tonic-gate case DATA_TYPE_INT64: {
16977c478bd9Sstevel@tonic-gate int64_t val;
16987c478bd9Sstevel@tonic-gate (void) nvpair_value_int64(nvpair, &val);
16997c478bd9Sstevel@tonic-gate valuep->t = UINT64;
17007c478bd9Sstevel@tonic-gate valuep->v = (unsigned long long)val;
17017c478bd9Sstevel@tonic-gate break;
17027c478bd9Sstevel@tonic-gate }
17037c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT64: {
17047c478bd9Sstevel@tonic-gate uint64_t val;
17057c478bd9Sstevel@tonic-gate (void) nvpair_value_uint64(nvpair, &val);
17067c478bd9Sstevel@tonic-gate valuep->t = UINT64;
17077c478bd9Sstevel@tonic-gate valuep->v = (unsigned long long)val;
17087c478bd9Sstevel@tonic-gate break;
17097c478bd9Sstevel@tonic-gate }
17107c478bd9Sstevel@tonic-gate
17117c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN_ARRAY: {
17127c478bd9Sstevel@tonic-gate boolean_t *val;
17137c478bd9Sstevel@tonic-gate (void) nvpair_value_boolean_array(nvpair, &val, &nelem);
17147c478bd9Sstevel@tonic-gate if (not_array == 1 || index >= nelem)
17157c478bd9Sstevel@tonic-gate goto invalid;
17167c478bd9Sstevel@tonic-gate valuep->t = UINT64;
17177c478bd9Sstevel@tonic-gate valuep->v = (unsigned long long)val[index];
17187c478bd9Sstevel@tonic-gate break;
17197c478bd9Sstevel@tonic-gate }
17207c478bd9Sstevel@tonic-gate case DATA_TYPE_BYTE_ARRAY: {
17217c478bd9Sstevel@tonic-gate uchar_t *val;
17227c478bd9Sstevel@tonic-gate (void) nvpair_value_byte_array(nvpair, &val, &nelem);
17237c478bd9Sstevel@tonic-gate if (not_array == 1 || index >= nelem)
17247c478bd9Sstevel@tonic-gate goto invalid;
17257c478bd9Sstevel@tonic-gate valuep->t = UINT64;
17267c478bd9Sstevel@tonic-gate valuep->v = (unsigned long long)val[index];
17277c478bd9Sstevel@tonic-gate break;
17287c478bd9Sstevel@tonic-gate }
17297c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING_ARRAY: {
17307c478bd9Sstevel@tonic-gate char **val;
17317c478bd9Sstevel@tonic-gate (void) nvpair_value_string_array(nvpair, &val, &nelem);
17327c478bd9Sstevel@tonic-gate if (not_array == 1 || index >= nelem)
17337c478bd9Sstevel@tonic-gate goto invalid;
17347c478bd9Sstevel@tonic-gate valuep->t = STRING;
173580ab886dSwesolows valuep->v = (uintptr_t)stable(val[index]);
17367c478bd9Sstevel@tonic-gate break;
17377c478bd9Sstevel@tonic-gate }
17387c478bd9Sstevel@tonic-gate
17397c478bd9Sstevel@tonic-gate case DATA_TYPE_INT8_ARRAY: {
17407c478bd9Sstevel@tonic-gate int8_t *val;
17417c478bd9Sstevel@tonic-gate (void) nvpair_value_int8_array(nvpair, &val, &nelem);
17427c478bd9Sstevel@tonic-gate if (not_array == 1 || index >= nelem)
17437c478bd9Sstevel@tonic-gate goto invalid;
17447c478bd9Sstevel@tonic-gate valuep->t = UINT64;
17457c478bd9Sstevel@tonic-gate valuep->v = (unsigned long long)val[index];
17467c478bd9Sstevel@tonic-gate break;
17477c478bd9Sstevel@tonic-gate }
17487c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT8_ARRAY: {
17497c478bd9Sstevel@tonic-gate uint8_t *val;
17507c478bd9Sstevel@tonic-gate (void) nvpair_value_uint8_array(nvpair, &val, &nelem);
17517c478bd9Sstevel@tonic-gate if (not_array == 1 || index >= nelem)
17527c478bd9Sstevel@tonic-gate goto invalid;
17537c478bd9Sstevel@tonic-gate valuep->t = UINT64;
17547c478bd9Sstevel@tonic-gate valuep->v = (unsigned long long)val[index];
17557c478bd9Sstevel@tonic-gate break;
17567c478bd9Sstevel@tonic-gate }
17577c478bd9Sstevel@tonic-gate case DATA_TYPE_INT16_ARRAY: {
17587c478bd9Sstevel@tonic-gate int16_t *val;
17597c478bd9Sstevel@tonic-gate (void) nvpair_value_int16_array(nvpair, &val, &nelem);
17607c478bd9Sstevel@tonic-gate if (not_array == 1 || index >= nelem)
17617c478bd9Sstevel@tonic-gate goto invalid;
17627c478bd9Sstevel@tonic-gate valuep->t = UINT64;
17637c478bd9Sstevel@tonic-gate valuep->v = (unsigned long long)val[index];
17647c478bd9Sstevel@tonic-gate break;
17657c478bd9Sstevel@tonic-gate }
17667c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT16_ARRAY: {
17677c478bd9Sstevel@tonic-gate uint16_t *val;
17687c478bd9Sstevel@tonic-gate (void) nvpair_value_uint16_array(nvpair, &val, &nelem);
17697c478bd9Sstevel@tonic-gate if (not_array == 1 || index >= nelem)
17707c478bd9Sstevel@tonic-gate goto invalid;
17717c478bd9Sstevel@tonic-gate valuep->t = UINT64;
17727c478bd9Sstevel@tonic-gate valuep->v = (unsigned long long)val[index];
17737c478bd9Sstevel@tonic-gate break;
17747c478bd9Sstevel@tonic-gate }
17757c478bd9Sstevel@tonic-gate case DATA_TYPE_INT32_ARRAY: {
17767c478bd9Sstevel@tonic-gate int32_t *val;
17777c478bd9Sstevel@tonic-gate (void) nvpair_value_int32_array(nvpair, &val, &nelem);
17787c478bd9Sstevel@tonic-gate if (not_array == 1 || index >= nelem)
17797c478bd9Sstevel@tonic-gate goto invalid;
17807c478bd9Sstevel@tonic-gate valuep->t = UINT64;
17817c478bd9Sstevel@tonic-gate valuep->v = (unsigned long long)val[index];
17827c478bd9Sstevel@tonic-gate break;
17837c478bd9Sstevel@tonic-gate }
17847c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT32_ARRAY: {
17857c478bd9Sstevel@tonic-gate uint32_t *val;
17867c478bd9Sstevel@tonic-gate (void) nvpair_value_uint32_array(nvpair, &val, &nelem);
17877c478bd9Sstevel@tonic-gate if (not_array == 1 || index >= nelem)
17887c478bd9Sstevel@tonic-gate goto invalid;
17897c478bd9Sstevel@tonic-gate valuep->t = UINT64;
17907c478bd9Sstevel@tonic-gate valuep->v = (unsigned long long)val[index];
17917c478bd9Sstevel@tonic-gate break;
17927c478bd9Sstevel@tonic-gate }
17937c478bd9Sstevel@tonic-gate case DATA_TYPE_INT64_ARRAY: {
17947c478bd9Sstevel@tonic-gate int64_t *val;
17957c478bd9Sstevel@tonic-gate (void) nvpair_value_int64_array(nvpair, &val, &nelem);
17967c478bd9Sstevel@tonic-gate if (not_array == 1 || index >= nelem)
17977c478bd9Sstevel@tonic-gate goto invalid;
17987c478bd9Sstevel@tonic-gate valuep->t = UINT64;
17997c478bd9Sstevel@tonic-gate valuep->v = (unsigned long long)val[index];
18007c478bd9Sstevel@tonic-gate break;
18017c478bd9Sstevel@tonic-gate }
18027c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT64_ARRAY: {
18037c478bd9Sstevel@tonic-gate uint64_t *val;
18047c478bd9Sstevel@tonic-gate (void) nvpair_value_uint64_array(nvpair, &val, &nelem);
18057c478bd9Sstevel@tonic-gate if (not_array == 1 || index >= nelem)
18067c478bd9Sstevel@tonic-gate goto invalid;
18077c478bd9Sstevel@tonic-gate valuep->t = UINT64;
18087c478bd9Sstevel@tonic-gate valuep->v = (unsigned long long)val[index];
18097c478bd9Sstevel@tonic-gate break;
18107c478bd9Sstevel@tonic-gate }
18117c478bd9Sstevel@tonic-gate
18127c478bd9Sstevel@tonic-gate default :
18137aec1d6eScindi out(O_ALTFP|O_VERB2,
18147c478bd9Sstevel@tonic-gate "platform_payloadprop: unsupported data type for %s",
18153e8d8e18Sdb propstr);
18167c478bd9Sstevel@tonic-gate return (1);
18177c478bd9Sstevel@tonic-gate }
18187c478bd9Sstevel@tonic-gate
18197c478bd9Sstevel@tonic-gate return (0);
18207c478bd9Sstevel@tonic-gate
18217c478bd9Sstevel@tonic-gate invalid:
18227aec1d6eScindi out(O_ALTFP|O_VERB2,
18237aec1d6eScindi "platform_payloadprop: invalid array reference for %s", propstr);
18247c478bd9Sstevel@tonic-gate return (1);
18257c478bd9Sstevel@tonic-gate }
18267aec1d6eScindi
18277aec1d6eScindi /*ARGSUSED*/
18287aec1d6eScindi int
platform_path_exists(nvlist_t * fmri)18297aec1d6eScindi platform_path_exists(nvlist_t *fmri)
18307aec1d6eScindi {
18317aec1d6eScindi return (fmd_nvl_fmri_present(Hdl, fmri));
18327aec1d6eScindi }
18337aec1d6eScindi
18347aec1d6eScindi struct evalue *
platform_payloadprop_values(const char * propstr,int * nvals)18357aec1d6eScindi platform_payloadprop_values(const char *propstr, int *nvals)
18367aec1d6eScindi {
18377aec1d6eScindi struct evalue *retvals;
18387aec1d6eScindi nvlist_t *basenvp;
18397aec1d6eScindi nvpair_t *nvpair;
18407aec1d6eScindi char *nvpname;
18417aec1d6eScindi
18427aec1d6eScindi *nvals = 0;
18437aec1d6eScindi
18447aec1d6eScindi if (payloadnvp == NULL)
18457aec1d6eScindi return (NULL);
18467aec1d6eScindi
18477aec1d6eScindi basenvp = payloadnvp;
18487aec1d6eScindi
18497aec1d6eScindi /* search for nvpair entry */
18507aec1d6eScindi nvpair = NULL;
18517aec1d6eScindi while ((nvpair = nvlist_next_nvpair(basenvp, nvpair)) != NULL) {
18527aec1d6eScindi nvpname = nvpair_name(nvpair);
18537aec1d6eScindi ASSERT(nvpname != NULL);
18547aec1d6eScindi
18557aec1d6eScindi if (strcmp(propstr, nvpname) == 0)
18567aec1d6eScindi break;
18577aec1d6eScindi }
18587aec1d6eScindi
18597aec1d6eScindi if (nvpair == NULL)
18607aec1d6eScindi return (NULL); /* property not found */
18617aec1d6eScindi
18627aec1d6eScindi switch (nvpair_type(nvpair)) {
18637aec1d6eScindi case DATA_TYPE_NVLIST: {
18647aec1d6eScindi nvlist_t *embnvp = NULL;
18657aec1d6eScindi char *scheme = NULL;
18667aec1d6eScindi
18677aec1d6eScindi (void) nvpair_value_nvlist(nvpair, &embnvp);
18687aec1d6eScindi if (nvlist_lookup_string(embnvp, FM_FMRI_SCHEME,
18697aec1d6eScindi &scheme) == 0) {
18707aec1d6eScindi if (strcmp(scheme, FM_FMRI_SCHEME_HC) == 0) {
18717aec1d6eScindi *nvals = 1;
18727aec1d6eScindi retvals = MALLOC(sizeof (struct evalue));
18737aec1d6eScindi retvals->t = NODEPTR;
18747aec1d6eScindi retvals->v =
187580ab886dSwesolows (uintptr_t)hc_fmri_nodeize(embnvp);
18767aec1d6eScindi return (retvals);
18777aec1d6eScindi }
18787aec1d6eScindi }
18797aec1d6eScindi return (NULL);
18807aec1d6eScindi }
18817aec1d6eScindi case DATA_TYPE_NVLIST_ARRAY: {
18827aec1d6eScindi char *scheme = NULL;
18837aec1d6eScindi nvlist_t **nvap;
18847aec1d6eScindi uint_t nel;
18857aec1d6eScindi int i;
18867aec1d6eScindi int hccount;
18877aec1d6eScindi
18887aec1d6eScindi /*
18897aec1d6eScindi * since we're only willing to handle hc fmri's, we
18907aec1d6eScindi * must count them first before allocating retvals.
18917aec1d6eScindi */
18927aec1d6eScindi if (nvpair_value_nvlist_array(nvpair, &nvap, &nel) != 0)
18937aec1d6eScindi return (NULL);
18947aec1d6eScindi
18957aec1d6eScindi hccount = 0;
18967aec1d6eScindi for (i = 0; i < nel; i++) {
18977aec1d6eScindi if (nvlist_lookup_string(nvap[i], FM_FMRI_SCHEME,
18987aec1d6eScindi &scheme) == 0 &&
18997aec1d6eScindi strcmp(scheme, FM_FMRI_SCHEME_HC) == 0) {
19007aec1d6eScindi hccount++;
19017aec1d6eScindi }
19027aec1d6eScindi }
19037aec1d6eScindi
19047aec1d6eScindi if (hccount == 0)
19057aec1d6eScindi return (NULL);
19067aec1d6eScindi
19077aec1d6eScindi *nvals = hccount;
19087aec1d6eScindi retvals = MALLOC(sizeof (struct evalue) * hccount);
19097aec1d6eScindi
19107aec1d6eScindi hccount = 0;
19117aec1d6eScindi for (i = 0; i < nel; i++) {
19127aec1d6eScindi if (nvlist_lookup_string(nvap[i], FM_FMRI_SCHEME,
19137aec1d6eScindi &scheme) == 0 &&
19147aec1d6eScindi strcmp(scheme, FM_FMRI_SCHEME_HC) == 0) {
19157aec1d6eScindi retvals[hccount].t = NODEPTR;
191680ab886dSwesolows retvals[hccount].v = (uintptr_t)
19177aec1d6eScindi hc_fmri_nodeize(nvap[i]);
19187aec1d6eScindi hccount++;
19197aec1d6eScindi }
19207aec1d6eScindi }
19217aec1d6eScindi return (retvals);
19227aec1d6eScindi }
19237aec1d6eScindi case DATA_TYPE_BOOLEAN:
19247aec1d6eScindi case DATA_TYPE_BOOLEAN_VALUE: {
19257aec1d6eScindi boolean_t val;
19267aec1d6eScindi
19277aec1d6eScindi *nvals = 1;
19287aec1d6eScindi retvals = MALLOC(sizeof (struct evalue));
19297aec1d6eScindi (void) nvpair_value_boolean_value(nvpair, &val);
19307aec1d6eScindi retvals->t = UINT64;
19317aec1d6eScindi retvals->v = (unsigned long long)val;
19327aec1d6eScindi return (retvals);
19337aec1d6eScindi }
19347aec1d6eScindi case DATA_TYPE_BYTE: {
19357aec1d6eScindi uchar_t val;
19367aec1d6eScindi
19377aec1d6eScindi *nvals = 1;
19387aec1d6eScindi retvals = MALLOC(sizeof (struct evalue));
19397aec1d6eScindi (void) nvpair_value_byte(nvpair, &val);
19407aec1d6eScindi retvals->t = UINT64;
19417aec1d6eScindi retvals->v = (unsigned long long)val;
19427aec1d6eScindi return (retvals);
19437aec1d6eScindi }
19447aec1d6eScindi case DATA_TYPE_STRING: {
19457aec1d6eScindi char *val;
19467aec1d6eScindi
19477aec1d6eScindi *nvals = 1;
19487aec1d6eScindi retvals = MALLOC(sizeof (struct evalue));
19497aec1d6eScindi retvals->t = STRING;
19507aec1d6eScindi (void) nvpair_value_string(nvpair, &val);
195180ab886dSwesolows retvals->v = (uintptr_t)stable(val);
19527aec1d6eScindi return (retvals);
19537aec1d6eScindi }
19547aec1d6eScindi
19557aec1d6eScindi case DATA_TYPE_INT8: {
19567aec1d6eScindi int8_t val;
19577aec1d6eScindi
19587aec1d6eScindi *nvals = 1;
19597aec1d6eScindi retvals = MALLOC(sizeof (struct evalue));
19607aec1d6eScindi (void) nvpair_value_int8(nvpair, &val);
19617aec1d6eScindi retvals->t = UINT64;
19627aec1d6eScindi retvals->v = (unsigned long long)val;
19637aec1d6eScindi return (retvals);
19647aec1d6eScindi }
19657aec1d6eScindi case DATA_TYPE_UINT8: {
19667aec1d6eScindi uint8_t val;
19677aec1d6eScindi
19687aec1d6eScindi *nvals = 1;
19697aec1d6eScindi retvals = MALLOC(sizeof (struct evalue));
19707aec1d6eScindi (void) nvpair_value_uint8(nvpair, &val);
19717aec1d6eScindi retvals->t = UINT64;
19727aec1d6eScindi retvals->v = (unsigned long long)val;
19737aec1d6eScindi return (retvals);
19747aec1d6eScindi }
19757aec1d6eScindi
19767aec1d6eScindi case DATA_TYPE_INT16: {
19777aec1d6eScindi int16_t val;
19787aec1d6eScindi
19797aec1d6eScindi *nvals = 1;
19807aec1d6eScindi retvals = MALLOC(sizeof (struct evalue));
19817aec1d6eScindi (void) nvpair_value_int16(nvpair, &val);
19827aec1d6eScindi retvals->t = UINT64;
19837aec1d6eScindi retvals->v = (unsigned long long)val;
19847aec1d6eScindi return (retvals);
19857aec1d6eScindi }
19867aec1d6eScindi case DATA_TYPE_UINT16: {
19877aec1d6eScindi uint16_t val;
19887aec1d6eScindi
19897aec1d6eScindi *nvals = 1;
19907aec1d6eScindi retvals = MALLOC(sizeof (struct evalue));
19917aec1d6eScindi (void) nvpair_value_uint16(nvpair, &val);
19927aec1d6eScindi retvals->t = UINT64;
19937aec1d6eScindi retvals->v = (unsigned long long)val;
19947aec1d6eScindi return (retvals);
19957aec1d6eScindi }
19967aec1d6eScindi
19977aec1d6eScindi case DATA_TYPE_INT32: {
19987aec1d6eScindi int32_t val;
19997aec1d6eScindi
20007aec1d6eScindi *nvals = 1;
20017aec1d6eScindi retvals = MALLOC(sizeof (struct evalue));
20027aec1d6eScindi (void) nvpair_value_int32(nvpair, &val);
20037aec1d6eScindi retvals->t = UINT64;
20047aec1d6eScindi retvals->v = (unsigned long long)val;
20057aec1d6eScindi return (retvals);
20067aec1d6eScindi }
20077aec1d6eScindi case DATA_TYPE_UINT32: {
20087aec1d6eScindi uint32_t val;
20097aec1d6eScindi
20107aec1d6eScindi *nvals = 1;
20117aec1d6eScindi retvals = MALLOC(sizeof (struct evalue));
20127aec1d6eScindi (void) nvpair_value_uint32(nvpair, &val);
20137aec1d6eScindi retvals->t = UINT64;
20147aec1d6eScindi retvals->v = (unsigned long long)val;
20157aec1d6eScindi return (retvals);
20167aec1d6eScindi }
20177aec1d6eScindi
20187aec1d6eScindi case DATA_TYPE_INT64: {
20197aec1d6eScindi int64_t val;
20207aec1d6eScindi
20217aec1d6eScindi *nvals = 1;
20227aec1d6eScindi retvals = MALLOC(sizeof (struct evalue));
20237aec1d6eScindi (void) nvpair_value_int64(nvpair, &val);
20247aec1d6eScindi retvals->t = UINT64;
20257aec1d6eScindi retvals->v = (unsigned long long)val;
20267aec1d6eScindi return (retvals);
20277aec1d6eScindi }
20287aec1d6eScindi case DATA_TYPE_UINT64: {
20297aec1d6eScindi uint64_t val;
20307aec1d6eScindi
20317aec1d6eScindi *nvals = 1;
20327aec1d6eScindi retvals = MALLOC(sizeof (struct evalue));
20337aec1d6eScindi (void) nvpair_value_uint64(nvpair, &val);
20347aec1d6eScindi retvals->t = UINT64;
20357aec1d6eScindi retvals->v = (unsigned long long)val;
20367aec1d6eScindi return (retvals);
20377aec1d6eScindi }
20387aec1d6eScindi
20397aec1d6eScindi case DATA_TYPE_BOOLEAN_ARRAY: {
20407aec1d6eScindi boolean_t *val;
20417aec1d6eScindi uint_t nel;
20427aec1d6eScindi int i;
20437aec1d6eScindi
20447aec1d6eScindi (void) nvpair_value_boolean_array(nvpair, &val, &nel);
20457aec1d6eScindi *nvals = nel;
20467aec1d6eScindi retvals = MALLOC(sizeof (struct evalue) * nel);
20477aec1d6eScindi for (i = 0; i < nel; i++) {
20487aec1d6eScindi retvals[i].t = UINT64;
20497aec1d6eScindi retvals[i].v = (unsigned long long)val[i];
20507aec1d6eScindi }
20517aec1d6eScindi return (retvals);
20527aec1d6eScindi }
20537aec1d6eScindi case DATA_TYPE_BYTE_ARRAY: {
20547aec1d6eScindi uchar_t *val;
20557aec1d6eScindi uint_t nel;
20567aec1d6eScindi int i;
20577aec1d6eScindi
20587aec1d6eScindi (void) nvpair_value_byte_array(nvpair, &val, &nel);
20597aec1d6eScindi *nvals = nel;
20607aec1d6eScindi retvals = MALLOC(sizeof (struct evalue) * nel);
20617aec1d6eScindi for (i = 0; i < nel; i++) {
20627aec1d6eScindi retvals[i].t = UINT64;
20637aec1d6eScindi retvals[i].v = (unsigned long long)val[i];
20647aec1d6eScindi }
20657aec1d6eScindi return (retvals);
20667aec1d6eScindi }
20677aec1d6eScindi case DATA_TYPE_STRING_ARRAY: {
20687aec1d6eScindi char **val;
20697aec1d6eScindi uint_t nel;
20707aec1d6eScindi int i;
20717aec1d6eScindi
20727aec1d6eScindi (void) nvpair_value_string_array(nvpair, &val, &nel);
20737aec1d6eScindi *nvals = nel;
20747aec1d6eScindi retvals = MALLOC(sizeof (struct evalue) * nel);
20757aec1d6eScindi for (i = 0; i < nel; i++) {
20767aec1d6eScindi retvals[i].t = STRING;
207780ab886dSwesolows retvals[i].v = (uintptr_t)stable(val[i]);
20787aec1d6eScindi }
20797aec1d6eScindi return (retvals);
20807aec1d6eScindi }
20817aec1d6eScindi
20827aec1d6eScindi case DATA_TYPE_INT8_ARRAY: {
20837aec1d6eScindi int8_t *val;
20847aec1d6eScindi uint_t nel;
20857aec1d6eScindi int i;
20867aec1d6eScindi
20877aec1d6eScindi (void) nvpair_value_int8_array(nvpair, &val, &nel);
20887aec1d6eScindi *nvals = nel;
20897aec1d6eScindi retvals = MALLOC(sizeof (struct evalue) * nel);
20907aec1d6eScindi for (i = 0; i < nel; i++) {
20917aec1d6eScindi retvals[i].t = UINT64;
20927aec1d6eScindi retvals[i].v = (unsigned long long)val[i];
20937aec1d6eScindi }
20947aec1d6eScindi return (retvals);
20957aec1d6eScindi }
20967aec1d6eScindi case DATA_TYPE_UINT8_ARRAY: {
20977aec1d6eScindi uint8_t *val;
20987aec1d6eScindi uint_t nel;
20997aec1d6eScindi int i;
21007aec1d6eScindi
21017aec1d6eScindi (void) nvpair_value_uint8_array(nvpair, &val, &nel);
21027aec1d6eScindi *nvals = nel;
21037aec1d6eScindi retvals = MALLOC(sizeof (struct evalue) * nel);
21047aec1d6eScindi for (i = 0; i < nel; i++) {
21057aec1d6eScindi retvals[i].t = UINT64;
21067aec1d6eScindi retvals[i].v = (unsigned long long)val[i];
21077aec1d6eScindi }
21087aec1d6eScindi return (retvals);
21097aec1d6eScindi }
21107aec1d6eScindi case DATA_TYPE_INT16_ARRAY: {
21117aec1d6eScindi int16_t *val;
21127aec1d6eScindi uint_t nel;
21137aec1d6eScindi int i;
21147aec1d6eScindi
21157aec1d6eScindi (void) nvpair_value_int16_array(nvpair, &val, &nel);
21167aec1d6eScindi *nvals = nel;
21177aec1d6eScindi retvals = MALLOC(sizeof (struct evalue) * nel);
21187aec1d6eScindi for (i = 0; i < nel; i++) {
21197aec1d6eScindi retvals[i].t = UINT64;
21207aec1d6eScindi retvals[i].v = (unsigned long long)val[i];
21217aec1d6eScindi }
21227aec1d6eScindi return (retvals);
21237aec1d6eScindi }
21247aec1d6eScindi case DATA_TYPE_UINT16_ARRAY: {
21257aec1d6eScindi uint16_t *val;
21267aec1d6eScindi uint_t nel;
21277aec1d6eScindi int i;
21287aec1d6eScindi
21297aec1d6eScindi (void) nvpair_value_uint16_array(nvpair, &val, &nel);
21307aec1d6eScindi *nvals = nel;
21317aec1d6eScindi retvals = MALLOC(sizeof (struct evalue) * nel);
21327aec1d6eScindi for (i = 0; i < nel; i++) {
21337aec1d6eScindi retvals[i].t = UINT64;
21347aec1d6eScindi retvals[i].v = (unsigned long long)val[i];
21357aec1d6eScindi }
21367aec1d6eScindi return (retvals);
21377aec1d6eScindi }
21387aec1d6eScindi case DATA_TYPE_INT32_ARRAY: {
21397aec1d6eScindi int32_t *val;
21407aec1d6eScindi uint_t nel;
21417aec1d6eScindi int i;
21427aec1d6eScindi
21437aec1d6eScindi (void) nvpair_value_int32_array(nvpair, &val, &nel);
21447aec1d6eScindi *nvals = nel;
21457aec1d6eScindi retvals = MALLOC(sizeof (struct evalue) * nel);
21467aec1d6eScindi for (i = 0; i < nel; i++) {
21477aec1d6eScindi retvals[i].t = UINT64;
21487aec1d6eScindi retvals[i].v = (unsigned long long)val[i];
21497aec1d6eScindi }
21507aec1d6eScindi return (retvals);
21517aec1d6eScindi }
21527aec1d6eScindi case DATA_TYPE_UINT32_ARRAY: {
21537aec1d6eScindi uint32_t *val;
21547aec1d6eScindi uint_t nel;
21557aec1d6eScindi int i;
21567aec1d6eScindi
21577aec1d6eScindi (void) nvpair_value_uint32_array(nvpair, &val, &nel);
21587aec1d6eScindi *nvals = nel;
21597aec1d6eScindi retvals = MALLOC(sizeof (struct evalue) * nel);
21607aec1d6eScindi for (i = 0; i < nel; i++) {
21617aec1d6eScindi retvals[i].t = UINT64;
21627aec1d6eScindi retvals[i].v = (unsigned long long)val[i];
21637aec1d6eScindi }
21647aec1d6eScindi return (retvals);
21657aec1d6eScindi }
21667aec1d6eScindi case DATA_TYPE_INT64_ARRAY: {
21677aec1d6eScindi int64_t *val;
21687aec1d6eScindi uint_t nel;
21697aec1d6eScindi int i;
21707aec1d6eScindi
21717aec1d6eScindi (void) nvpair_value_int64_array(nvpair, &val, &nel);
21727aec1d6eScindi *nvals = nel;
21737aec1d6eScindi retvals = MALLOC(sizeof (struct evalue) * nel);
21747aec1d6eScindi for (i = 0; i < nel; i++) {
21757aec1d6eScindi retvals[i].t = UINT64;
21767aec1d6eScindi retvals[i].v = (unsigned long long)val[i];
21777aec1d6eScindi }
21787aec1d6eScindi return (retvals);
21797aec1d6eScindi }
21807aec1d6eScindi case DATA_TYPE_UINT64_ARRAY: {
21817aec1d6eScindi uint64_t *val;
21827aec1d6eScindi uint_t nel;
21837aec1d6eScindi int i;
21847aec1d6eScindi
21857aec1d6eScindi (void) nvpair_value_uint64_array(nvpair, &val, &nel);
21867aec1d6eScindi *nvals = nel;
21877aec1d6eScindi retvals = MALLOC(sizeof (struct evalue) * nel);
21887aec1d6eScindi for (i = 0; i < nel; i++) {
21897aec1d6eScindi retvals[i].t = UINT64;
21907aec1d6eScindi retvals[i].v = (unsigned long long)val[i];
21917aec1d6eScindi }
21927aec1d6eScindi return (retvals);
21937aec1d6eScindi }
21947aec1d6eScindi
21957aec1d6eScindi }
21967aec1d6eScindi
21977aec1d6eScindi return (NULL);
21987aec1d6eScindi }
219908f6c065Sgavinm
220008f6c065Sgavinm /*
220108f6c065Sgavinm * When a list.repaired event is seen the following is called for
220208f6c065Sgavinm * each fault in the associated fault list to convert the given FMRI
220308f6c065Sgavinm * to an instanced path. Only hc scheme is supported.
220408f6c065Sgavinm */
220508f6c065Sgavinm const struct ipath *
platform_fault2ipath(nvlist_t * flt)220608f6c065Sgavinm platform_fault2ipath(nvlist_t *flt)
220708f6c065Sgavinm {
220808f6c065Sgavinm nvlist_t *rsrc;
220908f6c065Sgavinm struct node *np;
221008f6c065Sgavinm char *scheme;
22119dd0f810Scindi const struct ipath *ip;
221208f6c065Sgavinm
221308f6c065Sgavinm if (nvlist_lookup_nvlist(flt, FM_FAULT_RESOURCE, &rsrc) != 0) {
221408f6c065Sgavinm out(O_ALTFP, "platform_fault2ipath: no resource member");
221508f6c065Sgavinm return (NULL);
221608f6c065Sgavinm } else if (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &scheme) != 0) {
221708f6c065Sgavinm out(O_ALTFP, "platform_fault2ipath: no scheme type for rsrc");
221808f6c065Sgavinm return (NULL);
221908f6c065Sgavinm }
222008f6c065Sgavinm
222108f6c065Sgavinm if (strncmp(scheme, FM_FMRI_SCHEME_HC,
222208f6c065Sgavinm sizeof (FM_FMRI_SCHEME_HC) - 1) != 0) {
222308f6c065Sgavinm out(O_ALTFP, "platform_fault2ipath: returning NULL for non-hc "
222408f6c065Sgavinm "scheme %s", scheme);
222508f6c065Sgavinm return (NULL);
222608f6c065Sgavinm }
222708f6c065Sgavinm
222808f6c065Sgavinm if ((np = hc_fmri_nodeize(rsrc)) == NULL)
222908f6c065Sgavinm return (NULL); /* nodeize will already have whinged */
223008f6c065Sgavinm
22319dd0f810Scindi ip = ipath(np);
22329dd0f810Scindi tree_free(np);
22339dd0f810Scindi return (ip);
223408f6c065Sgavinm }
2235