enum class Command;
static int issueLoadService(int socknum, const char *service_name);
-static int checkLoadReply(int socknum, cpbuffer<1024> &rbuffer, handle_t *handle_p, ServiceState *state_p);
+static int checkLoadReply(int socknum, cpbuffer<1024> &rbuffer, handle_t *handle_p, service_state_t *state_p);
static int startStopService(int socknum, const char *service_name, Command command, bool do_pin, bool wait_for_service, bool verbose);
static int unpinService(int socknum, const char *service_name, bool verbose);
static int listServices(int socknum);
cpbuffer<1024> rbuffer;
wait_for_reply(rbuffer, socknum);
- ServiceState state;
- //ServiceState target_state;
+ service_state_t state;
+ //service_state_t target_state;
handle_t handle;
if (checkLoadReply(socknum, rbuffer, &handle, &state) != 0) {
return 0;
}
- ServiceState wanted_state = do_stop ? ServiceState::STOPPED : ServiceState::STARTED;
+ service_state_t wanted_state = do_stop ? service_state_t::STOPPED : service_state_t::STARTED;
int pcommand = 0;
switch (command) {
case Command::STOP_SERVICE:
}
// Check that a "load service" reply was received, and that the requested service was found.
-static int checkLoadReply(int socknum, cpbuffer<1024> &rbuffer, handle_t *handle_p, ServiceState *state_p)
+static int checkLoadReply(int socknum, cpbuffer<1024> &rbuffer, handle_t *handle_p, service_state_t *state_p)
{
using namespace std;
if (rbuffer[0] == DINIT_RP_SERVICERECORD) {
fillBufferTo(&rbuffer, socknum, 2 + sizeof(*handle_p));
rbuffer.extract((char *) handle_p, 2, sizeof(*handle_p));
- if (state_p) *state_p = static_cast<ServiceState>(rbuffer[1]);
- //target_state = static_cast<ServiceState>(rbuffer[2 + sizeof(handle)]);
+ if (state_p) *state_p = static_cast<service_state_t>(rbuffer[1]);
+ //target_state = static_cast<service_state_t>(rbuffer[2 + sizeof(handle)]);
rbuffer.consume(3 + sizeof(*handle_p));
return 0;
}
while (rbuffer[0] == DINIT_RP_SVCINFO) {
fillBufferTo(&rbuffer, socknum, 8);
int nameLen = rbuffer[1];
- ServiceState current = static_cast<ServiceState>(rbuffer[2]);
- ServiceState target = static_cast<ServiceState>(rbuffer[3]);
+ service_state_t current = static_cast<service_state_t>(rbuffer[2]);
+ service_state_t target = static_cast<service_state_t>(rbuffer[3]);
fillBufferTo(&rbuffer, socknum, nameLen + 8);
cout << "[";
- cout << (target == ServiceState::STARTED ? "{" : " ");
- cout << (current == ServiceState::STARTED ? "+" : " ");
- cout << (target == ServiceState::STARTED ? "}" : " ");
+ cout << (target == service_state_t::STARTED ? "{" : " ");
+ cout << (current == service_state_t::STARTED ? "+" : " ");
+ cout << (target == service_state_t::STARTED ? "}" : " ");
- if (current == ServiceState::STARTING) {
+ if (current == service_state_t::STARTING) {
cout << "<<";
}
- else if (current == ServiceState::STOPPING) {
+ else if (current == service_state_t::STOPPING) {
cout << ">>";
}
else {
cout << " ";
}
- cout << (target == ServiceState::STOPPED ? "{" : " ");
- cout << (current == ServiceState::STOPPED ? "-" : " ");
- cout << (target == ServiceState::STOPPED ? "}" : " ");
+ cout << (target == service_state_t::STOPPED ? "{" : " ");
+ cout << (current == service_state_t::STOPPED ? "-" : " ");
+ cout << (target == service_state_t::STOPPED ? "}" : " ");
cout << "] " << name << endl;
}
}
- bool will_restart = (desired_state == ServiceState::STARTED)
+ bool will_restart = (desired_state == service_state_t::STARTED)
&& services->get_auto_restart();
for (auto dependency : depends_on) {
dependency->dependentStopped();
}
- service_state = ServiceState::STOPPED;
+ service_state = service_state_t::STOPPED;
if (will_restart) {
// Desired state is "started".
bool did_exit = WIFEXITED(exit_status);
bool was_signalled = WIFSIGNALED(exit_status);
- if (exit_status != 0 && service_state != ServiceState::STOPPING) {
+ if (exit_status != 0 && service_state != service_state_t::STOPPING) {
if (did_exit) {
log(LogLevel::ERROR, "Service ", service_name, " process terminated with exit code ", WEXITSTATUS(exit_status));
}
}
}
- if (service_state == ServiceState::STARTING) {
+ if (service_state == service_state_t::STARTING) {
if (did_exit && WEXITSTATUS(exit_status) == 0) {
started();
}
failed_to_start();
}
}
- else if (service_state == ServiceState::STOPPING) {
+ else if (service_state == service_state_t::STOPPING) {
// We won't log a non-zero exit status or termination due to signal here -
// we assume that the process died because we signalled it.
stopped();
}
- else if (smooth_recovery && service_state == ServiceState::STARTED && desired_state == ServiceState::STARTED) {
+ else if (smooth_recovery && service_state == service_state_t::STARTED && desired_state == service_state_t::STARTED) {
// TODO if we are pinned-started then we should probably check
// that dependencies have started before trying to re-start the
// service process.
bool did_exit = WIFEXITED(exit_status);
bool was_signalled = WIFSIGNALED(exit_status);
- if (exit_status != 0 && service_state != ServiceState::STOPPING) {
+ if (exit_status != 0 && service_state != service_state_t::STOPPING) {
if (did_exit) {
log(LogLevel::ERROR, "Service ", service_name, " process terminated with exit code ", WEXITSTATUS(exit_status));
}
return;
}
- if (service_state == ServiceState::STARTING) {
+ if (service_state == service_state_t::STARTING) {
// POSIX requires that if the process exited clearly with a status code of 0,
// the exit status value will be 0:
if (exit_status == 0) {
failed_to_start();
}
}
- else if (service_state == ServiceState::STOPPING) {
+ else if (service_state == service_state_t::STOPPING) {
// We won't log a non-zero exit status or termination due to signal here -
// we assume that the process died because we signalled it.
stopped();
}
- else if (smooth_recovery && service_state == ServiceState::STARTED && desired_state == ServiceState::STARTED) {
+ else if (smooth_recovery && service_state == service_state_t::STARTED && desired_state == service_state_t::STARTED) {
// TODO if we are pinned-started then we should probably check
// that dependencies have started before trying to re-start the
// service process.
bool did_exit = WIFEXITED(exit_status);
bool was_signalled = WIFSIGNALED(exit_status);
- if (service_state == ServiceState::STOPPING) {
+ if (service_state == service_state_t::STOPPING) {
if (did_exit && WEXITSTATUS(exit_status) == 0) {
stopped();
}
}
sr->pid = -1;
log(LogLevel::ERROR, sr->service_name, ": execution failed: ", strerror(exec_status));
- if (sr->service_state == ServiceState::STARTING) {
+ if (sr->service_state == service_state_t::STARTING) {
sr->failed_to_start();
}
- else if (sr->service_state == ServiceState::STOPPING) {
+ else if (sr->service_state == service_state_t::STOPPING) {
// Must be a scripted service. We've logged the failure, but it's probably better
// not to leave the service in STARTED state:
sr->stopped();
// This could be a smooth recovery (state already STARTED). Even more, the process
// might be stopped (and killed via a signal) during smooth recovery. We don't to
// process startup again in either case, so we check for state STARTING:
- if (sr->service_state == ServiceState::STARTING) {
+ if (sr->service_state == service_state_t::STARTING) {
sr->started();
}
}
void service_record::release() noexcept
{
if (--required_by == 0) {
- desired_state = ServiceState::STOPPED;
+ desired_state = service_state_t::STOPPED;
// Can stop, and can release dependencies now. We don't need to issue a release if
// the require was pending though:
prop_require = false;
services->addToPropQueue(this);
- if (service_state == ServiceState::STOPPED) {
+ if (service_state == service_state_t::STOPPED) {
services->service_inactive(this);
}
else {
start_explicit = true;
}
- if (desired_state == ServiceState::STARTED && service_state != ServiceState::STOPPED) return;
+ if (desired_state == service_state_t::STARTED && service_state != service_state_t::STOPPED) return;
- bool was_active = service_state != ServiceState::STOPPED || desired_state != ServiceState::STOPPED;
- desired_state = ServiceState::STARTED;
+ bool was_active = service_state != service_state_t::STOPPED || desired_state != service_state_t::STOPPED;
+ desired_state = service_state_t::STARTED;
- if (service_state != ServiceState::STOPPED) {
+ if (service_state != service_state_t::STOPPED) {
// We're already starting/started, or we are stopping and need to wait for
// that the complete.
- if (service_state != ServiceState::STOPPING || ! can_interrupt_stop()) {
+ if (service_state != service_state_t::STOPPING || ! can_interrupt_stop()) {
return;
}
// We're STOPPING, and that can be interrupted. Our dependencies might be STOPPING,
services->service_active(this);
}
- service_state = ServiceState::STARTING;
+ service_state = service_state_t::STARTING;
waiting_for_deps = true;
if (startCheckDependencies(true)) {
void service_record::execute_transition() noexcept
{
- if (service_state == ServiceState::STARTING) {
+ if (service_state == service_state_t::STARTING) {
if (startCheckDependencies(false)) {
allDepsStarted(false);
}
}
- else if (service_state == ServiceState::STOPPING) {
+ else if (service_state == service_state_t::STOPPING) {
if (stopCheckDependents()) {
all_deps_stopped();
}
{
if (pinned_stopped) return;
- if (service_state != ServiceState::STARTING) {
+ if (service_state != service_state_t::STARTING) {
return;
}
- service_state = ServiceState::STARTING;
+ service_state = service_state_t::STARTING;
waiting_for_deps = true;
void service_record::dependencyStarted() noexcept
{
- if (service_state == ServiceState::STARTING && waiting_for_deps) {
+ if (service_state == service_state_t::STARTING && waiting_for_deps) {
services->addToStartQueue(this);
}
}
bool all_deps_started = true;
for (sr_iter i = depends_on.begin(); i != depends_on.end(); ++i) {
- if ((*i)->service_state != ServiceState::STARTED) {
+ if ((*i)->service_state != service_state_t::STARTED) {
if (start_deps) {
all_deps_started = false;
(*i)->prop_start = true;
for (auto i = soft_deps.begin(); i != soft_deps.end(); ++i) {
service_record * to = i->getTo();
if (start_deps) {
- if (to->service_state != ServiceState::STARTED) {
+ if (to->service_state != service_state_t::STARTED) {
to->prop_start = true;
services->addToPropQueue(to);
i->waiting_on = true;
}
}
else if (i->waiting_on) {
- if (to->service_state != ServiceState::STARTING) {
+ if (to->service_state != service_state_t::STARTING) {
// Service has either started or is no longer starting
i->waiting_on = false;
}
void service_record::acquiredConsole() noexcept
{
- if (service_state != ServiceState::STARTING) {
+ if (service_state != service_state_t::STARTING) {
// We got the console but no longer want it.
release_console();
}
}
logServiceStarted(service_name);
- service_state = ServiceState::STARTED;
+ service_state = service_state_t::STARTED;
notifyListeners(service_event::STARTED);
if (onstart_flags.rw_ready) {
setup_external_log();
}
- if (force_stop || desired_state == ServiceState::STOPPED) {
+ if (force_stop || desired_state == service_state_t::STOPPED) {
// We must now stop.
do_stop();
return;
}
logServiceFailed(service_name);
- service_state = ServiceState::STOPPED;
+ service_state = service_state_t::STOPPED;
if (start_explicit) {
start_explicit = false;
release();
// Cancel start of dependents:
for (sr_iter i = dependents.begin(); i != dependents.end(); i++) {
- if ((*i)->service_state == ServiceState::STARTING) {
+ if ((*i)->service_state == service_state_t::STARTING) {
(*i)->prop_failure = true;
services->addToPropQueue(*i);
}
// Mark this and all dependent services as force-stopped.
void service_record::forceStop() noexcept
{
- if (service_state != ServiceState::STOPPED) {
+ if (service_state != service_state_t::STOPPED) {
force_stop = true;
services->addToStopQueue(this);
}
void service_record::dependentStopped() noexcept
{
- if (service_state == ServiceState::STOPPING && waiting_for_deps) {
+ if (service_state == service_state_t::STOPPING && waiting_for_deps) {
services->addToStopQueue(this);
}
}
{
if (pinned_started) return;
- if (service_state != ServiceState::STARTED) {
- if (service_state == ServiceState::STARTING) {
+ if (service_state != service_state_t::STARTED) {
+ if (service_state == service_state_t::STARTING) {
if (! can_interrupt_start()) {
// Well this is awkward: we're going to have to continue
// starting, but we don't want any dependents to think that
}
}
- service_state = ServiceState::STOPPING;
+ service_state = service_state_t::STOPPING;
waiting_for_deps = true;
if (stopDependents()) {
services->addToStopQueue(this);
{
if (pinned_started) {
pinned_started = false;
- if (desired_state == ServiceState::STOPPED) {
+ if (desired_state == service_state_t::STOPPED) {
do_stop();
services->processQueues(false);
}
}
if (pinned_stopped) {
pinned_stopped = false;
- if (desired_state == ServiceState::STARTED) {
+ if (desired_state == service_state_t::STARTED) {
do_start();
services->processQueues(true);
}
// We may be STARTING (regular restart) or STARTED ("smooth recovery"). This affects whether
// the process should be granted access to the console:
- bool on_console = service_state == ServiceState::STARTING
+ bool on_console = service_state == service_state_t::STARTING
? onstart_flags.starts_on_console : onstart_flags.runs_on_console;
if (! start_ps_process(exec_arg_parts, on_console)) {
- if (service_state == ServiceState::STARTING) {
+ if (service_state == service_state_t::STARTING) {
failed_to_start();
}
else {
- desired_state = ServiceState::STOPPED;
+ desired_state = service_state_t::STOPPED;
forceStop();
}
services->processQueues();
string service_name;
service_type record_type; /* ServiceType::DUMMY, PROCESS, SCRIPTED, INTERNAL */
- ServiceState service_state = ServiceState::STOPPED; /* ServiceState::STOPPED, STARTING, STARTED, STOPPING */
- ServiceState desired_state = ServiceState::STOPPED; /* ServiceState::STOPPED / STARTED */
+ service_state_t service_state = service_state_t::STOPPED; /* service_state_t::STOPPED, STARTING, STARTED, STOPPING */
+ service_state_t desired_state = service_state_t::STOPPED; /* service_state_t::STOPPED / STARTED */
string program_name; // storage for program/script and arguments
std::vector<const char *> exec_arg_parts; // pointer to each argument/part of the program_name, and nullptr
// Check if service is, fundamentally, stopped.
bool is_stopped() noexcept
{
- return service_state == ServiceState::STOPPED
- || (service_state == ServiceState::STARTING && waiting_for_deps);
+ return service_state == service_state_t::STOPPED
+ || (service_state == service_state_t::STARTING && waiting_for_deps);
}
void notifyListeners(service_event event) noexcept
public:
service_record(service_set *set, string name)
- : service_state(ServiceState::STOPPED), desired_state(ServiceState::STOPPED),
+ : service_state(service_state_t::STOPPED), desired_state(service_state_t::STOPPED),
auto_restart(false), smooth_recovery(false),
pinned_stopped(false), pinned_started(false), waiting_for_deps(false),
waiting_for_execstat(false), start_explicit(false),
}
// Get the current service state.
- ServiceState getState() noexcept
+ service_state_t getState() noexcept
{
return service_state;
}
// Get the target (aka desired) state.
- ServiceState getTargetState() noexcept
+ service_state_t getTargetState() noexcept
{
return desired_state;
}
}
const std::string &getServiceName() const noexcept { return service_name; }
- ServiceState getState() const noexcept { return service_state; }
+ service_state_t getState() const noexcept { return service_state; }
void start(bool activate = true) noexcept; // start the service
void stop(bool bring_down = true) noexcept; // stop the service