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

pmda.c

/*
 * Web PMDA, based on generic driver for a daemon-based PMDA
 *
 * Copyright (c) 2000-2003 Silicon Graphics, Inc.  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
 * 
 * Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
 * Mountain View, CA 94043, USA, or: http://www.sgi.com
 */

#ident "$Id: pmda.c,v 2.23 2004/06/20 22:38:25 kenmcd Exp $"

#include "pmapi.h"

#include "./weblog.h"
#include <stdio.h>
/*
 * see comment in weblog.h re: NON_POSIX_REGEX
 */
#include <regex.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/un.h>
#include <netdb.h>
#include <signal.h>
#include <string.h>
#include <errno.h>

#ifdef HAVE_SCHED_H
#include <sched.h>
#endif

#ifdef IS_SOLARIS
#define CLONE_VM        0x00000100 
#elif !defined(CLONE_VM)
#define CLONE_VM        0x0
#endif

#ifndef HAVE_SPROC
int sproc (void (*entry) (void *), int flags, void *arg);
#endif

#include "domain.h"

/* path to the configuration file */
static char *configFileName = (char*)0;

/* line number of configuration file */
static int  line = 0;

/* number of errors in configuration file */
static int  err = 0;

/* configured for num of servers */
__uint32_t  wl_numServers = 0;

/* number of active servers */
__uint32_t  wl_numActive = 0;

/* check logs every 15 seconds by default */
__uint32_t  wl_refreshDelay = 15;

/* re-open logs if unchanged in this number of seconds */
__uint32_t  wl_chkDelay = 20;

/* max servers per sproc */
__uint32_t  wl_sprocThresh = 80;

/* number of sprocs spawned */
__uint32_t  wl_numSprocs = 0;

/* number of regex parsed */
__uint32_t  wl_numRegex = 0;

/* list of web servers */
WebServer   *wl_servers = (WebServer*)0;

/* list of regular expressions */
WebRegex    *wl_regexTable = (WebRegex*)0;

/* instance table of web servers */
pmdaInstid  *wl_serverInst = (pmdaInstid*)0;

/* pmAPI hack to piggy back requestes from PMCD */
extern int _pm_moreinput;

/* list of sprocs spawned from the main process */
WebSproc    *wl_sproc;

/* default name for log file */
char        *wl_logFile = "weblog.log";

/* default path to help file */
char        wl_helpFile[MAXPATHLEN];

/*
 * Usage Information
 */

void
usage(void)
{
    fprintf(stderr, 
          "Usage: %s [options] configfile\n\
\n\
Options\n\
  -C            check configuration and exit\n\
  -d domain PMDA domain number\n\
  -h helpfile   get help text from helpfile rather than default path\n\
  -i port   expect PMCD to connect on given inet port (number or name)\n\
  -l logfile      redirect diagnostics and trace output (default weblog.log)\n\
  -n idlesec      number of seconds of weblog inactivity before checking for\n\
            log rotation\n\
  -p        expect PMCD to supply stdin/stdout (pipe)\n\
  -S num    number of web servers per sproc\n\
  -t delay  maximum number of seconds between reading weblog files\n\
  -u socket expect PMCD to connect on given unix domain socket\n\
\n\
If none of the -i, -p or -u options are given, the configuration file is\n\
checked and then %s terminates.\n", pmProgname, pmProgname);
    exit(1);
}

void
logmessage(int priority, const char *format, ...)
{
    va_list     arglist;
    char    buffer[2048];
    char    *level;
    char    *p;
    time_t  now;

    buffer[0] = '\0';
    time(&now);

#if defined(sgi)
    priority = LOG_PRI(priority);
#endif
    switch (priority) {
        case LOG_EMERG :
            level = "Emergency";
            break;
        case LOG_ALERT :
            level = "Alert";
            break;
        case LOG_CRIT :
            level = "Critical";
            break;
        case LOG_ERR :
            level = "Error";
            break;
        case LOG_WARNING :
            level = "Warning";
            break;
        case LOG_NOTICE :
            level = "Notice";
            break;
        case LOG_INFO :
            level = "Info";
            break;
        case LOG_DEBUG :
            level = "Debug";
            break;
        default:
            level = "???";
            break;
    }

    va_start (arglist, format);
    vsnprintf (buffer, sizeof(buffer), format, arglist);
    for (p = buffer; *p; p++);
    if (*(--p) == '\n') *p = '\0';
    fprintf (stderr, "[%.19s] %s(%d) %s: %s\n", ctime(&now), pmProgname, (int)getpid(), level, buffer) ;
    va_end (arglist) ;
}

/*
 * Errors message during parsing of config file
 */

static void
yyerror(char *s)
{
    fprintf(stderr, "[%s:%d] Error: %s\n", configFileName, line, s);
    err++;
}

/*
 * Warning message during parsing of config file
 */

static void
yywarn(char *s)
{
    fprintf(stderr, "[%s:%d] Warning: %s\n", configFileName, line, s);
}

/*
 * skip remaining characters on this line
 */

static void
skip_to_eol(FILE *f)
{
    int           c;

    while ((c = fgetc(f)) != EOF) {
      if (c == '\n')
          return;
    }
    return;
}

/*
 * Are we at the end of the line (sucks up spaces and tabs which may preceed 
 * EOL)
 */

static void
check_to_eol(FILE *f)
{
    int           c;
    int           i = 0;

    while ((c = fgetc(f)) != EOF) {
      if (c == '\n')
          break;
      if (c == ' ' || c == '\t')
          continue;
      i++;
    }
    if (i)
      yywarn("additional words in line, ignored");

    return;
}

/*
 * Get a word. A word if any text until a whitespace
 */

static int
getword(FILE *f, char *buf, int len)
{
    int           c;
    char    *bend = &buf[len-1];

    while ((c = fgetc(f)) != EOF) {
      if (c == ' ' || c == '\t')
          continue;
      ungetc(c, f);
      break;
    }

    while ((c = fgetc(f)) != EOF) {
      if (c == ' ' || c == '\t')
          break;
      if (c == '\n') {
          ungetc(c, f);
          break;
      }
      if (buf < bend) {
          *buf++ = c;
          continue;
      }
      else {
          yyerror("word too long, remainder of line ignored");
          return -1;
      }
    }
    *buf = '\0';

    return c == EOF ? 0 : 1;
}

/*
 * Get the next line from buffer
 */

static int
get_to_eol(FILE *f, char *buf, int len)
{
    int           c;
    char    *bend = &buf[len-1];

    while ((c = fgetc(f)) != EOF) {
      if (c == ' ' || c == '\t')
          continue;
      ungetc(c, f);
      break;
    }

    while ((c = fgetc(f)) != EOF) {
      if (c == '\n')
          break;
      if (buf < bend) {
          *buf++ = c;
          continue;
      }
      else {
          yyerror("list of words too long, remainder of line ignored");
          return -1;
      }
    }
    *buf = '\0';
    return c == EOF ? 0 : 1;
}

/*
 * Replacement for pmdaMainLoop
 * Has a select loop on pipe from PMCD, reads in PDUs and acts on them 
 * appropriately.
 */

static void
receivePDUs(pmdaInterface *dispatch)
{
    int                 nfds = 0;
    time_t        interval = 0;
    int                 sts = 0;
    struct timeval      timeout;
    fd_set        rfds;


    FD_ZERO(&rfds);
    nfds = fileno(stdin)+1;

    for (;;) {

      FD_SET(fileno(stdin), &rfds);
      gettimeofday(&timeout, NULL);
      timeout.tv_usec = 0;
      interval = (time_t)wl_refreshDelay - (timeout.tv_sec % (time_t)wl_refreshDelay);
      timeout.tv_sec = interval;

#ifdef PCP_DEBUG
      if (pmDebug & DBG_TRACE_APPL1)
          logmessage(LOG_DEBUG, "Select set for %d seconds\n", 
                   interval);
#endif

      sts = select(nfds, &rfds, (fd_set*)0, (fd_set*)0, &timeout);
      if (sts < 0) {
          logmessage(LOG_ERR, "Error on fetch select: %s", 
                   strerror(errno));
          exit(1);
      }  

      if (sts == 0) {

#ifdef PCP_DEBUG
          if (pmDebug & DBG_TRACE_APPL1)
            logmessage(LOG_DEBUG, "Select timed out\n");
#endif

          refreshAll();
          continue;
      }

      if (__pmdaMainPDU(dispatch) < 0){
          exit(1);
          /*NOTREACHED*/
      }

      if (interval == 0) {
          refreshAll();
      }

    }
}

/*
 * Catch an SPROC dying, report what we know, and exit
 * -- when main exits, other sprocs will get SIGHUP and exit quietly
 */
/*ARGSUSED0*/
static void
onchld(int dummy)
{
    int done;
    int waitStatus;
    int sprocNum;

    while ((done = waitpid(-1, &waitStatus, WNOHANG)) > 0) {
      for (sprocNum = 1; 
           wl_sproc[sprocNum].pid != done && sprocNum <= wl_numSprocs; 
           sprocNum++);

      if (sprocNum > wl_numSprocs)
          {
            logmessage(LOG_INFO, 
                  "Unexpected child process (pid=%d) died!\n",
                  done);
            continue;
          }

      if (WIFEXITED(waitStatus)) {

          if (WEXITSTATUS(waitStatus) == 0)
            logmessage(LOG_INFO, 
                       "Sproc %d (pid=%d) exited normally\n",
                       sprocNum, done);
          else
            logmessage(LOG_INFO, 
                       "Sproc %d (pid=%d) exited with status = %d\n",
                       sprocNum, done, WEXITSTATUS(waitStatus));
      }
      else if (WIFSIGNALED(waitStatus)) {
          
#ifdef WCOREDUMP
          if (WCOREDUMP(waitStatus))
            logmessage(LOG_INFO, 
                       "Sproc %d (pid=%d) received signal = %d and dumped core\n",
                       sprocNum, done, WTERMSIG(waitStatus));
#endif
          logmessage(LOG_INFO, 
                   "Sproc %d (pid=%d) received signal = %d\n",
                   sprocNum, done, WTERMSIG(waitStatus));
      }
      else {
          logmessage(LOG_INFO, 
                   "Sproc %d (pid=%d) died, reason unknown\n",
                   sprocNum, done);
      }

      logmessage(LOG_INFO, 
                 "Sproc %d managed servers %d to %d\n",
                 sprocNum,
                 wl_sproc[sprocNum].firstServer,
                 wl_sproc[sprocNum].lastServer);
    }

    logmessage(LOG_INFO, "Main process exiting\n");
    exit(0);
}

/*
 * Parse command line args and the configuration file. Also sets up and fires 
 * off the required sprocs
 */

int
main(int argc, char **argv)
{
    extern char         *optarg;
    extern int          optind;
    extern int          pmDebug;

    WebServer           *server = (WebServer *)0;
    WebSproc            *proc = (WebSproc *)0;

    char          *endnum = (char*)0;
    char          buf1[FILENAME_MAX];
    char          buf2[FILENAME_MAX];
    char          emess[120];
    char          *p;
    char          *pstart, *pend;
    char          argsDone, argFound;
    char          *err_msg;

    int                 i = 0;
    int                 argCount = 0;
    int                 checkOnly = 0;
    int                 sts = 0;
    int                 n = 0;
    int                 serverTableSize = 0;
    int                 regexTableSize = 0;

    FILE          *configFile = (FILE*)0;
    FILE          *tmpFp = (FILE*)0;

    pmdaInterface desc;
    struct timeval      delta;

    struct {
      int         *argPos;
      char        *argString;
    } regexargs[2];

#ifdef PCP_DEBUG
    struct timeval      start;
    struct timeval      end;
    double        startTime;
#endif

    /* trim cmd name of leading directory components */
    pmProgname = argv[0];
    for (p = pmProgname; *p; p++) {
      if (*p == '/')
          pmProgname = p+1;
    }

#ifdef PCP_DEBUG
    gettimeofday(&start, NULL);
#endif

    wl_isDSO = 0;

    snprintf(wl_helpFile, sizeof(wl_helpFile),
            "%s/weblog/help", pmGetConfig("PCP_PMDAS_DIR"));
    pmdaDaemon(&desc, PMDA_INTERFACE_2, pmProgname, WEBSERVER,
            wl_logFile, wl_helpFile);

    while ((n = pmdaGetOpt(argc, argv, "CD:d:h:i:l:n:pS:t:u:?", 
                     &desc, &err)) != EOF) {
      switch (n) {

      case 'C':
          checkOnly = 1;
          break;

      case 'S':
          wl_sprocThresh = (int)strtol(optarg, &endnum, 10);
          if (*endnum != '\0') {
            fprintf(stderr, "%s: -S requires numeric argument\n",
                  pmProgname);
            err++;
          }
          break;
          
      case 'n':
          if (pmParseInterval(optarg, &delta, &err_msg) < 0) {
                    (void)fprintf(stderr,
                            "%s: -n requires a time interval: %s\n",
                            err_msg, pmProgname);
                    free(err_msg);
                    err++;
                }
          else {
            wl_chkDelay = delta.tv_sec;
          }
          break;
          
      case 't':
          if (pmParseInterval(optarg, &delta, &err_msg) < 0) {
                    (void)fprintf(stderr,
                            "%s: -t requires a time interval: %s\n",
                            err_msg, pmProgname);
                    free(err_msg);
                    err++;
                }
          else {
            wl_refreshDelay = delta.tv_sec;
          }
          break;

      default:
          fprintf(stderr, "%s: Unknown option \"-%c\"", pmProgname, (char)n);
          err++;
          break;
      }
    }

    if (err || optind != argc-1) {
      usage();
      /*NOTREACHED*/
    }

    line = 0;
    configFileName = argv[optind];
    configFile = fopen(configFileName, "r");
    
    if (configFile == (FILE*)0) {
      fprintf(stderr, "Unable to open config file %s\n", configFileName);
      usage();
      /*NOTREACHED*/
    }

    if (checkOnly == 0) {
      /*
       * if doing more than just parsing, force errors from here
       * on into the logfile
       */
      pmdaOpenLog(&desc);
    }

    /*
     * Parse the configuration file
     */

    /* These settings should be reflected below */
    regexargs[0].argString = strdup("method");
    regexargs[1].argString = strdup("size");

    while(!feof(configFile)) {

      sts = getword(configFile, buf1, sizeof(buf1));

      if (sts == 0) {
          /* End of File */
          break;
      }

      line++;

      if (sts < 0) {
          /* error, reported in getword() */
          skip_to_eol(configFile);
          continue;
      }
      
      if (buf1[0] == '\0' || buf1[0] == '#') {
          /* comment, or nothing in the line, next line please */
          skip_to_eol(configFile);
          continue;
      }

      if (strcasecmp(buf1, "regex_posix") == 0) {
          /*
           * Parse a regex specification
           */

          if (wl_numRegex == regexTableSize) {
            regexTableSize += 2;
            wl_regexTable = (WebRegex*)realloc(wl_regexTable,
                                 regexTableSize * sizeof(WebRegex));
            if (wl_regexTable == (WebRegex*)0) {
                __pmNoMem("main.wl_regexInst", 
                       (wl_numRegex + 1) * sizeof(WebRegex),
                       PM_FATAL_ERR);
                /*NOTREACHED*/
            }
          }

          sts = getword(configFile, buf1, sizeof(buf1));

          if (sts <= 0 || buf1[0] == '\0') {
            if (sts >= 0)
                yyerror("unable to extract regex name");
            skip_to_eol(configFile);
            continue;
          }

          wl_regexTable[wl_numRegex].name = strdup(buf1);

          if (wl_numRegex) {
            for (n = 0; n < wl_numRegex; n++) {
                if (strcmp(wl_regexTable[n].name, 
                         wl_regexTable[wl_numRegex].name) == 0) {

                  snprintf(emess, sizeof(emess), "duplicate regex name (%s)",
                        wl_regexTable[wl_numRegex].name);
                  yyerror(emess);
                  break;
                }
            }
            if (n < wl_numRegex) {
                skip_to_eol(configFile);
                continue;
            }
          }

          sts = getword(configFile, buf1, sizeof(buf1));

          if (sts <= 0 || buf1[0] == '\0') {
            if (sts >= 0)
                yyerror("unable to extract regex match parameters");
            skip_to_eol(configFile);
            continue;
          }

          regexargs[0].argPos = &(wl_regexTable[wl_numRegex].methodPos);
          regexargs[1].argPos = &(wl_regexTable[wl_numRegex].sizePos);
          wl_regexTable[wl_numRegex].methodPos = 0;
          wl_regexTable[wl_numRegex].sizePos = 0;
          wl_regexTable[wl_numRegex].sizePos = 0;
          wl_regexTable[wl_numRegex].s_statusPos = 0;

          pstart = buf1;
          argCount = 0;
          do {
            argFound = 0;
            argsDone = 1;
            argCount++;
            for(pend = pstart; *pend; pend++) {
                if(*pend == ',') {
                  *pend = '\0';
                  argsDone = 0;
                  break;
                }
            }
            for(i = 0; i < sizeof(regexargs) / sizeof(regexargs[0]); i++) {
                if(strcmp(pstart, regexargs[i].argString) == 0) {
                  *regexargs[i].argPos = argCount;
                  argFound = 1;
                  break;
                }
            }
            if(!argFound) {
                /* not the old method,size style */
                switch(pstart[0]) {
                case '1':
                  wl_regexTable[wl_numRegex].methodPos = argCount;
                  argFound = 1;
                  break;
                case '2':
                  wl_regexTable[wl_numRegex].sizePos = argCount;
                  argFound = 1;
                  break;
                case '3':
                  wl_regexTable[wl_numRegex].c_statusPos = argCount;
                  argFound = 1;
                  break;
                case '4':
                  wl_regexTable[wl_numRegex].s_statusPos = argCount;
                  argFound = 1;
                  break;
                case '-':
                  wl_regexTable[wl_numRegex].methodPos = argCount++;
                  wl_regexTable[wl_numRegex].sizePos = argCount;
                  argFound = 1;
                  argsDone = 1;
                  break;
                default:
                  break;
                }
            }
            pstart = pend + 1;
          } while(argsDone == 0 && argFound != 0);

          if(argFound == 0) {
            yyerror("invalid keyword in regex match parameters");
            skip_to_eol(configFile);
            continue;
            }

          sts = get_to_eol(configFile, buf1, sizeof(buf1));

          if (sts <= 0 || buf1[0] == '\0') {
            if (sts >= 0)
                yyerror("unable to extract regex");
            else
                skip_to_eol(configFile);
            continue;
          }

          wl_regexTable[wl_numRegex].regex = malloc(sizeof(*wl_regexTable[wl_numRegex].regex));
          if(wl_regexTable[wl_numRegex].regex == NULL) {
            __pmNoMem("main.wl_regex", 
                    sizeof(*wl_regexTable[wl_numRegex].regex),
                    PM_FATAL_ERR);
            /*NOTREACHED*/
          }

          if (regcomp(wl_regexTable[wl_numRegex].regex, buf1, REG_EXTENDED) != 0) {
            yyerror("unable to compile regex");
            continue;
          }

#ifdef PCP_DEBUG
          if (pmDebug & DBG_TRACE_APPL0)
            logmessage(LOG_DEBUG, "%d regex %s: %s\n", 
                  wl_numRegex, wl_regexTable[wl_numRegex].name, buf1);
#endif

          wl_regexTable[wl_numRegex].posix_regexp = 1;
          wl_numRegex++;
      }
#ifdef NON_POSIX_REGEX
      else if (strcasecmp(buf1, "regex") == 0) {
          /*
           * Parse a regex specification
           */

          if (wl_numRegex == regexTableSize) {
            regexTableSize += 2;
            wl_regexTable = (WebRegex*)realloc(wl_regexTable,
                                 regexTableSize * sizeof(WebRegex));
            if (wl_regexTable == (WebRegex*)0) {
                __pmNoMem("main.wl_regexInst", 
                       (wl_numRegex + 1) * sizeof(WebRegex),
                       PM_FATAL_ERR);
                /*NOTREACHED*/
            }
          }

          sts = getword(configFile, buf1, sizeof(buf1));

          if (sts <= 0 || buf1[0] == '\0') {
            if (sts >= 0)
                yyerror("unable to extract regex name");
            skip_to_eol(configFile);
            continue;
          }

          wl_regexTable[wl_numRegex].name = strdup(buf1);

          if (wl_numRegex) {
            for (n = 0; n < wl_numRegex; n++) {
                if (strcmp(wl_regexTable[n].name, 
                         wl_regexTable[wl_numRegex].name) == 0) {

                  snprintf(emess, sizeof(emess), "duplicate regex name (%s)",
                        wl_regexTable[wl_numRegex].name);
                  yyerror(emess);
                  break;
                }
            }
            if (n < wl_numRegex) {
                skip_to_eol(configFile);
                continue;
            }
          }

          sts = get_to_eol(configFile, buf1, sizeof(buf1));

          if (sts <= 0 || buf1[0] == '\0') {
            if (sts >= 0)
                yyerror("unable to extract regex");
            else
                skip_to_eol(configFile);
            continue;
          }

          if(strstr(buf1, "$2") != NULL && strstr(buf1, "$3") != NULL ) {
            /* 
             * extended caching server format 
             *
             * although these aren't used in the non-regex code, they
             * are a good enough placeholder until server->counts.extendedp
             * is set below
             */
            wl_regexTable[wl_numRegex].c_statusPos = 1;
            wl_regexTable[wl_numRegex].s_statusPos = 1;

            }
          wl_regexTable[wl_numRegex].np_regex = regcmp(buf1, (char*)0);

          if (wl_regexTable[wl_numRegex].np_regex == (char*)0) {
            yyerror("unable to compile regex");
            continue;
          }

#ifdef PCP_DEBUG
          if (pmDebug & DBG_TRACE_APPL0)
            logmessage(LOG_DEBUG, "%d NON POSIX regex %s: %s\n", 
                  wl_numRegex, wl_regexTable[wl_numRegex].name, buf1);
#endif

          wl_regexTable[wl_numRegex].posix_regexp = 0;
          wl_numRegex++;
      }
#endif
      else if (strcasecmp(buf1, "server") == 0) {
          /*
           * Parse a server specification
           */

          if (wl_numServers == serverTableSize) {
            serverTableSize += 4;
            wl_serverInst = (pmdaInstid*)realloc(wl_serverInst,
                               serverTableSize * sizeof(pmdaInstid));
            if (wl_serverInst == (pmdaInstid*)0) {
                __pmNoMem("main.wl_serverInst", 
                       (wl_numServers + 1) * sizeof(pmdaInstid),
                       PM_FATAL_ERR);
                /*NOTREACHED*/
            }

            wl_servers = (WebServer*)realloc(wl_servers,
                               serverTableSize * sizeof(WebServer));
            if (wl_servers == (WebServer*)0) {
                __pmNoMem("main.wl_servers", 
                       (wl_numServers + 1) * sizeof(WebServer),
                       PM_FATAL_ERR);
                /*NOTREACHED*/
            }
          }

          /* Get server name */

          sts = getword(configFile, buf1, sizeof(buf1));

          if (sts <= 0 || buf1[0] == '\0') {
            if (sts >= 0)
                yyerror("unable to extract server name");
            skip_to_eol(configFile);
            continue;
          }

          if (wl_numServers) {
            for (n = 0; n < wl_numServers; n++) {
                if (strcmp(buf1, wl_serverInst[n].i_name) == 0) {
                  snprintf(emess, sizeof(emess), "duplicate server name (%s)", buf1);
                  yyerror(emess);
                  break;
                }
            }
            if (n < wl_numServers) {
                skip_to_eol(configFile);
                continue;
            }
          }

          wl_serverInst[wl_numServers].i_name = strdup(buf1);
          wl_serverInst[wl_numServers].i_inst = wl_numServers;

          server = &(wl_servers[wl_numServers]);
          memset(server, 0, sizeof(*server));
          server->access.filePtr = -1;
          server->error.filePtr = -1;

          /* Get server active flag */

          sts = getword(configFile, buf1, sizeof(buf1));

          if (sts <= 0 || buf1[0] == '\0') {
            if (sts >= 0)
                yyerror("unable to extract active flag");
            skip_to_eol(configFile);
            continue;
          }

          if (strcasecmp(buf1, "on") == 0) {
            server->counts.active = 1;
          }
          else if (strcasecmp(buf1, "off") == 0) {
            server->counts.active = 0;
          }
          else {
            yyerror("illegal active flag");
            skip_to_eol(configFile);
            continue;
          }

          /* Get access log regex and file name */


          sts = getword(configFile, buf1, sizeof(buf1));

          if (sts <= 0 || buf1[0] == '\0') {
            if (sts >= 0)
                yyerror("unable to extract access log regex");
            skip_to_eol(configFile);
            continue;
          }

          sts = getword(configFile, buf2, sizeof(buf2));

          if (sts <= 0 || buf2[0] == '\0') {
            if (sts >= 0)
                yyerror("unable to extract access log name");
            skip_to_eol(configFile);
            continue;
          }

          for (n = 0; n < wl_numRegex; n++)
            if (strcmp(buf1, wl_regexTable[n].name) == 0)
                break;

          if (n == wl_numRegex) {
            snprintf(emess, sizeof(emess), "access log regex \"%s\" not defined", buf1);
            yyerror(emess);
            skip_to_eol(configFile);
            continue;
          } else if(wl_regexTable[n].c_statusPos > 0 &&
                    wl_regexTable[n].s_statusPos > 0) {
            /* common extended format or one that uses the same codes */
            server->counts.extendedp = 1;   
              if(strcmp(wl_regexTable[n].name, "SQUID") == 0) {
                /* 
                 * default squid format - uses text codes not numerics
                 * so it *has* to be a special case
                 */
                server->counts.extendedp = 2;   
            }
          }

          server->access.format = n;
          server->access.fileName = strdup(buf2);
          
          if (server->counts.active) {
            tmpFp = fopen(server->access.fileName, "r");
            if (tmpFp == (FILE*)0) {
                snprintf(emess, sizeof(emess), "cannot open access log \"%s\"", buf2);
                yywarn(emess);
                server->access.filePtr = -1;
            }
            else
                fclose(tmpFp);
          }

          /* Get error log regex and file name */

          sts = getword(configFile, buf1, sizeof(buf1));

          if (sts <= 0 || buf1[0] == '\0') {
            if (sts >= 0)
                yyerror("unable to extract error log regex");
            skip_to_eol(configFile);
            continue;
          }

          sts = getword(configFile, buf2, sizeof(buf2));

          if (sts <= 0 || buf2[0] == '\0') {
            if (sts >= 0)
                yyerror("unable to extract error log name");
            skip_to_eol(configFile);
            continue;
          }

          for (n = 0; n < wl_numRegex; n++)
            if (strcmp(buf1, wl_regexTable[n].name) == 0)
                break;

          if (n == wl_numRegex) {
            snprintf(emess, sizeof(emess), "error log regex \"%s\" not defined", buf1);
            yyerror(emess);
            skip_to_eol(configFile);
            continue;
          }

          server->error.format = n;
          server->error.fileName = strdup(buf2);
          
          if (server->counts.active) {
            tmpFp = fopen(server->error.fileName, "r");
            if (tmpFp == (FILE*)0) {
                snprintf(emess, sizeof(emess), "cannot open error log \"%s\"", buf2);
                yywarn(emess);
                server->error.filePtr = -1;
            }
            else
                fclose(tmpFp);
          }

          check_to_eol(configFile);

#ifdef PCP_DEBUG
          if (pmDebug & DBG_TRACE_APPL0) {
            logmessage(LOG_DEBUG, "%d Server %s, %d, %d, %s, %d, %s\n",
                  wl_numServers,
                  wl_serverInst[wl_numServers].i_name,
                  server->counts.active,
                  server->access.format,
                  server->access.fileName,
                  server->error.format,
                  server->error.fileName);
          }
#endif

          if (server->counts.active)
            wl_numActive++;

          wl_numServers++;
      }
      else {
          snprintf(emess, sizeof(emess), "illegal keyword \"%s\"", buf1);
          yyerror(emess);
          skip_to_eol(configFile);
          continue;
      }
    }

    if (wl_numServers == 0) {
      yyerror("no servers were specified in the configuration file!");
    }

    fclose(configFile);

    if (checkOnly || err) {
      /* errors, or parse only, no PMCD communication option */
      exit(err);
    }

    wl_indomTable[0].it_numinst = wl_numServers;
    wl_indomTable[0].it_set = wl_serverInst;

    web_init(&desc);
    pmdaConnect(&desc);

    /* catch any sprocs dying */

    signal(SIGCHLD, onchld);

    /* fire off all the sprocs that we need */

    wl_numSprocs = (wl_numServers-1) / wl_sprocThresh;
    wl_sproc = (WebSproc*)malloc((wl_numSprocs+1) * sizeof(WebSproc));
    if (wl_sproc == NULL) {
      logmessage(LOG_ERR,
               "wl_numServers = %d, wl_sprocThresh = %d",
               wl_numServers,
               wl_sprocThresh);
      __pmNoMem("main.wl_sproc", 
              (wl_numSprocs+1) * sizeof(WebSproc),
              PM_FATAL_ERR);
      /*NOTREACHED*/
    }


    for (n = 0; n <= wl_numSprocs; n++)
      {
          proc = &wl_sproc[n];
          proc->pid = -1;
          proc->methodStr = (char *)0;
          proc->sizeStr = (char *)0;
          proc->c_statusStr = (char *)0;
          proc->s_statusStr = (char *)0;
          proc->strLength = 0;
      }

    if (wl_numSprocs) {

      for (n=1; n<=wl_numSprocs; n++) {
          proc = &wl_sproc[n];

          sts = pipe(proc->inFD);
          if (sts) {
            logmessage(LOG_ERR, 
                       "Cannot allocate fileDes 1 for sproc[%d]", 
                       n);
            exit(1);
          }

#ifdef PCP_DEBUG
          if (pmDebug & DBG_TRACE_APPL2)
            logmessage(LOG_DEBUG,
                        "Creating in pipe (in=%d, out=%d) for sproc %d\n",
                        proc->inFD[0],
                        proc->inFD[1],
                        n);
#endif

          sts = pipe(proc->outFD);
          if (sts) {
            logmessage(LOG_ERR, 
                       "Cannot allocate fileDes 2 for sproc[%d]", 
                       n);
            exit(1);
          }

#ifdef PCP_DEBUG
          if (pmDebug & DBG_TRACE_APPL2)
            logmessage(LOG_DEBUG,
                        "Creating out pipe (in=%d, out=%d) for sproc %d\n",
                        proc->outFD[0],
                        proc->outFD[1],
                        n);
#endif

          proc->firstServer = (n)*wl_sprocThresh;
          if (n != wl_numSprocs)
            proc->lastServer = proc->firstServer +
                wl_sprocThresh - 1;
          else
            proc->lastServer = wl_numServers - 1;

          logmessage(LOG_INFO, 
                   "Creating sproc [%d] for servers %d to %d\n",
                   n, proc->firstServer, proc->lastServer);

          proc->id = n;

#ifndef HAVE_SPROC
          proc->pid = sproc(sprocMain, CLONE_VM, (void*)(&proc->id));
#else
          proc->pid = sproc(sprocMain, PR_SADDR, (void*)(&proc->id));
#endif

          if (proc->pid < 0) {
            logmessage(LOG_ERR, "main: error creating sproc %d: %s\n",
                       n, strerror(errno));
            exit(1);
          }

#ifdef PCP_DEBUG
          if(pmDebug & DBG_TRACE_APPL0) {
            logmessage(LOG_INFO,
                     "main: created sproc %d: pid %d\n",
                     n,
                     proc->pid);
          }
#endif

          /* close off unwanted pipes */

          if(close(proc->inFD[0]) < 0) {
            logmessage(LOG_WARNING,
                     "main: pipe close(fd=%d) failed: %s\n",
                     proc->inFD[0],
                     strerror(errno));
          }
          if(close(proc->outFD[1]) < 0) {
            logmessage(LOG_WARNING,
                     "main: pipe close(fd=%d) failed: %s\n",
                     proc->outFD[1],
                     strerror(errno));
          }
      }
    }

    wl_sproc[0].firstServer = 0;
    wl_sproc[0].lastServer  = (wl_numServers <= wl_sprocThresh) ?
      wl_numServers - 1 : wl_sprocThresh - 1;

#ifdef PCP_DEBUG
    if (pmDebug & DBG_TRACE_APPL0)
      logmessage(LOG_DEBUG,
                  "Main process will monitor servers 0 to %d\n",
                  wl_sproc[0].lastServer);
#endif

    for (n=0; n <= wl_sproc[0].lastServer; n++) {
      if (wl_servers[n].counts.active) {
          openLogFile(&(wl_servers[n].access));
          openLogFile(&(wl_servers[n].error));
      }
    }

#ifdef PCP_DEBUG
    gettimeofday(&end, NULL);
    startTime = (end.tv_sec - start.tv_sec) + 
              ((end.tv_usec - start.tv_usec) / 1000000.0);
    if (pmDebug & DBG_TRACE_APPL0)
      logmessage(LOG_DEBUG, "Agent started in %f seconds", startTime);
#endif

    receivePDUs(&desc);

    logmessage(LOG_INFO, "Connection to PMCD closed by PMCD\n");
    logmessage(LOG_INFO, "Last fetch took %d msec\n", wl_catchupTime);
    logmessage(LOG_INFO, "Exiting...\n");

    return 0;
}

Generated by  Doxygen 1.6.0   Back to index