Various exception handling fixes and 'noexcept' declarations
[oweals/dinit.git] / service.cc
1 #include <cstring>
2 #include <cerrno>
3 #include <sstream>
4 #include <iterator>
5 #include <memory>
6 #include <sys/types.h>
7 #include <sys/stat.h>
8 #include <fcntl.h>
9 #include <unistd.h>
10 #include "service.h"
11 #include "dinit-log.h"
12
13 // from dinit.cc:
14 void open_control_socket(struct ev_loop *loop) noexcept;
15
16
17 // Find the requested service by name
18 static ServiceRecord * findService(const std::list<ServiceRecord *> & records,
19                                     const char *name) noexcept
20 {
21     using std::list;
22     list<ServiceRecord *>::const_iterator i = records.begin();
23     for ( ; i != records.end(); i++ ) {
24         if (strcmp((*i)->getServiceName(), name) == 0) {
25             return *i;
26         }
27     }
28     return (ServiceRecord *)0;
29 }
30
31 ServiceRecord * ServiceSet::findService(std::string name) noexcept
32 {
33     return ::findService(records, name.c_str());
34 }
35
36 void ServiceSet::startService(const char *name)
37 {
38     using namespace std;
39     ServiceRecord *record = loadServiceRecord(name);
40     
41     record->start();
42 }
43
44 void ServiceSet::stopService(const std::string & name) noexcept
45 {
46     ServiceRecord *record = findService(name);
47     if (record != nullptr) {
48         record->stop();
49     }
50 }
51
52 // Called when a service has actually stopped.
53 void ServiceRecord::stopped() noexcept
54 {
55     logServiceStopped(service_name);
56     service_state = ServiceState::STOPPED;
57     force_stop = false;
58     
59     // Stop any dependencies whose desired state is STOPPED:
60     for (sr_iter i = depends_on.begin(); i != depends_on.end(); i++) {
61         (*i)->dependentStopped();
62     }
63
64     service_set->service_inactive(this);
65     
66     // TODO inform listeners.
67     if (desired_state == ServiceState::STARTED) {
68         // Desired state is "started".
69         start();
70     }
71 }
72
73 void ServiceRecord::process_child_callback(struct ev_loop *loop, ev_child *w, int revents) noexcept
74 {    
75     ServiceRecord *sr = (ServiceRecord *) w->data;
76
77     sr->pid = -1;
78     ev_child_stop(ev_default_loop(EVFLAG_AUTO), &sr->child_listener);
79     
80     // Ok, for a process service, any process death which we didn't rig
81     // ourselves is a bit... unexpected. Probably, the child died because
82     // we asked it to (sr->service_state == STOPPING). But even if
83     // we didn't, there's not much we can do.
84     
85     if (sr->service_type == ServiceType::PROCESS) {
86         // TODO log non-zero rstatus?
87         if (sr->service_state == ServiceState::STOPPING) {
88             sr->stopped();
89         }
90         else {
91             sr->forceStop();
92         }
93         
94         if (sr->auto_restart && sr->service_set->get_auto_restart()) {
95             sr->start();
96         }
97     }
98     else {  // SCRIPTED
99         if (sr->service_state == ServiceState::STOPPING) {
100             if (w->rstatus == 0) {
101                 sr->stopped();
102             }
103             else {
104                 // ??? failed to stop! Let's log it as info:
105                 log(LogLevel::INFO, "service ", sr->service_name, " stop command failed with exit code ", w->rstatus);
106                 // Just assume that we stopped, so that any dependencies
107                 // can be stopped:
108                 sr->stopped();
109             }
110         }
111         else { // STARTING
112             if (w->rstatus == 0) {
113                 sr->started();
114             }
115             else {
116                 // failed to start
117                 sr->failed_to_start();
118             }
119         }
120     }
121 }
122
123 void ServiceRecord::start() noexcept
124 {
125     if ((service_state == ServiceState::STARTING || service_state == ServiceState::STARTED)
126             && desired_state == ServiceState::STOPPED) {
127         // This service was starting, or started, but was set to be stopped.
128         // Cancel the stop (and continue starting/running).
129         // TODO any listeners waiting for stop should be notified of
130         //      its cancellation
131     }
132
133     if (desired_state == ServiceState::STARTED) return;
134
135     desired_state = ServiceState::STARTED;
136     
137     if (service_state != ServiceState::STOPPED) {
138         // We're already starting/started, or we are stopping and need to wait for
139         // that the complete.
140         return;
141     }
142     
143     service_state = ServiceState::STARTING;
144     service_set->service_active(this);
145
146     // Ask dependencies to start, mark them as being waited on.
147     if (! startCheckDependencies(true)) {
148         return;
149     }
150
151     // Actually start this service.
152     allDepsStarted();
153 }
154
155 void ServiceRecord::dependencyStarted() noexcept
156 {
157     if (service_state != ServiceState::STARTING) {
158         return;
159     }
160
161     if (startCheckDependencies(false)) {
162         allDepsStarted();
163     }
164 }
165
166 bool ServiceRecord::startCheckDependencies(bool start_deps) noexcept
167 {
168     bool all_deps_started = true;
169
170     for (sr_iter i = depends_on.begin(); i != depends_on.end(); ++i) {
171         if ((*i)->service_state != ServiceState::STARTED) {
172             if (start_deps) {
173                 all_deps_started = false;
174                 (*i)->start();
175             }
176             else {
177                 return false;
178             }
179         }
180     }
181
182     for (auto i = soft_deps.begin(); i != soft_deps.end(); ++i) {
183         ServiceRecord * to = i->getTo();
184         if (start_deps) {
185             if (to->service_state != ServiceState::STARTED) {
186                 to->start();
187                 i->waiting_on = true;
188                 all_deps_started = false;
189             }
190             else {
191                 i->waiting_on = false;
192             }
193         }
194         else if (i->waiting_on) {
195             if (to->service_state != ServiceState::STARTING) {
196                 // Service has either started or is no longer starting
197                 i->waiting_on = false;
198             }
199             else {
200                 // We are still waiting on this service
201                 return false;
202             }
203         }
204     }
205     
206     return all_deps_started;
207 }
208
209 void ServiceRecord::allDepsStarted() noexcept
210 {
211     if (service_type == ServiceType::PROCESS) {
212         bool start_success = start_ps_process();
213         if (start_success) {
214             started();
215         }
216         else {
217             failed_to_start();
218         }
219     }
220     else if (service_type == ServiceType::SCRIPTED) {
221         // Script-controlled service
222         bool start_success = start_ps_process(std::vector<std::string>(1, "start"));
223         if (! start_success) {
224             failed_to_start();
225         }
226     }
227     else {
228         // "internal" service
229         started();
230     }
231 }
232
233 void ServiceRecord::started()
234 {
235     logServiceStarted(service_name);
236     service_state = ServiceState::STARTED;
237     // TODO - inform listeners
238
239     if (onstart_flags.release_console) {
240         log_to_console = false;
241     }
242
243     if (onstart_flags.rw_ready) {
244         open_control_socket(ev_default_loop(EVFLAG_AUTO));
245     }
246
247     if (force_stop || desired_state == ServiceState::STOPPED) {
248         // We must now stop.
249         stop();
250         return;
251     }
252
253     // Notify any dependents whose desired state is STARTED:
254     for (auto i = dependents.begin(); i != dependents.end(); i++) {
255         if ((*i)->desired_state == ServiceState::STARTED) {
256             (*i)->dependencyStarted();
257         }
258     }
259     for (auto i = soft_dpts.begin(); i != soft_dpts.end(); i++) {
260         if ((*i)->getFrom()->desired_state == ServiceState::STARTED) {
261             (*i)->getFrom()->dependencyStarted();
262         }
263     }
264 }
265
266 void ServiceRecord::failed_to_start()
267 {
268     logServiceFailed(service_name);
269     service_state = ServiceState::STOPPED;
270     desired_state = ServiceState::STOPPED;
271     service_set->service_inactive(this);
272     // failure to start
273     // Cancel start of dependents:
274     for (sr_iter i = dependents.begin(); i != dependents.end(); i++) {
275         if ((*i)->desired_state == ServiceState::STARTED) {
276             (*i)->failed_dependency();
277         }
278     }    
279     for (auto i = soft_dpts.begin(); i != soft_dpts.end(); i++) {
280         if ((*i)->getFrom()->desired_state == ServiceState::STARTED) {
281             // We can send 'start', because this is only a soft dependency.
282             // Our startup failure means that they don't have to wait for us.
283             (*i)->getFrom()->start();
284         }
285     }
286 }
287
288 bool ServiceRecord::start_ps_process() noexcept
289 {
290     try {
291         return start_ps_process(std::vector<std::string>());
292     }
293     catch (std::bad_alloc & bad_alloc_exc) {
294         // TODO log error
295         return false;
296     }
297 }
298
299 bool ServiceRecord::start_ps_process(const std::vector<std::string> &pargs) noexcept
300 {
301     // In general, you can't tell whether fork/exec is successful. We use a pipe to communicate
302     // success/failure from the child to the parent. The pipe is set CLOEXEC so a successful
303     // exec closes the pipe, and the parent sees EOF. If the exec is unsuccessful, the errno
304     // is written to the pipe, and the parent can read it.
305
306     // TODO should NOT wait for the exec to succeed or fail here, as that could (when/if we allow
307     // running child processes with lower priority) result in priority inversion.
308
309     using std::vector;
310     using std::string;
311     
312     int pipefd[2];
313     if (pipe2(pipefd, O_CLOEXEC)) {
314         // TODO log error
315         return false;
316     }
317     
318     // Set up the argument array and other data now (before fork), in case memory allocation fails.
319
320     try {
321         //auto argsv = std::vector<const char *>(num_args + pargs.size() + 1);
322         auto argsv = std::vector<const char *>(num_args + pargs.size() + 1);
323         auto args = argsv.data();
324         int i;
325         for (i = 0; i < num_args; i++) {
326             args[i] = exec_arg_parts[i];
327         }
328         for (auto progarg : pargs) {
329             args[i] = progarg.c_str();
330             i++;
331         }
332         args[i] = nullptr;
333         
334         string logfile = this->logfile;
335         if (logfile.length() == 0) {
336             logfile = "/dev/null";
337         }
338
339         // TODO make sure pipefd's are not 0/1/2 (STDIN/OUT/ERR) - if they are, dup them
340         // until they are not.
341
342         pid_t forkpid = fork();
343         if (forkpid == -1) {
344             // TODO log error
345             close(pipefd[0]);
346             close(pipefd[1]);
347             return false;
348         }
349
350         if (forkpid == 0) {
351             // Child process. Must not allocate memory (or otherwise risk throwing any exception)
352             // from here until exit().
353             ev_default_destroy(); // won't need that on this side, free up fds.
354
355             // Re-set stdin, stdout, stderr
356             close(0); close(1); close(2);
357
358             // TODO rethink this logic. If we open it at not-0, shouldn't we just dup it to 0?:
359             if (open("/dev/null", O_RDONLY) == 0) {
360               // stdin = 0. That's what we should have; proceed with opening
361               // stdout and stderr.
362               open(logfile.c_str(), O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
363               dup2(1, 2);
364             }
365
366             execvp(exec_arg_parts[0], const_cast<char **>(args));
367
368             // If we got here, the exec failed:
369             int exec_status = errno;
370             write(pipefd[1], &exec_status, sizeof(int));
371             exit(0);
372         }
373         else {
374             // Parent process
375             close(pipefd[1]); // close the 'other end' fd
376
377             int exec_status;
378             if (read(pipefd[0], &exec_status, sizeof(int)) == 0) {
379                 // pipe closed; success
380                 pid = forkpid;
381
382                 // Add a process listener so we can detect when the
383                 // service stops
384                 ev_child_init(&child_listener, process_child_callback, pid, 0);
385                 child_listener.data = this;
386                 ev_child_start(ev_default_loop(EVFLAG_AUTO), &child_listener);
387
388                 close(pipefd[0]);
389                 return true;
390             }
391             else {
392                 // TODO log error
393                 close(pipefd[0]);
394                 return false;
395             }
396         }
397     }
398     catch (std::bad_alloc &bad_alloc_exc) {
399         log(LogLevel::ERROR, "Out of memory");
400         return false;
401     }
402 }
403
404 // Mark this and all dependent services as force-stopped.
405 void ServiceRecord::forceStop() noexcept
406 {
407     force_stop = true;
408     stop();
409     for (sr_iter i = dependents.begin(); i != dependents.end(); i++) {
410         (*i)->forceStop();
411     }
412     // We don't want to force stop soft dependencies, however.
413 }
414
415 // A dependency of this service failed to start.
416 void ServiceRecord::failed_dependency()
417 {
418     desired_state = ServiceState::STOPPED;
419     
420     // Presumably, we were starting. So now we're not.
421     service_state = ServiceState::STOPPED;
422     
423     // Notify dependents of this service also
424     for (auto i = dependents.begin(); i != dependents.end(); i++) {
425         if ((*i)->desired_state == ServiceState::STARTED) {
426             (*i)->failed_dependency();
427         }
428     }
429     for (auto i = soft_dpts.begin(); i != soft_dpts.end(); i++) {
430         if ((*i)->getFrom()->desired_state == ServiceState::STARTED) {
431             // It's a soft dependency, so send them 'started' rather than
432             // 'failed dep'.
433             (*i)->getFrom()->started();
434         }
435     }    
436 }
437
438 void ServiceRecord::dependentStopped() noexcept
439 {
440     if (service_state == ServiceState::STOPPING) {
441         // Check the other dependents before we stop.
442         if (stopCheckDependents()) {
443             allDepsStopped();
444         }
445     }
446 }
447
448 void ServiceRecord::stop() noexcept
449 {
450     if ((service_state == ServiceState::STOPPING || service_state == ServiceState::STOPPED)
451             && desired_state == ServiceState::STARTED) {
452         // The service *was* stopped/stopping, but it was going to restart.
453         // Now, we'll cancel the restart.
454         // TODO inform listeners waiting for start of cancellation
455     }
456     
457     if (desired_state == ServiceState::STOPPED) return;
458     
459     desired_state = ServiceState::STOPPED;
460
461     if (service_state != ServiceState::STARTED) {
462         if (service_state == ServiceState::STARTING) {
463             // Well this is awkward: we're going to have to continue
464             // starting, but we don't want any dependents to think that
465             // they are still waiting to start.
466             // Make sure they remain stopped:
467             stopDependents();
468         }
469         
470         // If we're starting we need to wait for that to complete.
471         // If we're already stopping/stopped there's nothing to do.
472         return;
473     }
474     
475     service_state = ServiceState::STOPPING;
476     // If we get here, we are in STARTED state; stop all dependents.
477     if (stopDependents()) {
478         allDepsStopped();
479     }
480 }
481
482 bool ServiceRecord::stopCheckDependents() noexcept
483 {
484     bool all_deps_stopped = true;
485     for (sr_iter i = dependents.begin(); i != dependents.end(); ++i) {
486         if ((*i)->service_state != ServiceState::STOPPED) {
487             all_deps_stopped = false;
488             break;
489         }
490     }
491     
492     return all_deps_stopped;
493 }
494
495 bool ServiceRecord::stopDependents() noexcept
496 {
497     bool all_deps_stopped = true;
498     for (sr_iter i = dependents.begin(); i != dependents.end(); ++i) {
499         if ((*i)->service_state != ServiceState::STOPPED) {
500             all_deps_stopped = false;
501             (*i)->stop();
502         }
503     }
504     
505     return all_deps_stopped;
506 }
507
508
509
510 // Dependency stopped or is stopping; we must stop too.
511 void ServiceRecord::allDepsStopped()
512 {
513     if (service_type == ServiceType::PROCESS) {
514         if (pid != -1) {
515           // The process is still kicking on - must actually kill it.
516           kill(pid, SIGTERM);
517           if (term_signal != -1) {
518               kill(pid, term_signal);
519           }
520           // Now we wait; the rest is done in process_child_callback
521         }
522         else {
523             // The process is already dead.
524             stopped();
525         }
526     }
527     else if (service_type == ServiceType::SCRIPTED) {
528         // Scripted service.
529         if (! start_ps_process(std::vector<string>(1, "stop"))) {
530             // stop script failed, but there's not much we can do:
531             stopped();
532         }
533     }
534     else {
535         stopped();
536     }
537 }
538
539 void ServiceSet::service_active(ServiceRecord *sr) noexcept
540 {
541     active_services++;
542 }
543
544 void ServiceSet::service_inactive(ServiceRecord *sr) noexcept
545 {
546     active_services--;
547     if (active_services == 0 && rollback_handler != nullptr) {
548         rollback_handler->rollbackComplete();
549     }
550 }