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