/* * Copyright (C), 2000-2007 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 3 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, see . */ #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 1024 /* 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.9 2007/07/25 12:54:32 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) { LogError("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) { int scored = 0; int errors = 0; char line[READ_SIZE]; char search_string[READ_SIZE]; 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, READ_SIZE)) { if(Util_startsWith(line, "Scoreboard")) { if(1 != sscanf(line, "%*s%*[: ]%s", search_string)) { Util_chomp(line); LogError("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){ LogError("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){ LogError("APACHE-STATUS warning: No idle server or threads found\n"); /* This is not really an error, only a very bussy server */ return TRUE; } /* * Conditions are only tested if the limit parameter is greater than zero. */ if(loglimit > 0){ if(Util_evalQExpression(myPort->ApacheStatus.loglimitOP, (100 * no_logging / active_servers), loglimit)) { LogError("APACHE-STATUS error:" " %i percent of Apache processes are logging\n", loglimit); errors++; } } if(startlimit > 0){ if(Util_evalQExpression(myPort->ApacheStatus.startlimitOP, (100 * no_start / active_servers), startlimit)) { LogError("APACHE-STATUS error:" " %i percent of Apache processes are starting\n", startlimit); errors++; } } if(requestlimit > 0){ if(Util_evalQExpression(myPort->ApacheStatus.requestlimitOP, (100 * no_request / active_servers), requestlimit)) { LogError("APACHE-STATUS error:" " %i percent of Apache processes are reading requests\n", requestlimit); errors++; } } if(replylimit > 0 ){ if(Util_evalQExpression(myPort->ApacheStatus.replylimitOP, (100 * no_reply / active_servers), replylimit)) { LogError("APACHE-STATUS error:" " %i percent of Apache processes are sending a reply\n", replylimit); errors++; } } if(keepalivelimit > 0){ if(Util_evalQExpression(myPort->ApacheStatus.keepalivelimitOP, (100 * no_keepalive / active_servers), keepalivelimit)) { LogError("APACHE-STATUS error:" " %i percent of Apache processes are in keepalive\n", keepalivelimit); errors++; } } if(dnslimit > 0){ if(Util_evalQExpression(myPort->ApacheStatus.dnslimitOP, (100 * no_dns / active_servers), dnslimit)) { LogError("APACHE-STATUS error:" " %i percent of Apache processes are waiting for DNS\n", dnslimit); errors++; } } if(closelimit > 0){ if(Util_evalQExpression(myPort->ApacheStatus.closelimitOP, (100 * no_close / active_servers), closelimit)){ LogError("APACHE-STATUS error:" " %i percent of Apache processes are closing connections\n", closelimit); errors++; } } if(gracefullimit > 0){ if(Util_evalQExpression(myPort->ApacheStatus.gracefullimitOP, (100 * no_graceful / active_servers), gracefullimit)) { LogError("APACHE-STATUS error:" " %i percent of Apache processes are finishing gracefully\n", gracefullimit); errors++; } } if(cleanuplimit > 0){ if(Util_evalQExpression(myPort->ApacheStatus.cleanuplimitOP, (100 * no_cleanup / active_servers), cleanuplimit)) { LogError("APACHE-STATUS error:" " %i percent of Apache processes are in idle cleanup\n", cleanuplimit); errors++; } } if(waitlimit > 0){ if(Util_evalQExpression(myPort->ApacheStatus.waitlimitOP, (100 * no_wait / active_servers), waitlimit)) { LogError("APACHE-STATUS error:" " %i percent of Apache processes are waiting for a connection\n", waitlimit); errors++; } } return (errors==0); }