xref: /illumos-gate/usr/src/lib/fm/topo/libtopo/common/svc.c (revision 6a634c9d)
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[] = {
76*f6e214c7SGavin Maltby 	    svc_fmri_prop_get },
7895efa359SEric Schrock 	    TOPO_STABILITY_INTERNAL, svc_fmri_nvl2str },
8095efa359SEric Schrock 	    TOPO_STABILITY_INTERNAL, svc_fmri_str2nvl },
8295efa359SEric Schrock 	    TOPO_STABILITY_INTERNAL, svc_fmri_present },
8595efa359SEric Schrock 	    svc_fmri_replaced },
8895efa359SEric Schrock 	    svc_fmri_service_state },
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
svc_error(topo_mod_t * mod)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 *
svc_get_handle(topo_mod_t * mod)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
svc_init(topo_mod_t * mod,topo_version_t version)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
svc_fini(topo_mod_t * mod)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 *
svc_create_node(topo_mod_t * mod,tnode_t * pnode,char * fmristr)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
svc_enum(topo_mod_t * mod,tnode_t * pnode,const char * name,topo_instance_t min,topo_instance_t max,void * notused1,void * notused2)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
svc_release(topo_mod_t * mod,tnode_t * node)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
svc_component_valid(const char * str)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
svc_fmri_prop_get(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)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