8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / svc / startd / libscf.c
blobc4a3b20117637bcc1d48ed329951865ccb6232e5
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2012 Milan Jurik. All rights reserved.
28 #include <sys/contract/process.h>
29 #include <assert.h>
30 #include <errno.h>
31 #include <libscf.h>
32 #include <libscf_priv.h>
33 #include <poll.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
38 #include "startd.h"
40 #define SMF_SNAPSHOT_RUNNING "running"
42 #define INFO_EVENTS_ALL "info_events_all"
44 char *
45 inst_fmri_to_svc_fmri(const char *fmri)
47 char *buf, *sfmri;
48 const char *scope, *svc;
49 int r;
50 boolean_t local;
52 buf = startd_alloc(max_scf_fmri_size);
53 sfmri = startd_alloc(max_scf_fmri_size);
55 (void) strcpy(buf, fmri);
57 r = scf_parse_svc_fmri(buf, &scope, &svc, NULL, NULL, NULL);
58 assert(r == 0);
60 local = strcmp(scope, SCF_SCOPE_LOCAL) == 0;
62 (void) snprintf(sfmri, max_scf_fmri_size, "svc:%s%s/%s",
63 local ? "" : "//", local ? "" : scope, svc);
65 startd_free(buf, max_scf_fmri_size);
67 return (sfmri);
71 * Wrapper for the scf_*_create() functions. On SCF_ERROR_NO_MEMORY and
72 * SCF_ERROR_NO_RESOURCES, retries or dies. So this can only fail with
73 * SCF_ERROR_INVALID_ARGUMENT, if h is NULL.
75 void *
76 libscf_object_create(void *f(scf_handle_t *), scf_handle_t *h)
78 void *o;
79 uint_t try, msecs;
80 scf_error_t err;
82 o = f(h);
83 if (o != NULL)
84 return (o);
85 err = scf_error();
86 if (err != SCF_ERROR_NO_MEMORY && err != SCF_ERROR_NO_RESOURCES)
87 return (NULL);
89 msecs = ALLOC_DELAY;
91 for (try = 0; try < ALLOC_RETRY; ++try) {
92 (void) poll(NULL, 0, msecs);
93 msecs *= ALLOC_DELAY_MULT;
94 o = f(h);
95 if (o != NULL)
96 return (o);
97 err = scf_error();
98 if (err != SCF_ERROR_NO_MEMORY && err != SCF_ERROR_NO_RESOURCES)
99 return (NULL);
102 uu_die("Insufficient memory.\n");
103 /* NOTREACHED */
106 scf_snapshot_t *
107 libscf_get_running_snapshot(scf_instance_t *inst)
109 scf_handle_t *h;
110 scf_snapshot_t *snap;
112 h = scf_instance_handle(inst);
113 if (h == NULL)
114 return (NULL);
116 snap = scf_snapshot_create(h);
117 if (snap == NULL)
118 return (NULL);
120 if (scf_instance_get_snapshot(inst, SMF_SNAPSHOT_RUNNING, snap) == 0)
121 return (snap);
123 scf_snapshot_destroy(snap);
124 return (NULL);
128 * Make sure a service has a "running" snapshot. If it doesn't, make one from
129 * the editing configuration.
131 scf_snapshot_t *
132 libscf_get_or_make_running_snapshot(scf_instance_t *inst, const char *fmri,
133 boolean_t retake)
135 scf_handle_t *h;
136 scf_snapshot_t *snap;
138 h = scf_instance_handle(inst);
140 snap = scf_snapshot_create(h);
141 if (snap == NULL)
142 goto err;
144 if (scf_instance_get_snapshot(inst, SMF_SNAPSHOT_RUNNING, snap) == 0)
145 return (snap);
147 switch (scf_error()) {
148 case SCF_ERROR_NOT_FOUND:
149 break;
151 case SCF_ERROR_DELETED:
152 scf_snapshot_destroy(snap);
153 return (NULL);
155 default:
156 err:
157 log_error(LOG_NOTICE,
158 "Could not check for running snapshot of %s (%s).\n", fmri,
159 scf_strerror(scf_error()));
160 scf_snapshot_destroy(snap);
161 return (NULL);
164 if (_scf_snapshot_take_new(inst, SMF_SNAPSHOT_RUNNING, snap) == 0) {
165 log_framework(LOG_DEBUG, "Took running snapshot for %s.\n",
166 fmri);
167 } else {
168 if (retake && scf_error() == SCF_ERROR_BACKEND_READONLY)
169 restarter_mark_pending_snapshot(fmri,
170 RINST_RETAKE_RUNNING);
171 else
172 log_error(LOG_DEBUG,
173 "Could not create running snapshot for %s "
174 "(%s).\n", fmri, scf_strerror(scf_error()));
176 scf_snapshot_destroy(snap);
177 snap = NULL;
180 return (snap);
184 * When a service comes up, point the "start" snapshot at the "running"
185 * snapshot. Returns 0 on success, ENOTSUP if fmri designates something other
186 * than an instance, ECONNABORTED, ENOENT if the instance does not exist, or
187 * EACCES.
190 libscf_snapshots_poststart(scf_handle_t *h, const char *fmri, boolean_t retake)
192 scf_instance_t *inst = NULL;
193 scf_snapshot_t *running, *start = NULL;
194 int ret = 0, r;
196 r = libscf_fmri_get_instance(h, fmri, &inst);
197 switch (r) {
198 case 0:
199 break;
201 case ENOTSUP:
202 case ECONNABORTED:
203 case ENOENT:
204 return (r);
206 case EINVAL:
207 default:
208 assert(0);
209 abort();
212 start = safe_scf_snapshot_create(h);
214 again:
215 running = libscf_get_or_make_running_snapshot(inst, fmri, retake);
216 if (running == NULL) {
217 ret = 0;
218 goto out;
221 lookup:
222 if (scf_instance_get_snapshot(inst, "start", start) != 0) {
223 switch (scf_error()) {
224 case SCF_ERROR_CONNECTION_BROKEN:
225 default:
226 ret = ECONNABORTED;
227 goto out;
229 case SCF_ERROR_NOT_FOUND:
230 if (_scf_snapshot_take_new(inst, "start", start) != 0) {
231 switch (scf_error()) {
232 case SCF_ERROR_CONNECTION_BROKEN:
233 default:
234 ret = ECONNABORTED;
235 goto out;
237 case SCF_ERROR_DELETED:
238 ret = ENOENT;
239 goto out;
241 case SCF_ERROR_EXISTS:
242 goto lookup;
244 case SCF_ERROR_NO_RESOURCES:
245 uu_die("Repository server out of "
246 "resources.\n");
247 /* NOTREACHED */
249 case SCF_ERROR_BACKEND_READONLY:
250 goto readonly;
252 case SCF_ERROR_PERMISSION_DENIED:
253 uu_die("Insufficient privileges.\n");
254 /* NOTREACHED */
256 case SCF_ERROR_BACKEND_ACCESS:
257 ret = EACCES;
258 goto out;
260 case SCF_ERROR_HANDLE_MISMATCH:
261 case SCF_ERROR_INTERNAL:
262 case SCF_ERROR_INVALID_ARGUMENT:
263 case SCF_ERROR_NOT_SET:
264 bad_error("_scf_snapshot_take_new",
265 scf_error());
268 break;
270 case SCF_ERROR_DELETED:
271 ret = ENOENT;
272 goto out;
274 case SCF_ERROR_HANDLE_MISMATCH:
275 case SCF_ERROR_NOT_SET:
276 case SCF_ERROR_INVALID_ARGUMENT:
277 bad_error("scf_instance_get_snapshot", scf_error());
281 if (_scf_snapshot_attach(running, start) == 0) {
282 log_framework(LOG_DEBUG, "Updated \"start\" snapshot for %s.\n",
283 fmri);
284 } else {
285 switch (scf_error()) {
286 case SCF_ERROR_CONNECTION_BROKEN:
287 default:
288 ret = ECONNABORTED;
289 goto out;
291 case SCF_ERROR_DELETED:
292 scf_snapshot_destroy(running);
293 goto again;
295 case SCF_ERROR_NO_RESOURCES:
296 uu_die("Repository server out of resources.\n");
297 /* NOTREACHED */
299 case SCF_ERROR_PERMISSION_DENIED:
300 uu_die("Insufficient privileges.\n");
301 /* NOTREACHED */
303 case SCF_ERROR_BACKEND_ACCESS:
304 ret = EACCES;
305 goto out;
307 case SCF_ERROR_BACKEND_READONLY:
308 readonly:
309 if (retake)
310 restarter_mark_pending_snapshot(fmri,
311 RINST_RETAKE_START);
312 break;
314 case SCF_ERROR_HANDLE_MISMATCH:
315 case SCF_ERROR_NOT_SET:
316 bad_error("_scf_snapshot_attach", scf_error());
320 out:
321 scf_snapshot_destroy(start);
322 scf_snapshot_destroy(running);
323 scf_instance_destroy(inst);
325 return (ret);
329 * Before a refresh, update the "running" snapshot from the editing
330 * configuration.
332 * Returns 0 on success and -1 on failure.
335 libscf_snapshots_refresh(scf_instance_t *inst, const char *fmri)
337 scf_handle_t *h;
338 scf_snapshot_t *snap;
339 boolean_t err = 1;
341 h = scf_instance_handle(inst);
342 if (h == NULL)
343 goto out;
345 snap = scf_snapshot_create(h);
346 if (snap == NULL)
347 goto out;
349 if (scf_instance_get_snapshot(inst, SMF_SNAPSHOT_RUNNING, snap) == 0) {
350 if (_scf_snapshot_take_attach(inst, snap) == 0)
351 err = 0;
352 } else {
353 switch (scf_error()) {
354 case SCF_ERROR_DELETED:
355 err = 0;
356 goto out;
358 case SCF_ERROR_NOT_FOUND:
359 break;
361 case SCF_ERROR_NOT_SET:
362 assert(0);
363 abort();
364 /* NOTREACHED */
366 default:
367 goto out;
370 log_error(LOG_DEBUG,
371 "Service %s has no %s snapshot; creating one.\n", fmri,
372 SMF_SNAPSHOT_RUNNING);
374 if (_scf_snapshot_take_new(inst, SMF_SNAPSHOT_RUNNING,
375 snap) == 0)
376 err = 0;
379 out:
380 scf_snapshot_destroy(snap);
382 if (!err)
383 return (0);
385 log_error(LOG_WARNING,
386 "Could not update \"running\" snapshot for refresh of %s.\n", fmri);
387 return (-1);
391 * int libscf_read_single_astring()
392 * Reads a single astring value of the requested property into the
393 * pre-allocated buffer (conventionally of size max_scf_value_size).
394 * Multiple values constitute an error.
396 * Returns 0 on success or LIBSCF_PROPERTY_ABSENT or LIBSCF_PROPERTY_ERROR.
398 static int
399 libscf_read_single_astring(scf_handle_t *h, scf_property_t *prop, char **ret)
401 scf_value_t *val = safe_scf_value_create(h);
402 int r = 0;
404 if (scf_property_get_value(prop, val) == -1) {
405 if (scf_error() == SCF_ERROR_NOT_FOUND)
406 r = LIBSCF_PROPERTY_ABSENT;
407 else
408 r = LIBSCF_PROPERTY_ERROR;
409 goto read_single_astring_fail;
412 if (scf_value_get_astring(val, *ret, max_scf_value_size) <= 0) {
413 r = LIBSCF_PROPERTY_ERROR;
414 goto read_single_astring_fail;
417 read_single_astring_fail:
418 scf_value_destroy(val);
419 return (r);
423 * libscf_get_stn_tset
425 int32_t
426 libscf_get_stn_tset(scf_instance_t *inst)
428 scf_handle_t *h = scf_instance_handle(inst);
429 scf_propertygroup_t *pg = scf_pg_create(h);
430 char *pgname = NULL;
431 int32_t t, f, tset;
433 assert(inst != NULL);
435 pgname = startd_alloc(max_scf_fmri_size);
436 if (h == NULL || pg == NULL) {
437 tset = -1;
438 goto cleanup;
441 for (tset = 0, t = 1; t < SCF_STATE_ALL; t <<= 1) {
442 f = t << 16;
444 (void) strcpy(pgname, SCF_STN_PREFIX_TO);
445 (void) strlcat(pgname, smf_state_to_string(t),
446 max_scf_fmri_size);
448 if (scf_instance_get_pg_composed(inst, NULL, pgname, pg) ==
449 SCF_SUCCESS) {
450 tset |= t;
451 } else if (scf_error() != SCF_ERROR_NOT_FOUND && scf_error() !=
452 SCF_ERROR_DELETED) {
453 tset = -1;
454 goto cleanup;
457 (void) strcpy(pgname, SCF_STN_PREFIX_FROM);
458 (void) strlcat(pgname, smf_state_to_string(t),
459 max_scf_fmri_size);
461 if (scf_instance_get_pg_composed(inst, NULL, pgname, pg) ==
462 SCF_SUCCESS) {
463 tset |= f;
464 } else if (scf_error() != SCF_ERROR_NOT_FOUND && scf_error() !=
465 SCF_ERROR_DELETED) {
466 tset = -1;
467 goto cleanup;
471 cleanup:
472 scf_pg_destroy(pg);
473 startd_free(pgname, max_scf_fmri_size);
475 return (tset);
478 static int32_t
479 libscf_get_global_stn_tset(scf_handle_t *h)
481 scf_instance_t *inst = scf_instance_create(h);
482 int32_t tset = -1;
484 if (inst == NULL) {
485 goto cleanup;
488 if (scf_handle_decode_fmri(h, SCF_INSTANCE_GLOBAL, NULL, NULL, inst,
489 NULL, NULL, SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0) {
490 goto cleanup;
493 tset = libscf_get_stn_tset(inst);
495 cleanup:
496 scf_instance_destroy(inst);
498 if (tset == -1)
499 log_framework(LOG_WARNING,
500 "Failed to get system wide notification parameters: %s\n",
501 scf_strerror(scf_error()));
503 return (tset);
506 static int
507 libscf_read_state(const scf_propertygroup_t *pg, const char *prop_name,
508 restarter_instance_state_t *state)
510 scf_handle_t *h;
511 scf_property_t *prop;
512 char *char_state = startd_alloc(max_scf_value_size);
513 int ret = 0;
515 h = scf_pg_handle(pg);
516 prop = safe_scf_property_create(h);
518 if (scf_pg_get_property(pg, prop_name, prop) == -1) {
519 if (scf_error() == SCF_ERROR_NOT_FOUND)
520 ret = LIBSCF_PROPERTY_ABSENT;
521 else
522 ret = LIBSCF_PROPERTY_ERROR;
523 } else {
524 ret = libscf_read_single_astring(h, prop, &char_state);
525 if (ret != 0) {
526 if (ret != LIBSCF_PROPERTY_ABSENT)
527 ret = LIBSCF_PROPERTY_ERROR;
528 } else {
529 *state = restarter_string_to_state(char_state);
530 ret = 0;
534 startd_free(char_state, max_scf_value_size);
535 scf_property_destroy(prop);
536 return (ret);
540 * int libscf_read_states(const scf_propertygroup_t *,
541 * restarter_instance_state_t *, restarter_instance_state_t *)
543 * Set the current state and next_state values for the given service instance.
544 * Returns 0 on success, or a libscf error code on failure.
547 libscf_read_states(const scf_propertygroup_t *pg,
548 restarter_instance_state_t *state, restarter_instance_state_t *next_state)
550 int state_ret, next_state_ret, ret;
552 state_ret = libscf_read_state(pg, SCF_PROPERTY_STATE, state);
553 next_state_ret = libscf_read_state(pg, SCF_PROPERTY_NEXT_STATE,
554 next_state);
556 if (state_ret == LIBSCF_PROPERTY_ERROR ||
557 next_state_ret == LIBSCF_PROPERTY_ERROR) {
558 ret = LIBSCF_PROPERTY_ERROR;
559 } else if (state_ret == 0 && next_state_ret == 0) {
560 ret = 0;
561 } else if (state_ret == LIBSCF_PROPERTY_ABSENT &&
562 next_state_ret == LIBSCF_PROPERTY_ABSENT) {
563 *state = RESTARTER_STATE_UNINIT;
564 *next_state = RESTARTER_STATE_NONE;
565 ret = 0;
566 } else if (state_ret == LIBSCF_PROPERTY_ABSENT ||
567 next_state_ret == LIBSCF_PROPERTY_ABSENT) {
568 log_framework(LOG_DEBUG,
569 "Only one repository state exists, setting "
570 "restarter states to MAINTENANCE and NONE\n");
571 *state = RESTARTER_STATE_MAINT;
572 *next_state = RESTARTER_STATE_NONE;
573 ret = 0;
574 } else {
575 ret = LIBSCF_PROPERTY_ERROR;
578 read_states_out:
579 return (ret);
583 * depgroup_empty()
585 * Returns 0 if not empty.
586 * Returns 1 if empty.
587 * Returns -1 on error (check scf_error()).
590 depgroup_empty(scf_handle_t *h, scf_propertygroup_t *pg)
592 int empty = 1;
593 scf_iter_t *iter;
594 scf_property_t *prop;
595 int ret;
597 iter = safe_scf_iter_create(h);
598 prop = safe_scf_property_create(h);
600 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS) {
601 scf_property_destroy(prop);
602 scf_iter_destroy(iter);
603 return (-1);
606 ret = scf_iter_next_property(iter, prop);
607 if (ret < 0) {
608 scf_property_destroy(prop);
609 scf_iter_destroy(iter);
610 return (-1);
613 if (ret == 1)
614 empty = 0;
616 scf_property_destroy(prop);
617 scf_iter_destroy(iter);
619 return (empty);
622 gv_type_t
623 depgroup_read_scheme(scf_handle_t *h, scf_propertygroup_t *pg)
625 scf_property_t *prop;
626 char *scheme = startd_alloc(max_scf_value_size);
627 gv_type_t ret;
629 prop = safe_scf_property_create(h);
631 if (scf_pg_get_property(pg, SCF_PROPERTY_TYPE, prop) == -1 ||
632 libscf_read_single_astring(h, prop, &scheme) != 0) {
633 scf_property_destroy(prop);
634 startd_free(scheme, max_scf_value_size);
635 return (GVT_UNSUPPORTED);
638 if (strcmp(scheme, "service") == 0)
639 ret = GVT_INST;
640 else if (strcmp(scheme, "path") == 0)
641 ret = GVT_FILE;
642 else
643 ret = GVT_UNSUPPORTED;
645 startd_free(scheme, max_scf_value_size);
646 scf_property_destroy(prop);
647 return (ret);
650 depgroup_type_t
651 depgroup_read_grouping(scf_handle_t *h, scf_propertygroup_t *pg)
653 char *grouping = startd_alloc(max_scf_value_size);
654 depgroup_type_t ret;
655 scf_property_t *prop = safe_scf_property_create(h);
657 if (scf_pg_get_property(pg, SCF_PROPERTY_GROUPING, prop) == -1 ||
658 libscf_read_single_astring(h, prop, &grouping) != 0) {
659 scf_property_destroy(prop);
660 startd_free(grouping, max_scf_value_size);
661 return (DEPGRP_UNSUPPORTED);
664 if (strcmp(grouping, SCF_DEP_REQUIRE_ANY) == 0)
665 ret = DEPGRP_REQUIRE_ANY;
666 else if (strcmp(grouping, SCF_DEP_REQUIRE_ALL) == 0)
667 ret = DEPGRP_REQUIRE_ALL;
668 else if (strcmp(grouping, SCF_DEP_OPTIONAL_ALL) == 0)
669 ret = DEPGRP_OPTIONAL_ALL;
670 else if (strcmp(grouping, SCF_DEP_EXCLUDE_ALL) == 0)
671 ret = DEPGRP_EXCLUDE_ALL;
672 else {
673 ret = DEPGRP_UNSUPPORTED;
675 startd_free(grouping, max_scf_value_size);
676 scf_property_destroy(prop);
677 return (ret);
680 restarter_error_t
681 depgroup_read_restart(scf_handle_t *h, scf_propertygroup_t *pg)
683 scf_property_t *prop = safe_scf_property_create(h);
684 char *restart_on = startd_alloc(max_scf_value_size);
685 restarter_error_t ret;
687 if (scf_pg_get_property(pg, SCF_PROPERTY_RESTART_ON, prop) == -1 ||
688 libscf_read_single_astring(h, prop, &restart_on) != 0) {
689 startd_free(restart_on, max_scf_value_size);
690 scf_property_destroy(prop);
691 return (RERR_UNSUPPORTED);
694 if (strcmp(restart_on, SCF_DEP_RESET_ON_ERROR) == 0)
695 ret = RERR_FAULT;
696 else if (strcmp(restart_on, SCF_DEP_RESET_ON_RESTART) == 0)
697 ret = RERR_RESTART;
698 else if (strcmp(restart_on, SCF_DEP_RESET_ON_REFRESH) == 0)
699 ret = RERR_REFRESH;
700 else if (strcmp(restart_on, SCF_DEP_RESET_ON_NONE) == 0)
701 ret = RERR_NONE;
702 else
703 ret = RERR_UNSUPPORTED;
705 startd_free(restart_on, max_scf_value_size);
706 scf_property_destroy(prop);
707 return (ret);
711 * int get_boolean()
712 * Fetches the value of a boolean property of the given property group.
713 * Returns
714 * 0 - success
715 * ECONNABORTED - repository connection broken
716 * ECANCELED - pg was deleted
717 * ENOENT - the property doesn't exist or has no values
718 * EINVAL - the property has the wrong type
719 * the property is not single-valued
720 * EACCES - the current user does not have permission to read the value
722 static int
723 get_boolean(scf_propertygroup_t *pg, const char *propname, uint8_t *valuep)
725 scf_handle_t *h;
726 scf_property_t *prop;
727 scf_value_t *val;
728 int ret = 0, r;
729 scf_type_t type;
731 h = scf_pg_handle(pg);
732 prop = safe_scf_property_create(h);
733 val = safe_scf_value_create(h);
735 if (scf_pg_get_property(pg, propname, prop) != 0) {
736 switch (scf_error()) {
737 case SCF_ERROR_CONNECTION_BROKEN:
738 default:
739 ret = ECONNABORTED;
740 goto out;
742 case SCF_ERROR_DELETED:
743 ret = ECANCELED;
744 goto out;
746 case SCF_ERROR_NOT_FOUND:
747 ret = ENOENT;
748 goto out;
750 case SCF_ERROR_HANDLE_MISMATCH:
751 case SCF_ERROR_INVALID_ARGUMENT:
752 case SCF_ERROR_NOT_SET:
753 bad_error("scf_pg_get_property", scf_error());
757 if (scf_property_type(prop, &type) != 0) {
758 switch (scf_error()) {
759 case SCF_ERROR_CONNECTION_BROKEN:
760 default:
761 ret = ECONNABORTED;
762 goto out;
764 case SCF_ERROR_DELETED:
765 ret = ENOENT;
766 goto out;
768 case SCF_ERROR_NOT_SET:
769 bad_error("scf_property_type", scf_error());
773 if (type != SCF_TYPE_BOOLEAN) {
774 ret = EINVAL;
775 goto out;
778 if (scf_property_get_value(prop, val) != 0) {
779 switch (scf_error()) {
780 case SCF_ERROR_CONNECTION_BROKEN:
781 default:
782 ret = ECONNABORTED;
783 goto out;
785 case SCF_ERROR_DELETED:
786 case SCF_ERROR_NOT_FOUND:
787 ret = ENOENT;
788 goto out;
790 case SCF_ERROR_CONSTRAINT_VIOLATED:
791 ret = EINVAL;
792 goto out;
794 case SCF_ERROR_PERMISSION_DENIED:
795 ret = EACCES;
796 goto out;
798 case SCF_ERROR_NOT_SET:
799 bad_error("scf_property_get_value", scf_error());
803 r = scf_value_get_boolean(val, valuep);
804 assert(r == 0);
806 out:
807 scf_value_destroy(val);
808 scf_property_destroy(prop);
809 return (ret);
813 * get info event property from restarter:default
816 libscf_get_info_events_all(scf_propertygroup_t *pg)
818 uint8_t v;
819 int r = 0;
821 if (get_boolean(pg, INFO_EVENTS_ALL, &v) == 0) {
822 r = v;
823 } else if (scf_error() != SCF_ERROR_NOT_FOUND) {
824 uu_warn("Failed get_boolean %s/%s: %s\n",
825 SCF_PG_OPTIONS, INFO_EVENTS_ALL,
826 scf_strerror(scf_error()));
829 return (r);
833 * int get_count()
834 * Fetches the value of a count property of the given property group.
835 * Returns
836 * 0 - success
837 * ECONNABORTED - repository connection broken
838 * unknown libscf error
839 * ECANCELED - pg was deleted
840 * ENOENT - the property doesn't exist or has no values
841 * EINVAL - the property has the wrong type
842 * the property is not single-valued
843 * EACCES - the current user does not have permission to read the value
845 static int
846 get_count(scf_propertygroup_t *pg, const char *propname, uint64_t *valuep)
848 scf_handle_t *h;
849 scf_property_t *prop;
850 scf_value_t *val;
851 int ret = 0, r;
853 h = scf_pg_handle(pg);
854 prop = safe_scf_property_create(h);
855 val = safe_scf_value_create(h);
857 if (scf_pg_get_property(pg, propname, prop) != 0) {
858 switch (scf_error()) {
859 case SCF_ERROR_CONNECTION_BROKEN:
860 default:
861 ret = ECONNABORTED;
862 goto out;
864 case SCF_ERROR_DELETED:
865 ret = ECANCELED;
866 goto out;
868 case SCF_ERROR_NOT_FOUND:
869 ret = ENOENT;
870 goto out;
872 case SCF_ERROR_HANDLE_MISMATCH:
873 case SCF_ERROR_INVALID_ARGUMENT:
874 case SCF_ERROR_NOT_SET:
875 bad_error("scf_pg_get_property", scf_error());
879 if (scf_property_is_type(prop, SCF_TYPE_COUNT) != 0) {
880 switch (scf_error()) {
881 case SCF_ERROR_CONNECTION_BROKEN:
882 default:
883 ret = ECONNABORTED;
884 goto out;
886 case SCF_ERROR_TYPE_MISMATCH:
887 ret = EINVAL;
888 goto out;
890 case SCF_ERROR_DELETED:
891 ret = ECANCELED;
892 goto out;
894 case SCF_ERROR_INVALID_ARGUMENT:
895 case SCF_ERROR_NOT_BOUND:
896 case SCF_ERROR_NOT_SET:
897 bad_error("scf_property_is_type", scf_error());
901 if (scf_property_get_value(prop, val) != 0) {
902 switch (scf_error()) {
903 case SCF_ERROR_CONNECTION_BROKEN:
904 default:
905 ret = ECONNABORTED;
906 goto out;
908 case SCF_ERROR_DELETED:
909 ret = ECANCELED;
910 goto out;
912 case SCF_ERROR_NOT_FOUND:
913 ret = ENOENT;
914 goto out;
916 case SCF_ERROR_CONSTRAINT_VIOLATED:
917 ret = EINVAL;
918 goto out;
920 case SCF_ERROR_PERMISSION_DENIED:
921 ret = EACCES;
922 goto out;
924 case SCF_ERROR_NOT_SET:
925 bad_error("scf_property_get_value", scf_error());
929 r = scf_value_get_count(val, valuep);
930 assert(r == 0);
932 out:
933 scf_value_destroy(val);
934 scf_property_destroy(prop);
935 return (ret);
939 static void
940 get_restarter(scf_handle_t *h, scf_propertygroup_t *pg, char **restarter)
942 scf_property_t *prop = safe_scf_property_create(h);
944 if (scf_pg_get_property(pg, SCF_PROPERTY_RESTARTER, prop) == -1 ||
945 libscf_read_single_astring(h, prop, restarter) != 0)
946 *restarter[0] = '\0';
948 scf_property_destroy(prop);
952 * int libscf_instance_get_fmri(scf_instance_t *, char **)
953 * Give a valid SCF instance, return its FMRI. Returns 0 on success,
954 * ECONNABORTED, or ECANCELED if inst is deleted.
957 libscf_instance_get_fmri(scf_instance_t *inst, char **retp)
959 char *inst_fmri = startd_alloc(max_scf_fmri_size);
961 inst_fmri[0] = 0;
962 if (scf_instance_to_fmri(inst, inst_fmri, max_scf_fmri_size) <= 0) {
963 startd_free(inst_fmri, max_scf_fmri_size);
964 switch (scf_error()) {
965 case SCF_ERROR_CONNECTION_BROKEN:
966 default:
967 return (ECONNABORTED);
969 case SCF_ERROR_DELETED:
970 return (ECANCELED);
972 case SCF_ERROR_NOT_SET:
973 assert(0);
974 abort();
978 *retp = inst_fmri;
979 return (0);
983 * int libscf_fmri_get_instance(scf_handle_t *, const char *,
984 * scf_instance_t **)
985 * Given a valid SCF handle and an FMRI, return the SCF instance that matches
986 * exactly. The instance must be released using scf_instance_destroy().
987 * Returns 0 on success, EINVAL if the FMRI is invalid, ENOTSUP if the FMRI
988 * is valid but designates something other than an instance, ECONNABORTED if
989 * the repository connection is broken, or ENOENT if the instance does not
990 * exist.
993 libscf_fmri_get_instance(scf_handle_t *h, const char *fmri,
994 scf_instance_t **instp)
996 scf_instance_t *inst;
997 int r;
999 inst = safe_scf_instance_create(h);
1001 r = libscf_lookup_instance(fmri, inst);
1003 if (r == 0)
1004 *instp = inst;
1005 else
1006 scf_instance_destroy(inst);
1008 return (r);
1012 libscf_lookup_instance(const char *fmri, scf_instance_t *inst)
1014 if (scf_handle_decode_fmri(scf_instance_handle(inst), fmri, NULL, NULL,
1015 inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1016 switch (scf_error()) {
1017 case SCF_ERROR_INVALID_ARGUMENT:
1018 return (EINVAL);
1020 case SCF_ERROR_CONSTRAINT_VIOLATED:
1021 return (ENOTSUP);
1023 case SCF_ERROR_CONNECTION_BROKEN:
1024 return (ECONNABORTED);
1026 case SCF_ERROR_NOT_FOUND:
1027 return (ENOENT);
1029 case SCF_ERROR_HANDLE_MISMATCH:
1030 default:
1031 bad_error("scf_handle_decode_fmri", scf_error());
1035 return (0);
1039 * int libscf_get_deathrow()
1040 * Read deathrow for inst. Returns 0, ECONNABORTED if the connection to the
1041 * repository is broken, ECANCELED if inst is deleted, or ENOENT if inst
1042 * has no deathrow property group.
1044 * If deathrow/deathrow was missing or invalid, *deathrow will be -1 and a
1045 * debug message is logged.
1048 libscf_get_deathrow(scf_handle_t *h, scf_instance_t *inst, int *deathrow)
1050 scf_propertygroup_t *pg;
1051 int r;
1052 uint8_t deathrow_8;
1054 pg = safe_scf_pg_create(h);
1056 if (scf_instance_get_pg_composed(inst, NULL, SCF_PG_DEATHROW, pg) !=
1057 0) {
1058 switch (scf_error()) {
1059 case SCF_ERROR_CONNECTION_BROKEN:
1060 default:
1061 scf_pg_destroy(pg);
1062 return (ECONNABORTED);
1064 case SCF_ERROR_DELETED:
1065 scf_pg_destroy(pg);
1066 return (ECANCELED);
1068 case SCF_ERROR_NOT_FOUND:
1069 *deathrow = -1;
1070 break;
1072 case SCF_ERROR_HANDLE_MISMATCH:
1073 case SCF_ERROR_INVALID_ARGUMENT:
1074 case SCF_ERROR_NOT_SET:
1075 bad_error("libscf_get_deathrow", scf_error());
1077 } else {
1078 switch (r = get_boolean(pg,
1079 SCF_PROPERTY_DEATHROW, &deathrow_8)) {
1080 case 0:
1081 *deathrow = deathrow_8;
1082 break;
1084 case ECONNABORTED:
1085 case ECANCELED:
1086 scf_pg_destroy(pg);
1087 return (r);
1089 case ENOENT:
1090 case EINVAL:
1091 *deathrow = -1;
1092 break;
1094 default:
1095 bad_error("get_boolean", r);
1099 scf_pg_destroy(pg);
1101 return (0);
1105 * void libscf_get_basic_instance_data()
1106 * Read enabled, enabled_ovr, and restarter_fmri (into an allocated
1107 * buffer) for inst. Returns 0, ECONNABORTED if the connection to the
1108 * repository is broken, ECANCELED if inst is deleted, or ENOENT if inst
1109 * has no general property group.
1111 * On success, restarter_fmri may be NULL. If general/enabled was missing
1112 * or invalid, *enabledp will be -1 and a debug message is logged.
1115 libscf_get_basic_instance_data(scf_handle_t *h, scf_instance_t *inst,
1116 const char *fmri, int *enabledp, int *enabled_ovrp, char **restarter_fmri)
1118 scf_propertygroup_t *pg;
1119 int r;
1120 uint8_t enabled_8;
1122 pg = safe_scf_pg_create(h);
1124 if (enabled_ovrp == NULL)
1125 goto enabled;
1127 if (scf_instance_get_pg_composed(inst, NULL, SCF_PG_GENERAL_OVR, pg) !=
1128 0) {
1129 switch (scf_error()) {
1130 case SCF_ERROR_CONNECTION_BROKEN:
1131 default:
1132 scf_pg_destroy(pg);
1133 return (ECONNABORTED);
1135 case SCF_ERROR_DELETED:
1136 scf_pg_destroy(pg);
1137 return (ECANCELED);
1139 case SCF_ERROR_NOT_FOUND:
1140 *enabled_ovrp = -1;
1141 break;
1143 case SCF_ERROR_HANDLE_MISMATCH:
1144 case SCF_ERROR_INVALID_ARGUMENT:
1145 case SCF_ERROR_NOT_SET:
1146 bad_error("scf_instance_get_pg_composed", scf_error());
1148 } else {
1149 switch (r = get_boolean(pg, SCF_PROPERTY_ENABLED, &enabled_8)) {
1150 case 0:
1151 *enabled_ovrp = enabled_8;
1152 break;
1154 case ECONNABORTED:
1155 case ECANCELED:
1156 scf_pg_destroy(pg);
1157 return (r);
1159 case ENOENT:
1160 case EINVAL:
1161 *enabled_ovrp = -1;
1162 break;
1164 case EACCES:
1165 default:
1166 bad_error("get_boolean", r);
1170 enabled:
1172 * Since general/restarter can be at the service level, we must do
1173 * a composed lookup. These properties are immediate, though, so we
1174 * must use the "editing" snapshot. Technically enabled shouldn't be
1175 * at the service level, but looking it up composed, too, doesn't
1176 * hurt.
1178 if (scf_instance_get_pg_composed(inst, NULL, SCF_PG_GENERAL, pg) != 0) {
1179 scf_pg_destroy(pg);
1180 switch (scf_error()) {
1181 case SCF_ERROR_CONNECTION_BROKEN:
1182 default:
1183 return (ECONNABORTED);
1185 case SCF_ERROR_DELETED:
1186 return (ECANCELED);
1188 case SCF_ERROR_NOT_FOUND:
1189 return (ENOENT);
1191 case SCF_ERROR_NOT_SET:
1192 bad_error("scf_instance_get_pg_composed", scf_error());
1196 switch (r = get_boolean(pg, SCF_PROPERTY_ENABLED, &enabled_8)) {
1197 case 0:
1198 *enabledp = enabled_8;
1199 break;
1201 case ECONNABORTED:
1202 case ECANCELED:
1203 scf_pg_destroy(pg);
1204 return (r);
1206 case ENOENT:
1208 * DEBUG because this happens when svccfg import creates
1209 * a temporary service.
1211 log_framework(LOG_DEBUG,
1212 "general/enabled property of %s is missing.\n", fmri);
1213 *enabledp = -1;
1214 break;
1216 case EINVAL:
1217 log_framework(LOG_ERR,
1218 "general/enabled property of %s is invalid.\n", fmri);
1219 *enabledp = -1;
1220 break;
1222 case EACCES:
1223 default:
1224 bad_error("get_boolean", r);
1227 if (restarter_fmri != NULL)
1228 get_restarter(h, pg, restarter_fmri);
1230 scf_pg_destroy(pg);
1232 return (0);
1236 * Sets pg to the name property group of s_inst. If it doesn't exist, it is
1237 * added.
1239 * Fails with
1240 * ECONNABORTED - repository disconnection or unknown libscf error
1241 * ECANCELED - inst is deleted
1242 * EPERM - permission is denied
1243 * EACCES - backend denied access
1244 * EROFS - backend readonly
1247 libscf_inst_get_or_add_pg(scf_instance_t *inst, const char *name,
1248 const char *type, uint32_t flags, scf_propertygroup_t *pg)
1250 uint32_t f;
1252 again:
1253 if (scf_instance_get_pg(inst, name, pg) == 0) {
1254 if (scf_pg_get_flags(pg, &f) != 0) {
1255 switch (scf_error()) {
1256 case SCF_ERROR_CONNECTION_BROKEN:
1257 default:
1258 return (ECONNABORTED);
1260 case SCF_ERROR_DELETED:
1261 goto add;
1263 case SCF_ERROR_NOT_SET:
1264 bad_error("scf_pg_get_flags", scf_error());
1268 if (f == flags)
1269 return (0);
1271 if (scf_pg_delete(pg) != 0) {
1272 switch (scf_error()) {
1273 case SCF_ERROR_CONNECTION_BROKEN:
1274 default:
1275 return (ECONNABORTED);
1277 case SCF_ERROR_DELETED:
1278 break;
1280 case SCF_ERROR_PERMISSION_DENIED:
1281 return (EPERM);
1283 case SCF_ERROR_BACKEND_ACCESS:
1284 return (EACCES);
1286 case SCF_ERROR_BACKEND_READONLY:
1287 return (EROFS);
1289 case SCF_ERROR_NOT_SET:
1290 bad_error("scf_pg_delete", scf_error());
1293 } else {
1294 switch (scf_error()) {
1295 case SCF_ERROR_CONNECTION_BROKEN:
1296 default:
1297 return (ECONNABORTED);
1299 case SCF_ERROR_DELETED:
1300 return (ECANCELED);
1302 case SCF_ERROR_NOT_FOUND:
1303 break;
1305 case SCF_ERROR_HANDLE_MISMATCH:
1306 case SCF_ERROR_INVALID_ARGUMENT:
1307 case SCF_ERROR_NOT_SET:
1308 bad_error("scf_instance_get_pg", scf_error());
1312 add:
1313 if (scf_instance_add_pg(inst, name, type, flags, pg) == 0)
1314 return (0);
1316 switch (scf_error()) {
1317 case SCF_ERROR_CONNECTION_BROKEN:
1318 default:
1319 return (ECONNABORTED);
1321 case SCF_ERROR_DELETED:
1322 return (ECANCELED);
1324 case SCF_ERROR_EXISTS:
1325 goto again;
1327 case SCF_ERROR_PERMISSION_DENIED:
1328 return (EPERM);
1330 case SCF_ERROR_BACKEND_ACCESS:
1331 return (EACCES);
1333 case SCF_ERROR_BACKEND_READONLY:
1334 return (EROFS);
1336 case SCF_ERROR_HANDLE_MISMATCH:
1337 case SCF_ERROR_INVALID_ARGUMENT:
1338 case SCF_ERROR_NOT_SET:
1339 bad_error("scf_instance_add_pg", scf_error());
1340 /* NOTREACHED */
1345 * Returns
1346 * 0 - success
1347 * ECONNABORTED - repository connection broken
1348 * - unknown libscf error
1349 * ECANCELED
1351 static scf_error_t
1352 transaction_add_set(scf_transaction_t *tx, scf_transaction_entry_t *ent,
1353 const char *pname, scf_type_t ty)
1355 for (;;) {
1356 if (scf_transaction_property_change_type(tx, ent, pname,
1357 ty) == 0)
1358 return (0);
1360 switch (scf_error()) {
1361 case SCF_ERROR_CONNECTION_BROKEN:
1362 default:
1363 return (ECONNABORTED);
1365 case SCF_ERROR_DELETED:
1366 return (ECANCELED);
1368 case SCF_ERROR_NOT_FOUND:
1369 break;
1371 case SCF_ERROR_HANDLE_MISMATCH:
1372 case SCF_ERROR_INVALID_ARGUMENT:
1373 case SCF_ERROR_IN_USE:
1374 case SCF_ERROR_NOT_SET:
1375 bad_error("scf_transaction_property_change_type",
1376 scf_error());
1379 if (scf_transaction_property_new(tx, ent, pname, ty) == 0)
1380 return (0);
1382 switch (scf_error()) {
1383 case SCF_ERROR_CONNECTION_BROKEN:
1384 default:
1385 return (ECONNABORTED);
1387 case SCF_ERROR_DELETED:
1388 return (ECANCELED);
1390 case SCF_ERROR_EXISTS:
1391 break;
1393 case SCF_ERROR_HANDLE_MISMATCH:
1394 case SCF_ERROR_INVALID_ARGUMENT:
1395 case SCF_ERROR_IN_USE:
1396 case SCF_ERROR_NOT_SET:
1397 bad_error("scf_transaction_property_new", scf_error());
1398 /* NOTREACHED */
1404 * Returns
1405 * 0 - success
1406 * ECONNABORTED - repository connection broken
1407 * - unknown libscf error
1408 * ECANCELED - pg was deleted
1409 * EPERM
1410 * EACCES
1411 * EROFS
1413 static int
1414 pg_set_prop_value(scf_propertygroup_t *pg, const char *pname, scf_value_t *v)
1416 scf_handle_t *h;
1417 scf_transaction_t *tx;
1418 scf_transaction_entry_t *e;
1419 scf_type_t ty;
1420 scf_error_t scfe;
1421 int ret, r;
1423 h = scf_pg_handle(pg);
1424 tx = safe_scf_transaction_create(h);
1425 e = safe_scf_entry_create(h);
1427 ty = scf_value_type(v);
1428 assert(ty != SCF_TYPE_INVALID);
1430 for (;;) {
1431 if (scf_transaction_start(tx, pg) != 0) {
1432 switch (scf_error()) {
1433 case SCF_ERROR_CONNECTION_BROKEN:
1434 default:
1435 ret = ECONNABORTED;
1436 goto out;
1438 case SCF_ERROR_DELETED:
1439 ret = ECANCELED;
1440 goto out;
1442 case SCF_ERROR_PERMISSION_DENIED:
1443 ret = EPERM;
1444 goto out;
1446 case SCF_ERROR_BACKEND_ACCESS:
1447 ret = EACCES;
1448 goto out;
1450 case SCF_ERROR_BACKEND_READONLY:
1451 ret = EROFS;
1452 goto out;
1454 case SCF_ERROR_NOT_SET:
1455 bad_error("scf_transaction_start", ret);
1459 ret = transaction_add_set(tx, e, pname, ty);
1460 switch (ret) {
1461 case 0:
1462 break;
1464 case ECONNABORTED:
1465 case ECANCELED:
1466 goto out;
1468 default:
1469 bad_error("transaction_add_set", ret);
1472 r = scf_entry_add_value(e, v);
1473 assert(r == 0);
1475 r = scf_transaction_commit(tx);
1476 if (r == 1)
1477 break;
1478 if (r != 0) {
1479 scfe = scf_error();
1480 scf_transaction_reset(tx);
1481 switch (scfe) {
1482 case SCF_ERROR_CONNECTION_BROKEN:
1483 default:
1484 ret = ECONNABORTED;
1485 goto out;
1487 case SCF_ERROR_DELETED:
1488 ret = ECANCELED;
1489 goto out;
1491 case SCF_ERROR_PERMISSION_DENIED:
1492 ret = EPERM;
1493 goto out;
1495 case SCF_ERROR_BACKEND_ACCESS:
1496 ret = EACCES;
1497 goto out;
1499 case SCF_ERROR_BACKEND_READONLY:
1500 ret = EROFS;
1501 goto out;
1503 case SCF_ERROR_NOT_SET:
1504 bad_error("scf_transaction_commit", scfe);
1508 scf_transaction_reset(tx);
1510 if (scf_pg_update(pg) == -1) {
1511 switch (scf_error()) {
1512 case SCF_ERROR_CONNECTION_BROKEN:
1513 default:
1514 ret = ECONNABORTED;
1515 goto out;
1517 case SCF_ERROR_DELETED:
1518 ret = ECANCELED;
1519 goto out;
1521 case SCF_ERROR_NOT_SET:
1522 bad_error("scf_pg_update", scf_error());
1527 ret = 0;
1529 out:
1530 scf_transaction_destroy(tx);
1531 scf_entry_destroy(e);
1532 return (ret);
1536 * Returns
1537 * 0 - success
1538 * ECONNABORTED - repository connection broken
1539 * - unknown libscf error
1540 * ECANCELED - inst was deleted
1541 * EPERM
1542 * EACCES
1543 * EROFS
1546 libscf_inst_set_boolean_prop(scf_instance_t *inst, const char *pgname,
1547 const char *pgtype, uint32_t pgflags, const char *pname, int val)
1549 scf_handle_t *h;
1550 scf_propertygroup_t *pg = NULL;
1551 scf_value_t *v;
1552 int ret = 0;
1554 h = scf_instance_handle(inst);
1555 pg = safe_scf_pg_create(h);
1556 v = safe_scf_value_create(h);
1558 ret = libscf_inst_get_or_add_pg(inst, pgname, pgtype, pgflags, pg);
1559 switch (ret) {
1560 case 0:
1561 break;
1563 case ECONNABORTED:
1564 case ECANCELED:
1565 case EPERM:
1566 case EACCES:
1567 case EROFS:
1568 goto out;
1570 default:
1571 bad_error("libscf_inst_get_or_add_pg", ret);
1574 scf_value_set_boolean(v, val);
1576 ret = pg_set_prop_value(pg, pname, v);
1577 switch (ret) {
1578 case 0:
1579 case ECONNABORTED:
1580 case ECANCELED:
1581 case EPERM:
1582 case EACCES:
1583 case EROFS:
1584 break;
1586 default:
1587 bad_error("pg_set_prop_value", ret);
1590 out:
1591 scf_pg_destroy(pg);
1592 scf_value_destroy(v);
1593 return (ret);
1597 * Returns
1598 * 0 - success
1599 * ECONNABORTED - repository connection broken
1600 * - unknown libscf error
1601 * ECANCELED - inst was deleted
1602 * EPERM
1603 * EACCES
1604 * EROFS
1607 libscf_inst_set_count_prop(scf_instance_t *inst, const char *pgname,
1608 const char *pgtype, uint32_t pgflags, const char *pname, uint64_t count)
1610 scf_handle_t *h;
1611 scf_propertygroup_t *pg = NULL;
1612 scf_value_t *v;
1613 int ret = 0;
1615 h = scf_instance_handle(inst);
1616 pg = safe_scf_pg_create(h);
1617 v = safe_scf_value_create(h);
1619 ret = libscf_inst_get_or_add_pg(inst, pgname, pgtype, pgflags, pg);
1620 switch (ret) {
1621 case 0:
1622 break;
1624 case ECONNABORTED:
1625 case ECANCELED:
1626 case EPERM:
1627 case EACCES:
1628 case EROFS:
1629 goto out;
1631 default:
1632 bad_error("libscf_inst_get_or_add_pg", ret);
1635 scf_value_set_count(v, count);
1637 ret = pg_set_prop_value(pg, pname, v);
1638 switch (ret) {
1639 case 0:
1640 case ECONNABORTED:
1641 case ECANCELED:
1642 case EPERM:
1643 case EACCES:
1644 case EROFS:
1645 break;
1647 default:
1648 bad_error("pg_set_prop_value", ret);
1651 out:
1652 scf_pg_destroy(pg);
1653 scf_value_destroy(v);
1654 return (ret);
1658 * Returns 0 on success, ECONNABORTED if the repository connection is broken,
1659 * ECANCELED if inst is deleted, EROFS if the backend is readonly, or EPERM if
1660 * permission was denied.
1663 libscf_set_enable_ovr(scf_instance_t *inst, int enable)
1665 return (libscf_inst_set_boolean_prop(inst, SCF_PG_GENERAL_OVR,
1666 SCF_PG_GENERAL_OVR_TYPE, SCF_PG_GENERAL_OVR_FLAGS,
1667 SCF_PROPERTY_ENABLED, enable));
1671 * Returns 0 on success, ECONNABORTED if the repository connection is broken,
1672 * ECANCELED if inst is deleted, EROFS if the backend is readonly, or EPERM if
1673 * permission was denied.
1676 libscf_set_deathrow(scf_instance_t *inst, int deathrow)
1678 return (libscf_inst_set_boolean_prop(inst, SCF_PG_DEATHROW,
1679 SCF_PG_DEATHROW_TYPE, SCF_PG_DEATHROW_FLAGS,
1680 SCF_PROPERTY_DEATHROW, deathrow));
1684 * Returns 0, ECONNABORTED, ECANCELED, or EPERM.
1687 libscf_delete_enable_ovr(scf_instance_t *inst)
1689 return (scf_instance_delete_prop(inst, SCF_PG_GENERAL_OVR,
1690 SCF_PROPERTY_ENABLED));
1694 * Fails with
1695 * ECONNABORTED - repository connection was broken
1696 * ECANCELED - pg was deleted
1697 * ENOENT - pg has no milestone property
1698 * EINVAL - the milestone property is misconfigured
1700 static int
1701 pg_get_milestone(scf_propertygroup_t *pg, scf_property_t *prop,
1702 scf_value_t *val, char *buf, size_t buf_sz)
1704 if (scf_pg_get_property(pg, SCF_PROPERTY_MILESTONE, prop) != 0) {
1705 switch (scf_error()) {
1706 case SCF_ERROR_CONNECTION_BROKEN:
1707 default:
1708 return (ECONNABORTED);
1710 case SCF_ERROR_DELETED:
1711 return (ECANCELED);
1713 case SCF_ERROR_NOT_FOUND:
1714 return (ENOENT);
1716 case SCF_ERROR_HANDLE_MISMATCH:
1717 case SCF_ERROR_INVALID_ARGUMENT:
1718 case SCF_ERROR_NOT_SET:
1719 bad_error("scf_pg_get_property", scf_error());
1723 if (scf_property_get_value(prop, val) != 0) {
1724 switch (scf_error()) {
1725 case SCF_ERROR_CONNECTION_BROKEN:
1726 default:
1727 return (ECONNABORTED);
1729 case SCF_ERROR_DELETED:
1730 case SCF_ERROR_CONSTRAINT_VIOLATED:
1731 case SCF_ERROR_NOT_FOUND:
1732 return (EINVAL);
1734 case SCF_ERROR_NOT_SET:
1735 case SCF_ERROR_PERMISSION_DENIED:
1736 bad_error("scf_property_get_value", scf_error());
1740 if (scf_value_get_astring(val, buf, buf_sz) < 0) {
1741 switch (scf_error()) {
1742 case SCF_ERROR_TYPE_MISMATCH:
1743 return (EINVAL);
1745 case SCF_ERROR_NOT_SET:
1746 default:
1747 bad_error("scf_value_get_astring", scf_error());
1751 return (0);
1755 * Fails with
1756 * ECONNABORTED - repository connection was broken
1757 * ECANCELED - inst was deleted
1758 * ENOENT - inst has no milestone property
1759 * EINVAL - the milestone property is misconfigured
1762 libscf_get_milestone(scf_instance_t *inst, scf_property_t *prop,
1763 scf_value_t *val, char *buf, size_t buf_sz)
1765 scf_propertygroup_t *pg;
1766 int r;
1768 pg = safe_scf_pg_create(scf_instance_handle(inst));
1770 if (scf_instance_get_pg(inst, SCF_PG_OPTIONS_OVR, pg) == 0) {
1771 switch (r = pg_get_milestone(pg, prop, val, buf, buf_sz)) {
1772 case 0:
1773 case ECONNABORTED:
1774 case EINVAL:
1775 goto out;
1777 case ECANCELED:
1778 case ENOENT:
1779 break;
1781 default:
1782 bad_error("pg_get_milestone", r);
1784 } else {
1785 switch (scf_error()) {
1786 case SCF_ERROR_CONNECTION_BROKEN:
1787 default:
1788 r = ECONNABORTED;
1789 goto out;
1791 case SCF_ERROR_DELETED:
1792 r = ECANCELED;
1793 goto out;
1795 case SCF_ERROR_NOT_FOUND:
1796 break;
1798 case SCF_ERROR_HANDLE_MISMATCH:
1799 case SCF_ERROR_INVALID_ARGUMENT:
1800 case SCF_ERROR_NOT_SET:
1801 bad_error("scf_instance_get_pg", scf_error());
1805 if (scf_instance_get_pg(inst, SCF_PG_OPTIONS, pg) == 0) {
1806 r = pg_get_milestone(pg, prop, val, buf, buf_sz);
1807 } else {
1808 switch (scf_error()) {
1809 case SCF_ERROR_CONNECTION_BROKEN:
1810 default:
1811 r = ECONNABORTED;
1812 goto out;
1814 case SCF_ERROR_DELETED:
1815 r = ECANCELED;
1816 goto out;
1818 case SCF_ERROR_NOT_FOUND:
1819 r = ENOENT;
1820 break;
1822 case SCF_ERROR_HANDLE_MISMATCH:
1823 case SCF_ERROR_INVALID_ARGUMENT:
1824 case SCF_ERROR_NOT_SET:
1825 bad_error("scf_instance_get_pg", scf_error());
1829 out:
1830 scf_pg_destroy(pg);
1832 return (r);
1836 * Get the runlevel character from the runlevel property of the given property
1837 * group. Fails with
1838 * ECONNABORTED - repository connection was broken
1839 * ECANCELED - prop's property group was deleted
1840 * ENOENT - the property has no values
1841 * EINVAL - the property has more than one value
1842 * the property is of the wrong type
1843 * the property value is malformed
1846 libscf_extract_runlevel(scf_property_t *prop, char *rlp)
1848 scf_value_t *val;
1849 char buf[2];
1851 val = safe_scf_value_create(scf_property_handle(prop));
1853 if (scf_property_get_value(prop, val) != 0) {
1854 scf_value_destroy(val);
1855 switch (scf_error()) {
1856 case SCF_ERROR_CONNECTION_BROKEN:
1857 return (ECONNABORTED);
1859 case SCF_ERROR_NOT_SET:
1860 return (ENOENT);
1862 case SCF_ERROR_DELETED:
1863 return (ECANCELED);
1865 case SCF_ERROR_CONSTRAINT_VIOLATED:
1866 return (EINVAL);
1868 case SCF_ERROR_NOT_FOUND:
1869 return (ENOENT);
1871 case SCF_ERROR_HANDLE_MISMATCH:
1872 case SCF_ERROR_NOT_BOUND:
1873 case SCF_ERROR_PERMISSION_DENIED:
1874 default:
1875 bad_error("scf_property_get_value", scf_error());
1879 if (scf_value_get_astring(val, buf, sizeof (buf)) < 0) {
1880 scf_value_destroy(val);
1881 if (scf_error() != SCF_ERROR_TYPE_MISMATCH)
1882 bad_error("scf_value_get_astring", scf_error());
1884 return (EINVAL);
1887 scf_value_destroy(val);
1889 if (buf[0] == '\0' || buf[1] != '\0')
1890 return (EINVAL);
1892 *rlp = buf[0];
1894 return (0);
1898 * Delete the "runlevel" property from the given property group. Also set the
1899 * "milestone" property to the given string. Fails with ECONNABORTED,
1900 * ECANCELED, EPERM, EACCES, or EROFS.
1903 libscf_clear_runlevel(scf_propertygroup_t *pg, const char *milestone)
1905 scf_handle_t *h;
1906 scf_transaction_t *tx;
1907 scf_transaction_entry_t *e_rl, *e_ms;
1908 scf_value_t *val;
1909 scf_error_t serr;
1910 boolean_t isempty = B_TRUE;
1911 int ret = 0, r;
1913 h = scf_pg_handle(pg);
1914 tx = safe_scf_transaction_create(h);
1915 e_rl = safe_scf_entry_create(h);
1916 e_ms = safe_scf_entry_create(h);
1917 val = safe_scf_value_create(h);
1919 if (milestone) {
1920 r = scf_value_set_astring(val, milestone);
1921 assert(r == 0);
1924 for (;;) {
1925 if (scf_transaction_start(tx, pg) != 0) {
1926 switch (scf_error()) {
1927 case SCF_ERROR_CONNECTION_BROKEN:
1928 default:
1929 ret = ECONNABORTED;
1930 goto out;
1932 case SCF_ERROR_DELETED:
1933 ret = ECANCELED;
1934 goto out;
1936 case SCF_ERROR_PERMISSION_DENIED:
1937 ret = EPERM;
1938 goto out;
1940 case SCF_ERROR_BACKEND_ACCESS:
1941 ret = EACCES;
1942 goto out;
1944 case SCF_ERROR_BACKEND_READONLY:
1945 ret = EROFS;
1946 goto out;
1948 case SCF_ERROR_NOT_SET:
1949 bad_error("scf_transaction_start", scf_error());
1953 if (scf_transaction_property_delete(tx, e_rl,
1954 "runlevel") == 0) {
1955 isempty = B_FALSE;
1956 } else {
1957 switch (scf_error()) {
1958 case SCF_ERROR_CONNECTION_BROKEN:
1959 default:
1960 ret = ECONNABORTED;
1961 goto out;
1963 case SCF_ERROR_DELETED:
1964 ret = ECANCELED;
1965 goto out;
1967 case SCF_ERROR_NOT_FOUND:
1968 break;
1970 case SCF_ERROR_HANDLE_MISMATCH:
1971 case SCF_ERROR_NOT_BOUND:
1972 case SCF_ERROR_INVALID_ARGUMENT:
1973 bad_error("scf_transaction_property_delete",
1974 scf_error());
1978 if (milestone) {
1979 ret = transaction_add_set(tx, e_ms,
1980 SCF_PROPERTY_MILESTONE, SCF_TYPE_ASTRING);
1981 switch (ret) {
1982 case 0:
1983 break;
1985 case ECONNABORTED:
1986 case ECANCELED:
1987 goto out;
1989 default:
1990 bad_error("transaction_add_set", ret);
1993 isempty = B_FALSE;
1995 r = scf_entry_add_value(e_ms, val);
1996 assert(r == 0);
1999 if (isempty)
2000 goto out;
2002 r = scf_transaction_commit(tx);
2003 if (r == 1)
2004 break;
2005 if (r != 0) {
2006 serr = scf_error();
2007 scf_transaction_reset(tx);
2008 switch (serr) {
2009 case SCF_ERROR_CONNECTION_BROKEN:
2010 ret = ECONNABORTED;
2011 goto out;
2013 case SCF_ERROR_PERMISSION_DENIED:
2014 ret = EPERM;
2015 goto out;
2017 case SCF_ERROR_BACKEND_ACCESS:
2018 ret = EACCES;
2019 goto out;
2021 case SCF_ERROR_BACKEND_READONLY:
2022 ret = EROFS;
2023 goto out;
2025 default:
2026 bad_error("scf_transaction_commit", serr);
2030 scf_transaction_reset(tx);
2032 if (scf_pg_update(pg) == -1) {
2033 switch (scf_error()) {
2034 case SCF_ERROR_CONNECTION_BROKEN:
2035 ret = ECONNABORTED;
2036 goto out;
2038 case SCF_ERROR_NOT_SET:
2039 ret = ECANCELED;
2040 goto out;
2042 default:
2043 assert(0);
2044 abort();
2049 out:
2050 scf_transaction_destroy(tx);
2051 scf_entry_destroy(e_rl);
2052 scf_entry_destroy(e_ms);
2053 scf_value_destroy(val);
2054 return (ret);
2058 * int libscf_get_template_values(scf_instance_t *, scf_snapshot_t *,
2059 * char **)
2061 * Return template values for inst in *common_name suitable for use in
2062 * restarter_inst_t->ri_common_name. Called by restarter_insert_inst().
2064 * Returns 0 on success, ECANCELED if the instance is deleted, ECHILD if
2065 * a value fetch failed for a property, ENOENT if the instance has no
2066 * tm_common_name property group or the property group is deleted, and
2067 * ECONNABORTED if the repository connection is broken.
2070 libscf_get_template_values(scf_instance_t *inst, scf_snapshot_t *snap,
2071 char **common_name, char **c_common_name)
2073 scf_handle_t *h;
2074 scf_propertygroup_t *pg = NULL;
2075 scf_property_t *prop = NULL;
2076 int ret = 0, r;
2077 char *cname = startd_alloc(max_scf_value_size);
2078 char *c_cname = startd_alloc(max_scf_value_size);
2079 int common_name_initialized = B_FALSE;
2080 int c_common_name_initialized = B_FALSE;
2082 h = scf_instance_handle(inst);
2083 pg = safe_scf_pg_create(h);
2084 prop = safe_scf_property_create(h);
2087 * The tm_common_name property group, as with all template property
2088 * groups, is optional.
2090 if (scf_instance_get_pg_composed(inst, snap, SCF_PG_TM_COMMON_NAME, pg)
2091 == -1) {
2092 switch (scf_error()) {
2093 case SCF_ERROR_DELETED:
2094 ret = ECANCELED;
2095 goto template_values_out;
2097 case SCF_ERROR_NOT_FOUND:
2098 goto template_values_out;
2100 case SCF_ERROR_CONNECTION_BROKEN:
2101 default:
2102 ret = ECONNABORTED;
2103 goto template_values_out;
2105 case SCF_ERROR_INVALID_ARGUMENT:
2106 case SCF_ERROR_HANDLE_MISMATCH:
2107 case SCF_ERROR_NOT_SET:
2108 bad_error("scf_instance_get_pg_composed", scf_error());
2113 * The name we wish uses the current locale name as the property name.
2115 if (st->st_locale != NULL) {
2116 if (scf_pg_get_property(pg, st->st_locale, prop) == -1) {
2117 switch (scf_error()) {
2118 case SCF_ERROR_DELETED:
2119 case SCF_ERROR_NOT_FOUND:
2120 break;
2122 case SCF_ERROR_CONNECTION_BROKEN:
2123 default:
2124 ret = ECONNABORTED;
2125 goto template_values_out;
2127 case SCF_ERROR_INVALID_ARGUMENT:
2128 case SCF_ERROR_HANDLE_MISMATCH:
2129 case SCF_ERROR_NOT_SET:
2130 bad_error("scf_pg_get_property", scf_error());
2132 } else {
2133 if ((r = libscf_read_single_astring(h, prop, &cname)) !=
2134 0) {
2135 if (r != LIBSCF_PROPERTY_ABSENT)
2136 ret = ECHILD;
2137 goto template_values_out;
2140 *common_name = cname;
2141 common_name_initialized = B_TRUE;
2146 * Also pull out the C locale name, as a fallback for the case where
2147 * service offers no localized name.
2149 if (scf_pg_get_property(pg, "C", prop) == -1) {
2150 switch (scf_error()) {
2151 case SCF_ERROR_DELETED:
2152 ret = ENOENT;
2153 goto template_values_out;
2155 case SCF_ERROR_NOT_FOUND:
2156 break;
2158 case SCF_ERROR_CONNECTION_BROKEN:
2159 default:
2160 ret = ECONNABORTED;
2161 goto template_values_out;
2163 case SCF_ERROR_INVALID_ARGUMENT:
2164 case SCF_ERROR_HANDLE_MISMATCH:
2165 case SCF_ERROR_NOT_SET:
2166 bad_error("scf_pg_get_property", scf_error());
2168 } else {
2169 if ((r = libscf_read_single_astring(h, prop, &c_cname)) != 0) {
2170 if (r != LIBSCF_PROPERTY_ABSENT)
2171 ret = ECHILD;
2172 goto template_values_out;
2175 *c_common_name = c_cname;
2176 c_common_name_initialized = B_TRUE;
2180 template_values_out:
2181 if (common_name_initialized == B_FALSE)
2182 startd_free(cname, max_scf_value_size);
2183 if (c_common_name_initialized == B_FALSE)
2184 startd_free(c_cname, max_scf_value_size);
2185 scf_property_destroy(prop);
2186 scf_pg_destroy(pg);
2188 return (ret);
2192 * int libscf_get_startd_properties(scf_handle_t *, scf_instance_t *,
2193 * scf_snapshot_t *, uint_t *, char **)
2195 * Return startd settings for inst in *flags suitable for use in
2196 * restarter_inst_t->ri_flags. Called by restarter_insert_inst().
2198 * Returns 0 on success, ECANCELED if the instance is deleted, ECHILD if
2199 * a value fetch failed for a property, ENOENT if the instance has no
2200 * general property group or the property group is deleted, and
2201 * ECONNABORTED if the repository connection is broken.
2204 libscf_get_startd_properties(scf_instance_t *inst,
2205 scf_snapshot_t *snap, uint_t *flags, char **prefixp)
2207 scf_handle_t *h;
2208 scf_propertygroup_t *pg = NULL;
2209 scf_property_t *prop = NULL;
2210 int style = RINST_CONTRACT;
2211 char *style_str = startd_alloc(max_scf_value_size);
2212 int ret = 0, r;
2214 h = scf_instance_handle(inst);
2215 pg = safe_scf_pg_create(h);
2216 prop = safe_scf_property_create(h);
2219 * The startd property group is optional.
2221 if (scf_instance_get_pg_composed(inst, snap, SCF_PG_STARTD, pg) == -1) {
2222 switch (scf_error()) {
2223 case SCF_ERROR_DELETED:
2224 ret = ECANCELED;
2225 goto instance_flags_out;
2227 case SCF_ERROR_NOT_FOUND:
2228 ret = ENOENT;
2229 goto instance_flags_out;
2231 case SCF_ERROR_CONNECTION_BROKEN:
2232 default:
2233 ret = ECONNABORTED;
2234 goto instance_flags_out;
2236 case SCF_ERROR_INVALID_ARGUMENT:
2237 case SCF_ERROR_HANDLE_MISMATCH:
2238 case SCF_ERROR_NOT_SET:
2239 bad_error("scf_instance_get_pg_composed", scf_error());
2244 * 1. Duration property.
2246 if (scf_pg_get_property(pg, SCF_PROPERTY_DURATION, prop) == -1) {
2247 switch (scf_error()) {
2248 case SCF_ERROR_DELETED:
2249 ret = ENOENT;
2250 goto instance_flags_out;
2252 case SCF_ERROR_NOT_FOUND:
2253 break;
2255 case SCF_ERROR_CONNECTION_BROKEN:
2256 default:
2257 ret = ECONNABORTED;
2258 goto instance_flags_out;
2260 case SCF_ERROR_INVALID_ARGUMENT:
2261 case SCF_ERROR_HANDLE_MISMATCH:
2262 case SCF_ERROR_NOT_SET:
2263 bad_error("scf_pg_get_property", scf_error());
2265 } else {
2266 errno = 0;
2267 if ((r = libscf_read_single_astring(h, prop, &style_str))
2268 != 0) {
2269 if (r != LIBSCF_PROPERTY_ABSENT)
2270 ret = ECHILD;
2271 goto instance_flags_out;
2274 if (strcmp(style_str, "child") == 0)
2275 style = RINST_WAIT;
2276 else if (strcmp(style_str, "transient") == 0)
2277 style = RINST_TRANSIENT;
2281 * 2. utmpx prefix property.
2283 if (scf_pg_get_property(pg, SCF_PROPERTY_UTMPX_PREFIX, prop) == 0) {
2284 errno = 0;
2285 if ((r = libscf_read_single_astring(h, prop, prefixp)) != 0) {
2286 if (r != LIBSCF_PROPERTY_ABSENT)
2287 ret = ECHILD;
2288 goto instance_flags_out;
2290 } else {
2291 switch (scf_error()) {
2292 case SCF_ERROR_DELETED:
2293 ret = ENOENT;
2294 goto instance_flags_out;
2296 case SCF_ERROR_NOT_FOUND:
2297 goto instance_flags_out;
2299 case SCF_ERROR_CONNECTION_BROKEN:
2300 default:
2301 ret = ECONNABORTED;
2302 goto instance_flags_out;
2304 case SCF_ERROR_INVALID_ARGUMENT:
2305 case SCF_ERROR_HANDLE_MISMATCH:
2306 case SCF_ERROR_NOT_SET:
2307 bad_error("scf_pg_get_property", scf_error());
2311 instance_flags_out:
2312 startd_free(style_str, max_scf_value_size);
2313 *flags = (*flags & ~RINST_STYLE_MASK) | style;
2315 scf_property_destroy(prop);
2316 scf_pg_destroy(pg);
2318 return (ret);
2322 * int libscf_read_method_ids(scf_handle_t *, scf_instance_t *, ctid_t *,
2323 * ctid_t *, pid_t *)
2325 * Sets given id_t variables to primary and transient contract IDs and start
2326 * PID. Returns 0, ECONNABORTED, and ECANCELED.
2329 libscf_read_method_ids(scf_handle_t *h, scf_instance_t *inst, const char *fmri,
2330 ctid_t *primary, ctid_t *transient, pid_t *start_pid)
2332 scf_propertygroup_t *pg = NULL;
2333 scf_property_t *prop = NULL;
2334 scf_value_t *val = NULL;
2335 uint64_t p, t;
2336 int ret = 0;
2338 *primary = 0;
2339 *transient = 0;
2340 *start_pid = -1;
2342 pg = safe_scf_pg_create(h);
2343 prop = safe_scf_property_create(h);
2344 val = safe_scf_value_create(h);
2346 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) == -1) {
2347 switch (scf_error()) {
2348 case SCF_ERROR_CONNECTION_BROKEN:
2349 default:
2350 ret = ECONNABORTED;
2351 goto read_id_err;
2353 case SCF_ERROR_DELETED:
2354 ret = ECANCELED;
2355 goto read_id_err;
2357 case SCF_ERROR_NOT_FOUND:
2358 goto read_id_err;
2360 case SCF_ERROR_NOT_SET:
2361 bad_error("scf_instance_get_pg", scf_error());
2365 ret = get_count(pg, SCF_PROPERTY_CONTRACT, &p);
2366 switch (ret) {
2367 case 0:
2368 break;
2370 case EINVAL:
2371 log_error(LOG_NOTICE,
2372 "%s: Ignoring %s/%s: multivalued or not of type count\n",
2373 fmri, SCF_PG_RESTARTER, SCF_PROPERTY_CONTRACT);
2374 /* FALLTHROUGH */
2375 case ENOENT:
2376 ret = 0;
2377 goto read_trans;
2379 case ECONNABORTED:
2380 case ECANCELED:
2381 goto read_id_err;
2383 case EACCES:
2384 default:
2385 bad_error("get_count", ret);
2388 *primary = p;
2390 read_trans:
2391 ret = get_count(pg, SCF_PROPERTY_TRANSIENT_CONTRACT, &t);
2392 switch (ret) {
2393 case 0:
2394 break;
2396 case EINVAL:
2397 log_error(LOG_NOTICE,
2398 "%s: Ignoring %s/%s: multivalued or not of type count\n",
2399 fmri, SCF_PG_RESTARTER, SCF_PROPERTY_TRANSIENT_CONTRACT);
2400 /* FALLTHROUGH */
2402 case ENOENT:
2403 ret = 0;
2404 goto read_pid_only;
2406 case ECONNABORTED:
2407 case ECANCELED:
2408 goto read_id_err;
2410 case EACCES:
2411 default:
2412 bad_error("get_count", ret);
2415 *transient = t;
2417 read_pid_only:
2418 ret = get_count(pg, SCF_PROPERTY_START_PID, &p);
2419 switch (ret) {
2420 case 0:
2421 break;
2423 case EINVAL:
2424 log_error(LOG_NOTICE,
2425 "%s: Ignoring %s/%s: multivalued or not of type count\n",
2426 fmri, SCF_PG_RESTARTER, SCF_PROPERTY_START_PID);
2427 /* FALLTHROUGH */
2428 case ENOENT:
2429 ret = 0;
2430 goto read_id_err;
2432 case ECONNABORTED:
2433 case ECANCELED:
2434 goto read_id_err;
2436 case EACCES:
2437 default:
2438 bad_error("get_count", ret);
2441 *start_pid = p;
2443 read_id_err:
2444 scf_value_destroy(val);
2445 scf_property_destroy(prop);
2446 scf_pg_destroy(pg);
2447 return (ret);
2451 * Returns with
2452 * 0 - success
2453 * ECONNABORTED - repository connection broken
2454 * - unknown libscf error
2455 * ECANCELED - s_inst was deleted
2456 * EPERM
2457 * EACCES
2458 * EROFS
2461 libscf_write_start_pid(scf_instance_t *s_inst, pid_t pid)
2463 scf_handle_t *h;
2464 scf_transaction_entry_t *t_pid;
2465 scf_value_t *v_pid;
2466 scf_propertygroup_t *pg;
2467 int ret = 0;
2469 h = scf_instance_handle(s_inst);
2471 pg = safe_scf_pg_create(h);
2472 t_pid = safe_scf_entry_create(h);
2473 v_pid = safe_scf_value_create(h);
2475 get_pg:
2476 ret = libscf_inst_get_or_add_pg(s_inst, SCF_PG_RESTARTER,
2477 SCF_PG_RESTARTER_TYPE, SCF_PG_RESTARTER_FLAGS, pg);
2478 switch (ret) {
2479 case 0:
2480 break;
2482 case ECONNABORTED:
2483 case ECANCELED:
2484 case EPERM:
2485 case EACCES:
2486 case EROFS:
2487 goto write_start_err;
2489 default:
2490 bad_error("libscf_inst_get_or_add_pg", ret);
2493 scf_value_set_count(v_pid, pid);
2495 ret = pg_set_prop_value(pg, SCF_PROPERTY_START_PID, v_pid);
2496 switch (ret) {
2497 case 0:
2498 case ECONNABORTED:
2499 case EPERM:
2500 case EACCES:
2501 case EROFS:
2502 break;
2504 case ECANCELED:
2505 goto get_pg;
2507 default:
2508 bad_error("pg_set_prop_value", ret);
2511 write_start_err:
2512 scf_entry_destroy(t_pid);
2513 scf_value_destroy(v_pid);
2514 scf_pg_destroy(pg);
2516 return (ret);
2520 * Add a property indicating the instance log file. If the dir is
2521 * equal to LOG_PREFIX_EARLY, then the property restarter/alt_logfile
2522 * of the instance is used; otherwise, restarter/logfile is used.
2524 * Returns
2525 * 0 - success
2526 * ECONNABORTED
2527 * ECANCELED
2528 * EPERM
2529 * EACCES
2530 * EROFS
2531 * EAGAIN
2534 libscf_note_method_log(scf_instance_t *inst, const char *dir, const char *file)
2536 scf_handle_t *h;
2537 scf_value_t *v;
2538 scf_propertygroup_t *pg;
2539 int ret = 0;
2540 char *logname;
2541 const char *propname;
2543 h = scf_instance_handle(inst);
2544 pg = safe_scf_pg_create(h);
2545 v = safe_scf_value_create(h);
2547 logname = uu_msprintf("%s%s", dir, file);
2549 if (logname == NULL) {
2550 ret = errno;
2551 goto out;
2554 ret = libscf_inst_get_or_add_pg(inst, SCF_PG_RESTARTER,
2555 SCF_PG_RESTARTER_TYPE, SCF_PG_RESTARTER_FLAGS, pg);
2556 switch (ret) {
2557 case 0:
2558 break;
2560 case ECONNABORTED:
2561 case ECANCELED:
2562 case EPERM:
2563 case EACCES:
2564 case EROFS:
2565 goto out;
2567 default:
2568 bad_error("libscf_inst_get_or_add_pg", ret);
2571 (void) scf_value_set_astring(v, logname);
2573 if (strcmp(LOG_PREFIX_EARLY, dir) == 0)
2574 propname = SCF_PROPERTY_ALT_LOGFILE;
2575 else
2576 propname = SCF_PROPERTY_LOGFILE;
2578 ret = pg_set_prop_value(pg, propname, v);
2579 switch (ret) {
2580 case 0:
2581 case ECONNABORTED:
2582 case ECANCELED:
2583 case EPERM:
2584 case EACCES:
2585 case EROFS:
2586 break;
2588 default:
2589 bad_error("pg_set_prop_value", ret);
2592 out:
2593 scf_pg_destroy(pg);
2594 scf_value_destroy(v);
2595 uu_free(logname);
2596 return (ret);
2600 * Returns
2601 * 0 - success
2602 * ENAMETOOLONG - name is too long
2603 * ECONNABORTED
2604 * ECANCELED
2605 * EPERM
2606 * EACCES
2607 * EROFS
2610 libscf_write_method_status(scf_instance_t *s_inst, const char *name,
2611 int status)
2613 scf_handle_t *h;
2614 scf_transaction_t *tx;
2615 scf_transaction_entry_t *e_time, *e_stat;
2616 scf_value_t *v_time, *v_stat;
2617 scf_propertygroup_t *pg;
2618 int ret = 0, r;
2619 char pname[30];
2620 struct timeval tv;
2621 scf_error_t scfe;
2623 if (strlen(name) + sizeof ("_method_waitstatus") > sizeof (pname))
2624 return (ENAMETOOLONG);
2626 h = scf_instance_handle(s_inst);
2628 pg = safe_scf_pg_create(h);
2629 tx = safe_scf_transaction_create(h);
2630 e_time = safe_scf_entry_create(h);
2631 v_time = safe_scf_value_create(h);
2632 e_stat = safe_scf_entry_create(h);
2633 v_stat = safe_scf_value_create(h);
2635 get_pg:
2636 ret = libscf_inst_get_or_add_pg(s_inst, SCF_PG_RESTARTER,
2637 SCF_PG_RESTARTER_TYPE, SCF_PG_RESTARTER_FLAGS, pg);
2638 switch (ret) {
2639 case 0:
2640 break;
2642 case ECONNABORTED:
2643 case ECANCELED:
2644 case EPERM:
2645 case EACCES:
2646 case EROFS:
2647 goto out;
2649 default:
2650 bad_error("libscf_inst_get_or_add_pg", ret);
2653 (void) gettimeofday(&tv, NULL);
2655 r = scf_value_set_time(v_time, tv.tv_sec, tv.tv_usec * 1000);
2656 assert(r == 0);
2658 scf_value_set_integer(v_stat, status);
2660 for (;;) {
2661 if (scf_transaction_start(tx, pg) != 0) {
2662 switch (scf_error()) {
2663 case SCF_ERROR_CONNECTION_BROKEN:
2664 default:
2665 ret = ECONNABORTED;
2666 goto out;
2668 case SCF_ERROR_DELETED:
2669 ret = ECANCELED;
2670 goto out;
2672 case SCF_ERROR_PERMISSION_DENIED:
2673 ret = EPERM;
2674 goto out;
2676 case SCF_ERROR_BACKEND_ACCESS:
2677 ret = EACCES;
2678 goto out;
2680 case SCF_ERROR_BACKEND_READONLY:
2681 ret = EROFS;
2682 goto out;
2684 case SCF_ERROR_NOT_SET:
2685 bad_error("scf_transaction_start", ret);
2689 (void) snprintf(pname, sizeof (pname), "%s_method_timestamp",
2690 name);
2691 ret = transaction_add_set(tx, e_time, pname, SCF_TYPE_TIME);
2692 switch (ret) {
2693 case 0:
2694 break;
2696 case ECONNABORTED:
2697 case ECANCELED:
2698 goto out;
2700 default:
2701 bad_error("transaction_add_set", ret);
2704 r = scf_entry_add_value(e_time, v_time);
2705 assert(r == 0);
2707 (void) snprintf(pname, sizeof (pname), "%s_method_waitstatus",
2708 name);
2709 ret = transaction_add_set(tx, e_stat, pname, SCF_TYPE_INTEGER);
2710 switch (ret) {
2711 case 0:
2712 break;
2714 case ECONNABORTED:
2715 case ECANCELED:
2716 goto out;
2718 default:
2719 bad_error("transaction_add_set", ret);
2722 r = scf_entry_add_value(e_stat, v_stat);
2723 if (r != 0)
2724 bad_error("scf_entry_add_value", scf_error());
2726 r = scf_transaction_commit(tx);
2727 if (r == 1)
2728 break;
2729 if (r != 0) {
2730 scfe = scf_error();
2731 scf_transaction_reset_all(tx);
2732 switch (scfe) {
2733 case SCF_ERROR_CONNECTION_BROKEN:
2734 default:
2735 ret = ECONNABORTED;
2736 goto out;
2738 case SCF_ERROR_DELETED:
2739 ret = ECANCELED;
2740 goto out;
2742 case SCF_ERROR_PERMISSION_DENIED:
2743 ret = EPERM;
2744 goto out;
2746 case SCF_ERROR_BACKEND_ACCESS:
2747 ret = EACCES;
2748 goto out;
2750 case SCF_ERROR_BACKEND_READONLY:
2751 ret = EROFS;
2752 goto out;
2754 case SCF_ERROR_NOT_SET:
2755 bad_error("scf_transaction_commit", scfe);
2759 scf_transaction_reset_all(tx);
2761 if (scf_pg_update(pg) == -1) {
2762 switch (scf_error()) {
2763 case SCF_ERROR_CONNECTION_BROKEN:
2764 default:
2765 ret = ECONNABORTED;
2766 goto out;
2768 case SCF_ERROR_DELETED:
2769 ret = ECANCELED;
2770 goto out;
2772 case SCF_ERROR_NOT_SET:
2773 bad_error("scf_pg_update", scf_error());
2778 out:
2779 scf_transaction_destroy(tx);
2780 scf_entry_destroy(e_time);
2781 scf_value_destroy(v_time);
2782 scf_entry_destroy(e_stat);
2783 scf_value_destroy(v_stat);
2784 scf_pg_destroy(pg);
2786 return (ret);
2789 extern int32_t stn_global;
2791 * Call dgraph_add_instance() for each instance in the repository.
2793 void
2794 libscf_populate_graph(scf_handle_t *h)
2796 scf_scope_t *scope;
2797 scf_service_t *svc;
2798 scf_instance_t *inst;
2799 scf_iter_t *svc_iter;
2800 scf_iter_t *inst_iter;
2802 scope = safe_scf_scope_create(h);
2803 svc = safe_scf_service_create(h);
2804 inst = safe_scf_instance_create(h);
2805 svc_iter = safe_scf_iter_create(h);
2806 inst_iter = safe_scf_iter_create(h);
2808 deathrow_init();
2810 stn_global = libscf_get_global_stn_tset(h);
2812 if (scf_handle_get_local_scope(h, scope) !=
2813 SCF_SUCCESS)
2814 uu_die("retrieving local scope failed: %s\n",
2815 scf_strerror(scf_error()));
2817 if (scf_iter_scope_services(svc_iter, scope) == -1)
2818 uu_die("walking local scope's services failed\n");
2820 while (scf_iter_next_service(svc_iter, svc) > 0) {
2821 if (scf_iter_service_instances(inst_iter, svc) == -1)
2822 uu_die("unable to walk service's instances");
2824 while (scf_iter_next_instance(inst_iter, inst) > 0) {
2825 char *fmri;
2827 if (libscf_instance_get_fmri(inst, &fmri) == 0) {
2828 int err;
2830 err = dgraph_add_instance(fmri, inst, B_TRUE);
2831 if (err != 0 && err != EEXIST)
2832 log_error(LOG_WARNING,
2833 "Failed to add %s (%s).\n", fmri,
2834 strerror(err));
2835 startd_free(fmri, max_scf_fmri_size);
2840 deathrow_fini();
2842 scf_iter_destroy(inst_iter);
2843 scf_iter_destroy(svc_iter);
2844 scf_instance_destroy(inst);
2845 scf_service_destroy(svc);
2846 scf_scope_destroy(scope);
2850 * Monitors get handled differently since there can be multiple of them.
2852 * Returns exec string on success. If method not defined, returns
2853 * LIBSCF_PGROUP_ABSENT; if exec property missing, returns
2854 * LIBSCF_PROPERTY_ABSENT. Returns LIBSCF_PROPERTY_ERROR on other failures.
2856 char *
2857 libscf_get_method(scf_handle_t *h, int type, restarter_inst_t *inst,
2858 scf_snapshot_t *snap, method_restart_t *restart_on, uint_t *cte_mask,
2859 uint8_t *need_sessionp, uint64_t *timeout, uint8_t *timeout_retry)
2861 scf_instance_t *scf_inst = NULL;
2862 scf_propertygroup_t *pg = NULL, *pg_startd = NULL;
2863 scf_property_t *prop = NULL;
2864 const char *name;
2865 char *method = startd_alloc(max_scf_value_size);
2866 char *ig = startd_alloc(max_scf_value_size);
2867 char *restart = startd_alloc(max_scf_value_size);
2868 char *ret;
2869 int error = 0, r;
2871 scf_inst = safe_scf_instance_create(h);
2872 pg = safe_scf_pg_create(h);
2873 pg_startd = safe_scf_pg_create(h);
2874 prop = safe_scf_property_create(h);
2876 ret = NULL;
2878 *restart_on = METHOD_RESTART_UNKNOWN;
2880 switch (type) {
2881 case METHOD_START:
2882 name = "start";
2883 break;
2884 case METHOD_STOP:
2885 name = "stop";
2886 break;
2887 case METHOD_REFRESH:
2888 name = "refresh";
2889 break;
2890 default:
2891 error = LIBSCF_PROPERTY_ERROR;
2892 goto get_method_cleanup;
2895 if (scf_handle_decode_fmri(h, inst->ri_i.i_fmri, NULL, NULL, scf_inst,
2896 NULL, NULL, SCF_DECODE_FMRI_EXACT) == -1) {
2897 log_error(LOG_WARNING,
2898 "%s: get_method decode instance FMRI failed: %s\n",
2899 inst->ri_i.i_fmri, scf_strerror(scf_error()));
2900 error = LIBSCF_PROPERTY_ERROR;
2901 goto get_method_cleanup;
2904 if (scf_instance_get_pg_composed(scf_inst, snap, name, pg) == -1) {
2905 if (scf_error() == SCF_ERROR_NOT_FOUND)
2906 error = LIBSCF_PGROUP_ABSENT;
2907 else
2908 error = LIBSCF_PROPERTY_ERROR;
2909 goto get_method_cleanup;
2912 if (scf_pg_get_property(pg, SCF_PROPERTY_EXEC, prop) == -1) {
2913 if (scf_error() == SCF_ERROR_NOT_FOUND)
2914 error = LIBSCF_PROPERTY_ABSENT;
2915 else
2916 error = LIBSCF_PROPERTY_ERROR;
2917 goto get_method_cleanup;
2920 error = libscf_read_single_astring(h, prop, &method);
2921 if (error != 0) {
2922 log_error(LOG_WARNING,
2923 "%s: get_method failed: can't get a single astring "
2924 "from %s/%s\n", inst->ri_i.i_fmri, name, SCF_PROPERTY_EXEC);
2925 goto get_method_cleanup;
2928 error = expand_method_tokens(method, scf_inst, snap, type, &ret);
2929 if (error != 0) {
2930 log_instance(inst, B_TRUE, "Could not expand method tokens "
2931 "in \"%s\": %s.", method, ret);
2932 error = LIBSCF_PROPERTY_ERROR;
2933 goto get_method_cleanup;
2936 r = get_count(pg, SCF_PROPERTY_TIMEOUT, timeout);
2937 switch (r) {
2938 case 0:
2939 break;
2941 case ECONNABORTED:
2942 error = LIBSCF_PROPERTY_ERROR;
2943 goto get_method_cleanup;
2945 case EINVAL:
2946 log_instance(inst, B_TRUE, "%s/%s is multi-valued or not of "
2947 "type count. Using infinite timeout.", name,
2948 SCF_PROPERTY_TIMEOUT);
2949 /* FALLTHROUGH */
2950 case ECANCELED:
2951 case ENOENT:
2952 *timeout = METHOD_TIMEOUT_INFINITE;
2953 break;
2955 case EACCES:
2956 default:
2957 bad_error("get_count", r);
2960 /* Both 0 and -1 (ugh) are considered infinite timeouts. */
2961 if (*timeout == -1 || *timeout == 0)
2962 *timeout = METHOD_TIMEOUT_INFINITE;
2964 if (scf_instance_get_pg_composed(scf_inst, snap, SCF_PG_STARTD,
2965 pg_startd) == -1) {
2966 switch (scf_error()) {
2967 case SCF_ERROR_CONNECTION_BROKEN:
2968 case SCF_ERROR_DELETED:
2969 error = LIBSCF_PROPERTY_ERROR;
2970 goto get_method_cleanup;
2972 case SCF_ERROR_NOT_FOUND:
2973 *cte_mask = 0;
2974 break;
2976 case SCF_ERROR_INVALID_ARGUMENT:
2977 case SCF_ERROR_HANDLE_MISMATCH:
2978 case SCF_ERROR_NOT_BOUND:
2979 case SCF_ERROR_NOT_SET:
2980 bad_error("scf_instance_get_pg_composed", scf_error());
2982 } else {
2983 if (scf_pg_get_property(pg_startd, SCF_PROPERTY_IGNORE,
2984 prop) == -1) {
2985 if (scf_error() == SCF_ERROR_NOT_FOUND)
2986 *cte_mask = 0;
2987 else {
2988 error = LIBSCF_PROPERTY_ERROR;
2989 goto get_method_cleanup;
2991 } else {
2992 error = libscf_read_single_astring(h, prop, &ig);
2993 if (error != 0) {
2994 log_error(LOG_WARNING,
2995 "%s: get_method failed: can't get a single "
2996 "astring from %s/%s\n", inst->ri_i.i_fmri,
2997 name, SCF_PROPERTY_IGNORE);
2998 goto get_method_cleanup;
3001 if (strcmp(ig, "core") == 0)
3002 *cte_mask = CT_PR_EV_CORE;
3003 else if (strcmp(ig, "signal") == 0)
3004 *cte_mask = CT_PR_EV_SIGNAL;
3005 else if (strcmp(ig, "core,signal") == 0 ||
3006 strcmp(ig, "signal,core") == 0)
3007 *cte_mask = CT_PR_EV_CORE | CT_PR_EV_SIGNAL;
3008 else
3009 *cte_mask = 0;
3012 r = get_boolean(pg_startd, SCF_PROPERTY_NEED_SESSION,
3013 need_sessionp);
3014 switch (r) {
3015 case 0:
3016 break;
3018 case ECONNABORTED:
3019 error = LIBSCF_PROPERTY_ERROR;
3020 goto get_method_cleanup;
3022 case ECANCELED:
3023 case ENOENT:
3024 case EINVAL:
3025 *need_sessionp = 0;
3026 break;
3028 case EACCES:
3029 default:
3030 bad_error("get_boolean", r);
3034 * Determine whether service has overriden retry after
3035 * method timeout. Default to retry if no value is
3036 * specified.
3038 r = get_boolean(pg_startd, SCF_PROPERTY_TIMEOUT_RETRY,
3039 timeout_retry);
3040 switch (r) {
3041 case 0:
3042 break;
3044 case ECONNABORTED:
3045 error = LIBSCF_PROPERTY_ERROR;
3046 goto get_method_cleanup;
3048 case ECANCELED:
3049 case ENOENT:
3050 case EINVAL:
3051 *timeout_retry = 1;
3052 break;
3054 case EACCES:
3055 default:
3056 bad_error("get_boolean", r);
3060 if (type != METHOD_START)
3061 goto get_method_cleanup;
3063 /* Only start methods need to honor the restart_on property. */
3065 if (scf_pg_get_property(pg, SCF_PROPERTY_RESTART_ON, prop) == -1) {
3066 if (scf_error() == SCF_ERROR_NOT_FOUND)
3067 *restart_on = METHOD_RESTART_ALL;
3068 else
3069 error = LIBSCF_PROPERTY_ERROR;
3070 goto get_method_cleanup;
3073 error = libscf_read_single_astring(h, prop, &restart);
3074 if (error != 0) {
3075 log_error(LOG_WARNING,
3076 "%s: get_method failed: can't get a single astring "
3077 "from %s/%s\n", inst->ri_i.i_fmri, name,
3078 SCF_PROPERTY_RESTART_ON);
3079 goto get_method_cleanup;
3082 if (strcmp(restart, "all") == 0)
3083 *restart_on = METHOD_RESTART_ALL;
3084 else if (strcmp(restart, "external_fault") == 0)
3085 *restart_on = METHOD_RESTART_EXTERNAL_FAULT;
3086 else if (strcmp(restart, "any_fault") == 0)
3087 *restart_on = METHOD_RESTART_ANY_FAULT;
3089 get_method_cleanup:
3090 startd_free(ig, max_scf_value_size);
3091 startd_free(method, max_scf_value_size);
3092 startd_free(restart, max_scf_value_size);
3094 scf_instance_destroy(scf_inst);
3095 scf_pg_destroy(pg);
3096 scf_pg_destroy(pg_startd);
3097 scf_property_destroy(prop);
3099 if (error != 0 && ret != NULL) {
3100 free(ret);
3101 ret = NULL;
3104 errno = error;
3105 return (ret);
3109 * Returns 1 if we've reached the fault threshold
3112 update_fault_count(restarter_inst_t *inst, int type)
3114 assert(type == FAULT_COUNT_INCR || type == FAULT_COUNT_RESET);
3116 if (type == FAULT_COUNT_INCR) {
3117 inst->ri_i.i_fault_count++;
3118 log_framework(LOG_INFO, "%s: Increasing fault count to %d\n",
3119 inst->ri_i.i_fmri, inst->ri_i.i_fault_count);
3121 if (type == FAULT_COUNT_RESET)
3122 inst->ri_i.i_fault_count = 0;
3124 if (inst->ri_i.i_fault_count >= FAULT_THRESHOLD)
3125 return (1);
3127 return (0);
3131 * int libscf_unset_action()
3132 * Delete any pending timestamps for the specified action which is
3133 * older than the supplied ts.
3135 * Returns 0 on success, ECONNABORTED, EACCES, or EPERM on failure.
3138 libscf_unset_action(scf_handle_t *h, scf_propertygroup_t *pg,
3139 admin_action_t a, hrtime_t ts)
3141 scf_transaction_t *t;
3142 scf_transaction_entry_t *e;
3143 scf_property_t *prop;
3144 scf_value_t *val;
3145 hrtime_t rep_ts;
3146 int ret = 0, r;
3148 t = safe_scf_transaction_create(h);
3149 e = safe_scf_entry_create(h);
3150 prop = safe_scf_property_create(h);
3151 val = safe_scf_value_create(h);
3153 for (;;) {
3154 if (scf_pg_update(pg) == -1) {
3155 switch (scf_error()) {
3156 case SCF_ERROR_CONNECTION_BROKEN:
3157 default:
3158 ret = ECONNABORTED;
3159 goto unset_action_cleanup;
3161 case SCF_ERROR_DELETED:
3162 goto unset_action_cleanup;
3164 case SCF_ERROR_NOT_SET:
3165 assert(0);
3166 abort();
3170 if (scf_transaction_start(t, pg) == -1) {
3171 switch (scf_error()) {
3172 case SCF_ERROR_CONNECTION_BROKEN:
3173 default:
3174 ret = ECONNABORTED;
3175 goto unset_action_cleanup;
3177 case SCF_ERROR_DELETED:
3178 goto unset_action_cleanup;
3180 case SCF_ERROR_PERMISSION_DENIED:
3181 ret = EPERM;
3182 goto unset_action_cleanup;
3184 case SCF_ERROR_BACKEND_ACCESS:
3185 case SCF_ERROR_BACKEND_READONLY:
3186 ret = EACCES;
3187 goto unset_action_cleanup;
3189 case SCF_ERROR_IN_USE:
3190 case SCF_ERROR_HANDLE_MISMATCH:
3191 case SCF_ERROR_NOT_SET:
3192 assert(0);
3193 abort();
3197 /* Return failure only if the property hasn't been deleted. */
3198 if (scf_pg_get_property(pg, admin_actions[a], prop) == -1) {
3199 switch (scf_error()) {
3200 case SCF_ERROR_CONNECTION_BROKEN:
3201 default:
3202 ret = ECONNABORTED;
3203 goto unset_action_cleanup;
3205 case SCF_ERROR_DELETED:
3206 case SCF_ERROR_NOT_FOUND:
3207 goto unset_action_cleanup;
3209 case SCF_ERROR_HANDLE_MISMATCH:
3210 case SCF_ERROR_INVALID_ARGUMENT:
3211 case SCF_ERROR_NOT_SET:
3212 assert(0);
3213 abort();
3217 if (scf_property_get_value(prop, val) == -1) {
3218 switch (scf_error()) {
3219 case SCF_ERROR_CONNECTION_BROKEN:
3220 default:
3221 ret = ECONNABORTED;
3222 goto unset_action_cleanup;
3224 case SCF_ERROR_DELETED:
3225 case SCF_ERROR_NOT_FOUND:
3226 goto unset_action_cleanup;
3228 case SCF_ERROR_CONSTRAINT_VIOLATED:
3230 * More than one value was associated with
3231 * this property -- this is incorrect. Take
3232 * the opportunity to clean up and clear the
3233 * entire property.
3235 rep_ts = ts;
3236 break;
3238 case SCF_ERROR_PERMISSION_DENIED:
3239 case SCF_ERROR_NOT_SET:
3240 assert(0);
3241 abort();
3243 } else if (scf_value_get_integer(val, &rep_ts) == -1) {
3244 assert(scf_error() == SCF_ERROR_TYPE_MISMATCH);
3245 rep_ts = 0;
3248 /* Repository ts is more current. Don't clear the action. */
3249 if (rep_ts > ts)
3250 goto unset_action_cleanup;
3252 r = scf_transaction_property_change_type(t, e,
3253 admin_actions[a], SCF_TYPE_INTEGER);
3254 assert(r == 0);
3256 r = scf_transaction_commit(t);
3257 if (r == 1)
3258 break;
3260 if (r != 0) {
3261 switch (scf_error()) {
3262 case SCF_ERROR_CONNECTION_BROKEN:
3263 default:
3264 ret = ECONNABORTED;
3265 goto unset_action_cleanup;
3267 case SCF_ERROR_DELETED:
3268 break;
3270 case SCF_ERROR_PERMISSION_DENIED:
3271 ret = EPERM;
3272 goto unset_action_cleanup;
3274 case SCF_ERROR_BACKEND_ACCESS:
3275 case SCF_ERROR_BACKEND_READONLY:
3276 ret = EACCES;
3277 goto unset_action_cleanup;
3279 case SCF_ERROR_INVALID_ARGUMENT:
3280 case SCF_ERROR_NOT_SET:
3281 assert(0);
3282 abort();
3286 scf_transaction_reset(t);
3289 unset_action_cleanup:
3290 scf_transaction_destroy(t);
3291 scf_entry_destroy(e);
3292 scf_property_destroy(prop);
3293 scf_value_destroy(val);
3295 return (ret);
3299 * Decorates & binds hndl. hndl must be unbound. Returns
3300 * 0 - success
3301 * -1 - repository server is not running
3302 * -1 - repository server is out of resources
3304 static int
3305 handle_decorate_and_bind(scf_handle_t *hndl)
3307 scf_value_t *door_dec_value;
3309 door_dec_value = safe_scf_value_create(hndl);
3312 * Decorate if alternate door path set.
3314 if (st->st_door_path) {
3315 if (scf_value_set_astring(door_dec_value, st->st_door_path) !=
3317 uu_die("$STARTD_ALT_DOOR is too long.\n");
3319 if (scf_handle_decorate(hndl, "door_path", door_dec_value) != 0)
3320 bad_error("scf_handle_decorate", scf_error());
3323 scf_value_destroy(door_dec_value);
3325 if (scf_handle_bind(hndl) == 0)
3326 return (0);
3328 switch (scf_error()) {
3329 case SCF_ERROR_NO_SERVER:
3330 case SCF_ERROR_NO_RESOURCES:
3331 return (-1);
3333 case SCF_ERROR_INVALID_ARGUMENT:
3334 case SCF_ERROR_IN_USE:
3335 default:
3336 bad_error("scf_handle_bind", scf_error());
3337 /* NOTREACHED */
3341 scf_handle_t *
3342 libscf_handle_create_bound(scf_version_t v)
3344 scf_handle_t *hndl = scf_handle_create(v);
3346 if (hndl == NULL)
3347 return (hndl);
3349 if (handle_decorate_and_bind(hndl) == 0)
3350 return (hndl);
3352 scf_handle_destroy(hndl);
3353 return (NULL);
3356 void
3357 libscf_handle_rebind(scf_handle_t *h)
3359 (void) scf_handle_unbind(h);
3361 MUTEX_LOCK(&st->st_configd_live_lock);
3364 * Try to rebind the handle before sleeping in case the server isn't
3365 * really dead.
3367 while (handle_decorate_and_bind(h) != 0)
3368 (void) pthread_cond_wait(&st->st_configd_live_cv,
3369 &st->st_configd_live_lock);
3371 MUTEX_UNLOCK(&st->st_configd_live_lock);
3375 * Create a handle and try to bind it until it succeeds. Always returns
3376 * a bound handle.
3378 scf_handle_t *
3379 libscf_handle_create_bound_loop()
3381 scf_handle_t *h;
3383 while ((h = scf_handle_create(SCF_VERSION)) == NULL) {
3384 /* This should have been caught earlier. */
3385 assert(scf_error() != SCF_ERROR_VERSION_MISMATCH);
3386 (void) sleep(2);
3389 if (handle_decorate_and_bind(h) != 0)
3390 libscf_handle_rebind(h);
3392 return (h);
3396 * Call cb for each dependency property group of inst. cb is invoked with
3397 * a pointer to the scf_propertygroup_t and arg. If the repository connection
3398 * is broken, returns ECONNABORTED. If inst is deleted, returns ECANCELED.
3399 * If cb returns non-zero, the walk is stopped and EINTR is returned.
3400 * Otherwise returns 0.
3403 walk_dependency_pgs(scf_instance_t *inst, callback_t cb, void *arg)
3405 scf_handle_t *h;
3406 scf_snapshot_t *snap;
3407 scf_iter_t *iter;
3408 scf_propertygroup_t *pg;
3409 int r;
3411 h = scf_instance_handle(inst);
3413 iter = safe_scf_iter_create(h);
3414 pg = safe_scf_pg_create(h);
3416 snap = libscf_get_running_snapshot(inst);
3418 if (scf_iter_instance_pgs_typed_composed(iter, inst, snap,
3419 SCF_GROUP_DEPENDENCY) != 0) {
3420 scf_snapshot_destroy(snap);
3421 scf_pg_destroy(pg);
3422 scf_iter_destroy(iter);
3423 switch (scf_error()) {
3424 case SCF_ERROR_CONNECTION_BROKEN:
3425 default:
3426 return (ECONNABORTED);
3428 case SCF_ERROR_DELETED:
3429 return (ECANCELED);
3431 case SCF_ERROR_HANDLE_MISMATCH:
3432 case SCF_ERROR_INVALID_ARGUMENT:
3433 case SCF_ERROR_NOT_SET:
3434 assert(0);
3435 abort();
3439 for (;;) {
3440 r = scf_iter_next_pg(iter, pg);
3441 if (r == 0)
3442 break;
3443 if (r == -1) {
3444 scf_snapshot_destroy(snap);
3445 scf_pg_destroy(pg);
3446 scf_iter_destroy(iter);
3448 switch (scf_error()) {
3449 case SCF_ERROR_CONNECTION_BROKEN:
3450 return (ECONNABORTED);
3452 case SCF_ERROR_DELETED:
3453 return (ECANCELED);
3455 case SCF_ERROR_NOT_SET:
3456 case SCF_ERROR_INVALID_ARGUMENT:
3457 case SCF_ERROR_NOT_BOUND:
3458 case SCF_ERROR_HANDLE_MISMATCH:
3459 default:
3460 bad_error("scf_iter_next_pg", scf_error());
3464 r = cb(pg, arg);
3466 if (r != 0)
3467 break;
3470 scf_snapshot_destroy(snap);
3471 scf_pg_destroy(pg);
3472 scf_iter_destroy(iter);
3474 return (r == 0 ? 0 : EINTR);
3478 * Call cb for each of the string values of prop. cb is invoked with
3479 * a pointer to the string and arg. If the connection to the repository is
3480 * broken, ECONNABORTED is returned. If the property is deleted, ECANCELED is
3481 * returned. If the property does not have astring type, EINVAL is returned.
3482 * If cb returns non-zero, the walk is stopped and EINTR is returned.
3483 * Otherwise 0 is returned.
3486 walk_property_astrings(scf_property_t *prop, callback_t cb, void *arg)
3488 scf_handle_t *h;
3489 scf_value_t *val;
3490 scf_iter_t *iter;
3491 char *buf;
3492 int r;
3493 ssize_t sz;
3495 if (scf_property_is_type(prop, SCF_TYPE_ASTRING) != 0) {
3496 switch (scf_error()) {
3497 case SCF_ERROR_CONNECTION_BROKEN:
3498 default:
3499 return (ECONNABORTED);
3501 case SCF_ERROR_DELETED:
3502 return (ECANCELED);
3504 case SCF_ERROR_TYPE_MISMATCH:
3505 return (EINVAL);
3507 case SCF_ERROR_NOT_SET:
3508 assert(0);
3509 abort();
3513 h = scf_property_handle(prop);
3515 val = safe_scf_value_create(h);
3516 iter = safe_scf_iter_create(h);
3518 if (scf_iter_property_values(iter, prop) != 0) {
3519 scf_iter_destroy(iter);
3520 scf_value_destroy(val);
3521 switch (scf_error()) {
3522 case SCF_ERROR_CONNECTION_BROKEN:
3523 default:
3524 return (ECONNABORTED);
3526 case SCF_ERROR_DELETED:
3527 return (ECANCELED);
3529 case SCF_ERROR_HANDLE_MISMATCH:
3530 case SCF_ERROR_NOT_SET:
3531 assert(0);
3532 abort();
3536 buf = startd_alloc(max_scf_value_size);
3538 for (;;) {
3539 r = scf_iter_next_value(iter, val);
3540 if (r < 0) {
3541 startd_free(buf, max_scf_value_size);
3542 scf_iter_destroy(iter);
3543 scf_value_destroy(val);
3545 switch (scf_error()) {
3546 case SCF_ERROR_CONNECTION_BROKEN:
3547 return (ECONNABORTED);
3549 case SCF_ERROR_DELETED:
3550 return (ECANCELED);
3552 case SCF_ERROR_NOT_SET:
3553 case SCF_ERROR_INVALID_ARGUMENT:
3554 case SCF_ERROR_NOT_BOUND:
3555 case SCF_ERROR_HANDLE_MISMATCH:
3556 case SCF_ERROR_PERMISSION_DENIED:
3557 default:
3558 bad_error("scf_iter_next_value", scf_error());
3561 if (r == 0)
3562 break;
3564 sz = scf_value_get_astring(val, buf, max_scf_value_size);
3565 assert(sz >= 0);
3567 r = cb(buf, arg);
3569 if (r != 0)
3570 break;
3573 startd_free(buf, max_scf_value_size);
3574 scf_value_destroy(val);
3575 scf_iter_destroy(iter);
3577 return (r == 0 ? 0 : EINTR);
3581 * Returns 0 or ECONNABORTED.
3584 libscf_create_self(scf_handle_t *h)
3586 scf_scope_t *scope;
3587 scf_service_t *svc;
3588 scf_instance_t *inst;
3589 instance_data_t idata;
3590 int ret = 0, r;
3591 ctid_t ctid;
3592 uint64_t uint64;
3593 uint_t count = 0, msecs = ALLOC_DELAY;
3595 const char * const startd_svc = "system/svc/restarter";
3596 const char * const startd_inst = "default";
3598 /* If SCF_SERVICE_STARTD changes, our strings must change, too. */
3599 assert(strcmp(SCF_SERVICE_STARTD,
3600 "svc:/system/svc/restarter:default") == 0);
3602 scope = safe_scf_scope_create(h);
3603 svc = safe_scf_service_create(h);
3604 inst = safe_scf_instance_create(h);
3606 if (scf_handle_get_scope(h, SCF_SCOPE_LOCAL, scope) != 0) {
3607 assert(scf_error() == SCF_ERROR_CONNECTION_BROKEN);
3608 ret = ECONNABORTED;
3609 goto out;
3612 get_svc:
3613 if (scf_scope_get_service(scope, startd_svc, svc) != 0) {
3614 switch (scf_error()) {
3615 case SCF_ERROR_CONNECTION_BROKEN:
3616 case SCF_ERROR_DELETED:
3617 default:
3618 ret = ECONNABORTED;
3619 goto out;
3621 case SCF_ERROR_NOT_FOUND:
3622 break;
3624 case SCF_ERROR_HANDLE_MISMATCH:
3625 case SCF_ERROR_INVALID_ARGUMENT:
3626 case SCF_ERROR_NOT_SET:
3627 bad_error("scf_scope_get_service", scf_error());
3630 add_svc:
3631 if (scf_scope_add_service(scope, startd_svc, svc) != 0) {
3632 switch (scf_error()) {
3633 case SCF_ERROR_CONNECTION_BROKEN:
3634 case SCF_ERROR_DELETED:
3635 default:
3636 ret = ECONNABORTED;
3637 goto out;
3639 case SCF_ERROR_EXISTS:
3640 goto get_svc;
3642 case SCF_ERROR_PERMISSION_DENIED:
3643 case SCF_ERROR_BACKEND_ACCESS:
3644 case SCF_ERROR_BACKEND_READONLY:
3645 uu_warn("Could not create %s: %s\n",
3646 SCF_SERVICE_STARTD,
3647 scf_strerror(scf_error()));
3648 goto out;
3650 case SCF_ERROR_HANDLE_MISMATCH:
3651 case SCF_ERROR_INVALID_ARGUMENT:
3652 case SCF_ERROR_NOT_SET:
3653 bad_error("scf_scope_add_service", scf_error());
3658 if (scf_service_get_instance(svc, startd_inst, NULL) == 0)
3659 goto out;
3661 switch (scf_error()) {
3662 case SCF_ERROR_CONNECTION_BROKEN:
3663 default:
3664 ret = ECONNABORTED;
3665 goto out;
3667 case SCF_ERROR_NOT_FOUND:
3668 break;
3670 case SCF_ERROR_DELETED:
3671 goto add_svc;
3673 case SCF_ERROR_HANDLE_MISMATCH:
3674 case SCF_ERROR_INVALID_ARGUMENT:
3675 case SCF_ERROR_NOT_SET:
3676 bad_error("scf_service_get_instance", scf_error());
3679 add_inst:
3680 if (scf_service_add_instance(svc, startd_inst, inst) != 0) {
3681 switch (scf_error()) {
3682 case SCF_ERROR_CONNECTION_BROKEN:
3683 default:
3684 ret = ECONNABORTED;
3685 goto out;
3687 case SCF_ERROR_EXISTS:
3688 break;
3690 case SCF_ERROR_PERMISSION_DENIED:
3691 case SCF_ERROR_BACKEND_ACCESS:
3692 uu_die("Could not create %s: %s\n", SCF_SERVICE_STARTD,
3693 scf_strerror(scf_error()));
3694 /* NOTREACHED */
3696 case SCF_ERROR_BACKEND_READONLY:
3697 log_error(LOG_NOTICE,
3698 "Could not create %s: backend readonly.\n",
3699 SCF_SERVICE_STARTD);
3700 goto out;
3702 case SCF_ERROR_DELETED:
3703 goto add_svc;
3705 case SCF_ERROR_HANDLE_MISMATCH:
3706 case SCF_ERROR_INVALID_ARGUMENT:
3707 case SCF_ERROR_NOT_SET:
3708 bad_error("scf_service_add_instance", scf_error());
3712 /* Set start time. */
3713 idata.i_fmri = SCF_SERVICE_STARTD;
3714 idata.i_state = RESTARTER_STATE_NONE;
3715 idata.i_next_state = RESTARTER_STATE_NONE;
3716 set_state:
3717 switch (r = _restarter_commit_states(h, &idata,
3718 RESTARTER_STATE_ONLINE, RESTARTER_STATE_NONE,
3719 restarter_get_str_short(restarter_str_insert_in_graph))) {
3720 case 0:
3721 break;
3723 case ENOMEM:
3724 ++count;
3725 if (count < ALLOC_RETRY) {
3726 (void) poll(NULL, 0, msecs);
3727 msecs *= ALLOC_DELAY_MULT;
3728 goto set_state;
3731 uu_die("Insufficient memory.\n");
3732 /* NOTREACHED */
3734 case ECONNABORTED:
3735 ret = ECONNABORTED;
3736 goto out;
3738 case ENOENT:
3739 goto add_inst;
3741 case EPERM:
3742 case EACCES:
3743 case EROFS:
3744 uu_warn("Could not timestamp %s: %s\n", idata.i_fmri,
3745 strerror(r));
3746 break;
3748 case EINVAL:
3749 default:
3750 bad_error("_restarter_commit_states", r);
3753 /* Set general/enabled. */
3754 ret = libscf_inst_set_boolean_prop(inst, SCF_PG_GENERAL,
3755 SCF_PG_GENERAL_TYPE, SCF_PG_GENERAL_FLAGS, SCF_PROPERTY_ENABLED, 1);
3756 switch (ret) {
3757 case 0:
3758 case ECONNABORTED:
3759 case EPERM:
3760 case EACCES:
3761 case EROFS:
3762 break;
3764 case ECANCELED:
3765 goto add_inst;
3767 default:
3768 bad_error("libscf_inst_set_boolean_prop", ret);
3771 ret = libscf_write_start_pid(inst, getpid());
3772 switch (ret) {
3773 case 0:
3774 case ECONNABORTED:
3775 case EPERM:
3776 case EACCES:
3777 case EROFS:
3778 break;
3780 case ECANCELED:
3781 goto add_inst;
3783 default:
3784 bad_error("libscf_write_start_pid", ret);
3787 ctid = proc_get_ctid();
3788 if (ctid > 0) {
3790 uint64 = (uint64_t)ctid;
3791 ret = libscf_inst_set_count_prop(inst,
3792 SCF_PG_RESTARTER, SCF_PG_RESTARTER_TYPE,
3793 SCF_PG_RESTARTER_FLAGS, SCF_PROPERTY_CONTRACT, uint64);
3795 switch (ret) {
3796 case 0:
3797 case ECONNABORTED:
3798 case EPERM:
3799 case EACCES:
3800 case EROFS:
3801 break;
3803 case ECANCELED:
3804 goto add_inst;
3806 default:
3807 bad_error("libscf_inst_set_count_prop", ret);
3811 ret = libscf_note_method_log(inst, LOG_PREFIX_EARLY,
3812 STARTD_DEFAULT_LOG);
3813 if (ret == 0) {
3814 ret = libscf_note_method_log(inst, LOG_PREFIX_NORMAL,
3815 STARTD_DEFAULT_LOG);
3818 switch (ret) {
3819 case 0:
3820 case ECONNABORTED:
3821 case EPERM:
3822 case EACCES:
3823 case EROFS:
3824 case EAGAIN:
3825 break;
3827 case ECANCELED:
3828 goto add_inst;
3830 default:
3831 bad_error("libscf_note_method_log", ret);
3834 out:
3835 scf_instance_destroy(inst);
3836 scf_service_destroy(svc);
3837 scf_scope_destroy(scope);
3838 return (ret);
3842 * Returns
3843 * 0 - success
3844 * ENOENT - SCF_SERVICE_STARTD does not exist in repository
3845 * EPERM
3846 * EACCES
3847 * EROFS
3850 libscf_set_reconfig(int set)
3852 scf_handle_t *h;
3853 scf_instance_t *inst;
3854 scf_propertygroup_t *pg;
3855 int ret = 0;
3857 h = libscf_handle_create_bound_loop();
3858 inst = safe_scf_instance_create(h);
3859 pg = safe_scf_pg_create(h);
3861 again:
3862 if (scf_handle_decode_fmri(h, SCF_SERVICE_STARTD, NULL, NULL,
3863 inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) == -1) {
3864 switch (scf_error()) {
3865 case SCF_ERROR_CONNECTION_BROKEN:
3866 default:
3867 libscf_handle_rebind(h);
3868 goto again;
3870 case SCF_ERROR_NOT_FOUND:
3871 ret = ENOENT;
3872 goto reconfig_out;
3874 case SCF_ERROR_HANDLE_MISMATCH:
3875 case SCF_ERROR_INVALID_ARGUMENT:
3876 case SCF_ERROR_CONSTRAINT_VIOLATED:
3877 bad_error("scf_handle_decode_fmri", scf_error());
3881 ret = libscf_inst_set_boolean_prop(inst, "system", SCF_GROUP_FRAMEWORK,
3882 SCF_PG_FLAG_NONPERSISTENT, "reconfigure", set);
3883 switch (ret) {
3884 case 0:
3885 case EPERM:
3886 case EACCES:
3887 case EROFS:
3888 break;
3890 case ECONNABORTED:
3891 libscf_handle_rebind(h);
3892 goto again;
3894 case ECANCELED:
3895 ret = ENOENT;
3896 break;
3898 default:
3899 bad_error("libscf_inst_set_boolean_prop", ret);
3902 reconfig_out:
3903 scf_pg_destroy(pg);
3904 scf_instance_destroy(inst);
3905 scf_handle_destroy(h);
3906 return (ret);
3910 * Set inst->ri_m_inst to the scf instance for inst. If it has been deleted,
3911 * set inst->ri_mi_deleted to true. If the repository connection is broken, it
3912 * is rebound with libscf_handle_rebound().
3914 void
3915 libscf_reget_instance(restarter_inst_t *inst)
3917 scf_handle_t *h;
3918 int r;
3920 h = scf_instance_handle(inst->ri_m_inst);
3922 again:
3923 r = libscf_lookup_instance(inst->ri_i.i_fmri, inst->ri_m_inst);
3924 switch (r) {
3925 case 0:
3926 case ENOENT:
3927 inst->ri_mi_deleted = (r == ENOENT);
3928 return;
3930 case ECONNABORTED:
3931 libscf_handle_rebind(h);
3932 goto again;
3934 case EINVAL:
3935 case ENOTSUP:
3936 default:
3937 bad_error("libscf_lookup_instance", r);