72 |
|
|
73 |
static int check_skip(Service_T); |
static int check_skip(Service_T); |
74 |
static void connection_timeout(int); |
static void connection_timeout(int); |
|
static int check_timeout(Service_T); |
|
|
static int check_checksum(Service_T); |
|
|
static int do_not_validate(Service_T); |
|
75 |
static int compare_value(int, int, int); |
static int compare_value(int, int, int); |
76 |
static void reset_resource_counter(Service_T); |
static void reset_resource_counter(Service_T); |
77 |
|
|
78 |
|
static int check_process(Service_T, ProcessTree_T *, int); |
79 |
static int check_process_state(Service_T, char *); |
static int check_process_state(Service_T, char *); |
80 |
static int check_device(Service_T, Device_T, char *); |
static int check_process_resources(Service_T, Resource_T, char *); |
81 |
static int check_connection(Service_T, Port_T, char *); |
static int check_process_connection(Service_T, Port_T, char *); |
|
static void do_validate(Service_T, ProcessTree_T *, int); |
|
|
static int check_resources(Service_T, Resource_T, char *); |
|
|
static int check_timestamp(Service_T, Timestamp_T, char *); |
|
|
static void vlog(char * report, int n, Service_T s, char *m,...); |
|
82 |
|
|
83 |
|
static int check_device(Service_T); |
84 |
|
static int check_device_resources(Service_T, Device_T, char *); |
85 |
|
|
86 |
|
static int check_file(Service_T); |
87 |
|
|
88 |
|
static int check_directory(Service_T); |
89 |
|
|
90 |
|
static int check_timestamps(Service_T); |
91 |
|
static int check_timestamp_item(Service_T, Timestamp_T, char *); |
92 |
|
|
93 |
|
static int check_timeout(Service_T); |
94 |
|
|
95 |
|
static int check_checksum(Service_T); |
96 |
|
|
97 |
|
static void do_validate(Service_T, ProcessTree_T *, int); |
98 |
|
static int do_not_validate(Service_T); |
99 |
|
static void vlog(char *, int, Service_T, char *,...); |
100 |
|
static int eval_actions(int, Service_T, char *, char *, int); |
101 |
|
|
102 |
/* ---------------------------------------------------------------- Public */ |
/* ---------------------------------------------------------------- Public */ |
103 |
|
|
153 |
*/ |
*/ |
154 |
static void do_validate(Service_T s, ProcessTree_T * pt, int treesize) { |
static void do_validate(Service_T s, ProcessTree_T * pt, int treesize) { |
155 |
|
|
|
Port_T pp; |
|
|
Device_T td; |
|
|
Resource_T pr; |
|
|
Timestamp_T tl; |
|
|
pid_t pid= -1; |
|
156 |
sigset_t ns,os; |
sigset_t ns,os; |
|
char report[STRLEN]; |
|
|
struct stat stat_buf; |
|
157 |
|
|
158 |
ASSERT(s); |
ASSERT(s); |
159 |
ASSERT(s->path); |
ASSERT(s->path); |
179 |
|
|
180 |
case TASK_PROCESS: |
case TASK_PROCESS: |
181 |
|
|
182 |
/* Test for running process */ |
if (! check_process(s, pt, treesize)) |
183 |
if(!(pid= is_process_running(s))) { |
goto reinstall; |
184 |
|
|
185 |
/* Reset the proc info object to prevent false data in the first run */ |
break; |
186 |
memset(s->procinfo, 0, sizeof *(s->procinfo)); |
|
187 |
|
case TASK_DEVICE: |
188 |
Event_post(s, EVENT_START, "Reason: Process is not running."); |
|
189 |
|
if (! check_device(s)) |
190 |
goto reinstall; |
goto reinstall; |
|
|
|
|
} else { |
|
|
|
|
|
DEBUG("'%s' is running with pid %d\n", s->name, (int)pid); |
|
|
|
|
|
} |
|
191 |
|
|
192 |
if(Run.doprocess) { |
break; |
193 |
|
|
194 |
if(update_process_data(s, pt, treesize, pid)) { |
|
195 |
|
case TASK_FILE: |
196 |
|
|
197 |
|
if (! check_file(s)) |
198 |
|
goto reinstall; |
199 |
|
|
200 |
|
break; |
201 |
|
|
202 |
|
case TASK_DIRECTORY: |
203 |
|
|
204 |
|
if (! check_directory(s)) |
205 |
|
goto reinstall; |
206 |
|
|
207 |
|
break; |
208 |
|
|
209 |
|
default: |
210 |
|
break; |
211 |
|
|
212 |
|
} |
213 |
|
|
214 |
|
/** Common task actions */ |
215 |
|
if (! check_timestamps(s)) |
216 |
|
goto reinstall; |
217 |
|
|
218 |
|
|
219 |
|
reinstall: |
220 |
|
|
221 |
if(! check_process_state(s, report)) { |
/* Remove the SIGTERM block */ |
222 |
|
pthread_sigmask(SIG_SETMASK, &os, NULL); |
223 |
|
|
224 |
Event_post(s, EVENT_RESOURCE, "Reason: %s\n", report); |
/* Release service action mutex */ |
225 |
|
END_LOCK; |
226 |
|
|
227 |
|
} |
228 |
|
|
229 |
|
|
230 |
|
/** |
231 |
|
* Returns the logical OR of pre-condition tests. |
232 |
|
* A variant of the template-method pattern |
233 |
|
*/ |
234 |
|
static int do_not_validate(Service_T s) { |
235 |
|
|
236 |
|
ASSERT(s); |
237 |
|
|
238 |
|
return(!s->do_monitor || |
239 |
|
check_skip(s) || |
240 |
|
check_timeout(s) || |
241 |
|
check_checksum(s)); |
242 |
|
|
243 |
|
} |
244 |
|
|
245 |
|
|
246 |
|
/** |
247 |
|
* Evaluate actions of a service. Post appropriate actions if necessary. |
248 |
|
* Return FALSE in case of a fatal event. |
249 |
|
*/ |
250 |
|
static int eval_actions(int action, Service_T s, char *report, char *check, |
251 |
|
int alert_event) { |
252 |
|
|
253 |
|
ASSERT(s); |
254 |
|
ASSERT(report); |
255 |
|
ASSERT(check); |
256 |
|
|
257 |
|
switch(action) { |
258 |
|
case ACTION_ALERT: |
259 |
|
if(s->def_timeout) s->nstart++; |
260 |
|
Event_post(s, alert_event, "Reason: %s\n", report); |
261 |
|
break; /* continue */ |
262 |
|
|
263 |
} else { |
case ACTION_STOP: |
264 |
|
Event_post(s, EVENT_STOP, "Reason: %s\n", report); |
265 |
DEBUG("'%s' check_process_state() passed.\n", s->name); |
return FALSE; |
|
|
|
|
} |
|
266 |
|
|
267 |
for(pr= s->resourcelist; pr; pr= pr->next) { |
case ACTION_RESTART: |
268 |
|
Event_post(s, EVENT_RESTART, "Reason: %s\n", report); |
269 |
if(!check_resources(s, pr, report)) { |
return FALSE; |
270 |
|
|
271 |
switch(pr->action) { |
default: |
272 |
case ACTION_ALERT: |
log("'%s' Unknow %s failure action.\n", s->name, check); |
273 |
if(s->def_timeout) s->nstart++; |
break; |
274 |
Event_post(s, EVENT_RESOURCE, "Reason: %s\n", report); |
|
275 |
/* We are also interested in other alerts/stops/restarts! */ |
} |
|
pr->cycle=0; |
|
|
break; |
|
276 |
|
|
277 |
case ACTION_STOP: |
return TRUE; |
278 |
Event_post(s, EVENT_STOP, "Reason: %s\n", report); |
} |
|
reset_resource_counter(s); |
|
|
goto reinstall; |
|
279 |
|
|
|
case ACTION_RESTART: |
|
|
Event_post(s, EVENT_RESTART, "Reason: %s\n", report); |
|
|
reset_resource_counter(s); |
|
|
goto reinstall; |
|
280 |
|
|
281 |
default: |
/** |
282 |
log("'%s' Unknow resource failure action.\n", s->name); |
* Validate all given timestamps of a service s. Events are posted according |
283 |
break; |
* to its configuration. In case of a fatal event FALSE is returned. |
284 |
} |
*/ |
285 |
|
static int check_timestamps(Service_T s) { |
286 |
|
|
287 |
} |
Timestamp_T tl; |
288 |
|
char report[STRLEN]; |
|
} |
|
|
|
|
|
} else { |
|
289 |
|
|
290 |
log("'%s' failed to get service data\n", s->name); |
for(tl= s->timestamplist; tl; tl= tl->next) { |
291 |
|
|
292 |
} |
if(!check_timestamp_item(s, tl, report)) { |
293 |
|
|
294 |
|
if (! eval_actions(tl->action, s, report, "timestamp", |
295 |
|
EVENT_TIMESTAMP)) { |
296 |
|
|
297 |
|
return FALSE; |
298 |
|
|
299 |
} |
} |
300 |
|
|
|
/* Test each host:port and protocol in the service's portlist */ |
|
|
for(pp= s->portlist; pp; pp= pp->next) { |
|
|
|
|
|
if(!check_connection(s, pp, report)) { |
|
|
|
|
|
Event_post(s, EVENT_RESTART, "Reason: %s\n", report); |
|
|
goto reinstall; |
|
|
|
|
|
} |
|
|
|
|
301 |
} |
} |
|
break; |
|
302 |
|
|
303 |
case TASK_DEVICE: |
} |
304 |
|
|
305 |
/* Test devices */ |
return TRUE; |
|
if(s->devicelist) { |
|
306 |
|
|
307 |
if(!get_fsusage(s->path, s->devinfo)) { |
} |
|
Event_post(s, EVENT_RESTART, "Reason: unable to read device state\n"); |
|
|
goto reinstall; |
|
|
} |
|
308 |
|
|
309 |
for(td= s->devicelist; td; td= td->next) { |
/** |
310 |
|
* Validate a given directory service s. Events are posted according to |
311 |
|
* its configuration. In case of a fatal event FALSE is returned. |
312 |
|
*/ |
313 |
|
static int check_directory(Service_T s) { |
314 |
|
|
315 |
if(!check_device(s, td, report)) { |
struct stat stat_buf; |
316 |
|
|
317 |
switch(td->action) { |
if(stat(s->path, &stat_buf) != 0) { |
|
case ACTION_ALERT: |
|
|
Event_post(s, EVENT_RESOURCE, "Reason: %s\n", report); |
|
|
break; |
|
|
|
|
|
case ACTION_STOP: |
|
|
Event_post(s, EVENT_STOP, "Reason: %s\n", report); |
|
|
goto reinstall; |
|
|
|
|
|
case ACTION_RESTART: |
|
|
Event_post(s, EVENT_RESTART, "Reason: %s\n", report); |
|
|
goto reinstall; |
|
|
|
|
|
default: |
|
|
log("'%s' Unknow device failure action.\n", s->name); |
|
|
break; |
|
|
} |
|
318 |
|
|
319 |
} |
log("'%s' doesn't exist\n", s->name); |
320 |
|
Event_post(s, EVENT_RESTART, "Reason: directory doesn't exist\n"); |
321 |
|
return FALSE; |
322 |
|
|
323 |
} |
} |
324 |
|
|
325 |
} |
if(!S_ISDIR(stat_buf.st_mode)) { |
|
break; |
|
326 |
|
|
327 |
case TASK_FILE: |
log("'%s' is not directory\n", s->name); |
328 |
|
Event_post(s, EVENT_RESTART, "Reason: object is not directory\n"); |
329 |
|
return FALSE; |
330 |
|
|
331 |
if(stat(s->path, &stat_buf) != 0) { |
} |
|
log("'%s' doesn't exist\n", s->name); |
|
|
Event_post(s, EVENT_RESTART, "Reason: file doesn't exist\n"); |
|
|
goto reinstall; |
|
|
} |
|
332 |
|
|
333 |
if(!S_ISREG(stat_buf.st_mode)) { |
if( s->perm != -1 && (stat_buf.st_mode & 07777) != s->perm ) { |
|
log("'%s' is not regular file\n", s->name); |
|
|
Event_post(s, EVENT_RESTART, "Reason: object is not file\n"); |
|
|
goto reinstall; |
|
|
} |
|
334 |
|
|
335 |
if( s->perm != -1 && (stat_buf.st_mode & 07777) != s->perm ) { |
log("'%s' permission test failed -- current permission: %o\n", |
|
log("'%s' permission test failed -- current permission: %o\n", |
|
336 |
s->name, stat_buf.st_mode&07777); |
s->name, stat_buf.st_mode&07777); |
337 |
Event_post(s, EVENT_RESTART, "Reason: permission test failed: %o\n", |
Event_post(s, EVENT_RESTART, "Reason: permission test failed: %o\n", |
338 |
stat_buf.st_mode&07777); |
stat_buf.st_mode&07777); |
339 |
goto reinstall; |
return FALSE; |
|
} |
|
340 |
|
|
341 |
DEBUG("'%s' file permission check passed [current permission=%o]\n", |
} |
|
s->name, stat_buf.st_mode&07777); |
|
342 |
|
|
343 |
break; |
DEBUG("'%s' directory permission check passed [current permission=%o]\n", |
344 |
|
s->name, stat_buf.st_mode&07777); |
345 |
|
|
346 |
case TASK_DIRECTORY: |
return TRUE; |
347 |
|
|
348 |
if(stat(s->path, &stat_buf) != 0) { |
} |
|
log("'%s' doesn't exist\n", s->name); |
|
|
Event_post(s, EVENT_RESTART, "Reason: directory doesn't exist\n"); |
|
|
goto reinstall; |
|
|
} |
|
349 |
|
|
350 |
if(!S_ISDIR(stat_buf.st_mode)) { |
/** |
351 |
log("'%s' is not directory\n", s->name); |
* Validate a given file service s. Events are posted according to |
352 |
Event_post(s, EVENT_RESTART, "Reason: object is not directory\n"); |
* its configuration. In case of a fatal event FALSE is returned. |
353 |
goto reinstall; |
*/ |
354 |
} |
static int check_file(Service_T s) { |
355 |
|
|
356 |
if( s->perm != -1 && (stat_buf.st_mode & 07777) != s->perm ) { |
struct stat stat_buf; |
|
log("'%s' permission test failed -- current permission: %o\n", |
|
|
s->name, stat_buf.st_mode&07777); |
|
|
Event_post(s, EVENT_RESTART, "Reason: permission test failed: %o\n", |
|
|
stat_buf.st_mode&07777); |
|
|
goto reinstall; |
|
|
} |
|
357 |
|
|
358 |
DEBUG("'%s' directory permission check passed [current permission=%o]\n", |
if(stat(s->path, &stat_buf) != 0) { |
|
s->name, stat_buf.st_mode&07777); |
|
359 |
|
|
360 |
break; |
log("'%s' doesn't exist\n", s->name); |
361 |
|
Event_post(s, EVENT_RESTART, "Reason: file doesn't exist\n"); |
362 |
|
return FALSE; |
363 |
|
|
364 |
default: |
} |
365 |
break; |
|
366 |
|
if(!S_ISREG(stat_buf.st_mode)) { |
367 |
|
|
368 |
|
log("'%s' is not regular file\n", s->name); |
369 |
|
Event_post(s, EVENT_RESTART, "Reason: object is not file\n"); |
370 |
|
return FALSE; |
371 |
|
|
372 |
} |
} |
373 |
|
|
374 |
|
if( s->perm != -1 && (stat_buf.st_mode & 07777) != s->perm ) { |
375 |
|
|
376 |
|
log("'%s' permission test failed -- current permission: %o\n", |
377 |
|
s->name, stat_buf.st_mode&07777); |
378 |
|
Event_post(s, EVENT_RESTART, "Reason: permission test failed: %o\n", |
379 |
|
stat_buf.st_mode&07777); |
380 |
|
return FALSE; |
381 |
|
|
382 |
/** Common task actions */ |
} |
383 |
for(tl= s->timestamplist; tl; tl= tl->next) { |
|
384 |
|
DEBUG("'%s' file permission check passed [current permission=%o]\n", |
385 |
|
s->name, stat_buf.st_mode&07777); |
386 |
|
|
387 |
|
return TRUE; |
388 |
|
|
389 |
|
} |
390 |
|
|
391 |
|
/** |
392 |
|
* Validate a given device service s. Events are posted according to |
393 |
|
* its configuration. In case of a fatal event FALSE is returned. |
394 |
|
*/ |
395 |
|
static int check_device(Service_T s) { |
396 |
|
|
397 |
|
Device_T td; |
398 |
|
char report[STRLEN]; |
399 |
|
|
400 |
|
/* Test devices */ |
401 |
|
if(s->devicelist) { |
402 |
|
|
403 |
|
if(!get_fsusage(s->path, s->devinfo)) { |
404 |
|
|
405 |
if(!check_timestamp(s, tl, report)) { |
Event_post(s, EVENT_RESTART, "Reason: unable to read device state\n"); |
406 |
|
return FALSE; |
407 |
|
|
408 |
|
} |
409 |
|
|
410 |
|
for(td= s->devicelist; td; td= td->next) { |
411 |
|
|
412 |
|
if(!check_device_resources(s, td, report)) { |
413 |
|
|
414 |
switch(tl->action) { |
if (! eval_actions(td->action, s, report, "device", |
415 |
case ACTION_ALERT: |
EVENT_RESOURCE)) { |
|
if(s->def_timeout) s->nstart++; |
|
|
Event_post(s, EVENT_TIMESTAMP, "Reason: %s\n", report); |
|
|
break; /* continue */ |
|
416 |
|
|
417 |
case ACTION_STOP: |
return FALSE; |
418 |
Event_post(s, EVENT_STOP, "Reason: %s\n", report); |
|
419 |
goto reinstall; |
} |
420 |
|
|
|
case ACTION_RESTART: |
|
|
Event_post(s, EVENT_RESTART, "Reason: %s\n", report); |
|
|
goto reinstall; |
|
|
|
|
|
default: |
|
|
log("'%s' Unknow timestamp failure action.\n", s->name); |
|
|
break; |
|
|
|
|
421 |
} |
} |
422 |
|
|
423 |
} |
} |
424 |
|
|
425 |
|
} |
426 |
|
|
427 |
} |
return TRUE; |
|
|
|
|
reinstall: |
|
|
|
|
|
/* Remove the SIGTERM block */ |
|
|
pthread_sigmask(SIG_SETMASK, &os, NULL); |
|
428 |
|
|
|
/* Release service action mutex */ |
|
|
END_LOCK; |
|
|
|
|
429 |
} |
} |
430 |
|
|
|
|
|
431 |
/** |
/** |
432 |
* Returns the logical OR of pre-condition tests. |
* Validate a given process service s. Events are posted according to |
433 |
* A variant of the template-method pattern |
* its configuration. In case of a fatal event FALSE is returned. |
434 |
*/ |
*/ |
435 |
static int do_not_validate(Service_T s) { |
static int check_process(Service_T s, ProcessTree_T * pt, int treesize) { |
436 |
|
|
437 |
ASSERT(s); |
Port_T pp; |
438 |
|
Resource_T pr; |
439 |
|
pid_t pid= -1; |
440 |
|
char report[STRLEN]; |
441 |
|
|
442 |
return(!s->do_monitor || |
/* Test for running process */ |
443 |
check_skip(s) || |
if(!(pid= is_process_running(s))) { |
|
check_timeout(s) || |
|
|
check_checksum(s)); |
|
444 |
|
|
445 |
} |
/* Reset the proc info object to prevent false data in the first run */ |
446 |
|
memset(s->procinfo, 0, sizeof *(s->procinfo)); |
447 |
|
|
448 |
|
Event_post(s, EVENT_START, "Reason: Process is not running."); |
449 |
|
return FALSE; |
450 |
|
|
451 |
|
} else { |
452 |
|
|
453 |
|
DEBUG("'%s' is running with pid %d\n", s->name, (int)pid); |
454 |
|
|
455 |
|
} |
456 |
|
|
457 |
|
if(Run.doprocess) { |
458 |
|
|
459 |
|
if(update_process_data(s, pt, treesize, pid)) { |
460 |
|
|
461 |
|
if(! check_process_state(s, report)) { |
462 |
|
|
463 |
|
Event_post(s, EVENT_RESOURCE, "Reason: %s\n", report); |
464 |
|
|
465 |
|
} else { |
466 |
|
|
467 |
|
DEBUG("'%s' check_process_state() passed.\n", s->name); |
468 |
|
|
469 |
|
} |
470 |
|
|
471 |
|
for(pr= s->resourcelist; pr; pr= pr->next) { |
472 |
|
|
473 |
|
if(!check_process_resources(s, pr, report)) { |
474 |
|
|
475 |
|
pr->cycle=0; |
476 |
|
|
477 |
|
if (! eval_actions(pr->action, s, report, "resource", |
478 |
|
EVENT_TIMESTAMP)) { |
479 |
|
|
480 |
|
reset_resource_counter(s); |
481 |
|
return FALSE; |
482 |
|
|
483 |
|
} |
484 |
|
|
485 |
|
} |
486 |
|
|
487 |
|
} |
488 |
|
|
489 |
|
} else { |
490 |
|
|
491 |
|
log("'%s' failed to get service data\n", s->name); |
492 |
|
|
493 |
|
} |
494 |
|
|
495 |
|
} |
496 |
|
|
497 |
|
/* Test each host:port and protocol in the service's portlist */ |
498 |
|
for(pp= s->portlist; pp; pp= pp->next) { |
499 |
|
|
500 |
|
if(!check_process_connection(s, pp, report)) { |
501 |
|
|
502 |
|
Event_post(s, EVENT_RESTART, "Reason: %s\n", report); |
503 |
|
|
504 |
|
return FALSE; |
505 |
|
} |
506 |
|
|
507 |
|
} |
508 |
|
|
509 |
|
|
510 |
|
return TRUE; |
511 |
|
|
512 |
|
} |
513 |
|
|
514 |
/** |
/** |
515 |
* Returns TRUE if the connection and protocol test succeeded |
* Returns TRUE if the connection and protocol test succeeded |
516 |
* otherwise FALSE. |
* otherwise FALSE. |
517 |
*/ |
*/ |
518 |
static int check_connection(Service_T s, Port_T pp, char *report) { |
static int check_process_connection(Service_T s, Port_T pp, char *report) { |
519 |
|
|
520 |
volatile int rv= TRUE; |
volatile int rv= TRUE; |
521 |
|
|
699 |
* Returns TRUE if the proc test succeeded |
* Returns TRUE if the proc test succeeded |
700 |
* otherwise FALSE. |
* otherwise FALSE. |
701 |
*/ |
*/ |
702 |
static int check_resources(Service_T s, Resource_T pr, char *report) { |
static int check_process_resources(Service_T s, Resource_T pr, char *report) { |
703 |
|
|
704 |
ProcInfo_T pi; |
ProcInfo_T pi; |
705 |
int okay= TRUE; |
int okay= TRUE; |
1037 |
/** |
/** |
1038 |
* Returns TRUE if the timestamp test succeded, otherwise FALSE |
* Returns TRUE if the timestamp test succeded, otherwise FALSE |
1039 |
*/ |
*/ |
1040 |
static int check_timestamp(Service_T s, Timestamp_T t, char *report) { |
static int check_timestamp_item(Service_T s, Timestamp_T t, char *report) { |
1041 |
|
|
1042 |
time_t now; |
time_t now; |
1043 |
time_t timestamp; |
time_t timestamp; |
1071 |
* Returns TRUE if the device test succeeded |
* Returns TRUE if the device test succeeded |
1072 |
* otherwise FALSE. |
* otherwise FALSE. |
1073 |
*/ |
*/ |
1074 |
static int check_device(Service_T t, Device_T td, char *report) { |
static int check_device_resources(Service_T t, Device_T td, char *report) { |
1075 |
|
|
1076 |
ASSERT(t); |
ASSERT(t); |
1077 |
ASSERT(td); |
ASSERT(td); |