#include "startd.h"
static int
gt_running(restarter_instance_state_t state)
{
if (state == RESTARTER_STATE_ONLINE ||
state == RESTARTER_STATE_DEGRADED)
return (1);
return (0);
}
static int
gt_enter_uninit(scf_handle_t *h, graph_vertex_t *v,
restarter_instance_state_t old_state, restarter_error_t rerr)
{
int err;
scf_instance_t *inst;
err = libscf_fmri_get_instance(h, v->gv_name, &inst);
switch (err) {
case 0:
break;
case ECONNABORTED:
return (ECONNABORTED);
case ENOENT:
return (0);
case EINVAL:
case ENOTSUP:
default:
bad_error("libscf_fmri_get_instance", err);
}
err = refresh_vertex(v, inst);
if (err == 0)
graph_enable_by_vertex(v, v->gv_flags & GV_ENABLED, 0);
scf_instance_destroy(inst);
if (gt_running(old_state)) {
log_framework(LOG_DEBUG, "Propagating stop of %s.\n",
v->gv_name);
graph_transition_propagate(v, PROPAGATE_STOP, rerr);
}
graph_transition_sulogin(RESTARTER_STATE_UNINIT, old_state);
return (0);
}
static int
gt_enter_maint(scf_handle_t *h, graph_vertex_t *v,
restarter_instance_state_t old_state, restarter_error_t rerr)
{
int to_offline = v->gv_flags & GV_TOOFFLINE;
v->gv_flags &= ~GV_TODISABLE;
v->gv_flags &= ~GV_TOOFFLINE;
if (gt_running(old_state)) {
if (to_offline) {
log_framework(LOG_DEBUG, "%s removed from subtree\n",
v->gv_name);
graph_offline_subtree_leaves(v, (void *)h);
}
log_framework(LOG_DEBUG, "Propagating maintenance (stop) of "
"%s.\n", v->gv_name);
graph_transition_propagate(v, PROPAGATE_STOP, rerr);
graph_transition_propagate(v, PROPAGATE_SAT, rerr);
} else {
log_framework(LOG_DEBUG, "Propagating maintenance of %s.\n",
v->gv_name);
graph_transition_propagate(v, PROPAGATE_SAT, rerr);
}
graph_transition_sulogin(RESTARTER_STATE_MAINT, old_state);
return (0);
}
static int
gt_enter_offline(scf_handle_t *h, graph_vertex_t *v,
restarter_instance_state_t old_state, restarter_error_t rerr)
{
int to_offline = v->gv_flags & GV_TOOFFLINE;
v->gv_flags &= ~GV_TOOFFLINE;
if (v->gv_flags & GV_TODISABLE) {
if (gt_running(old_state) && v->gv_post_disable_f)
v->gv_post_disable_f();
vertex_send_event(v, RESTARTER_EVENT_TYPE_DISABLE);
} else if (v->gv_flags & GV_ENABLED) {
if (to_offline == 0)
graph_start_if_satisfied(v);
}
if (gt_running(old_state)) {
if (to_offline) {
log_framework(LOG_DEBUG, "%s removed from subtree\n",
v->gv_name);
graph_offline_subtree_leaves(v, (void *)h);
}
log_framework(LOG_DEBUG, "Propagating stop of %s.\n",
v->gv_name);
graph_transition_propagate(v, PROPAGATE_STOP, rerr);
graph_transition_propagate(v, PROPAGATE_SAT, rerr);
} else {
log_framework(LOG_DEBUG, "Propagating offline of %s.\n",
v->gv_name);
graph_transition_propagate(v, PROPAGATE_SAT, rerr);
}
graph_transition_sulogin(RESTARTER_STATE_OFFLINE, old_state);
return (0);
}
static int
gt_enter_disabled(scf_handle_t *h, graph_vertex_t *v,
restarter_instance_state_t old_state, restarter_error_t rerr)
{
int to_offline = v->gv_flags & GV_TOOFFLINE;
v->gv_flags &= ~GV_TODISABLE;
v->gv_flags &= ~GV_TOOFFLINE;
if (v->gv_flags & GV_ENABLED) {
vertex_send_event(v, RESTARTER_EVENT_TYPE_ENABLE);
} else if (gt_running(old_state) && v->gv_post_disable_f) {
v->gv_post_disable_f();
}
if (gt_running(old_state)) {
if (to_offline) {
log_framework(LOG_DEBUG, "%s removed from subtree\n",
v->gv_name);
graph_offline_subtree_leaves(v, (void *)h);
}
log_framework(LOG_DEBUG, "Propagating stop of %s.\n",
v->gv_name);
graph_transition_propagate(v, PROPAGATE_STOP, rerr);
graph_transition_propagate(v, PROPAGATE_SAT, rerr);
} else {
log_framework(LOG_DEBUG, "Propagating disable of %s.\n",
v->gv_name);
graph_transition_propagate(v, PROPAGATE_SAT, rerr);
}
graph_transition_sulogin(RESTARTER_STATE_DISABLED, old_state);
return (0);
}
static int
gt_internal_online_or_degraded(scf_handle_t *h, graph_vertex_t *v,
restarter_instance_state_t old_state, restarter_error_t rerr)
{
int r;
if (gt_running(old_state) == 0) {
if (old_state != RESTARTER_STATE_UNINIT &&
v->gv_post_online_f)
v->gv_post_online_f();
r = libscf_snapshots_poststart(h, v->gv_name, B_TRUE);
switch (r) {
case 0:
case ENOENT:
break;
case ECONNABORTED:
return (ECONNABORTED);
case EACCES:
case ENOTSUP:
default:
bad_error("libscf_snapshots_poststart", r);
}
}
if (!(v->gv_flags & GV_ENABLED)) {
vertex_send_event(v, RESTARTER_EVENT_TYPE_DISABLE);
} else if (v->gv_flags & GV_TOOFFLINE) {
offline_vertex(v);
}
if (gt_running(old_state) == 0) {
log_framework(LOG_DEBUG, "Propagating start of %s.\n",
v->gv_name);
graph_transition_propagate(v, PROPAGATE_START, rerr);
} else if (rerr == RERR_REFRESH) {
log_framework(LOG_DEBUG, "Propagating refresh of %s.\n",
v->gv_name);
graph_transition_propagate(v, PROPAGATE_STOP, rerr);
}
return (0);
}
static int
gt_enter_online(scf_handle_t *h, graph_vertex_t *v,
restarter_instance_state_t old_state, restarter_error_t rerr)
{
int r;
r = gt_internal_online_or_degraded(h, v, old_state, rerr);
if (r != 0)
return (r);
graph_transition_sulogin(RESTARTER_STATE_ONLINE, old_state);
return (0);
}
static int
gt_enter_degraded(scf_handle_t *h, graph_vertex_t *v,
restarter_instance_state_t old_state, restarter_error_t rerr)
{
int r;
r = gt_internal_online_or_degraded(h, v, old_state, rerr);
if (r != 0)
return (r);
graph_transition_sulogin(RESTARTER_STATE_DEGRADED, old_state);
return (0);
}
int
gt_transition(scf_handle_t *h, graph_vertex_t *v, restarter_error_t rerr,
restarter_instance_state_t old_state)
{
int err;
int lost_repository = 0;
err = vertex_subgraph_dependencies_shutdown(h, v, old_state);
switch (err) {
case 0:
break;
case ECONNABORTED:
lost_repository = 1;
break;
default:
bad_error("vertex_subgraph_dependencies_shutdown", err);
}
switch (v->gv_state) {
case RESTARTER_STATE_UNINIT:
err = gt_enter_uninit(h, v, old_state, rerr);
break;
case RESTARTER_STATE_DISABLED:
err = gt_enter_disabled(h, v, old_state, rerr);
break;
case RESTARTER_STATE_OFFLINE:
err = gt_enter_offline(h, v, old_state, rerr);
break;
case RESTARTER_STATE_ONLINE:
err = gt_enter_online(h, v, old_state, rerr);
break;
case RESTARTER_STATE_DEGRADED:
err = gt_enter_degraded(h, v, old_state, rerr);
break;
case RESTARTER_STATE_MAINT:
err = gt_enter_maint(h, v, old_state, rerr);
break;
default:
#ifndef NDEBUG
uu_warn("%s:%d: Invalid state %d.\n", __FILE__, __LINE__,
v->gv_state);
#endif
abort();
}
switch (err) {
case 0:
break;
case ECONNABORTED:
lost_repository = 1;
break;
default:
#ifndef NDEBUG
uu_warn("%s:%d: "
"gt_enter_%s() failed with unexpected error %d.\n",
__FILE__, __LINE__, instance_state_str[v->gv_state], err);
#endif
abort();
}
return (lost_repository ? ECONNABORTED : 0);
}