11 // Tokenize a string, allow quoting
12 // TODO doesn't yet allow quoting...
13 static std::vector<std::string> tokenize(std::string arg)
15 // TODO rewrite to be more efficient.
17 istringstream iss(arg);
18 return vector<string>(istream_iterator<string>(iss), istream_iterator<string>());
21 // Find the requested service by name
22 static ServiceRecord * findService(const std::list<ServiceRecord *> & records,
26 list<ServiceRecord *>::const_iterator i = records.begin();
27 for ( ; i != records.end(); i++ ) {
28 if (strcmp((*i)->getServiceName(), name) == 0) {
32 return (ServiceRecord *)0;
35 ServiceRecord * ServiceSet::findService(std::string name)
37 return ::findService(records, name.c_str());
40 void ServiceSet::startService(const char *name)
43 ServiceRecord *record = loadServiceRecord(name);
48 void ServiceSet::stopService(const std::string & name)
50 ServiceRecord *record = findService(name);
51 if (record != nullptr) {
56 // Called when a service has actually stopped.
57 void ServiceRecord::stopped()
59 service_state = SVC_STOPPED;
62 // Stop any dependencies whose desired state is SVC_STOPPED:
63 for (sr_iter i = depends_on.begin(); i != depends_on.end(); i++) {
64 (*i)->dependentStopped();
67 service_set->service_inactive(this);
69 // TODO inform listeners.
70 if (desired_state == SVC_STARTED) {
71 // Desired state is "started".
76 void ServiceRecord::process_child_callback(struct ev_loop *loop, ev_child *w, int revents)
78 ServiceRecord *sr = (ServiceRecord *) w->data;
81 ev_child_stop(ev_default_loop(EVFLAG_AUTO), &sr->child_listener);
83 // Ok, for a process service, any process death which we didn't rig
84 // ourselves is a bit... unexpected. Probably, the child died because
85 // we asked it to (sr->service_state == SVC_STOPPING). But even if
86 // we didn't, there's not much we can do.
88 if (sr->service_type == SVC_PROCESS) {
89 // TODO log non-zero rstatus?
90 if (sr->service_state == SVC_STOPPING) {
97 if (sr->auto_restart && sr->service_set->get_auto_restart()) {
101 else { // SVC_SCRIPTED
102 if (sr->service_state == SVC_STOPPING) {
103 if (w->rstatus == 0) {
108 // ??? failed to stop!
109 // For now just pretend we stopped, so that any dependencies
114 else { // SVC_STARTING
115 if (w->rstatus == 0) {
120 sr->failed_to_start();
126 void ServiceRecord::start()
128 if ((service_state == SVC_STARTING || service_state == SVC_STARTED)
129 && desired_state == SVC_STOPPED) {
130 // This service was starting, or started, but was set to be stopped.
131 // Cancel the stop (and continue starting/running).
132 // TODO any listeners waiting for stop should be notified of
136 auto old_desired_state = desired_state;
137 desired_state = SVC_STARTED;
139 if (service_state == SVC_STARTED || service_state == SVC_STARTING) {
140 // We couldn't be started or starting unless all dependencies have
141 // already started: so there's nothing left to do.
145 bool all_deps_started = true;
147 // Ask dependencies to start, mark them as being waited on.
149 for (sr_iter i = depends_on.begin(); i != depends_on.end(); ++i) {
150 // Note, we cannot treat a dependency as started if its force_stop
152 if ((*i)->service_state != SVC_STARTED || (*i)->force_stop) {
153 all_deps_started = false;
158 if (old_desired_state != SVC_STARTED) {
159 // This is a fresh start, so we mark all soft dependencies as 'waiting on' and ask them
161 for (auto i = soft_deps.begin(); i != soft_deps.end(); ++i) {
162 if (i->getTo()->service_state != SVC_STARTED) {
163 all_deps_started = false;
165 i->waiting_on = true;
170 // This is (or at least may be) a notification that a dependency is ready; let's
172 for (auto i = soft_deps.begin(); i != soft_deps.end(); ++i) {
173 ServiceRecord * to = i->getTo();
175 if ((to->desired_state != SVC_STARTED && to->service_state != SVC_STARTING) || to->service_state == SVC_STARTED) {
176 // Service has either started or is no longer starting
177 i->waiting_on = false;
180 all_deps_started = false;
187 if (! all_deps_started) {
188 // The dependencies will notify this service once they've started.
192 // Actually start this service.
193 service_state = SVC_STARTING;
194 service_set->service_active(this);
196 if (service_type == SVC_PROCESS) {
197 bool start_success = start_ps_process();
205 else if (service_type == SVC_SCRIPTED) {
206 // Script-controlled service
207 bool start_success = start_ps_process(std::vector<std::string>(1, "start"));
208 if (! start_success) {
213 // "internal" service
218 void ServiceRecord::started()
220 service_state = SVC_STARTED;
221 // TODO - inform listeners
223 if (desired_state == SVC_STARTED) {
224 // Start any dependents whose desired state is SVC_STARTED:
225 for (auto i = dependents.begin(); i != dependents.end(); i++) {
226 if ((*i)->desired_state == SVC_STARTED) {
230 for (auto i = soft_dpts.begin(); i != soft_dpts.end(); i++) {
231 if ((*i)->getFrom()->desired_state == SVC_STARTED) {
232 (*i)->getFrom()->start();
241 void ServiceRecord::failed_to_start()
243 service_state = SVC_STOPPED;
244 desired_state = SVC_STOPPED;
245 service_set->service_inactive(this);
247 // Cancel start of dependents:
248 for (sr_iter i = dependents.begin(); i != dependents.end(); i++) {
249 if ((*i)->desired_state == SVC_STARTED) {
250 (*i)->failed_dependency();
253 for (auto i = soft_dpts.begin(); i != soft_dpts.end(); i++) {
254 if ((*i)->getFrom()->desired_state == SVC_STARTED) {
255 // We can send 'start', because this is only a soft dependency.
256 // Our startup failure means that they don't have to wait for us.
257 (*i)->getFrom()->start();
262 bool ServiceRecord::start_ps_process()
264 return start_ps_process(std::vector<std::string>());
268 // TODO this can currently throw std::bad_alloc, fix that (in the worst case,
269 // return failure instead).
270 bool ServiceRecord::start_ps_process(const std::vector<std::string> &pargs)
272 // In general, you can't tell whether fork/exec is successful. We use a pipe to communicate
273 // success/failure from the child to the parent. The pipe is set CLOEXEC so a successful
274 // exec closes the pipe, and the parent sees EOF. If the exec is unsuccessful, the errno
275 // is written to the pipe, and the parent can read it.
277 // TODO should NOT wait for the exec to succeed or fail here, as that could (when/if we allow
278 // running child processes with lower priority) result in priority inversion.
284 if (pipe2(pipefd, O_CLOEXEC)) {
289 // TODO make sure pipefd's are not 0/1/2 (STDIN/OUT/ERR) - if they are, dup them
290 // until they are not.
292 pid_t forkpid = fork();
302 ev_default_destroy(); // won't need that on this side, free up fds.
304 // Re-set stdin, stdout, stderr
305 close(0); close(1); close(2);
306 string logfile = this->logfile;
307 if (logfile.length() == 0) {
308 logfile = "/dev/null";
311 // TODO rethink this logic. If we open it at not-0, shouldn't we just dup it to 0?:
312 if (open("/dev/null", O_RDONLY) == 0) {
313 // stdin = 0. That's what we should have; proceed with opening
314 // stdout and stderr.
315 open(logfile.c_str(), O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
319 // Tokenize the command, and add additional arguments from pargs:
320 vector<string> progAndArgs = tokenize(program_name);
321 progAndArgs.insert(progAndArgs.end(), pargs.begin(), pargs.end());
323 const char * pname = progAndArgs[0].c_str();
324 const char ** args = new const char *[progAndArgs.size() + 1];
326 for (std::vector<std::string>::size_type i = 0; i < progAndArgs.size(); i++) {
327 args[i] = progAndArgs[i].c_str();
329 args[progAndArgs.size()] = nullptr;
331 execvp(pname, const_cast<char **>(args));
333 // If we got here, the exec failed:
334 int exec_status = errno;
335 write(pipefd[1], &exec_status, sizeof(int));
340 close(pipefd[1]); // close the 'other end' fd
343 if (read(pipefd[0], &exec_status, sizeof(int)) == 0) {
344 // pipe closed; success
347 // Add a process listener so we can detect when the
349 ev_child_init(&child_listener, process_child_callback, pid, 0);
350 child_listener.data = this;
351 ev_child_start(ev_default_loop(EVFLAG_AUTO), &child_listener);
367 // Mark this and all dependent services as force-stopped.
368 void ServiceRecord::forceStop()
372 for (sr_iter i = dependents.begin(); i != dependents.end(); i++) {
375 // We don't want to force stop soft dependencies, however.
378 // A dependency of this service failed to start.
379 void ServiceRecord::failed_dependency()
381 desired_state = SVC_STOPPED;
383 // Presumably, we were starting. So now we're not.
384 service_state = SVC_STOPPED;
386 // Notify dependents of this service also
387 for (auto i = dependents.begin(); i != dependents.end(); i++) {
388 if ((*i)->desired_state == SVC_STARTED) {
389 (*i)->failed_dependency();
392 for (auto i = soft_dpts.begin(); i != soft_dpts.end(); i++) {
393 if ((*i)->getFrom()->desired_state == SVC_STARTED) {
394 // It's a soft dependency, so send them 'started' rather than
396 (*i)->getFrom()->started();
401 void ServiceRecord::dependentStopped()
403 if (service_state != SVC_STOPPED && (desired_state == SVC_STOPPED || force_stop)) {
404 // Check the other dependents before we stop.
405 if (stopCheckDependents()) {
411 void ServiceRecord::stop()
413 if ((service_state == SVC_STOPPING || service_state == SVC_STOPPED)
414 && desired_state == SVC_STARTED) {
415 // The service *was* stopped/stopping, but it was going to restart.
416 // Now, we'll cancel the restart.
417 // TODO inform listeners waiting for start of cancellation
420 if (desired_state == SVC_STOPPED) return;
422 desired_state = SVC_STOPPED;
424 if (service_state != SVC_STARTED) {
425 if (service_state == SVC_STARTING) {
426 // Well this is awkward: we're going to have to continue
427 // starting, but we don't want any dependents to think that
428 // they are still waiting to start.
429 // Make sure they remain stopped:
433 // If we're starting we need to wait for that to complete.
434 // If we're already stopping/stopped there's nothing to do.
438 // If we get here, we are in STARTED state; stop all dependents.
439 if (stopCheckDependents()) {
444 bool ServiceRecord::stopCheckDependents()
446 bool all_deps_stopped = true;
447 for (sr_iter i = dependents.begin(); i != dependents.end(); ++i) {
448 if ((*i)->service_state != SVC_STOPPED) {
449 all_deps_stopped = false;
454 return all_deps_stopped;
457 bool ServiceRecord::stopDependents()
459 bool all_deps_stopped = true;
460 for (sr_iter i = dependents.begin(); i != dependents.end(); ++i) {
461 if ((*i)->service_state != SVC_STOPPED) {
462 all_deps_stopped = false;
467 return all_deps_stopped;
472 // Dependency stopped or is stopping; we must stop too.
473 void ServiceRecord::stopping()
475 service_state = SVC_STOPPING;
477 if (service_type == SVC_PROCESS) {
479 // The process is still kicking on - must actually kill it.
481 // Now we wait; the rest is done in process_child_callback
484 // The process is already dead.
490 start_ps_process(std::vector<string>(1, "stop"));
494 void ServiceSet::service_active(ServiceRecord *sr)
499 void ServiceSet::service_inactive(ServiceRecord *sr)