Fix acquire/release counting in some sitations.
[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 void service_set::stop_service(const std::string & name) noexcept
43 {
44     service_record *record = find_service(name);
45     if (record != nullptr) {
46         record->stop();
47         process_queues();
48     }
49 }
50
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
54 {
55     if (have_console) {
56         bp_sys::tcsetpgrp(0, bp_sys::getpgrp());
57         discard_console_log_buffer();
58         release_console();
59     }
60
61     force_stop = false;
62
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;
68                 release();
69             }
70         }
71     }
72
73     bool will_restart = (desired_state == service_state_t::STARTED)
74             && services->get_auto_restart();
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     log_service_stopped(service_name);
108     notify_listeners(service_event_t::STOPPED);
109 }
110
111 bool service_record::do_auto_restart() noexcept
112 {
113     if (auto_restart) {
114         return services->get_auto_restart();
115     }
116     return false;
117 }
118
119 void service_record::require() noexcept
120 {
121     if (required_by++ == 0) {
122         prop_require = !prop_release;
123         prop_release = false;
124         services->add_prop_queue(this);
125         if (service_state != service_state_t::STARTING && service_state != service_state_t::STARTED) {
126             prop_start = true;
127         }
128     }
129 }
130
131 void service_record::release(bool issue_stop) noexcept
132 {
133     if (--required_by == 0) {
134         desired_state = service_state_t::STOPPED;
135
136         // Can stop, and can release dependencies now. We don't need to issue a release if
137         // the require was pending though:
138         prop_release = !prop_require;
139         prop_require = false;
140         services->add_prop_queue(this);
141
142         if (service_state == service_state_t::STOPPED) {
143             services->service_inactive(this);
144         }
145         else if (issue_stop) {
146             do_stop();
147         }
148     }
149 }
150
151 void service_record::release_dependencies() noexcept
152 {
153     for (auto & dependency : depends_on) {
154         service_record * dep_to = dependency.get_to();
155         if (dependency.holding_acq) {
156             // We must clear holding_acq before calling release, otherwise the dependency
157             // may decide to stop, check this link and release itself a second time.
158             dependency.holding_acq = false;
159             dep_to->release();
160         }
161     }
162 }
163
164 void service_record::start(bool activate) noexcept
165 {
166     if (activate && ! start_explicit) {
167         require();
168         start_explicit = true;
169     }
170     
171     if (desired_state == service_state_t::STARTED && service_state != service_state_t::STOPPED) return;
172
173     bool was_active = service_state != service_state_t::STOPPED || desired_state != service_state_t::STOPPED;
174     desired_state = service_state_t::STARTED;
175     
176     if (service_state != service_state_t::STOPPED) {
177         // We're already starting/started, or we are stopping and need to wait for
178         // that the complete.
179         if (service_state != service_state_t::STOPPING || ! can_interrupt_stop()) {
180             return;
181         }
182         // We're STOPPING, and that can be interrupted. Our dependencies might be STOPPING,
183         // but if so they are waiting (for us), so they too can be instantly returned to
184         // STARTING state.
185         notify_listeners(service_event_t::STOPCANCELLED);
186     }
187     else if (! was_active) {
188         services->service_active(this);
189     }
190
191     service_state = service_state_t::STARTING;
192     waiting_for_deps = true;
193
194     if (start_check_dependencies()) {
195         services->add_transition_queue(this);
196     }
197 }
198
199 void service_record::do_propagation() noexcept
200 {
201     if (prop_require) {
202         // Need to require all our dependencies
203         for (auto & dep : depends_on) {
204             dep.get_to()->require();
205             dep.holding_acq = true;
206         }
207         prop_require = false;
208     }
209     
210     if (prop_release) {
211         release_dependencies();
212         prop_release = false;
213     }
214     
215     if (prop_failure) {
216         prop_failure = false;
217         failed_to_start(true);
218     }
219     
220     if (prop_start) {
221         prop_start = false;
222         start(false);
223     }
224
225     if (prop_stop) {
226         prop_stop = false;
227         do_stop();
228     }
229 }
230
231 void service_record::execute_transition() noexcept
232 {
233     // state is STARTED with restarting set true if we are running a smooth recovery.
234     if (service_state == service_state_t::STARTING || (service_state == service_state_t::STARTED
235             && restarting)) {
236         if (check_deps_started()) {
237             all_deps_started();
238         }
239     }
240     else if (service_state == service_state_t::STOPPING) {
241         if (stop_check_dependents()) {
242             waiting_for_deps = false;
243             bring_down();
244         }
245     }
246 }
247
248 void service_record::do_start() noexcept
249 {
250     if (pinned_stopped) return;
251     
252     if (service_state != service_state_t::STARTING) {
253         return;
254     }
255     
256     service_state = service_state_t::STARTING;
257
258     waiting_for_deps = true;
259
260     // Ask dependencies to start, mark them as being waited on.
261     if (check_deps_started()) {
262         // Once all dependencies are started, we start properly:
263         all_deps_started();
264     }
265 }
266
267 void service_record::dependency_started() noexcept
268 {
269     // Note that we check for STARTED state here in case the service is in smooth recovery while pinned.
270     // In that case it will wait for dependencies to start before restarting the process.
271     if ((service_state == service_state_t::STARTING || service_state == service_state_t::STARTED)
272             && waiting_for_deps) {
273         services->add_transition_queue(this);
274     }
275 }
276
277 bool service_record::start_check_dependencies() noexcept
278 {
279     bool all_deps_started = true;
280
281     for (auto & dep : depends_on) {
282         service_record * to = dep.get_to();
283         if (to->service_state != service_state_t::STARTED) {
284             if (to->service_state != service_state_t::STARTING) {
285                 to->prop_start = true;
286                 services->add_prop_queue(to);
287             }
288             dep.waiting_on = true;
289             all_deps_started = false;
290         }
291     }
292     
293     return all_deps_started;
294 }
295
296 bool service_record::check_deps_started() noexcept
297 {
298     for (auto & dep : depends_on) {
299         if (dep.waiting_on) {
300             return false;
301         }
302     }
303
304     return true;
305 }
306
307 void service_record::all_deps_started() noexcept
308 {
309     if (onstart_flags.starts_on_console && ! have_console) {
310         queue_for_console();
311         return;
312     }
313     
314     waiting_for_deps = false;
315
316     if (! can_proceed_to_start()) {
317         waiting_for_deps = true;
318         return;
319     }
320
321     bool start_success = bring_up();
322     if (! start_success) {
323         failed_to_start();
324     }
325 }
326
327 void service_record::acquired_console() noexcept
328 {
329     waiting_for_console = false;
330     have_console = true;
331
332     if (service_state != service_state_t::STARTING) {
333         // We got the console but no longer want it.
334         release_console();
335     }
336     else if (check_deps_started()) {
337         all_deps_started();
338     }
339     else {
340         // We got the console but can't use it yet.
341         release_console();
342     }
343 }
344
345 void service_record::started() noexcept
346 {
347     // If we start on console but don't keep it, release it now:
348     if (have_console && ! onstart_flags.runs_on_console) {
349         bp_sys::tcsetpgrp(0, bp_sys::getpgrp());
350         release_console();
351     }
352
353     log_service_started(get_name());
354     service_state = service_state_t::STARTED;
355     notify_listeners(service_event_t::STARTED);
356
357     if (onstart_flags.rw_ready) {
358         open_control_socket();
359     }
360     if (onstart_flags.log_ready) {
361         setup_external_log();
362     }
363
364     if (force_stop || desired_state == service_state_t::STOPPED) {
365         // We must now stop.
366         do_stop();
367         return;
368     }
369
370     // Notify any dependents whose desired state is STARTED:
371     for (auto dept : dependents) {
372         dept->get_from()->dependency_started();
373         dept->waiting_on = false;
374     }
375 }
376
377 void service_record::failed_to_start(bool depfailed, bool immediate_stop) noexcept
378 {
379     if (waiting_for_console) {
380         services->unqueue_console(this);
381         waiting_for_console = false;
382     }
383
384     if (start_explicit) {
385         start_explicit = false;
386         release(false);
387     }
388
389     // Cancel start of dependents:
390     for (auto & dept : dependents) {
391         switch (dept->dep_type) {
392         case dependency_type::REGULAR:
393         case dependency_type::MILESTONE:
394             if (dept->get_from()->service_state == service_state_t::STARTING) {
395                 dept->get_from()->prop_failure = true;
396                 services->add_prop_queue(dept->get_from());
397             }
398             break;
399         case dependency_type::WAITS_FOR:
400         case dependency_type::SOFT:
401             if (dept->waiting_on) {
402                 dept->waiting_on = false;
403                 dept->get_from()->dependency_started();
404             }
405         }
406
407         // Always release now, so that our desired state will be STOPPED before we call
408         // stopped() below (if we do so). Otherwise it may decide to restart us.
409         if (dept->holding_acq) {
410             dept->holding_acq = false;
411             release(false);
412         }
413     }
414
415     log_service_failed(get_name());
416     notify_listeners(service_event_t::FAILEDSTART);
417
418     if (immediate_stop) {
419         stopped();
420     }
421 }
422
423 bool service_record::bring_up() noexcept
424 {
425     // default implementation: there is no process, so we are started.
426     started();
427     return true;
428 }
429
430 // Mark this and all dependent services as force-stopped.
431 void service_record::forced_stop() noexcept
432 {
433     if (service_state != service_state_t::STOPPED) {
434         force_stop = true;
435         if (! pinned_started) {
436             prop_stop = true;
437             services->add_transition_queue(this);
438         }
439     }
440 }
441
442 void service_record::dependent_stopped() noexcept
443 {
444     if (service_state == service_state_t::STOPPING && waiting_for_deps) {
445         services->add_transition_queue(this);
446     }
447 }
448
449 void service_record::stop(bool bring_down) noexcept
450 {
451     if (start_explicit) {
452         start_explicit = false;
453         release();
454     }
455
456     if (bring_down) {
457         do_stop();
458     }
459 }
460
461 void service_record::do_stop() noexcept
462 {
463     // A service that does actually stop for any reason should have its explicit activation released, unless
464     // it will restart:
465     if (start_explicit && ! do_auto_restart()) {
466         start_explicit = false;
467         release(false);
468     }
469
470     bool all_deps_stopped = stop_dependents();
471
472     if (service_state != service_state_t::STARTED) {
473         if (service_state == service_state_t::STARTING) {
474             // If waiting for a dependency, or waiting for the console, we can interrupt start. Otherwise,
475             // we need to delegate to can_interrupt_start() (which can be overridden).
476             if (! waiting_for_deps && ! waiting_for_console) {
477                 if (! can_interrupt_start()) {
478                     // Well this is awkward: we're going to have to continue starting. We can stop once we've
479                     // reached the started state.
480                     return;
481                 }
482
483                 if (! interrupt_start()) {
484                     // Now wait for service startup to actually end; we don't need to handle it here.
485                     notify_listeners(service_event_t::STARTCANCELLED);
486                     return;
487                 }
488             }
489             else if (waiting_for_console) {
490                 services->unqueue_console(this);
491                 waiting_for_console = false;
492             }
493
494             // We must have had desired_state == STARTED.
495             notify_listeners(service_event_t::STARTCANCELLED);
496
497             // Reaching this point, we are starting interruptibly - so we
498             // stop now (by falling through to below).
499         }
500         else {
501             // If we're starting we need to wait for that to complete.
502             // If we're already stopping/stopped there's nothing to do.
503             return;
504         }
505     }
506
507     if (pinned_started) return;
508
509     service_state = service_state_t::STOPPING;
510     waiting_for_deps = true;
511     if (all_deps_stopped) {
512         services->add_transition_queue(this);
513     }
514 }
515
516 bool service_record::stop_check_dependents() noexcept
517 {
518     bool all_deps_stopped = true;
519     for (auto dept : dependents) {
520         if (dept->dep_type == dependency_type::REGULAR && ! dept->get_from()->is_stopped()) {
521             all_deps_stopped = false;
522             break;
523         }
524     }
525     
526     return all_deps_stopped;
527 }
528
529 bool service_record::stop_dependents() noexcept
530 {
531     bool all_deps_stopped = true;
532     for (auto dept : dependents) {
533         if (dept->dep_type == dependency_type::REGULAR ||
534                 (dept->dep_type == dependency_type::MILESTONE &&
535                 dept->get_from()->service_state != service_state_t::STARTED)) {
536             if (! dept->get_from()->is_stopped()) {
537                 // Note we check *first* since if the dependent service is not stopped,
538                 // 1. We will issue a stop to it shortly and
539                 // 2. It will notify us when stopped, at which point the stop_check_dependents()
540                 //    check is run anyway.
541                 all_deps_stopped = false;
542             }
543
544             if (force_stop) {
545                 // If this service is to be forcefully stopped, dependents must also be.
546                 dept->get_from()->forced_stop();
547             }
548
549             dept->get_from()->prop_stop = true;
550             services->add_prop_queue(dept->get_from());
551         }
552         else {
553             // waits-for or soft dependency:
554             if (dept->waiting_on) {
555                 dept->waiting_on = false;
556                 dept->get_from()->dependency_started();
557             }
558             if (dept->holding_acq) {
559                 dept->holding_acq = false;
560                 release();
561             }
562         }
563     }
564
565     return all_deps_stopped;
566 }
567
568 // All dependents have stopped; we can stop now, too. Only called when STOPPING.
569 void service_record::bring_down() noexcept
570 {
571     waiting_for_deps = false;
572     stopped();
573 }
574
575 void service_record::unpin() noexcept
576 {
577     if (pinned_started) {
578         pinned_started = false;
579         if (desired_state == service_state_t::STOPPED || force_stop) {
580             do_stop();
581             services->process_queues();
582         }
583     }
584     if (pinned_stopped) {
585         pinned_stopped = false;
586         if (desired_state == service_state_t::STARTED) {
587             do_start();
588             services->process_queues();
589         }
590     }
591 }
592
593 void service_record::queue_for_console() noexcept
594 {
595     waiting_for_console = true;
596     services->append_console_queue(this);
597 }
598
599 void service_record::release_console() noexcept
600 {
601     have_console = false;
602     services->pull_console_queue();
603 }
604
605 bool service_record::interrupt_start() noexcept
606 {
607     return true;
608 }
609
610 void service_set::service_active(service_record *sr) noexcept
611 {
612     active_services++;
613 }
614
615 void service_set::service_inactive(service_record *sr) noexcept
616 {
617     active_services--;
618 }