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 /* |
|
23 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. |
|
24 */ |
|
25 |
|
26 #include <sys/list.h> |
|
27 #include <sys/types.h> |
|
28 #include <sys/stat.h> |
|
29 #include <string.h> |
|
30 #include <stdio.h> |
|
31 #include <stdlib.h> |
|
32 #include <stddef.h> |
|
33 #include <unistd.h> |
|
34 #include <fcntl.h> |
|
35 #include <libscf.h> |
|
36 #include <libscf_priv.h> |
|
37 #include <rad/adr.h> |
|
38 #include <rad/rad_modapi.h> |
|
39 |
|
40 #include "api_smf_old.h" |
|
41 #include "propvec.h" |
|
42 |
|
43 static pthread_mutex_t service_lock = PTHREAD_MUTEX_INITIALIZER; |
|
44 static list_t service_list; |
|
45 static list_t instance_list; |
|
46 static rad_instance_t *agg_inst; |
|
47 static int service_count = 0; |
|
48 static int instance_count = 0; |
|
49 |
|
50 typedef struct servinst { |
|
51 char *sname; /* Service name */ |
|
52 char *iname; /* Instance name */ |
|
53 char *fmri; /* FMRI */ |
|
54 rad_instance_t *inst; /* rad object instance */ |
|
55 boolean_t instance; |
|
56 |
|
57 int ninstances; |
|
58 list_t instances; /* A service's instances */ |
|
59 list_node_t node; /* Membership in the global list */ |
|
60 list_node_t snode; /* An instance's membership in its service */ |
|
61 } servinst_t; |
|
62 |
|
63 static const char *framework_pgtypes[] = { |
|
64 SCF_GROUP_FRAMEWORK, |
|
65 SCF_GROUP_DEPENDENCY, |
|
66 SCF_GROUP_METHOD, |
|
67 SCF_GROUP_TEMPLATE, |
|
68 SCF_GROUP_TEMPLATE_PG_PATTERN, |
|
69 SCF_GROUP_TEMPLATE_PROP_PATTERN, |
|
70 NULL |
|
71 }; |
|
72 |
|
73 static conerr_t |
|
74 error_scf(adr_data_t **error, int code) |
|
75 { |
|
76 if (error != NULL) { |
|
77 adr_data_t *e = adr_data_new_struct(&t__SmfError); |
|
78 adr_struct_set(e, "error", |
|
79 adr_data_new_enum(&t__SmfErrorCode, code)); |
|
80 adr_struct_set(e, "message", |
|
81 adr_data_new_string(scf_strerror(code), LT_CONST)); |
|
82 *error = adr_data_purify(e); |
|
83 } |
|
84 return (CE_OBJECT); |
|
85 } |
|
86 |
|
87 static conerr_t |
|
88 simple_scf(adr_data_t **error, int result) |
|
89 { |
|
90 if (result == 0) |
|
91 return (CE_OK); |
|
92 return (error_scf(error, scf_error())); |
|
93 } |
|
94 |
|
95 static boolean_t |
|
96 strinset(const char **set, const char *str) |
|
97 { |
|
98 for (; *set != NULL; set++) |
|
99 if (strcmp(*set, str) == 0) |
|
100 return (B_TRUE); |
|
101 return (B_FALSE); |
|
102 } |
|
103 |
|
104 static boolean_t |
|
105 strnotinset(const char **set, const char *str) |
|
106 { |
|
107 return (!strinset(set, str)); |
|
108 } |
|
109 |
|
110 scf_handle_t * |
|
111 handle_create(void) |
|
112 { |
|
113 scf_handle_t *h = scf_handle_create(SCF_VERSION); |
|
114 if (h == NULL) |
|
115 return (NULL); |
|
116 |
|
117 if (scf_handle_bind(h) == -1) { |
|
118 scf_handle_destroy(h); |
|
119 return (NULL); |
|
120 } |
|
121 return (h); |
|
122 } |
|
123 |
|
124 static int getpgs(servinst_t *si, adr_data_t **data, boolean_t namesonly, |
|
125 boolean_t(*fp)(const char **, const char *), const char **set, |
|
126 adr_data_t **error) |
|
127 { |
|
128 conerr_t err = CE_OK; |
|
129 scf_handle_t *scfhandle = handle_create(); |
|
130 scf_service_t *service = scf_service_create(scfhandle); |
|
131 scf_instance_t *instance = scf_instance_create(scfhandle); |
|
132 scf_snapshot_t *snap = scf_snapshot_create(scfhandle); |
|
133 scf_iter_t *iter = scf_iter_create(scfhandle); |
|
134 scf_propertygroup_t *pg = scf_pg_create(scfhandle); |
|
135 |
|
136 if (scf_handle_decode_fmri(scfhandle, si->fmri, NULL, service, |
|
137 instance, NULL, NULL, 0) != SCF_SUCCESS) { |
|
138 rad_log(RL_WARN, "Couldn't decode '%s': %s\n", si->fmri, |
|
139 scf_strerror(scf_error())); |
|
140 err = error_scf(error, scf_error()); |
|
141 goto out; |
|
142 } |
|
143 |
|
144 if (si->instance) { |
|
145 if (scf_instance_get_snapshot(instance, "running", snap) != 0 || |
|
146 scf_iter_instance_pgs_composed(iter, instance, snap) |
|
147 != SCF_SUCCESS) { |
|
148 err = error_scf(error, scf_error()); |
|
149 goto out; |
|
150 } |
|
151 } else { |
|
152 if (scf_iter_service_pgs(iter, service) != SCF_SUCCESS) { |
|
153 rad_log(RL_WARN, "failed to initialize iterator: %s\n", |
|
154 scf_strerror(scf_error())); |
|
155 err = error_scf(error, scf_error()); |
|
156 goto out; |
|
157 } |
|
158 } |
|
159 |
|
160 adr_data_t *result = namesonly ? |
|
161 adr_data_new_array(&adr_t_array_string, 5) : |
|
162 adr_data_new_array(&t_array__PropertyGroup, 5); |
|
163 while (scf_iter_next_pg(iter, pg) > 0) { |
|
164 char nbuf[1000]; |
|
165 char tbuf[1000]; |
|
166 (void) scf_pg_get_name(pg, nbuf, 1000); |
|
167 (void) scf_pg_get_type(pg, tbuf, 1000); |
|
168 |
|
169 if (fp(set, tbuf)) { |
|
170 if (namesonly) { |
|
171 (void) adr_array_add(result, |
|
172 adr_data_new_string(nbuf, LT_COPY)); |
|
173 } else { |
|
174 adr_data_t *pgdata = |
|
175 adr_data_new_struct(&t__PropertyGroup); |
|
176 adr_struct_set(pgdata, "name", |
|
177 adr_data_new_string(nbuf, LT_COPY)); |
|
178 adr_struct_set(pgdata, "type", |
|
179 adr_data_new_string(tbuf, LT_COPY)); |
|
180 (void) adr_array_add(result, pgdata); |
|
181 } |
|
182 } |
|
183 } |
|
184 |
|
185 *data = result; |
|
186 |
|
187 out: |
|
188 scf_pg_destroy(pg); |
|
189 scf_snapshot_destroy(snap); |
|
190 scf_iter_destroy(iter); |
|
191 scf_instance_destroy(instance); |
|
192 scf_service_destroy(service); |
|
193 scf_handle_destroy(scfhandle); |
|
194 |
|
195 return (err); |
|
196 } |
|
197 |
|
198 /* ARGSUSED */ |
|
199 conerr_t |
|
200 interface_ServiceInfo_read_fmri(rad_instance_t *inst, adr_attribute_t *attr, |
|
201 adr_data_t **data, adr_data_t **error) |
|
202 { |
|
203 servinst_t *si = rad_instance_getdata(inst); |
|
204 *data = adr_data_new_string(si->fmri, LT_COPY); |
|
205 return (CE_OK); |
|
206 } |
|
207 |
|
208 /* ARGSUSED */ |
|
209 conerr_t |
|
210 interface_ServiceInfo_read_methodNames(rad_instance_t *inst, |
|
211 adr_attribute_t *attr, adr_data_t **data, adr_data_t **error) |
|
212 { |
|
213 const char *pgtypes[] = { SCF_GROUP_METHOD, NULL }; |
|
214 return (getpgs(rad_instance_getdata(inst), data, B_TRUE, |
|
215 strinset, pgtypes, error)); |
|
216 } |
|
217 |
|
218 /* ARGSUSED */ |
|
219 conerr_t |
|
220 interface_ServiceInfo_read_dependencyNames(rad_instance_t *inst, |
|
221 adr_attribute_t *attr, adr_data_t **data, adr_data_t **error) |
|
222 { |
|
223 const char *pgtypes[] = { SCF_GROUP_DEPENDENCY, NULL }; |
|
224 return (getpgs(rad_instance_getdata(inst), data, B_TRUE, |
|
225 strinset, pgtypes, error)); |
|
226 } |
|
227 |
|
228 /* ARGSUSED */ |
|
229 conerr_t |
|
230 interface_ServiceInfo_read_propertyGroups(rad_instance_t *inst, |
|
231 adr_attribute_t *attr, adr_data_t **data, adr_data_t **error) |
|
232 { |
|
233 return (getpgs(rad_instance_getdata(inst), data, B_FALSE, |
|
234 strnotinset, framework_pgtypes, error)); |
|
235 } |
|
236 |
|
237 /* ARGSUSED */ |
|
238 conerr_t |
|
239 interface_ServiceInfo_read_manpages(rad_instance_t *inst, adr_attribute_t *attr, |
|
240 adr_data_t **data, adr_data_t **error) |
|
241 { |
|
242 servinst_t *si = rad_instance_getdata(inst); |
|
243 char *title, *section, *path; |
|
244 rad_propvec_t *badprop; |
|
245 rad_propvec_t evec[] = { |
|
246 { SCF_PROPERTY_TM_MANPATH, NULL, SCF_TYPE_USTRING, &path, 0 }, |
|
247 { SCF_PROPERTY_TM_TITLE, NULL, SCF_TYPE_USTRING, &title, 0 }, |
|
248 { SCF_PROPERTY_TM_SECTION, NULL, SCF_TYPE_USTRING, §ion, |
|
249 0 }, |
|
250 { NULL } |
|
251 }; |
|
252 |
|
253 const char *pgtypes[] = { |
|
254 SCF_GROUP_TEMPLATE, |
|
255 NULL |
|
256 }; |
|
257 |
|
258 adr_data_t *pgs; |
|
259 conerr_t err = getpgs(si, &pgs, B_TRUE, strinset, pgtypes, error); |
|
260 if (err != CE_OK) |
|
261 return (err); |
|
262 adr_data_t *result = adr_data_new_array(&t_array__Manpage, 5); |
|
263 for (int i = 0; i < adr_array_size(pgs); i++) { |
|
264 const char *str = adr_data_to_string(adr_array_get(pgs, i)); |
|
265 if (strncmp(str, SCF_PG_TM_MAN_PREFIX, |
|
266 strlen(SCF_PG_TM_MAN_PREFIX)) != 0) { |
|
267 continue; |
|
268 } |
|
269 |
|
270 if (rad_read_propvec(si->fmri, str, B_FALSE, evec, |
|
271 &badprop) != 0) |
|
272 continue; |
|
273 |
|
274 adr_data_t *mp = adr_data_new_struct(&t__Manpage); |
|
275 adr_struct_set(mp, "title", |
|
276 adr_data_new_string(title, LT_COPY)); |
|
277 adr_struct_set(mp, "section", |
|
278 adr_data_new_string(section, LT_COPY)); |
|
279 adr_struct_set(mp, "path", adr_data_new_string(path, LT_COPY)); |
|
280 (void) adr_array_add(result, mp); |
|
281 rad_clean_propvec(evec); |
|
282 } |
|
283 adr_data_free(pgs); |
|
284 *data = result; |
|
285 |
|
286 return (CE_OK); |
|
287 } |
|
288 |
|
289 /* ARGSUSED */ |
|
290 conerr_t |
|
291 interface_ServiceInfo_read_doclinks(rad_instance_t *inst, adr_attribute_t *attr, |
|
292 adr_data_t **data, adr_data_t **error) |
|
293 { |
|
294 servinst_t *si = rad_instance_getdata(inst); |
|
295 char *uri; |
|
296 rad_propvec_t *badprop; |
|
297 rad_propvec_t evec[] = { |
|
298 { SCF_PROPERTY_TM_URI, NULL, SCF_TYPE_USTRING, &uri, 0 }, |
|
299 { NULL } |
|
300 }; |
|
301 |
|
302 const char *pgtypes[] = { |
|
303 SCF_GROUP_TEMPLATE, |
|
304 NULL |
|
305 }; |
|
306 |
|
307 adr_data_t *pgs; |
|
308 conerr_t err = getpgs(si, &pgs, B_TRUE, strinset, pgtypes, error); |
|
309 if (err != CE_OK) |
|
310 return (err); |
|
311 adr_data_t *result = adr_data_new_array(&adr_t_array_string, 5); |
|
312 for (int i = 0; i < adr_array_size(pgs); i++) { |
|
313 const char *str = adr_data_to_string(adr_array_get(pgs, i)); |
|
314 if (strncmp(str, SCF_PG_TM_DOC_PREFIX, |
|
315 strlen(SCF_PG_TM_DOC_PREFIX)) != 0) { |
|
316 continue; |
|
317 } |
|
318 |
|
319 if (rad_read_propvec(si->fmri, str, B_FALSE, evec, |
|
320 &badprop) == 0) { |
|
321 (void) adr_array_add(result, |
|
322 adr_data_new_string(uri, LT_COPY)); |
|
323 rad_clean_propvec(evec); |
|
324 } |
|
325 } |
|
326 adr_data_free(pgs); |
|
327 *data = result; |
|
328 |
|
329 return (CE_OK); |
|
330 } |
|
331 |
|
332 /* ARGSUSED */ |
|
333 conerr_t |
|
334 interface_ServiceInfo_read_persistentlyEnabled(rad_instance_t *inst, |
|
335 adr_attribute_t *attr, adr_data_t **data, adr_data_t **error) |
|
336 { |
|
337 servinst_t *si = rad_instance_getdata(inst); |
|
338 if (!si->instance) |
|
339 return (error_scf(error, SCF_ERROR_INVALID_ARGUMENT)); |
|
340 |
|
341 boolean_t enabled; |
|
342 rad_propvec_t evec[] = { |
|
343 { SCF_PROPERTY_ENABLED, NULL, SCF_TYPE_BOOLEAN, &enabled, 0 }, |
|
344 { NULL } |
|
345 }; |
|
346 |
|
347 rad_propvec_t *badprop; |
|
348 int scferr = rad_read_propvec(si->fmri, SCF_PG_GENERAL, B_FALSE, |
|
349 evec, &badprop); |
|
350 if (scferr != 0) |
|
351 return (error_scf(error, scferr)); |
|
352 rad_clean_propvec(evec); |
|
353 |
|
354 *data = adr_data_new_boolean(enabled); |
|
355 return (CE_OK); |
|
356 } |
|
357 |
|
358 /* ARGSUSED */ |
|
359 conerr_t |
|
360 interface_ServiceInfo_read_temporarilyEnabled(rad_instance_t *inst, |
|
361 adr_attribute_t *attr, adr_data_t **data, adr_data_t **error) |
|
362 { |
|
363 servinst_t *si = rad_instance_getdata(inst); |
|
364 if (!si->instance) |
|
365 return (error_scf(error, SCF_ERROR_INVALID_ARGUMENT)); |
|
366 |
|
367 boolean_t enabled; |
|
368 rad_propvec_t evec[] = { |
|
369 { SCF_PROPERTY_ENABLED, NULL, SCF_TYPE_BOOLEAN, &enabled, 0 }, |
|
370 { NULL } |
|
371 }; |
|
372 |
|
373 rad_propvec_t *badprop; |
|
374 if (rad_read_propvec(si->fmri, SCF_PG_GENERAL_OVR, B_FALSE, evec, |
|
375 &badprop) != 0) |
|
376 return (interface_ServiceInfo_read_persistentlyEnabled( |
|
377 inst, attr, data, error)); |
|
378 rad_clean_propvec(evec); |
|
379 |
|
380 *data = adr_data_new_boolean(enabled); |
|
381 return (CE_OK); |
|
382 } |
|
383 |
|
384 /* ARGSUSED */ |
|
385 conerr_t |
|
386 interface_ServiceInfo_read_enabled(rad_instance_t *inst, adr_attribute_t *attr, |
|
387 adr_data_t **data, adr_data_t **error) |
|
388 { |
|
389 /* |
|
390 * XXX: The java version always had the same implementation for both. |
|
391 */ |
|
392 return (interface_ServiceInfo_read_persistentlyEnabled(inst, attr, data, |
|
393 error)); |
|
394 } |
|
395 |
|
396 /* ARGSUSED */ |
|
397 conerr_t |
|
398 interface_ServiceInfo_read_instance(rad_instance_t *inst, adr_attribute_t *attr, |
|
399 adr_data_t **data, adr_data_t **error) |
|
400 { |
|
401 servinst_t *si = rad_instance_getdata(inst); |
|
402 *data = adr_data_new_boolean(si->instance); |
|
403 return (CE_OK); |
|
404 } |
|
405 |
|
406 /* ARGSUSED */ |
|
407 conerr_t |
|
408 interface_ServiceInfo_read_restarter(rad_instance_t *inst, |
|
409 adr_attribute_t *attr, adr_data_t **data, adr_data_t **error) |
|
410 { |
|
411 servinst_t *si = rad_instance_getdata(inst); |
|
412 if (!si->instance) |
|
413 return (error_scf(error, SCF_ERROR_INVALID_ARGUMENT)); |
|
414 |
|
415 char *fmri = NULL; |
|
416 rad_propvec_t evec[] = { |
|
417 { SCF_PROPERTY_RESTARTER, NULL, SCF_TYPE_USTRING, &fmri, 0 }, |
|
418 { NULL } |
|
419 }; |
|
420 |
|
421 rad_propvec_t *badprop; |
|
422 if (rad_read_propvec(si->fmri, SCF_PG_GENERAL, B_FALSE, evec, |
|
423 &badprop) == 0) { |
|
424 *data = adr_data_new_string(fmri, LT_COPY); |
|
425 rad_clean_propvec(evec); |
|
426 } else { |
|
427 *data = adr_data_new_fstring("svc:/%s:%s", |
|
428 "system/svc/restarter", "default"); |
|
429 } |
|
430 |
|
431 return (*data != NULL ? CE_OK : CE_SYSTEM); |
|
432 } |
|
433 |
|
434 static adr_data_t * |
|
435 state2enum(const char *state) |
|
436 { |
|
437 if (strcmp(state, SCF_STATE_STRING_UNINIT) == 0) { |
|
438 return (&e__SmfState_UNINIT); |
|
439 } else if (strcmp(state, SCF_STATE_STRING_MAINT) == 0) { |
|
440 return (&e__SmfState_MAINT); |
|
441 } else if (strcmp(state, SCF_STATE_STRING_LEGACY) == 0) { |
|
442 return (&e__SmfState_LEGACY); |
|
443 } else { |
|
444 return (adr_data_new_enum_byname(&t__SmfState, state)); |
|
445 } |
|
446 } |
|
447 |
|
448 /* ARGSUSED */ |
|
449 conerr_t |
|
450 interface_ServiceInfo_read_state(rad_instance_t *inst, adr_attribute_t *attr, |
|
451 adr_data_t **data, adr_data_t **error) |
|
452 { |
|
453 servinst_t *si = rad_instance_getdata(inst); |
|
454 if (!si->instance) |
|
455 return (error_scf(error, SCF_ERROR_INVALID_ARGUMENT)); |
|
456 |
|
457 char *state = smf_get_state(si->fmri); |
|
458 if (state == NULL) |
|
459 return (error_scf(error, scf_error())); |
|
460 |
|
461 *data = state2enum(state); |
|
462 free(state); |
|
463 return (*data != NULL ? CE_OK : CE_SYSTEM); |
|
464 } |
|
465 |
|
466 /* ARGSUSED */ |
|
467 conerr_t |
|
468 interface_ServiceInfo_read_nextState(rad_instance_t *inst, |
|
469 adr_attribute_t *attr, adr_data_t **data, adr_data_t **error) |
|
470 { |
|
471 servinst_t *si = rad_instance_getdata(inst); |
|
472 if (!si->instance) |
|
473 return (error_scf(error, SCF_ERROR_INVALID_ARGUMENT)); |
|
474 |
|
475 char *state = NULL; |
|
476 rad_propvec_t evec[] = { |
|
477 { SCF_PROPERTY_NEXT_STATE, NULL, SCF_TYPE_ASTRING, &state, 0 }, |
|
478 { NULL } |
|
479 }; |
|
480 |
|
481 rad_propvec_t *badprop; |
|
482 int scferr = rad_read_propvec(si->fmri, SCF_PG_RESTARTER, B_FALSE, evec, |
|
483 &badprop); |
|
484 if (scferr != 0) |
|
485 return (error_scf(error, scferr)); |
|
486 |
|
487 *data = state2enum(state); |
|
488 rad_clean_propvec(evec); |
|
489 return (*data != NULL ? CE_OK : CE_SYSTEM); |
|
490 } |
|
491 |
|
492 /* ARGSUSED */ |
|
493 conerr_t |
|
494 interface_ServiceInfo_read_auxiliaryState(rad_instance_t *inst, |
|
495 adr_attribute_t *attr, adr_data_t **data, adr_data_t **error) |
|
496 { |
|
497 servinst_t *si = rad_instance_getdata(inst); |
|
498 if (!si->instance) |
|
499 return (error_scf(error, SCF_ERROR_INVALID_ARGUMENT)); |
|
500 |
|
501 char *aux; |
|
502 rad_propvec_t evec[] = { |
|
503 { SCF_PROPERTY_AUX_STATE, NULL, SCF_TYPE_ASTRING, &aux, 0 }, |
|
504 { NULL } |
|
505 }; |
|
506 |
|
507 rad_propvec_t *badprop; |
|
508 int scferr = rad_read_propvec(si->fmri, SCF_PG_RESTARTER, B_FALSE, evec, |
|
509 &badprop); |
|
510 if (scferr != 0) { |
|
511 if (scferr == SCF_ERROR_NOT_FOUND) { |
|
512 *data = NULL; |
|
513 return (CE_OK); |
|
514 } |
|
515 return (error_scf(error, scferr)); |
|
516 } |
|
517 |
|
518 *data = adr_data_new_string(aux, LT_COPY); |
|
519 rad_clean_propvec(evec); |
|
520 |
|
521 return (*data != NULL ? CE_OK : CE_SYSTEM); |
|
522 } |
|
523 |
|
524 /* ARGSUSED */ |
|
525 conerr_t |
|
526 interface_ServiceInfo_read_stime(rad_instance_t *inst, adr_attribute_t *attr, |
|
527 adr_data_t **data, adr_data_t **error) |
|
528 { |
|
529 servinst_t *si = rad_instance_getdata(inst); |
|
530 if (!si->instance) |
|
531 return (error_scf(error, SCF_ERROR_INVALID_ARGUMENT)); |
|
532 |
|
533 scf_time_t time; |
|
534 rad_propvec_t evec[] = { |
|
535 { SCF_PROPERTY_STATE_TIMESTAMP, NULL, SCF_TYPE_TIME, &time, 0 }, |
|
536 { NULL } |
|
537 }; |
|
538 |
|
539 rad_propvec_t *badprop; |
|
540 int scferr = rad_read_propvec(si->fmri, SCF_PG_RESTARTER, B_FALSE, evec, |
|
541 &badprop); |
|
542 if (scferr != 0) |
|
543 return (error_scf(error, scferr)); |
|
544 |
|
545 rad_clean_propvec(evec); |
|
546 |
|
547 *data = adr_data_new_time(time.t_seconds, time.t_ns); |
|
548 |
|
549 return (*data != NULL ? CE_OK : CE_SYSTEM); |
|
550 } |
|
551 |
|
552 /* ARGSUSED */ |
|
553 conerr_t |
|
554 interface_ServiceInfo_read_contractID(rad_instance_t *inst, |
|
555 adr_attribute_t *attr, adr_data_t **data, adr_data_t **error) |
|
556 { |
|
557 servinst_t *si = rad_instance_getdata(inst); |
|
558 if (!si->instance) |
|
559 return (error_scf(error, SCF_ERROR_INVALID_ARGUMENT)); |
|
560 |
|
561 uint64_t count; |
|
562 rad_propvec_t evec[] = { |
|
563 { SCF_PROPERTY_CONTRACT, NULL, SCF_TYPE_COUNT, &count, 0 }, |
|
564 { NULL } |
|
565 }; |
|
566 |
|
567 rad_propvec_t *badprop; |
|
568 int scferr = rad_read_propvec(si->fmri, SCF_PG_RESTARTER, B_FALSE, evec, |
|
569 &badprop); |
|
570 if (scferr != 0) |
|
571 return (error_scf(error, scferr)); |
|
572 rad_clean_propvec(evec); |
|
573 |
|
574 *data = adr_data_new_long(count); |
|
575 |
|
576 return (*data != NULL ? CE_OK : CE_SYSTEM); |
|
577 } |
|
578 |
|
579 /* ARGSUSED */ |
|
580 conerr_t |
|
581 interface_ServiceInfo_read_reason(rad_instance_t *inst, adr_attribute_t *attr, |
|
582 adr_data_t **data, adr_data_t **error) |
|
583 { |
|
584 servinst_t *si = rad_instance_getdata(inst); |
|
585 if (!si->instance) |
|
586 return (error_scf(error, SCF_ERROR_INVALID_ARGUMENT)); |
|
587 *data = NULL; |
|
588 return (CE_OK); |
|
589 } |
|
590 |
|
591 /* ARGSUSED */ |
|
592 conerr_t |
|
593 interface_ServiceInfo_write_persistentlyEnabled(rad_instance_t *inst, |
|
594 adr_attribute_t *attr, adr_data_t *data, adr_data_t **error) |
|
595 { |
|
596 servinst_t *si = rad_instance_getdata(inst); |
|
597 boolean_t enable = adr_data_to_boolean(data); |
|
598 if (!si->instance) |
|
599 return (error_scf(error, SCF_ERROR_INVALID_ARGUMENT)); |
|
600 |
|
601 return (simple_scf(error, enable ? smf_enable_instance(si->fmri, 0) : |
|
602 smf_disable_instance(si->fmri, 0))); |
|
603 } |
|
604 |
|
605 static conerr_t |
|
606 get_pg(scf_handle_t *scfhandle, scf_propertygroup_t *pg, servinst_t *si, |
|
607 const char *snapname, const char *pgname, adr_data_t **error) |
|
608 { |
|
609 conerr_t err = CE_OK; |
|
610 scf_service_t *service = scf_service_create(scfhandle); |
|
611 scf_instance_t *instance = scf_instance_create(scfhandle); |
|
612 scf_snapshot_t *snap = scf_snapshot_create(scfhandle); |
|
613 |
|
614 if (service == NULL || instance == NULL || snap == NULL) { |
|
615 err = error_scf(error, SCF_ERROR_NO_MEMORY); |
|
616 goto out; |
|
617 } |
|
618 |
|
619 if (scf_handle_decode_fmri(scfhandle, si->fmri, NULL, service, |
|
620 instance, NULL, NULL, 0) != SCF_SUCCESS) { |
|
621 rad_log(RL_WARN, "Couldn't decode '%s': %s\n", |
|
622 si->fmri, scf_strerror(scf_error())); |
|
623 err = error_scf(error, scf_error()); |
|
624 goto out; |
|
625 } |
|
626 |
|
627 if (si->instance) { |
|
628 scf_snapshot_t *usesnap = NULL; |
|
629 if (snapname != NULL) { |
|
630 usesnap = snap; |
|
631 if (scf_instance_get_snapshot(instance, snapname, snap) |
|
632 != 0) { |
|
633 err = error_scf(error, scf_error()); |
|
634 goto out; |
|
635 } |
|
636 } |
|
637 if (scf_instance_get_pg_composed(instance, usesnap, pgname, pg) |
|
638 != 0) { |
|
639 err = error_scf(error, scf_error()); |
|
640 goto out; |
|
641 } |
|
642 } else { |
|
643 if (scf_service_get_pg(service, pgname, pg) != SCF_SUCCESS) { |
|
644 err = error_scf(error, scf_error()); |
|
645 goto out; |
|
646 } |
|
647 } |
|
648 out: |
|
649 scf_snapshot_destroy(snap); |
|
650 scf_instance_destroy(instance); |
|
651 scf_service_destroy(service); |
|
652 return (err); |
|
653 } |
|
654 |
|
655 /* ARGSUSED */ |
|
656 conerr_t |
|
657 interface_ServiceInfo_invoke_getDependency(rad_instance_t *inst, |
|
658 adr_method_t *meth, adr_data_t **ret, adr_data_t **args, int count, |
|
659 adr_data_t **error) |
|
660 { |
|
661 conerr_t err = CE_OK; |
|
662 const char *pgname = adr_data_to_string(args[0]); |
|
663 servinst_t *si = rad_instance_getdata(inst); |
|
664 char type[1000]; |
|
665 char grouping[1000]; |
|
666 char restarton[1000]; |
|
667 |
|
668 scf_handle_t *scfhandle = handle_create(); |
|
669 scf_iter_t *iter = scf_iter_create(scfhandle); |
|
670 scf_propertygroup_t *pg = scf_pg_create(scfhandle); |
|
671 scf_property_t *prop = scf_property_create(scfhandle); |
|
672 scf_value_t *val = scf_value_create(scfhandle); |
|
673 |
|
674 if (scfhandle == NULL || iter == NULL || pg == NULL || prop == NULL || |
|
675 val == NULL) { |
|
676 err = error_scf(error, SCF_ERROR_NO_MEMORY); |
|
677 goto out; |
|
678 } |
|
679 if ((err = get_pg(scfhandle, pg, si, "running", pgname, error)) |
|
680 != CE_OK) |
|
681 goto out; |
|
682 |
|
683 if (scf_pg_get_type(pg, type, sizeof (type)) == 0) { |
|
684 err = error_scf(error, scf_error()); |
|
685 goto out; |
|
686 } |
|
687 if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) { |
|
688 err = error_scf(error, SCF_ERROR_INVALID_ARGUMENT); |
|
689 goto out; |
|
690 } |
|
691 |
|
692 if (scf_pg_get_property(pg, SCF_PROPERTY_GROUPING, prop) != 0 || |
|
693 scf_property_get_value(prop, val) != 0 || |
|
694 scf_value_get_as_string(val, grouping, sizeof (grouping)) == -1 || |
|
695 scf_pg_get_property(pg, SCF_PROPERTY_RESTART_ON, prop) != 0 || |
|
696 scf_property_get_value(prop, val) != 0 || |
|
697 scf_value_get_as_string(val, restarton, sizeof (restarton)) == -1 || |
|
698 scf_pg_get_property(pg, SCF_PROPERTY_ENTITIES, prop) != 0 || |
|
699 scf_iter_property_values(iter, prop) != 0) { |
|
700 err = error_scf(error, scf_error()); |
|
701 goto out; |
|
702 } |
|
703 |
|
704 adr_data_t *result = adr_data_new_struct(&t__Dependency); |
|
705 adr_data_t *array = adr_data_new_array(&adr_t_array_string, 5); |
|
706 adr_struct_set(result, "name", adr_data_ref(args[0])); |
|
707 adr_struct_set(result, "grouping", |
|
708 adr_data_new_string(grouping, LT_COPY)); |
|
709 adr_struct_set(result, "restartOn", |
|
710 adr_data_new_string(restarton, LT_COPY)); |
|
711 adr_struct_set(result, "target", array); |
|
712 while (scf_iter_next_value(iter, val) > 0) { |
|
713 if (scf_value_get_as_string(val, type, sizeof (type)) == -1) { |
|
714 err = error_scf(error, scf_error()); |
|
715 adr_data_free(result); |
|
716 goto out; |
|
717 } |
|
718 (void) adr_array_add(array, adr_data_new_string(type, LT_COPY)); |
|
719 } |
|
720 if (!adr_data_verify(result, NULL, B_TRUE)) { |
|
721 adr_data_free(result); |
|
722 err = error_scf(error, SCF_ERROR_NO_MEMORY); |
|
723 goto out; |
|
724 } |
|
725 |
|
726 *ret = result; |
|
727 out: |
|
728 scf_value_destroy(val); |
|
729 scf_property_destroy(prop); |
|
730 scf_pg_destroy(pg); |
|
731 scf_iter_destroy(iter); |
|
732 scf_handle_destroy(scfhandle); |
|
733 return (err); |
|
734 } |
|
735 |
|
736 /* ARGSUSED */ |
|
737 conerr_t |
|
738 interface_ServiceInfo_invoke_getPropertyNames(rad_instance_t *inst, |
|
739 adr_method_t *meth, adr_data_t **ret, adr_data_t **args, int count, |
|
740 adr_data_t **error) |
|
741 { |
|
742 conerr_t err = CE_OK; |
|
743 const char *pgname = adr_data_to_string(args[0]); |
|
744 servinst_t *si = rad_instance_getdata(inst); |
|
745 |
|
746 scf_handle_t *scfhandle = handle_create(); |
|
747 scf_iter_t *iter = scf_iter_create(scfhandle); |
|
748 scf_propertygroup_t *pg = scf_pg_create(scfhandle); |
|
749 scf_property_t *prop = scf_property_create(scfhandle); |
|
750 |
|
751 if (scfhandle == NULL || iter == NULL || pg == NULL || prop == NULL) { |
|
752 err = error_scf(error, SCF_ERROR_NO_MEMORY); |
|
753 goto out; |
|
754 } |
|
755 |
|
756 if ((err = get_pg(scfhandle, pg, si, "running", pgname, error)) |
|
757 != CE_OK) |
|
758 goto out; |
|
759 |
|
760 adr_data_t *result = adr_data_new_array(&adr_t_array_string, 5); |
|
761 (void) scf_iter_pg_properties(iter, pg); |
|
762 while (scf_iter_next_property(iter, prop) > 0) { |
|
763 char pbuf[1000]; |
|
764 (void) scf_property_get_name(prop, pbuf, 1000); |
|
765 (void) adr_array_add(result, |
|
766 adr_data_new_string(pbuf, LT_COPY)); |
|
767 } |
|
768 *ret = result; |
|
769 |
|
770 out: |
|
771 scf_property_destroy(prop); |
|
772 scf_pg_destroy(pg); |
|
773 scf_iter_destroy(iter); |
|
774 scf_handle_destroy(scfhandle); |
|
775 |
|
776 return (err); |
|
777 } |
|
778 |
|
779 /* ARGSUSED */ |
|
780 conerr_t |
|
781 interface_ServiceInfo_invoke_getPropertyType(rad_instance_t *inst, |
|
782 adr_method_t *meth, adr_data_t **ret, adr_data_t **args, int count, |
|
783 adr_data_t **error) |
|
784 { |
|
785 const char *pgname = adr_data_to_string(args[0]); |
|
786 const char *propname = adr_data_to_string(args[1]); |
|
787 conerr_t err = CE_OK; |
|
788 servinst_t *si = rad_instance_getdata(inst); |
|
789 |
|
790 scf_handle_t *scfhandle = handle_create(); |
|
791 scf_propertygroup_t *pg = scf_pg_create(scfhandle); |
|
792 scf_property_t *prop = scf_property_create(scfhandle); |
|
793 scf_type_t type; |
|
794 |
|
795 if (scfhandle == NULL || pg == NULL || prop == NULL) { |
|
796 err = error_scf(error, SCF_ERROR_NO_MEMORY); |
|
797 goto out; |
|
798 } |
|
799 if ((err = get_pg(scfhandle, pg, si, "running", pgname, error)) |
|
800 != CE_OK) |
|
801 goto out; |
|
802 |
|
803 if (scf_pg_get_property(pg, propname, prop) != 0 || |
|
804 scf_property_type(prop, &type) != 0) { |
|
805 err = error_scf(error, scf_error()); |
|
806 goto out; |
|
807 } |
|
808 |
|
809 adr_data_t *result = adr_data_new_enum(&t__PropertyType, type); |
|
810 if (result != NULL) |
|
811 *ret = result; |
|
812 else |
|
813 err = error_scf(error, SCF_ERROR_NO_MEMORY); |
|
814 |
|
815 out: |
|
816 scf_property_destroy(prop); |
|
817 scf_pg_destroy(pg); |
|
818 scf_handle_destroy(scfhandle); |
|
819 return (err); |
|
820 } |
|
821 |
|
822 /* ARGSUSED */ |
|
823 conerr_t |
|
824 interface_ServiceInfo_invoke_getPropertyValues(rad_instance_t *inst, |
|
825 adr_method_t *meth, adr_data_t **ret, adr_data_t **args, int count, |
|
826 adr_data_t **error) |
|
827 { |
|
828 conerr_t err = CE_OK; |
|
829 const char *pgname = adr_data_to_string(args[0]); |
|
830 const char *propname = adr_data_to_string(args[1]); |
|
831 |
|
832 servinst_t *si = rad_instance_getdata(inst); |
|
833 |
|
834 scf_handle_t *scfhandle = handle_create(); |
|
835 scf_service_t *service = scf_service_create(scfhandle); |
|
836 scf_instance_t *instance = scf_instance_create(scfhandle); |
|
837 scf_snapshot_t *snap = scf_snapshot_create(scfhandle); |
|
838 scf_iter_t *iter = scf_iter_create(scfhandle); |
|
839 scf_propertygroup_t *pg = scf_pg_create(scfhandle); |
|
840 scf_property_t *prop = scf_property_create(scfhandle); |
|
841 scf_value_t *val = scf_value_create(scfhandle); |
|
842 |
|
843 if (scfhandle == NULL || service == NULL || instance == NULL || |
|
844 snap == NULL || iter == NULL || pg == NULL || prop == NULL || |
|
845 prop == NULL || val == NULL) { |
|
846 err = error_scf(error, SCF_ERROR_NO_MEMORY); |
|
847 goto out; |
|
848 } |
|
849 |
|
850 if (scf_handle_decode_fmri(scfhandle, si->fmri, NULL, service, |
|
851 instance, NULL, NULL, 0) != SCF_SUCCESS) { |
|
852 rad_log(RL_WARN, "Couldn't decode '%s': %s\n", |
|
853 si->fmri, scf_strerror(scf_error())); |
|
854 err = error_scf(error, scf_error()); |
|
855 goto out; |
|
856 } |
|
857 if ((si->instance ? scf_instance_get_pg(instance, pgname, pg) : |
|
858 scf_service_get_pg(service, pgname, pg)) != 0 || |
|
859 scf_pg_get_property(pg, propname, prop) != 0 || |
|
860 scf_iter_property_values(iter, prop) != 0) { |
|
861 err = error_scf(error, scf_error()); |
|
862 goto out; |
|
863 } |
|
864 |
|
865 adr_data_t *result = adr_data_new_array(&adr_t_array_string, 5); |
|
866 while (scf_iter_next_value(iter, val) > 0) { |
|
867 char pbuf[1000]; |
|
868 (void) scf_value_get_as_string(val, pbuf, 1000); |
|
869 (void) adr_array_add(result, |
|
870 adr_data_new_string(pbuf, LT_COPY)); |
|
871 } |
|
872 *ret = result; |
|
873 out: |
|
874 scf_value_destroy(val); |
|
875 scf_property_destroy(prop); |
|
876 scf_pg_destroy(pg); |
|
877 scf_iter_destroy(iter); |
|
878 scf_snapshot_destroy(snap); |
|
879 scf_instance_destroy(instance); |
|
880 scf_service_destroy(service); |
|
881 scf_handle_destroy(scfhandle); |
|
882 |
|
883 return (err); |
|
884 } |
|
885 |
|
886 /* ARGSUSED */ |
|
887 conerr_t |
|
888 interface_ServiceInfo_invoke_getSnapshotPropertyValues(rad_instance_t *inst, |
|
889 adr_method_t *meth, adr_data_t **ret, adr_data_t **args, int count, |
|
890 adr_data_t **error) |
|
891 { |
|
892 conerr_t err = CE_OK; |
|
893 const char *snapname = adr_data_to_string(args[0]); |
|
894 const char *pgname = adr_data_to_string(args[1]); |
|
895 const char *propname = adr_data_to_string(args[2]); |
|
896 |
|
897 servinst_t *si = rad_instance_getdata(inst); |
|
898 if (!si->instance) |
|
899 return (error_scf(error, SCF_ERROR_INVALID_ARGUMENT)); |
|
900 |
|
901 rad_log(RL_DEBUG, "Reading from snapshot: %s\n", snapname); |
|
902 |
|
903 scf_handle_t *scfhandle = handle_create(); |
|
904 scf_iter_t *iter = scf_iter_create(scfhandle); |
|
905 scf_propertygroup_t *pg = scf_pg_create(scfhandle); |
|
906 scf_property_t *prop = scf_property_create(scfhandle); |
|
907 scf_value_t *val = scf_value_create(scfhandle); |
|
908 |
|
909 if (scfhandle == NULL || iter == NULL || pg == NULL || prop == NULL || |
|
910 val == NULL) { |
|
911 err = error_scf(error, SCF_ERROR_NO_MEMORY); |
|
912 goto out; |
|
913 } |
|
914 |
|
915 if ((err = get_pg(scfhandle, pg, si, "running", pgname, error)) |
|
916 != CE_OK) |
|
917 goto out; |
|
918 if (scf_pg_get_property(pg, propname, prop) != 0) { |
|
919 err = error_scf(error, scf_error()); |
|
920 goto out; |
|
921 } |
|
922 |
|
923 adr_data_t *result = adr_data_new_array(&adr_t_array_string, 5); |
|
924 (void) scf_iter_property_values(iter, prop); |
|
925 while (scf_iter_next_value(iter, val) > 0) { |
|
926 char pbuf[1000]; |
|
927 (void) scf_value_get_as_string(val, pbuf, 1000); |
|
928 (void) adr_array_add(result, |
|
929 adr_data_new_string(pbuf, LT_COPY)); |
|
930 } |
|
931 *ret = result; |
|
932 out: |
|
933 scf_value_destroy(val); |
|
934 scf_property_destroy(prop); |
|
935 scf_pg_destroy(pg); |
|
936 scf_iter_destroy(iter); |
|
937 scf_handle_destroy(scfhandle); |
|
938 |
|
939 return (err); |
|
940 } |
|
941 |
|
942 /* ARGSUSED */ |
|
943 conerr_t |
|
944 interface_ServiceInfo_invoke_setPropertyValues(rad_instance_t *inst, |
|
945 adr_method_t *meth, adr_data_t **ret, adr_data_t **args, int count, |
|
946 adr_data_t **error) |
|
947 { |
|
948 conerr_t err = CE_OK; |
|
949 const char *pgname = adr_data_to_string(args[0]); |
|
950 const char *propname = adr_data_to_string(args[1]); |
|
951 adr_data_t *values = args[2]; |
|
952 |
|
953 servinst_t *si = rad_instance_getdata(inst); |
|
954 |
|
955 scf_handle_t *scfhandle = handle_create(); |
|
956 scf_service_t *service = scf_service_create(scfhandle); |
|
957 scf_instance_t *instance = scf_instance_create(scfhandle); |
|
958 scf_propertygroup_t *pg = scf_pg_create(scfhandle); |
|
959 scf_property_t *prop = scf_property_create(scfhandle); |
|
960 scf_transaction_t *tx = scf_transaction_create(scfhandle); |
|
961 scf_transaction_entry_t *ent = scf_entry_create(scfhandle); |
|
962 scf_value_t **val = |
|
963 rad_zalloc(adr_array_size(values) * sizeof (scf_value_t *)); |
|
964 scf_type_t type; |
|
965 |
|
966 if (scfhandle == NULL || service == NULL || instance == NULL || |
|
967 pg == NULL || prop == NULL || tx == NULL || ent == NULL || |
|
968 val == NULL) { |
|
969 err = error_scf(error, SCF_ERROR_NO_MEMORY); |
|
970 goto out; |
|
971 } |
|
972 |
|
973 for (int i = 0; i < adr_array_size(values); i++) { |
|
974 if ((val[i] = scf_value_create(scfhandle)) == NULL) { |
|
975 err = error_scf(error, SCF_ERROR_NO_MEMORY); |
|
976 goto out; |
|
977 } |
|
978 } |
|
979 |
|
980 if (scf_handle_decode_fmri(scfhandle, si->fmri, NULL, service, |
|
981 instance, NULL, NULL, 0) != SCF_SUCCESS) { |
|
982 rad_log(RL_WARN, "Couldn't decode '%s': %s\n", |
|
983 si->fmri, scf_strerror(scf_error())); |
|
984 err = error_scf(error, scf_error()); |
|
985 goto out; |
|
986 } |
|
987 |
|
988 if (si->instance) { |
|
989 /* XXX: silly logic from original java */ |
|
990 if (scf_instance_get_pg(instance, pgname, pg) != 0 && |
|
991 scf_service_get_pg(service, pgname, pg) != 0) { |
|
992 err = error_scf(error, scf_error()); |
|
993 goto out; |
|
994 } |
|
995 } else { |
|
996 if (scf_service_get_pg(service, pgname, pg) != 0) { |
|
997 err = error_scf(error, scf_error()); |
|
998 goto out; |
|
999 } |
|
1000 } |
|
1001 |
|
1002 if (scf_pg_get_property(pg, propname, prop) != 0 || |
|
1003 scf_property_type(prop, &type) != 0) { |
|
1004 err = error_scf(error, scf_error()); |
|
1005 goto out; |
|
1006 } |
|
1007 |
|
1008 top: |
|
1009 if (scf_transaction_start(tx, pg) == -1) { |
|
1010 err = error_scf(error, scf_error()); |
|
1011 goto out; |
|
1012 } |
|
1013 if (scf_transaction_property_change(tx, ent, propname, type) != 0) { |
|
1014 err = error_scf(error, scf_error()); |
|
1015 goto out; |
|
1016 } |
|
1017 |
|
1018 for (int i = 0; i < adr_array_size(values); i++) { |
|
1019 if (scf_value_set_from_string(val[i], type, |
|
1020 adr_data_to_string(adr_array_get(values, i))) != 0 || |
|
1021 scf_entry_add_value(ent, val[i]) != 0) { |
|
1022 err = error_scf(error, scf_error()); |
|
1023 goto out; |
|
1024 } |
|
1025 } |
|
1026 |
|
1027 int txret = scf_transaction_commit(tx); |
|
1028 if (txret == 1) |
|
1029 goto out; |
|
1030 if (txret == 0 && scf_pg_update(pg) != -1) { |
|
1031 scf_transaction_reset(tx); |
|
1032 goto top; |
|
1033 } |
|
1034 err = error_scf(error, scf_error()); |
|
1035 |
|
1036 out: |
|
1037 if (val != NULL) { |
|
1038 for (int i = 0; i < adr_array_size(values); i++) { |
|
1039 if (val[i] == NULL) |
|
1040 break; |
|
1041 scf_value_destroy(val[i]); |
|
1042 } |
|
1043 free(val); |
|
1044 } |
|
1045 |
|
1046 scf_entry_destroy(ent); |
|
1047 scf_transaction_destroy(tx); |
|
1048 scf_property_destroy(prop); |
|
1049 scf_pg_destroy(pg); |
|
1050 scf_instance_destroy(instance); |
|
1051 scf_service_destroy(service); |
|
1052 scf_handle_destroy(scfhandle); |
|
1053 |
|
1054 return (err); |
|
1055 } |
|
1056 |
|
1057 /* ARGSUSED */ |
|
1058 conerr_t |
|
1059 interface_ServiceInfo_invoke_createPropertyGroup(rad_instance_t *inst, |
|
1060 adr_method_t *meth, adr_data_t **ret, adr_data_t **args, int count, |
|
1061 adr_data_t **error) |
|
1062 { |
|
1063 conerr_t err = CE_OK; |
|
1064 const char *pgname = adr_data_to_string(args[0]); |
|
1065 const char *pgtype = adr_data_to_string(args[1]); |
|
1066 |
|
1067 servinst_t *si = rad_instance_getdata(inst); |
|
1068 |
|
1069 scf_handle_t *scfhandle = handle_create(); |
|
1070 scf_service_t *service = scf_service_create(scfhandle); |
|
1071 scf_instance_t *instance = scf_instance_create(scfhandle); |
|
1072 scf_propertygroup_t *pg = scf_pg_create(scfhandle); |
|
1073 |
|
1074 if (scfhandle == NULL || service == NULL || instance == NULL || |
|
1075 pg == NULL) { |
|
1076 err = error_scf(error, SCF_ERROR_NO_MEMORY); |
|
1077 goto out; |
|
1078 } |
|
1079 |
|
1080 if (scf_handle_decode_fmri(scfhandle, si->fmri, NULL, service, |
|
1081 instance, NULL, NULL, 0) != SCF_SUCCESS) { |
|
1082 rad_log(RL_WARN, "Couldn't decode '%s': %s\n", |
|
1083 si->fmri, scf_strerror(scf_error())); |
|
1084 err = error_scf(error, scf_error()); |
|
1085 goto out; |
|
1086 } |
|
1087 |
|
1088 if (si->instance) { |
|
1089 if (scf_instance_add_pg(instance, pgname, pgtype, 0, pg) != 0) { |
|
1090 err = error_scf(error, scf_error()); |
|
1091 goto out; |
|
1092 } |
|
1093 } else { |
|
1094 if (scf_service_add_pg(service, pgname, pgtype, 0, pg) != 0) { |
|
1095 err = error_scf(error, scf_error()); |
|
1096 goto out; |
|
1097 } |
|
1098 } |
|
1099 |
|
1100 out: |
|
1101 scf_pg_destroy(pg); |
|
1102 scf_instance_destroy(instance); |
|
1103 scf_service_destroy(service); |
|
1104 scf_handle_destroy(scfhandle); |
|
1105 |
|
1106 return (err); |
|
1107 } |
|
1108 |
|
1109 /* ARGSUSED */ |
|
1110 conerr_t |
|
1111 interface_ServiceInfo_invoke_deletePropertyGroup(rad_instance_t *inst, |
|
1112 adr_method_t *meth, adr_data_t **ret, adr_data_t **args, int count, |
|
1113 adr_data_t **error) |
|
1114 { |
|
1115 conerr_t err = CE_OK; |
|
1116 const char *pgname = adr_data_to_string(args[0]); |
|
1117 |
|
1118 servinst_t *si = rad_instance_getdata(inst); |
|
1119 |
|
1120 scf_handle_t *scfhandle = handle_create(); |
|
1121 scf_service_t *service = scf_service_create(scfhandle); |
|
1122 scf_instance_t *instance = scf_instance_create(scfhandle); |
|
1123 scf_propertygroup_t *pg = scf_pg_create(scfhandle); |
|
1124 |
|
1125 if (scfhandle == NULL || service == NULL || instance == NULL || |
|
1126 pg == NULL) { |
|
1127 err = error_scf(error, SCF_ERROR_NO_MEMORY); |
|
1128 goto out; |
|
1129 } |
|
1130 |
|
1131 if (scf_handle_decode_fmri(scfhandle, si->fmri, NULL, service, |
|
1132 instance, NULL, NULL, 0) != SCF_SUCCESS) { |
|
1133 rad_log(RL_WARN, "Couldn't decode '%s': %s\n", |
|
1134 si->fmri, scf_strerror(scf_error())); |
|
1135 err = error_scf(error, scf_error()); |
|
1136 goto out; |
|
1137 } |
|
1138 |
|
1139 if (si->instance) { |
|
1140 /* XXX: silly logic from original java */ |
|
1141 if (scf_instance_get_pg(instance, pgname, pg) != 0 && |
|
1142 scf_service_get_pg(service, pgname, pg) != 0) { |
|
1143 err = error_scf(error, scf_error()); |
|
1144 goto out; |
|
1145 } |
|
1146 } else { |
|
1147 if (scf_service_get_pg(service, pgname, pg) != 0) { |
|
1148 err = error_scf(error, scf_error()); |
|
1149 goto out; |
|
1150 } |
|
1151 } |
|
1152 |
|
1153 if (scf_pg_delete(pg) != 0) { |
|
1154 err = error_scf(error, scf_error()); |
|
1155 goto out; |
|
1156 } |
|
1157 out: |
|
1158 scf_pg_destroy(pg); |
|
1159 scf_instance_destroy(instance); |
|
1160 scf_service_destroy(service); |
|
1161 scf_handle_destroy(scfhandle); |
|
1162 |
|
1163 return (err); |
|
1164 } |
|
1165 |
|
1166 /* ARGSUSED */ |
|
1167 conerr_t |
|
1168 interface_ServiceInfo_invoke_createProperty(rad_instance_t *inst, |
|
1169 adr_method_t *meth, adr_data_t **ret, adr_data_t **args, int count, |
|
1170 adr_data_t **error) |
|
1171 { |
|
1172 conerr_t err = CE_OK; |
|
1173 const char *pgname = adr_data_to_string(args[0]); |
|
1174 const char *propname = adr_data_to_string(args[1]); |
|
1175 scf_type_t type = adr_enum_tovalue(args[2]); |
|
1176 int sret; |
|
1177 |
|
1178 servinst_t *si = rad_instance_getdata(inst); |
|
1179 |
|
1180 scf_handle_t *scfhandle = handle_create(); |
|
1181 scf_service_t *service = scf_service_create(scfhandle); |
|
1182 scf_instance_t *instance = scf_instance_create(scfhandle); |
|
1183 scf_propertygroup_t *pg = scf_pg_create(scfhandle); |
|
1184 scf_transaction_t *tx = scf_transaction_create(scfhandle); |
|
1185 scf_transaction_entry_t *ent = scf_entry_create(scfhandle); |
|
1186 |
|
1187 if (scfhandle == NULL || service == NULL || instance == NULL || |
|
1188 pg == NULL || tx == NULL || ent == NULL) { |
|
1189 err = error_scf(error, SCF_ERROR_NO_MEMORY); |
|
1190 goto out; |
|
1191 } |
|
1192 |
|
1193 if (scf_handle_decode_fmri(scfhandle, si->fmri, NULL, service, |
|
1194 instance, NULL, NULL, 0) != SCF_SUCCESS) { |
|
1195 rad_log(RL_WARN, "Couldn't decode '%s': %s\n", |
|
1196 si->fmri, scf_strerror(scf_error())); |
|
1197 err = error_scf(error, scf_error()); |
|
1198 goto out; |
|
1199 } |
|
1200 |
|
1201 if (si->instance) { |
|
1202 /* XXX: silly logic from original java */ |
|
1203 if (scf_instance_get_pg(instance, pgname, pg) != 0 && |
|
1204 scf_service_get_pg(service, pgname, pg) != 0) { |
|
1205 err = error_scf(error, scf_error()); |
|
1206 goto out; |
|
1207 } |
|
1208 } else { |
|
1209 if (scf_service_get_pg(service, pgname, pg) != 0) { |
|
1210 err = error_scf(error, scf_error()); |
|
1211 goto out; |
|
1212 } |
|
1213 } |
|
1214 |
|
1215 top: |
|
1216 if (scf_transaction_start(tx, pg) == -1) { |
|
1217 err = error_scf(error, scf_error()); |
|
1218 goto out; |
|
1219 } |
|
1220 sret = scf_transaction_property_change(tx, ent, propname, type); |
|
1221 if (sret == -1 && scf_error() == SCF_ERROR_NOT_FOUND) |
|
1222 sret = scf_transaction_property_new(tx, ent, propname, type); |
|
1223 if (sret == -1) { |
|
1224 err = error_scf(error, scf_error()); |
|
1225 goto out; |
|
1226 } |
|
1227 |
|
1228 sret = scf_transaction_commit(tx); |
|
1229 if (sret == 1) |
|
1230 goto out; |
|
1231 if (sret == 0 && scf_pg_update(pg) != -1) { |
|
1232 scf_transaction_reset(tx); |
|
1233 goto top; |
|
1234 } |
|
1235 err = error_scf(error, scf_error()); |
|
1236 |
|
1237 out: |
|
1238 scf_entry_destroy(ent); |
|
1239 scf_transaction_destroy(tx); |
|
1240 scf_pg_destroy(pg); |
|
1241 scf_instance_destroy(instance); |
|
1242 scf_service_destroy(service); |
|
1243 scf_handle_destroy(scfhandle); |
|
1244 |
|
1245 return (err); |
|
1246 } |
|
1247 |
|
1248 /* ARGSUSED */ |
|
1249 conerr_t |
|
1250 interface_ServiceInfo_invoke_deleteProperty(rad_instance_t *inst, |
|
1251 adr_method_t *meth, adr_data_t **ret, adr_data_t **args, int count, |
|
1252 adr_data_t **error) |
|
1253 { |
|
1254 conerr_t err = CE_OK; |
|
1255 const char *pgname = adr_data_to_string(args[0]); |
|
1256 const char *propname = adr_data_to_string(args[1]); |
|
1257 int sret; |
|
1258 |
|
1259 servinst_t *si = rad_instance_getdata(inst); |
|
1260 |
|
1261 scf_handle_t *scfhandle = handle_create(); |
|
1262 scf_service_t *service = scf_service_create(scfhandle); |
|
1263 scf_instance_t *instance = scf_instance_create(scfhandle); |
|
1264 scf_propertygroup_t *pg = scf_pg_create(scfhandle); |
|
1265 scf_transaction_t *tx = scf_transaction_create(scfhandle); |
|
1266 scf_transaction_entry_t *ent = scf_entry_create(scfhandle); |
|
1267 |
|
1268 if (scfhandle == NULL || service == NULL || instance == NULL || |
|
1269 pg == NULL || tx == NULL || ent == NULL) { |
|
1270 err = error_scf(error, SCF_ERROR_NO_MEMORY); |
|
1271 goto out; |
|
1272 } |
|
1273 |
|
1274 if (scf_handle_decode_fmri(scfhandle, si->fmri, NULL, service, |
|
1275 instance, NULL, NULL, 0) != SCF_SUCCESS) { |
|
1276 rad_log(RL_WARN, "Couldn't decode '%s': %s\n", |
|
1277 si->fmri, scf_strerror(scf_error())); |
|
1278 err = error_scf(error, scf_error()); |
|
1279 goto out; |
|
1280 } |
|
1281 |
|
1282 if (si->instance) { |
|
1283 /* XXX: really, really silly logic from original java */ |
|
1284 if (scf_instance_get_pg(instance, pgname, pg) != 0 && |
|
1285 scf_service_get_pg(service, pgname, pg) != 0) { |
|
1286 err = error_scf(error, scf_error()); |
|
1287 goto out; |
|
1288 } |
|
1289 } else { |
|
1290 if (scf_service_get_pg(service, pgname, pg) != 0) { |
|
1291 err = error_scf(error, scf_error()); |
|
1292 goto out; |
|
1293 } |
|
1294 } |
|
1295 |
|
1296 top: |
|
1297 if (scf_transaction_start(tx, pg) == -1) { |
|
1298 err = error_scf(error, scf_error()); |
|
1299 goto out; |
|
1300 } |
|
1301 if (scf_transaction_property_delete(tx, ent, propname) != 0) { |
|
1302 err = error_scf(error, scf_error()); |
|
1303 goto out; |
|
1304 } |
|
1305 |
|
1306 sret = scf_transaction_commit(tx); |
|
1307 if (sret == 1) |
|
1308 goto out; |
|
1309 if (sret == 0 && scf_pg_update(pg) != -1) { |
|
1310 scf_transaction_reset(tx); |
|
1311 goto top; |
|
1312 } |
|
1313 err = error_scf(error, scf_error()); |
|
1314 |
|
1315 out: |
|
1316 scf_entry_destroy(ent); |
|
1317 scf_transaction_destroy(tx); |
|
1318 scf_pg_destroy(pg); |
|
1319 scf_instance_destroy(instance); |
|
1320 scf_service_destroy(service); |
|
1321 scf_handle_destroy(scfhandle); |
|
1322 |
|
1323 return (err); |
|
1324 } |
|
1325 |
|
1326 /* ARGSUSED */ |
|
1327 conerr_t |
|
1328 interface_ServiceInfo_invoke_getPropertyTemplate(rad_instance_t *inst, |
|
1329 adr_method_t *meth, adr_data_t **ret, adr_data_t **args, int count, |
|
1330 adr_data_t **error) |
|
1331 { |
|
1332 conerr_t err = CE_OK; |
|
1333 const char *pgname = adr_data_to_string(args[0]); |
|
1334 const char *propname = adr_data_to_string(args[1]); |
|
1335 const char *locale = adr_data_to_string(args[2]); |
|
1336 |
|
1337 servinst_t *si = rad_instance_getdata(inst); |
|
1338 scf_handle_t *scfhandle = handle_create(); |
|
1339 scf_pg_tmpl_t *pgtmpl = scf_tmpl_pg_create(scfhandle); |
|
1340 scf_prop_tmpl_t *proptmpl = scf_tmpl_prop_create(scfhandle); |
|
1341 |
|
1342 if (scfhandle == NULL || pgtmpl == NULL || proptmpl == NULL) { |
|
1343 err = error_scf(error, SCF_ERROR_NO_MEMORY); |
|
1344 goto out; |
|
1345 } |
|
1346 |
|
1347 if (scf_tmpl_get_by_pg_name(si->fmri, NULL, pgname, NULL, pgtmpl, |
|
1348 0) == -1 || |
|
1349 scf_tmpl_get_by_prop(pgtmpl, propname, proptmpl, 0) == -1) { |
|
1350 err = error_scf(error, scf_error()); |
|
1351 goto out; |
|
1352 } |
|
1353 |
|
1354 adr_data_t *result = adr_data_new_struct(&t__Template); |
|
1355 |
|
1356 char *name; |
|
1357 if (scf_tmpl_prop_common_name(proptmpl, locale, &name) >= 0) |
|
1358 adr_struct_set(result, "name", |
|
1359 adr_data_new_string(name, LT_FREE)); |
|
1360 |
|
1361 if (scf_tmpl_prop_description(proptmpl, locale, &name) >= 0) |
|
1362 adr_struct_set(result, "description", |
|
1363 adr_data_new_string(name, LT_FREE)); |
|
1364 |
|
1365 if (scf_tmpl_prop_units(proptmpl, locale, &name) >= 0) |
|
1366 adr_struct_set(result, "units", |
|
1367 adr_data_new_string(name, LT_FREE)); |
|
1368 |
|
1369 uint8_t vis; |
|
1370 if (scf_tmpl_prop_visibility(proptmpl, &vis) == -1) { |
|
1371 adr_data_free(result); |
|
1372 goto out; |
|
1373 } |
|
1374 adr_data_t *visvalue = NULL; |
|
1375 switch (vis) { |
|
1376 case SCF_TMPL_VISIBILITY_HIDDEN: |
|
1377 visvalue = &e__PropertyVisibility_HIDDEN; |
|
1378 break; |
|
1379 case SCF_TMPL_VISIBILITY_READONLY: |
|
1380 visvalue = &e__PropertyVisibility_READONLY; |
|
1381 break; |
|
1382 case SCF_TMPL_VISIBILITY_READWRITE: |
|
1383 visvalue = &e__PropertyVisibility_READWRITE; |
|
1384 break; |
|
1385 } |
|
1386 adr_struct_set(result, "visibility", visvalue); |
|
1387 |
|
1388 scf_values_t values; |
|
1389 if (scf_tmpl_prop_internal_seps(proptmpl, &values) == 0) { |
|
1390 adr_data_t *array = |
|
1391 adr_data_new_array(&adr_t_array_string, values.value_count); |
|
1392 for (int i = 0; i < values.value_count; i++) |
|
1393 (void) adr_array_add(array, adr_data_new_string( |
|
1394 values.values_as_strings[i], LT_COPY)); |
|
1395 adr_struct_set(result, "separators", array); |
|
1396 scf_values_destroy(&values); |
|
1397 } |
|
1398 |
|
1399 if (scf_tmpl_value_name_choices(proptmpl, &values) == 0) { |
|
1400 adr_data_t *array = |
|
1401 adr_data_new_array(&adr_t_array_string, values.value_count); |
|
1402 for (int i = 0; i < values.value_count; i++) |
|
1403 (void) adr_array_add(array, adr_data_new_string( |
|
1404 values.values_as_strings[i], LT_COPY)); |
|
1405 adr_struct_set(result, "allowed", array); |
|
1406 scf_values_destroy(&values); |
|
1407 } |
|
1408 |
|
1409 if ((*ret = adr_data_purify_deep(result)) == NULL) |
|
1410 err = error_scf(error, SCF_ERROR_NO_MEMORY); |
|
1411 out: |
|
1412 scf_tmpl_prop_destroy(proptmpl); |
|
1413 scf_tmpl_pg_destroy(pgtmpl); |
|
1414 scf_handle_destroy(scfhandle); |
|
1415 |
|
1416 return (err); |
|
1417 } |
|
1418 |
|
1419 static int |
|
1420 get_localedprop(servinst_t *si, const char *locale, const char *name, |
|
1421 adr_data_t **ret, adr_data_t **error) |
|
1422 { |
|
1423 char *str; |
|
1424 rad_propvec_t *badprop; |
|
1425 rad_propvec_t evec[] = { |
|
1426 { locale, NULL, SCF_TYPE_ASTRING, &str, 0 }, |
|
1427 { NULL } |
|
1428 }; |
|
1429 |
|
1430 int scferr = rad_read_propvec(si->fmri, name, si->instance, evec, |
|
1431 &badprop); |
|
1432 if (scferr != 0) { |
|
1433 if (error != NULL && scferr == SCF_ERROR_NOT_FOUND) { |
|
1434 *ret = NULL; |
|
1435 return (CE_OK); |
|
1436 } |
|
1437 return (error_scf(error, scferr)); |
|
1438 } |
|
1439 |
|
1440 *ret = adr_data_new_string(str, LT_COPY); |
|
1441 rad_clean_propvec(evec); |
|
1442 return (CE_OK); |
|
1443 } |
|
1444 |
|
1445 /* ARGSUSED */ |
|
1446 conerr_t |
|
1447 interface_ServiceInfo_invoke_getCommonName(rad_instance_t *inst, |
|
1448 adr_method_t *meth, adr_data_t **ret, adr_data_t **args, int count, |
|
1449 adr_data_t **error) |
|
1450 { |
|
1451 const char *locale = adr_data_to_string(args[0]); |
|
1452 servinst_t *si = rad_instance_getdata(inst); |
|
1453 |
|
1454 if (get_localedprop(si, locale, SCF_PG_TM_COMMON_NAME, ret, NULL) |
|
1455 == CE_OK) |
|
1456 return (CE_OK); |
|
1457 return (get_localedprop(si, "C", SCF_PG_TM_COMMON_NAME, ret, error)); |
|
1458 } |
|
1459 |
|
1460 /* ARGSUSED */ |
|
1461 conerr_t |
|
1462 interface_ServiceInfo_invoke_getDescription(rad_instance_t *inst, |
|
1463 adr_method_t *meth, adr_data_t **ret, adr_data_t **args, int count, |
|
1464 adr_data_t **error) |
|
1465 { |
|
1466 const char *locale = adr_data_to_string(args[0]); |
|
1467 servinst_t *si = rad_instance_getdata(inst); |
|
1468 |
|
1469 if (get_localedprop(si, locale, SCF_PG_TM_DESCRIPTION, ret, NULL) |
|
1470 == CE_OK) |
|
1471 return (CE_OK); |
|
1472 return (get_localedprop(si, "C", SCF_PG_TM_DESCRIPTION, ret, error)); |
|
1473 } |
|
1474 |
|
1475 /* ARGSUSED */ |
|
1476 conerr_t |
|
1477 interface_ServiceInfo_invoke_getLogInfo(rad_instance_t *inst, |
|
1478 adr_method_t *meth, adr_data_t **ret, adr_data_t **args, int count, |
|
1479 adr_data_t **error) |
|
1480 { |
|
1481 servinst_t *si = rad_instance_getdata(inst); |
|
1482 if (!si->instance) |
|
1483 return (CE_OBJECT); |
|
1484 |
|
1485 char *logname = NULL; |
|
1486 rad_propvec_t evec[] = { |
|
1487 { SCF_PROPERTY_LOGFILE, NULL, SCF_TYPE_USTRING, &logname, 0 }, |
|
1488 { NULL } |
|
1489 }; |
|
1490 |
|
1491 rad_propvec_t *badprop; |
|
1492 int errval = rad_read_propvec(si->fmri, SCF_PG_RESTARTER, B_FALSE, |
|
1493 evec, &badprop); |
|
1494 if (errval != 0) |
|
1495 return (CE_OBJECT); |
|
1496 |
|
1497 struct stat st; |
|
1498 if (stat(logname, &st) != 0) { |
|
1499 free(logname); |
|
1500 return (CE_OBJECT); |
|
1501 } |
|
1502 |
|
1503 int max_size = adr_data_to_integer(args[0]); |
|
1504 |
|
1505 int bsize = max_size >= 0 && max_size < st.st_size ? |
|
1506 max_size : st.st_size; |
|
1507 char *buffer = malloc(bsize); |
|
1508 if (buffer == NULL) { |
|
1509 free(logname); |
|
1510 return (CE_NOMEM); |
|
1511 } |
|
1512 |
|
1513 int fd; |
|
1514 if ((fd = open(logname, O_RDONLY)) == -1) { |
|
1515 free(buffer); |
|
1516 free(logname); |
|
1517 return (CE_PRIV); |
|
1518 } |
|
1519 |
|
1520 if (pread(fd, buffer, bsize, st.st_size - bsize) != bsize) { |
|
1521 (void) close(fd); |
|
1522 free(buffer); |
|
1523 free(logname); |
|
1524 return (CE_SYSTEM); |
|
1525 } |
|
1526 |
|
1527 (void) close(fd); |
|
1528 |
|
1529 adr_data_t *result = adr_data_new_struct(&t__LogInfo); |
|
1530 adr_struct_set(result, "name", adr_data_new_string(logname, LT_FREE)); |
|
1531 adr_struct_set(result, "size", adr_data_new_integer(st.st_size)); |
|
1532 adr_struct_set(result, "MTime", adr_data_new_time_ts(&st.st_mtim)); |
|
1533 adr_struct_set(result, "contents", |
|
1534 adr_data_new_opaque(buffer, bsize, LT_FREE)); |
|
1535 |
|
1536 if ((*ret = adr_data_purify(result)) == NULL) |
|
1537 return (CE_OBJECT); |
|
1538 |
|
1539 return (CE_OK); |
|
1540 } |
|
1541 |
|
1542 /* ARGSUSED */ |
|
1543 conerr_t |
|
1544 interface_ServiceInfo_invoke_delete(rad_instance_t *inst, adr_method_t *meth, |
|
1545 adr_data_t **ret, adr_data_t **args, int count, adr_data_t **error) |
|
1546 { |
|
1547 conerr_t err = CE_OK; |
|
1548 servinst_t *si = rad_instance_getdata(inst); |
|
1549 |
|
1550 scf_handle_t *scfhandle = handle_create(); |
|
1551 scf_service_t *service = scf_service_create(scfhandle); |
|
1552 scf_instance_t *instance = scf_instance_create(scfhandle); |
|
1553 |
|
1554 if (scfhandle == NULL || service == NULL || instance == NULL) { |
|
1555 err = error_scf(error, SCF_ERROR_NO_MEMORY); |
|
1556 goto out; |
|
1557 } |
|
1558 |
|
1559 if (scf_handle_decode_fmri(scfhandle, si->fmri, NULL, service, |
|
1560 instance, NULL, NULL, si->instance ? |
|
1561 SCF_DECODE_FMRI_REQUIRE_INSTANCE : |
|
1562 SCF_DECODE_FMRI_REQUIRE_NO_INSTANCE) != SCF_SUCCESS) { |
|
1563 rad_log(RL_WARN, "Couldn't decode '%s': %s\n", |
|
1564 si->fmri, scf_strerror(scf_error())); |
|
1565 err = error_scf(error, scf_error()); |
|
1566 goto out; |
|
1567 } |
|
1568 |
|
1569 err = simple_scf(error, si->instance ? |
|
1570 scf_instance_delete(instance) : scf_service_delete(service)); |
|
1571 out: |
|
1572 scf_service_destroy(service); |
|
1573 scf_instance_destroy(instance); |
|
1574 scf_handle_destroy(scfhandle); |
|
1575 return (err); |
|
1576 } |
|
1577 |
|
1578 /* ARGSUSED */ |
|
1579 conerr_t |
|
1580 interface_ServiceInfo_invoke_clear(rad_instance_t *inst, adr_method_t *meth, |
|
1581 adr_data_t **ret, adr_data_t **args, int count, adr_data_t **error) |
|
1582 { |
|
1583 servinst_t *si = rad_instance_getdata(inst); |
|
1584 if (!si->instance) |
|
1585 return (error_scf(error, SCF_ERROR_INVALID_ARGUMENT)); |
|
1586 |
|
1587 return (simple_scf(error, smf_restore_instance(si->fmri))); |
|
1588 } |
|
1589 |
|
1590 /* ARGSUSED */ |
|
1591 conerr_t |
|
1592 interface_ServiceInfo_invoke_degrade(rad_instance_t *inst, adr_method_t *meth, |
|
1593 adr_data_t **ret, adr_data_t **args, int count, adr_data_t **error) |
|
1594 { |
|
1595 servinst_t *si = rad_instance_getdata(inst); |
|
1596 if (!si->instance) |
|
1597 return (error_scf(error, SCF_ERROR_INVALID_ARGUMENT)); |
|
1598 |
|
1599 return (simple_scf(error, smf_degrade_instance(si->fmri, |
|
1600 adr_data_to_boolean(args[0]) ? SMF_IMMEDIATE : 0))); |
|
1601 } |
|
1602 |
|
1603 /* ARGSUSED */ |
|
1604 conerr_t |
|
1605 interface_ServiceInfo_invoke_maintain(rad_instance_t *inst, adr_method_t *meth, |
|
1606 adr_data_t **ret, adr_data_t **args, int count, adr_data_t **error) |
|
1607 { |
|
1608 servinst_t *si = rad_instance_getdata(inst); |
|
1609 if (!si->instance) |
|
1610 return (error_scf(error, SCF_ERROR_INVALID_ARGUMENT)); |
|
1611 |
|
1612 return (simple_scf(error, smf_maintain_instance(si->fmri, |
|
1613 adr_data_to_boolean(args[0]) ? SMF_IMMEDIATE : 0))); |
|
1614 } |
|
1615 |
|
1616 /* ARGSUSED */ |
|
1617 conerr_t |
|
1618 interface_ServiceInfo_invoke_restart(rad_instance_t *inst, adr_method_t *meth, |
|
1619 adr_data_t **ret, adr_data_t **args, int count, adr_data_t **error) |
|
1620 { |
|
1621 servinst_t *si = rad_instance_getdata(inst); |
|
1622 if (!si->instance) |
|
1623 return (error_scf(error, SCF_ERROR_INVALID_ARGUMENT)); |
|
1624 |
|
1625 return (simple_scf(error, smf_restart_instance(si->fmri))); |
|
1626 } |
|
1627 |
|
1628 /* ARGSUSED */ |
|
1629 conerr_t |
|
1630 interface_ServiceInfo_invoke_refresh(rad_instance_t *inst, adr_method_t *meth, |
|
1631 adr_data_t **ret, adr_data_t **args, int count, adr_data_t **error) |
|
1632 { |
|
1633 servinst_t *si = rad_instance_getdata(inst); |
|
1634 if (!si->instance) |
|
1635 return (error_scf(error, SCF_ERROR_INVALID_ARGUMENT)); |
|
1636 |
|
1637 return (simple_scf(error, smf_refresh_instance(si->fmri))); |
|
1638 } |
|
1639 |
|
1640 /* ARGSUSED */ |
|
1641 conerr_t |
|
1642 interface_Aggregator_read_services(rad_instance_t *inst, adr_attribute_t *attr, |
|
1643 adr_data_t **data, adr_data_t **error) |
|
1644 { |
|
1645 rad_mutex_enter(&service_lock); |
|
1646 adr_data_t *result = |
|
1647 adr_data_new_array(&t_array__Service, service_count); |
|
1648 |
|
1649 for (servinst_t *si = list_head(&service_list); si != NULL; |
|
1650 si = list_next(&service_list, si)) { |
|
1651 adr_data_t *insts = adr_data_new_array(&adr_t_array_string, |
|
1652 si->ninstances); |
|
1653 for (servinst_t *i = list_head(&si->instances); i != NULL; |
|
1654 i = list_next(&si->instances, i)) |
|
1655 (void) adr_array_add(insts, |
|
1656 adr_data_new_string(i->iname, |
|
1657 LT_COPY)); |
|
1658 |
|
1659 adr_data_t *service = adr_data_new_struct(&t__Service); |
|
1660 adr_struct_set(service, "fmri", |
|
1661 adr_data_new_string(si->fmri, LT_COPY)); |
|
1662 adr_struct_set(service, "objectName", |
|
1663 rad_instance_getname(si->inst)); |
|
1664 adr_struct_set(service, "instances", insts); |
|
1665 (void) adr_array_add(result, service); |
|
1666 } |
|
1667 |
|
1668 if (adr_data_verify(result, NULL, B_TRUE)) |
|
1669 *data = result; |
|
1670 else |
|
1671 adr_data_free(result); |
|
1672 |
|
1673 rad_mutex_exit(&service_lock); |
|
1674 return (*data != NULL ? CE_OK : CE_OBJECT); |
|
1675 } |
|
1676 |
|
1677 /* ARGSUSED */ |
|
1678 conerr_t |
|
1679 interface_Aggregator_read_instances(rad_instance_t *inst, adr_attribute_t *attr, |
|
1680 adr_data_t **data, adr_data_t **error) |
|
1681 { |
|
1682 conerr_t err = CE_OK; |
|
1683 |
|
1684 scf_handle_t *scfhandle = handle_create(); |
|
1685 scf_service_t *service = scf_service_create(scfhandle); |
|
1686 scf_instance_t *instance = scf_instance_create(scfhandle); |
|
1687 scf_propertygroup_t *pg = scf_pg_create(scfhandle); |
|
1688 scf_property_t *prop = scf_property_create(scfhandle); |
|
1689 scf_value_t *val = scf_value_create(scfhandle); |
|
1690 |
|
1691 if (scfhandle == NULL || service == NULL || instance == NULL || |
|
1692 pg == NULL || prop == NULL || prop == NULL || |
|
1693 val == NULL) { |
|
1694 err = error_scf(error, SCF_ERROR_NO_MEMORY); |
|
1695 goto out; |
|
1696 } |
|
1697 |
|
1698 rad_mutex_enter(&service_lock); |
|
1699 adr_data_t *result = adr_data_new_array(&t_array__Instance, |
|
1700 instance_count); |
|
1701 |
|
1702 /* |
|
1703 * It would be easy to iterate over all instances -- not just the |
|
1704 * ones we know about -- but until we dynamically add and remove |
|
1705 * their MBeans we'll stick to our list to avoid confusion. |
|
1706 */ |
|
1707 for (servinst_t *si = list_head(&instance_list); si != NULL; |
|
1708 si = list_next(&instance_list, si)) { |
|
1709 |
|
1710 char statestr[MAX_SCF_STATE_STRING_SZ]; |
|
1711 ssize_t len; |
|
1712 int64_t seconds; |
|
1713 int32_t ns; |
|
1714 |
|
1715 if (scf_handle_decode_fmri(scfhandle, si->fmri, NULL, service, |
|
1716 instance, NULL, NULL, 0) != SCF_SUCCESS) |
|
1717 continue; |
|
1718 if (scf_instance_get_pg(instance, SCF_PG_RESTARTER, pg) != 0) |
|
1719 continue; |
|
1720 |
|
1721 if (scf_pg_get_property(pg, SCF_PROPERTY_STATE, prop) != 0 || |
|
1722 scf_property_get_value(prop, val) != 0 || |
|
1723 (len = scf_value_get_as_string(val, statestr, |
|
1724 MAX_SCF_STATE_STRING_SZ)) == -1 || |
|
1725 len > MAX_SCF_STATE_STRING_SZ - 1) |
|
1726 continue; |
|
1727 |
|
1728 if (scf_pg_get_property(pg, SCF_PROPERTY_STATE_TIMESTAMP, |
|
1729 prop) != 0 || scf_property_get_value(prop, val) != 0 || |
|
1730 scf_value_get_time(val, &seconds, &ns) != 0) |
|
1731 continue; |
|
1732 |
|
1733 adr_data_t *inst = adr_data_new_struct(&t__Instance); |
|
1734 adr_struct_set(inst, "fmri", |
|
1735 adr_data_new_string(si->fmri, LT_COPY)); |
|
1736 adr_struct_set(inst, "objectName", |
|
1737 rad_instance_getname(si->inst)); |
|
1738 adr_struct_set(inst, "STime", adr_data_new_time(seconds, ns)); |
|
1739 adr_struct_set(inst, "state", state2enum(statestr)); |
|
1740 if (!adr_data_verify(inst, NULL, B_TRUE)) |
|
1741 adr_data_free(inst); |
|
1742 else |
|
1743 (void) adr_array_add(result, inst); |
|
1744 } |
|
1745 |
|
1746 if ((*data = adr_data_purify(result)) == NULL) |
|
1747 err = CE_OBJECT; |
|
1748 rad_mutex_exit(&service_lock); |
|
1749 out: |
|
1750 scf_value_destroy(val); |
|
1751 scf_property_destroy(prop); |
|
1752 scf_pg_destroy(pg); |
|
1753 scf_instance_destroy(instance); |
|
1754 scf_service_destroy(service); |
|
1755 scf_handle_destroy(scfhandle); |
|
1756 |
|
1757 return (err); |
|
1758 } |
|
1759 |
|
1760 static rad_moderr_t |
|
1761 notify_thread(rad_thread_t *arg) |
|
1762 { |
|
1763 scf_handle_t *scfhandle = handle_create(); |
|
1764 scf_service_t *service = scf_service_create(scfhandle); |
|
1765 scf_instance_t *instance = scf_instance_create(scfhandle); |
|
1766 scf_propertygroup_t *pg = scf_pg_create(scfhandle); |
|
1767 char fmri[5]; |
|
1768 char sname[1000], iname[1000]; |
|
1769 servinst_t *si; |
|
1770 int ret; |
|
1771 |
|
1772 if (scfhandle == NULL || service == NULL || instance == NULL || |
|
1773 pg == NULL || |
|
1774 _scf_notify_add_pgtype(scfhandle, SCF_GROUP_FRAMEWORK) != 0) |
|
1775 goto out; |
|
1776 |
|
1777 rad_thread_ack(arg, RM_OK); |
|
1778 while ((ret = _scf_notify_wait(pg, fmri, 5)) >= 0) { |
|
1779 rad_log(RL_DEBUG, "received SMF event"); |
|
1780 |
|
1781 if (ret > 0) |
|
1782 continue; /* We should care */ |
|
1783 |
|
1784 if (scf_pg_get_parent_instance(pg, instance) != 0 || |
|
1785 scf_instance_get_parent(instance, service) != 0 || |
|
1786 scf_instance_get_name(instance, iname, 1000) == -1 || |
|
1787 scf_service_get_name(service, sname, 1000) == -1) |
|
1788 continue; |
|
1789 |
|
1790 rad_mutex_enter(&service_lock); |
|
1791 |
|
1792 for (si = list_head(&instance_list); si != NULL; |
|
1793 si = list_next(&instance_list, si)) |
|
1794 if (strcmp(si->iname, iname) == 0 && |
|
1795 strcmp(si->sname, sname) == 0) |
|
1796 break; |
|
1797 |
|
1798 if (si == NULL) { |
|
1799 rad_mutex_exit(&service_lock); |
|
1800 continue; |
|
1801 } |
|
1802 |
|
1803 rad_log(RL_DEBUG, "identified SMF event: %s/%s", sname, iname); |
|
1804 |
|
1805 adr_data_t *stime = NULL, *state = NULL, *nstate = NULL; |
|
1806 adr_data_t *astate = NULL, *reason = NULL; |
|
1807 |
|
1808 /* Inefficient, but expedient */ |
|
1809 (void) interface_ServiceInfo_read_stime(si->inst, NULL, &stime, |
|
1810 NULL); |
|
1811 (void) interface_ServiceInfo_read_state(si->inst, NULL, &state, |
|
1812 NULL); |
|
1813 (void) interface_ServiceInfo_read_nextState(si->inst, NULL, |
|
1814 &nstate, NULL); |
|
1815 (void) interface_ServiceInfo_read_auxiliaryState(si->inst, NULL, |
|
1816 &astate, NULL); |
|
1817 (void) interface_ServiceInfo_read_reason(si->inst, NULL, |
|
1818 &reason, NULL); |
|
1819 |
|
1820 adr_data_t *event = adr_data_new_struct(&t__StateChange); |
|
1821 adr_struct_set(event, "source", |
|
1822 rad_instance_getname(si->inst)); |
|
1823 adr_struct_set(event, "state", state); |
|
1824 adr_struct_set(event, "nextState", nstate); |
|
1825 adr_struct_set(event, "stateTime", stime); |
|
1826 adr_struct_set(event, "auxState", astate); |
|
1827 adr_struct_set(event, "reason", reason); |
|
1828 adr_struct_set(event, "anomaly", adr_data_new_boolean(B_FALSE)); |
|
1829 if (adr_data_verify(event, NULL, B_FALSE)) { |
|
1830 rad_log(RL_DEBUG, "sending SMF event"); |
|
1831 if (agg_inst != NULL) |
|
1832 rad_instance_notify(agg_inst, "statechange", |
|
1833 0, adr_data_ref(event)); |
|
1834 rad_instance_notify(si->inst, "statechange", 0, event); |
|
1835 } else { |
|
1836 rad_log(RL_DEBUG, "failed to send SMF event"); |
|
1837 adr_data_free(event); |
|
1838 } |
|
1839 |
|
1840 rad_mutex_exit(&service_lock); |
|
1841 } |
|
1842 rad_log(RL_ERROR, "_scf_notify_wait failed: %s", |
|
1843 scf_strerror(scf_error())); |
|
1844 |
|
1845 /* XXX: reestablish on configd death */ |
|
1846 out: |
|
1847 scf_pg_destroy(pg); |
|
1848 scf_instance_destroy(instance); |
|
1849 scf_service_destroy(service); |
|
1850 scf_handle_destroy(scfhandle); |
|
1851 |
|
1852 rad_log(RL_ERROR, "exiting SMF event loop"); |
|
1853 |
|
1854 return (RM_SYSTEM); |
|
1855 } |
|
1856 |
|
1857 static servinst_t * |
|
1858 make_service(char *sname, char *iname) |
|
1859 { |
|
1860 adr_name_t *objname; |
|
1861 boolean_t inst = iname != NULL; |
|
1862 servinst_t *si = rad_zalloc(sizeof (servinst_t)); |
|
1863 si->sname = strdup(sname); |
|
1864 si->iname = inst ? strdup(iname) : NULL; |
|
1865 /* LINTED */ |
|
1866 if (si->instance = inst) { |
|
1867 (void) asprintf(&si->fmri, "svc:/%s:%s", sname, iname); |
|
1868 objname = adr_name_vcreate(MOD_DOMAIN, 3, |
|
1869 "type", "ServiceInfo", "service", sname, "instance", iname); |
|
1870 } else { |
|
1871 list_create(&si->instances, sizeof (servinst_t), |
|
1872 offsetof(servinst_t, snode)); |
|
1873 (void) asprintf(&si->fmri, "svc:/%s", sname); |
|
1874 objname = adr_name_vcreate(MOD_DOMAIN, 2, |
|
1875 "type", "ServiceInfo", "service", sname); |
|
1876 } |
|
1877 |
|
1878 si->inst = rad_instance_create(objname, &modinfo, |
|
1879 &interface_ServiceInfo_svr, si, NULL); |
|
1880 (void) rad_cont_insert(rad_container, si->inst, INST_ID_PICK); |
|
1881 |
|
1882 if (inst) { |
|
1883 list_insert_tail(&instance_list, si); |
|
1884 instance_count++; |
|
1885 } else { |
|
1886 list_insert_tail(&service_list, si); |
|
1887 service_count++; |
|
1888 } |
|
1889 |
|
1890 |
|
1891 return (si); |
|
1892 } |
|
1893 |
|
1894 int |
|
1895 _rad_init(void) |
|
1896 { |
|
1897 adr_name_t *aname; |
|
1898 conerr_t cerr; |
|
1899 |
|
1900 list_create(&service_list, sizeof (servinst_t), |
|
1901 offsetof(servinst_t, node)); |
|
1902 list_create(&instance_list, sizeof (servinst_t), |
|
1903 offsetof(servinst_t, node)); |
|
1904 |
|
1905 scf_handle_t *scfhandle = handle_create(); |
|
1906 scf_scope_t *scope = scf_scope_create(scfhandle); |
|
1907 scf_iter_t *siter = scf_iter_create(scfhandle); |
|
1908 scf_iter_t *iiter = scf_iter_create(scfhandle); |
|
1909 scf_service_t *service = scf_service_create(scfhandle); |
|
1910 scf_instance_t *instance = scf_instance_create(scfhandle); |
|
1911 |
|
1912 (void) scf_handle_get_scope(scfhandle, SCF_SCOPE_LOCAL, scope); |
|
1913 (void) scf_iter_scope_services(siter, scope); |
|
1914 while (scf_iter_next_service(siter, service) > 0) { |
|
1915 char svcname[1000]; |
|
1916 (void) scf_service_get_name(service, svcname, 1000); |
|
1917 servinst_t *svc = make_service(svcname, NULL); |
|
1918 (void) scf_iter_service_instances(iiter, service); |
|
1919 while (scf_iter_next_instance(iiter, instance) > 0) { |
|
1920 char instname[1000]; |
|
1921 (void) scf_instance_get_name(instance, instname, 1000); |
|
1922 list_insert_tail(&svc->instances, |
|
1923 make_service(svcname, instname)); |
|
1924 svc->ninstances++; |
|
1925 } |
|
1926 } |
|
1927 |
|
1928 scf_instance_destroy(instance); |
|
1929 scf_service_destroy(service); |
|
1930 scf_iter_destroy(iiter); |
|
1931 scf_iter_destroy(siter); |
|
1932 scf_scope_destroy(scope); |
|
1933 scf_handle_destroy(scfhandle); |
|
1934 |
|
1935 aname = adr_name_vcreate(MOD_DOMAIN, 1, "type", "Aggregator"); |
|
1936 cerr = rad_cont_insert_singleton(rad_container, aname, |
|
1937 &modinfo, &interface_Aggregator_svr); |
|
1938 adr_name_rele(aname); |
|
1939 if (cerr != CE_OK) { |
|
1940 rad_log(RL_ERROR, "(mod_smf) failed to insert Aggregator"); |
|
1941 return (-1); |
|
1942 } |
|
1943 |
|
1944 if (rad_thread_create(notify_thread, NULL) != RM_OK) |
|
1945 rad_log(RL_ERROR, "failed to start SMF listener"); |
|
1946 return (0); |
|
1947 } |
|
1948 |
|
1949 /* |
|
1950 * _rad_fini is called by the RAD daemon when the module is unloaded. Any |
|
1951 * module finalisation is completed here. |
|
1952 */ |
|
1953 /*ARGSUSED*/ |
|
1954 void |
|
1955 _rad_fini(void *unused) |
|
1956 { |
|
1957 } |
|