xref: /onnv-gate/usr/src/lib/smbsrv/libmlsvc/common/svcctl_scm.c (revision 7961:4b5e3051f38b)
1*7961SNatalie.Li@Sun.COM /*
2*7961SNatalie.Li@Sun.COM  * CDDL HEADER START
3*7961SNatalie.Li@Sun.COM  *
4*7961SNatalie.Li@Sun.COM  * The contents of this file are subject to the terms of the
5*7961SNatalie.Li@Sun.COM  * Common Development and Distribution License (the "License").
6*7961SNatalie.Li@Sun.COM  * You may not use this file except in compliance with the License.
7*7961SNatalie.Li@Sun.COM  *
8*7961SNatalie.Li@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*7961SNatalie.Li@Sun.COM  * or http://www.opensolaris.org/os/licensing.
10*7961SNatalie.Li@Sun.COM  * See the License for the specific language governing permissions
11*7961SNatalie.Li@Sun.COM  * and limitations under the License.
12*7961SNatalie.Li@Sun.COM  *
13*7961SNatalie.Li@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
14*7961SNatalie.Li@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*7961SNatalie.Li@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
16*7961SNatalie.Li@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
17*7961SNatalie.Li@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
18*7961SNatalie.Li@Sun.COM  *
19*7961SNatalie.Li@Sun.COM  * CDDL HEADER END
20*7961SNatalie.Li@Sun.COM  */
21*7961SNatalie.Li@Sun.COM /*
22*7961SNatalie.Li@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23*7961SNatalie.Li@Sun.COM  * Use is subject to license terms.
24*7961SNatalie.Li@Sun.COM  */
25*7961SNatalie.Li@Sun.COM 
26*7961SNatalie.Li@Sun.COM /*
27*7961SNatalie.Li@Sun.COM  * Service Control Manager (SCM) for SVCCTL service.
28*7961SNatalie.Li@Sun.COM  *
29*7961SNatalie.Li@Sun.COM  * This routine maintains a list of SMF service and their states. A list
30*7961SNatalie.Li@Sun.COM  * of Solaris SMF service are displayed on the Server/Connection Manager
31*7961SNatalie.Li@Sun.COM  * Windows client.
32*7961SNatalie.Li@Sun.COM  */
33*7961SNatalie.Li@Sun.COM 
34*7961SNatalie.Li@Sun.COM #include <stdio.h>
35*7961SNatalie.Li@Sun.COM #include <stdlib.h>
36*7961SNatalie.Li@Sun.COM #include <stdarg.h>
37*7961SNatalie.Li@Sun.COM #include <strings.h>
38*7961SNatalie.Li@Sun.COM #include <assert.h>
39*7961SNatalie.Li@Sun.COM #include <errno.h>
40*7961SNatalie.Li@Sun.COM #include <libscf.h>
41*7961SNatalie.Li@Sun.COM #include <libscf_priv.h>
42*7961SNatalie.Li@Sun.COM #include <time.h>
43*7961SNatalie.Li@Sun.COM #include <sys/types.h>
44*7961SNatalie.Li@Sun.COM 
45*7961SNatalie.Li@Sun.COM #include "svcctl_scm.h"
46*7961SNatalie.Li@Sun.COM 
47*7961SNatalie.Li@Sun.COM #define	LEGACY_UNKNOWN	"unknown"
48*7961SNatalie.Li@Sun.COM #define	SVC_NAME_PROP	"name"
49*7961SNatalie.Li@Sun.COM 
50*7961SNatalie.Li@Sun.COM /* Flags for svcctl_scm_pg_get_val() */
51*7961SNatalie.Li@Sun.COM #define	EMPTY_OK	0x01
52*7961SNatalie.Li@Sun.COM #define	MULTI_OK	0x02
53*7961SNatalie.Li@Sun.COM 
54*7961SNatalie.Li@Sun.COM /*
55*7961SNatalie.Li@Sun.COM  * svcctl_scm_avl_nodecmp
56*7961SNatalie.Li@Sun.COM  *
57*7961SNatalie.Li@Sun.COM  * Comparision function for nodes in an AVL tree of services.
58*7961SNatalie.Li@Sun.COM  */
59*7961SNatalie.Li@Sun.COM /* ARGSUSED */
60*7961SNatalie.Li@Sun.COM static int
61*7961SNatalie.Li@Sun.COM svcctl_scm_avl_nodecmp(const void *l_arg, const void *r_arg, void *m_name_len)
62*7961SNatalie.Li@Sun.COM {
63*7961SNatalie.Li@Sun.COM 	const svcctl_svc_node_t *l = l_arg;
64*7961SNatalie.Li@Sun.COM 	const svcctl_svc_node_t *r = r_arg;
65*7961SNatalie.Li@Sun.COM 	int *max_name_len = m_name_len;
66*7961SNatalie.Li@Sun.COM 	int ret = 0;
67*7961SNatalie.Li@Sun.COM 
68*7961SNatalie.Li@Sun.COM 	ret = strncasecmp(l->sn_name, r->sn_name, *max_name_len);
69*7961SNatalie.Li@Sun.COM 
70*7961SNatalie.Li@Sun.COM 	if (ret > 0)
71*7961SNatalie.Li@Sun.COM 		return (1);
72*7961SNatalie.Li@Sun.COM 	if (ret < 0)
73*7961SNatalie.Li@Sun.COM 		return (-1);
74*7961SNatalie.Li@Sun.COM 	return (0);
75*7961SNatalie.Li@Sun.COM }
76*7961SNatalie.Li@Sun.COM 
77*7961SNatalie.Li@Sun.COM /*
78*7961SNatalie.Li@Sun.COM  * svcctl_scm_pg_get_val
79*7961SNatalie.Li@Sun.COM  *
80*7961SNatalie.Li@Sun.COM  * Get the single value of the named property in the given property group,
81*7961SNatalie.Li@Sun.COM  * which must have type ty, and put it in *vp.  If ty is SCF_TYPE_ASTRING, vp
82*7961SNatalie.Li@Sun.COM  * is taken to be a char **, and sz is the size of the buffer.  sz is unused
83*7961SNatalie.Li@Sun.COM  * otherwise.  Return 0 on success, -1 if the property doesn't exist, has the
84*7961SNatalie.Li@Sun.COM  * wrong type, or doesn't have a single value.  If flags has EMPTY_OK, don't
85*7961SNatalie.Li@Sun.COM  * complain if the property has no values (but return nonzero).  If flags has
86*7961SNatalie.Li@Sun.COM  * MULTI_OK and the property has multiple values, succeed with E2BIG.
87*7961SNatalie.Li@Sun.COM  */
88*7961SNatalie.Li@Sun.COM static int
89*7961SNatalie.Li@Sun.COM svcctl_scm_pg_get_val(svcctl_manager_context_t *mgr_ctx,
90*7961SNatalie.Li@Sun.COM     scf_propertygroup_t *pg, const char *propname, scf_type_t ty, void *vp,
91*7961SNatalie.Li@Sun.COM     size_t sz, uint_t flags)
92*7961SNatalie.Li@Sun.COM {
93*7961SNatalie.Li@Sun.COM 	int ret = -1, r;
94*7961SNatalie.Li@Sun.COM 	boolean_t multi = B_FALSE;
95*7961SNatalie.Li@Sun.COM 
96*7961SNatalie.Li@Sun.COM 	assert((flags & ~(EMPTY_OK | MULTI_OK)) == 0);
97*7961SNatalie.Li@Sun.COM 
98*7961SNatalie.Li@Sun.COM 	if (scf_pg_get_property(pg, propname, mgr_ctx->mc_scf_gprop) == -1)
99*7961SNatalie.Li@Sun.COM 		return (ret);
100*7961SNatalie.Li@Sun.COM 
101*7961SNatalie.Li@Sun.COM 	if (scf_property_is_type(mgr_ctx->mc_scf_gprop, ty) != SCF_SUCCESS)
102*7961SNatalie.Li@Sun.COM 		return (ret);
103*7961SNatalie.Li@Sun.COM 
104*7961SNatalie.Li@Sun.COM 	if (scf_property_get_value(mgr_ctx->mc_scf_gprop,
105*7961SNatalie.Li@Sun.COM 	    mgr_ctx->mc_scf_gval) != SCF_SUCCESS) {
106*7961SNatalie.Li@Sun.COM 		switch (scf_error()) {
107*7961SNatalie.Li@Sun.COM 		case SCF_ERROR_NOT_FOUND:
108*7961SNatalie.Li@Sun.COM 			return (ret);
109*7961SNatalie.Li@Sun.COM 
110*7961SNatalie.Li@Sun.COM 		case SCF_ERROR_CONSTRAINT_VIOLATED:
111*7961SNatalie.Li@Sun.COM 			if (flags & MULTI_OK) {
112*7961SNatalie.Li@Sun.COM 				multi = B_TRUE;
113*7961SNatalie.Li@Sun.COM 				break;
114*7961SNatalie.Li@Sun.COM 			}
115*7961SNatalie.Li@Sun.COM 			return (ret);
116*7961SNatalie.Li@Sun.COM 
117*7961SNatalie.Li@Sun.COM 		case SCF_ERROR_PERMISSION_DENIED:
118*7961SNatalie.Li@Sun.COM 		default:
119*7961SNatalie.Li@Sun.COM 			return (ret);
120*7961SNatalie.Li@Sun.COM 		}
121*7961SNatalie.Li@Sun.COM 	}
122*7961SNatalie.Li@Sun.COM 
123*7961SNatalie.Li@Sun.COM 	switch (ty) {
124*7961SNatalie.Li@Sun.COM 	case SCF_TYPE_ASTRING:
125*7961SNatalie.Li@Sun.COM 		r = scf_value_get_astring
126*7961SNatalie.Li@Sun.COM 		    (mgr_ctx->mc_scf_gval, vp, sz) > 0 ? SCF_SUCCESS : -1;
127*7961SNatalie.Li@Sun.COM 		break;
128*7961SNatalie.Li@Sun.COM 
129*7961SNatalie.Li@Sun.COM 	case SCF_TYPE_BOOLEAN:
130*7961SNatalie.Li@Sun.COM 		r = scf_value_get_boolean(mgr_ctx->mc_scf_gval, (uint8_t *)vp);
131*7961SNatalie.Li@Sun.COM 		break;
132*7961SNatalie.Li@Sun.COM 
133*7961SNatalie.Li@Sun.COM 	case SCF_TYPE_COUNT:
134*7961SNatalie.Li@Sun.COM 		r = scf_value_get_count(mgr_ctx->mc_scf_gval, (uint64_t *)vp);
135*7961SNatalie.Li@Sun.COM 		break;
136*7961SNatalie.Li@Sun.COM 
137*7961SNatalie.Li@Sun.COM 	case SCF_TYPE_INTEGER:
138*7961SNatalie.Li@Sun.COM 		r = scf_value_get_integer(mgr_ctx->mc_scf_gval, (int64_t *)vp);
139*7961SNatalie.Li@Sun.COM 		break;
140*7961SNatalie.Li@Sun.COM 
141*7961SNatalie.Li@Sun.COM 	case SCF_TYPE_TIME: {
142*7961SNatalie.Li@Sun.COM 		int64_t sec;
143*7961SNatalie.Li@Sun.COM 		int32_t ns;
144*7961SNatalie.Li@Sun.COM 		r = scf_value_get_time(mgr_ctx->mc_scf_gval, &sec, &ns);
145*7961SNatalie.Li@Sun.COM 		((struct timeval *)vp)->tv_sec = sec;
146*7961SNatalie.Li@Sun.COM 		((struct timeval *)vp)->tv_usec = ns / 1000;
147*7961SNatalie.Li@Sun.COM 		break;
148*7961SNatalie.Li@Sun.COM 	}
149*7961SNatalie.Li@Sun.COM 
150*7961SNatalie.Li@Sun.COM 	case SCF_TYPE_USTRING:
151*7961SNatalie.Li@Sun.COM 		r = scf_value_get_ustring(mgr_ctx->mc_scf_gval, vp, sz) > 0 ?
152*7961SNatalie.Li@Sun.COM 		    SCF_SUCCESS : -1;
153*7961SNatalie.Li@Sun.COM 		break;
154*7961SNatalie.Li@Sun.COM 
155*7961SNatalie.Li@Sun.COM 	default:
156*7961SNatalie.Li@Sun.COM 		return (ret);
157*7961SNatalie.Li@Sun.COM 	}
158*7961SNatalie.Li@Sun.COM 
159*7961SNatalie.Li@Sun.COM 	if (r != SCF_SUCCESS)
160*7961SNatalie.Li@Sun.COM 		return (ret);
161*7961SNatalie.Li@Sun.COM 
162*7961SNatalie.Li@Sun.COM 	ret = multi ? E2BIG : 0;
163*7961SNatalie.Li@Sun.COM 
164*7961SNatalie.Li@Sun.COM 	return (ret);
165*7961SNatalie.Li@Sun.COM }
166*7961SNatalie.Li@Sun.COM 
167*7961SNatalie.Li@Sun.COM /*
168*7961SNatalie.Li@Sun.COM  * svcctl_scm_get_running_snapshot
169*7961SNatalie.Li@Sun.COM  *
170*7961SNatalie.Li@Sun.COM  * Get running snapshot of a service instance.
171*7961SNatalie.Li@Sun.COM  */
172*7961SNatalie.Li@Sun.COM static scf_snapshot_t *
173*7961SNatalie.Li@Sun.COM svcctl_scm_get_running_snapshot(svcctl_manager_context_t *mgr_ctx,
174*7961SNatalie.Li@Sun.COM     scf_instance_t *inst)
175*7961SNatalie.Li@Sun.COM {
176*7961SNatalie.Li@Sun.COM 	scf_snapshot_t *snap;
177*7961SNatalie.Li@Sun.COM 
178*7961SNatalie.Li@Sun.COM 	snap = scf_snapshot_create(mgr_ctx->mc_scf_hdl);
179*7961SNatalie.Li@Sun.COM 	if (snap == NULL)
180*7961SNatalie.Li@Sun.COM 		return (NULL);
181*7961SNatalie.Li@Sun.COM 
182*7961SNatalie.Li@Sun.COM 	if (scf_instance_get_snapshot(inst, "running", snap) == 0)
183*7961SNatalie.Li@Sun.COM 		return (snap);
184*7961SNatalie.Li@Sun.COM 
185*7961SNatalie.Li@Sun.COM 	if (scf_error() != SCF_ERROR_NOT_FOUND)
186*7961SNatalie.Li@Sun.COM 		return (NULL);
187*7961SNatalie.Li@Sun.COM 
188*7961SNatalie.Li@Sun.COM 	scf_snapshot_destroy(snap);
189*7961SNatalie.Li@Sun.COM 	return (NULL);
190*7961SNatalie.Li@Sun.COM }
191*7961SNatalie.Li@Sun.COM 
192*7961SNatalie.Li@Sun.COM /*
193*7961SNatalie.Li@Sun.COM  * svcctl_scm_inst_get_val
194*7961SNatalie.Li@Sun.COM  *
195*7961SNatalie.Li@Sun.COM  * As svcctl_scm_pg_get_val(), except look the property group up in an
196*7961SNatalie.Li@Sun.COM  * instance.  If "use_running" is set, and the running snapshot exists,
197*7961SNatalie.Li@Sun.COM  * do a composed lookup there.  Otherwise, do an (optionally composed)
198*7961SNatalie.Li@Sun.COM  * lookup on the current values.  Note that lookups using snapshots are
199*7961SNatalie.Li@Sun.COM  * always composed.
200*7961SNatalie.Li@Sun.COM  */
201*7961SNatalie.Li@Sun.COM static int
202*7961SNatalie.Li@Sun.COM svcctl_scm_inst_get_val(svcctl_manager_context_t *mgr_ctx, scf_instance_t *inst,
203*7961SNatalie.Li@Sun.COM     const char *pgname, const char *propname, scf_type_t ty, void *vp,
204*7961SNatalie.Li@Sun.COM     size_t sz, uint_t flags, int use_running, int composed)
205*7961SNatalie.Li@Sun.COM {
206*7961SNatalie.Li@Sun.COM 	scf_snapshot_t *snap = NULL;
207*7961SNatalie.Li@Sun.COM 	int r;
208*7961SNatalie.Li@Sun.COM 
209*7961SNatalie.Li@Sun.COM 	if (use_running)
210*7961SNatalie.Li@Sun.COM 		snap = svcctl_scm_get_running_snapshot(mgr_ctx, inst);
211*7961SNatalie.Li@Sun.COM 	if (composed || use_running)
212*7961SNatalie.Li@Sun.COM 		r = scf_instance_get_pg_composed(inst, snap, pgname,
213*7961SNatalie.Li@Sun.COM 		    mgr_ctx->mc_scf_gpg);
214*7961SNatalie.Li@Sun.COM 	else
215*7961SNatalie.Li@Sun.COM 		r = scf_instance_get_pg(inst, pgname, mgr_ctx->mc_scf_gpg);
216*7961SNatalie.Li@Sun.COM 	if (snap)
217*7961SNatalie.Li@Sun.COM 		scf_snapshot_destroy(snap);
218*7961SNatalie.Li@Sun.COM 	if (r == -1)
219*7961SNatalie.Li@Sun.COM 		return (-1);
220*7961SNatalie.Li@Sun.COM 
221*7961SNatalie.Li@Sun.COM 	r = svcctl_scm_pg_get_val(mgr_ctx, mgr_ctx->mc_scf_gpg, propname, ty,
222*7961SNatalie.Li@Sun.COM 	    vp, sz, flags);
223*7961SNatalie.Li@Sun.COM 
224*7961SNatalie.Li@Sun.COM 	return (r);
225*7961SNatalie.Li@Sun.COM }
226*7961SNatalie.Li@Sun.COM 
227*7961SNatalie.Li@Sun.COM /*
228*7961SNatalie.Li@Sun.COM  * svcctl_scm_get_restarter_string_prop
229*7961SNatalie.Li@Sun.COM  *
230*7961SNatalie.Li@Sun.COM  * Get a string property from the restarter property group of the given
231*7961SNatalie.Li@Sun.COM  * instance.  Return an empty string on normal problems.
232*7961SNatalie.Li@Sun.COM  */
233*7961SNatalie.Li@Sun.COM static void
234*7961SNatalie.Li@Sun.COM svcctl_scm_get_restarter_string_prop(svcctl_manager_context_t *mgr_ctx,
235*7961SNatalie.Li@Sun.COM     scf_instance_t *inst, const char *pname, char *buf, size_t buf_sz)
236*7961SNatalie.Li@Sun.COM {
237*7961SNatalie.Li@Sun.COM 	if (svcctl_scm_inst_get_val(mgr_ctx, inst, SCF_PG_RESTARTER, pname,
238*7961SNatalie.Li@Sun.COM 	    SCF_TYPE_ASTRING, buf, buf_sz, 0, 0, 1) != 0)
239*7961SNatalie.Li@Sun.COM 		*buf = '\0';
240*7961SNatalie.Li@Sun.COM }
241*7961SNatalie.Li@Sun.COM 
242*7961SNatalie.Li@Sun.COM /*
243*7961SNatalie.Li@Sun.COM  * svcctl_scm_svc_transitioning
244*7961SNatalie.Li@Sun.COM  *
245*7961SNatalie.Li@Sun.COM  * Return true if a service instance is transitioning.
246*7961SNatalie.Li@Sun.COM  */
247*7961SNatalie.Li@Sun.COM static int
248*7961SNatalie.Li@Sun.COM svcctl_scm_svc_transitioning(svcctl_manager_context_t *mgr_ctx,
249*7961SNatalie.Li@Sun.COM     scf_instance_t *inst)
250*7961SNatalie.Li@Sun.COM {
251*7961SNatalie.Li@Sun.COM 	char nstate_name[MAX_SCF_STATE_STRING_SZ];
252*7961SNatalie.Li@Sun.COM 
253*7961SNatalie.Li@Sun.COM 	bzero(nstate_name, MAX_SCF_STATE_STRING_SZ);
254*7961SNatalie.Li@Sun.COM 	svcctl_scm_get_restarter_string_prop(mgr_ctx, inst,
255*7961SNatalie.Li@Sun.COM 	    SCF_PROPERTY_NEXT_STATE, nstate_name, sizeof (nstate_name));
256*7961SNatalie.Li@Sun.COM 
257*7961SNatalie.Li@Sun.COM 	return ((*nstate_name == '\0'));
258*7961SNatalie.Li@Sun.COM }
259*7961SNatalie.Li@Sun.COM 
260*7961SNatalie.Li@Sun.COM /*
261*7961SNatalie.Li@Sun.COM  * svcctl_scm_get_svcstate
262*7961SNatalie.Li@Sun.COM  *
263*7961SNatalie.Li@Sun.COM  * Gets the state of an SMF service.
264*7961SNatalie.Li@Sun.COM  */
265*7961SNatalie.Li@Sun.COM static int
266*7961SNatalie.Li@Sun.COM svcctl_scm_get_svcstate(svcctl_manager_context_t *mgr_ctx,
267*7961SNatalie.Li@Sun.COM     char **buf, scf_walkinfo_t *wip)
268*7961SNatalie.Li@Sun.COM {
269*7961SNatalie.Li@Sun.COM 	char *state_name;
270*7961SNatalie.Li@Sun.COM 	size_t max_state_size;
271*7961SNatalie.Li@Sun.COM 
272*7961SNatalie.Li@Sun.COM 	max_state_size = MAX_SCF_STATE_STRING_SZ + 1;
273*7961SNatalie.Li@Sun.COM 
274*7961SNatalie.Li@Sun.COM 	if ((state_name = malloc(max_state_size)) == NULL)
275*7961SNatalie.Li@Sun.COM 		return (-1);
276*7961SNatalie.Li@Sun.COM 
277*7961SNatalie.Li@Sun.COM 	if (wip->pg == NULL) {
278*7961SNatalie.Li@Sun.COM 		svcctl_scm_get_restarter_string_prop(mgr_ctx, wip->inst,
279*7961SNatalie.Li@Sun.COM 		    SCF_PROPERTY_STATE, state_name, max_state_size);
280*7961SNatalie.Li@Sun.COM 
281*7961SNatalie.Li@Sun.COM 		/* Don't print blank fields, to ease parsing. */
282*7961SNatalie.Li@Sun.COM 		if (state_name[0] == '\0') {
283*7961SNatalie.Li@Sun.COM 			state_name[0] = '-';
284*7961SNatalie.Li@Sun.COM 			state_name[1] = '\0';
285*7961SNatalie.Li@Sun.COM 		}
286*7961SNatalie.Li@Sun.COM 
287*7961SNatalie.Li@Sun.COM 		if (svcctl_scm_svc_transitioning(mgr_ctx, wip->inst))
288*7961SNatalie.Li@Sun.COM 			/* Append an asterisk if new state is valid. */
289*7961SNatalie.Li@Sun.COM 			(void) strlcat(state_name, "*", max_state_size);
290*7961SNatalie.Li@Sun.COM 
291*7961SNatalie.Li@Sun.COM 	} else
292*7961SNatalie.Li@Sun.COM 		(void) strlcpy(state_name, SCF_STATE_STRING_LEGACY,
293*7961SNatalie.Li@Sun.COM 		    max_state_size);
294*7961SNatalie.Li@Sun.COM 
295*7961SNatalie.Li@Sun.COM 	*buf = state_name;
296*7961SNatalie.Li@Sun.COM 	return (0);
297*7961SNatalie.Li@Sun.COM }
298*7961SNatalie.Li@Sun.COM 
299*7961SNatalie.Li@Sun.COM /*
300*7961SNatalie.Li@Sun.COM  * svcctl_scm_get_svcdesc
301*7961SNatalie.Li@Sun.COM  *
302*7961SNatalie.Li@Sun.COM  * Gets the description of an SMF service.
303*7961SNatalie.Li@Sun.COM  */
304*7961SNatalie.Li@Sun.COM static int
305*7961SNatalie.Li@Sun.COM svcctl_scm_get_svcdesc(svcctl_manager_context_t *mgr_ctx,
306*7961SNatalie.Li@Sun.COM     char **buf, scf_walkinfo_t *wip)
307*7961SNatalie.Li@Sun.COM {
308*7961SNatalie.Li@Sun.COM 	char *x;
309*7961SNatalie.Li@Sun.COM 	size_t newsize;
310*7961SNatalie.Li@Sun.COM 	char *newbuf;
311*7961SNatalie.Li@Sun.COM 	char *desc_buf = NULL;
312*7961SNatalie.Li@Sun.COM 
313*7961SNatalie.Li@Sun.COM 	if ((desc_buf = malloc(mgr_ctx->mc_scf_max_value_len + 1)) == NULL)
314*7961SNatalie.Li@Sun.COM 		return (-1);
315*7961SNatalie.Li@Sun.COM 
316*7961SNatalie.Li@Sun.COM 	bzero(desc_buf, mgr_ctx->mc_scf_max_value_len + 1);
317*7961SNatalie.Li@Sun.COM 	if (wip->pg != NULL)
318*7961SNatalie.Li@Sun.COM 		desc_buf[0] = '-';
319*7961SNatalie.Li@Sun.COM 	else if (svcctl_scm_inst_get_val(mgr_ctx, wip->inst,
320*7961SNatalie.Li@Sun.COM 	    SCF_PG_TM_COMMON_NAME, "C", SCF_TYPE_USTRING, desc_buf,
321*7961SNatalie.Li@Sun.COM 	    mgr_ctx->mc_scf_max_value_len, 0, 1, 1) == -1)
322*7961SNatalie.Li@Sun.COM 		desc_buf[0] = '-';
323*7961SNatalie.Li@Sun.COM 
324*7961SNatalie.Li@Sun.COM 	/*
325*7961SNatalie.Li@Sun.COM 	 * Collapse multi-line tm_common_name values into a single line.
326*7961SNatalie.Li@Sun.COM 	 */
327*7961SNatalie.Li@Sun.COM 	for (x = desc_buf; *x != '\0'; x++)
328*7961SNatalie.Li@Sun.COM 		if (*x == '\n')
329*7961SNatalie.Li@Sun.COM 			*x = ' ';
330*7961SNatalie.Li@Sun.COM 
331*7961SNatalie.Li@Sun.COM 	newsize = strlen(desc_buf) + 1;
332*7961SNatalie.Li@Sun.COM 	if ((newbuf = malloc(newsize)) == NULL) {
333*7961SNatalie.Li@Sun.COM 		free(desc_buf);
334*7961SNatalie.Li@Sun.COM 		return (-1);
335*7961SNatalie.Li@Sun.COM 	}
336*7961SNatalie.Li@Sun.COM 
337*7961SNatalie.Li@Sun.COM 	(void) snprintf(newbuf, newsize, "%s", desc_buf);
338*7961SNatalie.Li@Sun.COM 	free(desc_buf);
339*7961SNatalie.Li@Sun.COM 
340*7961SNatalie.Li@Sun.COM 	*buf = newbuf;
341*7961SNatalie.Li@Sun.COM 	return (0);
342*7961SNatalie.Li@Sun.COM }
343*7961SNatalie.Li@Sun.COM 
344*7961SNatalie.Li@Sun.COM /*
345*7961SNatalie.Li@Sun.COM  * svcctl_scm_get_svcfmri
346*7961SNatalie.Li@Sun.COM  *
347*7961SNatalie.Li@Sun.COM  * Gets the FMRI of an SMF service.
348*7961SNatalie.Li@Sun.COM  */
349*7961SNatalie.Li@Sun.COM static int
350*7961SNatalie.Li@Sun.COM svcctl_scm_get_svcfmri(svcctl_manager_context_t *mgr_ctx,
351*7961SNatalie.Li@Sun.COM     char **buf, scf_walkinfo_t *wip)
352*7961SNatalie.Li@Sun.COM {
353*7961SNatalie.Li@Sun.COM 	size_t newsize;
354*7961SNatalie.Li@Sun.COM 	char *newbuf;
355*7961SNatalie.Li@Sun.COM 	char *fmri_buf = NULL;
356*7961SNatalie.Li@Sun.COM 	void *fmri_p = NULL;
357*7961SNatalie.Li@Sun.COM 	size_t fmri_size;
358*7961SNatalie.Li@Sun.COM 
359*7961SNatalie.Li@Sun.COM 	if ((fmri_buf = malloc(mgr_ctx->mc_scf_max_fmri_len + 1)) == NULL)
360*7961SNatalie.Li@Sun.COM 		return (-1);
361*7961SNatalie.Li@Sun.COM 
362*7961SNatalie.Li@Sun.COM 	if (wip->pg == NULL) {
363*7961SNatalie.Li@Sun.COM 		if (scf_instance_to_fmri(wip->inst, fmri_buf,
364*7961SNatalie.Li@Sun.COM 		    mgr_ctx->mc_scf_max_fmri_len + 1) == -1) {
365*7961SNatalie.Li@Sun.COM 			free(fmri_buf);
366*7961SNatalie.Li@Sun.COM 			return (-1);
367*7961SNatalie.Li@Sun.COM 		}
368*7961SNatalie.Li@Sun.COM 	} else {
369*7961SNatalie.Li@Sun.COM 		(void) strlcpy(fmri_buf, SCF_FMRI_LEGACY_PREFIX,
370*7961SNatalie.Li@Sun.COM 		    mgr_ctx->mc_scf_max_fmri_len + 1);
371*7961SNatalie.Li@Sun.COM 
372*7961SNatalie.Li@Sun.COM 		fmri_p = fmri_buf + sizeof (SCF_FMRI_LEGACY_PREFIX) - 1;
373*7961SNatalie.Li@Sun.COM 		fmri_size = mgr_ctx->mc_scf_max_fmri_len + 1 - \
374*7961SNatalie.Li@Sun.COM 		    (sizeof (SCF_FMRI_LEGACY_PREFIX) - 1);
375*7961SNatalie.Li@Sun.COM 
376*7961SNatalie.Li@Sun.COM 		if (svcctl_scm_pg_get_val(mgr_ctx, wip->pg,
377*7961SNatalie.Li@Sun.COM 		    SCF_LEGACY_PROPERTY_NAME, SCF_TYPE_ASTRING,
378*7961SNatalie.Li@Sun.COM 		    fmri_p, fmri_size, 0) != 0)
379*7961SNatalie.Li@Sun.COM 			(void) strlcat(fmri_buf, LEGACY_UNKNOWN,
380*7961SNatalie.Li@Sun.COM 			    mgr_ctx->mc_scf_max_fmri_len + 1);
381*7961SNatalie.Li@Sun.COM 	}
382*7961SNatalie.Li@Sun.COM 
383*7961SNatalie.Li@Sun.COM 	newsize = strlen(fmri_buf) + 1;
384*7961SNatalie.Li@Sun.COM 	if ((newbuf = malloc(newsize)) == NULL) {
385*7961SNatalie.Li@Sun.COM 		free(fmri_buf);
386*7961SNatalie.Li@Sun.COM 		return (-1);
387*7961SNatalie.Li@Sun.COM 	}
388*7961SNatalie.Li@Sun.COM 
389*7961SNatalie.Li@Sun.COM 	(void) snprintf(newbuf, newsize, "%s", fmri_buf);
390*7961SNatalie.Li@Sun.COM 	free(fmri_buf);
391*7961SNatalie.Li@Sun.COM 
392*7961SNatalie.Li@Sun.COM 	*buf = newbuf;
393*7961SNatalie.Li@Sun.COM 	return (0);
394*7961SNatalie.Li@Sun.COM }
395*7961SNatalie.Li@Sun.COM 
396*7961SNatalie.Li@Sun.COM /*
397*7961SNatalie.Li@Sun.COM  * svcctl_scm_get_svcname
398*7961SNatalie.Li@Sun.COM  *
399*7961SNatalie.Li@Sun.COM  * Gets the FMRI of an SMF service.
400*7961SNatalie.Li@Sun.COM  */
401*7961SNatalie.Li@Sun.COM static int
402*7961SNatalie.Li@Sun.COM svcctl_scm_get_svcname(char **buf, char *fmri)
403*7961SNatalie.Li@Sun.COM {
404*7961SNatalie.Li@Sun.COM 	char *nm_buf = NULL;
405*7961SNatalie.Li@Sun.COM 	char *newbuf;
406*7961SNatalie.Li@Sun.COM 	size_t newsize;
407*7961SNatalie.Li@Sun.COM 
408*7961SNatalie.Li@Sun.COM 	if (fmri == NULL)
409*7961SNatalie.Li@Sun.COM 		return (-1);
410*7961SNatalie.Li@Sun.COM 
411*7961SNatalie.Li@Sun.COM 	newsize = strlen(fmri);
412*7961SNatalie.Li@Sun.COM 	if ((newbuf = malloc(newsize)) == NULL)
413*7961SNatalie.Li@Sun.COM 		return (-1);
414*7961SNatalie.Li@Sun.COM 
415*7961SNatalie.Li@Sun.COM 	if ((nm_buf = strchr(fmri, '/')) == NULL)
416*7961SNatalie.Li@Sun.COM 		return (-1);
417*7961SNatalie.Li@Sun.COM 
418*7961SNatalie.Li@Sun.COM 	(void) snprintf(newbuf, newsize, "%s", ++nm_buf);
419*7961SNatalie.Li@Sun.COM 	*buf = newbuf;
420*7961SNatalie.Li@Sun.COM 	return (0);
421*7961SNatalie.Li@Sun.COM }
422*7961SNatalie.Li@Sun.COM 
423*7961SNatalie.Li@Sun.COM /*
424*7961SNatalie.Li@Sun.COM  * svcctl_scm_cb_list_svcinst
425*7961SNatalie.Li@Sun.COM  *
426*7961SNatalie.Li@Sun.COM  * Callback function to walk all the services in an SCF repository.
427*7961SNatalie.Li@Sun.COM  */
428*7961SNatalie.Li@Sun.COM static int
429*7961SNatalie.Li@Sun.COM svcctl_scm_cb_list_svcinst(void *context, scf_walkinfo_t *wip)
430*7961SNatalie.Li@Sun.COM {
431*7961SNatalie.Li@Sun.COM 	svcctl_svc_node_t *node = NULL;
432*7961SNatalie.Li@Sun.COM 	uu_avl_index_t idx;
433*7961SNatalie.Li@Sun.COM 	svcctl_manager_context_t *mgr_ctx = (svcctl_manager_context_t *)context;
434*7961SNatalie.Li@Sun.COM 
435*7961SNatalie.Li@Sun.COM 	node = malloc(sizeof (*node));
436*7961SNatalie.Li@Sun.COM 	if (node == NULL)
437*7961SNatalie.Li@Sun.COM 		return (-1);
438*7961SNatalie.Li@Sun.COM 
439*7961SNatalie.Li@Sun.COM 	node->sn_fmri = NULL;
440*7961SNatalie.Li@Sun.COM 	if (svcctl_scm_get_svcfmri(mgr_ctx, &node->sn_fmri, wip) != 0)
441*7961SNatalie.Li@Sun.COM 		return (-1);
442*7961SNatalie.Li@Sun.COM 
443*7961SNatalie.Li@Sun.COM 	node->sn_name = NULL;
444*7961SNatalie.Li@Sun.COM 	if (svcctl_scm_get_svcname(&node->sn_name, node->sn_fmri) != 0)
445*7961SNatalie.Li@Sun.COM 		return (-1);
446*7961SNatalie.Li@Sun.COM 
447*7961SNatalie.Li@Sun.COM 	node->sn_desc = NULL;
448*7961SNatalie.Li@Sun.COM 	if (svcctl_scm_get_svcdesc(mgr_ctx, &node->sn_desc, wip) != 0)
449*7961SNatalie.Li@Sun.COM 		return (-1);
450*7961SNatalie.Li@Sun.COM 
451*7961SNatalie.Li@Sun.COM 	node->sn_state = NULL;
452*7961SNatalie.Li@Sun.COM 	if (svcctl_scm_get_svcstate(mgr_ctx, &node->sn_state, wip) != 0)
453*7961SNatalie.Li@Sun.COM 		return (-1);
454*7961SNatalie.Li@Sun.COM 
455*7961SNatalie.Li@Sun.COM 	/* Insert into AVL tree. */
456*7961SNatalie.Li@Sun.COM 	uu_avl_node_init(node, &node->sn_node, mgr_ctx->mc_svcs_pool);
457*7961SNatalie.Li@Sun.COM 	(void) uu_avl_find(mgr_ctx->mc_svcs, node,
458*7961SNatalie.Li@Sun.COM 	    &mgr_ctx->mc_scf_max_fmri_len, &idx);
459*7961SNatalie.Li@Sun.COM 	uu_avl_insert(mgr_ctx->mc_svcs, node, idx);
460*7961SNatalie.Li@Sun.COM 
461*7961SNatalie.Li@Sun.COM 	return (0);
462*7961SNatalie.Li@Sun.COM }
463*7961SNatalie.Li@Sun.COM 
464*7961SNatalie.Li@Sun.COM /*
465*7961SNatalie.Li@Sun.COM  * svcctl_scm_map_status
466*7961SNatalie.Li@Sun.COM  *
467*7961SNatalie.Li@Sun.COM  * Report the service status.
468*7961SNatalie.Li@Sun.COM  *
469*7961SNatalie.Li@Sun.COM  * The mapping between the Microsoft service states and SMF service states
470*7961SNatalie.Li@Sun.COM  * are as follows.
471*7961SNatalie.Li@Sun.COM  *
472*7961SNatalie.Li@Sun.COM  * SMF service states
473*7961SNatalie.Li@Sun.COM  * ==================
474*7961SNatalie.Li@Sun.COM  *	SCF_STATE_UNINIT                0x00000001
475*7961SNatalie.Li@Sun.COM  *	SCF_STATE_MAINT                 0x00000002
476*7961SNatalie.Li@Sun.COM  *	SCF_STATE_OFFLINE               0x00000004
477*7961SNatalie.Li@Sun.COM  *	SCF_STATE_DISABLED              0x00000008
478*7961SNatalie.Li@Sun.COM  *	SCF_STATE_ONLINE                0x00000010
479*7961SNatalie.Li@Sun.COM  *	SCF_STATE_DEGRADED              0x00000020
480*7961SNatalie.Li@Sun.COM  *	SCF_STATE_ALL                   0x0000003F
481*7961SNatalie.Li@Sun.COM  *
482*7961SNatalie.Li@Sun.COM  * Microsoft service states
483*7961SNatalie.Li@Sun.COM  * ========================
484*7961SNatalie.Li@Sun.COM  *	SERVICE_CONTINUE_PENDING	0x00000005
485*7961SNatalie.Li@Sun.COM  *	SERVICE_PAUSE_PENDING		0x00000006
486*7961SNatalie.Li@Sun.COM  *	SERVICE_PAUSED			0x00000007
487*7961SNatalie.Li@Sun.COM  *	SERVICE_RUNNING			0x00000004
488*7961SNatalie.Li@Sun.COM  *	SERVICE_START_PENDING		0x00000002
489*7961SNatalie.Li@Sun.COM  *	SERVICE_STOP_PENDING		0x00000003
490*7961SNatalie.Li@Sun.COM  *	SERVICE_STOPPED			0x00000001
491*7961SNatalie.Li@Sun.COM  *
492*7961SNatalie.Li@Sun.COM  * Mapping
493*7961SNatalie.Li@Sun.COM  * =======
494*7961SNatalie.Li@Sun.COM  *
495*7961SNatalie.Li@Sun.COM  *	SCF_STATE_ONLINE	<->	SERVICE_RUNNING
496*7961SNatalie.Li@Sun.COM  *	SCF_STATE_OFFLINE	<->	SERVICE_PAUSED
497*7961SNatalie.Li@Sun.COM  *	SCF_STATE_DISABLED	<->	SERVICE_STOPPED
498*7961SNatalie.Li@Sun.COM  *	SCF_STATE_UNINIT	<->	SERVICE_START_PENDING
499*7961SNatalie.Li@Sun.COM  *	SCF_STATE_DEGRADED	<->	SERVICE_STOP_PENDING
500*7961SNatalie.Li@Sun.COM  *	SCF_STATE_MAINT		<->	SERVICE_PAUSE_PENDING
501*7961SNatalie.Li@Sun.COM  *	SCF_STATE_STRING_LEGACY <->	SERVICE_RUNNING
502*7961SNatalie.Li@Sun.COM  *	Service Transitioning	<->	SERVICE_STOP_PENDING
503*7961SNatalie.Li@Sun.COM  */
504*7961SNatalie.Li@Sun.COM uint32_t
505*7961SNatalie.Li@Sun.COM svcctl_scm_map_status(const char *state)
506*7961SNatalie.Li@Sun.COM {
507*7961SNatalie.Li@Sun.COM 	int i;
508*7961SNatalie.Li@Sun.COM 
509*7961SNatalie.Li@Sun.COM 	struct {
510*7961SNatalie.Li@Sun.COM 		const char	*scf_state;
511*7961SNatalie.Li@Sun.COM 		uint32_t	scm_state;
512*7961SNatalie.Li@Sun.COM 	} state_map[] = {
513*7961SNatalie.Li@Sun.COM 		{ SCF_STATE_STRING_ONLINE,	SERVICE_RUNNING },
514*7961SNatalie.Li@Sun.COM 		{ SCF_STATE_STRING_OFFLINE,	SERVICE_PAUSED },
515*7961SNatalie.Li@Sun.COM 		{ SCF_STATE_STRING_DISABLED,	SERVICE_STOPPED },
516*7961SNatalie.Li@Sun.COM 		{ SCF_STATE_STRING_UNINIT,	SERVICE_START_PENDING },
517*7961SNatalie.Li@Sun.COM 		{ SCF_STATE_STRING_DEGRADED,	SERVICE_STOP_PENDING },
518*7961SNatalie.Li@Sun.COM 		{ SCF_STATE_STRING_MAINT,	SERVICE_PAUSE_PENDING },
519*7961SNatalie.Li@Sun.COM 		{ SCF_STATE_STRING_LEGACY,	SERVICE_RUNNING }
520*7961SNatalie.Li@Sun.COM 	};
521*7961SNatalie.Li@Sun.COM 
522*7961SNatalie.Li@Sun.COM 	for (i = 0; i < (sizeof (state_map)/sizeof (state_map[0])); ++i) {
523*7961SNatalie.Li@Sun.COM 		if (strcmp(state, state_map[i].scf_state) == 0)
524*7961SNatalie.Li@Sun.COM 			return (state_map[i].scm_state);
525*7961SNatalie.Li@Sun.COM 	}
526*7961SNatalie.Li@Sun.COM 
527*7961SNatalie.Li@Sun.COM 	if (strrchr(state, '*') != 0)	/* State Transitioning */
528*7961SNatalie.Li@Sun.COM 		return (SERVICE_STOP_PENDING);
529*7961SNatalie.Li@Sun.COM 
530*7961SNatalie.Li@Sun.COM 	return (SERVICE_RUNNING);
531*7961SNatalie.Li@Sun.COM }
532*7961SNatalie.Li@Sun.COM 
533*7961SNatalie.Li@Sun.COM /*
534*7961SNatalie.Li@Sun.COM  * svcctl_scm_enum_services
535*7961SNatalie.Li@Sun.COM  *
536*7961SNatalie.Li@Sun.COM  * Enumerates all SMF services.
537*7961SNatalie.Li@Sun.COM  */
538*7961SNatalie.Li@Sun.COM void
539*7961SNatalie.Li@Sun.COM svcctl_scm_enum_services(svcctl_manager_context_t *mgr_ctx,
540*7961SNatalie.Li@Sun.COM     unsigned char *services)
541*7961SNatalie.Li@Sun.COM {
542*7961SNatalie.Li@Sun.COM 	svcctl_svc_node_t *node = NULL;
543*7961SNatalie.Li@Sun.COM 	int base_offset, offset, i;
544*7961SNatalie.Li@Sun.COM 	mts_wchar_t *wide_name;
545*7961SNatalie.Li@Sun.COM 	char *name;
546*7961SNatalie.Li@Sun.COM 
547*7961SNatalie.Li@Sun.COM 	/*LINTED E_BAD_PTR_CAST_ALIGN*/
548*7961SNatalie.Li@Sun.COM 	svc_enum_status_t *svc = (svc_enum_status_t *)services;
549*7961SNatalie.Li@Sun.COM 
550*7961SNatalie.Li@Sun.COM 	base_offset = mgr_ctx->mc_scf_numsvcs * sizeof (svc_enum_status_t);
551*7961SNatalie.Li@Sun.COM 
552*7961SNatalie.Li@Sun.COM 	offset = base_offset;
553*7961SNatalie.Li@Sun.COM 	node = uu_avl_first(mgr_ctx->mc_svcs);
554*7961SNatalie.Li@Sun.COM 
555*7961SNatalie.Li@Sun.COM 	for (i = 0; ((i < mgr_ctx->mc_scf_numsvcs) && (node != NULL)); ++i) {
556*7961SNatalie.Li@Sun.COM 		svc[i].svc_name = offset;
557*7961SNatalie.Li@Sun.COM 		/*LINTED E_BAD_PTR_CAST_ALIGN*/
558*7961SNatalie.Li@Sun.COM 		wide_name = (mts_wchar_t *)&services[offset];
559*7961SNatalie.Li@Sun.COM 		name = node->sn_name;
560*7961SNatalie.Li@Sun.COM 		(void) mts_mbstowcs(wide_name, name, (strlen(name) + 1));
561*7961SNatalie.Li@Sun.COM 
562*7961SNatalie.Li@Sun.COM 		offset += SVCCTL_WNSTRLEN(name);
563*7961SNatalie.Li@Sun.COM 
564*7961SNatalie.Li@Sun.COM 		svc[i].display_name = offset;
565*7961SNatalie.Li@Sun.COM 		/*LINTED E_BAD_PTR_CAST_ALIGN*/
566*7961SNatalie.Li@Sun.COM 		wide_name = (mts_wchar_t *)&services[offset];
567*7961SNatalie.Li@Sun.COM 		name = node->sn_fmri;
568*7961SNatalie.Li@Sun.COM 		(void) mts_mbstowcs(wide_name, name, (strlen(name) + 1));
569*7961SNatalie.Li@Sun.COM 
570*7961SNatalie.Li@Sun.COM 		offset += SVCCTL_WNSTRLEN(name);
571*7961SNatalie.Li@Sun.COM 
572*7961SNatalie.Li@Sun.COM 		svc[i].svc_status.cur_state =
573*7961SNatalie.Li@Sun.COM 		    svcctl_scm_map_status(node->sn_state);
574*7961SNatalie.Li@Sun.COM 		svc[i].svc_status.service_type = SERVICE_WIN32_SHARE_PROCESS;
575*7961SNatalie.Li@Sun.COM 		svc[i].svc_status.ctrl_accepted = 0;
576*7961SNatalie.Li@Sun.COM 		svc[i].svc_status.w32_exitcode = 0;
577*7961SNatalie.Li@Sun.COM 		svc[i].svc_status.svc_specified_exitcode = 0;
578*7961SNatalie.Li@Sun.COM 		svc[i].svc_status.check_point = 0;
579*7961SNatalie.Li@Sun.COM 		svc[i].svc_status.wait_hint = 0;
580*7961SNatalie.Li@Sun.COM 
581*7961SNatalie.Li@Sun.COM 		node = uu_avl_next(mgr_ctx->mc_svcs, node);
582*7961SNatalie.Li@Sun.COM 	}
583*7961SNatalie.Li@Sun.COM }
584*7961SNatalie.Li@Sun.COM 
585*7961SNatalie.Li@Sun.COM /*
586*7961SNatalie.Li@Sun.COM  * svcctl_scm_cb_bytes_needed
587*7961SNatalie.Li@Sun.COM  *
588*7961SNatalie.Li@Sun.COM  * Callback function to calculate bytes needed to enumerate SMF services.
589*7961SNatalie.Li@Sun.COM  */
590*7961SNatalie.Li@Sun.COM static int
591*7961SNatalie.Li@Sun.COM svcctl_scm_cb_bytes_needed(void *svc_node, void *byte_cnt)
592*7961SNatalie.Li@Sun.COM {
593*7961SNatalie.Li@Sun.COM 	svcctl_svc_node_t *node = svc_node;
594*7961SNatalie.Li@Sun.COM 	int *cnt = byte_cnt;
595*7961SNatalie.Li@Sun.COM 
596*7961SNatalie.Li@Sun.COM 	*cnt += (strlen(node->sn_fmri) + 1) * sizeof (mts_wchar_t);
597*7961SNatalie.Li@Sun.COM 	*cnt += (strlen(node->sn_name) + 1) * sizeof (mts_wchar_t);
598*7961SNatalie.Li@Sun.COM 
599*7961SNatalie.Li@Sun.COM 	return (UU_WALK_NEXT);
600*7961SNatalie.Li@Sun.COM }
601*7961SNatalie.Li@Sun.COM 
602*7961SNatalie.Li@Sun.COM /*
603*7961SNatalie.Li@Sun.COM  * svcctl_scm_bytes_needed
604*7961SNatalie.Li@Sun.COM  *
605*7961SNatalie.Li@Sun.COM  * Calculates bytes needed to enumerate SMF services.
606*7961SNatalie.Li@Sun.COM  */
607*7961SNatalie.Li@Sun.COM void
608*7961SNatalie.Li@Sun.COM svcctl_scm_bytes_needed(svcctl_manager_context_t *mgr_ctx)
609*7961SNatalie.Li@Sun.COM {
610*7961SNatalie.Li@Sun.COM 	int bytes_needed = 0, svc_enum_status_size = 0;
611*7961SNatalie.Li@Sun.COM 
612*7961SNatalie.Li@Sun.COM 	(void) uu_avl_walk(mgr_ctx->mc_svcs, svcctl_scm_cb_bytes_needed,
613*7961SNatalie.Li@Sun.COM 	    &bytes_needed, 0);
614*7961SNatalie.Li@Sun.COM 
615*7961SNatalie.Li@Sun.COM 	svc_enum_status_size =
616*7961SNatalie.Li@Sun.COM 	    mgr_ctx->mc_scf_numsvcs * sizeof (svc_enum_status_t);
617*7961SNatalie.Li@Sun.COM 	bytes_needed += svc_enum_status_size;
618*7961SNatalie.Li@Sun.COM 
619*7961SNatalie.Li@Sun.COM 	mgr_ctx->mc_bytes_needed = bytes_needed;
620*7961SNatalie.Li@Sun.COM }
621*7961SNatalie.Li@Sun.COM 
622*7961SNatalie.Li@Sun.COM /*
623*7961SNatalie.Li@Sun.COM  * svcctl_scm_validate_service
624*7961SNatalie.Li@Sun.COM  *
625*7961SNatalie.Li@Sun.COM  * Check to see whether or not a service is supported.
626*7961SNatalie.Li@Sun.COM  *
627*7961SNatalie.Li@Sun.COM  * Returns:
628*7961SNatalie.Li@Sun.COM  *	ERROR_SUCCESS
629*7961SNatalie.Li@Sun.COM  *	ERROR_SERVICE_DOES_NOT_EXIST
630*7961SNatalie.Li@Sun.COM  */
631*7961SNatalie.Li@Sun.COM uint32_t
632*7961SNatalie.Li@Sun.COM svcctl_scm_validate_service(svcctl_manager_context_t *mgr_ctx, char *svc_name)
633*7961SNatalie.Li@Sun.COM {
634*7961SNatalie.Li@Sun.COM 	svcctl_svc_node_t node;
635*7961SNatalie.Li@Sun.COM 	uu_avl_index_t idx;
636*7961SNatalie.Li@Sun.COM 
637*7961SNatalie.Li@Sun.COM 	if (svc_name == NULL)
638*7961SNatalie.Li@Sun.COM 		return (ERROR_SERVICE_DOES_NOT_EXIST);
639*7961SNatalie.Li@Sun.COM 
640*7961SNatalie.Li@Sun.COM 	bzero(&node, sizeof (svcctl_svc_node_t));
641*7961SNatalie.Li@Sun.COM 	node.sn_name = svc_name;
642*7961SNatalie.Li@Sun.COM 	if (uu_avl_find(mgr_ctx->mc_svcs, &node,
643*7961SNatalie.Li@Sun.COM 	    &mgr_ctx->mc_scf_max_fmri_len, &idx) != NULL)
644*7961SNatalie.Li@Sun.COM 		return (ERROR_SUCCESS);
645*7961SNatalie.Li@Sun.COM 
646*7961SNatalie.Li@Sun.COM 	return (ERROR_SERVICE_DOES_NOT_EXIST);
647*7961SNatalie.Li@Sun.COM }
648*7961SNatalie.Li@Sun.COM 
649*7961SNatalie.Li@Sun.COM /*
650*7961SNatalie.Li@Sun.COM  * svcctl_scm_find_service
651*7961SNatalie.Li@Sun.COM  *
652*7961SNatalie.Li@Sun.COM  * Lookup a service.
653*7961SNatalie.Li@Sun.COM  */
654*7961SNatalie.Li@Sun.COM svcctl_svc_node_t *
655*7961SNatalie.Li@Sun.COM svcctl_scm_find_service(svcctl_manager_context_t *mgr_ctx, char *svc_name)
656*7961SNatalie.Li@Sun.COM {
657*7961SNatalie.Li@Sun.COM 	svcctl_svc_node_t node;
658*7961SNatalie.Li@Sun.COM 	uu_avl_index_t idx;
659*7961SNatalie.Li@Sun.COM 	svcctl_svc_node_t *f_node = NULL;
660*7961SNatalie.Li@Sun.COM 
661*7961SNatalie.Li@Sun.COM 	if (svc_name == NULL)
662*7961SNatalie.Li@Sun.COM 		return (NULL);
663*7961SNatalie.Li@Sun.COM 
664*7961SNatalie.Li@Sun.COM 	bzero(&node, sizeof (svcctl_svc_node_t));
665*7961SNatalie.Li@Sun.COM 	node.sn_name = svc_name;
666*7961SNatalie.Li@Sun.COM 	f_node = uu_avl_find(mgr_ctx->mc_svcs, &node,
667*7961SNatalie.Li@Sun.COM 	    &mgr_ctx->mc_scf_max_fmri_len, &idx);
668*7961SNatalie.Li@Sun.COM 	if (f_node != NULL)
669*7961SNatalie.Li@Sun.COM 		return (f_node);
670*7961SNatalie.Li@Sun.COM 
671*7961SNatalie.Li@Sun.COM 	return (NULL);
672*7961SNatalie.Li@Sun.COM }
673*7961SNatalie.Li@Sun.COM 
674*7961SNatalie.Li@Sun.COM /*
675*7961SNatalie.Li@Sun.COM  * svcctl_scm_refresh
676*7961SNatalie.Li@Sun.COM  *
677*7961SNatalie.Li@Sun.COM  * Refresh SCM services per context.
678*7961SNatalie.Li@Sun.COM  */
679*7961SNatalie.Li@Sun.COM int
680*7961SNatalie.Li@Sun.COM svcctl_scm_refresh(svcctl_manager_context_t *mgr_ctx)
681*7961SNatalie.Li@Sun.COM {
682*7961SNatalie.Li@Sun.COM 	svcctl_scm_fini(mgr_ctx);
683*7961SNatalie.Li@Sun.COM 	return (svcctl_scm_init(mgr_ctx));
684*7961SNatalie.Li@Sun.COM }
685*7961SNatalie.Li@Sun.COM 
686*7961SNatalie.Li@Sun.COM /*
687*7961SNatalie.Li@Sun.COM  * svcctl_scm_scf_handle_init
688*7961SNatalie.Li@Sun.COM  *
689*7961SNatalie.Li@Sun.COM  * Initialize SCF handle per context.
690*7961SNatalie.Li@Sun.COM  */
691*7961SNatalie.Li@Sun.COM int
692*7961SNatalie.Li@Sun.COM svcctl_scm_scf_handle_init(svcctl_manager_context_t *mgr_ctx)
693*7961SNatalie.Li@Sun.COM {
694*7961SNatalie.Li@Sun.COM 	mgr_ctx->mc_scf_hdl = scf_handle_create(SCF_VERSION);
695*7961SNatalie.Li@Sun.COM 	if (mgr_ctx->mc_scf_hdl == NULL)
696*7961SNatalie.Li@Sun.COM 		return (-1);
697*7961SNatalie.Li@Sun.COM 
698*7961SNatalie.Li@Sun.COM 	if (scf_handle_bind(mgr_ctx->mc_scf_hdl) == -1) {
699*7961SNatalie.Li@Sun.COM 		scf_handle_destroy(mgr_ctx->mc_scf_hdl);
700*7961SNatalie.Li@Sun.COM 		return (-1);
701*7961SNatalie.Li@Sun.COM 	}
702*7961SNatalie.Li@Sun.COM 
703*7961SNatalie.Li@Sun.COM 	mgr_ctx->mc_scf_gpg = scf_pg_create(mgr_ctx->mc_scf_hdl);
704*7961SNatalie.Li@Sun.COM 	mgr_ctx->mc_scf_gprop = scf_property_create(mgr_ctx->mc_scf_hdl);
705*7961SNatalie.Li@Sun.COM 	mgr_ctx->mc_scf_gval = scf_value_create(mgr_ctx->mc_scf_hdl);
706*7961SNatalie.Li@Sun.COM 
707*7961SNatalie.Li@Sun.COM 	if ((mgr_ctx->mc_scf_gpg == NULL) ||
708*7961SNatalie.Li@Sun.COM 	    (mgr_ctx->mc_scf_gprop == NULL) ||
709*7961SNatalie.Li@Sun.COM 	    (mgr_ctx->mc_scf_gval == NULL)) {
710*7961SNatalie.Li@Sun.COM 		(void) scf_handle_unbind(mgr_ctx->mc_scf_hdl);
711*7961SNatalie.Li@Sun.COM 		scf_handle_destroy(mgr_ctx->mc_scf_hdl);
712*7961SNatalie.Li@Sun.COM 		return (-1);
713*7961SNatalie.Li@Sun.COM 	}
714*7961SNatalie.Li@Sun.COM 
715*7961SNatalie.Li@Sun.COM 	mgr_ctx->mc_scf_max_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
716*7961SNatalie.Li@Sun.COM 	mgr_ctx->mc_scf_max_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
717*7961SNatalie.Li@Sun.COM 
718*7961SNatalie.Li@Sun.COM 	return (0);
719*7961SNatalie.Li@Sun.COM }
720*7961SNatalie.Li@Sun.COM 
721*7961SNatalie.Li@Sun.COM /*
722*7961SNatalie.Li@Sun.COM  * svcctl_scm_scf_handle_init
723*7961SNatalie.Li@Sun.COM  *
724*7961SNatalie.Li@Sun.COM  * Destroy SCF handle per context.
725*7961SNatalie.Li@Sun.COM  */
726*7961SNatalie.Li@Sun.COM void
727*7961SNatalie.Li@Sun.COM svcctl_scm_scf_handle_fini(svcctl_manager_context_t *mgr_ctx)
728*7961SNatalie.Li@Sun.COM {
729*7961SNatalie.Li@Sun.COM 	scf_value_destroy(mgr_ctx->mc_scf_gval);
730*7961SNatalie.Li@Sun.COM 	scf_property_destroy(mgr_ctx->mc_scf_gprop);
731*7961SNatalie.Li@Sun.COM 	scf_pg_destroy(mgr_ctx->mc_scf_gpg);
732*7961SNatalie.Li@Sun.COM 	(void) scf_handle_unbind(mgr_ctx->mc_scf_hdl);
733*7961SNatalie.Li@Sun.COM 	scf_handle_destroy(mgr_ctx->mc_scf_hdl);
734*7961SNatalie.Li@Sun.COM }
735*7961SNatalie.Li@Sun.COM 
736*7961SNatalie.Li@Sun.COM /*
737*7961SNatalie.Li@Sun.COM  * svcctl_scm_init
738*7961SNatalie.Li@Sun.COM  *
739*7961SNatalie.Li@Sun.COM  * Initialize SCM repository per context.
740*7961SNatalie.Li@Sun.COM  * SCM repository holds a list of SMF services.
741*7961SNatalie.Li@Sun.COM  * Each SMF service node contains state, description and FMRI.
742*7961SNatalie.Li@Sun.COM  */
743*7961SNatalie.Li@Sun.COM int
744*7961SNatalie.Li@Sun.COM svcctl_scm_init(svcctl_manager_context_t *mgr_ctx)
745*7961SNatalie.Li@Sun.COM {
746*7961SNatalie.Li@Sun.COM 	int exit_status = 0;
747*7961SNatalie.Li@Sun.COM 
748*7961SNatalie.Li@Sun.COM 	assert(mgr_ctx->mc_svcs_pool == NULL);
749*7961SNatalie.Li@Sun.COM 	assert(mgr_ctx->mc_svcs == NULL);
750*7961SNatalie.Li@Sun.COM 
751*7961SNatalie.Li@Sun.COM 	mgr_ctx->mc_svcs_pool = uu_avl_pool_create("smf_svcs_pool",
752*7961SNatalie.Li@Sun.COM 	    sizeof (svcctl_svc_node_t), offsetof(svcctl_svc_node_t, sn_node),
753*7961SNatalie.Li@Sun.COM 	    svcctl_scm_avl_nodecmp, UU_AVL_DEBUG);
754*7961SNatalie.Li@Sun.COM 
755*7961SNatalie.Li@Sun.COM 	if (mgr_ctx->mc_svcs_pool == NULL)
756*7961SNatalie.Li@Sun.COM 		return (-1);
757*7961SNatalie.Li@Sun.COM 
758*7961SNatalie.Li@Sun.COM 	mgr_ctx->mc_svcs = uu_avl_create(mgr_ctx->mc_svcs_pool, NULL, 0);
759*7961SNatalie.Li@Sun.COM 	if (mgr_ctx->mc_svcs == NULL) {
760*7961SNatalie.Li@Sun.COM 		uu_avl_pool_destroy(mgr_ctx->mc_svcs_pool);
761*7961SNatalie.Li@Sun.COM 		return (-1);
762*7961SNatalie.Li@Sun.COM 	}
763*7961SNatalie.Li@Sun.COM 
764*7961SNatalie.Li@Sun.COM 	if (scf_walk_fmri(mgr_ctx->mc_scf_hdl, 0, NULL,
765*7961SNatalie.Li@Sun.COM 	    SCF_WALK_MULTIPLE | SCF_WALK_LEGACY,
766*7961SNatalie.Li@Sun.COM 	    svcctl_scm_cb_list_svcinst, mgr_ctx, &exit_status, NULL) != 0) {
767*7961SNatalie.Li@Sun.COM 		uu_avl_destroy(mgr_ctx->mc_svcs);
768*7961SNatalie.Li@Sun.COM 		uu_avl_pool_destroy(mgr_ctx->mc_svcs_pool);
769*7961SNatalie.Li@Sun.COM 		return (-1);
770*7961SNatalie.Li@Sun.COM 	}
771*7961SNatalie.Li@Sun.COM 
772*7961SNatalie.Li@Sun.COM 	mgr_ctx->mc_scf_numsvcs = uu_avl_numnodes(mgr_ctx->mc_svcs);
773*7961SNatalie.Li@Sun.COM 	if (mgr_ctx->mc_scf_numsvcs > 0)
774*7961SNatalie.Li@Sun.COM 		svcctl_scm_bytes_needed(mgr_ctx);
775*7961SNatalie.Li@Sun.COM 
776*7961SNatalie.Li@Sun.COM 	return (0);
777*7961SNatalie.Li@Sun.COM }
778*7961SNatalie.Li@Sun.COM 
779*7961SNatalie.Li@Sun.COM /*
780*7961SNatalie.Li@Sun.COM  * svcctl_scm_fini
781*7961SNatalie.Li@Sun.COM  *
782*7961SNatalie.Li@Sun.COM  * Destroy SCM repository per context.
783*7961SNatalie.Li@Sun.COM  */
784*7961SNatalie.Li@Sun.COM void
785*7961SNatalie.Li@Sun.COM svcctl_scm_fini(svcctl_manager_context_t *mgr_ctx)
786*7961SNatalie.Li@Sun.COM {
787*7961SNatalie.Li@Sun.COM 	uu_avl_walk_t *walk;
788*7961SNatalie.Li@Sun.COM 	svcctl_svc_node_t *node;
789*7961SNatalie.Li@Sun.COM 
790*7961SNatalie.Li@Sun.COM 	if ((mgr_ctx == NULL) || (mgr_ctx->mc_svcs_pool == NULL) ||
791*7961SNatalie.Li@Sun.COM 	    (mgr_ctx->mc_svcs == NULL))
792*7961SNatalie.Li@Sun.COM 		return;
793*7961SNatalie.Li@Sun.COM 
794*7961SNatalie.Li@Sun.COM 	if ((walk =
795*7961SNatalie.Li@Sun.COM 	    uu_avl_walk_start(mgr_ctx->mc_svcs, UU_WALK_ROBUST)) == NULL)
796*7961SNatalie.Li@Sun.COM 		return;
797*7961SNatalie.Li@Sun.COM 
798*7961SNatalie.Li@Sun.COM 	while ((node = uu_avl_walk_next(walk)) != NULL) {
799*7961SNatalie.Li@Sun.COM 		uu_avl_remove(mgr_ctx->mc_svcs, node);
800*7961SNatalie.Li@Sun.COM 		free(node->sn_name);
801*7961SNatalie.Li@Sun.COM 		free(node->sn_fmri);
802*7961SNatalie.Li@Sun.COM 		free(node->sn_desc);
803*7961SNatalie.Li@Sun.COM 		free(node->sn_state);
804*7961SNatalie.Li@Sun.COM 		free(node);
805*7961SNatalie.Li@Sun.COM 	}
806*7961SNatalie.Li@Sun.COM 	uu_avl_walk_end(walk);
807*7961SNatalie.Li@Sun.COM 	uu_avl_destroy(mgr_ctx->mc_svcs);
808*7961SNatalie.Li@Sun.COM 	uu_avl_pool_destroy(mgr_ctx->mc_svcs_pool);
809*7961SNatalie.Li@Sun.COM 	mgr_ctx->mc_svcs_pool = NULL;
810*7961SNatalie.Li@Sun.COM 	mgr_ctx->mc_svcs = NULL;
811*7961SNatalie.Li@Sun.COM }
812