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
55 if (onstart_flags.runs_on_console) {
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 for (auto & dependent : dependents) {
65 if (dependent->dep_type != dependency_type::REGULAR) {
66 if (dependent->holding_acq) {
67 dependent->holding_acq = false;
73 bool will_restart = (desired_state == service_state_t::STARTED)
74 && services->get_auto_restart();
76 for (auto dependency : depends_on) {
77 // we signal dependencies in case they are waiting for us to stop:
78 dependency.get_to()->dependent_stopped();
81 service_state = service_state_t::STOPPED;
84 // Desired state is "started".
92 start_explicit = false;
95 else if (required_by == 0) {
96 services->service_inactive(this);
100 log_service_stopped(service_name);
101 notify_listeners(service_event_t::STOPPED);
104 bool service_record::do_auto_restart() noexcept
107 return services->get_auto_restart();
112 void service_record::require() noexcept
114 if (required_by++ == 0) {
115 prop_require = !prop_release;
116 prop_release = false;
117 services->add_prop_queue(this);
118 if (service_state != service_state_t::STARTING && service_state != service_state_t::STARTED) {
124 void service_record::release(bool issue_stop) noexcept
126 if (--required_by == 0) {
127 desired_state = service_state_t::STOPPED;
129 // Can stop, and can release dependencies now. We don't need to issue a release if
130 // the require was pending though:
131 prop_release = !prop_require;
132 prop_require = false;
133 services->add_prop_queue(this);
135 if (service_state == service_state_t::STOPPED) {
136 services->service_inactive(this);
138 else if (issue_stop) {
144 void service_record::release_dependencies() noexcept
146 for (auto & dependency : depends_on) {
147 service_record * dep_to = dependency.get_to();
148 if (dependency.holding_acq) {
150 dependency.holding_acq = false;
155 void service_record::start(bool activate) noexcept
157 if (activate && ! start_explicit) {
159 start_explicit = true;
162 if (desired_state == service_state_t::STARTED && service_state != service_state_t::STOPPED) return;
164 bool was_active = service_state != service_state_t::STOPPED || desired_state != service_state_t::STOPPED;
165 desired_state = service_state_t::STARTED;
167 if (service_state != service_state_t::STOPPED) {
168 // We're already starting/started, or we are stopping and need to wait for
169 // that the complete.
170 if (service_state != service_state_t::STOPPING || ! can_interrupt_stop()) {
173 // We're STOPPING, and that can be interrupted. Our dependencies might be STOPPING,
174 // but if so they are waiting (for us), so they too can be instantly returned to
176 notify_listeners(service_event_t::STOPCANCELLED);
178 else if (! was_active) {
179 services->service_active(this);
182 service_state = service_state_t::STARTING;
183 waiting_for_deps = true;
185 if (start_check_dependencies()) {
186 services->add_transition_queue(this);
190 void service_record::do_propagation() noexcept
193 // Need to require all our dependencies
194 for (auto & dep : depends_on) {
195 dep.get_to()->require();
196 dep.holding_acq = true;
198 prop_require = false;
202 release_dependencies();
203 prop_release = false;
207 prop_failure = false;
208 failed_to_start(true);
222 void service_record::execute_transition() noexcept
224 // state is STARTED with restarting set true if we are running a smooth recovery.
225 if (service_state == service_state_t::STARTING || (service_state == service_state_t::STARTED
227 if (check_deps_started()) {
231 else if (service_state == service_state_t::STOPPING) {
232 if (stop_check_dependents()) {
233 waiting_for_deps = false;
239 void service_record::do_start() noexcept
241 if (pinned_stopped) return;
243 if (service_state != service_state_t::STARTING) {
247 service_state = service_state_t::STARTING;
249 waiting_for_deps = true;
251 // Ask dependencies to start, mark them as being waited on.
252 if (check_deps_started()) {
253 // Once all dependencies are started, we start properly:
258 void service_record::dependency_started() noexcept
260 // Note that we check for STARTED state here in case the service is in smooth recovery while pinned.
261 // In that case it will wait for dependencies to start before restarting the process.
262 if ((service_state == service_state_t::STARTING || service_state == service_state_t::STARTED)
263 && waiting_for_deps) {
264 services->add_transition_queue(this);
268 bool service_record::start_check_dependencies() noexcept
270 bool all_deps_started = true;
272 for (auto & dep : depends_on) {
273 service_record * to = dep.get_to();
274 if (to->service_state != service_state_t::STARTED) {
275 if (to->service_state != service_state_t::STARTING) {
276 to->prop_start = true;
277 services->add_prop_queue(to);
279 dep.waiting_on = true;
280 all_deps_started = false;
284 return all_deps_started;
287 bool service_record::check_deps_started() noexcept
289 for (auto & dep : depends_on) {
290 if (dep.waiting_on) {
298 void service_record::all_deps_started() noexcept
300 if (onstart_flags.starts_on_console && ! have_console) {
305 waiting_for_deps = false;
307 if (! can_proceed_to_start()) {
308 waiting_for_deps = true;
312 bool start_success = bring_up();
313 if (! start_success) {
318 void service_record::acquired_console() noexcept
320 waiting_for_console = false;
323 if (service_state != service_state_t::STARTING) {
324 // We got the console but no longer want it.
327 else if (check_deps_started()) {
331 // We got the console but can't use it yet.
336 void service_record::started() noexcept
338 // If we start on console but don't keep it, release it now:
339 if (have_console && ! onstart_flags.runs_on_console) {
340 bp_sys::tcsetpgrp(0, bp_sys::getpgrp());
344 log_service_started(get_name());
345 service_state = service_state_t::STARTED;
346 notify_listeners(service_event_t::STARTED);
348 if (onstart_flags.rw_ready) {
349 open_control_socket();
351 if (onstart_flags.log_ready) {
352 setup_external_log();
355 if (force_stop || desired_state == service_state_t::STOPPED) {
361 // Notify any dependents whose desired state is STARTED:
362 for (auto dept : dependents) {
363 dept->get_from()->dependency_started();
364 dept->waiting_on = false;
368 void service_record::failed_to_start(bool depfailed) noexcept
371 bp_sys::tcsetpgrp(0, bp_sys::getpgrp());
374 if (waiting_for_console) {
375 services->unqueue_console(this);
376 waiting_for_console = false;
379 log_service_failed(get_name());
380 service_state = service_state_t::STOPPED;
381 if (start_explicit) {
382 start_explicit = false;
385 notify_listeners(service_event_t::FAILEDSTART);
387 // Cancel start of dependents:
388 for (auto & dept : dependents) {
389 switch (dept->dep_type) {
390 case dependency_type::REGULAR:
391 case dependency_type::MILESTONE:
392 if (dept->get_from()->service_state == service_state_t::STARTING) {
393 dept->get_from()->prop_failure = true;
394 services->add_prop_queue(dept->get_from());
397 case dependency_type::WAITS_FOR:
398 case dependency_type::SOFT:
399 if (dept->waiting_on) {
400 dept->waiting_on = false;
401 dept->get_from()->dependency_started();
403 if (dept->holding_acq) {
404 dept->holding_acq = false;
411 bool service_record::bring_up() noexcept
413 // default implementation: there is no process, so we are started.
418 // Mark this and all dependent services as force-stopped.
419 void service_record::forced_stop() noexcept
421 if (service_state != service_state_t::STOPPED) {
423 if (! pinned_started) {
425 services->add_transition_queue(this);
430 void service_record::dependent_stopped() noexcept
432 if (service_state == service_state_t::STOPPING && waiting_for_deps) {
433 services->add_transition_queue(this);
437 void service_record::stop(bool bring_down) noexcept
439 if (start_explicit) {
440 start_explicit = false;
449 void service_record::do_stop() noexcept
451 // A service that does actually stop for any reason should have its explicit activation released, unless
453 if (start_explicit && ! do_auto_restart()) {
454 start_explicit = false;
458 bool all_deps_stopped = stop_dependents();
460 if (service_state != service_state_t::STARTED) {
461 if (service_state == service_state_t::STARTING) {
462 // If waiting for a dependency, or waiting for the console, we can interrupt start. Otherwise,
463 // we need to delegate to can_interrupt_start() (which can be overridden).
464 if (! waiting_for_deps && ! waiting_for_console) {
465 if (! can_interrupt_start()) {
466 // Well this is awkward: we're going to have to continue starting. We can stop once we've
467 // reached the started state.
471 if (! interrupt_start()) {
472 // Now wait for service startup to actually end; we don't need to handle it here.
473 notify_listeners(service_event_t::STARTCANCELLED);
477 else if (waiting_for_console) {
478 services->unqueue_console(this);
479 waiting_for_console = false;
482 // We must have had desired_state == STARTED.
483 notify_listeners(service_event_t::STARTCANCELLED);
485 // Reaching this point, we are starting interruptibly - so we
486 // stop now (by falling through to below).
489 // If we're starting we need to wait for that to complete.
490 // If we're already stopping/stopped there's nothing to do.
495 if (pinned_started) return;
497 service_state = service_state_t::STOPPING;
498 waiting_for_deps = true;
499 if (all_deps_stopped) {
500 services->add_transition_queue(this);
504 bool service_record::stop_check_dependents() noexcept
506 bool all_deps_stopped = true;
507 for (auto dept : dependents) {
508 if (dept->dep_type == dependency_type::REGULAR && ! dept->get_from()->is_stopped()) {
509 all_deps_stopped = false;
514 return all_deps_stopped;
517 bool service_record::stop_dependents() noexcept
519 bool all_deps_stopped = true;
520 for (auto dept : dependents) {
521 if (dept->dep_type == dependency_type::REGULAR ||
522 (dept->dep_type == dependency_type::MILESTONE &&
523 dept->get_from()->service_state != service_state_t::STARTED)) {
524 if (! dept->get_from()->is_stopped()) {
525 // Note we check *first* since if the dependent service is not stopped,
526 // 1. We will issue a stop to it shortly and
527 // 2. It will notify us when stopped, at which point the stop_check_dependents()
528 // check is run anyway.
529 all_deps_stopped = false;
533 // If this service is to be forcefully stopped, dependents must also be.
534 dept->get_from()->forced_stop();
537 dept->get_from()->prop_stop = true;
538 services->add_prop_queue(dept->get_from());
541 // waits-for or soft dependency:
542 if (dept->waiting_on) {
543 dept->waiting_on = false;
544 dept->get_from()->dependency_started();
546 if (dept->holding_acq) {
547 dept->holding_acq = false;
553 return all_deps_stopped;
556 // All dependents have stopped; we can stop now, too. Only called when STOPPING.
557 void service_record::bring_down() noexcept
559 waiting_for_deps = false;
563 void service_record::unpin() noexcept
565 if (pinned_started) {
566 pinned_started = false;
567 if (desired_state == service_state_t::STOPPED || force_stop) {
569 services->process_queues();
572 if (pinned_stopped) {
573 pinned_stopped = false;
574 if (desired_state == service_state_t::STARTED) {
576 services->process_queues();
581 void service_record::queue_for_console() noexcept
583 waiting_for_console = true;
584 services->append_console_queue(this);
587 void service_record::release_console() noexcept
589 have_console = false;
590 services->pull_console_queue();
593 bool service_record::interrupt_start() noexcept
595 if (onstart_flags.starts_on_console) {
596 services->unqueue_console(this);
601 void service_set::service_active(service_record *sr) noexcept
606 void service_set::service_inactive(service_record *sr) noexcept