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) {
98 if (sr->auto_restart && sr->service_set->get_auto_restart()) {
102 else { // SVC_SCRIPTED
103 if (sr->service_state == SVC_STOPPING) {
104 if (w->rstatus == 0) {
109 // ??? failed to stop!
110 // For now just pretend we stopped, so that any dependencies
115 else { // SVC_STARTING
116 if (w->rstatus == 0) {
121 sr->failed_to_start();
127 void ServiceRecord::start()
129 if ((service_state == SVC_STARTING || service_state == SVC_STARTED)
130 && desired_state == SVC_STOPPED) {
131 // This service was starting, or started, but was set to be stopped.
132 // Cancel the stop (and continue starting/running).
133 // TODO any listeners waiting for stop should be notified of
137 desired_state = SVC_STARTED;
139 if (service_state != SVC_STOPPED) {
140 // Either we need do nothing (service is already started/starting)
141 // or the service is currently being stopped and we must wait for
146 // Service state is SVC_STOPPED. Start the service.
148 // First, start dependencies
149 bool all_deps_started = true;
150 for (sr_iter i = depends_on.begin(); i != depends_on.end(); ++i) {
151 // Note, we cannot treat a dependency as started if its force_stop
153 if ((*i)->service_state != SVC_STARTED || (*i)->force_stop) {
154 all_deps_started = false;
159 if (! all_deps_started) {
160 // The dependencies will notify this service once they've started.
164 // Actually start this service.
165 service_state = SVC_STARTING;
166 service_set->service_active(this);
168 if (service_type == SVC_PROCESS) {
169 bool start_success = start_ps_process();
178 // Script-controlled service
179 bool start_success = start_ps_process(std::vector<std::string>(1, "start"));
180 if (! start_success) {
186 void ServiceRecord::started()
188 service_state = SVC_STARTED;
189 // TODO - inform listeners
191 if (desired_state == SVC_STARTED) {
192 // Start any dependents whose desired state is SVC_STARTED:
193 for (sr_iter i = dependents.begin(); i != dependents.end(); i++) {
194 if ((*i)->desired_state == SVC_STARTED) {
204 void ServiceRecord::failed_to_start()
206 service_state = SVC_STOPPED;
207 desired_state = SVC_STOPPED;
208 service_set->service_inactive(this);
210 // TODO - inform listeners of failure
211 // Cancel start of dependents:
212 for (sr_iter i = dependents.begin(); i != dependents.end(); i++) {
213 if ((*i)->desired_state == SVC_STARTED) {
214 (*i)->failed_dependency();
219 bool ServiceRecord::start_ps_process()
221 // BIG FAT NOTE: We rely on linux semantics of vfork() here.
223 // * Parent process execution is suspended until the forked child
224 // successfully exec's another program, or it exits
225 // * Memory is shared between the two processes until exec()
227 // Both of the above mean that we can determine in the parent process
228 // whether or not the exec succeeded. If vfork instead is implemented
229 // as an alias of fork, it will look like the exec always succeeded.
232 volatile int exec_status = 0;
233 pid_t forkpid = vfork();
236 // ev_default_destroy(); // won't need that on this side, free up fds.
237 // Hmm. causes segfault. Of course. Memory is shared due to vfork.
239 // Re-set stdin, stdout, stderr
240 close(0); close(1); close(2);
241 string logfile = this->logfile;
242 if (logfile.length() == 0) {
243 logfile = "/dev/null";
246 if (open("/dev/null", O_RDONLY) == 0) {
247 // stdin = 0. That's what we should have; proceed with opening
248 // stdout and stderr.
249 open(logfile.c_str(), O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
253 const char * pname = program_name.c_str();
254 char const * args[2] = { pname, 0 };
255 execvp(pname, (char ** const) args);
256 // If we got here, the exec failed
261 // Parent process - we only reach here once the exec() above
262 // has succeeded, or _exit() above was called (because vfork()
263 // suspends the parent until either of those occurs).
264 if (exec_status == 0) {
268 // Add a process listener so we can detect when the
270 ev_child_init(&child_listener, process_child_callback, pid, 0);
271 child_listener.data = this;
272 ev_child_start(ev_default_loop(EVFLAG_AUTO), &child_listener);
274 service_state = SVC_STARTED;
283 return start_ps_process(std::vector<std::string>());
287 bool ServiceRecord::start_ps_process(const std::vector<std::string> &pargs)
289 // In general, you can't tell whether fork/exec is successful. We use a pipe to communicate
290 // success/failure from the child to the parent. The pipe is set CLOEXEC so a successful
291 // exec closes the pipe, and the parent sees EOF. If the exec is unsuccessful, the errno
292 // is written to the pipe, and the parent can read it.
298 if (pipe2(pipefd, O_CLOEXEC)) {
303 // TODO make sure pipefd's are not 0/1/2 (STDIN/OUT/ERR) - if they are, dup them
304 // until they are not.
306 pid_t forkpid = fork();
316 ev_default_destroy(); // won't need that on this side, free up fds.
318 // Re-set stdin, stdout, stderr
319 close(0); close(1); close(2);
320 string logfile = this->logfile;
321 if (logfile.length() == 0) {
322 logfile = "/dev/null";
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);
333 // Tokenize the command, and add additional arguments from pargs:
334 vector<string> progAndArgs = tokenize(program_name);
335 progAndArgs.insert(progAndArgs.end(), pargs.begin(), pargs.end());
337 const char * pname = progAndArgs[0].c_str();
338 const char ** args = new const char *[progAndArgs.size() + 1];
340 for (std::vector<std::string>::size_type i = 0; i < progAndArgs.size(); i++) {
341 args[i] = progAndArgs[i].c_str();
343 args[progAndArgs.size()] = nullptr;
345 execvp(pname, (char ** const) args);
347 // If we got here, the exec failed:
348 int exec_status = errno;
349 write(pipefd[1], &exec_status, sizeof(int));
353 // Parent process - we only reach here once the exec() above
354 // has succeeded, or _exit() above was called (because vfork()
355 // suspends the parent until either of those occurs).
357 close(pipefd[1]); // close the 'other end' fd
360 if (read(pipefd[0], &exec_status, sizeof(int)) == 0) {
361 // pipe closed; success
364 // Add a process listener so we can detect when the
366 ev_child_init(&child_listener, process_child_callback, pid, 0);
367 child_listener.data = this;
368 ev_child_start(ev_default_loop(EVFLAG_AUTO), &child_listener);
384 // Mark this and all dependent services as force-stopped.
385 void ServiceRecord::forceStop()
388 for (sr_iter i = dependents.begin(); i != dependents.end(); i++) {
393 // A dependency of this service failed to start.
394 void ServiceRecord::failed_dependency()
396 // TODO notify listeners
397 desired_state = SVC_STOPPED;
399 // Presumably, we were starting. So now we're not.
400 service_state = SVC_STOPPED;
402 // Notify dependents of this service also
403 for (sr_iter i = dependents.begin(); i != dependents.end(); i++) {
404 if ((*i)->desired_state == SVC_STARTED) {
405 (*i)->failed_dependency();
410 void ServiceRecord::dependentStopped()
412 if (desired_state == SVC_STOPPED || force_stop) {
413 bool all_deps_stopped = true;
414 for (sr_iter i = dependents.begin(); i != dependents.end(); ++i) {
415 if ((*i)->service_state != SVC_STOPPED) {
416 all_deps_stopped = false;
421 if (all_deps_stopped) {
427 void ServiceRecord::stop()
429 if ((service_state == SVC_STOPPING || service_state == SVC_STOPPED)
430 && desired_state == SVC_STARTED) {
431 // The service *was* stopped/stopping, but it was going to restart.
432 // Now, we'll cancel the restart.
433 // TODO inform listeners waiting for start of cancellation
436 desired_state = SVC_STOPPED;
438 if (service_state != SVC_STARTED) {
439 // If we're starting we need to wait for that to complete.
440 // If we're already stopping/stopped there's nothing to do.
444 // Make sure all dependents have stopped.
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 if (! all_deps_stopped) {
455 // The dependents will notify this service once they've stopped.
459 // Ok, dependents have stopped. We can stop ourselves.
463 // Dependency stopped or is stopping; we must stop too.
464 void ServiceRecord::stopping()
466 service_state = SVC_STOPPING;
468 if (service_type == SVC_PROCESS) {
470 // The process is still kicking on - must actually kill it.
472 // Now we wait; the rest is done in process_child_callback
475 // The process is already dead.
481 start_ps_process(std::vector<string>(1, "stop"));
485 void ServiceSet::service_active(ServiceRecord *sr)
490 void ServiceSet::service_inactive(ServiceRecord *sr)