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)
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)
145 this->service_type = service_type;
146 program_name = command;
147 auto_restart = false;
148 // TODO splice the contents from the depends_on parameter
149 // rather than duplicating the list.
150 this->depends_on = *pdepends_on;
152 // For each dependency, add us as a dependent.
153 for (sr_iter i = depends_on.begin(); i != depends_on.end(); ++i) {
154 (*i)->dependents.push_back(this);
158 // Set logfile, should be done before service is started
159 void setLogfile(string logfile)
161 this->logfile = logfile;
164 // Set whether this service should automatically restart when it dies
165 void setAutoRestart(bool auto_restart)
167 this->auto_restart = auto_restart;
170 const char *getServiceName() const { return service_name.c_str(); }
171 int getState() const { return service_state; }
173 void start(); // start the service
174 void stop(); // stop the service
178 return service_type == SVC_DUMMY;
186 std::list<ServiceRecord *> records;
187 const char *service_dir; // directory containing service descriptions
188 bool restart_enabled; // whether automatic restart is enabled (allowed)
192 // Locate an existing service record.
193 ServiceRecord *findService(std::string name);
195 // Load a service description, and dependencies, if there is no existing
196 // record for the given name.
197 ServiceRecord *loadServiceRecord(const char *name);
202 ServiceSet(const char *service_dir)
204 this->service_dir = service_dir;
206 restart_enabled = true;
209 // Start the service with the given name. The named service will begin
210 // transition to the 'started' state.
212 // Throws an exception if the
213 // service description cannot be loaded.
214 void startService(const char *name);
216 // Stop the service with the given name. The named service will begin
217 // transition to the 'stopped' state.
218 void stopService(const std::string &name);
220 // Notification from service that it is active (state != SVC_STOPPED)
221 // Only to be called on the transition from inactive to active.
222 void service_active(ServiceRecord *);
224 // Notification from service that it is inactive (SVC_STOPPED)
225 // Only to be called on the transition from active to inactive.
226 void service_inactive(ServiceRecord *);
228 // Find out how many services are active (starting, running or stopping,
230 int count_active_services()
232 return active_services;
235 void stop_all_services()
237 restart_enabled = false;
238 for (std::list<ServiceRecord *>::iterator i = records.begin(); i != records.end(); ++i) {
243 void set_auto_restart(bool restart)
245 restart_enabled = restart;
248 bool get_auto_restart()
250 return restart_enabled;