Initial commit.
[oweals/dinit.git] / service.h
1 #include <string>
2 #include <list>
3 #include <vector>
4 #include "ev.h"
5
6 /* Possible service states */
7 #define SVC_STOPPED   0  /* service is not running */
8 #define SVC_STARTING  1  /* service script is running with "start" */
9 #define SVC_STARTED   2  /* service is running; start script finished. */
10 #define SVC_STOPPING  3  /* service script is running with "stop" */
11
12 /* Service types */
13 #define SVC_PROCESS  0  /* service runs as a process, and can be stopped
14                            by sending the process a signal */
15 #define SVC_SCRIPTED 1  /* service requires a command to start, and another
16                            command to stop */
17
18
19
20 // Exception
21 class ServiceNotFound
22 {
23     public:
24     std::string serviceName;
25 };
26
27
28 class ServiceSet; // forward declaration
29
30 class ServiceRecord
31 {
32     typedef std::string string;
33     
34     string service_name;
35     int service_type;  /* SVC_DAEMON or SVC_SCRIPTED */
36     int service_state; /* SVC_STOPPED, _STARTING, _STARTED, _STOPPING */
37     int desired_state; /* SVC_STOPPED / SVC_STARTED */
38     bool force_stop; // true if the service must actually stop. This is the
39                      // case if for example the process dies; the service,
40                      // and all its dependencies, MUST be stopped.
41     string program_name;  /* executable program or script */
42     string logfile; /* log file name, empty string specifies /dev/null */
43     bool auto_restart; /* whether to restart this (process) if it dies */
44     
45     typedef std::list<ServiceRecord *> sr_list;
46     typedef sr_list::iterator sr_iter;
47     
48     sr_list depends_on; // services this one depends on
49     sr_list dependents; // services depending on this one
50     // unsigned wait_count;  /* if we are waiting for dependents/dependencies to
51     //                         start/stop, this is how many we're waiting for */
52     
53     ServiceSet *service_set; // the set this service belongs to
54     
55     // Implementation details
56     
57     pid_t pid;  /* PID of the process. If state is STARTING or STOPPING,
58                    this is PID of the service script; otherwise it is the
59                    PID of the process itself (process service).
60                    */
61
62     ev_child child_listener;
63     
64     // Move service to STOPPING state. This can only be called once
65     // all dependents have stopped.
66     void stopping();
67     
68     // Service has actually stopped (includes having all dependents
69     // reaching STOPPED state).
70     void stopped();
71     
72     // Service has successfully started
73     void started();
74     
75     // Service failed to start
76     void failed_to_start();
77     
78     // A dependency of this service failed to start.
79     void failed_dependency();
80     
81     // For process services, start the process, return true on success
82     bool start_ps_process();
83     bool start_ps_process(const std::vector<std::string> &args);
84    
85     // Callback from libev when a child process dies
86     static void process_child_callback(struct ev_loop *loop, struct ev_child *w,
87             int revents);
88     
89     void dependentStopped(); // called when a dependent stopped
90     
91     void forceStop(); // force-stop this service and all dependents
92     
93     public:
94     ServiceRecord(ServiceSet *set, string name, int service_type, string command,
95             std::list<ServiceRecord *> * pdepends_on)
96     {
97         service_state = SVC_STOPPED;
98         desired_state = SVC_STOPPED;
99         
100         service_set = set;
101         service_name = name;
102         this->service_type = service_type;
103         program_name = command;
104         auto_restart = false;
105         // TODO splice the contents from the depends_on parameter
106         // rather than duplicating the list.
107         this->depends_on = *pdepends_on;
108         
109         // For each dependency, add us as a dependent.
110         for (sr_iter i = depends_on.begin(); i != depends_on.end(); ++i) {
111             (*i)->dependents.push_back(this);
112         }
113     }
114     
115     // Set logfile, should be done before service is started
116     void setLogfile(string logfile)
117     {
118         this->logfile = logfile;
119     }
120     
121     // Set whether this service should automatically restart when it dies
122     void setAutoRestart(bool auto_restart)
123     {
124         this->auto_restart = auto_restart;
125     }
126     
127     const char *getServiceName() const { return service_name.c_str(); }
128     int getState() const { return service_state; }
129     
130     void start();  // start the service
131     void stop();   // stop the service
132 };
133
134
135 class ServiceSet
136 {
137     int active_services;
138     std::list<ServiceRecord *> records;
139     const char *service_dir;  // directory containing service descriptions
140     bool restart_enabled; // whether automatic restart is enabled (allowed)
141     
142     // Private methods
143     
144     // Locate an existing service record.
145     ServiceRecord *findService(std::string name);
146     
147     // Load a service description, and dependencies, if there is no existing
148     // record for the given name.
149     ServiceRecord *loadServiceRecord(const char *name);
150
151     // Public
152     
153     public:
154     ServiceSet(const char *service_dir)
155     {
156         this->service_dir = service_dir;
157         active_services = 0;
158         restart_enabled = true;
159     }
160     
161     // Start the service with the given name. The named service will begin
162     // transition to the 'started' state.
163     //
164     // Throws an exception if the
165     // service description cannot be loaded.
166     void startService(const char *name);
167     
168     // Stop the service with the given name. The named service will begin
169     // transition to the 'stopped' state.
170     void stopService(const std::string &name);
171     
172     // Notification from service that it is active (state != SVC_STOPPED)
173     // Only to be called on the transition from inactive to active.
174     void service_active(ServiceRecord *);
175     
176     // Notification from service that it is inactive (SVC_STOPPED)
177     // Only to be called on the transition from active to inactive.
178     void service_inactive(ServiceRecord *);
179     
180     // Find out how many services are active (starting, running or stopping,
181     // but not stopped).
182     int count_active_services()
183     {
184         return active_services;
185     }
186     
187     void stop_all_services()
188     {
189         restart_enabled = false;
190         for (std::list<ServiceRecord *>::iterator i = records.begin(); i != records.end(); ++i) {
191             (*i)->stop();
192         }
193     }
194     
195     void set_auto_restart(bool restart)
196     {
197         restart_enabled = restart;
198     }
199     
200     bool get_auto_restart()
201     {
202         return restart_enabled;
203     }
204 };