45 |
|
|
46 |
|
|
47 |
/** |
/** |
48 |
* Manage process information persistently. Process data is saved to |
* Manage service information persistently. Service data is saved to |
49 |
* a state file (~/.monit.state) when monit runs in daemon mode for |
* a state file (~/.monit.state) when monit runs in daemon mode for |
50 |
* each poll cycle. Monit use this file to recover from a crash or to |
* each poll cycle. Monit use this file to recover from a crash or to |
51 |
* maintain process data persistently during a reload. |
* maintain service data persistently during a reload. |
52 |
* |
* |
53 |
* @author Jan-Henrik Haukeland, <hauk@tildeslash.com> |
* @author Jan-Henrik Haukeland, <hauk@tildeslash.com> |
54 |
* @version \$Id$ |
* @version \$Id$ |
60 |
|
|
61 |
|
|
62 |
/** |
/** |
63 |
* Fields from the Process_T object type, which we are interessted in |
* Fields from the Service_T object type, which we are interessted in |
64 |
* when handling the state. |
* when handling the state. |
65 |
*/ |
*/ |
66 |
typedef struct mystate { |
typedef struct mystate { |
78 |
|
|
79 |
static void close_state(FILE *); |
static void close_state(FILE *); |
80 |
static FILE *open_state(const char *mode); |
static FILE *open_state(const char *mode); |
81 |
static void clone_state(Process_T, State_T *); |
static void clone_state(Service_T, State_T *); |
82 |
static void update_process_state(Process_T, State_T *); |
static void update_service_state(Service_T, State_T *); |
83 |
|
|
84 |
|
|
85 |
/* ------------------------------------------------------------------ Public */ |
/* ------------------------------------------------------------------ Public */ |
86 |
|
|
87 |
|
|
|
|
|
88 |
/** |
/** |
89 |
* Save process state information to the state file |
* Save service state information to the state file |
90 |
*/ |
*/ |
91 |
void state_save() { |
void state_save() { |
92 |
|
|
93 |
int l= 0; |
int l= 0; |
94 |
State_T s; |
Service_T s; |
95 |
Process_T p; |
State_T state; |
96 |
FILE *S= NULL; |
FILE *S= NULL; |
97 |
|
|
98 |
if(! (S= open_state("w"))) |
if(! (S= open_state("w"))) |
99 |
return; |
return; |
100 |
|
|
101 |
l= get_process_list_length(); |
l= get_service_list_length(); |
102 |
|
|
103 |
if(fwrite(&l, 1, sizeof (int), S) != sizeof(int)) { |
if(fwrite(&l, 1, sizeof (int), S) != sizeof(int)) { |
104 |
log("%s: Unable to save monit state information to '%s'\n", |
log("%s: Unable to save monit state information to '%s'\n", |
106 |
goto error; |
goto error; |
107 |
} |
} |
108 |
|
|
109 |
for(p= processlist; p; p= p->next) { |
for(s= servicelist; s; s= s->next) { |
110 |
clone_state(p, &s); |
clone_state(s, &state); |
111 |
if(fwrite(&s, 1, sizeof(State_T), S) != sizeof(State_T)) { |
if(fwrite(&state, 1, sizeof(State_T), S) != sizeof(State_T)) { |
112 |
log("%s: An error occured when saving monit state information " |
log("%s: An error occured when saving monit state information " |
113 |
"for the process %s\n", prog, p->name); |
"for the service %s\n", prog, s->name); |
114 |
goto error; |
goto error; |
115 |
} |
} |
116 |
} |
} |
122 |
|
|
123 |
|
|
124 |
/** |
/** |
125 |
* Check if we should update current processes with persistent state |
* Check if we should update current services with persistent state |
126 |
* information. The logic is as follows: Iff a state file is present |
* information. The logic is as follows: Iff a state file is present |
127 |
* *and* older than the running monit daemon's lock file we have had a |
* *and* older than the running monit daemon's lock file we have had a |
128 |
* crash and should update data from the state file. |
* crash and should update data from the state file. |
143 |
|
|
144 |
|
|
145 |
/** |
/** |
146 |
* Update the current process list with data from the state file. We |
* Update the current service list with data from the state file. We |
147 |
* do *only* change processes found in *both* the monitrc file and in |
* do *only* change services found in *both* the monitrc file and in |
148 |
* the state file. The algorithm: |
* the state file. The algorithm: |
149 |
* |
* |
150 |
* Assume the control file was changed and a new process (B) was added |
* Assume the control file was changed and a new service (B) was added |
151 |
* so the monitrc file now contains the processes: A B and C. The |
* so the monitrc file now contains the services: A B and C. The |
152 |
* running monit daemon only knows the processes A and C. Upon restart |
* running monit daemon only knows the services A and C. Upon restart |
153 |
* after a crash the monit daemon first read the monitrc file and |
* after a crash the monit daemon first read the monitrc file and |
154 |
* creates the process list structure with A B and C. We then read the |
* creates the service list structure with A B and C. We then read the |
155 |
* state file and update the process A and C since they are found in |
* state file and update the service A and C since they are found in |
156 |
* the state file, B is not found in this file and therefore not |
* the state file, B is not found in this file and therefore not |
157 |
* changed. |
* changed. |
158 |
* |
* |
159 |
* The same strategy is used if a process was removed, e.g. if the |
* The same strategy is used if a service was removed, e.g. if the |
160 |
* process A was removed from monitrc; when reading the state file, |
* service A was removed from monitrc; when reading the state file, |
161 |
* process A is not found in the current process list (the list is |
* service A is not found in the current service list (the list is |
162 |
* always generated from monitrc) and therefore A is simply discarded. |
* always generated from monitrc) and therefore A is simply discarded. |
163 |
* |
* |
164 |
* Finally, after the monit process state is updated this function |
* Finally, after the monit service state is updated this function |
165 |
* writes the new state file. |
* writes the new state file. |
166 |
*/ |
*/ |
167 |
void state_update() { |
void state_update() { |
170 |
int l= 0; |
int l= 0; |
171 |
State_T s; |
State_T s; |
172 |
FILE *S= NULL; |
FILE *S= NULL; |
173 |
Process_T new; |
Service_T service; |
174 |
int has_error= FALSE; |
int has_error= FALSE; |
175 |
|
|
176 |
if(! (S= open_state("r"))) |
if(! (S= open_state("r"))) |
192 |
has_error= TRUE; |
has_error= TRUE; |
193 |
goto error; |
goto error; |
194 |
} |
} |
195 |
if((new= get_process(s.name))) { |
if((service= get_service(s.name))) { |
196 |
update_process_state(new, &s); |
update_service_state(service, &s); |
197 |
} |
} |
198 |
} |
} |
199 |
} |
} |
248 |
} |
} |
249 |
|
|
250 |
|
|
251 |
static void clone_state(Process_T p, State_T *s) { |
static void clone_state(Service_T service, State_T *state) { |
252 |
|
|
253 |
memset(s, 0, sizeof(State_T)); |
memset(state, 0, sizeof(State_T)); |
254 |
|
|
255 |
strncpy(s->name, p->name, STRLEN); |
strncpy(state->name, service->name, STRLEN); |
256 |
s->mode= p->mode; |
state->mode= service->mode; |
257 |
s->nstart= p->nstart; |
state->nstart= service->nstart; |
258 |
s->ncycle= p->ncycle; |
state->ncycle= service->ncycle; |
259 |
s->do_validate= p->do_validate; |
state->do_validate= service->do_validate; |
260 |
s->has_checksum_error= p->has_checksum_error; |
state->has_checksum_error= service->has_checksum_error; |
261 |
|
|
262 |
} |
} |
263 |
|
|
264 |
|
|
265 |
static void update_process_state(Process_T p, State_T *s) { |
static void update_service_state(Service_T service, State_T *state) { |
266 |
|
|
267 |
p->mode= s->mode; |
service->mode= state->mode; |
268 |
p->nstart= s->nstart; |
service->nstart= state->nstart; |
269 |
p->ncycle= s->ncycle; |
service->ncycle= state->ncycle; |
270 |
p->do_validate= s->do_validate; |
service->do_validate= state->do_validate; |
271 |
p->has_checksum_error= s->has_checksum_error; |
service->has_checksum_error= state->has_checksum_error; |
272 |
|
|
273 |
} |
} |