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) 2011, 2012, 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 <assert.h> |
|
36 |
|
37 #include <libscf.h> |
|
38 #include <libscf_priv.h> |
|
39 |
|
40 #include <rad/adr.h> |
|
41 #include <rad/rad_modapi.h> |
|
42 |
|
43 #include "api_smf.h" |
|
44 #include "rhandle.h" |
|
45 #include "smfutil.h" |
|
46 |
|
47 /* Shared with other files */ |
|
48 ssize_t max_fmri; |
|
49 ssize_t max_name; |
|
50 ssize_t max_value; |
|
51 ssize_t max_pgtype; |
|
52 |
|
53 svcerr_t |
|
54 error_scf(adr_data_t **error, adr_data_t *code, adr_data_t *target, |
|
55 const char *aux, const char *msg) |
|
56 { |
|
57 assert(adr_data_type(code) == &t__ErrorCode); |
|
58 assert(target == NULL || adr_data_type(target) == &t__ErrorTarget); |
|
59 |
|
60 if (error != NULL) { |
|
61 adr_data_t *e = adr_data_new_struct(&t__SmfError); |
|
62 adr_struct_set(e, "error", code); |
|
63 adr_struct_set(e, "target", target == NULL ? |
|
64 &e__ErrorTarget_NONE : target); |
|
65 if (aux != NULL) |
|
66 adr_struct_set(e, "aux", |
|
67 adr_data_new_string(aux, LT_COPY)); |
|
68 if (msg != NULL) |
|
69 adr_struct_set(e, "message", |
|
70 adr_data_new_string(msg, LT_COPY)); |
|
71 *error = adr_data_purify(e); |
|
72 } |
|
73 return (SE_FATAL); |
|
74 } |
|
75 |
|
76 svcerr_t |
|
77 internal_error(adr_data_t **error, const char *msg) |
|
78 { |
|
79 return (error_scf(error, &e__ErrorCode_INTERNAL, NULL, NULL, msg)); |
|
80 } |
|
81 |
|
82 /* |
|
83 * Generic error-mapping routine. |
|
84 * |
|
85 * Maps connection errors to SE_RECONNECT, deletions to SE_RETRY, |
|
86 * notfound to SE_NOTFOUND, and everything else to SE_FATAL. |
|
87 */ |
|
88 svcerr_t |
|
89 smfu_maperr(scf_error_t e) |
|
90 { |
|
91 switch (e) { |
|
92 case SCF_ERROR_DELETED: |
|
93 return (SE_RETRY); |
|
94 case SCF_ERROR_NO_SERVER: |
|
95 case SCF_ERROR_NOT_BOUND: |
|
96 case SCF_ERROR_CONNECTION_BROKEN: |
|
97 return (SE_RECONNECT); |
|
98 case SCF_ERROR_NOT_FOUND: |
|
99 return (SE_NOTFOUND); |
|
100 default: |
|
101 return (SE_FATAL); |
|
102 } |
|
103 } |
|
104 |
|
105 |
|
106 /* |
|
107 * Reads the specified instance's "enabled" property from the named |
|
108 * property group. Returns an error code or 0 on success. |
|
109 */ |
|
110 scf_error_t |
|
111 smfu_read_enabled(scf_instance_t *inst, scf_propertygroup_t *pg, |
|
112 scf_property_t *prop, scf_value_t *value, const char *pgname, uint8_t *bool) |
|
113 { |
|
114 if (scf_instance_get_pg(inst, pgname, pg) == -1 || |
|
115 scf_pg_get_property(pg, SCF_PROPERTY_ENABLED, prop) == -1 || |
|
116 scf_property_get_value(prop, value) == -1 || |
|
117 scf_value_get_boolean(value, bool) == -1) |
|
118 return (scf_error()); |
|
119 return (0); |
|
120 } |
|
121 |
|
122 /* |
|
123 * Gets a value as a string, allocating the necessary buffer and |
|
124 * returning it in *strp. Returns an error code or 0 on success. |
|
125 */ |
|
126 scf_error_t |
|
127 smfu_value_get_string(scf_value_t *val, char **strp) |
|
128 { |
|
129 ssize_t len, l; |
|
130 char *s = NULL; |
|
131 |
|
132 len = scf_value_get_as_string(val, NULL, 0); |
|
133 for (; len != -1; len = l) { |
|
134 s = malloc(len + 1); |
|
135 if (s == NULL) |
|
136 return (SCF_ERROR_NO_MEMORY); |
|
137 |
|
138 l = scf_value_get_as_string(val, s, len + 1); |
|
139 if (l == len) { |
|
140 *strp = s; |
|
141 return (0); |
|
142 } |
|
143 free(s); |
|
144 } |
|
145 |
|
146 return (scf_error()); |
|
147 } |
|
148 |
|
149 /* |
|
150 * Gets the named pg in the composed view of the named snapshot. If |
|
151 * snapname is not specified, the current pgs/properties are returned. |
|
152 * The caller must allocate the pg. Returns an error code or SE_OK |
|
153 * on success. |
|
154 */ |
|
155 svcerr_t |
|
156 smfu_instance_get_composed_pg(scf_handle_t *handle, scf_instance_t *instance, |
|
157 const char *snapname, const char *pgname, scf_propertygroup_t *pg, |
|
158 adr_data_t **error) |
|
159 { |
|
160 svcerr_t se = SE_OK; |
|
161 scf_snapshot_t *snap = NULL; |
|
162 |
|
163 if (snapname != NULL) { |
|
164 if ((snap = scf_snapshot_create(handle)) == NULL) |
|
165 return (SE_FATAL); |
|
166 if (scf_instance_get_snapshot(instance, snapname, |
|
167 snap) == -1) { |
|
168 if ((se = smfu_maperr(scf_error())) == SE_NOTFOUND) |
|
169 (void) error_scf(error, &e__ErrorCode_NOTFOUND, |
|
170 &e__ErrorTarget_SNAPSHOT, snapname, NULL); |
|
171 scf_snapshot_destroy(snap); |
|
172 return (se); |
|
173 } |
|
174 } |
|
175 if (scf_instance_get_pg_composed(instance, snap, pgname, |
|
176 pg) == -1) { |
|
177 if ((se = smfu_maperr(scf_error())) == SE_NOTFOUND) |
|
178 (void) error_scf(error, &e__ErrorCode_NOTFOUND, |
|
179 &e__ErrorTarget_PROPERTYGROUP, pgname, NULL); |
|
180 } |
|
181 if (snap != NULL) |
|
182 scf_snapshot_destroy(snap); |
|
183 return (se); |
|
184 } |
|
185 |
|
186 /* |
|
187 * Wrappers around the scf_iter_{instance,service} routines that take an |
|
188 * optional type. Behave like normal scf_* routines on error. |
|
189 */ |
|
190 |
|
191 static int |
|
192 iter_instance_pgs(scf_iter_t *iter, scf_instance_t *inst, const char *type) |
|
193 { |
|
194 if (type == NULL) |
|
195 return (scf_iter_instance_pgs(iter, inst)); |
|
196 return (scf_iter_instance_pgs_typed(iter, inst, type)); |
|
197 } |
|
198 |
|
199 static int |
|
200 iter_instance_pgs_composed(scf_iter_t *iter, scf_instance_t *inst, |
|
201 scf_snapshot_t *snap, const char *type) |
|
202 { |
|
203 if (type == NULL) |
|
204 return (scf_iter_instance_pgs_composed(iter, inst, snap)); |
|
205 return (scf_iter_instance_pgs_typed_composed(iter, inst, snap, type)); |
|
206 } |
|
207 |
|
208 static int |
|
209 iter_service_pgs(scf_iter_t *iter, scf_service_t *service, const char *type) |
|
210 { |
|
211 if (type == NULL) |
|
212 return (scf_iter_service_pgs(iter, service)); |
|
213 return (scf_iter_service_pgs_typed(iter, service, type)); |
|
214 } |
|
215 |
|
216 |
|
217 /* |
|
218 * Iterates over pgs in the composed view of the named snapshot. If |
|
219 * snapname is not specified, the current pgs/properties are used. A |
|
220 * property group type may be specified. Returns an error code or 0 |
|
221 * on success. |
|
222 */ |
|
223 scf_error_t |
|
224 smfu_instance_iter_composed_pgs(scf_handle_t *handle, scf_instance_t *instance, |
|
225 const char *snapname, const char *pgtype, scf_iter_t *iter) |
|
226 { |
|
227 int err = 0; |
|
228 scf_snapshot_t *snap = NULL; |
|
229 if (snapname != NULL) { |
|
230 if ((snap = scf_snapshot_create(handle)) == NULL || |
|
231 scf_instance_get_snapshot(instance, snapname, snap) == -1) { |
|
232 err = scf_error(); |
|
233 goto done; |
|
234 } |
|
235 } |
|
236 if (iter_instance_pgs_composed(iter, instance, snap, pgtype) == -1) |
|
237 err = scf_error(); |
|
238 |
|
239 done: |
|
240 if (snap != NULL) |
|
241 scf_snapshot_destroy(snap); |
|
242 return (err); |
|
243 } |
|
244 |
|
245 |
|
246 /* |
|
247 * Operates like scf_pg_get_property, but takes a fallback property |
|
248 * that is returned if the first one isn't found. Behaves like normal |
|
249 * scf_* routines on error. |
|
250 */ |
|
251 static int |
|
252 smfu_pg_get_fb_prop(scf_propertygroup_t *pg, |
|
253 const char *name, const char *fbname, scf_property_t *prop) |
|
254 { |
|
255 int res = scf_pg_get_property(pg, name, prop); |
|
256 if (res != 0 && scf_error() == SCF_ERROR_NOT_FOUND) |
|
257 res = scf_pg_get_property(pg, fbname, prop); |
|
258 return (res); |
|
259 } |
|
260 |
|
261 /* |
|
262 * Reads a string value from a traditionally localized template |
|
263 * property group (i.e. description, common name). First tries the |
|
264 * specified locale and then falls back to the C locale. |
|
265 */ |
|
266 svcerr_t |
|
267 smfu_get_l10n_str(scf_handle_t *handle, scf_propertygroup_t *pg, |
|
268 const char *locale, char **result) |
|
269 { |
|
270 scf_property_t *prop = scf_property_create(handle); |
|
271 scf_value_t *value = scf_value_create(handle); |
|
272 svcerr_t se = SE_OK; |
|
273 |
|
274 if (prop == NULL || value == NULL) { |
|
275 se = SE_FATAL; |
|
276 goto done; |
|
277 } |
|
278 |
|
279 if (smfu_pg_get_fb_prop(pg, locale, "C", prop) != 0 || |
|
280 scf_property_get_value(prop, value) != 0) { |
|
281 se = smfu_maperr(scf_error()); |
|
282 goto done; |
|
283 } |
|
284 |
|
285 scf_error_t serr = smfu_value_get_string(value, result); |
|
286 if (serr != 0) |
|
287 se = smfu_maperr(serr); |
|
288 |
|
289 done: |
|
290 scf_property_destroy(prop); |
|
291 scf_value_destroy(value); |
|
292 return (se); |
|
293 } |
|
294 |
|
295 /* |
|
296 * Obtains the specified property group of the service/instance |
|
297 * identified by "entity". For a service, returns the directly |
|
298 * attached property group, for an instance, returns the property group |
|
299 * from the composed view of the running snapshot. |
|
300 */ |
|
301 svcerr_t |
|
302 smfu_get_pg_r(scf_handle_t *handle, smfu_entity_t *entity, const char *name, |
|
303 scf_propertygroup_t *pg) |
|
304 { |
|
305 svcerr_t se = SE_OK; |
|
306 |
|
307 if (entity->instance != NULL) { |
|
308 se = smfu_instance_get_composed_pg(handle, entity->instance, |
|
309 "running", name, pg, NULL); |
|
310 } else if (scf_service_get_pg(entity->service, name, pg) != 0) { |
|
311 se = smfu_maperr(scf_error()); |
|
312 } |
|
313 |
|
314 return (se); |
|
315 } |
|
316 |
|
317 /* |
|
318 * Iterates over the property groups, of type "type" if "type" is |
|
319 * non-NULL, of the service/instance identified by "entity". For a |
|
320 * service, iterates over directly attached property groups, for an |
|
321 * instance, iterates over the property groups in the composed view of |
|
322 * the running snapshot. |
|
323 */ |
|
324 svcerr_t |
|
325 smfu_iter_pg_r(scf_handle_t *handle, smfu_entity_t *entity, const char *type, |
|
326 scf_iter_t *iter) |
|
327 { |
|
328 svcerr_t se = SE_OK; |
|
329 |
|
330 if (entity->instance != NULL) { |
|
331 scf_error_t scferr = smfu_instance_iter_composed_pgs(handle, |
|
332 entity->instance, "running", type, iter); |
|
333 if (scferr != 0) |
|
334 se = smfu_maperr(scferr); |
|
335 } else if (iter_service_pgs(iter, entity->service, type) != 0) { |
|
336 se = smfu_maperr(scf_error()); |
|
337 } |
|
338 |
|
339 return (se); |
|
340 } |
|
341 |
|
342 /* |
|
343 * Obtains the specified property group of the service/instance |
|
344 * identified by "entity". For both services and instances, returns |
|
345 * the directly attached property group. |
|
346 */ |
|
347 svcerr_t |
|
348 smfu_get_pg(smfu_entity_t *entity, const char *name, |
|
349 scf_propertygroup_t *pg, adr_data_t **error) |
|
350 { |
|
351 svcerr_t se = SE_OK; |
|
352 |
|
353 if (entity->instance != NULL) { |
|
354 if (scf_instance_get_pg(entity->instance, name, pg) != 0) |
|
355 se = smfu_maperr(scf_error()); |
|
356 } else if (scf_service_get_pg(entity->service, name, pg) != 0) { |
|
357 se = smfu_maperr(scf_error()); |
|
358 } |
|
359 |
|
360 if (se == SE_NOTFOUND) |
|
361 (void) error_scf(error, &e__ErrorCode_NOTFOUND, |
|
362 &e__ErrorTarget_PROPERTYGROUP, NULL, NULL); |
|
363 |
|
364 return (se); |
|
365 } |
|
366 |
|
367 /* |
|
368 * Iterates over the property groups, of type "type" if "type" is |
|
369 * non-NULL, of the service/instance identified by "entity". For both |
|
370 * services and instances, iterates over directly attached property |
|
371 * groups. |
|
372 */ |
|
373 svcerr_t |
|
374 smfu_iter_pg(smfu_entity_t *entity, const char *type, |
|
375 scf_iter_t *iter) |
|
376 { |
|
377 svcerr_t se = SE_OK; |
|
378 |
|
379 if (entity->instance != NULL) { |
|
380 if (iter_instance_pgs(iter, entity->instance, type) != 0) |
|
381 se = smfu_maperr(scf_error()); |
|
382 } else if (iter_service_pgs(iter, entity->service, type) != 0) { |
|
383 se = smfu_maperr(scf_error()); |
|
384 } |
|
385 |
|
386 return (se); |
|
387 } |
|
388 |
|
389 /* |
|
390 * Iterates over all services and instances on the system. Calls scb() |
|
391 * on each service if scb is non-NULL. Calls icb() on each instance if |
|
392 * icb is non-NULL. |
|
393 */ |
|
394 svcerr_t |
|
395 smfu_iter_svcs(scf_handle_t *h, svc_callback_t scb, inst_callback_t icb, |
|
396 void *arg) |
|
397 { |
|
398 svcerr_t se = SE_OK; |
|
399 |
|
400 scf_scope_t *scope = scf_scope_create(h); |
|
401 scf_iter_t *siter = scf_iter_create(h); |
|
402 scf_iter_t *iiter = scf_iter_create(h); |
|
403 scf_service_t *service = scf_service_create(h); |
|
404 scf_instance_t *instance = scf_instance_create(h); |
|
405 char sname[max_name + 1]; |
|
406 char iname[max_name + 1]; |
|
407 |
|
408 if (scope == NULL || siter == NULL || iiter == NULL || |
|
409 service == NULL || instance == NULL) { |
|
410 se = SE_FATAL; |
|
411 goto out; |
|
412 } |
|
413 |
|
414 if (scf_handle_get_scope(h, SCF_SCOPE_LOCAL, scope) == -1 || |
|
415 scf_iter_scope_services(siter, scope) == -1) { |
|
416 se = smfu_maperr(scf_error()); |
|
417 goto out; |
|
418 } |
|
419 |
|
420 int e; |
|
421 while ((e = scf_iter_next_service(siter, service)) > 0) { |
|
422 if (scf_service_get_name(service, sname, sizeof (sname)) |
|
423 == -1) { |
|
424 se = smfu_maperr(scf_error()); |
|
425 goto out; |
|
426 } |
|
427 if (scb) { |
|
428 if ((se = scb(h, service, sname, arg)) != SE_OK) |
|
429 goto out; |
|
430 } |
|
431 |
|
432 if (icb) { |
|
433 if (scf_iter_service_instances(iiter, service) == -1) { |
|
434 se = smfu_maperr(scf_error()); |
|
435 goto out; |
|
436 } |
|
437 while (scf_iter_next_instance(iiter, instance) > 0) { |
|
438 if (scf_instance_get_name(instance, iname, |
|
439 sizeof (iname)) == -1) { |
|
440 se = smfu_maperr(scf_error()); |
|
441 goto out; |
|
442 } |
|
443 se = icb(h, instance, sname, iname, arg); |
|
444 if (se != SE_OK) |
|
445 goto out; |
|
446 } |
|
447 } |
|
448 } |
|
449 if (e != 0) |
|
450 se = smfu_maperr(scf_error()); |
|
451 |
|
452 out: |
|
453 scf_instance_destroy(instance); |
|
454 scf_service_destroy(service); |
|
455 scf_iter_destroy(iiter); |
|
456 scf_iter_destroy(siter); |
|
457 scf_scope_destroy(scope); |
|
458 return (se == SE_BREAK ? SE_OK : se); |
|
459 } |
|
460 |
|
461 /* |
|
462 * Look up an entity based on service and (optional) instance name. |
|
463 */ |
|
464 svcerr_t |
|
465 smfu_lookup(scf_handle_t *scfhandle, const char *sname, const char *iname, |
|
466 smfu_entity_t *entity) |
|
467 { |
|
468 svcerr_t se = SE_FATAL; |
|
469 scf_scope_t *scope = scf_scope_create(scfhandle); |
|
470 scf_service_t *service = scf_service_create(scfhandle); |
|
471 scf_instance_t *instance = scf_instance_create(scfhandle); |
|
472 |
|
473 if (scope == NULL || service == NULL || instance == NULL) { |
|
474 se = SE_FATAL; |
|
475 goto error; |
|
476 } |
|
477 |
|
478 if (scf_handle_get_scope(scfhandle, SCF_SCOPE_LOCAL, scope) != 0 || |
|
479 scf_scope_get_service(scope, sname, service) != 0) { |
|
480 se = smfu_maperr(scf_error()); |
|
481 goto error; |
|
482 } |
|
483 |
|
484 if (iname != NULL) { |
|
485 if (scf_service_get_instance(service, iname, instance) != 0) { |
|
486 se = smfu_maperr(scf_error()); |
|
487 goto error; |
|
488 } |
|
489 entity->instance = instance; |
|
490 } |
|
491 |
|
492 entity->service = service; |
|
493 scf_scope_destroy(scope); |
|
494 return (SE_OK); |
|
495 |
|
496 error: |
|
497 scf_instance_destroy(instance); |
|
498 scf_service_destroy(service); |
|
499 scf_scope_destroy(scope); |
|
500 |
|
501 if (se == SE_NOTFOUND) |
|
502 return (SE_STALE); |
|
503 return (se); |
|
504 } |
|
505 |
|
506 /* |
|
507 * Free an entity. |
|
508 */ |
|
509 void |
|
510 smfu_entity_destroy(smfu_entity_t *entity) |
|
511 { |
|
512 scf_service_destroy(entity->service); |
|
513 scf_instance_destroy(entity->instance); |
|
514 } |
|
515 |
|
516 |
|
517 /* |
|
518 * Test for the existence of service sname, optionally with instance iname. |
|
519 */ |
|
520 svcerr_t |
|
521 smfu_test(const char *sname, const char *iname) |
|
522 { |
|
523 svcerr_t se; |
|
524 do { |
|
525 rad_handle_t *rh = rh_fetch(); |
|
526 if (rh == NULL) { |
|
527 se = smfu_maperr(scf_error()); |
|
528 } else { |
|
529 smfu_entity_t entity = SMFU_ENTITY_INIT; |
|
530 se = smfu_lookup(rh_hdl(rh), sname, iname, &entity); |
|
531 smfu_entity_destroy(&entity); |
|
532 } |
|
533 |
|
534 if (se == SE_RECONNECT) |
|
535 rh_kill(rh); |
|
536 rh_rele(rh); |
|
537 } while (se == SE_RETRY || se == SE_RECONNECT); |
|
538 |
|
539 return (se); |
|
540 } |
|
541 |
|
542 /* |
|
543 * Construct the ADR name for a service/instance. |
|
544 */ |
|
545 adr_name_t * |
|
546 smfu_name_alloc(const char *sname, const char *iname) |
|
547 { |
|
548 if (iname != NULL) |
|
549 return (adr_name_vcreate(SMF_DOMAIN, 3, |
|
550 SMF_KEY_TYPE, SMF_TYPE_INSTANCE, |
|
551 SMF_KEY_SERVICE, sname, |
|
552 SMF_KEY_INSTANCE, iname)); |
|
553 return (adr_name_vcreate(SMF_DOMAIN, 2, |
|
554 SMF_KEY_TYPE, SMF_TYPE_SERVICE, |
|
555 SMF_KEY_SERVICE, sname)); |
|
556 } |
|
557 |
|
558 /* |
|
559 * Construct the FMRI for a service/instance. |
|
560 */ |
|
561 char * |
|
562 smfu_fmri_alloc(const char *sname, const char *iname) |
|
563 { |
|
564 char *result = NULL; |
|
565 if (iname != NULL) |
|
566 (void) asprintf(&result, "svc:/%s:%s", sname, iname); |
|
567 else |
|
568 (void) asprintf(&result, "svc:/%s", sname); |
|
569 return (result); |
|
570 } |
|
571 |
|
572 void |
|
573 smfu_obj_free(smfobj_t *obj) |
|
574 { |
|
575 free(obj->sname); |
|
576 free(obj->iname); |
|
577 free(obj->fmri); |
|
578 free(obj); |
|
579 } |
|
580 |
|
581 smfobj_t * |
|
582 smfu_obj_alloc(const char *sname, const char *iname) |
|
583 { |
|
584 smfobj_t *smfo = rad_zalloc(sizeof (smfobj_t)); |
|
585 if (smfo == NULL) |
|
586 return (NULL); |
|
587 |
|
588 if ((smfo->sname = strdup(sname)) == NULL || |
|
589 (iname != NULL && (smfo->iname = strdup(iname)) == NULL) || |
|
590 (smfo->fmri = smfu_fmri_alloc(sname, iname)) == NULL) { |
|
591 smfu_obj_free(smfo); |
|
592 return (NULL); |
|
593 } |
|
594 |
|
595 return (smfo); |
|
596 } |
|
597 |
|
598 |
|
599 /* |
|
600 * Automatic retry mechanism. |
|
601 * |
|
602 * Calls cb() repeatedly while it returns SE_RETRY, reconnecting to the |
|
603 * repository as necessary. |
|
604 * |
|
605 * For the convenience of the callback, if a adr_data_t pointer is stored |
|
606 * in its result argument on failure it is freed. Also verifies the |
|
607 * result on success. |
|
608 */ |
|
609 static conerr_t |
|
610 smfu_rtrun_int(smfu_rtfunc_t cb, void *arg, adr_data_t **ret, |
|
611 adr_data_t **error, boolean_t nullable) |
|
612 { |
|
613 svcerr_t se = SE_OK; |
|
614 adr_data_t *result = NULL; |
|
615 |
|
616 do { |
|
617 rad_handle_t *rh = rh_fetch(); |
|
618 if (rh == NULL) |
|
619 se = smfu_maperr(scf_error()); |
|
620 else |
|
621 se = cb(rh_hdl(rh), arg, &result, error); |
|
622 |
|
623 if (se != SE_OK && result != NULL) { |
|
624 adr_data_free(result); |
|
625 result = NULL; |
|
626 } |
|
627 |
|
628 if (se == SE_RECONNECT) |
|
629 rh_kill(rh); |
|
630 rh_rele(rh); |
|
631 } while (se == SE_RETRY || se == SE_RECONNECT); |
|
632 |
|
633 assert(ret != NULL || result == NULL); |
|
634 if (ret != NULL && se == SE_OK) { |
|
635 if ((nullable && result == NULL) || |
|
636 adr_data_verify(result, NULL, B_TRUE)) { |
|
637 *ret = result; |
|
638 } else { |
|
639 adr_data_free(result); |
|
640 se = internal_error(error, NULL); |
|
641 } |
|
642 } |
|
643 |
|
644 if (se == SE_OK) |
|
645 return (ce_ok); |
|
646 if (se == SE_STALE) |
|
647 return (ce_notfound); |
|
648 |
|
649 if (se == SE_FATAL || se == SE_NOTFOUND) { |
|
650 if (error != NULL && *error == NULL) |
|
651 (void) internal_error(error, NULL); |
|
652 return (ce_object); |
|
653 } |
|
654 |
|
655 /* Shouldn't be seeing SE_RETRY, SE_RECONNECT, SE_BREAK */ |
|
656 rad_log(RL_FATAL, "smfu_rtrun: callback returned bad error: %d", se); |
|
657 return (ce_system); |
|
658 } |
|
659 |
|
660 conerr_t |
|
661 smfu_rtrun_opt(smfu_rtfunc_t cb, void *arg, adr_data_t **ret, |
|
662 adr_data_t **error) |
|
663 { |
|
664 return (smfu_rtrun_int(cb, arg, ret, error, B_TRUE)); |
|
665 } |
|
666 |
|
667 conerr_t |
|
668 smfu_rtrun(smfu_rtfunc_t cb, void *arg, adr_data_t **ret, adr_data_t **error) |
|
669 { |
|
670 return (smfu_rtrun_int(cb, arg, ret, error, B_FALSE)); |
|
671 } |
|
672 |
|
673 |
|
674 void |
|
675 smfu_init() |
|
676 { |
|
677 /* |
|
678 * Initialize constants |
|
679 */ |
|
680 max_fmri = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH); |
|
681 max_pgtype = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH); |
|
682 max_name = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH); |
|
683 max_value = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); |
|
684 } |
|