Properly intiiatiise force_stop
[oweals/dinit.git] / service.h
1 #include <string>
2 #include <list>
3 #include <vector>
4 #include "ev.h"
5
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"
12
13
14 /* Service types */
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
19                            command to stop */
20
21
22 // Exception loading service
23 class ServiceLoadExc
24 {
25     public:
26     std::string serviceName;
27     
28     ServiceLoadExc(std::string serviceName)
29         : serviceName(serviceName)
30     {
31     }
32 };
33
34 class ServiceNotFound : public ServiceLoadExc
35 {
36     public:
37     ServiceNotFound(std::string serviceName)
38         : ServiceLoadExc(serviceName)
39     {
40     }
41 };
42
43 class ServiceCyclicDependency : public ServiceLoadExc
44 {
45     public:
46     ServiceCyclicDependency(std::string serviceName)
47         : ServiceLoadExc(serviceName)
48     {
49     }
50 };
51
52 class ServiceDescriptionExc : public ServiceLoadExc
53 {
54     public:
55     std::string extraInfo;
56     
57     ServiceDescriptionExc(std::string serviceName, std::string extraInfo)
58         : ServiceLoadExc(serviceName), extraInfo(extraInfo)
59     {
60     }    
61 };
62
63
64 class ServiceSet; // forward declaration
65
66 class ServiceRecord
67 {
68     typedef std::string string;
69     
70     string service_name;
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 */
80     
81     typedef std::list<ServiceRecord *> sr_list;
82     typedef sr_list::iterator sr_iter;
83     
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 */
88     
89     ServiceSet *service_set; // the set this service belongs to
90     
91     // Implementation details
92     
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).
96                    */
97
98     ev_child child_listener;
99     
100     // Move service to STOPPING state. This can only be called once
101     // all dependents have stopped.
102     void stopping();
103     
104     // Service has actually stopped (includes having all dependents
105     // reaching STOPPED state).
106     void stopped();
107     
108     // Service has successfully started
109     void started();
110     
111     // Service failed to start
112     void failed_to_start();
113     
114     // A dependency of this service failed to start.
115     void failed_dependency();
116     
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);
120    
121     // Callback from libev when a child process dies
122     static void process_child_callback(struct ev_loop *loop, struct ev_child *w,
123             int revents);
124     
125     void dependentStopped(); // called when a dependent stopped
126     
127     void forceStop(); // force-stop this service and all dependents
128     
129     public:
130
131     ServiceRecord(ServiceSet *set, string name)
132         : service_state(SVC_STOPPED), desired_state(SVC_STOPPED), force_stop(false), auto_restart(false)
133     {
134         service_set = set;
135         service_name = name;
136         service_type = SVC_DUMMY;
137     }
138     
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)
142     {
143         service_set = set;
144         service_name = name;
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;
150         
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);
154         }
155     }
156     
157     // Set logfile, should be done before service is started
158     void setLogfile(string logfile)
159     {
160         this->logfile = logfile;
161     }
162     
163     // Set whether this service should automatically restart when it dies
164     void setAutoRestart(bool auto_restart)
165     {
166         this->auto_restart = auto_restart;
167     }
168     
169     const char *getServiceName() const { return service_name.c_str(); }
170     int getState() const { return service_state; }
171     
172     void start();  // start the service
173     void stop();   // stop the service
174     
175     bool isDummy()
176     {
177         return service_type == SVC_DUMMY;
178     }
179 };
180
181
182 class ServiceSet
183 {
184     int active_services;
185     std::list<ServiceRecord *> records;
186     const char *service_dir;  // directory containing service descriptions
187     bool restart_enabled; // whether automatic restart is enabled (allowed)
188     
189     // Private methods
190     
191     // Locate an existing service record.
192     ServiceRecord *findService(std::string name);
193     
194     // Load a service description, and dependencies, if there is no existing
195     // record for the given name.
196     ServiceRecord *loadServiceRecord(const char *name);
197
198     // Public
199     
200     public:
201     ServiceSet(const char *service_dir)
202     {
203         this->service_dir = service_dir;
204         active_services = 0;
205         restart_enabled = true;
206     }
207     
208     // Start the service with the given name. The named service will begin
209     // transition to the 'started' state.
210     //
211     // Throws an exception if the
212     // service description cannot be loaded.
213     void startService(const char *name);
214     
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);
218     
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 *);
222     
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 *);
226     
227     // Find out how many services are active (starting, running or stopping,
228     // but not stopped).
229     int count_active_services()
230     {
231         return active_services;
232     }
233     
234     void stop_all_services()
235     {
236         restart_enabled = false;
237         for (std::list<ServiceRecord *>::iterator i = records.begin(); i != records.end(); ++i) {
238             (*i)->stop();
239         }
240     }
241     
242     void set_auto_restart(bool restart)
243     {
244         restart_enabled = restart;
245     }
246     
247     bool get_auto_restart()
248     {
249         return restart_enabled;
250     }
251 };