Logo Search packages:      
Sourcecode: hobbit version File versions  Download package

hobbitd_client.c

/*----------------------------------------------------------------------------*/
/* Hobbit message daemon.                                                     */
/*                                                                            */
/* Client backend module                                                      */
/*                                                                            */
/* Copyright (C) 2005-2006 Henrik Storner <henrik@hswn.dk>                    */
/* "PORT" handling (C) Mirko Saam                                             */
/*                                                                            */
/* This program is released under the GNU General Public License (GPL),       */
/* version 2. See the file "COPYING" for details.                             */
/*                                                                            */
/*----------------------------------------------------------------------------*/

static char rcsid[] = "$Id: hobbitd_client.c,v 1.100 2006/08/09 08:49:19 henrik Rel $";

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
#include <signal.h>
#include <time.h>
#include <ctype.h>
#include <limits.h>

#include "libbbgen.h"
#include "hobbitd_worker.h"
#include "client_config.h"

#define MAX_META 20     /* The maximum number of meta-data items in a message */

enum msgtype_t { MSG_CPU, MSG_DISK, MSG_FILES, MSG_MEMORY, MSG_MSGS, MSG_PORTS, MSG_PROCS, MSG_LAST };

typedef struct sectlist_t {
      char *sname;
      char *sdata;
      struct sectlist_t *next;
} sectlist_t;
sectlist_t *sections = NULL;
int pslistinprocs = 1;
int portlistinports = 1;
int sendclearmsgs = 1;
int sendclearfiles = 1;
int sendclearports = 1;
int localmode     = 0;
int noreportcolor = COL_CLEAR;

void splitmsg(char *clientdata)
{
      char *cursection, *nextsection;
      char *sectname, *sectdata;

      /* Free the old list */
      if (sections) {
            sectlist_t *swalk, *stmp;

            swalk = sections;
            while (swalk) {
                  stmp = swalk;
                  swalk = swalk->next;
                  xfree(stmp);
            }

            sections = NULL;
      }

      if (clientdata == NULL) {
            errprintf("Got a NULL client data message\n");
            return;
      }

      /* Find the start of the first section */
      if (*clientdata == '[') 
            cursection = clientdata; 
      else {
            cursection = strstr(clientdata, "\n[");
            if (cursection) cursection++;
      }

      while (cursection) {
            sectlist_t *newsect = (sectlist_t *)malloc(sizeof(sectlist_t));

            /* Find end of this section (i.e. start of the next section, if any) */
            nextsection = strstr(cursection, "\n[");
            if (nextsection) {
                  *nextsection = '\0';
                  nextsection++;
            }

            /* Pick out the section name and data */
            sectname = cursection+1;
            sectdata = sectname + strcspn(sectname, "]\n");
            *sectdata = '\0'; sectdata++; if (*sectdata == '\n') sectdata++;

            /* Save the pointers in the list */
            newsect->sname = sectname;
            newsect->sdata = sectdata;
            newsect->next = sections;
            sections = newsect;

            /* Next section, please */
            cursection = nextsection;
      }
}

char *getdata(char *sectionname)
{
      sectlist_t *swalk;

      for (swalk = sections; (swalk && strcmp(swalk->sname, sectionname)); swalk = swalk->next) ;
      if (swalk) return swalk->sdata;

      return NULL;
}

int linecount(char *msg)
{
      int result = 0;
      char *nl;

      if (!msg) return 0;

      nl = msg - 1;
      while (nl) {
            nl++; if (*nl >= ' ') result++;
            nl = strchr(nl, '\n');
      }

      return result;
}

int want_msgtype(namelist_t *hinfo, enum msgtype_t msg)
{
      static namelist_t *currhost = NULL;
      static unsigned long currset = 0;

      if (currhost != hinfo) {
            char *val, *tok;

            currhost = hinfo;
            currset = 0;
            val = bbh_item(currhost, BBH_NOCOLUMNS);
            if (val) {
                  val = strdup(val);
                  tok = strtok(val, ",");
                  while (tok) {
                        if      (strcmp(tok, "cpu") == 0) currset |= (1 << MSG_CPU);
                        else if (strcmp(tok, "disk") == 0) currset |= (1 << MSG_DISK);
                        else if (strcmp(tok, "files") == 0) currset |= (1 << MSG_FILES);
                        else if (strcmp(tok, "memory") == 0) currset |= (1 << MSG_MEMORY);
                        else if (strcmp(tok, "msgs") == 0) currset |= (1 << MSG_MSGS);
                        else if (strcmp(tok, "ports") == 0) currset |= (1 << MSG_PORTS);
                        else if (strcmp(tok, "procs") == 0) currset |= (1 << MSG_PROCS);

                        tok = strtok(NULL, ",");
                  }
                  xfree(val);
            }
      }

      return ((currset & (1 << msg)) == 0);
}

void unix_cpu_report(char *hostname, char *clientclass, enum ostype_t os, 
                 namelist_t *hinfo, char *fromline, char *timestr, 
                 char *uptimestr, char *clockstr, char *msgcachestr,
                 char *whostr, char *psstr, char *topstr)
{
      char *p;
      float load1, load5, load15;
      float loadyellow, loadred;
      int recentlimit, ancientlimit, maxclockdiff;
      char loadresult[100];
      long uptimesecs = -1;
      char myupstr[100];

      int cpucolor = COL_GREEN;

      char msgline[4096];
      strbuffer_t *upmsg;

      if (!want_msgtype(hinfo, MSG_CPU)) return;

      if (!uptimestr) return;

      p = strstr(uptimestr, " up ");
      if (p) {
            char *uptimeresult;
            char *daymark;
            char *hourmark;
            long uphour, upmin, upsecs;
            uptimesecs = 0;

            uptimeresult = strdup(p+3);

            /* 
             * Linux: " up 178 days,  9:15,"
             * BSD: ""
             * Solaris: " up 21 days 20:58,"
             */
            daymark = strstr(uptimeresult, " day");
            dbgprintf("CPU check host %s: daymark '%s'\n", hostname, daymark);

            if (daymark) {
                  uptimesecs = atoi(uptimeresult) * 86400;
                  if (strncmp(daymark, " days ", 6) == 0) {
                        hourmark = daymark + 6;
                  }
                  else {
                        hourmark = strchr(daymark, ',');
                        if (hourmark) hourmark++; else hourmark = "";
                  }
            }
            else {
                  hourmark = uptimeresult;
            }

            hourmark += strspn(hourmark, " ");
            dbgprintf("CPU check host %s: hourmark '%s'\n", hostname, hourmark);
            if (sscanf(hourmark, "%ld:%ld", &uphour, &upmin) == 2) {
                  uptimesecs += 60*(60*uphour + upmin);
            }
            else if (sscanf(hourmark, "%ld hours %ld mins", &uphour, &upmin) == 2) {
                  uptimesecs += 60*(60*uphour + upmin);
            }
            else if (strstr(hourmark, " secs") && (sscanf(hourmark, "%ld secs", &upsecs) == 1)) {
                  uptimesecs += upsecs;
            }
            else if (strstr(hourmark, "min") && (sscanf(hourmark, "%ld min", &upmin) == 1)) {
                  uptimesecs += 60*upmin;
            }
            else if (strncmp(hourmark, "1 hr", 4) == 0) {
                  uptimesecs = 3600;
            }
            else {
                  uptimesecs = -1;
            }

            xfree(uptimeresult);
      }

      if (uptimesecs != -1) {
            int days = (uptimesecs / 86400);
            int hours = (uptimesecs % 86400) / 3600;
            int mins = (uptimesecs % 3600) / 60;

            if (days) sprintf(myupstr, "up: %d days", days);
            else sprintf(myupstr, "up: %02d:%02d", hours, mins);
      }
      else *myupstr = '\0';

      *loadresult = '\0';
      p = strstr(uptimestr, "load average: ");
      if (!p) p = strstr(uptimestr, "load averages: "); /* Many BSD's */
      if (p) {
            p = strchr(p, ':') + 1; p += strspn(p, " ");
            if ((sscanf(p, "%f, %f, %f", &load1, &load5, &load15) == 3) ||
                (sscanf(p, "%f %f %f", &load1, &load5, &load15) == 3)) {
                  sprintf(loadresult, "%.2f", load5);
            }
      }

      get_cpu_thresholds(hinfo, clientclass, &loadyellow, &loadred, &recentlimit, &ancientlimit, &maxclockdiff);

      upmsg = newstrbuffer(0);

      if (load5 > loadred) {
            cpucolor = COL_RED;
            addtobuffer(upmsg, "&red Load is CRITICAL\n");
      }
      else if (load5 > loadyellow) {
            cpucolor = COL_YELLOW;
            addtobuffer(upmsg, "&yellow Load is HIGH\n");
      }

      if ((uptimesecs != -1) && (recentlimit != -1) && (uptimesecs < recentlimit)) {
            if (cpucolor == COL_GREEN) cpucolor = COL_YELLOW;
            addtobuffer(upmsg, "&yellow Machine recently rebooted\n");
      }
      if ((uptimesecs != -1) && (ancientlimit != -1) && (uptimesecs > ancientlimit)) {
            if (cpucolor == COL_GREEN) cpucolor = COL_YELLOW;
            sprintf(msgline, "&yellow Machine has been up more than %d days\n", (ancientlimit / 86400));
            addtobuffer(upmsg, msgline);
      }

      if (clockstr) {
            char *p;
            struct timeval clockval;

            p = strstr(clockstr, "epoch:"); 
            if (p && (sscanf(p, "epoch: %ld.%ld", (long int *)&clockval.tv_sec, (long int *)&clockval.tv_usec) == 2)) {
                  struct timeval clockdiff;
                  struct timezone tz;
                  int cachedelay = 0;

                  if (msgcachestr) {
                        /* Message passed through msgcache, so adjust for the cache delay */
                        p = strstr(msgcachestr, "Cachedelay:");
                        if (p) cachedelay = atoi(p+11);
                  }

                  gettimeofday(&clockdiff, &tz);
                  clockdiff.tv_sec -= (clockval.tv_sec + cachedelay);
                  clockdiff.tv_usec -= clockval.tv_usec;
                  if (clockdiff.tv_usec < 0) {
                        clockdiff.tv_usec += 1000000;
                        clockdiff.tv_sec -= 1;
                  }

                  if ((maxclockdiff > 0) && (abs(clockdiff.tv_sec) > maxclockdiff)) {
                        if (cpucolor == COL_GREEN) cpucolor = COL_YELLOW;
                        sprintf(msgline, "&yellow System clock is %ld seconds off (max %ld)\n",
                              (long) clockdiff.tv_sec, (long) maxclockdiff);
                        addtobuffer(upmsg, msgline);
                  }
                  else {
                        sprintf(msgline, "System clock is %ld seconds off\n", (long) clockdiff.tv_sec);
                        addtobuffer(upmsg, msgline);
                  }
            }
      }

      init_status(cpucolor);
      sprintf(msgline, "status %s.cpu %s %s %s, %d users, %d procs, load=%s\n",
            commafy(hostname), colorname(cpucolor), 
            (timestr ? timestr : "<no timestamp data>"), 
            myupstr, 
            (whostr ? linecount(whostr) : 0), 
            (psstr ? linecount(psstr)-1 : 0), 
            loadresult);
      addtostatus(msgline);
      if (STRBUFLEN(upmsg)) {
            addtostrstatus(upmsg);
            addtostatus("\n");
      }
      if (topstr) {
            addtostatus("\n");
            addtostatus(topstr);
      }

      if (fromline && !localmode) addtostatus(fromline);
      finish_status();

      freestrbuffer(upmsg);
}


void unix_disk_report(char *hostname, char *clientclass, enum ostype_t os,
                  namelist_t *hinfo, char *fromline, char *timestr, 
                  char *freehdr, char *capahdr, char *mnthdr, char *dfstr)
{
      int diskcolor = COL_GREEN;

      int dchecks = 0;
      int freecol = -1;
      int capacol = -1;
      int mntcol  = -1;
      char *p, *bol, *nl;
      char msgline[4096];
      strbuffer_t *monmsg, *dfstr_filtered;
      char *dname;
      int dmin, dmax, dcount, dcolor;
      char *group;

      if (!want_msgtype(hinfo, MSG_DISK)) return;
      if (!dfstr) return;

      dbgprintf("Disk check host %s\n", hostname);

      monmsg = newstrbuffer(0);
      dfstr_filtered = newstrbuffer(0);
      dchecks = clear_disk_counts(hinfo, clientclass);
      clearalertgroups();

      bol = dfstr; /* Must do this always, to at least grab the column-numbers we need */
      while (bol) {
            int ignored = 0;

            nl = strchr(bol, '\n'); if (nl) *nl = '\0';

            if ((capacol == -1) && (mntcol == -1) && (freecol == -1)) {
                  /* First line: Check the header and find the columns we want */
                  p = strdup(bol);
                  freecol = selectcolumn(p, freehdr);
                  strcpy(p, bol);
                  capacol = selectcolumn(p, capahdr);
                  strcpy(p, bol);
                  mntcol = selectcolumn(p, mnthdr);
                  xfree(p);
                  dbgprintf("Disk check: header '%s', columns %d and %d\n", bol, freecol, capacol, mntcol);
            }
            else {
                  char *fsname = NULL, *levelstr = NULL;
                  int abswarn, abspanic;
                  long levelpct = -1, levelabs = -1, warnlevel, paniclevel;

                  p = strdup(bol);
                  fsname = getcolumn(p, mntcol); 
                  if (fsname) {
                        char *msgp = msgline;

                        add_disk_count(fsname);
                        get_disk_thresholds(hinfo, clientclass, fsname, 
                                        &warnlevel, &paniclevel, 
                                        &abswarn, &abspanic, 
                                        &ignored, &group);

                        strcpy(p, bol);
                        levelstr = getcolumn(p, freecol); if (levelstr) levelabs = atol(levelstr);
                        strcpy(p, bol);
                        levelstr = getcolumn(p, capacol); if (levelstr) levelpct = atol(levelstr);

                        dbgprintf("Disk check: FS='%s' level %ld%%/%ldU (thresholds: %lu/%lu, abs: %d/%d)\n",
                              fsname, levelpct, levelabs, 
                              warnlevel, paniclevel, abswarn, abspanic);

                        if (ignored) {
                              /* Forget about this one */
                        }
                        else if ( (abspanic && (levelabs <= paniclevel)) || 
                             (!abspanic && (levelpct >= paniclevel)) ) {
                              if (diskcolor < COL_RED) diskcolor = COL_RED;

                              msgp += sprintf(msgp, "&red %s ", fsname);

                              if (abspanic) msgp += sprintf(msgp, "(%lu units free)", levelabs);
                              else msgp += sprintf(msgp, "(%lu%% used)", levelpct);

                              msgp += sprintf(msgp, " has reached the PANIC level ");

                              if (abspanic) msgp += sprintf(msgp, "(%lu units)\n", paniclevel);
                              else msgp += sprintf(msgp, "(%lu%%)\n", paniclevel);

                              addtobuffer(monmsg, msgline);
                              addalertgroup(group);
                        }
                        else if ( (abswarn && (levelabs <= warnlevel)) || 
                                  (!abswarn && (levelpct >= warnlevel)) ) {
                              if (diskcolor < COL_YELLOW) diskcolor = COL_YELLOW;

                              msgp += sprintf(msgp, "&yellow %s ", fsname);

                              if (abswarn) msgp += sprintf(msgp, "(%lu units free)", levelabs);
                              else msgp += sprintf(msgp, "(%lu%% used)", levelpct);

                              msgp += sprintf(msgp, " has reached the WARNING level ");

                              if (abswarn) msgp += sprintf(msgp, "(%lu units)\n", warnlevel);
                              else msgp += sprintf(msgp, "(%lu%%)\n", warnlevel);

                              addtobuffer(monmsg, msgline);
                              addalertgroup(group);
                        }
                  }

                  xfree(p);
            }

            if (!ignored) {
                  addtobuffer(dfstr_filtered, bol);
                  addtobuffer(dfstr_filtered, "\n");
            }
            if (nl) { *nl = '\n'; bol = nl+1; } else bol = NULL;
      }

      if ((capacol == -1) && (mntcol == -1)) {
            /* If this happens, we havent found our headers so no filesystems have been processed */
            diskcolor = COL_YELLOW;
            sprintf(msgline, "&red Expected strings (%s and %s) not found in df output\n", 
                  capahdr, mnthdr);
            addtobuffer(monmsg, msgline);

            errprintf("Host %s (%s) sent incomprehensible disk report - missing columnheaders '%s' and '%s'\n%s\n",
                    hostname, osname(os), capahdr, mnthdr, dfstr);
      }

      /* Check for filesystems that must (not) exist */
      while ((dname = check_disk_count(&dcount, &dmin, &dmax, &dcolor, &group)) != NULL) {
            char limtxt[1024];

            *limtxt = '\0';

            if (dmax == -1) {
                  if (dmin > 0) sprintf(limtxt, "%d or more", dmin);
                  else if (dmin == 0) sprintf(limtxt, "none");
            }
            else {
                  if (dmin > 0) sprintf(limtxt, "between %d and %d", dmin, dmax);
                  else if (dmin == 0) sprintf(limtxt, "at most %d", dmax);
            }

            if (dcolor != COL_GREEN) {
                  if (dcolor > diskcolor) diskcolor = dcolor;
                  sprintf(msgline, "&%s Filesystem %s (found %d, req. %s)\n", 
                        colorname(dcolor), dname, dcount, limtxt);
                  addtobuffer(monmsg, msgline);
                  addalertgroup(group);
            }
      }

      /* Now we know the result, so generate a status message */
      init_status(diskcolor);
      group = getalertgroups();
      if (group) sprintf(msgline, "status/group:%s ", group); else strcpy(msgline, "status ");
      addtostatus(msgline);

      sprintf(msgline, "%s.disk %s %s - Filesystems %s\n",
            commafy(hostname), colorname(diskcolor), 
            (timestr ? timestr : "<No timestamp data>"), 
            ((diskcolor == COL_GREEN) ? "OK" : "NOT ok"));
      addtostatus(msgline);

      /* And add the info about what's wrong */
      if (STRBUFLEN(monmsg)) {
            addtostrstatus(monmsg);
            addtostatus("\n");
      }

      /* And the full df output */
      addtostrstatus(dfstr_filtered);

      if (fromline && !localmode) addtostatus(fromline);
      finish_status();

      freestrbuffer(monmsg);
      freestrbuffer(dfstr_filtered);
}

void unix_memory_report(char *hostname, char *clientclass, enum ostype_t os,
                    namelist_t *hinfo, char *fromline, char *timestr, 
                  long memphystotal, long memphysused, long memactused,
                  long memswaptotal, long memswapused)
{
      unsigned long memphyspct = 0, memswappct = 0, memactpct = 0;
      int physyellow, physred, swapyellow, swapred, actyellow, actred;

      int memorycolor = COL_GREEN, physcolor = COL_GREEN, swapcolor = COL_GREEN, actcolor = COL_GREEN;
      char *memorysummary = "OK";

      char msgline[4096];

      if (!want_msgtype(hinfo, MSG_MEMORY)) return;
      if (memphystotal == -1) return;
      if (memphysused  == -1) return;

      get_memory_thresholds(hinfo, clientclass, &physyellow, &physred, &swapyellow, &swapred, &actyellow, &actred);

      memphyspct = (memphystotal > 0) ? ((100 * memphysused) / memphystotal) : 0;
      if (memphyspct > physyellow) physcolor = COL_YELLOW;
      if (memphyspct > physred)    physcolor = COL_RED;

      if (memswapused != -1) {
            memswappct = (memswaptotal > 0) ? ((100 * memswapused) / memswaptotal) : 0;
            if (memswappct > swapyellow) swapcolor = COL_YELLOW;
            if (memswappct > swapred)    swapcolor = COL_RED;
      }

      if (memactused != -1) {
            memactpct = (memphystotal > 0) ? ((100 * memactused) / memphystotal) : 0;
            if (memactpct  > actyellow)  actcolor  = COL_YELLOW;
            if (memactpct  > actred)     actcolor  = COL_RED;
      }

      if ((physcolor == COL_YELLOW) || (swapcolor == COL_YELLOW) || (actcolor == COL_YELLOW)) {
            memorycolor = COL_YELLOW;
            memorysummary = "low";
      }
      if ((physcolor == COL_RED) || (swapcolor == COL_RED) || (actcolor == COL_RED)) {
            memorycolor = COL_RED;
            memorysummary = "CRITICAL";
      }

      if ((memphystotal == 0) && (memorycolor == COL_GREEN)) {
            memorycolor = COL_YELLOW;
            memorysummary = "detection FAILED";
      }

      init_status(memorycolor);
      sprintf(msgline, "status %s.memory %s %s - Memory %s\n",
            commafy(hostname), colorname(memorycolor), 
            (timestr ? timestr : "<No timestamp data>"),
            memorysummary);
      addtostatus(msgline);

      sprintf(msgline, "   %-12s%12s%12s%12s\n", "Memory", "Used", "Total", "Percentage");
      addtostatus(msgline);

      sprintf(msgline, "&%s %-12s%11luM%11luM%11lu%%\n", 
            colorname(physcolor), "Physical", memphysused, memphystotal, memphyspct);
      addtostatus(msgline);

      if (memactused != -1) {
            sprintf(msgline, "&%s %-12s%11luM%11luM%11lu%%\n", 
                  colorname(actcolor), "Actual", memactused, memphystotal, memactpct);
            addtostatus(msgline);
      }

      if (memswapused != -1) {
            sprintf(msgline, "&%s %-12s%11luM%11luM%11lu%%\n", 
                  colorname(swapcolor), "Swap", memswapused, memswaptotal, memswappct);
            addtostatus(msgline);
      }
      if (fromline && !localmode) addtostatus(fromline);
      finish_status();
}

void unix_procs_report(char *hostname, char *clientclass, enum ostype_t os,
                   namelist_t *hinfo, char *fromline, char *timestr, 
                   char *cmdhdr, char *altcmdhdr, char *psstr)
{
      int pscolor = COL_GREEN;

      int pchecks;
      int cmdofs = -1;
      char *p, *eol;
      char msgline[4096];
      strbuffer_t *monmsg;
      static strbuffer_t *countdata = NULL;
      int anycountdata = 0;
      char *group;

      if (!want_msgtype(hinfo, MSG_PROCS)) return;
      if (!psstr) return;

      if (!countdata) countdata = newstrbuffer(0);

      clearalertgroups();
      monmsg = newstrbuffer(0);

      sprintf(msgline, "data %s.proccounts\n", commafy(hostname));
      addtobuffer(countdata, msgline);

      /* 
       * Find where the command is located. We look for the header for the command,
       * and calculate the offset from the beginning of the line.
       *
       * NOTE: The header strings could show up in the normal "ps" output. So
       *       we look for it only in the first line of output.
       */
      eol = strchr(psstr, '\n'); if (eol) *eol = '\0';
      dbgprintf("Host %s need heading %s or %s - ps header line reads '%s'\n", 
              hostname, cmdhdr, (altcmdhdr ? altcmdhdr : "<none>"), psstr);

      /* Look for the primary key */
      p = strstr(psstr, cmdhdr);
      if (p) {
            cmdofs = (p - psstr);
            dbgprintf("Host %s: Found pri. heading '%s' at offset %d\n", hostname, cmdhdr, cmdofs);
      }

      /* If there's a secondary key, look for that also */
      if (altcmdhdr) {
            p = strstr(psstr, altcmdhdr);
            if (p) {
                  dbgprintf("Host %s: Found sec. heading '%s' at offset %d\n", hostname, altcmdhdr, (p - psstr));
                  if ((cmdofs == -1) || ((p - psstr) < cmdofs)) {
                        /* We'll use the secondary key */
                        cmdofs = (p - psstr);
                  }
            }
      }
      if (eol) *eol = '\n';

      if (debug) {
            if (cmdofs >= 0) dbgprintf("Host %s: Found ps commandline at offset %d\n", hostname, cmdofs);
            else dbgprintf("Host %s: None of the headings found\n", hostname);
      }

      pchecks = clear_process_counts(hinfo, clientclass);

      if (pchecks == 0) {
            /* Nothing to check */
            sprintf(msgline, "&%s No process checks defined\n", colorname(noreportcolor));
            addtobuffer(monmsg, msgline);
            pscolor = noreportcolor;
      }
      else if (cmdofs >= 0) {
            /* Count how many instances of each monitored process is running */
            char *pname, *pid, *bol, *nl;
            int pcount, pmin, pmax, pcolor, ptrack;

            bol = psstr;
            while (bol) {
                  nl = strchr(bol, '\n'); 

                  /* Take care - the ps output line may be shorter than what we look at */
                  if (nl) {
                        *nl = '\0';

                        if ((nl-bol) > cmdofs) add_process_count(bol+cmdofs);

                        *nl = '\n';
                        bol = nl+1;
                  }
                  else {
                        if (strlen(bol) > cmdofs) add_process_count(bol+cmdofs);

                        bol = NULL;
                  }
            }

            /* Check the number found for each monitored process */
            while ((pname = check_process_count(&pcount, &pmin, &pmax, &pcolor, &pid, &ptrack, &group)) != NULL) {
                  char limtxt[1024];

                  if (pmax == -1) {
                        if (pmin > 0) sprintf(limtxt, "%d or more", pmin);
                        else if (pmin == 0) sprintf(limtxt, "none");
                  }
                  else {
                        if (pmin > 0) sprintf(limtxt, "between %d and %d", pmin, pmax);
                        else if (pmin == 0) sprintf(limtxt, "at most %d", pmax);
                  }

                  if (pcolor == COL_GREEN) {
                        sprintf(msgline, "&green %s (found %d, req. %s)\n", pname, pcount, limtxt);
                        addtobuffer(monmsg, msgline);
                  }
                  else {
                        if (pcolor > pscolor) pscolor = pcolor;
                        sprintf(msgline, "&%s %s (found %d, req. %s)\n", 
                              colorname(pcolor), pname, pcount, limtxt);
                        addtobuffer(monmsg, msgline);
                        addalertgroup(group);
                  }

                  if (ptrack) {
                        /* Save the count data for later DATA message to track process counts */
                        if (!pid) pid = "default";
                        sprintf(msgline, "%s:%u\n", pid, pcount);
                        addtobuffer(countdata, msgline);
                        anycountdata = 1;
                  }
            }
      }
      else {
            pscolor = COL_YELLOW;
            sprintf(msgline, "&yellow Expected string %s not found in ps output header\n", cmdhdr);
            addtobuffer(monmsg, msgline);
      }

      /* Now we know the result, so generate a status message */
      init_status(pscolor);

      group = getalertgroups();
      if (group) sprintf(msgline, "status/group:%s ", group); else strcpy(msgline, "status ");
      addtostatus(msgline);

      sprintf(msgline, "%s.procs %s %s - Processes %s\n",
            commafy(hostname), colorname(pscolor), 
            (timestr ? timestr : "<No timestamp data>"), 
            ((pscolor == COL_GREEN) ? "OK" : "NOT ok"));
      addtostatus(msgline);

      /* And add the info about what's wrong */
      if (STRBUFLEN(monmsg)) {
            addtostrstatus(monmsg);
            addtostatus("\n");
      }

      /* And the full ps output for those who want it */
      if (pslistinprocs) {
            /*
             * NB: Process listings may contain HTML special characters.
             *     We must encode these for HTML, cf.
             *     http://www.w3.org/TR/html4/charset.html#h-5.3.2
             */
            char *inp, *tagpos;

            inp = psstr;
            do {
                  tagpos = inp + strcspn(inp, "<>&\"");
                  switch (*tagpos) {
                    case '<':
                        *tagpos = '\0'; addtostatus(inp); addtostatus("&lt;"); *tagpos = '<';
                        inp = tagpos + 1;
                        break;
                    case '>':
                        *tagpos = '\0'; addtostatus(inp); addtostatus("&gt;"); *tagpos = '>';
                        inp = tagpos + 1;
                        break;
                    case '&':
                        *tagpos = '\0'; addtostatus(inp); addtostatus("&amp;"); *tagpos = '&';
                        inp = tagpos + 1;
                        break;
                    case '\"':
                        *tagpos = '\0'; addtostatus(inp); addtostatus("&quot;"); *tagpos = '\"';
                        inp = tagpos + 1;
                        break;
                    default:
                        /* We're done */
                        addtostatus(inp); inp = NULL;
                        break;
                  }
            } while (inp && *inp);
      }

      if (fromline && !localmode) addtostatus(fromline);
      finish_status();

      freestrbuffer(monmsg);

      if (anycountdata) sendmessage(STRBUF(countdata), NULL, NULL, NULL, 0, BBTALK_TIMEOUT);
      clearstrbuffer(countdata);
}

static void old_msgs_report(char *hostname, namelist_t *hinfo, char *fromline, char *timestr, char *msgsstr)
{
      int msgscolor = COL_GREEN;
      char msgline[4096];
      char *summary = "All logs OK";

      if (msgsstr) {
            if (strstr(msgsstr, "&clear ")) { msgscolor = COL_CLEAR; summary = "No log data available"; }
            if (strstr(msgsstr, "&yellow ")) { msgscolor = COL_YELLOW; summary = "WARNING"; }
            if (strstr(msgsstr, "&red ")) { msgscolor = COL_RED; summary = "CRITICAL"; }
      }
      else if (sendclearmsgs) {
            msgscolor = noreportcolor; summary = "No log data available";
      }
      else 
            return;

      init_status(msgscolor);
      sprintf(msgline, "status %s.msgs %s System logs at %s : %s\n",
            commafy(hostname), colorname(msgscolor), 
            (timestr ? timestr : "<No timestamp data>"), 
            summary);
      addtostatus(msgline);

      if (msgsstr)
            addtostatus(msgsstr);
      else
            addtostatus("The client did not report any logfile data\n");

      if (fromline && !localmode) addtostatus(fromline);
      finish_status();
}

void msgs_report(char *hostname, char *clientclass, enum ostype_t os,
             namelist_t *hinfo, char *fromline, char *timestr, char *msgsstr)
{
      static strbuffer_t *greendata = NULL;
      static strbuffer_t *yellowdata = NULL;
      static strbuffer_t *reddata = NULL;
      sectlist_t *swalk;
      strbuffer_t *logsummary;
      int msgscolor = COL_GREEN;
      char msgline[PATH_MAX];
      char *group;

      if (!want_msgtype(hinfo, MSG_MSGS)) return;

      for (swalk = sections; (swalk && strncmp(swalk->sname, "msgs:", 5)); swalk = swalk->next) ;

      if (!swalk) {
            old_msgs_report(hostname, hinfo, fromline, timestr, msgsstr);
            return;
      }

      if (!greendata) greendata = newstrbuffer(0);
      if (!yellowdata) yellowdata = newstrbuffer(0);
      if (!reddata) reddata = newstrbuffer(0);
      clearalertgroups();

      logsummary = newstrbuffer(0);

      while (swalk) {
            int logcolor;

            clearstrbuffer(logsummary);
            logcolor = scan_log(hinfo, clientclass, swalk->sname+5, swalk->sdata, swalk->sname, logsummary);

            if (logcolor > msgscolor) msgscolor = logcolor;

            switch (logcolor) {
              case COL_GREEN:
                  if (!localmode) {
                        sprintf(msgline, "\nNo entries in <a href=\"%s\">%s</a>\n", 
                              hostsvcclienturl(hostname, swalk->sname), swalk->sname+5);
                  }
                  else {
                        sprintf(msgline, "\nNo entries in %s\n", 
                              swalk->sname+5);
                  }
                  addtobuffer(greendata, msgline);
                  break;

              case COL_YELLOW: 
                  if (!localmode) {
                        sprintf(msgline, "\n&yellow Warnings in <a href=\"%s\">%s</a>\n", 
                              hostsvcclienturl(hostname, swalk->sname), swalk->sname+5);
                  }
                  else {
                        sprintf(msgline, "\n&yellow Warnings in %s\n", 
                              swalk->sname+5);
                  }
                  addtobuffer(yellowdata, msgline);
                  addtostrbuffer(yellowdata, logsummary);
                  break;

              case COL_RED:
                  if (!localmode) {
                        sprintf(msgline, "\n&red Critical entries in <a href=\"%s\">%s</a>\n", 
                              hostsvcclienturl(hostname, swalk->sname), swalk->sname+5);
                  }
                  else {
                        sprintf(msgline, "\n&red Critical entries in %s\n", 
                              swalk->sname+5);
                  }
                  addtobuffer(reddata, msgline);
                  addtostrbuffer(reddata, logsummary);
                  break;
            }

            do { swalk=swalk->next; } while (swalk && strncmp(swalk->sname, "msgs:", 5));
      }

      freestrbuffer(logsummary);

      init_status(msgscolor);

      group = getalertgroups();
      if (group) sprintf(msgline, "status/group:%s ", group); else strcpy(msgline, "status ");
      addtostatus(msgline);

      sprintf(msgline, "%s.msgs %s System logs at %s\n",
            commafy(hostname), colorname(msgscolor), 
            (timestr ? timestr : "<No timestamp data>"));
      addtostatus(msgline);

      if (STRBUFLEN(reddata)) {
            addtostrstatus(reddata);
            clearstrbuffer(reddata);
            addtostatus("\n");
      }

      if (STRBUFLEN(yellowdata)) {
            addtostrstatus(yellowdata);
            clearstrbuffer(yellowdata);
            addtostatus("\n");
      }

      if (STRBUFLEN(greendata)) {
            addtostrstatus(greendata);
            clearstrbuffer(greendata);
            addtostatus("\n");
      }

      /* 
       * Add the full log message data from each logfile.
       * It's probably faster to re-walk the section list than
       * stuffing the full messages into a temporary buffer.
       */
      for (swalk = sections; (swalk && strncmp(swalk->sname, "msgs:", 5)); swalk = swalk->next) ;
      while (swalk) {
            if (!localmode) {
                  sprintf(msgline, "\nFull log <a href=\"%s\">%s</a>\n", 
                        hostsvcclienturl(hostname, swalk->sname), swalk->sname+5);
            }
            else {
                  sprintf(msgline, "\nFull log %s\n", 
                        swalk->sname+5);
            }
            addtostatus(msgline);
            addtostatus(swalk->sdata);
            do { swalk=swalk->next; } while (swalk && strncmp(swalk->sname, "msgs:", 5));
      }

      if (fromline && !localmode) addtostatus(fromline);

      finish_status();
}

void file_report(char *hostname, char *clientclass, enum ostype_t os,
             namelist_t *hinfo, char *fromline, char *timestr)
{
      static strbuffer_t *greendata = NULL;
      static strbuffer_t *yellowdata = NULL;
      static strbuffer_t *reddata = NULL;
      static strbuffer_t *sizedata = NULL;
      sectlist_t *swalk;
      strbuffer_t *filesummary;
      int filecolor = -1, onecolor;
      char msgline[PATH_MAX];
      char sectionname[PATH_MAX];
      int anyszdata = 0;
      char *group;

      if (!want_msgtype(hinfo, MSG_FILES)) return;

      if (!greendata) greendata = newstrbuffer(0);
      if (!yellowdata) yellowdata = newstrbuffer(0);
      if (!reddata) reddata = newstrbuffer(0);
      if (!sizedata) sizedata = newstrbuffer(0);
      filesummary = newstrbuffer(0);
      clearalertgroups();

      sprintf(msgline, "data %s.filesizes\n", commafy(hostname));
      addtobuffer(sizedata, msgline);

      for (swalk = sections; (swalk); swalk = swalk->next) {
            int trackit, anyrules;
            char *sfn = NULL;
            char *id = NULL;

            if (strncmp(swalk->sname, "file:", 5) == 0) {
                  off_t sz;
                  sfn = swalk->sname+5;
                  sprintf(sectionname, "file:%s", sfn);
                  onecolor = check_file(hinfo, clientclass, sfn, swalk->sdata, sectionname, filesummary, &sz, &id, &trackit, &anyrules);

                  if (trackit) {
                        /* Save the size data for later DATA message to track file sizes */
                        if (id == NULL) id = sfn;
#ifdef _LARGEFILE_SOURCE
                        sprintf(msgline, "%s:%lld\n", id, sz);
#else
                        sprintf(msgline, "%s:%ld\n", id, sz);
#endif
                        addtobuffer(sizedata, msgline);
                        anyszdata = 1;
                  }
            }
            else if (strncmp(swalk->sname, "logfile:", 8) == 0) {
                  off_t sz;
                  sfn = swalk->sname+8;
                  sprintf(sectionname, "logfile:%s", sfn);
                  onecolor = check_file(hinfo, clientclass, sfn, swalk->sdata, sectionname, filesummary, &sz, &id, &trackit, &anyrules);
                  if (trackit) {
                        /* Save the size data for later DATA message to track file sizes */
                        if (id == NULL) id = sfn;
#ifdef _LARGEFILE_SOURCE
                        sprintf(msgline, "%s:%lld\n", id, sz);
#else
                        sprintf(msgline, "%s:%ld\n", id, sz);
#endif
                        addtobuffer(sizedata, msgline);
                        anyszdata = 1;
                  }

                  if (!anyrules) {
                        /* Dont clutter the display with logfiles unless they have rules */
                        continue;
                  }
            }
            else if (strncmp(swalk->sname, "dir:", 4) == 0) {
                  unsigned long sz;
                  sfn = swalk->sname+4;
                  sprintf(sectionname, "dir:%s", sfn);
                  onecolor = check_dir(hinfo, clientclass, sfn, swalk->sdata, sectionname, filesummary, &sz, &id, &trackit);

                  if (trackit) {
                        /* Save the size data for later DATA message to track directory sizes */
                        if (id == NULL) id = sfn;
                        sprintf(msgline, "%s:%lu\n", id, sz);
                        addtobuffer(sizedata, msgline);
                        anyszdata = 1;
                  }
            }
            else continue;

            if (onecolor > filecolor) filecolor = onecolor;

            switch (onecolor) {
              case COL_GREEN:
                  if (!localmode) {
                        sprintf(msgline, "\n&green <a href=\"%s\">%s</a>\n", 
                              hostsvcclienturl(hostname, sectionname), sfn);
                  }
                  else {
                        sprintf(msgline, "\n&green %s\n", sfn);
                  }
                  addtobuffer(greendata, msgline);
                  break;

              case COL_YELLOW: 
                  if (!localmode) {
                        sprintf(msgline, "\n&yellow <a href=\"%s\">%s</a>\n", 
                              hostsvcclienturl(hostname, sectionname), sfn);
                  }
                  else {
                        sprintf(msgline, "\n&yellow %s\n", sfn);
                  }
                  addtobuffer(yellowdata, msgline);
                  addtostrbuffer(yellowdata, filesummary);
                  break;

              case COL_RED:
                  if (!localmode) {
                        sprintf(msgline, "\n&red <a href=\"%s\">%s</a>\n", 
                              hostsvcclienturl(hostname, sectionname), sfn);
                  }
                  else {
                        sprintf(msgline, "\n&red %s\n", sfn);
                  }
                  addtobuffer(reddata, msgline);
                  addtostrbuffer(reddata, filesummary);
                  break;
            }

            clearstrbuffer(filesummary);
      }

      freestrbuffer(filesummary);

      if ((filecolor == -1) && sendclearfiles) {
            filecolor = noreportcolor;
            addtobuffer(greendata, "No files checked\n");
      }

      if (filecolor != -1) {
            init_status(filecolor);

            group = getalertgroups();
            if (group) sprintf(msgline, "status/group:%s ", group); else strcpy(msgline, "status ");
            addtostatus(msgline);

            sprintf(msgline, "%s.files %s Files status at %s\n",
                  commafy(hostname), colorname(filecolor), 
                  (timestr ? timestr : "<No timestamp data>"));
            addtostatus(msgline);

            if (STRBUFLEN(reddata)) {
                  addtostrstatus(reddata);
                  clearstrbuffer(reddata);
                  addtostatus("\n");
            }

            if (STRBUFLEN(yellowdata)) {
                  addtostrstatus(yellowdata);
                  clearstrbuffer(yellowdata);
                  addtostatus("\n");
            }

            if (STRBUFLEN(greendata)) {
                  addtostrstatus(greendata);
                  clearstrbuffer(greendata);
                  addtostatus("\n");
            }

            if (fromline && !localmode) addtostatus(fromline);

            finish_status();
      }
      else {
            clearstrbuffer(reddata);
            clearstrbuffer(yellowdata);
            clearstrbuffer(greendata);
      }

      if (anyszdata) sendmessage(STRBUF(sizedata), NULL, NULL, NULL, 0, BBTALK_TIMEOUT);
      clearstrbuffer(sizedata);
}

void linecount_report(char *hostname, char *clientclass, enum ostype_t os,
                  namelist_t *hinfo, char *fromline, char *timestr)
{
      static strbuffer_t *countdata = NULL;
      sectlist_t *swalk;
      char msgline[PATH_MAX];
      int anydata = 0;

      if (!countdata) countdata = newstrbuffer(0);

      sprintf(msgline, "data %s.linecounts\n", commafy(hostname));
      addtobuffer(countdata, msgline);

      for (swalk = sections; (swalk); swalk = swalk->next) {
            if (strncmp(swalk->sname, "linecount:", 10) == 0) {
                  char *fn, *boln, *eoln, *id, *countstr;

                  anydata = 1;

                  fn = strchr(swalk->sname, ':'); fn += 1 + strspn(fn+1, "\t ");

                  boln = swalk->sdata;
                  while (boln) {
                        eoln = strchr(boln, '\n');

                        id = strtok(boln, ":");
                        countstr = (id ? strtok(NULL, "\n") : NULL);
                        if (id && countstr) {
                              countstr += strspn(countstr, "\t ");
                              sprintf(msgline, "%s#%s:%s\n", fn, id, countstr);
                              addtobuffer(countdata, msgline);
                        }

                        boln = (eoln ? eoln + 1 : NULL);
                  }
            }
      }

      if (anydata) sendmessage(STRBUF(countdata), NULL, NULL, NULL, 0, BBTALK_TIMEOUT);
      clearstrbuffer(countdata);
}


void unix_netstat_report(char *hostname, char *clientclass, enum ostype_t os,
                   namelist_t *hinfo, char *fromline, char *timestr,
                   char *netstatstr)
{
      strbuffer_t *msg;
      char msgline[4096];

      if (!netstatstr) return;

      msg = newstrbuffer(0);
      sprintf(msgline, "data %s.netstat\n%s\n", commafy(hostname), osname(os));
      addtobuffer(msg, msgline);
      addtobuffer(msg, netstatstr);
      sendmessage(STRBUF(msg), NULL, NULL, NULL, 0, BBTALK_TIMEOUT);

      freestrbuffer(msg);
}

void unix_ifstat_report(char *hostname, char *clientclass, enum ostype_t os,
                  namelist_t *hinfo, char *fromline, char *timestr,
                  char *ifstatstr)
{
      strbuffer_t *msg;
      char msgline[4096];

      if (!ifstatstr) return;

      msg = newstrbuffer(0);
      sprintf(msgline, "data %s.ifstat\n%s\n", commafy(hostname), osname(os));
      addtobuffer(msg, msgline);
      addtobuffer(msg, ifstatstr);
      sendmessage(STRBUF(msg), NULL, NULL, NULL, 0, BBTALK_TIMEOUT);

      freestrbuffer(msg);
}

void unix_vmstat_report(char *hostname, char *clientclass, enum ostype_t os,
                  namelist_t *hinfo, char *fromline, char *timestr,
                  char *vmstatstr)
{
      strbuffer_t *msg;
      char msgline[4096];

      char *p;

      if (!vmstatstr) return;

      p = strrchr(vmstatstr, '\n');
      if (!p) return;  /* No NL in vmstat output ? Unlikely. */

      msg = newstrbuffer(0);
      if (strlen(p) == 1) {
            /* Go back to the previous line */
            do { p--; } while ((p > vmstatstr) && (*p != '\n'));
      }
      sprintf(msgline, "data %s.vmstat\n%s\n", commafy(hostname), osname(os));
      addtobuffer(msg, msgline);
      addtobuffer(msg, p+1);
      sendmessage(STRBUF(msg), NULL, NULL, NULL, 0, BBTALK_TIMEOUT);

      freestrbuffer(msg);
}


void unix_ports_report(char *hostname, char *clientclass, enum ostype_t os,
                   namelist_t *hinfo, char *fromline, char *timestr, 
                   int localcol, int remotecol, int statecol, char *portstr)
{
      int portcolor = -1;
      int pchecks;
      char msgline[4096];
      static strbuffer_t *monmsg = NULL;
      static strbuffer_t *countdata = NULL;
      int anycountdata = 0;
      char *group;

      if (!want_msgtype(hinfo, MSG_PORTS)) return;
      if (!portstr) return;

      if (!monmsg) monmsg = newstrbuffer(0);
      if (!countdata) countdata = newstrbuffer(0);

      clearalertgroups();
      pchecks = clear_port_counts(hinfo, clientclass);

      sprintf(msgline, "data %s.portcounts\n", commafy(hostname));
      addtobuffer(countdata, msgline);

      if (pchecks > 0) {
            /* Count how many instances of each monitored condition are found */
            char *pname, *pid, *bol, *nl;
            int pcount, pmin, pmax, pcolor, ptrack;
            char *localstr, *remotestr, *statestr;

            bol = portstr;
            while (bol) {
                  char *p;

                  nl = strchr(bol, '\n'); if (nl) *nl = '\0';

                  /* Data lines */

                  p = strdup(bol); localstr = getcolumn(p, localcol);
                  strcpy(p, bol); remotestr = getcolumn(p, remotecol);
                  strcpy(p, bol); statestr = getcolumn(p, statecol);

                  add_port_count(localstr, remotestr, statestr);

                  xfree(p);

                  if (nl) { *nl = '\n'; bol = nl+1; } else bol = NULL;
            }

            /* Check the number found for each monitored port */
            while ((pname = check_port_count(&pcount, &pmin, &pmax, &pcolor, &pid, &ptrack, &group)) != NULL) {
                  char limtxt[1024];
                  
                  if (pmax == -1) {
                        if (pmin > 0) sprintf(limtxt, "%d or more", pmin);
                        else if (pmin == 0) sprintf(limtxt, "none");
                  }
                  else {
                        if (pmin > 0) sprintf(limtxt, "between %d and %d", pmin, pmax);
                        else if (pmin == 0) sprintf(limtxt, "at most %d", pmax);
                  }

                  if (pcolor > portcolor) portcolor = pcolor;

                  if (pcolor == COL_GREEN) {
                        sprintf(msgline, "&green %s (found %d, req. %s)\n", pname, pcount, limtxt);
                        addtobuffer(monmsg, msgline);
                  }
                  else {
                        sprintf(msgline, "&%s %s (found %d, req. %s)\n",
                              colorname(pcolor), pname, pcount, limtxt);
                        addtobuffer(monmsg, msgline);
                        addalertgroup(group);
                  }

                  if (ptrack) {
                        /* Save the size data for later DATA message to track port counts */
                        if (!pid) pid = "default";
                        sprintf(msgline, "%s:%u\n", pid, pcount);
                        addtobuffer(countdata, msgline);
                        anycountdata = 1;
                  }
            }
      }

      if ((portcolor == -1) && sendclearports) {
            /* Nothing to check */
            addtobuffer(monmsg, "No port checks defined\n");
            portcolor = noreportcolor;
      }

      if (portcolor != -1) {
            /* Now we know the result, so generate a status message */
            init_status(portcolor);

            group = getalertgroups();
            if (group) sprintf(msgline, "status/group:%s ", group); else strcpy(msgline, "status ");
            addtostatus(msgline);

            sprintf(msgline, "%s.ports %s %s - Ports %s\n",
                  commafy(hostname), colorname(portcolor), 
                  (timestr ? timestr : "<No timestamp data>"), 
                  ((portcolor == COL_GREEN) ? "OK" : "NOT ok"));
            addtostatus(msgline);

            /* And add the info about what's wrong */
            addtostrstatus(monmsg);
            addtostatus("\n");
            clearstrbuffer(monmsg);

            /* And the full port output for those who want it */
            if (portlistinports) addtostatus(portstr);

            if (fromline) addtostatus(fromline);
            finish_status();
      }
      else {
            clearstrbuffer(monmsg);
      }

      if (anycountdata) sendmessage(STRBUF(countdata), NULL, NULL, NULL, 0, BBTALK_TIMEOUT);
      clearstrbuffer(countdata);
}


#include "client/linux.c"
#include "client/freebsd.c"
#include "client/netbsd.c"
#include "client/openbsd.c"
#include "client/solaris.c"
#include "client/hpux.c"
#include "client/osf.c"
#include "client/aix.c"
#include "client/darwin.c"
#include "client/irix.c"
#include "client/sco_sv.c"

static volatile int reloadconfig = 0;

void sig_handler(int signum)
{
      switch (signum) {
        case SIGHUP:
            reloadconfig = 1;
            break;
        default:
            break;
      }
}

void clean_instr(char *s)
{
      char *p;

      p = s + strcspn(s, "\r\n");
      *p = '\0';
}

void testmode(char *configfn)
{
      namelist_t *hinfo, *oldhinfo = NULL;
      char hostname[1024], clientclass[1024];
      char s[4096];
      int cfid;

      load_hostnames(xgetenv("BBHOSTS"), NULL, get_fqdn());
      load_client_config(configfn);
      *hostname = '\0';
      *clientclass = '\0';

      while (1) {
            hinfo = NULL;
            while (!hinfo) {
                  printf("Hostname (.=end, ?=dump, !=reload) [%s]: ", hostname); 
                  fflush(stdout); fgets(hostname, sizeof(hostname), stdin);
                  clean_instr(hostname);

                  if (strlen(hostname) == 0) {
                        hinfo = oldhinfo;
                        if (hinfo) strcpy(hostname, bbh_item(hinfo, BBH_HOSTNAME));
                  }
                  else if (strcmp(hostname, ".") == 0) {
                        exit(0);
                  }
                  else if (strcmp(hostname, "!") == 0) {
                        load_hostnames(xgetenv("BBHOSTS"), NULL, get_fqdn());
                        load_client_config(configfn);
                        *hostname = '\0';
                  }
                  else if (strcmp(hostname, "?") == 0) {
                        dump_client_config();
                        if (oldhinfo) strcpy(hostname, bbh_item(oldhinfo, BBH_HOSTNAME));
                  }
                  else {
                        hinfo = hostinfo(hostname);
                        if (!hinfo) printf("Unknown host\n");

                        printf("Hosttype [%s]: ", clientclass); 
                        fflush(stdout); fgets(clientclass, sizeof(clientclass), stdin);
                        clean_instr(clientclass);
                  }
            }
            oldhinfo = hinfo;

            printf("Test (cpu, mem, disk, proc, log, port): "); fflush(stdout); 
            fgets(s, sizeof(s), stdin); clean_instr(s);
            if (strcmp(s, "cpu") == 0) {
                  float loadyellow, loadred;
                  int recentlimit, ancientlimit;
                  int maxclockdiff;

                  cfid = get_cpu_thresholds(hinfo, clientclass, &loadyellow, &loadred, &recentlimit, &ancientlimit, &maxclockdiff);

                  printf("Load: Yellow at %.2f, red at %.2f\n", loadyellow, loadred);
                  printf("Uptime: From boot until %s,", durationstring(recentlimit));
                  printf("and after %s uptime\n", durationstring(ancientlimit));
                  if (maxclockdiff > 0) printf("Max clock diff: %d\n", maxclockdiff);
            }
            else if (strcmp(s, "mem") == 0) {
                  int physyellow, physred, swapyellow, swapred, actyellow, actred;

                  get_memory_thresholds(hinfo, clientclass, &physyellow, &physred, 
                              &swapyellow, &swapred, &actyellow, &actred);
                  printf("Phys: Yellow at %d, red at %d\n", physyellow, physred);
                  printf("Swap: Yellow at %d, red at %d\n", swapyellow, swapred);
                  printf("Act.: Yellow at %d, red at %d\n", actyellow, actred);
            }
            else if (strcmp(s, "disk") == 0) {
                  unsigned long warnlevel, paniclevel;
                  int abswarn, abspanic, ignored;

                  printf("Filesystem: "); fflush(stdout);
                  fgets(s, sizeof(s), stdin); clean_instr(s);
                  cfid = get_disk_thresholds(hinfo, clientclass, s, &warnlevel, &paniclevel, 
                                       &abswarn, &abspanic, &ignored, NULL);
                  if (ignored) 
                        printf("Ignored\n");
                  else
                        printf("Yellow at %lu%c, red at %lu%c\n", 
                              warnlevel, (abswarn ? 'U' : '%'),
                              paniclevel, (abspanic ? 'U' : '%'));
            }
            else if (strcmp(s, "proc") == 0) {
                  int pchecks = clear_process_counts(hinfo, clientclass);
                  char *pname, *pid;
                  int pcount, pmin, pmax, pcolor, ptrack;
                  FILE *fd;

                  if (pchecks == 0) {
                        printf("No process checks for this host\n");
                        continue;
                  }

                  printf("To read 'ps' data from a file, enter '@FILENAME' at the prompt\n");
                  do {
                        printf("ps command string: "); fflush(stdout);
                        fgets(s, sizeof(s), stdin); clean_instr(s);
                        if (*s == '@') {
                              fd = fopen(s+1, "r");
                              while (fd && fgets(s, sizeof(s), fd)) {
                                    clean_instr(s);
                                    if (*s) add_process_count(s);
                              }
                              fclose(fd);
                        }
                        else {
                              if (*s) add_process_count(s);
                        }
                  } while (*s);

                  while ((pname = check_process_count(&pcount, &pmin, &pmax, &pcolor, &pid, &ptrack, NULL)) != NULL) {
                        printf("Process %s color %s: Count=%d, min=%d, max=%d\n",
                              pname, colorname(pcolor), pcount, pmin, pmax);
                  }
            }
            else if (strcmp(s, "log") == 0) {
                  FILE *fd;
                  char *sectname;
                  strbuffer_t *logdata, *logsummary;
                  int logcolor;

                  printf("log filename: "); fflush(stdout);
                  fgets(s, sizeof(s), stdin); clean_instr(s);
                  sectname = (char *)malloc(strlen(s) + 20);
                  sprintf(sectname, "msgs:%s", s);

                  logdata = newstrbuffer(0);
                  logsummary = newstrbuffer(0);

                  printf("To read log data from a file, enter '@FILENAME' at the prompt\n");
                  do {
                        printf("log line: "); fflush(stdout);
                        fgets(s, sizeof(s), stdin); clean_instr(s);
                        if (*s == '@') {
                              fd = fopen(s+1, "r");
                              while (fd && fgets(s, sizeof(s), fd)) {
                                    clean_instr(s);
                                    if (*s) addtobuffer(logdata, s);
                              }
                              fclose(fd);
                        }
                        else {
                              if (*s) addtobuffer(logdata, s);
                        }
                  } while (*s);

                  clearstrbuffer(logsummary);
                  logcolor = scan_log(hinfo, clientclass, sectname+5, STRBUF(logdata), sectname, logsummary);
                  printf("Log status is %s\n\n", colorname(logcolor));
                  if (STRBUFLEN(logsummary)) printf("%s\n", STRBUF(logsummary));
                  freestrbuffer(logsummary);
                  freestrbuffer(logdata);
            }
            else if (strcmp(s, "port") == 0) {
                  char *localstr, *remotestr, *statestr, *p, *pname, *pid;
                  int pcount, pmin, pmax, pcolor, pchecks, ptrack;
                  int localcol = 4, remotecol = 5, statecol = 6, portcolor = COL_GREEN;

                  pchecks = clear_port_counts(hinfo, clientclass);
                  if (pchecks == 0) {
                        printf("No PORT checks for this host\n");
                        continue;
                  }

                  printf("Need to know netstat columns for 'Local address', 'Remote address' and 'State'\n");
                  printf("Enter columns [%d %d %d]: ", localcol, remotecol, statecol); fflush(stdout);
                  fgets(s, sizeof(s), stdin); clean_instr(s);
                  if (*s) sscanf(s, "%d %d %d", &localcol, &remotecol, &statecol);

                  printf("To read 'netstat' data from a file, enter '@FILENAME' at the prompt\n");
                  do {
                        printf("netstat line: "); fflush(stdout);
                        fgets(s, sizeof(s), stdin); clean_instr(s);
                        if (*s == '@') {
                              FILE *fd;

                              fd = fopen(s+1, "r");
                              while (fd && fgets(s, sizeof(s), fd)) {
                                    clean_instr(s);
                                    if (*s) {
                                          p = strdup(s); localstr = getcolumn(p, localcol-1);
                                          strcpy(p, s); remotestr = getcolumn(p, remotecol-1);
                                          strcpy(p, s); statestr = getcolumn(p, statecol-1);
                                          add_port_count(localstr, remotestr, statestr);
                                          xfree(p);
                                    }
                              }
                              fclose(fd);
                        }
                        else if (*s) {
                              p = strdup(s); localstr = getcolumn(p, localcol-1);
                              strcpy(p, s); remotestr = getcolumn(p, remotecol-1);
                              strcpy(p, s); statestr = getcolumn(p, statecol-1);
                              add_port_count(localstr, remotestr, statestr);
                              xfree(p);
                        }
                  } while (*s);

                  /* Check the number found for each monitored port */
                  while ((pname = check_port_count(&pcount, &pmin, &pmax, &pcolor, &pid, &ptrack, NULL)) != NULL) {
                        char limtxt[1024];
                  
                        if (pmax == -1) {
                              if (pmin > 0) sprintf(limtxt, "%d or more", pmin);
                              else if (pmin == 0) sprintf(limtxt, "none");
                        }
                        else {
                              if (pmin > 0) sprintf(limtxt, "between %d and %d", pmin, pmax);
                              else if (pmin == 0) sprintf(limtxt, "at most %d", pmax);
                        }

                        if (pcolor == COL_GREEN) {
                              printf("&green %s (found %d, req. %s)\n", pname, pcount, limtxt);
                        }
                        else {
                              if (pcolor > portcolor) portcolor = pcolor;
                              printf("&%s %s (found %d, req. %s)\n",
                                    colorname(pcolor), pname, pcount, limtxt);
                        }
                  }
            }
      }

      exit(0);
}

int main(int argc, char *argv[])
{
      char *msg;
      int running;
      int argi, seq;
      struct sigaction sa;
      time_t nextconfigload = 0;
      char *configfn = NULL;

      /* Handle program options. */
      for (argi = 1; (argi < argc); argi++) {
            if (strcmp(argv[argi], "--debug") == 0) {
                  debug = 1;
            }
            else if (strcmp(argv[argi], "--no-ps-listing") == 0) {
                  pslistinprocs = 0;
            }
            else if (strcmp(argv[argi], "--no-port-listing") == 0) {
                  portlistinports = 0;
            }
            else if (strcmp(argv[argi], "--no-clear-msgs") == 0) {
                  sendclearmsgs = 0;
            }
            else if (strcmp(argv[argi], "--no-clear-files") == 0) {
                  sendclearfiles = 0;
            }
            else if (strcmp(argv[argi], "--no-clear-ports") == 0) {
                  sendclearports = 0;
            }
            else if (strncmp(argv[argi], "--clear-color=", 14) == 0) {
                  char *p = strchr(argv[argi], '=');
                  noreportcolor = parse_color(p+1);
            }
            else if (argnmatch(argv[argi], "--config=")) {
                  char *lp = strchr(argv[argi], '=');
                  configfn = strdup(lp+1);
            }
            else if (argnmatch(argv[argi], "--dump-config")) {
                  load_client_config(configfn);
                  dump_client_config();
                  return 0;
            }
            else if (strcmp(argv[argi], "--local") == 0) {
                  localmode = 1;
            }
            else if (strcmp(argv[argi], "--test") == 0) {
                  testmode(configfn);
            }
      }

      /* Signals */
      setup_signalhandler("hobbitd_client");
      memset(&sa, 0, sizeof(sa));
      sa.sa_handler = sig_handler;
      sigaction(SIGHUP, &sa, NULL);
      signal(SIGCHLD, SIG_IGN);

      save_errbuf = 0;
      running = 1;

      while (running) {
            char *eoln, *restofmsg, *p;
            char *metadata[MAX_META+1];
            int metacount;

            msg = get_hobbitd_message(C_CLIENT, argv[0], &seq, NULL);
            if (msg == NULL) {
                  errprintf("Failed to get a message, terminating\n");
                  running = 0;
                  continue;
            }

            if (reloadconfig || (time(NULL) >= nextconfigload)) {
                  nextconfigload = time(NULL) + 600;
                  reloadconfig = 0;
                  if (!localmode) load_hostnames(xgetenv("BBHOSTS"), NULL, get_fqdn());
                  load_client_config(configfn);
            }

            /* Split the message in the first line (with meta-data), and the rest */
            eoln = strchr(msg, '\n');
            if (eoln) {
                  *eoln = '\0';
                  restofmsg = eoln+1;
            }
            else {
                  restofmsg = "";
            }

            metacount = 0; 
            p = gettok(msg, "|");
            while (p && (metacount < MAX_META)) {
                  metadata[metacount++] = p;
                  p = gettok(NULL, "|");
            }
            metadata[metacount] = NULL;

            if ((metacount > 4) && (strncmp(metadata[0], "@@client", 8) == 0)) {
                  time_t timestamp = atoi(metadata[1]);
                  char *sender = metadata[2];
                  char *hostname = metadata[3];
                  char *clientos = metadata[4];
                  char *clientclass = metadata[5];
                  enum ostype_t os;
                  namelist_t *hinfo = NULL;

                  hinfo = (localmode ? localhostinfo(hostname) : hostinfo(hostname));
                  if (!hinfo) continue;
                  os = get_ostype(clientos);

                  /* Default clientclass to the OS name */
                  if (!clientclass || (*clientclass == '\0')) clientclass = clientos;

                  combo_start();
                  switch (os) {
                    case OS_FREEBSD: 
                        handle_freebsd_client(hostname, clientclass, os, hinfo, sender, timestamp, restofmsg);
                        break;

                    case OS_NETBSD: 
                        handle_netbsd_client(hostname, clientclass, os, hinfo, sender, timestamp, restofmsg);
                        break;

                    case OS_OPENBSD: 
                        handle_openbsd_client(hostname, clientclass, os, hinfo, sender, timestamp, restofmsg);
                        break;

                    case OS_LINUX22: 
                    case OS_LINUX: 
                    case OS_RHEL3: 
                        handle_linux_client(hostname, clientclass, os, hinfo, sender, timestamp, restofmsg);
                        break;

                    case OS_DARWIN:
                        handle_darwin_client(hostname, clientclass, os, hinfo, sender, timestamp, restofmsg);
                        break;

                    case OS_SOLARIS: 
                        handle_solaris_client(hostname, clientclass, os, hinfo, sender, timestamp, restofmsg);
                        break;

                    case OS_HPUX: 
                        handle_hpux_client(hostname, clientclass, os, hinfo, sender, timestamp, restofmsg);
                        break;

                    case OS_OSF: 
                        handle_osf_client(hostname, clientclass, os, hinfo, sender, timestamp, restofmsg);
                        break;

                    case OS_AIX: 
                        handle_aix_client(hostname, clientclass, os, hinfo, sender, timestamp, restofmsg);
                        break;

                    case OS_IRIX:
                        handle_irix_client(hostname, clientclass, os, hinfo, sender, timestamp, restofmsg);
                        break;
                        
                          case OS_SCO_SV:
                          handle_sco_sv_client(hostname, clientclass, os, hinfo, sender, timestamp, restofmsg);
                        break;
                        
                    case OS_WIN32: 
                    case OS_SNMP: 
                    case OS_UNKNOWN:
                        errprintf("No client backend for OS '%s' sent by %s\n", clientos, sender);
                        break;
                  }
                  combo_end();
            }
            else if (strncmp(metadata[0], "@@shutdown", 10) == 0) {
                  printf("Shutting down\n");
                  running = 0;
                  continue;
            }
            else if (strncmp(metadata[0], "@@logrotate", 11) == 0) {
                  char *fn = xgetenv("HOBBITCHANNEL_LOGFILENAME");
                  if (fn && strlen(fn)) {
                        freopen(fn, "a", stdout);
                        freopen(fn, "a", stderr);
                  }
                  continue;
            }
            else {
                  /* Unknown message - ignore it */
            }
      }

      return 0;
}


Generated by  Doxygen 1.6.0   Back to index