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