/* * Copyright (C), 2000-2003 by Contributors to the monit codebase. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #ifdef HAVE_STRING_H #include #endif #ifdef HAVE_STRINGS_H #include #endif #include "alert.h" #include "event.h" /** * Implementation of the event interface. * * NOTE1: Some event handlers are placed as functions in this file. In * the future and if there is a need for more flexibility; It is easy * to setup event handlers as callback functions and register them in * this class. Every event handler will have this signature: * * void handle_xxx_events(Event_T E); * * NOTE2: It's possible to do the call to handle_event() in a new * thread to make the event handling non-sequential and more * responsive. We have to double check the thread-safeness of the code * first though. * * @author Jan-Henrik Haukeland, * @version \$Id: event.c,v 1.1 2003/07/02 19:32:02 hauk Exp $ * @file */ /* ------------------------------------------------------------- Definitions */ struct Event_T { int id; char *message; Service_T source; }; struct Event_Table { int id; char description[STRLEN]; } Event_Table[]= { {EVENT_NULL, "No Event"}, {EVENT_FAILED, "Failed"}, {EVENT_START, "Start"}, {EVENT_STOP, "Stop"}, {EVENT_RESTART, "Restart"}, {EVENT_CHECKSUM, "Checksum error"}, {EVENT_RESOURCE, "Resource limit matched"}, {EVENT_TIMEOUT, "Timeout"}, {EVENT_TIMESTAMP, "Timestamp error"}}; /* -------------------------------------------------------------- Prototypes */ static void handle_event(Event_T E); static void handle_stop(Event_T E); static void handle_start(Event_T E); static void handle_restart(Event_T E); static void swap_message(Event_T E, char *new_message, ...); /* ------------------------------------------------------------------ Public */ /** * Construct and post a new Event * @param source The Service the event occured on * @param id The event type * @param s Optional message describing the event */ void Event_post(Service_T source, long id, char *s, ...) { Event_T e; ASSERT(source); NEW(e); e->id= id; e->message= NULL; e->source= source; if(s) { va_list ap; va_start(ap, s); e->message= format(s, ap); va_end(ap); } handle_event(e); } /** * Destroy an Event object and release allocated resources. * @param E An Event object reference */ void Event_free(Event_T *E) { ASSERT(E && *E); if((*E)->message) free((*E)->message); free(*E); (*E)= NULL; } /** * Get the Service where the event orginated * @param E An event object * @return The Service where the event orginated */ Service_T Event_get_source(Event_T E) { ASSERT(E); return E->source; } /** * Get the Event type * @param E An event object * @return The Event type */ int Event_get_id(Event_T E) { ASSERT(E); return E->id; } /** * Get the optionally Event message describing why the event was * fired. * @param E An event object * @return The Event message. May be NULL */ const char *Event_get_message(Event_T E) { ASSERT(E); return E->message; } /** * Get a textual description of the event type. For instance if the * event type is EVENT_RESTART, the textual description is * "Restart". Likewise if the event type is EVENT_CHECKSUM the textual * description is "Checksum error" and so on. * @param E An event object * @return A string describing the event type in clear text. If the * event type is not found NULL is returned. */ const char *Event_get_description(Event_T E) { int i; int size= sizeof(Event_Table)/sizeof(Event_Table[0]); ASSERT(E); for(i= 0; i < size; i++) if(E->id == Event_Table[i].id) return Event_Table[i].description; return NULL; } /* ----------------------------------------------------------------- Private */ /* * Handle the event * @param E An event */ static void handle_event(Event_T E) { ASSERT(E); /* Handle action events */ switch(E->id) { case EVENT_START: handle_start(E); break; case EVENT_STOP: handle_stop(E); break; case EVENT_RESTART: handle_restart(E); break; } if(E->id == EVENT_NULL) { /* The event was consumed by an action handler */ return; } handle_alert_event(E); /* TODO: handle_exec_event(E); */ Event_free(&E); } /* ---------------------------------------------------------- Event handlers */ static void handle_stop(Event_T E) { LOCK(Run.mutex) E->source->do_monitor= FALSE; END_LOCK; if(E->source->mode != MODE_PASSIVE) { check_service(E->source->name, "stop"); if(is_process_running(E->source)) { E->id= EVENT_FAILED; swap_message(E, "Failed to stop service '%s'", E->source->name); } } else { /* Set the 0 event so this event is not handled in subsequent handlers */ E->id= EVENT_NULL; } } static void handle_start(Event_T E) { if(E->source->def_timeout) E->source->nstart++; if(E->source->mode != MODE_PASSIVE) { check_service(E->source->name, "start"); if(!is_process_running(E->source)) { E->id= EVENT_FAILED; swap_message(E, "Failed to start service '%s'", E->source->name); } } else { /* Set the 0 event so this event is not handled in subsequent handlers */ E->id= EVENT_NULL; } } static void handle_restart(Event_T E) { if(E->source->def_timeout) E->source->nstart++; if(E->source->mode != MODE_PASSIVE) { check_service(E->source->name, "restart"); if(!is_process_running(E->source)) { E->id= EVENT_FAILED; swap_message(E, "Failed to restart service '%s'", E->source->name); } } else { /* Set the 0 event so this event is not handled in subsequent handlers */ E->id= EVENT_NULL; } } /* ----------------------------------------------------------------- Private */ static void swap_message(Event_T E, char *new_message, ...) { free(E->message); if(new_message) { va_list ap; va_start(ap, new_message); E->message= format(new_message, ap); va_end(ap); } }