xref: /illumos-gate/usr/src/lib/fm/topo/libtopo/common/svc.c (revision f6e214c7)
195efa359SEric Schrock /*
295efa359SEric Schrock  * CDDL HEADER START
395efa359SEric Schrock  *
495efa359SEric Schrock  * The contents of this file are subject to the terms of the
595efa359SEric Schrock  * Common Development and Distribution License (the "License").
695efa359SEric Schrock  * You may not use this file except in compliance with the License.
795efa359SEric Schrock  *
895efa359SEric Schrock  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
995efa359SEric Schrock  * or http://www.opensolaris.org/os/licensing.
1095efa359SEric Schrock  * See the License for the specific language governing permissions
1195efa359SEric Schrock  * and limitations under the License.
1295efa359SEric Schrock  *
1395efa359SEric Schrock  * When distributing Covered Code, include this CDDL HEADER in each
1495efa359SEric Schrock  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1595efa359SEric Schrock  * If applicable, add the following below this CDDL HEADER, with the
1695efa359SEric Schrock  * fields enclosed by brackets "[]" replaced with your own identifying
1795efa359SEric Schrock  * information: Portions Copyright [yyyy] [name of copyright owner]
1895efa359SEric Schrock  *
1995efa359SEric Schrock  * CDDL HEADER END
2095efa359SEric Schrock  */
2195efa359SEric Schrock 
2295efa359SEric Schrock /*
23*f6e214c7SGavin Maltby  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
2495efa359SEric Schrock  */
2595efa359SEric Schrock 
2695efa359SEric Schrock /*
2795efa359SEric Schrock  * This provides the basic mechanisms (str2nvl and nvl2str) for dealing with
2895efa359SEric Schrock  * the service schema.  The official version of a svc FMRI has the form:
2995efa359SEric Schrock  *
30*f6e214c7SGavin Maltby  *	svc://[scope@][system-fqn]/service[:instance][@contract-id]
3195efa359SEric Schrock  *
3295efa359SEric Schrock  * Where 'service' is a slash-delimited list of names.  Of these fields, the
3395efa359SEric Schrock  * scope, constract-id, and system-fqn are rarely used, leaving the much more
3495efa359SEric Schrock  * common form such as:
3595efa359SEric Schrock  *
36*f6e214c7SGavin Maltby  *	svc:///network/ssh:default
3795efa359SEric Schrock  *
3895efa359SEric Schrock  * Note that the SMF software typically uses a shorthard form, where the
3995efa359SEric Schrock  * authority is elided (svc:/network/ssh:default).  As this module deals with
4095efa359SEric Schrock  * FMA FMRIs, we only support fully specified FMRIs.
4195efa359SEric Schrock  *
4295efa359SEric Schrock  * This module does not support enumeration, but implements methods for FMRI
4395efa359SEric Schrock  * state (present, unusable, service state, and replaced).
4495efa359SEric Schrock  */
4595efa359SEric Schrock 
4695efa359SEric Schrock #include <fm/topo_mod.h>
4795efa359SEric Schrock #include <fm/fmd_fmri.h>
4895efa359SEric Schrock #include <sys/fm/protocol.h>
4995efa359SEric Schrock #include <topo_method.h>
5095efa359SEric Schrock #include <topo_subr.h>
51*f6e214c7SGavin Maltby #include <topo_prop.h>
5295efa359SEric Schrock #include <alloca.h>
5395efa359SEric Schrock #include <assert.h>
5495efa359SEric Schrock #include <svc.h>
5595efa359SEric Schrock #include <strings.h>
5695efa359SEric Schrock #include <libscf.h>
5795efa359SEric Schrock 
5895efa359SEric Schrock static int svc_fmri_nvl2str(topo_mod_t *, tnode_t *, topo_version_t,
5995efa359SEric Schrock     nvlist_t *, nvlist_t **);
6095efa359SEric Schrock static int svc_fmri_str2nvl(topo_mod_t *, tnode_t *, topo_version_t,
6195efa359SEric Schrock     nvlist_t *, nvlist_t **);
6295efa359SEric Schrock static int svc_fmri_present(topo_mod_t *, tnode_t *, topo_version_t,
6395efa359SEric Schrock     nvlist_t *, nvlist_t **);
6495efa359SEric Schrock static int svc_fmri_replaced(topo_mod_t *, tnode_t *, topo_version_t,
6595efa359SEric Schrock     nvlist_t *, nvlist_t **);
6695efa359SEric Schrock static int svc_fmri_service_state(topo_mod_t *, tnode_t *, topo_version_t,
6795efa359SEric Schrock     nvlist_t *, nvlist_t **);
6895efa359SEric Schrock static int svc_fmri_unusable(topo_mod_t *, tnode_t *, topo_version_t,
6995efa359SEric Schrock     nvlist_t *, nvlist_t **);
70*f6e214c7SGavin Maltby static int svc_fmri_prop_get(topo_mod_t *, tnode_t *, topo_version_t,
71*f6e214c7SGavin Maltby     nvlist_t *, nvlist_t **);
7295efa359SEric Schrock 
7395efa359SEric Schrock static const topo_method_t svc_methods[] = {
74*f6e214c7SGavin Maltby 	{ TOPO_METH_PROP_GET, TOPO_METH_PROP_GET_DESC,
75*f6e214c7SGavin Maltby 	    TOPO_METH_PROP_GET_VERSION, TOPO_STABILITY_INTERNAL,
76*f6e214c7SGavin Maltby 	    svc_fmri_prop_get },
7795efa359SEric Schrock 	{ TOPO_METH_NVL2STR, TOPO_METH_NVL2STR_DESC, TOPO_METH_NVL2STR_VERSION,
7895efa359SEric Schrock 	    TOPO_STABILITY_INTERNAL, svc_fmri_nvl2str },
7995efa359SEric Schrock 	{ TOPO_METH_STR2NVL, TOPO_METH_STR2NVL_DESC, TOPO_METH_STR2NVL_VERSION,
8095efa359SEric Schrock 	    TOPO_STABILITY_INTERNAL, svc_fmri_str2nvl },
8195efa359SEric Schrock 	{ TOPO_METH_PRESENT, TOPO_METH_PRESENT_DESC, TOPO_METH_PRESENT_VERSION,
8295efa359SEric Schrock 	    TOPO_STABILITY_INTERNAL, svc_fmri_present },
8395efa359SEric Schrock 	{ TOPO_METH_REPLACED, TOPO_METH_REPLACED_DESC,
8495efa359SEric Schrock 	    TOPO_METH_REPLACED_VERSION, TOPO_STABILITY_INTERNAL,
8595efa359SEric Schrock 	    svc_fmri_replaced },
8695efa359SEric Schrock 	{ TOPO_METH_SERVICE_STATE, TOPO_METH_SERVICE_STATE_DESC,
8795efa359SEric Schrock 	    TOPO_METH_SERVICE_STATE_VERSION, TOPO_STABILITY_INTERNAL,
8895efa359SEric Schrock 	    svc_fmri_service_state },
8995efa359SEric Schrock 	{ TOPO_METH_UNUSABLE, TOPO_METH_UNUSABLE_DESC,
9095efa359SEric Schrock 	    TOPO_METH_UNUSABLE_VERSION, TOPO_STABILITY_INTERNAL,
9195efa359SEric Schrock 	    svc_fmri_unusable },
9295efa359SEric Schrock 	{ NULL }
9395efa359SEric Schrock };
9495efa359SEric Schrock 
95*f6e214c7SGavin Maltby static int svc_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t,
96*f6e214c7SGavin Maltby     topo_instance_t, void *, void *);
97*f6e214c7SGavin Maltby static void svc_release(topo_mod_t *, tnode_t *);
98*f6e214c7SGavin Maltby 
9995efa359SEric Schrock static const topo_modops_t svc_ops =
10095efa359SEric Schrock 	{ svc_enum, svc_release };
10195efa359SEric Schrock static const topo_modinfo_t svc_info =
10295efa359SEric Schrock 	{ "svc", FM_FMRI_SCHEME_SVC, SVC_VERSION, &svc_ops };
10395efa359SEric Schrock 
10495efa359SEric Schrock static int
10595efa359SEric Schrock svc_error(topo_mod_t *mod)
10695efa359SEric Schrock {
10795efa359SEric Schrock 	switch (scf_error()) {
10895efa359SEric Schrock 	case SCF_ERROR_NO_MEMORY:
10995efa359SEric Schrock 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
11095efa359SEric Schrock 
11195efa359SEric Schrock 	default:
11295efa359SEric Schrock 		return (topo_mod_seterrno(mod, EMOD_UNKNOWN));
11395efa359SEric Schrock 	}
11495efa359SEric Schrock }
11595efa359SEric Schrock 
1169f342a5aSEric Schrock static scf_handle_t *
1179f342a5aSEric Schrock svc_get_handle(topo_mod_t *mod)
11895efa359SEric Schrock {
1199f342a5aSEric Schrock 	scf_handle_t *hdl = topo_mod_getspecific(mod);
12095efa359SEric Schrock 
1219f342a5aSEric Schrock 	if (hdl != NULL)
1229f342a5aSEric Schrock 		return (hdl);
12395efa359SEric Schrock 
1249f342a5aSEric Schrock 	if ((hdl = scf_handle_create(SCF_VERSION)) == NULL) {
1259f342a5aSEric Schrock 		(void) svc_error(mod);
1269f342a5aSEric Schrock 		return (NULL);
1279f342a5aSEric Schrock 	}
12895efa359SEric Schrock 
12995efa359SEric Schrock 	if (scf_handle_bind(hdl) != 0) {
13095efa359SEric Schrock 		scf_handle_destroy(hdl);
1319f342a5aSEric Schrock 		(void) svc_error(mod);
1329f342a5aSEric Schrock 		return (NULL);
13395efa359SEric Schrock 	}
13495efa359SEric Schrock 
1359f342a5aSEric Schrock 	topo_mod_setspecific(mod, hdl);
1369f342a5aSEric Schrock 
1379f342a5aSEric Schrock 	return (hdl);
1389f342a5aSEric Schrock }
1399f342a5aSEric Schrock 
1409f342a5aSEric Schrock int
1419f342a5aSEric Schrock svc_init(topo_mod_t *mod, topo_version_t version)
1429f342a5aSEric Schrock {
143*f6e214c7SGavin Maltby 	if (getenv("TOPOSVCDEBUG"))
144*f6e214c7SGavin Maltby 		topo_mod_setdebug(mod);
145*f6e214c7SGavin Maltby 
1469f342a5aSEric Schrock 	if (version != SVC_VERSION)
1479f342a5aSEric Schrock 		return (topo_mod_seterrno(mod, EMOD_VER_NEW));
1489f342a5aSEric Schrock 
14995efa359SEric Schrock 	if (topo_mod_register(mod, &svc_info, TOPO_VERSION) != 0) {
15095efa359SEric Schrock 		topo_mod_dprintf(mod, "failed to register svc_info: "
15195efa359SEric Schrock 		    "%s\n", topo_mod_errmsg(mod));
15295efa359SEric Schrock 		return (-1);
15395efa359SEric Schrock 	}
15495efa359SEric Schrock 
15595efa359SEric Schrock 	return (0);
15695efa359SEric Schrock }
15795efa359SEric Schrock 
15895efa359SEric Schrock void
15995efa359SEric Schrock svc_fini(topo_mod_t *mod)
16095efa359SEric Schrock {
16195efa359SEric Schrock 	scf_handle_t *hdl = topo_mod_getspecific(mod);
16295efa359SEric Schrock 
1639f342a5aSEric Schrock 	if (hdl != NULL)
1649f342a5aSEric Schrock 		scf_handle_destroy(hdl);
16595efa359SEric Schrock 
16695efa359SEric Schrock 	topo_mod_unregister(mod);
16795efa359SEric Schrock }
16895efa359SEric Schrock 
169*f6e214c7SGavin Maltby static tnode_t *
170*f6e214c7SGavin Maltby svc_create_node(topo_mod_t *mod, tnode_t *pnode, char *fmristr)
171*f6e214c7SGavin Maltby {
172*f6e214c7SGavin Maltby 	nvlist_t *fmri;
173*f6e214c7SGavin Maltby 	tnode_t *tn;
174*f6e214c7SGavin Maltby 	char *fixed;
175*f6e214c7SGavin Maltby 	ssize_t len;
176*f6e214c7SGavin Maltby 	int i, j, err;
177*f6e214c7SGavin Maltby 
178*f6e214c7SGavin Maltby 	/*
179*f6e214c7SGavin Maltby 	 * the scf_{x}_to_fmri interfaces return short-hand svc-scheme FMRI's
180*f6e214c7SGavin Maltby 	 * that look like:
181*f6e214c7SGavin Maltby 	 *
182*f6e214c7SGavin Maltby 	 * svc:/service[:instance]
183*f6e214c7SGavin Maltby 	 *
184*f6e214c7SGavin Maltby 	 * But all our other code assumes a proper svc-scheme FMRI, so we
185*f6e214c7SGavin Maltby 	 * correct the fmri string before we try to convert it to an nvlist.
186*f6e214c7SGavin Maltby 	 *
187*f6e214c7SGavin Maltby 	 * The short-hand version is kept as the label and can be used when
188*f6e214c7SGavin Maltby 	 * dealing with the SMF libraries and CLI's.
189*f6e214c7SGavin Maltby 	 */
190*f6e214c7SGavin Maltby 	len = strlen(fmristr) + 1;
191*f6e214c7SGavin Maltby 	if ((fixed = topo_mod_zalloc(mod, len + 1)) == NULL) {
192*f6e214c7SGavin Maltby 		(void) topo_mod_seterrno(mod, EMOD_NOMEM);
193*f6e214c7SGavin Maltby 		topo_mod_dprintf(mod, "topo_mod_zalloc() failed: %s",
194*f6e214c7SGavin Maltby 		    topo_mod_errmsg(mod));
195*f6e214c7SGavin Maltby 		return (NULL);
196*f6e214c7SGavin Maltby 	}
197*f6e214c7SGavin Maltby 	for (i = 0, j = 0; i < len; i++)
198*f6e214c7SGavin Maltby 		if (i == 5)
199*f6e214c7SGavin Maltby 			fixed[i] = '/';
200*f6e214c7SGavin Maltby 		else
201*f6e214c7SGavin Maltby 			fixed[i] = fmristr[j++];
202*f6e214c7SGavin Maltby 	fixed[i] = '\0';
203*f6e214c7SGavin Maltby 
204*f6e214c7SGavin Maltby 	if (topo_mod_str2nvl(mod, fixed, &fmri) < 0) {
205*f6e214c7SGavin Maltby 		topo_mod_dprintf(mod, "topo_mod_str2nvl() failed: %s",
206*f6e214c7SGavin Maltby 		    topo_mod_errmsg(mod));
207*f6e214c7SGavin Maltby 		topo_mod_free(mod, fixed, len + 1);
208*f6e214c7SGavin Maltby 		return (NULL);
209*f6e214c7SGavin Maltby 	}
210*f6e214c7SGavin Maltby 	topo_mod_free(mod, fixed, len + 1);
211*f6e214c7SGavin Maltby 
212*f6e214c7SGavin Maltby 	if (topo_node_range_create(mod, pnode, fmristr, 0, 0) < 0) {
213*f6e214c7SGavin Maltby 		topo_mod_dprintf(mod, "topo_node_range_create() failed: %s",
214*f6e214c7SGavin Maltby 		    topo_mod_errmsg(mod));
215*f6e214c7SGavin Maltby 		nvlist_free(fmri);
216*f6e214c7SGavin Maltby 		return (NULL);
217*f6e214c7SGavin Maltby 	}
218*f6e214c7SGavin Maltby 	if ((tn = topo_node_bind(mod, pnode, fmristr, 0, fmri)) == NULL) {
219*f6e214c7SGavin Maltby 		topo_mod_dprintf(mod, "topo_node_bind() failed: %s",
220*f6e214c7SGavin Maltby 		    topo_mod_errmsg(mod));
221*f6e214c7SGavin Maltby 		nvlist_free(fmri);
222*f6e214c7SGavin Maltby 		return (NULL);
223*f6e214c7SGavin Maltby 	}
224*f6e214c7SGavin Maltby 	nvlist_free(fmri);
225*f6e214c7SGavin Maltby 
226*f6e214c7SGavin Maltby 	if (topo_node_label_set(tn, fmristr, &err) != 0) {
227*f6e214c7SGavin Maltby 		topo_mod_dprintf(mod, "failed to set label: %s\n",
228*f6e214c7SGavin Maltby 		    topo_strerror(err));
229*f6e214c7SGavin Maltby 		return (NULL);
230*f6e214c7SGavin Maltby 	}
231*f6e214c7SGavin Maltby 	(void) topo_method_register(mod, tn, svc_methods);
232*f6e214c7SGavin Maltby 
233*f6e214c7SGavin Maltby 	return (tn);
234*f6e214c7SGavin Maltby }
235*f6e214c7SGavin Maltby 
23695efa359SEric Schrock /*ARGSUSED*/
23795efa359SEric Schrock static int
23895efa359SEric Schrock svc_enum(topo_mod_t *mod, tnode_t *pnode, const char *name,
23995efa359SEric Schrock     topo_instance_t min, topo_instance_t max, void *notused1, void *notused2)
24095efa359SEric Schrock {
241*f6e214c7SGavin Maltby 	scf_handle_t *hdl;
242*f6e214c7SGavin Maltby 	scf_scope_t *sc = NULL;
243*f6e214c7SGavin Maltby 	scf_iter_t *svc_iter = NULL;
244*f6e214c7SGavin Maltby 	scf_iter_t *inst_iter = NULL;
245*f6e214c7SGavin Maltby 	scf_service_t *svc = NULL;
246*f6e214c7SGavin Maltby 	scf_instance_t *inst = NULL;
247*f6e214c7SGavin Maltby 	int ret = -1;
248*f6e214c7SGavin Maltby 	char *sfmri, *ifmri;
249*f6e214c7SGavin Maltby 	ssize_t slen, ilen;
250*f6e214c7SGavin Maltby 	tnode_t *svc_node;
251*f6e214c7SGavin Maltby 
25295efa359SEric Schrock 	(void) topo_method_register(mod, pnode, svc_methods);
253*f6e214c7SGavin Maltby 
254*f6e214c7SGavin Maltby 	if ((hdl = svc_get_handle(mod)) == NULL)
255*f6e214c7SGavin Maltby 		goto out;
256*f6e214c7SGavin Maltby 
257*f6e214c7SGavin Maltby 	if ((sc = scf_scope_create(hdl)) == NULL ||
258*f6e214c7SGavin Maltby 	    (svc = scf_service_create(hdl)) == NULL ||
259*f6e214c7SGavin Maltby 	    (inst = scf_instance_create(hdl)) == NULL ||
260*f6e214c7SGavin Maltby 	    (svc_iter = scf_iter_create(hdl)) == NULL ||
261*f6e214c7SGavin Maltby 	    (inst_iter = scf_iter_create(hdl)) == NULL)
262*f6e214c7SGavin Maltby 		goto out;
263*f6e214c7SGavin Maltby 
264*f6e214c7SGavin Maltby 	if (scf_handle_get_scope(hdl, SCF_SCOPE_LOCAL, sc) != 0)
265*f6e214c7SGavin Maltby 		goto out;
266*f6e214c7SGavin Maltby 
267*f6e214c7SGavin Maltby 	if (scf_iter_scope_services(svc_iter, sc) != 0)
268*f6e214c7SGavin Maltby 		goto out;
269*f6e214c7SGavin Maltby 
270*f6e214c7SGavin Maltby 	while (scf_iter_next_service(svc_iter, svc) == 1) {
271*f6e214c7SGavin Maltby 		if (scf_iter_service_instances(inst_iter, svc) != 0)
272*f6e214c7SGavin Maltby 			continue;
273*f6e214c7SGavin Maltby 
274*f6e214c7SGavin Maltby 		if ((slen = scf_service_to_fmri(svc, NULL, 0)) < 0)
275*f6e214c7SGavin Maltby 			continue;
276*f6e214c7SGavin Maltby 
277*f6e214c7SGavin Maltby 		if ((sfmri = topo_mod_zalloc(mod, slen + 1)) == NULL) {
278*f6e214c7SGavin Maltby 			(void) topo_mod_seterrno(mod, EMOD_NOMEM);
279*f6e214c7SGavin Maltby 			goto out;
280*f6e214c7SGavin Maltby 		}
281*f6e214c7SGavin Maltby 		if (scf_service_to_fmri(svc, sfmri, slen + 1) == -1)
282*f6e214c7SGavin Maltby 			goto out;
283*f6e214c7SGavin Maltby 
284*f6e214c7SGavin Maltby 		if ((svc_node = svc_create_node(mod, pnode, sfmri)) == NULL) {
285*f6e214c7SGavin Maltby 			topo_mod_free(mod, sfmri, slen + 1);
286*f6e214c7SGavin Maltby 			/* topo mod errno set */
287*f6e214c7SGavin Maltby 			goto out;
288*f6e214c7SGavin Maltby 		}
289*f6e214c7SGavin Maltby 
290*f6e214c7SGavin Maltby 		while (scf_iter_next_instance(inst_iter, inst) == 1) {
291*f6e214c7SGavin Maltby 			if ((ilen = scf_instance_to_fmri(inst, NULL, 0)) < 0)
292*f6e214c7SGavin Maltby 				continue;
293*f6e214c7SGavin Maltby 
294*f6e214c7SGavin Maltby 			if ((ifmri = topo_mod_zalloc(mod, ilen + 1))
295*f6e214c7SGavin Maltby 			    == NULL) {
296*f6e214c7SGavin Maltby 				(void) topo_mod_seterrno(mod, EMOD_NOMEM);
297*f6e214c7SGavin Maltby 				topo_mod_free(mod, sfmri, slen + 1);
298*f6e214c7SGavin Maltby 				goto out;
299*f6e214c7SGavin Maltby 			}
300*f6e214c7SGavin Maltby 			if (scf_instance_to_fmri(inst, ifmri, ilen + 1) == -1)
301*f6e214c7SGavin Maltby 				goto out;
302*f6e214c7SGavin Maltby 
303*f6e214c7SGavin Maltby 			if ((svc_node = svc_create_node(mod, svc_node, ifmri))
304*f6e214c7SGavin Maltby 			    == NULL) {
305*f6e214c7SGavin Maltby 				topo_mod_free(mod, sfmri, slen + 1);
306*f6e214c7SGavin Maltby 				topo_mod_free(mod, ifmri, ilen + 1);
307*f6e214c7SGavin Maltby 				/* topo mod errno set */
308*f6e214c7SGavin Maltby 				goto out;
309*f6e214c7SGavin Maltby 			}
310*f6e214c7SGavin Maltby 			topo_mod_free(mod, ifmri, ilen + 1);
311*f6e214c7SGavin Maltby 		}
312*f6e214c7SGavin Maltby 		topo_mod_free(mod, sfmri, slen + 1);
313*f6e214c7SGavin Maltby 	}
314*f6e214c7SGavin Maltby 	ret = 0;
315*f6e214c7SGavin Maltby out:
316*f6e214c7SGavin Maltby 	scf_scope_destroy(sc);
317*f6e214c7SGavin Maltby 	scf_service_destroy(svc);
318*f6e214c7SGavin Maltby 	scf_instance_destroy(inst);
319*f6e214c7SGavin Maltby 	scf_iter_destroy(svc_iter);
320*f6e214c7SGavin Maltby 	scf_iter_destroy(inst_iter);
321*f6e214c7SGavin Maltby 
322*f6e214c7SGavin Maltby 	return (ret);
32395efa359SEric Schrock }
32495efa359SEric Schrock 
32595efa359SEric Schrock static void
32695efa359SEric Schrock svc_release(topo_mod_t *mod, tnode_t *node)
32795efa359SEric Schrock {
32895efa359SEric Schrock 	topo_method_unregister_all(mod, node);
32995efa359SEric Schrock }
33095efa359SEric Schrock 
33195efa359SEric Schrock static boolean_t
33295efa359SEric Schrock svc_component_valid(const char *str)
33395efa359SEric Schrock {
33495efa359SEric Schrock 	if (str == NULL)
33595efa359SEric Schrock 		return (B_TRUE);
33695efa359SEric Schrock 
33795efa359SEric Schrock 	if (*str == '\0')
33895efa359SEric Schrock 		return (B_FALSE);
33995efa359SEric Schrock 
34095efa359SEric Schrock 	if (strpbrk(str, "@/:") != NULL)
34195efa359SEric Schrock 		return (B_FALSE);
34295efa359SEric Schrock 
34395efa359SEric Schrock 	return (B_TRUE);
34495efa359SEric Schrock }
34595efa359SEric Schrock 
346*f6e214c7SGavin Maltby static int
347*f6e214c7SGavin Maltby svc_fmri_prop_get(topo_mod_t *mod, tnode_t *node, topo_version_t version,
348*f6e214c7SGavin Maltby     nvlist_t *in, nvlist_t **out)
349*f6e214c7SGavin Maltby {
350*f6e214c7SGavin Maltby 	char *svc_name, *svc_inst = NULL;
351*f6e214c7SGavin Maltby 	nvlist_t *rsrc, *args;
352*f6e214c7SGavin Maltby 	char *pgroup, *pname;
353*f6e214c7SGavin Maltby 	tnode_t *svc_node;
354*f6e214c7SGavin Maltby 	char *search;
355*f6e214c7SGavin Maltby 	size_t len;
356*f6e214c7SGavin Maltby 	int err;
357*f6e214c7SGavin Maltby 
358*f6e214c7SGavin Maltby 	if (version > TOPO_METH_PROP_GET_VERSION)
359*f6e214c7SGavin Maltby 		return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
360*f6e214c7SGavin Maltby 
361*f6e214c7SGavin Maltby 	err = nvlist_lookup_string(in, TOPO_PROP_GROUP, &pgroup);
362*f6e214c7SGavin Maltby 	err |= nvlist_lookup_string(in, TOPO_PROP_VAL_NAME, &pname);
363*f6e214c7SGavin Maltby 	err |= nvlist_lookup_nvlist(in, TOPO_PROP_RESOURCE, &rsrc);
364*f6e214c7SGavin Maltby 	if (err != 0)
365*f6e214c7SGavin Maltby 		return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
366*f6e214c7SGavin Maltby 
367*f6e214c7SGavin Maltby 	/*
368*f6e214c7SGavin Maltby 	 * Private args to prop method are optional
369*f6e214c7SGavin Maltby 	 */
370*f6e214c7SGavin Maltby 	if ((err = nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &args)) != 0) {
371*f6e214c7SGavin Maltby 		if (err != ENOENT)
372*f6e214c7SGavin Maltby 			return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
373*f6e214c7SGavin Maltby 		else
374*f6e214c7SGavin Maltby 			args = NULL;
375*f6e214c7SGavin Maltby 	}
376*f6e214c7SGavin Maltby 
377*f6e214c7SGavin Maltby 	/*
378*f6e214c7SGavin Maltby 	 * Lookup a topo node named svc:/svc_name[:svc_inst]
379*f6e214c7SGavin Maltby 	 */
380*f6e214c7SGavin Maltby 	if (nvlist_lookup_string(rsrc, FM_FMRI_SVC_NAME, &svc_name) != 0)
381*f6e214c7SGavin Maltby 		return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
382*f6e214c7SGavin Maltby 
383*f6e214c7SGavin Maltby 	(void) nvlist_lookup_string(rsrc, FM_FMRI_SVC_INSTANCE, &svc_inst);
384*f6e214c7SGavin Maltby 
385*f6e214c7SGavin Maltby 	len = 5 + strlen(svc_name) +
386*f6e214c7SGavin Maltby 	    (svc_inst != NULL ? 1 + strlen(svc_inst) : 0) + 1;
387*f6e214c7SGavin Maltby 
388*f6e214c7SGavin Maltby 	if ((search = topo_mod_alloc(mod, len)) == NULL)
389*f6e214c7SGavin Maltby 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
390*f6e214c7SGavin Maltby 
391*f6e214c7SGavin Maltby 	(void) snprintf(search, len, "svc:/%s", svc_name);
392*f6e214c7SGavin Maltby 	svc_node = topo_node_lookup(node, (const char *)search, 0);
393*f6e214c7SGavin Maltby 
394*f6e214c7SGavin Maltby 	if (svc_node == NULL) {
395*f6e214c7SGavin Maltby 		topo_mod_free(mod, search, len);
396*f6e214c7SGavin Maltby 		return (topo_mod_seterrno(mod, EMOD_NODE_NOENT));
397*f6e214c7SGavin Maltby 	}
398*f6e214c7SGavin Maltby 
399*f6e214c7SGavin Maltby 	if (svc_inst != NULL) {
400*f6e214c7SGavin Maltby 		(void) snprintf(search, len, "svc:/%s:%s", svc_name, svc_inst);
401*f6e214c7SGavin Maltby 		svc_node = topo_node_lookup(svc_node, (const char *)search, 0);
402*f6e214c7SGavin Maltby 		if (svc_node == NULL) {
403*f6e214c7SGavin Maltby 			topo_mod_free(mod, search, len);
404*f6e214c7SGavin Maltby 			return (topo_mod_seterrno(mod, EMOD_NODE_NOENT));
405*f6e214c7SGavin Maltby 		}
406*f6e214c7SGavin Maltby 	}
407*f6e214c7SGavin Maltby 
408*f6e214c7SGavin Maltby 	topo_mod_free(mod, search, len);
409*f6e214c7SGavin Maltby 
410*f6e214c7SGavin Maltby 	err = 0;
411*f6e214c7SGavin Maltby 	(void) topo_prop_getprop(svc_node, pgroup, pname, args, out, &err);
412*f6e214c7SGavin Maltby 
413*f6e214c7SGavin Maltby 	return (err);
414*f6e214c7SGavin Maltby }
415*f6e214c7SGavin Maltby 
41695efa359SEric Schrock /*ARGSUSED*/
41795efa359SEric Schrock static int
41895efa359SEric Schrock svc_fmri_nvl2str(topo_mod_t *mod, tnode_t *node, topo_version_t version,
41995efa359SEric Schrock     nvlist_t *nvl, nvlist_t **out)
42095efa359SEric Schrock {
42195efa359SEric Schrock 	uint8_t scheme_version;
42295efa359SEric Schrock 	char *scope = NULL;
42395efa359SEric Schrock 	char *fqn = NULL;
42495efa359SEric Schrock 	char *contract = NULL;
42595efa359SEric Schrock 	char *instance = NULL;
42695efa359SEric Schrock 	char *service;
42795efa359SEric Schrock 	int err;
42895efa359SEric Schrock 	char *buf = NULL;
42995efa359SEric Schrock 	size_t buflen = 0;
43095efa359SEric Schrock 	ssize_t size = 0;
43195efa359SEric Schrock 	nvlist_t *fmristr;
43295efa359SEric Schrock 
43395efa359SEric Schrock 	if (version > TOPO_METH_NVL2STR_VERSION)
43495efa359SEric Schrock 		return (topo_mod_seterrno(mod, EMOD_VER_NEW));
43595efa359SEric Schrock 
43695efa359SEric Schrock 	if (nvlist_lookup_uint8(nvl, FM_VERSION, &scheme_version) != 0 ||
43795efa359SEric Schrock 	    scheme_version > FM_SVC_SCHEME_VERSION)
43895efa359SEric Schrock 		return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
43995efa359SEric Schrock 
44095efa359SEric Schrock 	/*
44195efa359SEric Schrock 	 * Check for optional members.
44295efa359SEric Schrock 	 */
44395efa359SEric Schrock 	err = nvlist_lookup_string(nvl, FM_FMRI_SVC_INSTANCE, &instance);
44495efa359SEric Schrock 	if ((err != 0 && err != ENOENT) || !svc_component_valid(instance))
44595efa359SEric Schrock 		return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
44695efa359SEric Schrock 	err = nvlist_lookup_string(nvl, FM_FMRI_SVC_AUTH_SCOPE, &scope);
44795efa359SEric Schrock 	if ((err != 0 && err != ENOENT) || !svc_component_valid(scope))
44895efa359SEric Schrock 		return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
44995efa359SEric Schrock 	err = nvlist_lookup_string(nvl, FM_FMRI_SVC_AUTH_SYSTEM_FQN, &fqn);
45095efa359SEric Schrock 	if ((err != 0 && err != ENOENT) || !svc_component_valid(scope))
45195efa359SEric Schrock 		return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
45295efa359SEric Schrock 	err = nvlist_lookup_string(nvl, FM_FMRI_SVC_CONTRACT_ID, &contract);
45395efa359SEric Schrock 	if ((err != 0 && err != ENOENT) || !svc_component_valid(contract))
45495efa359SEric Schrock 		return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
45595efa359SEric Schrock 
45695efa359SEric Schrock 	/*
45795efa359SEric Schrock 	 * Get the service name.
45895efa359SEric Schrock 	 */
45995efa359SEric Schrock 	if (nvlist_lookup_string(nvl, FM_FMRI_SVC_NAME, &service) != 0)
46095efa359SEric Schrock 		return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
46195efa359SEric Schrock 
46295efa359SEric Schrock 	/*
46395efa359SEric Schrock 	 * We make two passes through this code.  The first time through we
46495efa359SEric Schrock 	 * calculate the size of buffer that we'll need, and the second time
46595efa359SEric Schrock 	 * through we fill it in.
46695efa359SEric Schrock 	 */
46795efa359SEric Schrock again:
46895efa359SEric Schrock 	/*
46995efa359SEric Schrock 	 * svc://[scope@][system-fqn]
47095efa359SEric Schrock 	 */
47195efa359SEric Schrock 	topo_fmristr_build(&size, buf, buflen, FM_FMRI_SCHEME_SVC,
47295efa359SEric Schrock 	    NULL, "://");
47395efa359SEric Schrock 	topo_fmristr_build(&size, buf, buflen, scope, NULL, "@");
47495efa359SEric Schrock 	topo_fmristr_build(&size, buf, buflen, fqn, NULL, NULL);
47595efa359SEric Schrock 
47695efa359SEric Schrock 	/* svc path */
47795efa359SEric Schrock 	if (*service == '\0')
47895efa359SEric Schrock 		return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
47995efa359SEric Schrock 
48095efa359SEric Schrock 	topo_fmristr_build(&size, buf, buflen, service, "/", NULL);
48195efa359SEric Schrock 
48295efa359SEric Schrock 	/* [:instance][@contract-id] */
48395efa359SEric Schrock 	topo_fmristr_build(&size, buf, buflen, instance, ":", NULL);
48495efa359SEric Schrock 	topo_fmristr_build(&size, buf, buflen, contract, "@", NULL);
48595efa359SEric Schrock 
48695efa359SEric Schrock 	if (buf == NULL) {
48795efa359SEric Schrock 		if ((buf = topo_mod_alloc(mod, size + 1)) == NULL)
48895efa359SEric Schrock 			return (topo_mod_seterrno(mod, EMOD_NOMEM));
48995efa359SEric Schrock 
49095efa359SEric Schrock 		buflen = size + 1;
49195efa359SEric Schrock 		size = 0;
49295efa359SEric Schrock 		goto again;
49395efa359SEric Schrock 	}
49495efa359SEric Schrock 
49595efa359SEric Schrock 	/*
49695efa359SEric Schrock 	 * Construct the nvlist to return as the result.
49795efa359SEric Schrock 	 */
49895efa359SEric Schrock 	if (topo_mod_nvalloc(mod, &fmristr, NV_UNIQUE_NAME) != 0) {
49995efa359SEric Schrock 		topo_mod_strfree(mod, buf);
50095efa359SEric Schrock 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
50195efa359SEric Schrock 	}
50295efa359SEric Schrock 
50395efa359SEric Schrock 	if (nvlist_add_string(fmristr, "fmri-string", buf) != 0) {
50495efa359SEric Schrock 		topo_mod_strfree(mod, buf);
50595efa359SEric Schrock 		nvlist_free(fmristr);
50695efa359SEric Schrock 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
50795efa359SEric Schrock 	}
50895efa359SEric Schrock 	topo_mod_strfree(mod, buf);
50995efa359SEric Schrock 	*out = fmristr;
51095efa359SEric Schrock 
51195efa359SEric Schrock 	return (0);
51295efa359SEric Schrock }
51395efa359SEric Schrock 
51495efa359SEric Schrock /*ARGSUSED*/
51595efa359SEric Schrock static int
51695efa359SEric Schrock svc_fmri_str2nvl(topo_mod_t *mod, tnode_t *node, topo_version_t version,
51795efa359SEric Schrock     nvlist_t *in, nvlist_t **out)
51895efa359SEric Schrock {
51995efa359SEric Schrock 	nvlist_t *fmri;
52095efa359SEric Schrock 	char *str, *loc, val;
52195efa359SEric Schrock 
52295efa359SEric Schrock 	if (version > TOPO_METH_STR2NVL_VERSION)
52395efa359SEric Schrock 		return (topo_mod_seterrno(mod, EMOD_VER_NEW));
52495efa359SEric Schrock 
52595efa359SEric Schrock 	if (nvlist_lookup_string(in, "fmri-string", &str) != 0)
52695efa359SEric Schrock 		return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
52795efa359SEric Schrock 
52895efa359SEric Schrock 	if (strncmp(str, "svc://", 6) != 0)
52995efa359SEric Schrock 		return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM));
53095efa359SEric Schrock 
53195efa359SEric Schrock 	if (topo_mod_nvalloc(mod, &fmri, NV_UNIQUE_NAME) != 0)
53295efa359SEric Schrock 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
53395efa359SEric Schrock 
53495efa359SEric Schrock 	str += 6;
53595efa359SEric Schrock 	if ((loc = strpbrk(str, "@/")) == NULL)
53695efa359SEric Schrock 		goto malformed;
53795efa359SEric Schrock 
53895efa359SEric Schrock 	if (*loc == '@') {
53995efa359SEric Schrock 		/* scope */
54095efa359SEric Schrock 		*loc = '\0';
54195efa359SEric Schrock 		if (!svc_component_valid(str)) {
54295efa359SEric Schrock 			*loc = '@';
54395efa359SEric Schrock 			goto malformed;
54495efa359SEric Schrock 		}
54595efa359SEric Schrock 
54695efa359SEric Schrock 		if (nvlist_add_string(fmri, FM_FMRI_SVC_AUTH_SCOPE, str) != 0) {
54795efa359SEric Schrock 			*loc = '@';
54895efa359SEric Schrock 			goto nomem;
54995efa359SEric Schrock 		}
55095efa359SEric Schrock 
55195efa359SEric Schrock 		*loc = '@';
55295efa359SEric Schrock 		str = loc + 1;
55395efa359SEric Schrock 		if ((loc = strchr(str, '/')) == NULL)
55495efa359SEric Schrock 			goto malformed;
55595efa359SEric Schrock 	}
55695efa359SEric Schrock 
55795efa359SEric Schrock 	if (loc != str) {
55895efa359SEric Schrock 		/* system-fqn */
55995efa359SEric Schrock 		*loc = '\0';
56095efa359SEric Schrock 		if (!svc_component_valid(str)) {
56195efa359SEric Schrock 			*loc = '/';
56295efa359SEric Schrock 			goto malformed;
56395efa359SEric Schrock 		}
56495efa359SEric Schrock 
56595efa359SEric Schrock 		if (nvlist_add_string(fmri, FM_FMRI_SVC_AUTH_SYSTEM_FQN,
56695efa359SEric Schrock 		    str) != 0) {
56795efa359SEric Schrock 			*loc = '/';
56895efa359SEric Schrock 			goto nomem;
56995efa359SEric Schrock 		}
57095efa359SEric Schrock 
57195efa359SEric Schrock 		*loc = '/';
57295efa359SEric Schrock 	}
57395efa359SEric Schrock 
57495efa359SEric Schrock 	str = loc + 1;
57595efa359SEric Schrock 	loc = strpbrk(str, ":@");
57695efa359SEric Schrock 
57795efa359SEric Schrock 	if (str[0] == '\0' || loc == str)
57895efa359SEric Schrock 		goto malformed;
57995efa359SEric Schrock 
58095efa359SEric Schrock 	if (loc != NULL) {
58195efa359SEric Schrock 		val = *loc;
58295efa359SEric Schrock 		*loc = '\0';
58395efa359SEric Schrock 	}
58495efa359SEric Schrock 
58595efa359SEric Schrock 	/* service name */
58695efa359SEric Schrock 	if (nvlist_add_string(fmri, FM_FMRI_SVC_NAME, str) != 0) {
58795efa359SEric Schrock 		if (loc != NULL)
58895efa359SEric Schrock 			*loc = val;
58995efa359SEric Schrock 		goto nomem;
59095efa359SEric Schrock 	}
59195efa359SEric Schrock 
59295efa359SEric Schrock 	if (loc != NULL)
59395efa359SEric Schrock 		*loc = val;
59495efa359SEric Schrock 
59595efa359SEric Schrock 	if (loc != NULL && *loc == ':') {
59695efa359SEric Schrock 		/* instance */
59795efa359SEric Schrock 		str = loc + 1;
59895efa359SEric Schrock 		if (str[0] == '\0' || str[0] == '@')
59995efa359SEric Schrock 			goto malformed;
60095efa359SEric Schrock 
60195efa359SEric Schrock 		loc = strchr(str, '@');
60295efa359SEric Schrock 		if (loc != NULL)
60395efa359SEric Schrock 			*loc = '\0';
60495efa359SEric Schrock 
60595efa359SEric Schrock 		if (nvlist_add_string(fmri, FM_FMRI_SVC_INSTANCE,
60695efa359SEric Schrock 		    str) != 0) {
60795efa359SEric Schrock 			if (loc != NULL)
60895efa359SEric Schrock 				*loc = '@';
60995efa359SEric Schrock 			goto nomem;
61095efa359SEric Schrock 		}
61195efa359SEric Schrock 
61295efa359SEric Schrock 		if (loc != NULL)
61395efa359SEric Schrock 			*loc = '@';
61495efa359SEric Schrock 	}
61595efa359SEric Schrock 
61695efa359SEric Schrock 	if (loc != NULL) {
61795efa359SEric Schrock 		/* contract-id */
61895efa359SEric Schrock 		assert(*loc == '@');
61995efa359SEric Schrock 		str = loc + 1;
62095efa359SEric Schrock 		if (str[0] == '\0')
62195efa359SEric Schrock 			goto malformed;
62295efa359SEric Schrock 
62395efa359SEric Schrock 		if (nvlist_add_string(fmri, FM_FMRI_SVC_CONTRACT_ID,
62495efa359SEric Schrock 		    str) != 0) {
62595efa359SEric Schrock 			goto nomem;
62695efa359SEric Schrock 		}
62795efa359SEric Schrock 	}
62895efa359SEric Schrock 
62995efa359SEric Schrock 	if (nvlist_add_uint8(fmri, FM_VERSION, FM_SVC_SCHEME_VERSION) != 0 ||
63095efa359SEric Schrock 	    nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_SVC) != 0)
63195efa359SEric Schrock 		goto nomem;
63295efa359SEric Schrock 
63395efa359SEric Schrock 	*out = fmri;
63495efa359SEric Schrock 	return (0);
63595efa359SEric Schrock 
63695efa359SEric Schrock malformed:
63795efa359SEric Schrock 	nvlist_free(fmri);
63895efa359SEric Schrock 	return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM));
63995efa359SEric Schrock 
64095efa359SEric Schrock nomem:
64195efa359SEric Schrock 	nvlist_free(fmri);
64295efa359SEric Schrock 	return (topo_mod_seterrno(mod, EMOD_NOMEM));
64395efa359SEric Schrock }
64495efa359SEric Schrock 
64595efa359SEric Schrock /*
646*f6e214c7SGavin Maltby  * This common function is shared by all consumers (present, replaced,
647*f6e214c7SGavin Maltby  * service state and unusable).
648*f6e214c7SGavin Maltby  *
649*f6e214c7SGavin Maltby  *				svc_get_state succeeds
650*f6e214c7SGavin Maltby  * Case				with FMD_SERVICE_STATE_*
651*f6e214c7SGavin Maltby  * ----------------------------	------------------------
652*f6e214c7SGavin Maltby  * svc name deleted		UNKNOWN
653*f6e214c7SGavin Maltby  * svc name not found		UNKNOWN
654*f6e214c7SGavin Maltby  * no fmri instance		OK
655*f6e214c7SGavin Maltby  * instance deleted		UNKNOWN
656*f6e214c7SGavin Maltby  * instance not found		UNKNOWN
657*f6e214c7SGavin Maltby  *
658*f6e214c7SGavin Maltby  * If none of the above apply and this is a call from the "present"
659*f6e214c7SGavin Maltby  * or "replaced" method (presence_only == B_TRUE) then
660*f6e214c7SGavin Maltby  * svc_get_state returns FMD_SERVICE_STATE_OK.
661*f6e214c7SGavin Maltby  *
662*f6e214c7SGavin Maltby  * The "present" method maps a svc_get_state return of UNKNOWN to
663*f6e214c7SGavin Maltby  * "not present" and a svc_get_state return of OK to "present".
664*f6e214c7SGavin Maltby  *
665*f6e214c7SGavin Maltby  * The "replaced" methods maps a return of UNKNOWN to FMD_OBJ_STATE_NOT_PRESENT
666*f6e214c7SGavin Maltby  * and OK to FMD_OBJ_STATE_UNKNOWN.
667*f6e214c7SGavin Maltby  *
668*f6e214c7SGavin Maltby  * For the "service state" and "unusable" methods svc_get_state goes on
669*f6e214c7SGavin Maltby  * to return the instance state as below, and the two methods map that
670*f6e214c7SGavin Maltby  * result as in the last two columns of the following table:
671*f6e214c7SGavin Maltby  *
672*f6e214c7SGavin Maltby  *			svc_get_state succeeds		Service
673*f6e214c7SGavin Maltby  * Instance state	with FMD_SERVICE_STATE_*	State		Unusable
674*f6e214c7SGavin Maltby  * --------------	-------------------------------	---------------	--------
675*f6e214c7SGavin Maltby  * none			OK				OK
676*f6e214c7SGavin Maltby  * uninitialized	OK				OK
677*f6e214c7SGavin Maltby  * maintenance		UNUSABLE			UNUSABLE	Yes
678*f6e214c7SGavin Maltby  * offline		OK				OK
679*f6e214c7SGavin Maltby  * disabled		OK				OK
680*f6e214c7SGavin Maltby  * online		OK				OK
681*f6e214c7SGavin Maltby  * degraded		DEGRADED			DEGRADED
682*f6e214c7SGavin Maltby  * legacy_run		OK (XXX can we see this?)	OK
683*f6e214c7SGavin Maltby  *
684*f6e214c7SGavin Maltby  * Note that *only* "maintenance" state should map to an unusable service state
685*f6e214c7SGavin Maltby  * or unusable status.  That's because a service entering maintenance state
686*f6e214c7SGavin Maltby  * is modelled as a defect fault diagnosis in FMA, but there is no
687*f6e214c7SGavin Maltby  * corresponding isolation action from a response agent since the the service
688*f6e214c7SGavin Maltby  * is already isolated by virtue of being in maintenance state.  Any transition
689*f6e214c7SGavin Maltby  * from maintenance state, even to offline, is considered a repair.  If on
690*f6e214c7SGavin Maltby  * repair fmd does not see the service usable again then the case hangs
691*f6e214c7SGavin Maltby  * around in the "resolved but not all resources back online" state and
692*f6e214c7SGavin Maltby  * further maintenance events for this service will not show up in fmd state
693*f6e214c7SGavin Maltby  * because case duplicate checking code will find the old case.
69495efa359SEric Schrock  */
695*f6e214c7SGavin Maltby 
69695efa359SEric Schrock static int
69795efa359SEric Schrock svc_get_state(topo_mod_t *mod, nvlist_t *fmri, boolean_t presence_only,
69895efa359SEric Schrock     int *ret)
69995efa359SEric Schrock {
7009f342a5aSEric Schrock 	scf_handle_t *hdl;
70195efa359SEric Schrock 	uint8_t fmversion;
70295efa359SEric Schrock 	char *instance, *name;
70395efa359SEric Schrock 	scf_service_t *svc = NULL;
70495efa359SEric Schrock 	scf_scope_t *scope = NULL;
70595efa359SEric Schrock 	scf_instance_t *inst = NULL;
70695efa359SEric Schrock 	scf_property_t *prop = NULL;
70795efa359SEric Schrock 	scf_iter_t *iter = NULL;
70895efa359SEric Schrock 	scf_value_t *val = NULL;
70995efa359SEric Schrock 	scf_propertygroup_t *pg = NULL;
71095efa359SEric Schrock 	int err, retval = 0;
71195efa359SEric Schrock 	ssize_t len;
71295efa359SEric Schrock 	char *state;
71395efa359SEric Schrock 
7149f342a5aSEric Schrock 	if ((hdl = svc_get_handle(mod)) == NULL)
7159f342a5aSEric Schrock 		return (-1);
7169f342a5aSEric Schrock 
71795efa359SEric Schrock 	if (nvlist_lookup_uint8(fmri, FM_VERSION, &fmversion) != 0 ||
71895efa359SEric Schrock 	    fmversion > FM_SVC_SCHEME_VERSION ||
71995efa359SEric Schrock 	    nvlist_lookup_string(fmri, FM_FMRI_SVC_NAME, &name) != 0)
72095efa359SEric Schrock 		return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM));
72195efa359SEric Schrock 
72295efa359SEric Schrock 	if ((svc = scf_service_create(hdl)) == NULL ||
72395efa359SEric Schrock 	    (inst = scf_instance_create(hdl)) == NULL ||
72495efa359SEric Schrock 	    (scope = scf_scope_create(hdl)) == NULL ||
72595efa359SEric Schrock 	    (prop = scf_property_create(hdl)) == NULL ||
72695efa359SEric Schrock 	    (iter = scf_iter_create(hdl)) == NULL ||
72795efa359SEric Schrock 	    (pg = scf_pg_create(hdl)) == NULL ||
72895efa359SEric Schrock 	    (val = scf_value_create(hdl)) == NULL)
72995efa359SEric Schrock 		goto error;
73095efa359SEric Schrock 
73195efa359SEric Schrock 	if (scf_handle_get_scope(hdl, SCF_SCOPE_LOCAL, scope) != 0)
73295efa359SEric Schrock 		goto error;
73395efa359SEric Schrock 
73495efa359SEric Schrock 	/*
73595efa359SEric Schrock 	 * If we fail to get the service due to _DELETED or _NOT_FOUND, then we
73695efa359SEric Schrock 	 * treat this as not present.
73795efa359SEric Schrock 	 */
73895efa359SEric Schrock 	if (scf_scope_get_service(scope, name, svc) != 0) {
73995efa359SEric Schrock 		err = scf_error();
74095efa359SEric Schrock 		if (err == SCF_ERROR_NOT_FOUND || err == SCF_ERROR_DELETED) {
74195efa359SEric Schrock 			*ret = FMD_SERVICE_STATE_UNKNOWN;
74295efa359SEric Schrock 			goto out;
74395efa359SEric Schrock 		} else {
74495efa359SEric Schrock 			goto error;
74595efa359SEric Schrock 		}
74695efa359SEric Schrock 	}
74795efa359SEric Schrock 
74895efa359SEric Schrock 	if (nvlist_lookup_string(fmri, FM_FMRI_SVC_INSTANCE, &instance) != 0) {
74995efa359SEric Schrock 		*ret = FMD_SERVICE_STATE_OK;
75095efa359SEric Schrock 		goto out;
75195efa359SEric Schrock 	}
75295efa359SEric Schrock 
75395efa359SEric Schrock 	/*
75495efa359SEric Schrock 	 * Again, check for _DELETED or _NOT_FOUND.
75595efa359SEric Schrock 	 */
75695efa359SEric Schrock 	if (scf_service_get_instance(svc, instance, inst) != 0) {
75795efa359SEric Schrock 		err = scf_error();
75895efa359SEric Schrock 		if (err == SCF_ERROR_NOT_FOUND || err == SCF_ERROR_DELETED) {
75995efa359SEric Schrock 			*ret = FMD_SERVICE_STATE_UNKNOWN;
76095efa359SEric Schrock 			goto out;
76195efa359SEric Schrock 		} else {
76295efa359SEric Schrock 			goto error;
76395efa359SEric Schrock 		}
76495efa359SEric Schrock 	}
76595efa359SEric Schrock 
76695efa359SEric Schrock 	/*
76795efa359SEric Schrock 	 * For presence, we are done.  Otherwise, we need to get the current
76895efa359SEric Schrock 	 * state of the instance.
76995efa359SEric Schrock 	 */
77095efa359SEric Schrock 	if (presence_only) {
77195efa359SEric Schrock 		*ret = FMD_SERVICE_STATE_OK;
77295efa359SEric Schrock 		goto out;
77395efa359SEric Schrock 	}
77495efa359SEric Schrock 
77595efa359SEric Schrock 	if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != 0 ||
77695efa359SEric Schrock 	    scf_pg_get_property(pg, SCF_PROPERTY_STATE, prop) != 0 ||
77795efa359SEric Schrock 	    scf_iter_property_values(iter, prop) != 0 ||
77895efa359SEric Schrock 	    scf_iter_next_value(iter, val) != 1)
77995efa359SEric Schrock 		goto error;
78095efa359SEric Schrock 
78195efa359SEric Schrock 	if ((len = scf_value_get_astring(val, NULL, 0)) < 0)
78295efa359SEric Schrock 		goto error;
78395efa359SEric Schrock 
78495efa359SEric Schrock 	state = alloca(len + 1);
78595efa359SEric Schrock 	if (scf_value_get_astring(val, state, len + 1) < 0)
78695efa359SEric Schrock 		goto error;
78795efa359SEric Schrock 
788*f6e214c7SGavin Maltby 	if (strcmp(state, SCF_STATE_STRING_MAINT) == 0) {
78995efa359SEric Schrock 		*ret = FMD_SERVICE_STATE_UNUSABLE;
790*f6e214c7SGavin Maltby 	} else if (strcmp(state, SCF_STATE_STRING_DEGRADED) == 0) {
79195efa359SEric Schrock 		*ret = FMD_SERVICE_STATE_DEGRADED;
792*f6e214c7SGavin Maltby 	} else {
79395efa359SEric Schrock 		*ret = FMD_SERVICE_STATE_OK;
794*f6e214c7SGavin Maltby 	}
79595efa359SEric Schrock 	goto out;
79695efa359SEric Schrock 
79795efa359SEric Schrock error:
79895efa359SEric Schrock 	retval = -1;
79995efa359SEric Schrock out:
80095efa359SEric Schrock 	scf_value_destroy(val);
80195efa359SEric Schrock 	scf_pg_destroy(pg);
80295efa359SEric Schrock 	scf_iter_destroy(iter);
80395efa359SEric Schrock 	scf_property_destroy(prop);
80495efa359SEric Schrock 	scf_instance_destroy(inst);
80595efa359SEric Schrock 	scf_scope_destroy(scope);
80695efa359SEric Schrock 	scf_service_destroy(svc);
80795efa359SEric Schrock 	return (retval);
80895efa359SEric Schrock }
80995efa359SEric Schrock 
81095efa359SEric Schrock /*ARGSUSED*/
81195efa359SEric Schrock static int
81295efa359SEric Schrock svc_fmri_present(topo_mod_t *mod, tnode_t *node, topo_version_t version,
81395efa359SEric Schrock     nvlist_t *in, nvlist_t **out)
81495efa359SEric Schrock {
81595efa359SEric Schrock 	int state;
81695efa359SEric Schrock 
81795efa359SEric Schrock 	if (version > TOPO_METH_PRESENT_VERSION)
81895efa359SEric Schrock 		return (topo_mod_seterrno(mod, EMOD_VER_NEW));
81995efa359SEric Schrock 
82095efa359SEric Schrock 	if (svc_get_state(mod, in, B_TRUE, &state) != 0)
82195efa359SEric Schrock 		return (-1);
82295efa359SEric Schrock 
82395efa359SEric Schrock 	if (topo_mod_nvalloc(mod, out, NV_UNIQUE_NAME) != 0)
82495efa359SEric Schrock 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
82595efa359SEric Schrock 	if (nvlist_add_uint32(*out, TOPO_METH_PRESENT_RET,
82695efa359SEric Schrock 	    state != FMD_SERVICE_STATE_UNKNOWN) != 0) {
82795efa359SEric Schrock 		nvlist_free(*out);
82895efa359SEric Schrock 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
82995efa359SEric Schrock 	}
83095efa359SEric Schrock 
83195efa359SEric Schrock 	return (0);
83295efa359SEric Schrock }
83395efa359SEric Schrock 
83495efa359SEric Schrock /*ARGSUSED*/
83595efa359SEric Schrock static int
83695efa359SEric Schrock svc_fmri_replaced(topo_mod_t *mod, tnode_t *node, topo_version_t version,
83795efa359SEric Schrock     nvlist_t *in, nvlist_t **out)
83895efa359SEric Schrock {
83995efa359SEric Schrock 	int state;
84095efa359SEric Schrock 
84195efa359SEric Schrock 	if (version > TOPO_METH_REPLACED_VERSION)
84295efa359SEric Schrock 		return (topo_mod_seterrno(mod, EMOD_VER_NEW));
84395efa359SEric Schrock 
84495efa359SEric Schrock 	if (svc_get_state(mod, in, B_TRUE, &state) != 0)
84595efa359SEric Schrock 		return (-1);
84695efa359SEric Schrock 
84795efa359SEric Schrock 	if (topo_mod_nvalloc(mod, out, NV_UNIQUE_NAME) != 0)
84895efa359SEric Schrock 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
84995efa359SEric Schrock 	if (nvlist_add_uint32(*out, TOPO_METH_REPLACED_RET,
85095efa359SEric Schrock 	    state == FMD_SERVICE_STATE_UNKNOWN ?
85195efa359SEric Schrock 	    FMD_OBJ_STATE_NOT_PRESENT : FMD_OBJ_STATE_UNKNOWN) != 0) {
85295efa359SEric Schrock 		nvlist_free(*out);
85395efa359SEric Schrock 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
85495efa359SEric Schrock 	}
85595efa359SEric Schrock 
85695efa359SEric Schrock 	return (0);
85795efa359SEric Schrock }
85895efa359SEric Schrock 
85995efa359SEric Schrock /*ARGSUSED*/
86095efa359SEric Schrock static int
86195efa359SEric Schrock svc_fmri_service_state(topo_mod_t *mod, tnode_t *node, topo_version_t version,
86295efa359SEric Schrock     nvlist_t *in, nvlist_t **out)
86395efa359SEric Schrock {
86495efa359SEric Schrock 	int state;
86595efa359SEric Schrock 
86695efa359SEric Schrock 	if (version > TOPO_METH_SERVICE_STATE_VERSION)
86795efa359SEric Schrock 		return (topo_mod_seterrno(mod, EMOD_VER_NEW));
86895efa359SEric Schrock 
86995efa359SEric Schrock 	if (svc_get_state(mod, in, B_FALSE, &state) != 0)
87095efa359SEric Schrock 		return (-1);
87195efa359SEric Schrock 
87295efa359SEric Schrock 	if (topo_mod_nvalloc(mod, out, NV_UNIQUE_NAME) != 0)
87395efa359SEric Schrock 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
87495efa359SEric Schrock 	if (nvlist_add_uint32(*out, TOPO_METH_SERVICE_STATE_RET,
87595efa359SEric Schrock 	    state) != 0) {
87695efa359SEric Schrock 		nvlist_free(*out);
87795efa359SEric Schrock 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
87895efa359SEric Schrock 	}
87995efa359SEric Schrock 
88095efa359SEric Schrock 	return (0);
88195efa359SEric Schrock }
88295efa359SEric Schrock 
88395efa359SEric Schrock /*ARGSUSED*/
88495efa359SEric Schrock static int
88595efa359SEric Schrock svc_fmri_unusable(topo_mod_t *mod, tnode_t *node, topo_version_t version,
88695efa359SEric Schrock     nvlist_t *in, nvlist_t **out)
88795efa359SEric Schrock {
88895efa359SEric Schrock 	int state;
88995efa359SEric Schrock 
89095efa359SEric Schrock 	if (version > TOPO_METH_UNUSABLE_VERSION)
89195efa359SEric Schrock 		return (topo_mod_seterrno(mod, EMOD_VER_NEW));
89295efa359SEric Schrock 
89395efa359SEric Schrock 	if (svc_get_state(mod, in, B_FALSE, &state) != 0)
89495efa359SEric Schrock 		return (-1);
89595efa359SEric Schrock 
89695efa359SEric Schrock 	if (topo_mod_nvalloc(mod, out, NV_UNIQUE_NAME) != 0)
89795efa359SEric Schrock 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
89895efa359SEric Schrock 	if (nvlist_add_uint32(*out, TOPO_METH_UNUSABLE_RET,
89995efa359SEric Schrock 	    (state == FMD_SERVICE_STATE_UNKNOWN ||
90095efa359SEric Schrock 	    state == FMD_SERVICE_STATE_UNUSABLE)) != 0) {
90195efa359SEric Schrock 		nvlist_free(*out);
90295efa359SEric Schrock 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
90395efa359SEric Schrock 	}
90495efa359SEric Schrock 
90595efa359SEric Schrock 	return (0);
90695efa359SEric Schrock }
907