Re-work state propogation/transition logic.
[oweals/dinit.git] / src / service.cc
1 #include <cstring>
2 #include <cerrno>
3 #include <iterator>
4 #include <memory>
5 #include <cstddef>
6
7 #include <sys/ioctl.h>
8 #include <fcntl.h>
9 #include <termios.h>
10
11 #include "dinit.h"
12 #include "service.h"
13 #include "dinit-log.h"
14 #include "dinit-socket.h"
15 #include "dinit-util.h"
16 #include "baseproc-sys.h"
17
18 /*
19  * service.cc - Service management.
20  * See service.h for details.
21  */
22
23 // Find the requested service by name
24 static service_record * find_service(const std::list<service_record *> & records,
25                                     const char *name) noexcept
26 {
27     using std::list;
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) {
31             return *i;
32         }
33     }
34     return nullptr;
35 }
36
37 service_record * service_set::find_service(const std::string &name) noexcept
38 {
39     return ::find_service(records, name.c_str());
40 }
41
42 // Called when a service has actually stopped; dependents have stopped already, unless this stop
43 // is due to an unexpected process termination.
44 void service_record::stopped() noexcept
45 {
46     if (have_console) {
47         bp_sys::tcsetpgrp(0, bp_sys::getpgrp());
48         release_console();
49     }
50
51     force_stop = false;
52
53     restarting |= auto_restart;
54     bool will_restart = restarting && required_by > 0;
55     restarting = false;
56
57     // If we won't restart, break soft dependencies now
58     if (! will_restart) {
59         for (auto dept : dependents) {
60             if (! dept->is_hard()) {
61                 // waits-for or soft dependency:
62                 if (dept->waiting_on) {
63                     dept->waiting_on = false;
64                     dept->get_from()->dependency_started();
65                 }
66                 if (dept->holding_acq) {
67                     dept->holding_acq = false;
68                     // release without issuing stop, since we're called only when this
69                     // service is already stopped/stopping:
70                     release(false);
71                 }
72             }
73         }
74     }
75
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();
79     }
80
81     service_state = service_state_t::STOPPED;
82
83     if (will_restart) {
84         // Desired state is "started".
85         restarting = true;
86         start(false);
87     }
88     else {
89         becoming_inactive();
90         
91         if (start_explicit) {
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;
95             release();
96         }
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);
104         }
105     }
106
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);
110
111         // If this service chains to another, start the other service now:
112         if (! will_restart && ! start_on_completion.empty()) {
113             try {
114                 auto chain_to = services->load_service(start_on_completion.c_str());
115                 chain_to->start();
116             }
117             catch (service_load_exc &sle) {
118                 log(loglevel_t::ERROR, "Couldn't chain to service ", start_on_completion, ": ",
119                         "couldn't load ", sle.service_name, ": ", sle.exc_description);
120             }
121             catch (std::bad_alloc &bae) {
122                 log(loglevel_t::ERROR, "Couldn't chain to service ", start_on_completion,
123                         ": Out of memory");
124             }
125         }
126     }
127     notify_listeners(service_event_t::STOPPED);
128 }
129
130 void service_record::require() noexcept
131 {
132     if (required_by++ == 0) {
133         prop_require = !prop_release;
134         prop_release = false;
135         services->add_prop_queue(this);
136         if (service_state != service_state_t::STARTING && service_state != service_state_t::STARTED) {
137             prop_start = true;
138         }
139     }
140 }
141
142 void service_record::release(bool issue_stop) noexcept
143 {
144     if (--required_by == 0) {
145         desired_state = service_state_t::STOPPED;
146
147         // Can stop, and can release dependencies now. We don't need to issue a release if
148         // the require was pending though:
149         if (service_state != service_state_t::STOPPED && service_state != service_state_t::STOPPING) {
150             prop_release = !prop_require;
151             prop_require = false;
152             services->add_prop_queue(this);
153         }
154
155         if (service_state == service_state_t::STOPPED) {
156             services->service_inactive(this);
157         }
158         else if (issue_stop) {
159                 stop_reason = stopped_reason_t::NORMAL;
160             do_stop();
161         }
162     }
163 }
164
165 void service_record::release_dependencies() noexcept
166 {
167     for (auto & dependency : depends_on) {
168         service_record * dep_to = dependency.get_to();
169         if (dependency.holding_acq) {
170             // We must clear holding_acq before calling release, otherwise the dependency
171             // may decide to stop, check this link and release itself a second time.
172             dependency.holding_acq = false;
173             dep_to->release();
174         }
175     }
176 }
177
178 void service_record::start(bool activate) noexcept
179 {
180     if (activate && ! start_explicit) {
181         require();
182         start_explicit = true;
183     }
184
185     bool was_active = service_state != service_state_t::STOPPED || desired_state != service_state_t::STOPPED;
186     desired_state = service_state_t::STARTED;
187     
188     if (service_state != service_state_t::STOPPED) {
189         // We're already starting/started, or we are stopping and need to wait for
190         // that the complete.
191         if (service_state != service_state_t::STOPPING) {
192             return;
193         }
194
195         if (! can_interrupt_stop()) {
196             restarting = true;
197             return;
198         }
199
200         // We're STOPPING, and that can be interrupted. Our dependencies might be STOPPING,
201         // but if so they are waiting (for us), so they too can be instantly returned to
202         // STARTING state.
203         notify_listeners(service_event_t::STOPCANCELLED);
204     }
205     else if (! was_active) {
206         services->service_active(this);
207     }
208
209     start_failed = false;
210     start_skipped = false;
211     service_state = service_state_t::STARTING;
212     waiting_for_deps = true;
213
214     if (start_check_dependencies()) {
215         services->add_transition_queue(this);
216     }
217 }
218
219 void service_record::do_propagation() noexcept
220 {
221     if (prop_require) {
222         // Need to require all our dependencies
223         for (auto & dep : depends_on) {
224             dep.get_to()->require();
225             dep.holding_acq = true;
226         }
227         prop_require = false;
228     }
229     
230     if (prop_release) {
231         release_dependencies();
232         prop_release = false;
233     }
234     
235     if (prop_failure) {
236         prop_failure = false;
237         stop_reason = stopped_reason_t::DEPFAILED;
238         failed_to_start(true);
239     }
240     
241     if (prop_start) {
242         prop_start = false;
243         start(false);
244     }
245
246     if (prop_stop) {
247         prop_stop = false;
248         do_stop();
249     }
250 }
251
252 void service_record::execute_transition() noexcept
253 {
254     // state is STARTED with restarting set true if we are running a smooth recovery.
255     if (service_state == service_state_t::STARTING || (service_state == service_state_t::STARTED
256             && restarting)) {
257         if (check_deps_started()) {
258             all_deps_started();
259         }
260     }
261     else if (service_state == service_state_t::STOPPING) {
262         if (stop_check_dependents()) {
263             waiting_for_deps = false;
264
265             // A service that does actually stop for any reason should have its explicit activation released, unless
266             // it will restart:
267             if (start_explicit && !auto_restart && !restarting) {
268                 start_explicit = false;
269                 release(false);
270             }
271
272             bring_down();
273         }
274     }
275 }
276
277 void service_record::do_start() noexcept
278 {
279     if (pinned_stopped) return;
280     
281     if (service_state != service_state_t::STARTING) {
282         return;
283     }
284     
285     service_state = service_state_t::STARTING;
286
287     waiting_for_deps = true;
288
289     // Ask dependencies to start, mark them as being waited on.
290     if (check_deps_started()) {
291         // Once all dependencies are started, we start properly:
292         all_deps_started();
293     }
294 }
295
296 void service_record::dependency_started() noexcept
297 {
298     // Note that we check for STARTED state here in case the service is in smooth recovery while pinned.
299     // In that case it will wait for dependencies to start before restarting the process.
300     if ((service_state == service_state_t::STARTING || service_state == service_state_t::STARTED)
301             && waiting_for_deps) {
302         services->add_transition_queue(this);
303     }
304 }
305
306 bool service_record::start_check_dependencies() noexcept
307 {
308     bool all_deps_started = true;
309
310     for (auto & dep : depends_on) {
311         service_record * to = dep.get_to();
312         if (to->service_state != service_state_t::STARTED) {
313             if (to->service_state != service_state_t::STARTING) {
314                 to->prop_start = true;
315                 services->add_prop_queue(to);
316             }
317             dep.waiting_on = true;
318             all_deps_started = false;
319         }
320     }
321     
322     return all_deps_started;
323 }
324
325 bool service_record::check_deps_started() noexcept
326 {
327     for (auto & dep : depends_on) {
328         if (dep.waiting_on) {
329             return false;
330         }
331     }
332
333     return true;
334 }
335
336 void service_record::all_deps_started() noexcept
337 {
338     if (onstart_flags.starts_on_console && ! have_console) {
339         queue_for_console();
340         return;
341     }
342     
343     waiting_for_deps = false;
344
345     if (! can_proceed_to_start()) {
346         waiting_for_deps = true;
347         return;
348     }
349
350     bool start_success = bring_up();
351     restarting = false;
352     if (! start_success) {
353         failed_to_start();
354     }
355 }
356
357 void service_record::acquired_console() noexcept
358 {
359     waiting_for_console = false;
360     have_console = true;
361
362     if (service_state != service_state_t::STARTING) {
363         // We got the console but no longer want it.
364         release_console();
365     }
366     else if (check_deps_started()) {
367         all_deps_started();
368     }
369     else {
370         // We got the console but can't use it yet.
371         release_console();
372     }
373 }
374
375 void service_record::started() noexcept
376 {
377     // If we start on console but don't keep it, release it now:
378     if (have_console && ! onstart_flags.runs_on_console) {
379         bp_sys::tcsetpgrp(0, bp_sys::getpgrp());
380         release_console();
381     }
382
383     log_service_started(get_name());
384     service_state = service_state_t::STARTED;
385     notify_listeners(service_event_t::STARTED);
386
387     if (onstart_flags.rw_ready) {
388         rootfs_is_rw();
389     }
390     if (onstart_flags.log_ready) {
391         setup_external_log();
392     }
393
394     if (force_stop || desired_state == service_state_t::STOPPED) {
395         // We must now stop.
396         do_stop();
397         return;
398     }
399
400     // Notify any dependents whose desired state is STARTED:
401     for (auto dept : dependents) {
402         dept->get_from()->dependency_started();
403         dept->waiting_on = false;
404     }
405 }
406
407 void service_record::failed_to_start(bool depfailed, bool immediate_stop) noexcept
408 {
409     if (waiting_for_console) {
410         services->unqueue_console(this);
411         waiting_for_console = false;
412     }
413
414     if (start_explicit) {
415         start_explicit = false;
416         release(false);
417     }
418
419     // Cancel start of dependents:
420     for (auto & dept : dependents) {
421         switch (dept->dep_type) {
422         case dependency_type::REGULAR:
423         case dependency_type::MILESTONE:
424             if (dept->get_from()->service_state == service_state_t::STARTING) {
425                 dept->get_from()->prop_failure = true;
426                 services->add_prop_queue(dept->get_from());
427             }
428             break;
429         case dependency_type::WAITS_FOR:
430         case dependency_type::SOFT:
431             if (dept->waiting_on) {
432                 dept->waiting_on = false;
433                 dept->get_from()->dependency_started();
434             }
435         }
436
437         // Always release now, so that our desired state will be STOPPED before we call
438         // stopped() below (if we do so). Otherwise it may decide to restart us.
439         if (dept->holding_acq) {
440             dept->holding_acq = false;
441             release(false);
442         }
443     }
444
445     start_failed = true;
446     log_service_failed(get_name());
447     notify_listeners(service_event_t::FAILEDSTART);
448
449     if (immediate_stop) {
450         stopped();
451     }
452 }
453
454 bool service_record::bring_up() noexcept
455 {
456     // default implementation: there is no process, so we are started.
457     started();
458     return true;
459 }
460
461 // Mark this and all dependent services as force-stopped.
462 void service_record::forced_stop() noexcept
463 {
464     if (service_state != service_state_t::STOPPED) {
465         force_stop = true;
466         if (! pinned_started) {
467             prop_stop = true;
468             services->add_prop_queue(this);
469         }
470     }
471 }
472
473 void service_record::dependent_stopped() noexcept
474 {
475     if (service_state == service_state_t::STOPPING && waiting_for_deps) {
476         services->add_transition_queue(this);
477     }
478 }
479
480 void service_record::stop(bool bring_down) noexcept
481 {
482     if (start_explicit) {
483         start_explicit = false;
484         required_by--;
485     }
486
487     // If our required_by count is 0, we should treat this as a full manual stop regardless
488     if (required_by == 0) {
489         bring_down = true;
490     }
491
492     if (bring_down && service_state != service_state_t::STOPPED
493                 && service_state != service_state_t::STOPPING) {
494         stop_reason = stopped_reason_t::NORMAL;
495         do_stop();
496     }
497 }
498
499 void service_record::restart() noexcept
500 {
501     // Re-start without affecting dependency links/activation.
502
503     if (service_state == service_state_t::STARTED) {
504         restarting = true;
505         stop_reason = stopped_reason_t::NORMAL;
506         do_stop();
507     }
508 }
509
510 void service_record::do_stop() noexcept
511 {
512     // Called when we should definitely stop. We may need to restart afterwards, but we
513     // won't know that for sure until the execution transition.
514
515     bool all_deps_stopped = stop_dependents();
516
517     if (service_state != service_state_t::STARTED) {
518         if (service_state == service_state_t::STARTING) {
519             // If waiting for a dependency, or waiting for the console, we can interrupt start. Otherwise,
520             // we need to delegate to can_interrupt_start() (which can be overridden).
521             if (! waiting_for_deps && ! waiting_for_console) {
522                 if (! can_interrupt_start()) {
523                     // Well this is awkward: we're going to have to continue starting. We can stop once
524                     // we've reached the started state.
525                     return;
526                 }
527
528                 if (! interrupt_start()) {
529                     // Now wait for service startup to actually end; we don't need to handle it here.
530                     notify_listeners(service_event_t::STARTCANCELLED);
531                     return;
532                 }
533             }
534             else if (waiting_for_console) {
535                 services->unqueue_console(this);
536                 waiting_for_console = false;
537             }
538
539             // We must have had desired_state == STARTED.
540             notify_listeners(service_event_t::STARTCANCELLED);
541
542             // Reaching this point, we are starting interruptibly - so we
543             // stop now (by falling through to below).
544         }
545         else {
546             // If we're starting we need to wait for that to complete.
547             // If we're already stopping/stopped there's nothing to do.
548             return;
549         }
550     }
551
552     if (pinned_started) return;
553
554     if (required_by == 0) {
555         prop_release = true;
556         services->add_prop_queue(this);
557     }
558
559     service_state = service_state_t::STOPPING;
560     waiting_for_deps = true;
561     if (all_deps_stopped) {
562         services->add_transition_queue(this);
563     }
564 }
565
566 bool service_record::stop_check_dependents() noexcept
567 {
568     bool all_deps_stopped = true;
569     for (auto dept : dependents) {
570         if (dept->is_hard() && dept->holding_acq) {
571             all_deps_stopped = false;
572             break;
573         }
574     }
575
576     return all_deps_stopped;
577 }
578
579 bool service_record::stop_dependents() noexcept
580 {
581     bool all_deps_stopped = true;
582     for (auto dept : dependents) {
583         if (dept->is_hard() && dept->holding_acq) {
584             if (! dept->get_from()->is_stopped()) {
585                 // Note we check *first* since if the dependent service is not stopped,
586                 // 1. We will issue a stop to it shortly and
587                 // 2. It will notify us when stopped, at which point the stop_check_dependents()
588                 //    check is run anyway.
589                 all_deps_stopped = false;
590             }
591
592             if (force_stop) {
593                 // If this service is to be forcefully stopped, dependents must also be.
594                 dept->get_from()->forced_stop();
595             }
596
597             dept->get_from()->prop_stop = true;
598             services->add_prop_queue(dept->get_from());
599         }
600     }
601
602     return all_deps_stopped;
603 }
604
605 // All dependents have stopped; we can stop now, too. Only called when STOPPING.
606 void service_record::bring_down() noexcept
607 {
608     waiting_for_deps = false;
609     stopped();
610 }
611
612 void service_record::unpin() noexcept
613 {
614     if (pinned_started) {
615         pinned_started = false;
616
617         for (auto &dep : depends_on) {
618             if (dep.is_hard()) {
619                 if (dep.get_to()->get_state() != service_state_t::STARTED) {
620                     desired_state = service_state_t::STOPPED;
621                 }
622             }
623             else if (dep.holding_acq) {
624                 dep.holding_acq = false;
625                 dep.get_to()->release();
626             }
627         }
628
629         if (desired_state == service_state_t::STOPPED || force_stop) {
630             do_stop();
631             services->process_queues();
632         }
633     }
634     if (pinned_stopped) {
635         pinned_stopped = false;
636         if (desired_state == service_state_t::STARTED) {
637             do_start();
638             services->process_queues();
639         }
640     }
641 }
642
643 void service_record::queue_for_console() noexcept
644 {
645     waiting_for_console = true;
646     services->append_console_queue(this);
647 }
648
649 void service_record::release_console() noexcept
650 {
651     have_console = false;
652     services->pull_console_queue();
653 }
654
655 bool service_record::interrupt_start() noexcept
656 {
657     return true;
658 }
659
660 void service_set::service_active(service_record *sr) noexcept
661 {
662     active_services++;
663 }
664
665 void service_set::service_inactive(service_record *sr) noexcept
666 {
667     active_services--;
668 }