xref: /onnv-gate/usr/src/lib/smbsrv/libmlsvc/common/svcctl_scm.c (revision 12508:edb7861a1533)
17961SNatalie.Li@Sun.COM /*
27961SNatalie.Li@Sun.COM  * CDDL HEADER START
37961SNatalie.Li@Sun.COM  *
47961SNatalie.Li@Sun.COM  * The contents of this file are subject to the terms of the
57961SNatalie.Li@Sun.COM  * Common Development and Distribution License (the "License").
67961SNatalie.Li@Sun.COM  * You may not use this file except in compliance with the License.
77961SNatalie.Li@Sun.COM  *
87961SNatalie.Li@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97961SNatalie.Li@Sun.COM  * or http://www.opensolaris.org/os/licensing.
107961SNatalie.Li@Sun.COM  * See the License for the specific language governing permissions
117961SNatalie.Li@Sun.COM  * and limitations under the License.
127961SNatalie.Li@Sun.COM  *
137961SNatalie.Li@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
147961SNatalie.Li@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157961SNatalie.Li@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
167961SNatalie.Li@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
177961SNatalie.Li@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
187961SNatalie.Li@Sun.COM  *
197961SNatalie.Li@Sun.COM  * CDDL HEADER END
207961SNatalie.Li@Sun.COM  */
21*12508Samw@Sun.COM 
227961SNatalie.Li@Sun.COM /*
23*12508Samw@Sun.COM  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
247961SNatalie.Li@Sun.COM  */
257961SNatalie.Li@Sun.COM 
267961SNatalie.Li@Sun.COM /*
277961SNatalie.Li@Sun.COM  * Service Control Manager (SCM) for SVCCTL service.
287961SNatalie.Li@Sun.COM  *
297961SNatalie.Li@Sun.COM  * This routine maintains a list of SMF service and their states. A list
307961SNatalie.Li@Sun.COM  * of Solaris SMF service are displayed on the Server/Connection Manager
317961SNatalie.Li@Sun.COM  * Windows client.
327961SNatalie.Li@Sun.COM  */
337961SNatalie.Li@Sun.COM #include <stdio.h>
347961SNatalie.Li@Sun.COM #include <stdlib.h>
357961SNatalie.Li@Sun.COM #include <stdarg.h>
367961SNatalie.Li@Sun.COM #include <strings.h>
377961SNatalie.Li@Sun.COM #include <assert.h>
387961SNatalie.Li@Sun.COM #include <errno.h>
397961SNatalie.Li@Sun.COM #include <libscf.h>
407961SNatalie.Li@Sun.COM #include <libscf_priv.h>
417961SNatalie.Li@Sun.COM #include <time.h>
4210122SJordan.Brown@Sun.COM #include <dlfcn.h>
437961SNatalie.Li@Sun.COM #include <sys/types.h>
44*12508Samw@Sun.COM 
45*12508Samw@Sun.COM #include <smbsrv/libsmb.h>
46*12508Samw@Sun.COM #include <smbsrv/libmlsvc.h>
4710122SJordan.Brown@Sun.COM #include <smbsrv/winsvc.h>
4810122SJordan.Brown@Sun.COM #include <smbsrv/ndl/svcctl.ndl>
497961SNatalie.Li@Sun.COM 
507961SNatalie.Li@Sun.COM #define	LEGACY_UNKNOWN	"unknown"
517961SNatalie.Li@Sun.COM #define	SVC_NAME_PROP	"name"
527961SNatalie.Li@Sun.COM 
537961SNatalie.Li@Sun.COM /* Flags for svcctl_scm_pg_get_val() */
547961SNatalie.Li@Sun.COM #define	EMPTY_OK	0x01
557961SNatalie.Li@Sun.COM #define	MULTI_OK	0x02
567961SNatalie.Li@Sun.COM 
5710122SJordan.Brown@Sun.COM static void *svcctl_scm_interposer_hdl = NULL;
5810122SJordan.Brown@Sun.COM static struct {
5910122SJordan.Brown@Sun.COM 	int (*svcctl_op_scm_init)(svcctl_manager_context_t *);
6010122SJordan.Brown@Sun.COM 	int (*svcctl_op_scf_init)(svcctl_manager_context_t *);
6110122SJordan.Brown@Sun.COM } svcctl_scm_ops;
6210122SJordan.Brown@Sun.COM 
637961SNatalie.Li@Sun.COM /*
647961SNatalie.Li@Sun.COM  * svcctl_scm_avl_nodecmp
657961SNatalie.Li@Sun.COM  *
667961SNatalie.Li@Sun.COM  * Comparision function for nodes in an AVL tree of services.
677961SNatalie.Li@Sun.COM  */
687961SNatalie.Li@Sun.COM /* ARGSUSED */
697961SNatalie.Li@Sun.COM static int
svcctl_scm_avl_nodecmp(const void * l_arg,const void * r_arg,void * m_name_len)707961SNatalie.Li@Sun.COM svcctl_scm_avl_nodecmp(const void *l_arg, const void *r_arg, void *m_name_len)
717961SNatalie.Li@Sun.COM {
727961SNatalie.Li@Sun.COM 	const svcctl_svc_node_t *l = l_arg;
737961SNatalie.Li@Sun.COM 	const svcctl_svc_node_t *r = r_arg;
747961SNatalie.Li@Sun.COM 	int *max_name_len = m_name_len;
757961SNatalie.Li@Sun.COM 	int ret = 0;
767961SNatalie.Li@Sun.COM 
777961SNatalie.Li@Sun.COM 	ret = strncasecmp(l->sn_name, r->sn_name, *max_name_len);
787961SNatalie.Li@Sun.COM 
797961SNatalie.Li@Sun.COM 	if (ret > 0)
807961SNatalie.Li@Sun.COM 		return (1);
817961SNatalie.Li@Sun.COM 	if (ret < 0)
827961SNatalie.Li@Sun.COM 		return (-1);
837961SNatalie.Li@Sun.COM 	return (0);
847961SNatalie.Li@Sun.COM }
857961SNatalie.Li@Sun.COM 
867961SNatalie.Li@Sun.COM /*
877961SNatalie.Li@Sun.COM  * svcctl_scm_pg_get_val
887961SNatalie.Li@Sun.COM  *
897961SNatalie.Li@Sun.COM  * Get the single value of the named property in the given property group,
907961SNatalie.Li@Sun.COM  * which must have type ty, and put it in *vp.  If ty is SCF_TYPE_ASTRING, vp
917961SNatalie.Li@Sun.COM  * is taken to be a char **, and sz is the size of the buffer.  sz is unused
927961SNatalie.Li@Sun.COM  * otherwise.  Return 0 on success, -1 if the property doesn't exist, has the
937961SNatalie.Li@Sun.COM  * wrong type, or doesn't have a single value.  If flags has EMPTY_OK, don't
947961SNatalie.Li@Sun.COM  * complain if the property has no values (but return nonzero).  If flags has
957961SNatalie.Li@Sun.COM  * MULTI_OK and the property has multiple values, succeed with E2BIG.
967961SNatalie.Li@Sun.COM  */
977961SNatalie.Li@Sun.COM static int
svcctl_scm_pg_get_val(svcctl_manager_context_t * mgr_ctx,scf_propertygroup_t * pg,const char * propname,scf_type_t ty,void * vp,size_t sz,uint_t flags)987961SNatalie.Li@Sun.COM svcctl_scm_pg_get_val(svcctl_manager_context_t *mgr_ctx,
997961SNatalie.Li@Sun.COM     scf_propertygroup_t *pg, const char *propname, scf_type_t ty, void *vp,
1007961SNatalie.Li@Sun.COM     size_t sz, uint_t flags)
1017961SNatalie.Li@Sun.COM {
1027961SNatalie.Li@Sun.COM 	int ret = -1, r;
1037961SNatalie.Li@Sun.COM 	boolean_t multi = B_FALSE;
1047961SNatalie.Li@Sun.COM 
1057961SNatalie.Li@Sun.COM 	assert((flags & ~(EMPTY_OK | MULTI_OK)) == 0);
1067961SNatalie.Li@Sun.COM 
1077961SNatalie.Li@Sun.COM 	if (scf_pg_get_property(pg, propname, mgr_ctx->mc_scf_gprop) == -1)
1087961SNatalie.Li@Sun.COM 		return (ret);
1097961SNatalie.Li@Sun.COM 
1107961SNatalie.Li@Sun.COM 	if (scf_property_is_type(mgr_ctx->mc_scf_gprop, ty) != SCF_SUCCESS)
1117961SNatalie.Li@Sun.COM 		return (ret);
1127961SNatalie.Li@Sun.COM 
1137961SNatalie.Li@Sun.COM 	if (scf_property_get_value(mgr_ctx->mc_scf_gprop,
1147961SNatalie.Li@Sun.COM 	    mgr_ctx->mc_scf_gval) != SCF_SUCCESS) {
1157961SNatalie.Li@Sun.COM 		switch (scf_error()) {
1167961SNatalie.Li@Sun.COM 		case SCF_ERROR_NOT_FOUND:
1177961SNatalie.Li@Sun.COM 			return (ret);
1187961SNatalie.Li@Sun.COM 
1197961SNatalie.Li@Sun.COM 		case SCF_ERROR_CONSTRAINT_VIOLATED:
1207961SNatalie.Li@Sun.COM 			if (flags & MULTI_OK) {
1217961SNatalie.Li@Sun.COM 				multi = B_TRUE;
1227961SNatalie.Li@Sun.COM 				break;
1237961SNatalie.Li@Sun.COM 			}
1247961SNatalie.Li@Sun.COM 			return (ret);
1257961SNatalie.Li@Sun.COM 
1267961SNatalie.Li@Sun.COM 		case SCF_ERROR_PERMISSION_DENIED:
1277961SNatalie.Li@Sun.COM 		default:
1287961SNatalie.Li@Sun.COM 			return (ret);
1297961SNatalie.Li@Sun.COM 		}
1307961SNatalie.Li@Sun.COM 	}
1317961SNatalie.Li@Sun.COM 
1327961SNatalie.Li@Sun.COM 	switch (ty) {
1337961SNatalie.Li@Sun.COM 	case SCF_TYPE_ASTRING:
1347961SNatalie.Li@Sun.COM 		r = scf_value_get_astring
1357961SNatalie.Li@Sun.COM 		    (mgr_ctx->mc_scf_gval, vp, sz) > 0 ? SCF_SUCCESS : -1;
1367961SNatalie.Li@Sun.COM 		break;
1377961SNatalie.Li@Sun.COM 
1387961SNatalie.Li@Sun.COM 	case SCF_TYPE_BOOLEAN:
1397961SNatalie.Li@Sun.COM 		r = scf_value_get_boolean(mgr_ctx->mc_scf_gval, (uint8_t *)vp);
1407961SNatalie.Li@Sun.COM 		break;
1417961SNatalie.Li@Sun.COM 
1427961SNatalie.Li@Sun.COM 	case SCF_TYPE_COUNT:
1437961SNatalie.Li@Sun.COM 		r = scf_value_get_count(mgr_ctx->mc_scf_gval, (uint64_t *)vp);
1447961SNatalie.Li@Sun.COM 		break;
1457961SNatalie.Li@Sun.COM 
1467961SNatalie.Li@Sun.COM 	case SCF_TYPE_INTEGER:
1477961SNatalie.Li@Sun.COM 		r = scf_value_get_integer(mgr_ctx->mc_scf_gval, (int64_t *)vp);
1487961SNatalie.Li@Sun.COM 		break;
1497961SNatalie.Li@Sun.COM 
1507961SNatalie.Li@Sun.COM 	case SCF_TYPE_TIME: {
1517961SNatalie.Li@Sun.COM 		int64_t sec;
1527961SNatalie.Li@Sun.COM 		int32_t ns;
1537961SNatalie.Li@Sun.COM 		r = scf_value_get_time(mgr_ctx->mc_scf_gval, &sec, &ns);
1547961SNatalie.Li@Sun.COM 		((struct timeval *)vp)->tv_sec = sec;
1557961SNatalie.Li@Sun.COM 		((struct timeval *)vp)->tv_usec = ns / 1000;
1567961SNatalie.Li@Sun.COM 		break;
1577961SNatalie.Li@Sun.COM 	}
1587961SNatalie.Li@Sun.COM 
1597961SNatalie.Li@Sun.COM 	case SCF_TYPE_USTRING:
1607961SNatalie.Li@Sun.COM 		r = scf_value_get_ustring(mgr_ctx->mc_scf_gval, vp, sz) > 0 ?
1617961SNatalie.Li@Sun.COM 		    SCF_SUCCESS : -1;
1627961SNatalie.Li@Sun.COM 		break;
1637961SNatalie.Li@Sun.COM 
1647961SNatalie.Li@Sun.COM 	default:
1657961SNatalie.Li@Sun.COM 		return (ret);
1667961SNatalie.Li@Sun.COM 	}
1677961SNatalie.Li@Sun.COM 
1687961SNatalie.Li@Sun.COM 	if (r != SCF_SUCCESS)
1697961SNatalie.Li@Sun.COM 		return (ret);
1707961SNatalie.Li@Sun.COM 
1717961SNatalie.Li@Sun.COM 	ret = multi ? E2BIG : 0;
1727961SNatalie.Li@Sun.COM 
1737961SNatalie.Li@Sun.COM 	return (ret);
1747961SNatalie.Li@Sun.COM }
1757961SNatalie.Li@Sun.COM 
1767961SNatalie.Li@Sun.COM /*
1777961SNatalie.Li@Sun.COM  * svcctl_scm_get_running_snapshot
1787961SNatalie.Li@Sun.COM  *
1797961SNatalie.Li@Sun.COM  * Get running snapshot of a service instance.
1807961SNatalie.Li@Sun.COM  */
1817961SNatalie.Li@Sun.COM static scf_snapshot_t *
svcctl_scm_get_running_snapshot(svcctl_manager_context_t * mgr_ctx,scf_instance_t * inst)1827961SNatalie.Li@Sun.COM svcctl_scm_get_running_snapshot(svcctl_manager_context_t *mgr_ctx,
1837961SNatalie.Li@Sun.COM     scf_instance_t *inst)
1847961SNatalie.Li@Sun.COM {
1857961SNatalie.Li@Sun.COM 	scf_snapshot_t *snap;
1867961SNatalie.Li@Sun.COM 
1877961SNatalie.Li@Sun.COM 	snap = scf_snapshot_create(mgr_ctx->mc_scf_hdl);
1887961SNatalie.Li@Sun.COM 	if (snap == NULL)
1897961SNatalie.Li@Sun.COM 		return (NULL);
1907961SNatalie.Li@Sun.COM 
1917961SNatalie.Li@Sun.COM 	if (scf_instance_get_snapshot(inst, "running", snap) == 0)
1927961SNatalie.Li@Sun.COM 		return (snap);
1937961SNatalie.Li@Sun.COM 
1947961SNatalie.Li@Sun.COM 	if (scf_error() != SCF_ERROR_NOT_FOUND)
1957961SNatalie.Li@Sun.COM 		return (NULL);
1967961SNatalie.Li@Sun.COM 
1977961SNatalie.Li@Sun.COM 	scf_snapshot_destroy(snap);
1987961SNatalie.Li@Sun.COM 	return (NULL);
1997961SNatalie.Li@Sun.COM }
2007961SNatalie.Li@Sun.COM 
2017961SNatalie.Li@Sun.COM /*
2027961SNatalie.Li@Sun.COM  * svcctl_scm_inst_get_val
2037961SNatalie.Li@Sun.COM  *
2047961SNatalie.Li@Sun.COM  * As svcctl_scm_pg_get_val(), except look the property group up in an
2057961SNatalie.Li@Sun.COM  * instance.  If "use_running" is set, and the running snapshot exists,
2067961SNatalie.Li@Sun.COM  * do a composed lookup there.  Otherwise, do an (optionally composed)
2077961SNatalie.Li@Sun.COM  * lookup on the current values.  Note that lookups using snapshots are
2087961SNatalie.Li@Sun.COM  * always composed.
2097961SNatalie.Li@Sun.COM  */
2107961SNatalie.Li@Sun.COM static int
svcctl_scm_inst_get_val(svcctl_manager_context_t * mgr_ctx,scf_instance_t * inst,const char * pgname,const char * propname,scf_type_t ty,void * vp,size_t sz,uint_t flags,int use_running,int composed)2117961SNatalie.Li@Sun.COM svcctl_scm_inst_get_val(svcctl_manager_context_t *mgr_ctx, scf_instance_t *inst,
2127961SNatalie.Li@Sun.COM     const char *pgname, const char *propname, scf_type_t ty, void *vp,
2137961SNatalie.Li@Sun.COM     size_t sz, uint_t flags, int use_running, int composed)
2147961SNatalie.Li@Sun.COM {
2157961SNatalie.Li@Sun.COM 	scf_snapshot_t *snap = NULL;
2167961SNatalie.Li@Sun.COM 	int r;
2177961SNatalie.Li@Sun.COM 
2187961SNatalie.Li@Sun.COM 	if (use_running)
2197961SNatalie.Li@Sun.COM 		snap = svcctl_scm_get_running_snapshot(mgr_ctx, inst);
2207961SNatalie.Li@Sun.COM 	if (composed || use_running)
2217961SNatalie.Li@Sun.COM 		r = scf_instance_get_pg_composed(inst, snap, pgname,
2227961SNatalie.Li@Sun.COM 		    mgr_ctx->mc_scf_gpg);
2237961SNatalie.Li@Sun.COM 	else
2247961SNatalie.Li@Sun.COM 		r = scf_instance_get_pg(inst, pgname, mgr_ctx->mc_scf_gpg);
2257961SNatalie.Li@Sun.COM 	if (snap)
2267961SNatalie.Li@Sun.COM 		scf_snapshot_destroy(snap);
2277961SNatalie.Li@Sun.COM 	if (r == -1)
2287961SNatalie.Li@Sun.COM 		return (-1);
2297961SNatalie.Li@Sun.COM 
2307961SNatalie.Li@Sun.COM 	r = svcctl_scm_pg_get_val(mgr_ctx, mgr_ctx->mc_scf_gpg, propname, ty,
2317961SNatalie.Li@Sun.COM 	    vp, sz, flags);
2327961SNatalie.Li@Sun.COM 
2337961SNatalie.Li@Sun.COM 	return (r);
2347961SNatalie.Li@Sun.COM }
2357961SNatalie.Li@Sun.COM 
2367961SNatalie.Li@Sun.COM /*
2377961SNatalie.Li@Sun.COM  * svcctl_scm_get_restarter_string_prop
2387961SNatalie.Li@Sun.COM  *
2397961SNatalie.Li@Sun.COM  * Get a string property from the restarter property group of the given
2407961SNatalie.Li@Sun.COM  * instance.  Return an empty string on normal problems.
2417961SNatalie.Li@Sun.COM  */
2427961SNatalie.Li@Sun.COM static void
svcctl_scm_get_restarter_string_prop(svcctl_manager_context_t * mgr_ctx,scf_instance_t * inst,const char * pname,char * buf,size_t buf_sz)2437961SNatalie.Li@Sun.COM svcctl_scm_get_restarter_string_prop(svcctl_manager_context_t *mgr_ctx,
2447961SNatalie.Li@Sun.COM     scf_instance_t *inst, const char *pname, char *buf, size_t buf_sz)
2457961SNatalie.Li@Sun.COM {
2467961SNatalie.Li@Sun.COM 	if (svcctl_scm_inst_get_val(mgr_ctx, inst, SCF_PG_RESTARTER, pname,
2477961SNatalie.Li@Sun.COM 	    SCF_TYPE_ASTRING, buf, buf_sz, 0, 0, 1) != 0)
2487961SNatalie.Li@Sun.COM 		*buf = '\0';
2497961SNatalie.Li@Sun.COM }
2507961SNatalie.Li@Sun.COM 
2517961SNatalie.Li@Sun.COM /*
2527961SNatalie.Li@Sun.COM  * svcctl_scm_svc_transitioning
2537961SNatalie.Li@Sun.COM  *
2547961SNatalie.Li@Sun.COM  * Return true if a service instance is transitioning.
2557961SNatalie.Li@Sun.COM  */
2567961SNatalie.Li@Sun.COM static int
svcctl_scm_svc_transitioning(svcctl_manager_context_t * mgr_ctx,scf_instance_t * inst)2577961SNatalie.Li@Sun.COM svcctl_scm_svc_transitioning(svcctl_manager_context_t *mgr_ctx,
2587961SNatalie.Li@Sun.COM     scf_instance_t *inst)
2597961SNatalie.Li@Sun.COM {
2607961SNatalie.Li@Sun.COM 	char nstate_name[MAX_SCF_STATE_STRING_SZ];
2617961SNatalie.Li@Sun.COM 
2627961SNatalie.Li@Sun.COM 	bzero(nstate_name, MAX_SCF_STATE_STRING_SZ);
2637961SNatalie.Li@Sun.COM 	svcctl_scm_get_restarter_string_prop(mgr_ctx, inst,
2647961SNatalie.Li@Sun.COM 	    SCF_PROPERTY_NEXT_STATE, nstate_name, sizeof (nstate_name));
2657961SNatalie.Li@Sun.COM 
2667961SNatalie.Li@Sun.COM 	return ((*nstate_name == '\0'));
2677961SNatalie.Li@Sun.COM }
2687961SNatalie.Li@Sun.COM 
2697961SNatalie.Li@Sun.COM /*
2707961SNatalie.Li@Sun.COM  * svcctl_scm_get_svcstate
2717961SNatalie.Li@Sun.COM  *
2727961SNatalie.Li@Sun.COM  * Gets the state of an SMF service.
2737961SNatalie.Li@Sun.COM  */
2747961SNatalie.Li@Sun.COM static int
svcctl_scm_get_svcstate(svcctl_manager_context_t * mgr_ctx,char ** buf,scf_walkinfo_t * wip)2757961SNatalie.Li@Sun.COM svcctl_scm_get_svcstate(svcctl_manager_context_t *mgr_ctx,
2767961SNatalie.Li@Sun.COM     char **buf, scf_walkinfo_t *wip)
2777961SNatalie.Li@Sun.COM {
2787961SNatalie.Li@Sun.COM 	char *state_name;
2797961SNatalie.Li@Sun.COM 	size_t max_state_size;
2807961SNatalie.Li@Sun.COM 
2817961SNatalie.Li@Sun.COM 	max_state_size = MAX_SCF_STATE_STRING_SZ + 1;
2827961SNatalie.Li@Sun.COM 
2837961SNatalie.Li@Sun.COM 	if ((state_name = malloc(max_state_size)) == NULL)
2847961SNatalie.Li@Sun.COM 		return (-1);
2857961SNatalie.Li@Sun.COM 
2867961SNatalie.Li@Sun.COM 	if (wip->pg == NULL) {
2877961SNatalie.Li@Sun.COM 		svcctl_scm_get_restarter_string_prop(mgr_ctx, wip->inst,
2887961SNatalie.Li@Sun.COM 		    SCF_PROPERTY_STATE, state_name, max_state_size);
2897961SNatalie.Li@Sun.COM 
2907961SNatalie.Li@Sun.COM 		/* Don't print blank fields, to ease parsing. */
2917961SNatalie.Li@Sun.COM 		if (state_name[0] == '\0') {
2927961SNatalie.Li@Sun.COM 			state_name[0] = '-';
2937961SNatalie.Li@Sun.COM 			state_name[1] = '\0';
2947961SNatalie.Li@Sun.COM 		}
2957961SNatalie.Li@Sun.COM 
2967961SNatalie.Li@Sun.COM 		if (svcctl_scm_svc_transitioning(mgr_ctx, wip->inst))
2977961SNatalie.Li@Sun.COM 			/* Append an asterisk if new state is valid. */
2987961SNatalie.Li@Sun.COM 			(void) strlcat(state_name, "*", max_state_size);
2997961SNatalie.Li@Sun.COM 
3007961SNatalie.Li@Sun.COM 	} else
3017961SNatalie.Li@Sun.COM 		(void) strlcpy(state_name, SCF_STATE_STRING_LEGACY,
3027961SNatalie.Li@Sun.COM 		    max_state_size);
3037961SNatalie.Li@Sun.COM 
3047961SNatalie.Li@Sun.COM 	*buf = state_name;
3057961SNatalie.Li@Sun.COM 	return (0);
3067961SNatalie.Li@Sun.COM }
3077961SNatalie.Li@Sun.COM 
3087961SNatalie.Li@Sun.COM /*
3097961SNatalie.Li@Sun.COM  * svcctl_scm_get_svcdesc
3107961SNatalie.Li@Sun.COM  *
3117961SNatalie.Li@Sun.COM  * Gets the description of an SMF service.
3127961SNatalie.Li@Sun.COM  */
3137961SNatalie.Li@Sun.COM static int
svcctl_scm_get_svcdesc(svcctl_manager_context_t * mgr_ctx,char ** buf,scf_walkinfo_t * wip)3147961SNatalie.Li@Sun.COM svcctl_scm_get_svcdesc(svcctl_manager_context_t *mgr_ctx,
3157961SNatalie.Li@Sun.COM     char **buf, scf_walkinfo_t *wip)
3167961SNatalie.Li@Sun.COM {
3177961SNatalie.Li@Sun.COM 	char *x;
3187961SNatalie.Li@Sun.COM 	size_t newsize;
3197961SNatalie.Li@Sun.COM 	char *newbuf;
3207961SNatalie.Li@Sun.COM 	char *desc_buf = NULL;
3217961SNatalie.Li@Sun.COM 
3227961SNatalie.Li@Sun.COM 	if ((desc_buf = malloc(mgr_ctx->mc_scf_max_value_len + 1)) == NULL)
3237961SNatalie.Li@Sun.COM 		return (-1);
3247961SNatalie.Li@Sun.COM 
3257961SNatalie.Li@Sun.COM 	bzero(desc_buf, mgr_ctx->mc_scf_max_value_len + 1);
3267961SNatalie.Li@Sun.COM 	if (wip->pg != NULL)
3277961SNatalie.Li@Sun.COM 		desc_buf[0] = '-';
3287961SNatalie.Li@Sun.COM 	else if (svcctl_scm_inst_get_val(mgr_ctx, wip->inst,
3297961SNatalie.Li@Sun.COM 	    SCF_PG_TM_COMMON_NAME, "C", SCF_TYPE_USTRING, desc_buf,
3307961SNatalie.Li@Sun.COM 	    mgr_ctx->mc_scf_max_value_len, 0, 1, 1) == -1)
3317961SNatalie.Li@Sun.COM 		desc_buf[0] = '-';
3327961SNatalie.Li@Sun.COM 
3337961SNatalie.Li@Sun.COM 	/*
3347961SNatalie.Li@Sun.COM 	 * Collapse multi-line tm_common_name values into a single line.
3357961SNatalie.Li@Sun.COM 	 */
3367961SNatalie.Li@Sun.COM 	for (x = desc_buf; *x != '\0'; x++)
3377961SNatalie.Li@Sun.COM 		if (*x == '\n')
3387961SNatalie.Li@Sun.COM 			*x = ' ';
3397961SNatalie.Li@Sun.COM 
3407961SNatalie.Li@Sun.COM 	newsize = strlen(desc_buf) + 1;
3417961SNatalie.Li@Sun.COM 	if ((newbuf = malloc(newsize)) == NULL) {
3427961SNatalie.Li@Sun.COM 		free(desc_buf);
3437961SNatalie.Li@Sun.COM 		return (-1);
3447961SNatalie.Li@Sun.COM 	}
3457961SNatalie.Li@Sun.COM 
3467961SNatalie.Li@Sun.COM 	(void) snprintf(newbuf, newsize, "%s", desc_buf);
3477961SNatalie.Li@Sun.COM 	free(desc_buf);
3487961SNatalie.Li@Sun.COM 
3497961SNatalie.Li@Sun.COM 	*buf = newbuf;
3507961SNatalie.Li@Sun.COM 	return (0);
3517961SNatalie.Li@Sun.COM }
3527961SNatalie.Li@Sun.COM 
3537961SNatalie.Li@Sun.COM /*
3547961SNatalie.Li@Sun.COM  * svcctl_scm_get_svcfmri
3557961SNatalie.Li@Sun.COM  *
3567961SNatalie.Li@Sun.COM  * Gets the FMRI of an SMF service.
3577961SNatalie.Li@Sun.COM  */
3587961SNatalie.Li@Sun.COM static int
svcctl_scm_get_svcfmri(svcctl_manager_context_t * mgr_ctx,char ** buf,scf_walkinfo_t * wip)3597961SNatalie.Li@Sun.COM svcctl_scm_get_svcfmri(svcctl_manager_context_t *mgr_ctx,
3607961SNatalie.Li@Sun.COM     char **buf, scf_walkinfo_t *wip)
3617961SNatalie.Li@Sun.COM {
3627961SNatalie.Li@Sun.COM 	size_t newsize;
3637961SNatalie.Li@Sun.COM 	char *newbuf;
3647961SNatalie.Li@Sun.COM 	char *fmri_buf = NULL;
3657961SNatalie.Li@Sun.COM 	void *fmri_p = NULL;
3667961SNatalie.Li@Sun.COM 	size_t fmri_size;
3677961SNatalie.Li@Sun.COM 
3687961SNatalie.Li@Sun.COM 	if ((fmri_buf = malloc(mgr_ctx->mc_scf_max_fmri_len + 1)) == NULL)
3697961SNatalie.Li@Sun.COM 		return (-1);
3707961SNatalie.Li@Sun.COM 
3717961SNatalie.Li@Sun.COM 	if (wip->pg == NULL) {
3727961SNatalie.Li@Sun.COM 		if (scf_instance_to_fmri(wip->inst, fmri_buf,
3737961SNatalie.Li@Sun.COM 		    mgr_ctx->mc_scf_max_fmri_len + 1) == -1) {
3747961SNatalie.Li@Sun.COM 			free(fmri_buf);
3757961SNatalie.Li@Sun.COM 			return (-1);
3767961SNatalie.Li@Sun.COM 		}
3777961SNatalie.Li@Sun.COM 	} else {
3787961SNatalie.Li@Sun.COM 		(void) strlcpy(fmri_buf, SCF_FMRI_LEGACY_PREFIX,
3797961SNatalie.Li@Sun.COM 		    mgr_ctx->mc_scf_max_fmri_len + 1);
3807961SNatalie.Li@Sun.COM 
3817961SNatalie.Li@Sun.COM 		fmri_p = fmri_buf + sizeof (SCF_FMRI_LEGACY_PREFIX) - 1;
3827961SNatalie.Li@Sun.COM 		fmri_size = mgr_ctx->mc_scf_max_fmri_len + 1 - \
3837961SNatalie.Li@Sun.COM 		    (sizeof (SCF_FMRI_LEGACY_PREFIX) - 1);
3847961SNatalie.Li@Sun.COM 
3857961SNatalie.Li@Sun.COM 		if (svcctl_scm_pg_get_val(mgr_ctx, wip->pg,
3867961SNatalie.Li@Sun.COM 		    SCF_LEGACY_PROPERTY_NAME, SCF_TYPE_ASTRING,
3877961SNatalie.Li@Sun.COM 		    fmri_p, fmri_size, 0) != 0)
3887961SNatalie.Li@Sun.COM 			(void) strlcat(fmri_buf, LEGACY_UNKNOWN,
3897961SNatalie.Li@Sun.COM 			    mgr_ctx->mc_scf_max_fmri_len + 1);
3907961SNatalie.Li@Sun.COM 	}
3917961SNatalie.Li@Sun.COM 
3927961SNatalie.Li@Sun.COM 	newsize = strlen(fmri_buf) + 1;
3937961SNatalie.Li@Sun.COM 	if ((newbuf = malloc(newsize)) == NULL) {
3947961SNatalie.Li@Sun.COM 		free(fmri_buf);
3957961SNatalie.Li@Sun.COM 		return (-1);
3967961SNatalie.Li@Sun.COM 	}
3977961SNatalie.Li@Sun.COM 
3987961SNatalie.Li@Sun.COM 	(void) snprintf(newbuf, newsize, "%s", fmri_buf);
3997961SNatalie.Li@Sun.COM 	free(fmri_buf);
4007961SNatalie.Li@Sun.COM 
4017961SNatalie.Li@Sun.COM 	*buf = newbuf;
4027961SNatalie.Li@Sun.COM 	return (0);
4037961SNatalie.Li@Sun.COM }
4047961SNatalie.Li@Sun.COM 
4057961SNatalie.Li@Sun.COM /*
4067961SNatalie.Li@Sun.COM  * svcctl_scm_get_svcname
4077961SNatalie.Li@Sun.COM  *
4087961SNatalie.Li@Sun.COM  * Gets the FMRI of an SMF service.
4097961SNatalie.Li@Sun.COM  */
4107961SNatalie.Li@Sun.COM static int
svcctl_scm_get_svcname(char ** buf,char * fmri)4117961SNatalie.Li@Sun.COM svcctl_scm_get_svcname(char **buf, char *fmri)
4127961SNatalie.Li@Sun.COM {
4137961SNatalie.Li@Sun.COM 	char *nm_buf = NULL;
4147961SNatalie.Li@Sun.COM 	char *newbuf;
4157961SNatalie.Li@Sun.COM 	size_t newsize;
4167961SNatalie.Li@Sun.COM 
4177961SNatalie.Li@Sun.COM 	if (fmri == NULL)
4187961SNatalie.Li@Sun.COM 		return (-1);
4197961SNatalie.Li@Sun.COM 
4207961SNatalie.Li@Sun.COM 	newsize = strlen(fmri);
4217961SNatalie.Li@Sun.COM 	if ((newbuf = malloc(newsize)) == NULL)
4227961SNatalie.Li@Sun.COM 		return (-1);
4237961SNatalie.Li@Sun.COM 
4247961SNatalie.Li@Sun.COM 	if ((nm_buf = strchr(fmri, '/')) == NULL)
4257961SNatalie.Li@Sun.COM 		return (-1);
4267961SNatalie.Li@Sun.COM 
4277961SNatalie.Li@Sun.COM 	(void) snprintf(newbuf, newsize, "%s", ++nm_buf);
4287961SNatalie.Li@Sun.COM 	*buf = newbuf;
4297961SNatalie.Li@Sun.COM 	return (0);
4307961SNatalie.Li@Sun.COM }
4317961SNatalie.Li@Sun.COM 
4327961SNatalie.Li@Sun.COM /*
4337961SNatalie.Li@Sun.COM  * svcctl_scm_cb_list_svcinst
4347961SNatalie.Li@Sun.COM  *
4357961SNatalie.Li@Sun.COM  * Callback function to walk all the services in an SCF repository.
4367961SNatalie.Li@Sun.COM  */
4377961SNatalie.Li@Sun.COM static int
svcctl_scm_cb_list_svcinst(void * context,scf_walkinfo_t * wip)4387961SNatalie.Li@Sun.COM svcctl_scm_cb_list_svcinst(void *context, scf_walkinfo_t *wip)
4397961SNatalie.Li@Sun.COM {
4407961SNatalie.Li@Sun.COM 	svcctl_svc_node_t *node = NULL;
4417961SNatalie.Li@Sun.COM 	uu_avl_index_t idx;
4427961SNatalie.Li@Sun.COM 	svcctl_manager_context_t *mgr_ctx = (svcctl_manager_context_t *)context;
4437961SNatalie.Li@Sun.COM 
4447961SNatalie.Li@Sun.COM 	node = malloc(sizeof (*node));
4457961SNatalie.Li@Sun.COM 	if (node == NULL)
4467961SNatalie.Li@Sun.COM 		return (-1);
4477961SNatalie.Li@Sun.COM 
4487961SNatalie.Li@Sun.COM 	node->sn_fmri = NULL;
4497961SNatalie.Li@Sun.COM 	if (svcctl_scm_get_svcfmri(mgr_ctx, &node->sn_fmri, wip) != 0)
4507961SNatalie.Li@Sun.COM 		return (-1);
4517961SNatalie.Li@Sun.COM 
4527961SNatalie.Li@Sun.COM 	node->sn_name = NULL;
4537961SNatalie.Li@Sun.COM 	if (svcctl_scm_get_svcname(&node->sn_name, node->sn_fmri) != 0)
4547961SNatalie.Li@Sun.COM 		return (-1);
4557961SNatalie.Li@Sun.COM 
4567961SNatalie.Li@Sun.COM 	node->sn_desc = NULL;
4577961SNatalie.Li@Sun.COM 	if (svcctl_scm_get_svcdesc(mgr_ctx, &node->sn_desc, wip) != 0)
4587961SNatalie.Li@Sun.COM 		return (-1);
4597961SNatalie.Li@Sun.COM 
4607961SNatalie.Li@Sun.COM 	node->sn_state = NULL;
4617961SNatalie.Li@Sun.COM 	if (svcctl_scm_get_svcstate(mgr_ctx, &node->sn_state, wip) != 0)
4627961SNatalie.Li@Sun.COM 		return (-1);
4637961SNatalie.Li@Sun.COM 
4647961SNatalie.Li@Sun.COM 	/* Insert into AVL tree. */
4657961SNatalie.Li@Sun.COM 	uu_avl_node_init(node, &node->sn_node, mgr_ctx->mc_svcs_pool);
4667961SNatalie.Li@Sun.COM 	(void) uu_avl_find(mgr_ctx->mc_svcs, node,
4677961SNatalie.Li@Sun.COM 	    &mgr_ctx->mc_scf_max_fmri_len, &idx);
4687961SNatalie.Li@Sun.COM 	uu_avl_insert(mgr_ctx->mc_svcs, node, idx);
4697961SNatalie.Li@Sun.COM 
4707961SNatalie.Li@Sun.COM 	return (0);
4717961SNatalie.Li@Sun.COM }
4727961SNatalie.Li@Sun.COM 
4737961SNatalie.Li@Sun.COM /*
4747961SNatalie.Li@Sun.COM  * svcctl_scm_map_status
4757961SNatalie.Li@Sun.COM  *
4767961SNatalie.Li@Sun.COM  * Report the service status.
4777961SNatalie.Li@Sun.COM  *
4787961SNatalie.Li@Sun.COM  * The mapping between the Microsoft service states and SMF service states
4797961SNatalie.Li@Sun.COM  * are as follows.
4807961SNatalie.Li@Sun.COM  *
4817961SNatalie.Li@Sun.COM  * SMF service states
4827961SNatalie.Li@Sun.COM  * ==================
4837961SNatalie.Li@Sun.COM  *	SCF_STATE_UNINIT                0x00000001
4847961SNatalie.Li@Sun.COM  *	SCF_STATE_MAINT                 0x00000002
4857961SNatalie.Li@Sun.COM  *	SCF_STATE_OFFLINE               0x00000004
4867961SNatalie.Li@Sun.COM  *	SCF_STATE_DISABLED              0x00000008
4877961SNatalie.Li@Sun.COM  *	SCF_STATE_ONLINE                0x00000010
4887961SNatalie.Li@Sun.COM  *	SCF_STATE_DEGRADED              0x00000020
4897961SNatalie.Li@Sun.COM  *	SCF_STATE_ALL                   0x0000003F
4907961SNatalie.Li@Sun.COM  *
4917961SNatalie.Li@Sun.COM  * Microsoft service states
4927961SNatalie.Li@Sun.COM  * ========================
4937961SNatalie.Li@Sun.COM  *	SERVICE_CONTINUE_PENDING	0x00000005
4947961SNatalie.Li@Sun.COM  *	SERVICE_PAUSE_PENDING		0x00000006
4957961SNatalie.Li@Sun.COM  *	SERVICE_PAUSED			0x00000007
4967961SNatalie.Li@Sun.COM  *	SERVICE_RUNNING			0x00000004
4977961SNatalie.Li@Sun.COM  *	SERVICE_START_PENDING		0x00000002
4987961SNatalie.Li@Sun.COM  *	SERVICE_STOP_PENDING		0x00000003
4997961SNatalie.Li@Sun.COM  *	SERVICE_STOPPED			0x00000001
5007961SNatalie.Li@Sun.COM  *
5017961SNatalie.Li@Sun.COM  * Mapping
5027961SNatalie.Li@Sun.COM  * =======
5037961SNatalie.Li@Sun.COM  *
5047961SNatalie.Li@Sun.COM  *	SCF_STATE_ONLINE	<->	SERVICE_RUNNING
5057961SNatalie.Li@Sun.COM  *	SCF_STATE_OFFLINE	<->	SERVICE_PAUSED
5067961SNatalie.Li@Sun.COM  *	SCF_STATE_DISABLED	<->	SERVICE_STOPPED
5077961SNatalie.Li@Sun.COM  *	SCF_STATE_UNINIT	<->	SERVICE_START_PENDING
5087961SNatalie.Li@Sun.COM  *	SCF_STATE_DEGRADED	<->	SERVICE_STOP_PENDING
5097961SNatalie.Li@Sun.COM  *	SCF_STATE_MAINT		<->	SERVICE_PAUSE_PENDING
5107961SNatalie.Li@Sun.COM  *	SCF_STATE_STRING_LEGACY <->	SERVICE_RUNNING
5117961SNatalie.Li@Sun.COM  *	Service Transitioning	<->	SERVICE_STOP_PENDING
5127961SNatalie.Li@Sun.COM  */
5137961SNatalie.Li@Sun.COM uint32_t
svcctl_scm_map_status(const char * state)5147961SNatalie.Li@Sun.COM svcctl_scm_map_status(const char *state)
5157961SNatalie.Li@Sun.COM {
5167961SNatalie.Li@Sun.COM 	int i;
5177961SNatalie.Li@Sun.COM 
5187961SNatalie.Li@Sun.COM 	struct {
5197961SNatalie.Li@Sun.COM 		const char	*scf_state;
5207961SNatalie.Li@Sun.COM 		uint32_t	scm_state;
5217961SNatalie.Li@Sun.COM 	} state_map[] = {
5227961SNatalie.Li@Sun.COM 		{ SCF_STATE_STRING_ONLINE,	SERVICE_RUNNING },
5237961SNatalie.Li@Sun.COM 		{ SCF_STATE_STRING_OFFLINE,	SERVICE_PAUSED },
5247961SNatalie.Li@Sun.COM 		{ SCF_STATE_STRING_DISABLED,	SERVICE_STOPPED },
5257961SNatalie.Li@Sun.COM 		{ SCF_STATE_STRING_UNINIT,	SERVICE_START_PENDING },
5267961SNatalie.Li@Sun.COM 		{ SCF_STATE_STRING_DEGRADED,	SERVICE_STOP_PENDING },
5277961SNatalie.Li@Sun.COM 		{ SCF_STATE_STRING_MAINT,	SERVICE_PAUSE_PENDING },
5287961SNatalie.Li@Sun.COM 		{ SCF_STATE_STRING_LEGACY,	SERVICE_RUNNING }
5297961SNatalie.Li@Sun.COM 	};
5307961SNatalie.Li@Sun.COM 
5317961SNatalie.Li@Sun.COM 	for (i = 0; i < (sizeof (state_map)/sizeof (state_map[0])); ++i) {
5327961SNatalie.Li@Sun.COM 		if (strcmp(state, state_map[i].scf_state) == 0)
5337961SNatalie.Li@Sun.COM 			return (state_map[i].scm_state);
5347961SNatalie.Li@Sun.COM 	}
5357961SNatalie.Li@Sun.COM 
5367961SNatalie.Li@Sun.COM 	if (strrchr(state, '*') != 0)	/* State Transitioning */
5377961SNatalie.Li@Sun.COM 		return (SERVICE_STOP_PENDING);
5387961SNatalie.Li@Sun.COM 
5397961SNatalie.Li@Sun.COM 	return (SERVICE_RUNNING);
5407961SNatalie.Li@Sun.COM }
5417961SNatalie.Li@Sun.COM 
5427961SNatalie.Li@Sun.COM /*
5437961SNatalie.Li@Sun.COM  * svcctl_scm_enum_services
5447961SNatalie.Li@Sun.COM  *
54510001SJoyce.McIntosh@Sun.COM  * Enumerates SMF services: handles wide-char or ascii requests.
54610001SJoyce.McIntosh@Sun.COM  *
54710001SJoyce.McIntosh@Sun.COM  * Returns the number of services written to buf.
5487961SNatalie.Li@Sun.COM  */
54910001SJoyce.McIntosh@Sun.COM uint32_t
svcctl_scm_enum_services(svcctl_manager_context_t * mgr_ctx,uint8_t * buf,size_t buflen,uint32_t * resume_handle,boolean_t use_wchar)55010001SJoyce.McIntosh@Sun.COM svcctl_scm_enum_services(svcctl_manager_context_t *mgr_ctx, uint8_t *buf,
55110001SJoyce.McIntosh@Sun.COM     size_t buflen, uint32_t *resume_handle, boolean_t use_wchar)
5527961SNatalie.Li@Sun.COM {
55310001SJoyce.McIntosh@Sun.COM 	svcctl_svc_node_t *node;
55410001SJoyce.McIntosh@Sun.COM 	int base_offset, offset;
55510966SJordan.Brown@Sun.COM 	smb_wchar_t *w_name;
55610001SJoyce.McIntosh@Sun.COM 	char *a_name;
55710001SJoyce.McIntosh@Sun.COM 	char *node_name;
55810001SJoyce.McIntosh@Sun.COM 	size_t namelen;
55910001SJoyce.McIntosh@Sun.COM 	uint32_t numsvcs = mgr_ctx->mc_scf_numsvcs;
56010001SJoyce.McIntosh@Sun.COM 	uint32_t ns;
56110001SJoyce.McIntosh@Sun.COM 	/*LINTED E_BAD_PTR_CAST_ALIGN*/
56210001SJoyce.McIntosh@Sun.COM 	svc_enum_status_t *svc = (svc_enum_status_t *)buf;
5637961SNatalie.Li@Sun.COM 
56410001SJoyce.McIntosh@Sun.COM 	if (buf == NULL || buflen == 0 || *resume_handle >= numsvcs) {
56510001SJoyce.McIntosh@Sun.COM 		*resume_handle = 0;
56610001SJoyce.McIntosh@Sun.COM 		return (0);
56710001SJoyce.McIntosh@Sun.COM 	}
5687961SNatalie.Li@Sun.COM 
56910001SJoyce.McIntosh@Sun.COM 	base_offset = numsvcs * sizeof (svc_enum_status_t);
57010001SJoyce.McIntosh@Sun.COM 	if (buflen < mgr_ctx->mc_bytes_needed) {
57110001SJoyce.McIntosh@Sun.COM 		while (base_offset > (buflen / 4)) {
57210001SJoyce.McIntosh@Sun.COM 			--numsvcs;
57310001SJoyce.McIntosh@Sun.COM 			base_offset = numsvcs * sizeof (svc_enum_status_t);
57410001SJoyce.McIntosh@Sun.COM 		}
57510001SJoyce.McIntosh@Sun.COM 	}
5767961SNatalie.Li@Sun.COM 
57710504SKeyur.Desai@Sun.COM 	offset = buflen;
5787961SNatalie.Li@Sun.COM 	node = uu_avl_first(mgr_ctx->mc_svcs);
5797961SNatalie.Li@Sun.COM 
58010001SJoyce.McIntosh@Sun.COM 	for (ns = 0; ((ns < *resume_handle) && (node != NULL)); ++ns)
58110001SJoyce.McIntosh@Sun.COM 		node = uu_avl_next(mgr_ctx->mc_svcs, node);
58210001SJoyce.McIntosh@Sun.COM 
58310001SJoyce.McIntosh@Sun.COM 	if (node == NULL) {
58410001SJoyce.McIntosh@Sun.COM 		*resume_handle = 0;
58510001SJoyce.McIntosh@Sun.COM 		return (0);
58610001SJoyce.McIntosh@Sun.COM 	}
58710001SJoyce.McIntosh@Sun.COM 
58810001SJoyce.McIntosh@Sun.COM 	for (ns = 0; ((ns < numsvcs) && (node != NULL)); ++ns) {
58910001SJoyce.McIntosh@Sun.COM 		node_name = node->sn_name;
59010001SJoyce.McIntosh@Sun.COM 		namelen = strlen(node_name) + 1;
59110001SJoyce.McIntosh@Sun.COM 		if (use_wchar) {
59210504SKeyur.Desai@Sun.COM 			offset -= SVCCTL_WNSTRLEN(node_name);
59310001SJoyce.McIntosh@Sun.COM 			/*LINTED E_BAD_PTR_CAST_ALIGN*/
59410966SJordan.Brown@Sun.COM 			w_name = (smb_wchar_t *)&buf[offset];
59510966SJordan.Brown@Sun.COM 			(void) smb_mbstowcs(w_name, node_name, namelen);
59610001SJoyce.McIntosh@Sun.COM 		} else {
59710504SKeyur.Desai@Sun.COM 			offset -= namelen;
59810001SJoyce.McIntosh@Sun.COM 			a_name = (char *)&buf[offset];
59910001SJoyce.McIntosh@Sun.COM 			(void) strlcpy(a_name, node_name, namelen);
60010001SJoyce.McIntosh@Sun.COM 		}
60110504SKeyur.Desai@Sun.COM 		svc[ns].svc_name = offset;
60210001SJoyce.McIntosh@Sun.COM 
60310504SKeyur.Desai@Sun.COM 		if (offset <= base_offset)
60410001SJoyce.McIntosh@Sun.COM 			break;
6057961SNatalie.Li@Sun.COM 
60610001SJoyce.McIntosh@Sun.COM 		node_name = node->sn_fmri;
60710001SJoyce.McIntosh@Sun.COM 		namelen = strlen(node_name) + 1;
60810001SJoyce.McIntosh@Sun.COM 		if (use_wchar) {
60910504SKeyur.Desai@Sun.COM 			offset -= SVCCTL_WNSTRLEN(node_name);
61010001SJoyce.McIntosh@Sun.COM 			/*LINTED E_BAD_PTR_CAST_ALIGN*/
61110966SJordan.Brown@Sun.COM 			w_name = (smb_wchar_t *)&buf[offset];
61210966SJordan.Brown@Sun.COM 			(void) smb_mbstowcs(w_name, node_name, namelen);
61310001SJoyce.McIntosh@Sun.COM 		} else {
61410504SKeyur.Desai@Sun.COM 			offset -= namelen;
61510001SJoyce.McIntosh@Sun.COM 			a_name = (char *)&buf[offset];
61610001SJoyce.McIntosh@Sun.COM 			(void) strlcpy(a_name, node_name, namelen);
61710001SJoyce.McIntosh@Sun.COM 		}
61810504SKeyur.Desai@Sun.COM 		svc[ns].display_name = offset;
61910001SJoyce.McIntosh@Sun.COM 
62010504SKeyur.Desai@Sun.COM 		if (offset <= base_offset)
62110001SJoyce.McIntosh@Sun.COM 			break;
62210001SJoyce.McIntosh@Sun.COM 
62310001SJoyce.McIntosh@Sun.COM 		svc[ns].svc_status.cur_state =
6247961SNatalie.Li@Sun.COM 		    svcctl_scm_map_status(node->sn_state);
62510001SJoyce.McIntosh@Sun.COM 		svc[ns].svc_status.service_type = SERVICE_WIN32_SHARE_PROCESS;
62610001SJoyce.McIntosh@Sun.COM 		svc[ns].svc_status.ctrl_accepted = 0;
62710001SJoyce.McIntosh@Sun.COM 		svc[ns].svc_status.w32_exitcode = 0;
62810001SJoyce.McIntosh@Sun.COM 		svc[ns].svc_status.svc_specified_exitcode = 0;
62910001SJoyce.McIntosh@Sun.COM 		svc[ns].svc_status.check_point = 0;
63010001SJoyce.McIntosh@Sun.COM 		svc[ns].svc_status.wait_hint = 0;
6317961SNatalie.Li@Sun.COM 
6327961SNatalie.Li@Sun.COM 		node = uu_avl_next(mgr_ctx->mc_svcs, node);
6337961SNatalie.Li@Sun.COM 	}
63410001SJoyce.McIntosh@Sun.COM 
63510001SJoyce.McIntosh@Sun.COM 	if (node == NULL) {
63610001SJoyce.McIntosh@Sun.COM 		*resume_handle = 0;
63710001SJoyce.McIntosh@Sun.COM 	} else {
63810001SJoyce.McIntosh@Sun.COM 		*resume_handle += ns;
63910001SJoyce.McIntosh@Sun.COM 
64010001SJoyce.McIntosh@Sun.COM 		if (*resume_handle >= mgr_ctx->mc_scf_numsvcs)
64110001SJoyce.McIntosh@Sun.COM 			*resume_handle = 0;
64210001SJoyce.McIntosh@Sun.COM 	}
64310001SJoyce.McIntosh@Sun.COM 
64410001SJoyce.McIntosh@Sun.COM 	return (ns);
6457961SNatalie.Li@Sun.COM }
6467961SNatalie.Li@Sun.COM 
6477961SNatalie.Li@Sun.COM /*
6487961SNatalie.Li@Sun.COM  * svcctl_scm_cb_bytes_needed
6497961SNatalie.Li@Sun.COM  *
6507961SNatalie.Li@Sun.COM  * Callback function to calculate bytes needed to enumerate SMF services.
6517961SNatalie.Li@Sun.COM  */
6527961SNatalie.Li@Sun.COM static int
svcctl_scm_cb_bytes_needed(void * svc_node,void * byte_cnt)6537961SNatalie.Li@Sun.COM svcctl_scm_cb_bytes_needed(void *svc_node, void *byte_cnt)
6547961SNatalie.Li@Sun.COM {
6557961SNatalie.Li@Sun.COM 	svcctl_svc_node_t *node = svc_node;
6567961SNatalie.Li@Sun.COM 	int *cnt = byte_cnt;
6577961SNatalie.Li@Sun.COM 
65810966SJordan.Brown@Sun.COM 	*cnt += (strlen(node->sn_fmri) + 1) * sizeof (smb_wchar_t);
65910966SJordan.Brown@Sun.COM 	*cnt += (strlen(node->sn_name) + 1) * sizeof (smb_wchar_t);
6607961SNatalie.Li@Sun.COM 
6617961SNatalie.Li@Sun.COM 	return (UU_WALK_NEXT);
6627961SNatalie.Li@Sun.COM }
6637961SNatalie.Li@Sun.COM 
6647961SNatalie.Li@Sun.COM /*
6657961SNatalie.Li@Sun.COM  * svcctl_scm_bytes_needed
6667961SNatalie.Li@Sun.COM  *
6677961SNatalie.Li@Sun.COM  * Calculates bytes needed to enumerate SMF services.
6687961SNatalie.Li@Sun.COM  */
66910122SJordan.Brown@Sun.COM static void
svcctl_scm_bytes_needed(svcctl_manager_context_t * mgr_ctx)6707961SNatalie.Li@Sun.COM svcctl_scm_bytes_needed(svcctl_manager_context_t *mgr_ctx)
6717961SNatalie.Li@Sun.COM {
6727961SNatalie.Li@Sun.COM 	int bytes_needed = 0, svc_enum_status_size = 0;
6737961SNatalie.Li@Sun.COM 
6747961SNatalie.Li@Sun.COM 	(void) uu_avl_walk(mgr_ctx->mc_svcs, svcctl_scm_cb_bytes_needed,
6757961SNatalie.Li@Sun.COM 	    &bytes_needed, 0);
6767961SNatalie.Li@Sun.COM 
6777961SNatalie.Li@Sun.COM 	svc_enum_status_size =
6787961SNatalie.Li@Sun.COM 	    mgr_ctx->mc_scf_numsvcs * sizeof (svc_enum_status_t);
6797961SNatalie.Li@Sun.COM 	bytes_needed += svc_enum_status_size;
6807961SNatalie.Li@Sun.COM 
6817961SNatalie.Li@Sun.COM 	mgr_ctx->mc_bytes_needed = bytes_needed;
6827961SNatalie.Li@Sun.COM }
6837961SNatalie.Li@Sun.COM 
6847961SNatalie.Li@Sun.COM /*
6857961SNatalie.Li@Sun.COM  * svcctl_scm_validate_service
6867961SNatalie.Li@Sun.COM  *
6877961SNatalie.Li@Sun.COM  * Check to see whether or not a service is supported.
6887961SNatalie.Li@Sun.COM  *
6897961SNatalie.Li@Sun.COM  * Returns:
6907961SNatalie.Li@Sun.COM  *	ERROR_SUCCESS
6917961SNatalie.Li@Sun.COM  *	ERROR_SERVICE_DOES_NOT_EXIST
6927961SNatalie.Li@Sun.COM  */
6937961SNatalie.Li@Sun.COM uint32_t
svcctl_scm_validate_service(svcctl_manager_context_t * mgr_ctx,char * svc_name)6947961SNatalie.Li@Sun.COM svcctl_scm_validate_service(svcctl_manager_context_t *mgr_ctx, char *svc_name)
6957961SNatalie.Li@Sun.COM {
6968474SJose.Borrego@Sun.COM 	if (svcctl_scm_find_service(mgr_ctx, svc_name) != NULL)
6977961SNatalie.Li@Sun.COM 		return (ERROR_SUCCESS);
6987961SNatalie.Li@Sun.COM 
6997961SNatalie.Li@Sun.COM 	return (ERROR_SERVICE_DOES_NOT_EXIST);
7007961SNatalie.Li@Sun.COM }
7017961SNatalie.Li@Sun.COM 
7027961SNatalie.Li@Sun.COM /*
7038474SJose.Borrego@Sun.COM  * svcctl_scm_map_windows_svc
7048474SJose.Borrego@Sun.COM  *
7058474SJose.Borrego@Sun.COM  * Windows client send windows service name. This method maps windows
7068474SJose.Borrego@Sun.COM  * service names to Solaris service names.
7078474SJose.Borrego@Sun.COM  */
7088474SJose.Borrego@Sun.COM static char *
svcctl_scm_map_windows_svc(char * svc_name)7098474SJose.Borrego@Sun.COM svcctl_scm_map_windows_svc(char *svc_name)
7108474SJose.Borrego@Sun.COM {
7118474SJose.Borrego@Sun.COM 	int i, size = 0;
7128474SJose.Borrego@Sun.COM 	struct {
7138474SJose.Borrego@Sun.COM 		char *win_svc_name;
7148474SJose.Borrego@Sun.COM 		char *solaris_svc_name;
7158474SJose.Borrego@Sun.COM 	} win2solaris_svc_map[] = {
71610001SJoyce.McIntosh@Sun.COM 		{ "eventlog", "system/system-log:default" },
71710001SJoyce.McIntosh@Sun.COM 		{ "RemoteRegistry", "system/svc/restarter:default" },
71810001SJoyce.McIntosh@Sun.COM 		{ "spooler",  "application/print/ppd-cache-update:default" }
7198474SJose.Borrego@Sun.COM 	};
7208474SJose.Borrego@Sun.COM 
7218474SJose.Borrego@Sun.COM 	size = sizeof (win2solaris_svc_map)/sizeof (win2solaris_svc_map[0]);
7228474SJose.Borrego@Sun.COM 	for (i = 0; i < size; ++i) {
7238474SJose.Borrego@Sun.COM 		if (strcasecmp(svc_name,
7248474SJose.Borrego@Sun.COM 		    win2solaris_svc_map[i].win_svc_name) == 0)
7258474SJose.Borrego@Sun.COM 			return (win2solaris_svc_map[i].solaris_svc_name);
7268474SJose.Borrego@Sun.COM 	}
7278474SJose.Borrego@Sun.COM 
7288474SJose.Borrego@Sun.COM 	return (NULL);
7298474SJose.Borrego@Sun.COM }
7308474SJose.Borrego@Sun.COM 
7318474SJose.Borrego@Sun.COM /*
7327961SNatalie.Li@Sun.COM  * svcctl_scm_find_service
7337961SNatalie.Li@Sun.COM  *
7347961SNatalie.Li@Sun.COM  * Lookup a service.
7357961SNatalie.Li@Sun.COM  */
7367961SNatalie.Li@Sun.COM svcctl_svc_node_t *
svcctl_scm_find_service(svcctl_manager_context_t * mgr_ctx,char * svc_name)7377961SNatalie.Li@Sun.COM svcctl_scm_find_service(svcctl_manager_context_t *mgr_ctx, char *svc_name)
7387961SNatalie.Li@Sun.COM {
7397961SNatalie.Li@Sun.COM 	svcctl_svc_node_t node;
7407961SNatalie.Li@Sun.COM 	uu_avl_index_t idx;
7417961SNatalie.Li@Sun.COM 	svcctl_svc_node_t *f_node = NULL;
7427961SNatalie.Li@Sun.COM 
7437961SNatalie.Li@Sun.COM 	if (svc_name == NULL)
7447961SNatalie.Li@Sun.COM 		return (NULL);
7457961SNatalie.Li@Sun.COM 
7467961SNatalie.Li@Sun.COM 	bzero(&node, sizeof (svcctl_svc_node_t));
7477961SNatalie.Li@Sun.COM 	node.sn_name = svc_name;
7487961SNatalie.Li@Sun.COM 	f_node = uu_avl_find(mgr_ctx->mc_svcs, &node,
7497961SNatalie.Li@Sun.COM 	    &mgr_ctx->mc_scf_max_fmri_len, &idx);
7507961SNatalie.Li@Sun.COM 	if (f_node != NULL)
7517961SNatalie.Li@Sun.COM 		return (f_node);
7527961SNatalie.Li@Sun.COM 
7538474SJose.Borrego@Sun.COM 	bzero(&node, sizeof (svcctl_svc_node_t));
7548474SJose.Borrego@Sun.COM 	node.sn_name = svcctl_scm_map_windows_svc(svc_name);
7558474SJose.Borrego@Sun.COM 	if (node.sn_name != NULL)
7568474SJose.Borrego@Sun.COM 		f_node = uu_avl_find(mgr_ctx->mc_svcs, &node,
7578474SJose.Borrego@Sun.COM 		    &mgr_ctx->mc_scf_max_fmri_len, &idx);
7588474SJose.Borrego@Sun.COM 
7598474SJose.Borrego@Sun.COM 	return (f_node);
7607961SNatalie.Li@Sun.COM }
7617961SNatalie.Li@Sun.COM 
7627961SNatalie.Li@Sun.COM /*
7637961SNatalie.Li@Sun.COM  * svcctl_scm_refresh
7647961SNatalie.Li@Sun.COM  *
7657961SNatalie.Li@Sun.COM  * Refresh SCM services per context.
7667961SNatalie.Li@Sun.COM  */
7677961SNatalie.Li@Sun.COM int
svcctl_scm_refresh(svcctl_manager_context_t * mgr_ctx)7687961SNatalie.Li@Sun.COM svcctl_scm_refresh(svcctl_manager_context_t *mgr_ctx)
7697961SNatalie.Li@Sun.COM {
7707961SNatalie.Li@Sun.COM 	svcctl_scm_fini(mgr_ctx);
77110122SJordan.Brown@Sun.COM 
77210122SJordan.Brown@Sun.COM 	if (svcctl_scm_ops.svcctl_op_scm_init != NULL)
77310122SJordan.Brown@Sun.COM 		return (svcctl_scm_ops.svcctl_op_scm_init(mgr_ctx));
77410122SJordan.Brown@Sun.COM 
7757961SNatalie.Li@Sun.COM 	return (svcctl_scm_init(mgr_ctx));
7767961SNatalie.Li@Sun.COM }
7777961SNatalie.Li@Sun.COM 
7787961SNatalie.Li@Sun.COM /*
7797961SNatalie.Li@Sun.COM  * svcctl_scm_scf_handle_init
7807961SNatalie.Li@Sun.COM  *
7817961SNatalie.Li@Sun.COM  * Initialize SCF handle per context.
7827961SNatalie.Li@Sun.COM  */
7837961SNatalie.Li@Sun.COM int
svcctl_scm_scf_handle_init(svcctl_manager_context_t * mgr_ctx)7847961SNatalie.Li@Sun.COM svcctl_scm_scf_handle_init(svcctl_manager_context_t *mgr_ctx)
7857961SNatalie.Li@Sun.COM {
78610122SJordan.Brown@Sun.COM 	if (svcctl_scm_ops.svcctl_op_scf_init != NULL)
78710122SJordan.Brown@Sun.COM 		return (svcctl_scm_ops.
78810122SJordan.Brown@Sun.COM 		    svcctl_op_scf_init(mgr_ctx));
78910122SJordan.Brown@Sun.COM 
7907961SNatalie.Li@Sun.COM 	mgr_ctx->mc_scf_hdl = scf_handle_create(SCF_VERSION);
7917961SNatalie.Li@Sun.COM 	if (mgr_ctx->mc_scf_hdl == NULL)
7927961SNatalie.Li@Sun.COM 		return (-1);
7937961SNatalie.Li@Sun.COM 
7947961SNatalie.Li@Sun.COM 	if (scf_handle_bind(mgr_ctx->mc_scf_hdl) == -1) {
7957961SNatalie.Li@Sun.COM 		scf_handle_destroy(mgr_ctx->mc_scf_hdl);
7967961SNatalie.Li@Sun.COM 		return (-1);
7977961SNatalie.Li@Sun.COM 	}
7987961SNatalie.Li@Sun.COM 
7997961SNatalie.Li@Sun.COM 	mgr_ctx->mc_scf_gpg = scf_pg_create(mgr_ctx->mc_scf_hdl);
8007961SNatalie.Li@Sun.COM 	mgr_ctx->mc_scf_gprop = scf_property_create(mgr_ctx->mc_scf_hdl);
8017961SNatalie.Li@Sun.COM 	mgr_ctx->mc_scf_gval = scf_value_create(mgr_ctx->mc_scf_hdl);
8027961SNatalie.Li@Sun.COM 
8037961SNatalie.Li@Sun.COM 	if ((mgr_ctx->mc_scf_gpg == NULL) ||
8047961SNatalie.Li@Sun.COM 	    (mgr_ctx->mc_scf_gprop == NULL) ||
8057961SNatalie.Li@Sun.COM 	    (mgr_ctx->mc_scf_gval == NULL)) {
8067961SNatalie.Li@Sun.COM 		(void) scf_handle_unbind(mgr_ctx->mc_scf_hdl);
8077961SNatalie.Li@Sun.COM 		scf_handle_destroy(mgr_ctx->mc_scf_hdl);
8087961SNatalie.Li@Sun.COM 		return (-1);
8097961SNatalie.Li@Sun.COM 	}
8107961SNatalie.Li@Sun.COM 
8117961SNatalie.Li@Sun.COM 	mgr_ctx->mc_scf_max_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
8127961SNatalie.Li@Sun.COM 	mgr_ctx->mc_scf_max_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
8137961SNatalie.Li@Sun.COM 
8147961SNatalie.Li@Sun.COM 	return (0);
8157961SNatalie.Li@Sun.COM }
8167961SNatalie.Li@Sun.COM 
8177961SNatalie.Li@Sun.COM /*
8187961SNatalie.Li@Sun.COM  * svcctl_scm_scf_handle_init
8197961SNatalie.Li@Sun.COM  *
8207961SNatalie.Li@Sun.COM  * Destroy SCF handle per context.
8217961SNatalie.Li@Sun.COM  */
8227961SNatalie.Li@Sun.COM void
svcctl_scm_scf_handle_fini(svcctl_manager_context_t * mgr_ctx)8237961SNatalie.Li@Sun.COM svcctl_scm_scf_handle_fini(svcctl_manager_context_t *mgr_ctx)
8247961SNatalie.Li@Sun.COM {
8257961SNatalie.Li@Sun.COM 	scf_value_destroy(mgr_ctx->mc_scf_gval);
8267961SNatalie.Li@Sun.COM 	scf_property_destroy(mgr_ctx->mc_scf_gprop);
8277961SNatalie.Li@Sun.COM 	scf_pg_destroy(mgr_ctx->mc_scf_gpg);
82810122SJordan.Brown@Sun.COM 
82910122SJordan.Brown@Sun.COM 	if (mgr_ctx->mc_scf_hdl != NULL) {
83010122SJordan.Brown@Sun.COM 		(void) scf_handle_unbind(mgr_ctx->mc_scf_hdl);
83110122SJordan.Brown@Sun.COM 		scf_handle_destroy(mgr_ctx->mc_scf_hdl);
83210122SJordan.Brown@Sun.COM 	}
8337961SNatalie.Li@Sun.COM }
8347961SNatalie.Li@Sun.COM 
8357961SNatalie.Li@Sun.COM /*
8367961SNatalie.Li@Sun.COM  * svcctl_scm_init
8377961SNatalie.Li@Sun.COM  *
8387961SNatalie.Li@Sun.COM  * Initialize SCM repository per context.
8397961SNatalie.Li@Sun.COM  * SCM repository holds a list of SMF services.
8407961SNatalie.Li@Sun.COM  * Each SMF service node contains state, description and FMRI.
8417961SNatalie.Li@Sun.COM  */
8427961SNatalie.Li@Sun.COM int
svcctl_scm_init(svcctl_manager_context_t * mgr_ctx)8437961SNatalie.Li@Sun.COM svcctl_scm_init(svcctl_manager_context_t *mgr_ctx)
8447961SNatalie.Li@Sun.COM {
8457961SNatalie.Li@Sun.COM 	int exit_status = 0;
8467961SNatalie.Li@Sun.COM 
8477961SNatalie.Li@Sun.COM 	assert(mgr_ctx->mc_svcs_pool == NULL);
8487961SNatalie.Li@Sun.COM 	assert(mgr_ctx->mc_svcs == NULL);
8497961SNatalie.Li@Sun.COM 
85010122SJordan.Brown@Sun.COM 	if (svcctl_scm_ops.svcctl_op_scm_init != NULL)
85110122SJordan.Brown@Sun.COM 		return (svcctl_scm_ops.svcctl_op_scm_init(mgr_ctx));
85210122SJordan.Brown@Sun.COM 
8537961SNatalie.Li@Sun.COM 	mgr_ctx->mc_svcs_pool = uu_avl_pool_create("smf_svcs_pool",
8547961SNatalie.Li@Sun.COM 	    sizeof (svcctl_svc_node_t), offsetof(svcctl_svc_node_t, sn_node),
8557961SNatalie.Li@Sun.COM 	    svcctl_scm_avl_nodecmp, UU_AVL_DEBUG);
8567961SNatalie.Li@Sun.COM 
8577961SNatalie.Li@Sun.COM 	if (mgr_ctx->mc_svcs_pool == NULL)
8587961SNatalie.Li@Sun.COM 		return (-1);
8597961SNatalie.Li@Sun.COM 
8607961SNatalie.Li@Sun.COM 	mgr_ctx->mc_svcs = uu_avl_create(mgr_ctx->mc_svcs_pool, NULL, 0);
8617961SNatalie.Li@Sun.COM 	if (mgr_ctx->mc_svcs == NULL) {
8627961SNatalie.Li@Sun.COM 		uu_avl_pool_destroy(mgr_ctx->mc_svcs_pool);
8637961SNatalie.Li@Sun.COM 		return (-1);
8647961SNatalie.Li@Sun.COM 	}
8657961SNatalie.Li@Sun.COM 
8667961SNatalie.Li@Sun.COM 	if (scf_walk_fmri(mgr_ctx->mc_scf_hdl, 0, NULL,
8677961SNatalie.Li@Sun.COM 	    SCF_WALK_MULTIPLE | SCF_WALK_LEGACY,
8687961SNatalie.Li@Sun.COM 	    svcctl_scm_cb_list_svcinst, mgr_ctx, &exit_status, NULL) != 0) {
8697961SNatalie.Li@Sun.COM 		uu_avl_destroy(mgr_ctx->mc_svcs);
8707961SNatalie.Li@Sun.COM 		uu_avl_pool_destroy(mgr_ctx->mc_svcs_pool);
8717961SNatalie.Li@Sun.COM 		return (-1);
8727961SNatalie.Li@Sun.COM 	}
8737961SNatalie.Li@Sun.COM 
8747961SNatalie.Li@Sun.COM 	mgr_ctx->mc_scf_numsvcs = uu_avl_numnodes(mgr_ctx->mc_svcs);
8757961SNatalie.Li@Sun.COM 	if (mgr_ctx->mc_scf_numsvcs > 0)
8767961SNatalie.Li@Sun.COM 		svcctl_scm_bytes_needed(mgr_ctx);
8777961SNatalie.Li@Sun.COM 
8787961SNatalie.Li@Sun.COM 	return (0);
8797961SNatalie.Li@Sun.COM }
8807961SNatalie.Li@Sun.COM 
8817961SNatalie.Li@Sun.COM /*
8827961SNatalie.Li@Sun.COM  * svcctl_scm_fini
8837961SNatalie.Li@Sun.COM  *
8847961SNatalie.Li@Sun.COM  * Destroy SCM repository per context.
8857961SNatalie.Li@Sun.COM  */
8867961SNatalie.Li@Sun.COM void
svcctl_scm_fini(svcctl_manager_context_t * mgr_ctx)8877961SNatalie.Li@Sun.COM svcctl_scm_fini(svcctl_manager_context_t *mgr_ctx)
8887961SNatalie.Li@Sun.COM {
8897961SNatalie.Li@Sun.COM 	uu_avl_walk_t *walk;
8907961SNatalie.Li@Sun.COM 	svcctl_svc_node_t *node;
8917961SNatalie.Li@Sun.COM 
8927961SNatalie.Li@Sun.COM 	if ((mgr_ctx == NULL) || (mgr_ctx->mc_svcs_pool == NULL) ||
8937961SNatalie.Li@Sun.COM 	    (mgr_ctx->mc_svcs == NULL))
8947961SNatalie.Li@Sun.COM 		return;
8957961SNatalie.Li@Sun.COM 
8967961SNatalie.Li@Sun.COM 	if ((walk =
8977961SNatalie.Li@Sun.COM 	    uu_avl_walk_start(mgr_ctx->mc_svcs, UU_WALK_ROBUST)) == NULL)
8987961SNatalie.Li@Sun.COM 		return;
8997961SNatalie.Li@Sun.COM 
9007961SNatalie.Li@Sun.COM 	while ((node = uu_avl_walk_next(walk)) != NULL) {
9017961SNatalie.Li@Sun.COM 		uu_avl_remove(mgr_ctx->mc_svcs, node);
9027961SNatalie.Li@Sun.COM 		free(node->sn_name);
9037961SNatalie.Li@Sun.COM 		free(node->sn_fmri);
9047961SNatalie.Li@Sun.COM 		free(node->sn_desc);
9057961SNatalie.Li@Sun.COM 		free(node->sn_state);
9067961SNatalie.Li@Sun.COM 		free(node);
9077961SNatalie.Li@Sun.COM 	}
9087961SNatalie.Li@Sun.COM 	uu_avl_walk_end(walk);
9097961SNatalie.Li@Sun.COM 	uu_avl_destroy(mgr_ctx->mc_svcs);
9107961SNatalie.Li@Sun.COM 	uu_avl_pool_destroy(mgr_ctx->mc_svcs_pool);
9117961SNatalie.Li@Sun.COM 	mgr_ctx->mc_svcs_pool = NULL;
9127961SNatalie.Li@Sun.COM 	mgr_ctx->mc_svcs = NULL;
9137961SNatalie.Li@Sun.COM }
91410122SJordan.Brown@Sun.COM 
91510122SJordan.Brown@Sun.COM /*
91610122SJordan.Brown@Sun.COM  * svcctl_init
91710122SJordan.Brown@Sun.COM  *
91810122SJordan.Brown@Sun.COM  * Initializes the SVCCTL service.
91910122SJordan.Brown@Sun.COM  * Initializes handle and ops structure to interposed library.
92010122SJordan.Brown@Sun.COM  */
92110122SJordan.Brown@Sun.COM void
svcctl_init(void)92210122SJordan.Brown@Sun.COM svcctl_init(void)
92310122SJordan.Brown@Sun.COM {
92410122SJordan.Brown@Sun.COM 	svcctl_scm_interposer_hdl = smb_dlopen();
92510122SJordan.Brown@Sun.COM 	if (svcctl_scm_interposer_hdl == NULL)
92610122SJordan.Brown@Sun.COM 		return;
92710122SJordan.Brown@Sun.COM 
92810122SJordan.Brown@Sun.COM 	bzero((void *)&svcctl_scm_ops,
92910122SJordan.Brown@Sun.COM 	    sizeof (svcctl_scm_ops));
93010122SJordan.Brown@Sun.COM 
93110122SJordan.Brown@Sun.COM 	svcctl_scm_ops.svcctl_op_scm_init =
93210122SJordan.Brown@Sun.COM 	    (int (*)())dlsym(svcctl_scm_interposer_hdl, "svcctl_scm_init");
93310122SJordan.Brown@Sun.COM 
93410122SJordan.Brown@Sun.COM 	svcctl_scm_ops.svcctl_op_scf_init =
93510122SJordan.Brown@Sun.COM 	    (int (*)())dlsym(svcctl_scm_interposer_hdl,
93610122SJordan.Brown@Sun.COM 	    "svcctl_scm_scf_handle_init");
93710122SJordan.Brown@Sun.COM 
93810122SJordan.Brown@Sun.COM 	if (svcctl_scm_ops.svcctl_op_scm_init == NULL ||
93910122SJordan.Brown@Sun.COM 	    svcctl_scm_ops.svcctl_op_scf_init == NULL)
94010122SJordan.Brown@Sun.COM 		svcctl_fini();
94110122SJordan.Brown@Sun.COM 
94210122SJordan.Brown@Sun.COM }
94310122SJordan.Brown@Sun.COM 
94410122SJordan.Brown@Sun.COM /*
94510122SJordan.Brown@Sun.COM  * svcctl_fini
94610122SJordan.Brown@Sun.COM  *
94710122SJordan.Brown@Sun.COM  * Finalizes the SVCCTL service.
94810122SJordan.Brown@Sun.COM  * Closes handle to interposed library.
94910122SJordan.Brown@Sun.COM  */
95010122SJordan.Brown@Sun.COM void
svcctl_fini(void)95110122SJordan.Brown@Sun.COM svcctl_fini(void)
95210122SJordan.Brown@Sun.COM {
95310122SJordan.Brown@Sun.COM 	smb_dlclose(svcctl_scm_interposer_hdl);
95410122SJordan.Brown@Sun.COM 	svcctl_scm_interposer_hdl = NULL;
95510122SJordan.Brown@Sun.COM 	bzero((void *)&svcctl_scm_ops,
95610122SJordan.Brown@Sun.COM 	    sizeof (svcctl_scm_ops));
95710122SJordan.Brown@Sun.COM }
958