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