xref: /titanic_41/usr/src/lib/lvm/libmeta/common/meta_smf.c (revision da14cebe459d3275048785f25bd869cb09b5307f)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * Service Management Facility (SMF) interfaces.
30  */
31 
32 #include <stdio.h>
33 #include <libscf.h>
34 #include <meta.h>
35 
36 static void enable(char *svc_names[], md_error_t *ep);
37 static void disable(char *svc_names[], md_error_t *ep);
38 static int enabled(char *svc_name);
39 static int online(char *svc_names[], char **names);
40 static void wait_online(char *svc_names[]);
41 static int is_online(char *svc_name);
42 
43 static char
44 *svm_core_svcs[] = {
45 	"system/metainit:default",
46 	"system/metasync:default",
47 	"system/mdmonitor:default",
48 	"network/rpc/meta:default",
49 	NULL
50 };
51 
52 static char
53 *svm_diskset_svcs[] = {
54 	"network/rpc/metamed:default",
55 	"network/rpc/metamh:default",
56 	NULL
57 };
58 
59 static char
60 *svm_mn_diskset_svcs[] = {
61 	"network/rpc/mdcomm:default",
62 	NULL
63 };
64 
65 /*
66  * Enable the specified SVM services through the SMF.
67  */
68 int
69 meta_smf_enable(uint_t flags, md_error_t *ep)
70 {
71 	if (flags & META_SMF_CORE) {
72 		enable(svm_core_svcs, ep);
73 		wait_online(svm_core_svcs);
74 	}
75 
76 	if (flags & META_SMF_DISKSET) {
77 		enable(svm_diskset_svcs, ep);
78 		wait_online(svm_diskset_svcs);
79 	}
80 
81 	if (flags & META_SMF_MN_DISKSET) {
82 		enable(svm_mn_diskset_svcs, ep);
83 		wait_online(svm_mn_diskset_svcs);
84 	}
85 
86 	if (ep != NULL)
87 		return ((mdisok(ep)) ? 0 : -1);
88 	else
89 		return (0);
90 }
91 
92 /*
93  * Disable the specified SVM services through the SMF.
94  */
95 int
96 meta_smf_disable(uint_t flags, md_error_t *ep)
97 {
98 	if (flags & META_SMF_CORE) {
99 		disable(svm_core_svcs, ep);
100 	}
101 
102 	if (flags & META_SMF_DISKSET) {
103 		disable(svm_diskset_svcs, ep);
104 	}
105 
106 	if (flags & META_SMF_MN_DISKSET) {
107 		disable(svm_mn_diskset_svcs, ep);
108 	}
109 
110 	if (ep != NULL)
111 		return ((mdisok(ep)) ? 0 : -1);
112 	else
113 		return (0);
114 }
115 
116 /*
117  * Determine if desired services are online.  If all services in the
118  * classes specified by flags are online, 1 is returned.  Otherwise
119  * 0 is returned.
120  */
121 
122 int
123 meta_smf_isonline(uint_t flags, md_error_t *ep)
124 {
125 	int	ret = 1;
126 	char	*names = NULL;
127 
128 	if (flags & META_SMF_CORE) {
129 		if (online(svm_core_svcs, &names) == 0)
130 			ret = 0;
131 	}
132 	if (flags & META_SMF_DISKSET) {
133 		if (online(svm_diskset_svcs, &names) == 0)
134 			ret = 0;
135 	}
136 	if (flags & META_SMF_MN_DISKSET) {
137 		if (online(svm_mn_diskset_svcs, &names) == 0)
138 			ret = 0;
139 	}
140 
141 	if (ret == 0) {
142 		(void) mderror(ep, MDE_SMF_NO_SERVICE, names);
143 		Free(names);
144 	}
145 
146 	return (ret);
147 }
148 
149 /*
150  * Return a bitmask of the META_SMF_* flags indicating which services should be
151  * online given the current SVM configuration.
152  */
153 int
154 meta_smf_getmask()
155 {
156 	int		mask = 0;
157 	mdsetname_t	*sp = NULL;
158 	mddb_config_t	c;
159 	md_error_t	status = mdnullerror;
160 	md_error_t	*ep = &status;
161 	int		max_sets;
162 
163 	/*
164 	 * If there are any local metadbs configured then the core services
165 	 * are needed.
166 	 */
167 	(void) memset(&c, 0, sizeof (c));
168 	c.c_setno = MD_LOCAL_SET;
169 	if (metaioctl(MD_DB_GETDEV, &c, &c.c_mde, NULL) != 0 || c.c_dbcnt == 0)
170 		return (mask);
171 
172 	mask |= META_SMF_CORE;
173 
174 	/*
175 	 * If any disksets configured then the diskset services are needed.
176 	 * Also check for multi-node sets.
177 	 */
178 	if ((max_sets = get_max_sets(ep)) > 0) {
179 		int i;
180 
181 		mdclrerror(ep);
182 		for (i = 1; i < max_sets; i++) {
183 			md_set_desc	*sd;
184 
185 			if ((sp = metasetnosetname(i, ep)) == NULL) {
186 				if (!mdisok(ep) && !mdiserror(ep, MDE_NO_SET) &&
187 				    !mdismddberror(ep, MDE_NOTENOUGH_DB) &&
188 				    !mdiserror(ep, MDE_SMF_NO_SERVICE) &&
189 				    ep->info.errclass != MDEC_RPC) {
190 					/*
191 					 * metad rpc program not registered
192 					 * can't get diskset info
193 					 */
194 					break;
195 				}
196 
197 			} else {
198 				mask |= META_SMF_DISKSET;
199 
200 				if ((sd = metaget_setdesc(sp, ep)) != NULL) {
201 					if (MD_MNSET_DESC(sd)) {
202 						mask |= META_SMF_MN_DISKSET;
203 
204 						/*
205 						 * we don't have to check the
206 						 * rest of the disksets at this
207 						 * point
208 						 */
209 						break;
210 					}
211 				}
212 			}
213 
214 			mdclrerror(ep);
215 		}
216 	}
217 
218 	return (mask);
219 }
220 
221 static void
222 enable(char *svc_names[], md_error_t *ep)
223 {
224 	int i;
225 
226 	for (i = 0; svc_names[i]; i++) {
227 		if (!enabled(svc_names[i]))
228 			if (smf_enable_instance(svc_names[i], 0) != 0) {
229 				if (ep != NULL) {
230 					(void) mderror(ep, MDE_SMF_FAIL,
231 					    svc_names[i]);
232 				}
233 			}
234 	}
235 }
236 
237 static void
238 disable(char *svc_names[], md_error_t *ep)
239 {
240 	int i;
241 
242 	for (i = 0; svc_names[i]; i++) {
243 		if (enabled(svc_names[i]))
244 			if (smf_disable_instance(svc_names[i], 0) != 0) {
245 				if (ep != NULL) {
246 					(void) mderror(ep, MDE_SMF_FAIL,
247 					    svc_names[i]);
248 				}
249 			}
250 	}
251 }
252 
253 static int
254 enabled(char *svc_name)
255 {
256 	scf_simple_prop_t	*prop;
257 	int			rval = 0;
258 
259 	prop = scf_simple_prop_get(NULL, svc_name, SCF_PG_GENERAL,
260 		SCF_PROPERTY_ENABLED);
261 
262 	if (scf_simple_prop_numvalues(prop) == 1) {
263 		if (*scf_simple_prop_next_boolean(prop) != 0)
264 			rval = 1;
265 	}
266 
267 	scf_simple_prop_free(prop);
268 
269 	return (rval);
270 }
271 
272 /*
273  * There can be a delay while the RPC services get going.  Try to
274  * make sure the RPC daemons are ready to run before we return.
275  * Check 15 times (15 seconds total wait time) and then just
276  * return.
277  */
278 static void
279 wait_online(char *svc_names[])
280 {
281 	int i;
282 	char	*names = NULL;
283 
284 	for (i = 0; i < 15; i++) {
285 		if (online(svc_names, &names))
286 			break;
287 		(void) sleep(1);
288 	}
289 
290 	if (names != NULL)
291 		Free(names);
292 }
293 
294 /*
295  * Check to see if all services in the svc_names are online.  If they are
296  * all online 1 is returned, otherwise 0 is returned.
297  */
298 
299 static int
300 online(char *svc_names[], char **names)
301 {
302 	int i;
303 	int rv = 1;
304 
305 	for (i = 0; svc_names[i]; i++) {
306 		if (is_online(svc_names[i]) == 0) {
307 			int sz;
308 			char *p;
309 
310 			/*
311 			 * Need space for the name, the new line, the
312 			 * tab and the null terminator.
313 			 */
314 			sz = strlen(svc_names[i]) + 3;
315 
316 			if (*names == NULL) {
317 				p = Malloc(sz);
318 				(void) snprintf(p, sz, "\n\t%s", svc_names[i]);
319 
320 			} else {
321 				/* Add space for existing names */
322 				sz += strlen(*names);
323 				p = Malloc(sz);
324 				(void) snprintf(p, sz, "%s\n\t%s", *names,
325 				    svc_names[i]);
326 				Free(*names);
327 			}
328 
329 			*names = p;
330 			rv = 0;
331 		}
332 	}
333 	return (rv);
334 }
335 
336 /*
337  * Return 1 if the specified service is online.  Otherwise, return 0.
338  */
339 static int
340 is_online(char *svc_name)
341 {
342 	int	rval = 0;
343 	char	*s;
344 
345 	if ((s = smf_get_state(svc_name)) != NULL) {
346 		if (strcmp(s, "online") == 0)
347 			rval = 1;
348 		free(s);
349 	}
350 	return (rval);
351 }
352