13 #include "dinit-log.h"
14 #include "dinit-socket.h"
15 #include "dinit-util.h"
16 #include "baseproc-sys.h"
19 * service.cc - Service management.
20 * See service.h for details.
23 // Find the requested service by name
24 static service_record * find_service(const std::list<service_record *> & records,
25 const char *name) noexcept
28 list<service_record *>::const_iterator i = records.begin();
29 for ( ; i != records.end(); ++i ) {
30 if (strcmp((*i)->get_name().c_str(), name) == 0) {
37 service_record * service_set::find_service(const std::string &name) noexcept
39 return ::find_service(records, name.c_str());
42 void service_set::stop_service(const std::string & name) noexcept
44 service_record *record = find_service(name);
45 if (record != nullptr) {
51 // Called when a service has actually stopped; dependents have stopped already, unless this stop
52 // is due to an unexpected process termination.
53 void service_record::stopped() noexcept
56 bp_sys::tcsetpgrp(0, bp_sys::getpgrp());
57 discard_console_log_buffer();
63 // If we are a soft dependency of another target, break the acquisition from that target now,
64 // so that we don't re-start:
65 for (auto & dependent : dependents) {
66 if (dependent->dep_type != dependency_type::REGULAR) {
67 if (dependent->holding_acq && ! dependent->waiting_on) {
68 dependent->holding_acq = false;
74 bool will_restart = (desired_state == service_state_t::STARTED)
75 && services->get_auto_restart();
77 for (auto & dependency : depends_on) {
78 // we signal dependencies in case they are waiting for us to stop:
79 dependency.get_to()->dependent_stopped();
82 service_state = service_state_t::STOPPED;
85 // Desired state is "started".
93 // If we were explicitly started, our required_by count must be at least 1. Use
94 // release() to correctly release, mark inactive and release dependencies.
95 start_explicit = false;
98 else if (required_by == 0) {
99 // This can only be the case if we didn't have start_explicit, since required_by would
100 // otherwise by non-zero.
101 prop_release = !prop_require;
102 prop_require = false;
103 services->add_prop_queue(this);
104 services->service_inactive(this);
108 // Start failure will have been logged already, only log if we are stopped for other reasons:
109 if (! start_failed) {
110 log_service_stopped(service_name);
112 // If this service chains to another, start the other service now:
113 if (! will_restart && ! start_on_completion.empty()) {
115 auto chain_to = services->load_service(start_on_completion.c_str());
118 catch (service_load_exc &sle) {
119 log(loglevel_t::ERROR, "Couldn't chain to service ", start_on_completion, ": ",
120 "couldn't load ", sle.service_name, ": ", sle.exc_description);
122 catch (std::bad_alloc &bae) {
123 log(loglevel_t::ERROR, "Couldn't chain to service ", start_on_completion,
128 notify_listeners(service_event_t::STOPPED);
131 bool service_record::do_auto_restart() noexcept
134 return services->get_auto_restart();
139 void service_record::require() noexcept
141 if (required_by++ == 0) {
142 prop_require = !prop_release;
143 prop_release = false;
144 services->add_prop_queue(this);
145 if (service_state != service_state_t::STARTING && service_state != service_state_t::STARTED) {
151 void service_record::release(bool issue_stop) noexcept
153 if (--required_by == 0) {
154 desired_state = service_state_t::STOPPED;
156 // Can stop, and can release dependencies now. We don't need to issue a release if
157 // the require was pending though:
158 prop_release = !prop_require;
159 prop_require = false;
160 services->add_prop_queue(this);
162 if (service_state == service_state_t::STOPPED) {
163 services->service_inactive(this);
165 else if (issue_stop) {
166 stop_reason = stopped_reason_t::NORMAL;
172 void service_record::release_dependencies() noexcept
174 for (auto & dependency : depends_on) {
175 service_record * dep_to = dependency.get_to();
176 if (dependency.holding_acq) {
177 // We must clear holding_acq before calling release, otherwise the dependency
178 // may decide to stop, check this link and release itself a second time.
179 dependency.holding_acq = false;
185 void service_record::start(bool activate) noexcept
187 if (activate && ! start_explicit) {
189 start_explicit = true;
192 if (desired_state == service_state_t::STARTED && service_state != service_state_t::STOPPED) return;
194 bool was_active = service_state != service_state_t::STOPPED || desired_state != service_state_t::STOPPED;
195 desired_state = service_state_t::STARTED;
197 if (service_state != service_state_t::STOPPED) {
198 // We're already starting/started, or we are stopping and need to wait for
199 // that the complete.
200 if (service_state != service_state_t::STOPPING || ! can_interrupt_stop()) {
203 // We're STOPPING, and that can be interrupted. Our dependencies might be STOPPING,
204 // but if so they are waiting (for us), so they too can be instantly returned to
206 notify_listeners(service_event_t::STOPCANCELLED);
208 else if (! was_active) {
209 services->service_active(this);
212 start_failed = false;
213 start_skipped = false;
214 service_state = service_state_t::STARTING;
215 waiting_for_deps = true;
217 if (start_check_dependencies()) {
218 services->add_transition_queue(this);
222 void service_record::do_propagation() noexcept
225 // Need to require all our dependencies
226 for (auto & dep : depends_on) {
227 dep.get_to()->require();
228 dep.holding_acq = true;
230 prop_require = false;
234 release_dependencies();
235 prop_release = false;
239 prop_failure = false;
240 stop_reason = stopped_reason_t::DEPFAILED;
241 failed_to_start(true);
255 void service_record::execute_transition() noexcept
257 // state is STARTED with restarting set true if we are running a smooth recovery.
258 if (service_state == service_state_t::STARTING || (service_state == service_state_t::STARTED
260 if (check_deps_started()) {
264 else if (service_state == service_state_t::STOPPING) {
265 if (stop_check_dependents()) {
266 waiting_for_deps = false;
272 void service_record::do_start() noexcept
274 if (pinned_stopped) return;
276 if (service_state != service_state_t::STARTING) {
280 service_state = service_state_t::STARTING;
282 waiting_for_deps = true;
284 // Ask dependencies to start, mark them as being waited on.
285 if (check_deps_started()) {
286 // Once all dependencies are started, we start properly:
291 void service_record::dependency_started() noexcept
293 // Note that we check for STARTED state here in case the service is in smooth recovery while pinned.
294 // In that case it will wait for dependencies to start before restarting the process.
295 if ((service_state == service_state_t::STARTING || service_state == service_state_t::STARTED)
296 && waiting_for_deps) {
297 services->add_transition_queue(this);
301 bool service_record::start_check_dependencies() noexcept
303 bool all_deps_started = true;
305 for (auto & dep : depends_on) {
306 service_record * to = dep.get_to();
307 if (to->service_state != service_state_t::STARTED) {
308 if (to->service_state != service_state_t::STARTING) {
309 to->prop_start = true;
310 services->add_prop_queue(to);
312 dep.waiting_on = true;
313 all_deps_started = false;
317 return all_deps_started;
320 bool service_record::check_deps_started() noexcept
322 for (auto & dep : depends_on) {
323 if (dep.waiting_on) {
331 void service_record::all_deps_started() noexcept
333 if (onstart_flags.starts_on_console && ! have_console) {
338 waiting_for_deps = false;
340 if (! can_proceed_to_start()) {
341 waiting_for_deps = true;
345 bool start_success = bring_up();
346 if (! start_success) {
351 void service_record::acquired_console() noexcept
353 waiting_for_console = false;
356 if (service_state != service_state_t::STARTING) {
357 // We got the console but no longer want it.
360 else if (check_deps_started()) {
364 // We got the console but can't use it yet.
369 void service_record::started() noexcept
371 // If we start on console but don't keep it, release it now:
372 if (have_console && ! onstart_flags.runs_on_console) {
373 bp_sys::tcsetpgrp(0, bp_sys::getpgrp());
377 log_service_started(get_name());
378 service_state = service_state_t::STARTED;
379 notify_listeners(service_event_t::STARTED);
381 if (onstart_flags.rw_ready) {
382 open_control_socket();
384 if (onstart_flags.log_ready) {
385 setup_external_log();
388 if (force_stop || desired_state == service_state_t::STOPPED) {
394 // Notify any dependents whose desired state is STARTED:
395 for (auto dept : dependents) {
396 dept->get_from()->dependency_started();
397 dept->waiting_on = false;
401 void service_record::failed_to_start(bool depfailed, bool immediate_stop) noexcept
403 if (waiting_for_console) {
404 services->unqueue_console(this);
405 waiting_for_console = false;
408 if (start_explicit) {
409 start_explicit = false;
413 // Cancel start of dependents:
414 for (auto & dept : dependents) {
415 switch (dept->dep_type) {
416 case dependency_type::REGULAR:
417 case dependency_type::MILESTONE:
418 if (dept->get_from()->service_state == service_state_t::STARTING) {
419 dept->get_from()->prop_failure = true;
420 services->add_prop_queue(dept->get_from());
423 case dependency_type::WAITS_FOR:
424 case dependency_type::SOFT:
425 if (dept->waiting_on) {
426 dept->waiting_on = false;
427 dept->get_from()->dependency_started();
431 // Always release now, so that our desired state will be STOPPED before we call
432 // stopped() below (if we do so). Otherwise it may decide to restart us.
433 if (dept->holding_acq) {
434 dept->holding_acq = false;
440 log_service_failed(get_name());
441 notify_listeners(service_event_t::FAILEDSTART);
443 if (immediate_stop) {
448 bool service_record::bring_up() noexcept
450 // default implementation: there is no process, so we are started.
455 // Mark this and all dependent services as force-stopped.
456 void service_record::forced_stop() noexcept
458 if (service_state != service_state_t::STOPPED) {
460 if (! pinned_started) {
462 services->add_transition_queue(this);
467 void service_record::dependent_stopped() noexcept
469 if (service_state == service_state_t::STOPPING && waiting_for_deps) {
470 services->add_transition_queue(this);
474 void service_record::stop(bool bring_down) noexcept
476 if (start_explicit) {
477 start_explicit = false;
481 if (bring_down && service_state != service_state_t::STOPPED
482 && service_state != service_state_t::STOPPING) {
483 stop_reason = stopped_reason_t::NORMAL;
488 void service_record::do_stop() noexcept
490 // A service that does actually stop for any reason should have its explicit activation released, unless
492 if (start_explicit && ! do_auto_restart()) {
493 start_explicit = false;
497 bool all_deps_stopped = stop_dependents();
499 if (service_state != service_state_t::STARTED) {
500 if (service_state == service_state_t::STARTING) {
501 // If waiting for a dependency, or waiting for the console, we can interrupt start. Otherwise,
502 // we need to delegate to can_interrupt_start() (which can be overridden).
503 if (! waiting_for_deps && ! waiting_for_console) {
504 if (! can_interrupt_start()) {
505 // Well this is awkward: we're going to have to continue starting. We can stop once
506 // we've reached the started state.
510 if (! interrupt_start()) {
511 // Now wait for service startup to actually end; we don't need to handle it here.
512 notify_listeners(service_event_t::STARTCANCELLED);
516 else if (waiting_for_console) {
517 services->unqueue_console(this);
518 waiting_for_console = false;
521 // We must have had desired_state == STARTED.
522 notify_listeners(service_event_t::STARTCANCELLED);
524 // Reaching this point, we are starting interruptibly - so we
525 // stop now (by falling through to below).
528 // If we're starting we need to wait for that to complete.
529 // If we're already stopping/stopped there's nothing to do.
534 if (pinned_started) return;
536 service_state = service_state_t::STOPPING;
537 waiting_for_deps = true;
538 if (all_deps_stopped) {
539 services->add_transition_queue(this);
543 bool service_record::stop_check_dependents() noexcept
545 bool all_deps_stopped = true;
546 for (auto dept : dependents) {
547 if (dept->dep_type == dependency_type::REGULAR && ! dept->get_from()->is_stopped()) {
548 all_deps_stopped = false;
553 return all_deps_stopped;
556 bool service_record::stop_dependents() noexcept
558 bool all_deps_stopped = true;
559 for (auto dept : dependents) {
560 if (dept->dep_type == dependency_type::REGULAR ||
561 (dept->dep_type == dependency_type::MILESTONE &&
562 dept->get_from()->service_state != service_state_t::STARTED)) {
563 if (! dept->get_from()->is_stopped()) {
564 // Note we check *first* since if the dependent service is not stopped,
565 // 1. We will issue a stop to it shortly and
566 // 2. It will notify us when stopped, at which point the stop_check_dependents()
567 // check is run anyway.
568 all_deps_stopped = false;
572 // If this service is to be forcefully stopped, dependents must also be.
573 dept->get_from()->forced_stop();
576 dept->get_from()->prop_stop = true;
577 services->add_prop_queue(dept->get_from());
580 // waits-for or soft dependency:
581 if (dept->waiting_on) {
582 dept->waiting_on = false;
583 dept->get_from()->dependency_started();
585 if (dept->holding_acq) {
586 dept->holding_acq = false;
587 // release without issuing stop, since we should be called only when this
588 // service is already stopped/stopping:
594 return all_deps_stopped;
597 // All dependents have stopped; we can stop now, too. Only called when STOPPING.
598 void service_record::bring_down() noexcept
600 waiting_for_deps = false;
604 void service_record::unpin() noexcept
606 if (pinned_started) {
607 pinned_started = false;
608 if (desired_state == service_state_t::STOPPED || force_stop) {
610 services->process_queues();
613 if (pinned_stopped) {
614 pinned_stopped = false;
615 if (desired_state == service_state_t::STARTED) {
617 services->process_queues();
622 void service_record::queue_for_console() noexcept
624 waiting_for_console = true;
625 services->append_console_queue(this);
628 void service_record::release_console() noexcept
630 have_console = false;
631 services->pull_console_queue();
634 bool service_record::interrupt_start() noexcept
639 void service_set::service_active(service_record *sr) noexcept
644 void service_set::service_inactive(service_record *sr) noexcept