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
meta_smf_enable(uint_t flags,md_error_t * ep)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
meta_smf_disable(uint_t flags,md_error_t * ep)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
meta_smf_isonline(uint_t flags,md_error_t * ep)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
meta_smf_getmask()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
enable(char * svc_names[],md_error_t * ep)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
disable(char * svc_names[],md_error_t * ep)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
enabled(char * svc_name)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
wait_online(char * svc_names[])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
online(char * svc_names[],char ** names)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
is_online(char * svc_name)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