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 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 // If we were explicitly started, our required_by count must be at least 1. Use
93 // release() to correctly release, mark inactive and release dependencies.
94 start_explicit = false;
97 else if (required_by == 0) {
98 // This can only be the case if we didn't have start_explicit, since required_by would
99 // otherwise by non-zero.
100 prop_release = !prop_require;
101 prop_require = false;
102 services->add_prop_queue(this);
103 services->service_inactive(this);
107 // Start failure will have been logged already, only log if we are stopped for other reasons:
108 if (! start_failed) {
109 log_service_stopped(service_name);
111 notify_listeners(service_event_t::STOPPED);
114 bool service_record::do_auto_restart() noexcept
117 return services->get_auto_restart();
122 void service_record::require() noexcept
124 if (required_by++ == 0) {
125 prop_require = !prop_release;
126 prop_release = false;
127 services->add_prop_queue(this);
128 if (service_state != service_state_t::STARTING && service_state != service_state_t::STARTED) {
134 void service_record::release(bool issue_stop) noexcept
136 if (--required_by == 0) {
137 desired_state = service_state_t::STOPPED;
139 // Can stop, and can release dependencies now. We don't need to issue a release if
140 // the require was pending though:
141 prop_release = !prop_require;
142 prop_require = false;
143 services->add_prop_queue(this);
145 if (service_state == service_state_t::STOPPED) {
146 services->service_inactive(this);
148 else if (issue_stop) {
149 stop_reason = stopped_reason_t::NORMAL;
155 void service_record::release_dependencies() noexcept
157 for (auto & dependency : depends_on) {
158 service_record * dep_to = dependency.get_to();
159 if (dependency.holding_acq) {
160 // We must clear holding_acq before calling release, otherwise the dependency
161 // may decide to stop, check this link and release itself a second time.
162 dependency.holding_acq = false;
168 void service_record::start(bool activate) noexcept
170 if (activate && ! start_explicit) {
172 start_explicit = true;
175 if (desired_state == service_state_t::STARTED && service_state != service_state_t::STOPPED) return;
177 bool was_active = service_state != service_state_t::STOPPED || desired_state != service_state_t::STOPPED;
178 desired_state = service_state_t::STARTED;
180 if (service_state != service_state_t::STOPPED) {
181 // We're already starting/started, or we are stopping and need to wait for
182 // that the complete.
183 if (service_state != service_state_t::STOPPING || ! can_interrupt_stop()) {
186 // We're STOPPING, and that can be interrupted. Our dependencies might be STOPPING,
187 // but if so they are waiting (for us), so they too can be instantly returned to
189 notify_listeners(service_event_t::STOPCANCELLED);
191 else if (! was_active) {
192 services->service_active(this);
195 start_failed = false;
196 start_skipped = false;
197 service_state = service_state_t::STARTING;
198 waiting_for_deps = true;
200 if (start_check_dependencies()) {
201 services->add_transition_queue(this);
205 void service_record::do_propagation() noexcept
208 // Need to require all our dependencies
209 for (auto & dep : depends_on) {
210 dep.get_to()->require();
211 dep.holding_acq = true;
213 prop_require = false;
217 release_dependencies();
218 prop_release = false;
222 prop_failure = false;
223 stop_reason = stopped_reason_t::DEPFAILED;
224 failed_to_start(true);
238 void service_record::execute_transition() noexcept
240 // state is STARTED with restarting set true if we are running a smooth recovery.
241 if (service_state == service_state_t::STARTING || (service_state == service_state_t::STARTED
243 if (check_deps_started()) {
247 else if (service_state == service_state_t::STOPPING) {
248 if (stop_check_dependents()) {
249 waiting_for_deps = false;
255 void service_record::do_start() noexcept
257 if (pinned_stopped) return;
259 if (service_state != service_state_t::STARTING) {
263 service_state = service_state_t::STARTING;
265 waiting_for_deps = true;
267 // Ask dependencies to start, mark them as being waited on.
268 if (check_deps_started()) {
269 // Once all dependencies are started, we start properly:
274 void service_record::dependency_started() noexcept
276 // Note that we check for STARTED state here in case the service is in smooth recovery while pinned.
277 // In that case it will wait for dependencies to start before restarting the process.
278 if ((service_state == service_state_t::STARTING || service_state == service_state_t::STARTED)
279 && waiting_for_deps) {
280 services->add_transition_queue(this);
284 bool service_record::start_check_dependencies() noexcept
286 bool all_deps_started = true;
288 for (auto & dep : depends_on) {
289 service_record * to = dep.get_to();
290 if (to->service_state != service_state_t::STARTED) {
291 if (to->service_state != service_state_t::STARTING) {
292 to->prop_start = true;
293 services->add_prop_queue(to);
295 dep.waiting_on = true;
296 all_deps_started = false;
300 return all_deps_started;
303 bool service_record::check_deps_started() noexcept
305 for (auto & dep : depends_on) {
306 if (dep.waiting_on) {
314 void service_record::all_deps_started() noexcept
316 if (onstart_flags.starts_on_console && ! have_console) {
321 waiting_for_deps = false;
323 if (! can_proceed_to_start()) {
324 waiting_for_deps = true;
328 bool start_success = bring_up();
329 if (! start_success) {
334 void service_record::acquired_console() noexcept
336 waiting_for_console = false;
339 if (service_state != service_state_t::STARTING) {
340 // We got the console but no longer want it.
343 else if (check_deps_started()) {
347 // We got the console but can't use it yet.
352 void service_record::started() noexcept
354 // If we start on console but don't keep it, release it now:
355 if (have_console && ! onstart_flags.runs_on_console) {
356 bp_sys::tcsetpgrp(0, bp_sys::getpgrp());
360 log_service_started(get_name());
361 service_state = service_state_t::STARTED;
362 notify_listeners(service_event_t::STARTED);
364 if (onstart_flags.rw_ready) {
365 open_control_socket();
367 if (onstart_flags.log_ready) {
368 setup_external_log();
371 if (force_stop || desired_state == service_state_t::STOPPED) {
377 // Notify any dependents whose desired state is STARTED:
378 for (auto dept : dependents) {
379 dept->get_from()->dependency_started();
380 dept->waiting_on = false;
384 void service_record::failed_to_start(bool depfailed, bool immediate_stop) noexcept
386 if (waiting_for_console) {
387 services->unqueue_console(this);
388 waiting_for_console = false;
391 if (start_explicit) {
392 start_explicit = false;
396 // Cancel start of dependents:
397 for (auto & dept : dependents) {
398 switch (dept->dep_type) {
399 case dependency_type::REGULAR:
400 case dependency_type::MILESTONE:
401 if (dept->get_from()->service_state == service_state_t::STARTING) {
402 dept->get_from()->prop_failure = true;
403 services->add_prop_queue(dept->get_from());
406 case dependency_type::WAITS_FOR:
407 case dependency_type::SOFT:
408 if (dept->waiting_on) {
409 dept->waiting_on = false;
410 dept->get_from()->dependency_started();
414 // Always release now, so that our desired state will be STOPPED before we call
415 // stopped() below (if we do so). Otherwise it may decide to restart us.
416 if (dept->holding_acq) {
417 dept->holding_acq = false;
423 log_service_failed(get_name());
424 notify_listeners(service_event_t::FAILEDSTART);
426 if (immediate_stop) {
431 bool service_record::bring_up() noexcept
433 // default implementation: there is no process, so we are started.
438 // Mark this and all dependent services as force-stopped.
439 void service_record::forced_stop() noexcept
441 if (service_state != service_state_t::STOPPED) {
443 if (! pinned_started) {
445 services->add_transition_queue(this);
450 void service_record::dependent_stopped() noexcept
452 if (service_state == service_state_t::STOPPING && waiting_for_deps) {
453 services->add_transition_queue(this);
457 void service_record::stop(bool bring_down) noexcept
459 if (start_explicit) {
460 start_explicit = false;
464 if (bring_down && service_state != service_state_t::STOPPED
465 && service_state != service_state_t::STOPPING) {
466 stop_reason = stopped_reason_t::NORMAL;
471 void service_record::do_stop() noexcept
473 // A service that does actually stop for any reason should have its explicit activation released, unless
475 if (start_explicit && ! do_auto_restart()) {
476 start_explicit = false;
480 bool all_deps_stopped = stop_dependents();
482 if (service_state != service_state_t::STARTED) {
483 if (service_state == service_state_t::STARTING) {
484 // If waiting for a dependency, or waiting for the console, we can interrupt start. Otherwise,
485 // we need to delegate to can_interrupt_start() (which can be overridden).
486 if (! waiting_for_deps && ! waiting_for_console) {
487 if (! can_interrupt_start()) {
488 // Well this is awkward: we're going to have to continue starting. We can stop once
489 // we've reached the started state.
493 if (! interrupt_start()) {
494 // Now wait for service startup to actually end; we don't need to handle it here.
495 notify_listeners(service_event_t::STARTCANCELLED);
499 else if (waiting_for_console) {
500 services->unqueue_console(this);
501 waiting_for_console = false;
504 // We must have had desired_state == STARTED.
505 notify_listeners(service_event_t::STARTCANCELLED);
507 // Reaching this point, we are starting interruptibly - so we
508 // stop now (by falling through to below).
511 // If we're starting we need to wait for that to complete.
512 // If we're already stopping/stopped there's nothing to do.
517 if (pinned_started) return;
519 service_state = service_state_t::STOPPING;
520 waiting_for_deps = true;
521 if (all_deps_stopped) {
522 services->add_transition_queue(this);
526 bool service_record::stop_check_dependents() noexcept
528 bool all_deps_stopped = true;
529 for (auto dept : dependents) {
530 if (dept->dep_type == dependency_type::REGULAR && ! dept->get_from()->is_stopped()) {
531 all_deps_stopped = false;
536 return all_deps_stopped;
539 bool service_record::stop_dependents() noexcept
541 bool all_deps_stopped = true;
542 for (auto dept : dependents) {
543 if (dept->dep_type == dependency_type::REGULAR ||
544 (dept->dep_type == dependency_type::MILESTONE &&
545 dept->get_from()->service_state != service_state_t::STARTED)) {
546 if (! dept->get_from()->is_stopped()) {
547 // Note we check *first* since if the dependent service is not stopped,
548 // 1. We will issue a stop to it shortly and
549 // 2. It will notify us when stopped, at which point the stop_check_dependents()
550 // check is run anyway.
551 all_deps_stopped = false;
555 // If this service is to be forcefully stopped, dependents must also be.
556 dept->get_from()->forced_stop();
559 dept->get_from()->prop_stop = true;
560 services->add_prop_queue(dept->get_from());
563 // waits-for or soft dependency:
564 if (dept->waiting_on) {
565 dept->waiting_on = false;
566 dept->get_from()->dependency_started();
568 if (dept->holding_acq) {
569 dept->holding_acq = false;
570 // release without issuing stop, since we should be called only when this
571 // service is already stopped/stopping:
577 return all_deps_stopped;
580 // All dependents have stopped; we can stop now, too. Only called when STOPPING.
581 void service_record::bring_down() noexcept
583 waiting_for_deps = false;
587 void service_record::unpin() noexcept
589 if (pinned_started) {
590 pinned_started = false;
591 if (desired_state == service_state_t::STOPPED || force_stop) {
593 services->process_queues();
596 if (pinned_stopped) {
597 pinned_stopped = false;
598 if (desired_state == service_state_t::STARTED) {
600 services->process_queues();
605 void service_record::queue_for_console() noexcept
607 waiting_for_console = true;
608 services->append_console_queue(this);
611 void service_record::release_console() noexcept
613 have_console = false;
614 services->pull_console_queue();
617 bool service_record::interrupt_start() noexcept
622 void service_set::service_active(service_record *sr) noexcept
627 void service_set::service_inactive(service_record *sr) noexcept