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]
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>
32 #include <libscf_priv.h>
40 #define SMF_SNAPSHOT_RUNNING "running"
42 #define INFO_EVENTS_ALL "info_events_all"
45 inst_fmri_to_svc_fmri(const char *fmri
)
48 const char *scope
, *svc
;
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
);
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
);
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.
76 libscf_object_create(void *f(scf_handle_t
*), scf_handle_t
*h
)
86 if (err
!= SCF_ERROR_NO_MEMORY
&& err
!= SCF_ERROR_NO_RESOURCES
)
91 for (try = 0; try < ALLOC_RETRY
; ++try) {
92 (void) poll(NULL
, 0, msecs
);
93 msecs
*= ALLOC_DELAY_MULT
;
98 if (err
!= SCF_ERROR_NO_MEMORY
&& err
!= SCF_ERROR_NO_RESOURCES
)
102 uu_die("Insufficient memory.\n");
107 libscf_get_running_snapshot(scf_instance_t
*inst
)
110 scf_snapshot_t
*snap
;
112 h
= scf_instance_handle(inst
);
116 snap
= scf_snapshot_create(h
);
120 if (scf_instance_get_snapshot(inst
, SMF_SNAPSHOT_RUNNING
, snap
) == 0)
123 scf_snapshot_destroy(snap
);
128 * Make sure a service has a "running" snapshot. If it doesn't, make one from
129 * the editing configuration.
132 libscf_get_or_make_running_snapshot(scf_instance_t
*inst
, const char *fmri
,
136 scf_snapshot_t
*snap
;
138 h
= scf_instance_handle(inst
);
140 snap
= scf_snapshot_create(h
);
144 if (scf_instance_get_snapshot(inst
, SMF_SNAPSHOT_RUNNING
, snap
) == 0)
147 switch (scf_error()) {
148 case SCF_ERROR_NOT_FOUND
:
151 case SCF_ERROR_DELETED
:
152 scf_snapshot_destroy(snap
);
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
);
164 if (_scf_snapshot_take_new(inst
, SMF_SNAPSHOT_RUNNING
, snap
) == 0) {
165 log_framework(LOG_DEBUG
, "Took running snapshot for %s.\n",
168 if (retake
&& scf_error() == SCF_ERROR_BACKEND_READONLY
)
169 restarter_mark_pending_snapshot(fmri
,
170 RINST_RETAKE_RUNNING
);
173 "Could not create running snapshot for %s "
174 "(%s).\n", fmri
, scf_strerror(scf_error()));
176 scf_snapshot_destroy(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
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
;
196 r
= libscf_fmri_get_instance(h
, fmri
, &inst
);
212 start
= safe_scf_snapshot_create(h
);
215 running
= libscf_get_or_make_running_snapshot(inst
, fmri
, retake
);
216 if (running
== NULL
) {
222 if (scf_instance_get_snapshot(inst
, "start", start
) != 0) {
223 switch (scf_error()) {
224 case SCF_ERROR_CONNECTION_BROKEN
:
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
:
237 case SCF_ERROR_DELETED
:
241 case SCF_ERROR_EXISTS
:
244 case SCF_ERROR_NO_RESOURCES
:
245 uu_die("Repository server out of "
249 case SCF_ERROR_BACKEND_READONLY
:
252 case SCF_ERROR_PERMISSION_DENIED
:
253 uu_die("Insufficient privileges.\n");
256 case SCF_ERROR_BACKEND_ACCESS
:
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",
270 case SCF_ERROR_DELETED
:
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",
285 switch (scf_error()) {
286 case SCF_ERROR_CONNECTION_BROKEN
:
291 case SCF_ERROR_DELETED
:
292 scf_snapshot_destroy(running
);
295 case SCF_ERROR_NO_RESOURCES
:
296 uu_die("Repository server out of resources.\n");
299 case SCF_ERROR_PERMISSION_DENIED
:
300 uu_die("Insufficient privileges.\n");
303 case SCF_ERROR_BACKEND_ACCESS
:
307 case SCF_ERROR_BACKEND_READONLY
:
310 restarter_mark_pending_snapshot(fmri
,
314 case SCF_ERROR_HANDLE_MISMATCH
:
315 case SCF_ERROR_NOT_SET
:
316 bad_error("_scf_snapshot_attach", scf_error());
321 scf_snapshot_destroy(start
);
322 scf_snapshot_destroy(running
);
323 scf_instance_destroy(inst
);
329 * Before a refresh, update the "running" snapshot from the editing
332 * Returns 0 on success and -1 on failure.
335 libscf_snapshots_refresh(scf_instance_t
*inst
, const char *fmri
)
338 scf_snapshot_t
*snap
;
341 h
= scf_instance_handle(inst
);
345 snap
= scf_snapshot_create(h
);
349 if (scf_instance_get_snapshot(inst
, SMF_SNAPSHOT_RUNNING
, snap
) == 0) {
350 if (_scf_snapshot_take_attach(inst
, snap
) == 0)
353 switch (scf_error()) {
354 case SCF_ERROR_DELETED
:
358 case SCF_ERROR_NOT_FOUND
:
361 case SCF_ERROR_NOT_SET
:
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
,
380 scf_snapshot_destroy(snap
);
385 log_error(LOG_WARNING
,
386 "Could not update \"running\" snapshot for refresh of %s.\n", fmri
);
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.
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
);
404 if (scf_property_get_value(prop
, val
) == -1) {
405 if (scf_error() == SCF_ERROR_NOT_FOUND
)
406 r
= LIBSCF_PROPERTY_ABSENT
;
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
);
423 * libscf_get_stn_tset
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
);
433 assert(inst
!= NULL
);
435 pgname
= startd_alloc(max_scf_fmri_size
);
436 if (h
== NULL
|| pg
== NULL
) {
441 for (tset
= 0, t
= 1; t
< SCF_STATE_ALL
; t
<<= 1) {
444 (void) strcpy(pgname
, SCF_STN_PREFIX_TO
);
445 (void) strlcat(pgname
, smf_state_to_string(t
),
448 if (scf_instance_get_pg_composed(inst
, NULL
, pgname
, pg
) ==
451 } else if (scf_error() != SCF_ERROR_NOT_FOUND
&& scf_error() !=
457 (void) strcpy(pgname
, SCF_STN_PREFIX_FROM
);
458 (void) strlcat(pgname
, smf_state_to_string(t
),
461 if (scf_instance_get_pg_composed(inst
, NULL
, pgname
, pg
) ==
464 } else if (scf_error() != SCF_ERROR_NOT_FOUND
&& scf_error() !=
473 startd_free(pgname
, max_scf_fmri_size
);
479 libscf_get_global_stn_tset(scf_handle_t
*h
)
481 scf_instance_t
*inst
= scf_instance_create(h
);
488 if (scf_handle_decode_fmri(h
, SCF_INSTANCE_GLOBAL
, NULL
, NULL
, inst
,
489 NULL
, NULL
, SCF_DECODE_FMRI_REQUIRE_INSTANCE
) != 0) {
493 tset
= libscf_get_stn_tset(inst
);
496 scf_instance_destroy(inst
);
499 log_framework(LOG_WARNING
,
500 "Failed to get system wide notification parameters: %s\n",
501 scf_strerror(scf_error()));
507 libscf_read_state(const scf_propertygroup_t
*pg
, const char *prop_name
,
508 restarter_instance_state_t
*state
)
511 scf_property_t
*prop
;
512 char *char_state
= startd_alloc(max_scf_value_size
);
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
;
522 ret
= LIBSCF_PROPERTY_ERROR
;
524 ret
= libscf_read_single_astring(h
, prop
, &char_state
);
526 if (ret
!= LIBSCF_PROPERTY_ABSENT
)
527 ret
= LIBSCF_PROPERTY_ERROR
;
529 *state
= restarter_string_to_state(char_state
);
534 startd_free(char_state
, max_scf_value_size
);
535 scf_property_destroy(prop
);
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
,
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) {
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
;
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
;
575 ret
= LIBSCF_PROPERTY_ERROR
;
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
)
594 scf_property_t
*prop
;
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
);
606 ret
= scf_iter_next_property(iter
, prop
);
608 scf_property_destroy(prop
);
609 scf_iter_destroy(iter
);
616 scf_property_destroy(prop
);
617 scf_iter_destroy(iter
);
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
);
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)
640 else if (strcmp(scheme
, "path") == 0)
643 ret
= GVT_UNSUPPORTED
;
645 startd_free(scheme
, max_scf_value_size
);
646 scf_property_destroy(prop
);
651 depgroup_read_grouping(scf_handle_t
*h
, scf_propertygroup_t
*pg
)
653 char *grouping
= startd_alloc(max_scf_value_size
);
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
;
673 ret
= DEPGRP_UNSUPPORTED
;
675 startd_free(grouping
, max_scf_value_size
);
676 scf_property_destroy(prop
);
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)
696 else if (strcmp(restart_on
, SCF_DEP_RESET_ON_RESTART
) == 0)
698 else if (strcmp(restart_on
, SCF_DEP_RESET_ON_REFRESH
) == 0)
700 else if (strcmp(restart_on
, SCF_DEP_RESET_ON_NONE
) == 0)
703 ret
= RERR_UNSUPPORTED
;
705 startd_free(restart_on
, max_scf_value_size
);
706 scf_property_destroy(prop
);
712 * Fetches the value of a boolean property of the given property group.
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
723 get_boolean(scf_propertygroup_t
*pg
, const char *propname
, uint8_t *valuep
)
726 scf_property_t
*prop
;
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
:
742 case SCF_ERROR_DELETED
:
746 case SCF_ERROR_NOT_FOUND
:
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
:
764 case SCF_ERROR_DELETED
:
768 case SCF_ERROR_NOT_SET
:
769 bad_error("scf_property_type", scf_error());
773 if (type
!= SCF_TYPE_BOOLEAN
) {
778 if (scf_property_get_value(prop
, val
) != 0) {
779 switch (scf_error()) {
780 case SCF_ERROR_CONNECTION_BROKEN
:
785 case SCF_ERROR_DELETED
:
786 case SCF_ERROR_NOT_FOUND
:
790 case SCF_ERROR_CONSTRAINT_VIOLATED
:
794 case SCF_ERROR_PERMISSION_DENIED
:
798 case SCF_ERROR_NOT_SET
:
799 bad_error("scf_property_get_value", scf_error());
803 r
= scf_value_get_boolean(val
, valuep
);
807 scf_value_destroy(val
);
808 scf_property_destroy(prop
);
813 * get info event property from restarter:default
816 libscf_get_info_events_all(scf_propertygroup_t
*pg
)
821 if (get_boolean(pg
, INFO_EVENTS_ALL
, &v
) == 0) {
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()));
834 * Fetches the value of a count property of the given property group.
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
846 get_count(scf_propertygroup_t
*pg
, const char *propname
, uint64_t *valuep
)
849 scf_property_t
*prop
;
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
:
864 case SCF_ERROR_DELETED
:
868 case SCF_ERROR_NOT_FOUND
:
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
:
886 case SCF_ERROR_TYPE_MISMATCH
:
890 case SCF_ERROR_DELETED
:
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
:
908 case SCF_ERROR_DELETED
:
912 case SCF_ERROR_NOT_FOUND
:
916 case SCF_ERROR_CONSTRAINT_VIOLATED
:
920 case SCF_ERROR_PERMISSION_DENIED
:
924 case SCF_ERROR_NOT_SET
:
925 bad_error("scf_property_get_value", scf_error());
929 r
= scf_value_get_count(val
, valuep
);
933 scf_value_destroy(val
);
934 scf_property_destroy(prop
);
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
);
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
:
967 return (ECONNABORTED
);
969 case SCF_ERROR_DELETED
:
972 case SCF_ERROR_NOT_SET
:
983 * int libscf_fmri_get_instance(scf_handle_t *, const char *,
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
993 libscf_fmri_get_instance(scf_handle_t
*h
, const char *fmri
,
994 scf_instance_t
**instp
)
996 scf_instance_t
*inst
;
999 inst
= safe_scf_instance_create(h
);
1001 r
= libscf_lookup_instance(fmri
, inst
);
1006 scf_instance_destroy(inst
);
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
:
1020 case SCF_ERROR_CONSTRAINT_VIOLATED
:
1023 case SCF_ERROR_CONNECTION_BROKEN
:
1024 return (ECONNABORTED
);
1026 case SCF_ERROR_NOT_FOUND
:
1029 case SCF_ERROR_HANDLE_MISMATCH
:
1031 bad_error("scf_handle_decode_fmri", scf_error());
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
;
1054 pg
= safe_scf_pg_create(h
);
1056 if (scf_instance_get_pg_composed(inst
, NULL
, SCF_PG_DEATHROW
, pg
) !=
1058 switch (scf_error()) {
1059 case SCF_ERROR_CONNECTION_BROKEN
:
1062 return (ECONNABORTED
);
1064 case SCF_ERROR_DELETED
:
1068 case SCF_ERROR_NOT_FOUND
:
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());
1078 switch (r
= get_boolean(pg
,
1079 SCF_PROPERTY_DEATHROW
, &deathrow_8
)) {
1081 *deathrow
= deathrow_8
;
1095 bad_error("get_boolean", r
);
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
;
1122 pg
= safe_scf_pg_create(h
);
1124 if (enabled_ovrp
== NULL
)
1127 if (scf_instance_get_pg_composed(inst
, NULL
, SCF_PG_GENERAL_OVR
, pg
) !=
1129 switch (scf_error()) {
1130 case SCF_ERROR_CONNECTION_BROKEN
:
1133 return (ECONNABORTED
);
1135 case SCF_ERROR_DELETED
:
1139 case SCF_ERROR_NOT_FOUND
:
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());
1149 switch (r
= get_boolean(pg
, SCF_PROPERTY_ENABLED
, &enabled_8
)) {
1151 *enabled_ovrp
= enabled_8
;
1166 bad_error("get_boolean", r
);
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
1178 if (scf_instance_get_pg_composed(inst
, NULL
, SCF_PG_GENERAL
, pg
) != 0) {
1180 switch (scf_error()) {
1181 case SCF_ERROR_CONNECTION_BROKEN
:
1183 return (ECONNABORTED
);
1185 case SCF_ERROR_DELETED
:
1188 case SCF_ERROR_NOT_FOUND
:
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
)) {
1198 *enabledp
= enabled_8
;
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
);
1217 log_framework(LOG_ERR
,
1218 "general/enabled property of %s is invalid.\n", fmri
);
1224 bad_error("get_boolean", r
);
1227 if (restarter_fmri
!= NULL
)
1228 get_restarter(h
, pg
, restarter_fmri
);
1236 * Sets pg to the name property group of s_inst. If it doesn't exist, it is
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
)
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
:
1258 return (ECONNABORTED
);
1260 case SCF_ERROR_DELETED
:
1263 case SCF_ERROR_NOT_SET
:
1264 bad_error("scf_pg_get_flags", scf_error());
1271 if (scf_pg_delete(pg
) != 0) {
1272 switch (scf_error()) {
1273 case SCF_ERROR_CONNECTION_BROKEN
:
1275 return (ECONNABORTED
);
1277 case SCF_ERROR_DELETED
:
1280 case SCF_ERROR_PERMISSION_DENIED
:
1283 case SCF_ERROR_BACKEND_ACCESS
:
1286 case SCF_ERROR_BACKEND_READONLY
:
1289 case SCF_ERROR_NOT_SET
:
1290 bad_error("scf_pg_delete", scf_error());
1294 switch (scf_error()) {
1295 case SCF_ERROR_CONNECTION_BROKEN
:
1297 return (ECONNABORTED
);
1299 case SCF_ERROR_DELETED
:
1302 case SCF_ERROR_NOT_FOUND
:
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());
1313 if (scf_instance_add_pg(inst
, name
, type
, flags
, pg
) == 0)
1316 switch (scf_error()) {
1317 case SCF_ERROR_CONNECTION_BROKEN
:
1319 return (ECONNABORTED
);
1321 case SCF_ERROR_DELETED
:
1324 case SCF_ERROR_EXISTS
:
1327 case SCF_ERROR_PERMISSION_DENIED
:
1330 case SCF_ERROR_BACKEND_ACCESS
:
1333 case SCF_ERROR_BACKEND_READONLY
:
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());
1347 * ECONNABORTED - repository connection broken
1348 * - unknown libscf error
1352 transaction_add_set(scf_transaction_t
*tx
, scf_transaction_entry_t
*ent
,
1353 const char *pname
, scf_type_t ty
)
1356 if (scf_transaction_property_change_type(tx
, ent
, pname
,
1360 switch (scf_error()) {
1361 case SCF_ERROR_CONNECTION_BROKEN
:
1363 return (ECONNABORTED
);
1365 case SCF_ERROR_DELETED
:
1368 case SCF_ERROR_NOT_FOUND
:
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",
1379 if (scf_transaction_property_new(tx
, ent
, pname
, ty
) == 0)
1382 switch (scf_error()) {
1383 case SCF_ERROR_CONNECTION_BROKEN
:
1385 return (ECONNABORTED
);
1387 case SCF_ERROR_DELETED
:
1390 case SCF_ERROR_EXISTS
:
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());
1406 * ECONNABORTED - repository connection broken
1407 * - unknown libscf error
1408 * ECANCELED - pg was deleted
1414 pg_set_prop_value(scf_propertygroup_t
*pg
, const char *pname
, scf_value_t
*v
)
1417 scf_transaction_t
*tx
;
1418 scf_transaction_entry_t
*e
;
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
);
1431 if (scf_transaction_start(tx
, pg
) != 0) {
1432 switch (scf_error()) {
1433 case SCF_ERROR_CONNECTION_BROKEN
:
1438 case SCF_ERROR_DELETED
:
1442 case SCF_ERROR_PERMISSION_DENIED
:
1446 case SCF_ERROR_BACKEND_ACCESS
:
1450 case SCF_ERROR_BACKEND_READONLY
:
1454 case SCF_ERROR_NOT_SET
:
1455 bad_error("scf_transaction_start", ret
);
1459 ret
= transaction_add_set(tx
, e
, pname
, ty
);
1469 bad_error("transaction_add_set", ret
);
1472 r
= scf_entry_add_value(e
, v
);
1475 r
= scf_transaction_commit(tx
);
1480 scf_transaction_reset(tx
);
1482 case SCF_ERROR_CONNECTION_BROKEN
:
1487 case SCF_ERROR_DELETED
:
1491 case SCF_ERROR_PERMISSION_DENIED
:
1495 case SCF_ERROR_BACKEND_ACCESS
:
1499 case SCF_ERROR_BACKEND_READONLY
:
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
:
1517 case SCF_ERROR_DELETED
:
1521 case SCF_ERROR_NOT_SET
:
1522 bad_error("scf_pg_update", scf_error());
1530 scf_transaction_destroy(tx
);
1531 scf_entry_destroy(e
);
1538 * ECONNABORTED - repository connection broken
1539 * - unknown libscf error
1540 * ECANCELED - inst was deleted
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
)
1550 scf_propertygroup_t
*pg
= NULL
;
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
);
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
);
1587 bad_error("pg_set_prop_value", ret
);
1592 scf_value_destroy(v
);
1599 * ECONNABORTED - repository connection broken
1600 * - unknown libscf error
1601 * ECANCELED - inst was deleted
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
)
1611 scf_propertygroup_t
*pg
= NULL
;
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
);
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
);
1648 bad_error("pg_set_prop_value", ret
);
1653 scf_value_destroy(v
);
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
));
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
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
:
1708 return (ECONNABORTED
);
1710 case SCF_ERROR_DELETED
:
1713 case SCF_ERROR_NOT_FOUND
:
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
:
1727 return (ECONNABORTED
);
1729 case SCF_ERROR_DELETED
:
1730 case SCF_ERROR_CONSTRAINT_VIOLATED
:
1731 case SCF_ERROR_NOT_FOUND
:
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
:
1745 case SCF_ERROR_NOT_SET
:
1747 bad_error("scf_value_get_astring", scf_error());
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
;
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
)) {
1782 bad_error("pg_get_milestone", r
);
1785 switch (scf_error()) {
1786 case SCF_ERROR_CONNECTION_BROKEN
:
1791 case SCF_ERROR_DELETED
:
1795 case SCF_ERROR_NOT_FOUND
:
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
);
1808 switch (scf_error()) {
1809 case SCF_ERROR_CONNECTION_BROKEN
:
1814 case SCF_ERROR_DELETED
:
1818 case SCF_ERROR_NOT_FOUND
:
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());
1836 * Get the runlevel character from the runlevel property of the given property
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
)
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
:
1862 case SCF_ERROR_DELETED
:
1865 case SCF_ERROR_CONSTRAINT_VIOLATED
:
1868 case SCF_ERROR_NOT_FOUND
:
1871 case SCF_ERROR_HANDLE_MISMATCH
:
1872 case SCF_ERROR_NOT_BOUND
:
1873 case SCF_ERROR_PERMISSION_DENIED
:
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());
1887 scf_value_destroy(val
);
1889 if (buf
[0] == '\0' || buf
[1] != '\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
)
1906 scf_transaction_t
*tx
;
1907 scf_transaction_entry_t
*e_rl
, *e_ms
;
1910 boolean_t isempty
= B_TRUE
;
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
);
1920 r
= scf_value_set_astring(val
, milestone
);
1925 if (scf_transaction_start(tx
, pg
) != 0) {
1926 switch (scf_error()) {
1927 case SCF_ERROR_CONNECTION_BROKEN
:
1932 case SCF_ERROR_DELETED
:
1936 case SCF_ERROR_PERMISSION_DENIED
:
1940 case SCF_ERROR_BACKEND_ACCESS
:
1944 case SCF_ERROR_BACKEND_READONLY
:
1948 case SCF_ERROR_NOT_SET
:
1949 bad_error("scf_transaction_start", scf_error());
1953 if (scf_transaction_property_delete(tx
, e_rl
,
1957 switch (scf_error()) {
1958 case SCF_ERROR_CONNECTION_BROKEN
:
1963 case SCF_ERROR_DELETED
:
1967 case SCF_ERROR_NOT_FOUND
:
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",
1979 ret
= transaction_add_set(tx
, e_ms
,
1980 SCF_PROPERTY_MILESTONE
, SCF_TYPE_ASTRING
);
1990 bad_error("transaction_add_set", ret
);
1995 r
= scf_entry_add_value(e_ms
, val
);
2002 r
= scf_transaction_commit(tx
);
2007 scf_transaction_reset(tx
);
2009 case SCF_ERROR_CONNECTION_BROKEN
:
2013 case SCF_ERROR_PERMISSION_DENIED
:
2017 case SCF_ERROR_BACKEND_ACCESS
:
2021 case SCF_ERROR_BACKEND_READONLY
:
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
:
2038 case SCF_ERROR_NOT_SET
:
2050 scf_transaction_destroy(tx
);
2051 scf_entry_destroy(e_rl
);
2052 scf_entry_destroy(e_ms
);
2053 scf_value_destroy(val
);
2058 * int libscf_get_template_values(scf_instance_t *, scf_snapshot_t *,
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
)
2074 scf_propertygroup_t
*pg
= NULL
;
2075 scf_property_t
*prop
= NULL
;
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
)
2092 switch (scf_error()) {
2093 case SCF_ERROR_DELETED
:
2095 goto template_values_out
;
2097 case SCF_ERROR_NOT_FOUND
:
2098 goto template_values_out
;
2100 case SCF_ERROR_CONNECTION_BROKEN
:
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
:
2122 case SCF_ERROR_CONNECTION_BROKEN
:
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());
2133 if ((r
= libscf_read_single_astring(h
, prop
, &cname
)) !=
2135 if (r
!= LIBSCF_PROPERTY_ABSENT
)
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
:
2153 goto template_values_out
;
2155 case SCF_ERROR_NOT_FOUND
:
2158 case SCF_ERROR_CONNECTION_BROKEN
:
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());
2169 if ((r
= libscf_read_single_astring(h
, prop
, &c_cname
)) != 0) {
2170 if (r
!= LIBSCF_PROPERTY_ABSENT
)
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
);
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
)
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
);
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
:
2225 goto instance_flags_out
;
2227 case SCF_ERROR_NOT_FOUND
:
2229 goto instance_flags_out
;
2231 case SCF_ERROR_CONNECTION_BROKEN
:
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
:
2250 goto instance_flags_out
;
2252 case SCF_ERROR_NOT_FOUND
:
2255 case SCF_ERROR_CONNECTION_BROKEN
:
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());
2267 if ((r
= libscf_read_single_astring(h
, prop
, &style_str
))
2269 if (r
!= LIBSCF_PROPERTY_ABSENT
)
2271 goto instance_flags_out
;
2274 if (strcmp(style_str
, "child") == 0)
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) {
2285 if ((r
= libscf_read_single_astring(h
, prop
, prefixp
)) != 0) {
2286 if (r
!= LIBSCF_PROPERTY_ABSENT
)
2288 goto instance_flags_out
;
2291 switch (scf_error()) {
2292 case SCF_ERROR_DELETED
:
2294 goto instance_flags_out
;
2296 case SCF_ERROR_NOT_FOUND
:
2297 goto instance_flags_out
;
2299 case SCF_ERROR_CONNECTION_BROKEN
:
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());
2312 startd_free(style_str
, max_scf_value_size
);
2313 *flags
= (*flags
& ~RINST_STYLE_MASK
) | style
;
2315 scf_property_destroy(prop
);
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
;
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
:
2353 case SCF_ERROR_DELETED
:
2357 case SCF_ERROR_NOT_FOUND
:
2360 case SCF_ERROR_NOT_SET
:
2361 bad_error("scf_instance_get_pg", scf_error());
2365 ret
= get_count(pg
, SCF_PROPERTY_CONTRACT
, &p
);
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
);
2385 bad_error("get_count", ret
);
2391 ret
= get_count(pg
, SCF_PROPERTY_TRANSIENT_CONTRACT
, &t
);
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
);
2412 bad_error("get_count", ret
);
2418 ret
= get_count(pg
, SCF_PROPERTY_START_PID
, &p
);
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
);
2438 bad_error("get_count", ret
);
2444 scf_value_destroy(val
);
2445 scf_property_destroy(prop
);
2453 * ECONNABORTED - repository connection broken
2454 * - unknown libscf error
2455 * ECANCELED - s_inst was deleted
2461 libscf_write_start_pid(scf_instance_t
*s_inst
, pid_t pid
)
2464 scf_transaction_entry_t
*t_pid
;
2466 scf_propertygroup_t
*pg
;
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
);
2476 ret
= libscf_inst_get_or_add_pg(s_inst
, SCF_PG_RESTARTER
,
2477 SCF_PG_RESTARTER_TYPE
, SCF_PG_RESTARTER_FLAGS
, pg
);
2487 goto write_start_err
;
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
);
2508 bad_error("pg_set_prop_value", ret
);
2512 scf_entry_destroy(t_pid
);
2513 scf_value_destroy(v_pid
);
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.
2534 libscf_note_method_log(scf_instance_t
*inst
, const char *dir
, const char *file
)
2538 scf_propertygroup_t
*pg
;
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
) {
2554 ret
= libscf_inst_get_or_add_pg(inst
, SCF_PG_RESTARTER
,
2555 SCF_PG_RESTARTER_TYPE
, SCF_PG_RESTARTER_FLAGS
, pg
);
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
;
2576 propname
= SCF_PROPERTY_LOGFILE
;
2578 ret
= pg_set_prop_value(pg
, propname
, v
);
2589 bad_error("pg_set_prop_value", ret
);
2594 scf_value_destroy(v
);
2602 * ENAMETOOLONG - name is too long
2610 libscf_write_method_status(scf_instance_t
*s_inst
, const char *name
,
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
;
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
);
2636 ret
= libscf_inst_get_or_add_pg(s_inst
, SCF_PG_RESTARTER
,
2637 SCF_PG_RESTARTER_TYPE
, SCF_PG_RESTARTER_FLAGS
, pg
);
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);
2658 scf_value_set_integer(v_stat
, status
);
2661 if (scf_transaction_start(tx
, pg
) != 0) {
2662 switch (scf_error()) {
2663 case SCF_ERROR_CONNECTION_BROKEN
:
2668 case SCF_ERROR_DELETED
:
2672 case SCF_ERROR_PERMISSION_DENIED
:
2676 case SCF_ERROR_BACKEND_ACCESS
:
2680 case SCF_ERROR_BACKEND_READONLY
:
2684 case SCF_ERROR_NOT_SET
:
2685 bad_error("scf_transaction_start", ret
);
2689 (void) snprintf(pname
, sizeof (pname
), "%s_method_timestamp",
2691 ret
= transaction_add_set(tx
, e_time
, pname
, SCF_TYPE_TIME
);
2701 bad_error("transaction_add_set", ret
);
2704 r
= scf_entry_add_value(e_time
, v_time
);
2707 (void) snprintf(pname
, sizeof (pname
), "%s_method_waitstatus",
2709 ret
= transaction_add_set(tx
, e_stat
, pname
, SCF_TYPE_INTEGER
);
2719 bad_error("transaction_add_set", ret
);
2722 r
= scf_entry_add_value(e_stat
, v_stat
);
2724 bad_error("scf_entry_add_value", scf_error());
2726 r
= scf_transaction_commit(tx
);
2731 scf_transaction_reset_all(tx
);
2733 case SCF_ERROR_CONNECTION_BROKEN
:
2738 case SCF_ERROR_DELETED
:
2742 case SCF_ERROR_PERMISSION_DENIED
:
2746 case SCF_ERROR_BACKEND_ACCESS
:
2750 case SCF_ERROR_BACKEND_READONLY
:
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
:
2768 case SCF_ERROR_DELETED
:
2772 case SCF_ERROR_NOT_SET
:
2773 bad_error("scf_pg_update", scf_error());
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
);
2789 extern int32_t stn_global
;
2791 * Call dgraph_add_instance() for each instance in the repository.
2794 libscf_populate_graph(scf_handle_t
*h
)
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
);
2810 stn_global
= libscf_get_global_stn_tset(h
);
2812 if (scf_handle_get_local_scope(h
, scope
) !=
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) {
2827 if (libscf_instance_get_fmri(inst
, &fmri
) == 0) {
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
,
2835 startd_free(fmri
, max_scf_fmri_size
);
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.
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
;
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
);
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
);
2878 *restart_on
= METHOD_RESTART_UNKNOWN
;
2887 case METHOD_REFRESH
:
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
;
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
;
2916 error
= LIBSCF_PROPERTY_ERROR
;
2917 goto get_method_cleanup
;
2920 error
= libscf_read_single_astring(h
, prop
, &method
);
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
);
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
);
2942 error
= LIBSCF_PROPERTY_ERROR
;
2943 goto get_method_cleanup
;
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
);
2952 *timeout
= METHOD_TIMEOUT_INFINITE
;
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
,
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
:
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());
2983 if (scf_pg_get_property(pg_startd
, SCF_PROPERTY_IGNORE
,
2985 if (scf_error() == SCF_ERROR_NOT_FOUND
)
2988 error
= LIBSCF_PROPERTY_ERROR
;
2989 goto get_method_cleanup
;
2992 error
= libscf_read_single_astring(h
, prop
, &ig
);
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
;
3012 r
= get_boolean(pg_startd
, SCF_PROPERTY_NEED_SESSION
,
3019 error
= LIBSCF_PROPERTY_ERROR
;
3020 goto get_method_cleanup
;
3030 bad_error("get_boolean", r
);
3034 * Determine whether service has overriden retry after
3035 * method timeout. Default to retry if no value is
3038 r
= get_boolean(pg_startd
, SCF_PROPERTY_TIMEOUT_RETRY
,
3045 error
= LIBSCF_PROPERTY_ERROR
;
3046 goto get_method_cleanup
;
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
;
3069 error
= LIBSCF_PROPERTY_ERROR
;
3070 goto get_method_cleanup
;
3073 error
= libscf_read_single_astring(h
, prop
, &restart
);
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
;
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
);
3096 scf_pg_destroy(pg_startd
);
3097 scf_property_destroy(prop
);
3099 if (error
!= 0 && ret
!= NULL
) {
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
)
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
;
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
);
3154 if (scf_pg_update(pg
) == -1) {
3155 switch (scf_error()) {
3156 case SCF_ERROR_CONNECTION_BROKEN
:
3159 goto unset_action_cleanup
;
3161 case SCF_ERROR_DELETED
:
3162 goto unset_action_cleanup
;
3164 case SCF_ERROR_NOT_SET
:
3170 if (scf_transaction_start(t
, pg
) == -1) {
3171 switch (scf_error()) {
3172 case SCF_ERROR_CONNECTION_BROKEN
:
3175 goto unset_action_cleanup
;
3177 case SCF_ERROR_DELETED
:
3178 goto unset_action_cleanup
;
3180 case SCF_ERROR_PERMISSION_DENIED
:
3182 goto unset_action_cleanup
;
3184 case SCF_ERROR_BACKEND_ACCESS
:
3185 case SCF_ERROR_BACKEND_READONLY
:
3187 goto unset_action_cleanup
;
3189 case SCF_ERROR_IN_USE
:
3190 case SCF_ERROR_HANDLE_MISMATCH
:
3191 case SCF_ERROR_NOT_SET
:
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
:
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
:
3217 if (scf_property_get_value(prop
, val
) == -1) {
3218 switch (scf_error()) {
3219 case SCF_ERROR_CONNECTION_BROKEN
:
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
3238 case SCF_ERROR_PERMISSION_DENIED
:
3239 case SCF_ERROR_NOT_SET
:
3243 } else if (scf_value_get_integer(val
, &rep_ts
) == -1) {
3244 assert(scf_error() == SCF_ERROR_TYPE_MISMATCH
);
3248 /* Repository ts is more current. Don't clear the action. */
3250 goto unset_action_cleanup
;
3252 r
= scf_transaction_property_change_type(t
, e
,
3253 admin_actions
[a
], SCF_TYPE_INTEGER
);
3256 r
= scf_transaction_commit(t
);
3261 switch (scf_error()) {
3262 case SCF_ERROR_CONNECTION_BROKEN
:
3265 goto unset_action_cleanup
;
3267 case SCF_ERROR_DELETED
:
3270 case SCF_ERROR_PERMISSION_DENIED
:
3272 goto unset_action_cleanup
;
3274 case SCF_ERROR_BACKEND_ACCESS
:
3275 case SCF_ERROR_BACKEND_READONLY
:
3277 goto unset_action_cleanup
;
3279 case SCF_ERROR_INVALID_ARGUMENT
:
3280 case SCF_ERROR_NOT_SET
:
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
);
3299 * Decorates & binds hndl. hndl must be unbound. Returns
3301 * -1 - repository server is not running
3302 * -1 - repository server is out of resources
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)
3328 switch (scf_error()) {
3329 case SCF_ERROR_NO_SERVER
:
3330 case SCF_ERROR_NO_RESOURCES
:
3333 case SCF_ERROR_INVALID_ARGUMENT
:
3334 case SCF_ERROR_IN_USE
:
3336 bad_error("scf_handle_bind", scf_error());
3342 libscf_handle_create_bound(scf_version_t v
)
3344 scf_handle_t
*hndl
= scf_handle_create(v
);
3349 if (handle_decorate_and_bind(hndl
) == 0)
3352 scf_handle_destroy(hndl
);
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
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
3379 libscf_handle_create_bound_loop()
3383 while ((h
= scf_handle_create(SCF_VERSION
)) == NULL
) {
3384 /* This should have been caught earlier. */
3385 assert(scf_error() != SCF_ERROR_VERSION_MISMATCH
);
3389 if (handle_decorate_and_bind(h
) != 0)
3390 libscf_handle_rebind(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
)
3406 scf_snapshot_t
*snap
;
3408 scf_propertygroup_t
*pg
;
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
);
3422 scf_iter_destroy(iter
);
3423 switch (scf_error()) {
3424 case SCF_ERROR_CONNECTION_BROKEN
:
3426 return (ECONNABORTED
);
3428 case SCF_ERROR_DELETED
:
3431 case SCF_ERROR_HANDLE_MISMATCH
:
3432 case SCF_ERROR_INVALID_ARGUMENT
:
3433 case SCF_ERROR_NOT_SET
:
3440 r
= scf_iter_next_pg(iter
, pg
);
3444 scf_snapshot_destroy(snap
);
3446 scf_iter_destroy(iter
);
3448 switch (scf_error()) {
3449 case SCF_ERROR_CONNECTION_BROKEN
:
3450 return (ECONNABORTED
);
3452 case SCF_ERROR_DELETED
:
3455 case SCF_ERROR_NOT_SET
:
3456 case SCF_ERROR_INVALID_ARGUMENT
:
3457 case SCF_ERROR_NOT_BOUND
:
3458 case SCF_ERROR_HANDLE_MISMATCH
:
3460 bad_error("scf_iter_next_pg", scf_error());
3470 scf_snapshot_destroy(snap
);
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
)
3495 if (scf_property_is_type(prop
, SCF_TYPE_ASTRING
) != 0) {
3496 switch (scf_error()) {
3497 case SCF_ERROR_CONNECTION_BROKEN
:
3499 return (ECONNABORTED
);
3501 case SCF_ERROR_DELETED
:
3504 case SCF_ERROR_TYPE_MISMATCH
:
3507 case SCF_ERROR_NOT_SET
:
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
:
3524 return (ECONNABORTED
);
3526 case SCF_ERROR_DELETED
:
3529 case SCF_ERROR_HANDLE_MISMATCH
:
3530 case SCF_ERROR_NOT_SET
:
3536 buf
= startd_alloc(max_scf_value_size
);
3539 r
= scf_iter_next_value(iter
, val
);
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
:
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
:
3558 bad_error("scf_iter_next_value", scf_error());
3564 sz
= scf_value_get_astring(val
, buf
, max_scf_value_size
);
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
)
3588 scf_instance_t
*inst
;
3589 instance_data_t idata
;
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
);
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
:
3621 case SCF_ERROR_NOT_FOUND
:
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());
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
:
3639 case SCF_ERROR_EXISTS
:
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",
3647 scf_strerror(scf_error()));
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)
3661 switch (scf_error()) {
3662 case SCF_ERROR_CONNECTION_BROKEN
:
3667 case SCF_ERROR_NOT_FOUND
:
3670 case SCF_ERROR_DELETED
:
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());
3680 if (scf_service_add_instance(svc
, startd_inst
, inst
) != 0) {
3681 switch (scf_error()) {
3682 case SCF_ERROR_CONNECTION_BROKEN
:
3687 case SCF_ERROR_EXISTS
:
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()));
3696 case SCF_ERROR_BACKEND_READONLY
:
3697 log_error(LOG_NOTICE
,
3698 "Could not create %s: backend readonly.\n",
3699 SCF_SERVICE_STARTD
);
3702 case SCF_ERROR_DELETED
:
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
;
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
))) {
3725 if (count
< ALLOC_RETRY
) {
3726 (void) poll(NULL
, 0, msecs
);
3727 msecs
*= ALLOC_DELAY_MULT
;
3731 uu_die("Insufficient memory.\n");
3744 uu_warn("Could not timestamp %s: %s\n", idata
.i_fmri
,
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);
3768 bad_error("libscf_inst_set_boolean_prop", ret
);
3771 ret
= libscf_write_start_pid(inst
, getpid());
3784 bad_error("libscf_write_start_pid", ret
);
3787 ctid
= proc_get_ctid();
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
);
3807 bad_error("libscf_inst_set_count_prop", ret
);
3811 ret
= libscf_note_method_log(inst
, LOG_PREFIX_EARLY
,
3812 STARTD_DEFAULT_LOG
);
3814 ret
= libscf_note_method_log(inst
, LOG_PREFIX_NORMAL
,
3815 STARTD_DEFAULT_LOG
);
3831 bad_error("libscf_note_method_log", ret
);
3835 scf_instance_destroy(inst
);
3836 scf_service_destroy(svc
);
3837 scf_scope_destroy(scope
);
3844 * ENOENT - SCF_SERVICE_STARTD does not exist in repository
3850 libscf_set_reconfig(int set
)
3853 scf_instance_t
*inst
;
3854 scf_propertygroup_t
*pg
;
3857 h
= libscf_handle_create_bound_loop();
3858 inst
= safe_scf_instance_create(h
);
3859 pg
= safe_scf_pg_create(h
);
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
:
3867 libscf_handle_rebind(h
);
3870 case SCF_ERROR_NOT_FOUND
:
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
);
3891 libscf_handle_rebind(h
);
3899 bad_error("libscf_inst_set_boolean_prop", ret
);
3904 scf_instance_destroy(inst
);
3905 scf_handle_destroy(h
);
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().
3915 libscf_reget_instance(restarter_inst_t
*inst
)
3920 h
= scf_instance_handle(inst
->ri_m_inst
);
3923 r
= libscf_lookup_instance(inst
->ri_i
.i_fmri
, inst
->ri_m_inst
);
3927 inst
->ri_mi_deleted
= (r
== ENOENT
);
3931 libscf_handle_rebind(h
);
3937 bad_error("libscf_lookup_instance", r
);