6 /* Possible service states */
7 // TODO can we use typesafe enum?
8 constexpr static int SVC_STOPPED = 0; // service is not running
9 constexpr static int SVC_STARTING = 1; // service script is running with "start"
10 constexpr static int SVC_STARTED = 2; // service is running; start script finished.
11 constexpr static int SVC_STOPPING = 3; // service script is running with "stop"
15 #define SVC_DUMMY 0 /* dummy service, used to detect cyclic dependencies */
16 #define SVC_PROCESS 1 /* service runs as a process, and can be stopped
17 by sending the process a signal */
18 #define SVC_SCRIPTED 2 /* service requires a command to start, and another
22 // Exception loading service
26 std::string serviceName;
28 ServiceLoadExc(std::string serviceName)
29 : serviceName(serviceName)
34 class ServiceNotFound : public ServiceLoadExc
37 ServiceNotFound(std::string serviceName)
38 : ServiceLoadExc(serviceName)
43 class ServiceCyclicDependency : public ServiceLoadExc
46 ServiceCyclicDependency(std::string serviceName)
47 : ServiceLoadExc(serviceName)
52 class ServiceDescriptionExc : public ServiceLoadExc
55 std::string extraInfo;
57 ServiceDescriptionExc(std::string serviceName, std::string extraInfo)
58 : ServiceLoadExc(serviceName), extraInfo(extraInfo)
64 class ServiceSet; // forward declaration
68 typedef std::string string;
71 int service_type; /* SVC_DAEMON or SVC_SCRIPTED */
72 int service_state; /* SVC_STOPPED, _STARTING, _STARTED, _STOPPING */
73 int desired_state; /* SVC_STOPPED / SVC_STARTED */
74 bool force_stop; // true if the service must actually stop. This is the
75 // case if for example the process dies; the service,
76 // and all its dependencies, MUST be stopped.
77 string program_name; /* executable program or script */
78 string logfile; /* log file name, empty string specifies /dev/null */
79 bool auto_restart; /* whether to restart this (process) if it dies */
81 typedef std::list<ServiceRecord *> sr_list;
82 typedef sr_list::iterator sr_iter;
84 sr_list depends_on; // services this one depends on
85 sr_list dependents; // services depending on this one
86 // unsigned wait_count; /* if we are waiting for dependents/dependencies to
87 // start/stop, this is how many we're waiting for */
89 ServiceSet *service_set; // the set this service belongs to
91 // Implementation details
93 pid_t pid; /* PID of the process. If state is STARTING or STOPPING,
94 this is PID of the service script; otherwise it is the
95 PID of the process itself (process service).
98 ev_child child_listener;
100 // Move service to STOPPING state. This can only be called once
101 // all dependents have stopped.
104 // Service has actually stopped (includes having all dependents
105 // reaching STOPPED state).
108 // Service has successfully started
111 // Service failed to start
112 void failed_to_start();
114 // A dependency of this service failed to start.
115 void failed_dependency();
117 // For process services, start the process, return true on success
118 bool start_ps_process();
119 bool start_ps_process(const std::vector<std::string> &args);
121 // Callback from libev when a child process dies
122 static void process_child_callback(struct ev_loop *loop, struct ev_child *w,
125 void dependentStopped(); // called when a dependent stopped
127 void forceStop(); // force-stop this service and all dependents
131 ServiceRecord(ServiceSet *set, string name)
132 : service_state(SVC_STOPPED), desired_state(SVC_STOPPED), force_stop(false), auto_restart(false)
136 service_type = SVC_DUMMY;
139 ServiceRecord(ServiceSet *set, string name, int service_type, string command,
140 std::list<ServiceRecord *> * pdepends_on)
141 : service_state(SVC_STOPPED), desired_state(SVC_STOPPED), force_stop(false), auto_restart(false)
145 this->service_type = service_type;
146 program_name = command;
147 // TODO splice the contents from the depends_on parameter
148 // rather than duplicating the list.
149 this->depends_on = *pdepends_on;
151 // For each dependency, add us as a dependent.
152 for (sr_iter i = depends_on.begin(); i != depends_on.end(); ++i) {
153 (*i)->dependents.push_back(this);
157 // Set logfile, should be done before service is started
158 void setLogfile(string logfile)
160 this->logfile = logfile;
163 // Set whether this service should automatically restart when it dies
164 void setAutoRestart(bool auto_restart)
166 this->auto_restart = auto_restart;
169 const char *getServiceName() const { return service_name.c_str(); }
170 int getState() const { return service_state; }
172 void start(); // start the service
173 void stop(); // stop the service
177 return service_type == SVC_DUMMY;
185 std::list<ServiceRecord *> records;
186 const char *service_dir; // directory containing service descriptions
187 bool restart_enabled; // whether automatic restart is enabled (allowed)
191 // Locate an existing service record.
192 ServiceRecord *findService(std::string name);
194 // Load a service description, and dependencies, if there is no existing
195 // record for the given name.
196 ServiceRecord *loadServiceRecord(const char *name);
201 ServiceSet(const char *service_dir)
203 this->service_dir = service_dir;
205 restart_enabled = true;
208 // Start the service with the given name. The named service will begin
209 // transition to the 'started' state.
211 // Throws an exception if the
212 // service description cannot be loaded.
213 void startService(const char *name);
215 // Stop the service with the given name. The named service will begin
216 // transition to the 'stopped' state.
217 void stopService(const std::string &name);
219 // Notification from service that it is active (state != SVC_STOPPED)
220 // Only to be called on the transition from inactive to active.
221 void service_active(ServiceRecord *);
223 // Notification from service that it is inactive (SVC_STOPPED)
224 // Only to be called on the transition from active to inactive.
225 void service_inactive(ServiceRecord *);
227 // Find out how many services are active (starting, running or stopping,
229 int count_active_services()
231 return active_services;
234 void stop_all_services()
236 restart_enabled = false;
237 for (std::list<ServiceRecord *>::iterator i = records.begin(); i != records.end(); ++i) {
242 void set_auto_restart(bool restart)
244 restart_enabled = restart;
247 bool get_auto_restart()
249 return restart_enabled;