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