/* * Copyright (C), 2000-2004 by the monit project group. * 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 #ifdef HAVE_STDIO_H #include #endif #ifdef HAVE_ERRNO_H #include #endif #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef HAVE_NETINET_IN_H #include #endif #include "protocol.h" #undef READ_SIZE #define READ_SIZE 8192 /* Private prototypes */ static int check_apache_stat(Socket_T s); /** * Check an Apache server to monitor its status. * Do this using the server-status report from mod_status, which * will only be available if the server is responding to * some extent. * * Currently based on the Scoreboard response, which is available * even with ExtendedStatus Off on Apache config file. * * @author David Fletcher, * @version \$Id: apache_status.c,v 1.1 2004/12/12 23:45:09 hauk Exp $ * @file */ int check_apache_status(Socket_T s) { char host[STRLEN]; const char *request= "/server-status?auto"; ASSERT(s); if(socket_print(s, "GET %s HTTP/1.1\r\n" "Host: %s\r\n" "Accept: */*\r\n" "User-Agent: %s/%s\r\n" "Connection: close\r\n\r\n", request, Util_getHTTPHostHeader(s, host, STRLEN), prog, VERSION) < 0) { log("HTTP: error sending data -- %s\n", STRERROR); return FALSE; } return check_apache_stat(s); } /* ----------------------------------------------------------------- Private */ /** * Extract the Scoreboard line from the mod_status response. * Count the active apache child processes, and those which are * in other states. If each percentage exceeds the corresponding * limit, then return FALSE. * @param s A socket * @param limit The maximum percentage of logging processes * @return TRUE if logging is OK otherwise FALSE */ static int check_apache_stat(Socket_T s) { char line[STRLEN]; char search_string[STRLEN]; int scored = 0; int tests = 0; int errors = 0; int loglimit= 0; int closelimit= 0; int dnslimit= 0; int keepalivelimit= 0; int replylimit= 0; int requestlimit= 0; int startlimit= 0; int waitlimit= 0; int gracefullimit= 0; int cleanuplimit= 0; int no_logging = 0; int no_close = 0; int no_dns = 0; int no_keepalive = 0; int no_reply = 0; int no_request = 0; int no_start = 0; int no_wait = 0; int no_graceful = 0; int no_cleanup = 0; int active_servers = 0; char *p; Port_T myPort= (Port_T)socket_get_Port(s); ASSERT(myPort); loglimit= myPort->ApacheStatus.loglimit; closelimit= myPort->ApacheStatus.closelimit; dnslimit= myPort->ApacheStatus.dnslimit; keepalivelimit= myPort->ApacheStatus.keepalivelimit; replylimit= myPort->ApacheStatus.replylimit; requestlimit= myPort->ApacheStatus.requestlimit; startlimit= myPort->ApacheStatus.startlimit; waitlimit= myPort->ApacheStatus.waitlimit; gracefullimit= myPort->ApacheStatus.gracefullimit; cleanuplimit= myPort->ApacheStatus.cleanuplimit; while(NULL != socket_readln(s, line, STRLEN)) { if(Util_startsWith(line, "Scoreboard")) { if(1 != sscanf(line, "%*s%*[: ]%s", search_string)) { Util_chomp(line, STRLEN); log("APACHE-STATUS error: parsing Apache status response '%s'\n", line); return FALSE; }else{ scored = 1; } } } DEBUG("Scoreboard: %s\n", search_string); /*Check that some scoreboard line was found, if not return an error*/ if(!scored){ log("APACHE-STATUS error: no scoreboard line returned by Apache\n"); return FALSE; } /* Total each of the status messages in the scoreboard */ for(p = search_string ; *p ; p++){ active_servers++; switch(*p){ case 'S': no_start++; break; case 'R': no_request++; break; case 'W': no_reply++; break; case 'K': no_keepalive++; break; case 'D': no_dns++; break; case 'C': no_close++; break; case 'L': no_logging++; break; case 'G': no_graceful++; break; case 'I': no_cleanup++; break; case '_': no_wait++; break; case '.': active_servers--; break; } } if(active_servers <= 0){ log("APACHE-STATUS error: No active servers found\n"); return FALSE; } /* * Conditions are only tested if the limit parameter is greater than zero. */ if(loglimit > 0){ tests++; if(Util_evalQExpression(myPort->ApacheStatus.loglimitOP, (100 * no_logging / active_servers), loglimit)) { log("APACHE-STATUS error:" " %i percent of Apache processes are logging\n", loglimit); errors++; } } if(startlimit > 0){ tests++; if(Util_evalQExpression(myPort->ApacheStatus.startlimitOP, (100 * no_start / active_servers), startlimit)) { log("APACHE-STATUS error:" " %i percent of Apache processes are starting\n", startlimit); errors++; } } if(requestlimit > 0){ tests++; if(Util_evalQExpression(myPort->ApacheStatus.requestlimitOP, (100 * no_request / active_servers), requestlimit)) { log("APACHE-STATUS error:" " %i percent of Apache processes are reading requests\n", requestlimit); errors++; } } if(replylimit > 0 ){ tests++; if(Util_evalQExpression(myPort->ApacheStatus.replylimitOP, (100 * no_reply / active_servers), replylimit)) { log("APACHE-STATUS error:" " %i percent of Apache processes are sending a reply\n", replylimit); errors++; } } if(keepalivelimit > 0){ tests++; if(Util_evalQExpression(myPort->ApacheStatus.keepalivelimitOP, (100 * no_keepalive / active_servers), keepalivelimit)) { log("APACHE-STATUS error:" " %i percent of Apache processes are in keepalive\n", keepalivelimit); errors++; } } if(dnslimit > 0){ tests++; if(Util_evalQExpression(myPort->ApacheStatus.dnslimitOP, (100 * no_dns / active_servers), dnslimit)) { log("APACHE-STATUS error:" " %i percent of Apache processes are waiting for DNS\n", dnslimit); errors++; } } if(closelimit > 0){ tests++; if(Util_evalQExpression(myPort->ApacheStatus.closelimitOP, (100 * no_close / active_servers), closelimit)){ log("APACHE-STATUS error:" " %i percent of Apache processes are closing connections\n", closelimit); errors++; } } if(gracefullimit > 0){ tests++; if(Util_evalQExpression(myPort->ApacheStatus.gracefullimitOP, (100 * no_graceful / active_servers), gracefullimit)) { log("APACHE-STATUS error:" " %i percent of Apache processes are finishing gracefully\n", gracefullimit); errors++; } } if(cleanuplimit > 0){ tests++; if(Util_evalQExpression(myPort->ApacheStatus.cleanuplimitOP, (100 * no_cleanup / active_servers), cleanuplimit)) { log("APACHE-STATUS error:" " %i percent of Apache processes are in idle cleanup\n", cleanuplimit); errors++; } } if(waitlimit > 0){ tests++; if(Util_evalQExpression(myPort->ApacheStatus.waitlimitOP, (100 * no_wait / active_servers), waitlimit)) { log("APACHE-STATUS error:" " %i percent of Apache processes are waiting for a connection\n", waitlimit); errors++; } } /* If no tests have been specified just return true. This should been catched by the parser */ if(tests == 0){ DEBUG("APACHE-STATUS warning: no tests given to perform\n"); return TRUE; } /* Single and multple tests return here, if all are failed */ if(errors == tests) return FALSE; /* Single test passed, or multiple tests but not all failed */ return TRUE; }