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