OSSP CVS Repository

ossp - ossp-pkg/fsl/fsl.c 1.9
Not logged in
[Honeypot]  [Browse]  [Directory]  [Home]  [Login
[Reports]  [Search]  [Ticket]  [Timeline
  [Raw

ossp-pkg/fsl/fsl.c 1.9
/*
**  OSSP fsl - Faking Syslog Library
**  Copyright (c) 2002 Ralf S. Engelschall <rse@engelschall.com>
**  Copyright (c) 2002 The OSSP Project <http://www.ossp.org/>
**  Copyright (c) 2002 Cable & Wireless Deutschland <http://www.cw.com/de/>
**
**  This file is part of OSSP fsl, a syslog(3) API faking library which
**  can be found at http://www.ossp.org/pkg/lib/fsl/.
**
**  Permission to use, copy, modify, and distribute this software for
**  any purpose with or without fee is hereby granted, provided that
**  the above copyright notice and this permission notice appear in all
**  copies.
**
**  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
**  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
**  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
**  IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
**  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
**  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
**  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
**  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
**  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
**  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
**  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
**  SUCH DAMAGE.
**
**  fsl.c: OSSP fsl library
*/

/* standard includes we use */
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>

/* standard include we re-implement */
#include <syslog.h>

/* third party (linked in) */
#include "l2.h"
#include "cfg.h"
#include "pcre.h"

/* default for the dedicated logfile */
#ifndef LOGFILE
#define LOGFILE "/tmp/syslog"
#endif

#ifndef LOG_PRIMASK
#define LOG_PRIMASK (LOG_EMERG|LOG_ALERT|LOG_CRIT|LOG_ERR|LOG_WARNING|LOG_NOTICE|LOG_INFO|LOG_DEBUG)
#endif
#ifndef LOG_PRI
#define LOG_PRI(p) ((p) & LOG_PRIMASK)
#endif

#include "config.h"
#define FSL_PREFIX "l2."

#define STMT(stuff) do { stuff } while (0)
#define CU(returncode) STMT( rc = returncode; goto CUS; )
#define VCU STMT( goto CUS; )

typedef struct {
    char   *base;
    size_t  used;
    size_t  size;
} buf_t;

/* general return codes */
typedef enum {
    FSL_OK = 0,               /* everything ok */
    FSL_ERR_ARG,              /* invalid argument */
    FSL_ERR_USE,              /* invalid use */
    FSL_ERR_MEM,              /* no more memory available */
    FSL_ERR_SYS               /* operating system error, see errno */
    //FSL_ERR_FMT,              /* formatting error */
    //FSL_ERR_INT,              /* internal error */
    //FSL_ERR_SYN,              /* syntax error */
} fsl_rc_t;

fsl_rc_t readfileorallfiles(buf_t *, const char *);
fsl_rc_t readfile          (buf_t *, const char *);
fsl_rc_t readallfiles      (buf_t *);
fsl_rc_t appendfiletobuffer(buf_t *, const char *);

/* log level to string mapping */
static struct {
    int level;
    char *string;
} level2string[] = {
    { LOG_EMERG,   "emerg"    },
    { LOG_ALERT,   "alert"    },
    { LOG_CRIT,    "crit"     },
    { LOG_ERR,     "err"      },
    { LOG_WARNING, "warning"  },
    { LOG_NOTICE,  "notice"   },
    { LOG_INFO,    "info"     },
    { LOG_DEBUG,   "debug"    },
    { 0,           NULL       }
};

static struct {
    int facility;
    char *string;
} facility2string[] = {
    { LOG_AUTH,     "auth"     },
    { LOG_AUTHPRIV, "authpriv" },
    { LOG_CONSOLE,  "console"  },
    { LOG_CRON,     "cron"     },
    { LOG_DAEMON,   "daemon"   },
    { LOG_FTP,      "ftp"      },
    { LOG_KERN,     "kern"     },
    { LOG_LPR,      "lpr"      },
    { LOG_MAIL,     "mail"     },
    { LOG_NEWS,     "news"     },
    { LOG_SECURITY, "security" },
    { LOG_SYSLOG,   "syslog"   },
    { LOG_USER,     "user"     },
    { LOG_UUCP,     "uucp"     },
    { LOG_LOCAL0,   "local0"   },
    { LOG_LOCAL1,   "local1"   },
    { LOG_LOCAL2,   "local2"   },
    { LOG_LOCAL3,   "local3"   },
    { LOG_LOCAL4,   "local4"   },
    { LOG_LOCAL5,   "local5"   },
    { LOG_LOCAL6,   "local6"   },
    { LOG_LOCAL7,   "local7"   },
    { 0,            NULL       }
};

/* internal context structure */
static struct {
    FILE *log;
    char *logfile;
    const char *ident;
    int logopt;
    int facility;
    int maskpri;
} ctx = { 
    NULL, LOGFILE, "unknown", 0, LOG_USER, 0xff
};

void FIXMEopenlog(const char *ident, int logopt, int facility)
{
    /* remember parameters */
    ctx.ident    = ident;
    ctx.logopt   = logopt;
    ctx.facility = facility;

    /* close perhaps still open logfile */
    if (ctx.log != NULL) {
        fclose(ctx.log);
        ctx.log = NULL;
    }

    /* (re-)open new logfile */
    if (!(ctx.logopt & LOG_NDELAY) && ctx.log == NULL)
        if ((ctx.log = fopen(ctx.logfile, "a")) == NULL)
            return;
    return;
}

void traverse(cfg_t *cfg, cfg_node_t *cfgnode)
{
    int rc;
    cfg_node_t *cfgchld;
    cfg_rc_t cfgrv;
    cfg_node_type_t cfgtyp;
    char *cp;
    int cfgchilds;

    fprintf(stderr, "DEBUG: diving\n");
    while (cfgnode != NULL) {
        if ((cfgrv = cfg_node_get(cfg, cfgnode, CFG_NODE_ATTR_TOKEN, &cp)) != CFG_OK) {
            (void)cfg_error(cfg, cfgrv, &cp); fprintf(stderr, "Error: cfg_node_get(CFG_NODE_ATTR_TOKEN) failed with error %s (%d)\n", cp, cfgrv); CU(1); }
        if ((cfgrv = cfg_node_get(cfg, cfgnode, CFG_NODE_ATTR_TYPE, &cfgtyp)) != CFG_OK) {
            (void)cfg_error(cfg, cfgrv, &cp); fprintf(stderr, "Error: cfg_node_get(CFG_NODE_ATTR_TYPE) failed with error %s (%d)\n", cp, cfgrv); CU(1); }
        if ((cfgrv = cfg_node_get(cfg, cfgnode, CFG_NODE_ATTR_CHILDS, &cfgchilds)) != CFG_OK) {
            (void)cfg_error(cfg, cfgrv, &cp); fprintf(stderr, "Error: cfg_node_get(CFG_NODE_ATTR_CHILDS) failed with error %s (%d)\n", cp, cfgrv); CU(1); }
        fprintf(stderr, "DEBUG: cfgnode=0x%.8lx[%d], *cp=\"%s\", type=%d\n", (unsigned long)cfgnode, cfgchilds, cp, cfgtyp);
        if ((cfgrv = cfg_node_get(cfg, cfgnode, CFG_NODE_ATTR_CHILD1, &cfgchld)) != CFG_OK) {
            (void)cfg_error(cfg, cfgrv, &cp); fprintf(stderr, "Error: cfg_node_get(CFG_NODE_ATTR_CHILD1) failed with error %s (%d)\n", cp, cfgrv); CU(1); }
        if (cfgchld != NULL)
            traverse(cfg, cfgchld);
        if ((cfgrv = cfg_node_get(cfg, cfgnode, CFG_NODE_ATTR_RBROTH, &cfgnode)) != CFG_OK) {
            (void)cfg_error(cfg, cfgrv, &cp); fprintf(stderr, "Error: cfg_node_get(CFG_NODE_ATTR_RBROTH) failed with error %s (%d)\n", cp, cfgrv); CU(1); }
    }
    fprintf(stderr, "DEBUG: climbing\n");
    CU(0);
CUS:
    return;
}

/* Substitutes $[0-9] in inbuf[inlen] with captured strings passed through capary[nary].
 * Returns the number of characters (to be) written to output.  Output can be suppressed
 * by passing a NULL outpbuf. The terminating NUL is not counted but will be written!
 */
int substcapture(const char *inbuf, int inlen, const char **capary, int nary, char *outbuf)
{
    int  i; /* input cursor, current position */
    int  n; /* outbuf cursor, next possible write position */
    int  m; /* index to capary */
    char c; /* scratch variable */

    i = 0;
    n = 0;
    while (i < inlen - 1 /* last char cannot start a two-character sequence, skipping it allows safe look ahead */) {
        c = inbuf[i];
        if (c == '$') {
            c = inbuf[i+1];
            if (c == '$') {
                if (outbuf != NULL)
                    outbuf[n] = '$';
                i+=2;
                n++;
            }
            else if ((c >= '0') && (c <= '9')) {
                m = c - '0';
                if (outbuf != NULL) {
                    outbuf[n] = '\0';
                    strcat(&outbuf[n], ((m < nary) && (capary[m] != NULL)) ? capary[m] : "");
                }
                i+=2;
                n+= ((m < nary) && (capary[m] != NULL)) ? strlen(capary[m]) : 0;
            }
            else {
                if (outbuf != NULL)
                    outbuf[n] = '$';
                i++;
                n++;
                if (outbuf != NULL)
                    outbuf[n] = c;
                i++;
                n++;
            }
        }
        else {
            if (outbuf != NULL)
                outbuf[n] = c;
            i++;
            n++;
        }
    }
    if (outbuf != NULL)
        outbuf[n] = '\0';
    return n;
}

void openlog(const char *ident, int logopt, int facility)
{
    int rc;
    buf_t buf;
    fsl_rc_t rv;
    cfg_t           *cfg;
    cfg_rc_t         cfgrv;
    cfg_node_t      *cfgseq;
    cfg_node_t      *cfgdir;
    cfg_node_t      *cfgarg;
    cfg_node_type_t  cfgtype;
    int              cfgnumc;
    char *argident;
    char *argmatch;
    char *argl2spec;
    char *cp; /* scratch variable */
    int   i;  /* scratch variable */
    int   n;  /* scratch variable */
    char *cpIdent;
    char *cpFacility;
    char *cpISF;
#define OVECSIZE 30 //FIXME find a good place for this
    int ovec[OVECSIZE];
    const char   **acpMatch;
    l2_env_t     *l2_env;
    l2_channel_t *l2_nch; /* noop channel */
    l2_channel_t *ch; /* scratch variable */
    l2_result_t   l2rv;

    cfg = NULL;
    buf.base = NULL;
    buf.used = 0;
    buf.size = 0;
    cpIdent = NULL;
    cpISF = NULL;
    l2_env = NULL;
    l2_nch = NULL;

fprintf(stderr, "DEBUG: BEGIN ident=\"%s\", logopt=0x%.8lx, facility=0x%.8lx\n", ident, (unsigned long)logopt, (unsigned long)facility);

    /* create L2 environment */
    if ((l2rv = l2_env_create(&l2_env)) != L2_OK) {
        cp = l2_env_strerror(l2_env, l2rv); fprintf(stderr, "Error: failed to create L2 environment (%d)\n", l2rv); CU(1); }
    if ((l2rv = l2_env_levels(l2_env, L2_LEVEL_ALL, L2_LEVEL_NONE)) != L2_OK) {
        cp = l2_env_strerror(l2_env, l2rv); fprintf(stderr, "Error: logging failed to set global logging level defaults %s(%d)\n", cp, l2rv); CU(1); }
    if ((l2rv = l2_env_formatter(l2_env, 'D', l2_util_fmt_dump, NULL)) != L2_OK) {
        cp = l2_env_strerror(l2_env, l2rv); fprintf(stderr, "Error: logging failed to register dump formatter %s(%d)\n", cp, l2rv); CU(1); }
    if ((l2rv = l2_env_formatter(l2_env, 'S', l2_util_fmt_string, NULL)) != L2_OK) {
        cp = l2_env_strerror(l2_env, l2rv); fprintf(stderr, "Error: logging failed to register string formatter %s(%d)\n", cp, l2rv); CU(1); }
    if ((l2rv = l2_env_formatter(l2_env, 'm', l2_util_fmt_errno, NULL)) != L2_OK) {
        cp = l2_env_strerror(l2_env, l2rv); fprintf(stderr, "Error: logging failed to register errno formatter %s(%d)\n", cp, l2rv); CU(1); }
    if ((l2rv = l2_env_settimer(l2_env, 20)) != L2_OK) { //FIXME do we need this?
        cp = l2_env_strerror(l2_env, l2rv); fprintf(stderr, "Error: failed to configure timer %s(%d)\n", cp, l2rv); CU(1); }

    /* create L2 noop channel */
    if ((l2rv = l2_channel_create(&l2_nch, l2_env, "noop")) != L2_OK) {
        cp = l2_env_strerror(l2_env, l2rv); fprintf(stderr, "Error: logging failed to create noop channel; %s(%d)\n", cp, l2rv); CU(1); }

    /* create IdentSlashFacility */
    if ((cpIdent = strdup((ident != NULL) ? ident : "unknown")) == NULL) {
        fprintf(stderr, "Error: strdup() failed\n"); CU(1); }
    cpFacility = "unknown";
    for (i = 0; facility2string[i].string != NULL; i++) {
        if (facility == facility2string[i].facility) {
            cpFacility = facility2string[i].string;
            break;
        }
    }
    if ((cpISF = (char *)malloc(strlen(cpIdent) + 1 + strlen(cpFacility) + 1)) == NULL) {
        fprintf(stderr, "Error: malloc() failed\n"); CU(1); }
    cpISF[0] = '\0';
    strcat(cpISF, cpIdent);
    strcat(cpISF, "/");
    strcat(cpISF, cpFacility);
fprintf(stderr, "DEBUG: ISF=\"%s\"\n", cpISF);

    if ((cfgrv = cfg_create(&cfg)) != CFG_OK) {
        (void)cfg_error(cfg, cfgrv, &cp); fprintf(stderr, "Error: cfg_create() failed with error %s (%d)\n", cp, cfgrv); CU(1); }

    if ((rv = readfileorallfiles(&buf, "config.log")) != FSL_OK) {
        fprintf(stderr, "DEBUG: error %d, system %s(%d)\n", rv, strerror(errno), errno); CU(1); }

    if ((cfgrv = cfg_import(cfg, NULL, CFG_FMT_CFG, buf.base, buf.size)) != CFG_OK) {
        (void)cfg_error(cfg, cfgrv, &cp); fprintf(stderr, "Error: cfg_import() failed with error %s (%d)\n", cp, cfgrv); CU(1); }

    /*  find root and check if it is a sequence and has one or more directives below it */
    if ((cfgrv = cfg_node_root(cfg, &cfgseq)) != CFG_OK) {
        (void)cfg_error(cfg, cfgrv, &cp); fprintf(stderr, "Error: cfg_node_root() failed with error %s (%d)\n", cp, cfgrv); CU(1); }
    //FIXME traverse(cfg, cfgseq); /* DEBUG */
    if ((cfgrv = cfg_node_get(cfg, cfgseq, CFG_NODE_ATTR_TYPE, &cfgtype)) != CFG_OK) {
        (void)cfg_error(cfg, cfgrv, &cp); fprintf(stderr, "Error: cfg_node_get(CFG_NODE_ATTR_TYPE) failed with error %s (%d)\n", cp, cfgrv); CU(1); }
    if (cfgtype != CFG_NODE_TYPE_SEQ) {
        fprintf(stderr, "Error: expected sequence\n"); CU(1); }
    if ((cfgrv = cfg_node_get(cfg, cfgseq, CFG_NODE_ATTR_CHILDS, &cfgnumc)) != CFG_OK) {
        (void)cfg_error(cfg, cfgrv, &cp); fprintf(stderr, "Error: cfg_node_get(CFG_NODE_ATTR_CHILDS) failed with error %s (%d)\n", cp, cfgrv); CU(1); }
    if (cfgnumc < 1) {
        fprintf(stderr, "Error: sequence is missing directives, expected 1, got %d\n", cfgnumc); CU(1); }

    /*  get first directive below sequence */
    if ((cfgrv = cfg_node_get(cfg, cfgseq, CFG_NODE_ATTR_CHILD1, &cfgdir)) != CFG_OK) {
        (void)cfg_error(cfg, cfgrv, &cp); fprintf(stderr, "Error: cfg_node_get(CFG_NODE_ATTR_CHILD1) failed with error %s (%d)\n", cp, cfgrv); CU(1); }
    while (cfgdir != NULL) {
        //FIXME fprintf(stderr, "DEBUG: cfgdir=0x%.8lx\n", (unsigned long)cfgdir);

        /*  check if operating on a directive which has exactly three arguments */
        if ((cfgrv = cfg_node_get(cfg, cfgdir, CFG_NODE_ATTR_TYPE, &cfgtype)) != CFG_OK) {
            (void)cfg_error(cfg, cfgrv, &cp); fprintf(stderr, "Error: cfg_node_get(CFG_NODE_ATTR_TYPE) failed with error %s (%d)\n", cp, cfgrv); CU(1); }
        if (cfgtype != CFG_NODE_TYPE_DIR) {
            fprintf(stderr, "Error: expected directive\n"); CU(1); }
        if ((cfgrv = cfg_node_get(cfg, cfgdir, CFG_NODE_ATTR_CHILDS, &cfgnumc)) != CFG_OK) {
            (void)cfg_error(cfg, cfgrv, &cp); fprintf(stderr, "Error: cfg_node_get(CFG_NODE_ATTR_CHILDS) failed with error %s (%d)\n", cp, cfgrv); CU(1); }
        if (cfgnumc != 3) {
            fprintf(stderr, "Error: directive missing arguments, expected 3, got %d\n", cfgnumc); CU(1); }

        /*  process first child of directive, check if it is an argument and has a valid token attached */
        if ((cfgrv = cfg_node_get(cfg, cfgdir, CFG_NODE_ATTR_CHILD1, &cfgarg)) != CFG_OK) {
            (void)cfg_error(cfg, cfgrv, &cp); fprintf(stderr, "Error: cfg_node_get(CFG_NODE_ATTR_CHILD1) failed with error %s (%d)\n", cp, cfgrv); CU(1); }
        if (cfgarg == NULL) {
            fprintf(stderr, "Error: argument \"argident\" is NULL\n"); CU(1); }
        if ((cfgrv = cfg_node_get(cfg, cfgarg, CFG_NODE_ATTR_TYPE, &cfgtype)) != CFG_OK) {
            (void)cfg_error(cfg, cfgrv, &cp); fprintf(stderr, "Error: cfg_node_get(CFG_NODE_ATTR_TYPE) failed with error %s (%d)\n", cp, cfgrv); CU(1); }
        if (cfgtype != CFG_NODE_TYPE_ARG) {
            fprintf(stderr, "Error: expected argument\n"); CU(1); }
        if ((cfgrv = cfg_node_get(cfg, cfgarg, CFG_NODE_ATTR_TOKEN, &argident)) != CFG_OK) {
            (void)cfg_error(cfg, cfgrv, &cp); fprintf(stderr, "Error: cfg_node_get(CFG_NODE_ATTR_TOKEN) failed with error %s (%d)\n", cp, cfgrv); CU(1); }
        if (argident == NULL) {
            fprintf(stderr, "Error: argument \"argident\" has NULL data\n"); CU(1); }

        /*  process right brother of argument, check if it is an argument and has a valid token attached */
        if ((cfgrv = cfg_node_get(cfg, cfgarg, CFG_NODE_ATTR_RBROTH, &cfgarg)) != CFG_OK) {
            (void)cfg_error(cfg, cfgrv, &cp); fprintf(stderr, "Error: cfg_node_get(CFG_NODE_ATTR_RBROTH) failed with error %s (%d)\n", cp, cfgrv); CU(1); }
        if (cfgarg == NULL) {
            fprintf(stderr, "Error: argument \"argmatch\" is NULL\n"); CU(1); }
        if ((cfgrv = cfg_node_get(cfg, cfgarg, CFG_NODE_ATTR_TYPE, &cfgtype)) != CFG_OK) {
            (void)cfg_error(cfg, cfgrv, &cp); fprintf(stderr, "Error: cfg_node_get(CFG_NODE_ATTR_TYPE) failed with error %s (%d)\n", cp, cfgrv); CU(1); }
        if (cfgtype != CFG_NODE_TYPE_ARG) {
            fprintf(stderr, "Error: expected argument\n"); CU(1); }
        if ((cfgrv = cfg_node_get(cfg, cfgarg, CFG_NODE_ATTR_TOKEN, &argmatch)) != CFG_OK) {
            (void)cfg_error(cfg, cfgrv, &cp); fprintf(stderr, "Error: cfg_node_get(CFG_NODE_ATTR_TOKEN) failed with error %s (%d)\n", cp, cfgrv); CU(1); }
        if (argmatch == NULL) {
            fprintf(stderr, "Error: argument \"argmatch\" has NULL data\n"); CU(1); }

        /*  process right brother of argument, check if it is an argument and has a valid token attached */
        if ((cfgrv = cfg_node_get(cfg, cfgarg, CFG_NODE_ATTR_RBROTH, &cfgarg)) != CFG_OK) {
            (void)cfg_error(cfg, cfgrv, &cp); fprintf(stderr, "Error: cfg_node_get(CFG_NODE_ATTR_RBROTH) failed with error %s (%d)\n", cp, cfgrv); CU(1); }
        if (cfgarg == NULL) {
            fprintf(stderr, "Error: argument \"argl2spec\" is NULL\n"); CU(1); }
        if ((cfgrv = cfg_node_get(cfg, cfgarg, CFG_NODE_ATTR_TYPE, &cfgtype)) != CFG_OK) {
            (void)cfg_error(cfg, cfgrv, &cp); fprintf(stderr, "Error: cfg_node_get(CFG_NODE_ATTR_TYPE) failed with error %s (%d)\n", cp, cfgrv); CU(1); }
        if (cfgtype != CFG_NODE_TYPE_ARG) {
            fprintf(stderr, "Error: expected argument\n"); CU(1); }
        if ((cfgrv = cfg_node_get(cfg, cfgarg, CFG_NODE_ATTR_TOKEN, &argl2spec)) != CFG_OK) {
            (void)cfg_error(cfg, cfgrv, &cp); fprintf(stderr, "Error: cfg_node_get(CFG_NODE_ATTR_TOKEN) failed with error %s (%d)\n", cp, cfgrv); CU(1); }
        if (argl2spec == NULL) {
            fprintf(stderr, "Error: argument \"argl2spec\" has NULL data\n"); CU(1); }

        /*  process the directive using the three arguments found */
        fprintf(stderr, "DEBUG: argident=%s, argmatch=%s, argl2spec=%s\n", argident, argmatch, argl2spec);
        {
            pcre       *pcreRegex;
            pcre_extra *pcreExtra;
            const char *cpError;
            int         iError;
            int         nMatch;

            /* compile regular expression into finite state machine and optimize */
            if ((pcreRegex = pcre_compile(argmatch, PCRE_CASELESS, &cpError, &iError, NULL)) == NULL) {
                fprintf(stderr, "Error: pcre_compile() failed with error %s (%d)\n", cpError, iError); CU(1); }
            pcreExtra = pcre_study(pcreRegex, 0, &cpError);
            if (cpError != NULL) {
                fprintf(stderr, "Error: pcre_study() failed with error %s\n", cpError); CU(1); }

            nMatch = pcre_exec(pcreRegex, pcreExtra, cpISF, strlen(cpISF), 0, 0, ovec, OVECSIZE);
            fprintf(stderr, "DEBUG: nMatch=%d when \"%s\" is used against \"%s\"\n", nMatch, argmatch, cpISF);
            if (nMatch >= 1) {
                pcre_get_substring_list(cpISF, ovec, nMatch, &acpMatch);
                if (acpMatch != NULL)
                    for (i = 0; i < nMatch; i++)
                        fprintf(stderr, "DEBUG: regex reference[%d]=\'%s\'\n", i, acpMatch[i] == NULL ? "(UNDEFINED)" : acpMatch[i]);
                n = substcapture(argl2spec, strlen(argl2spec), acpMatch, nMatch, NULL);
                if ((cp = (char *)malloc(n + 1)) == NULL) {
                    fprintf(stderr, "Error: malloc() failed\n"); CU(1); }
                if (substcapture(argl2spec, strlen(argl2spec), acpMatch, nMatch, cp) != n) {
                    fprintf(stderr, "Error: substcapture() failed\n"); CU(1); }
                argl2spec = cp;
        fprintf(stderr, "DEBUG: argident=%s, argmatch=%s, argl2spec=%s\n", argident, argmatch, argl2spec);

                /* create L2 channel throuh spec and link into root channel */
                if ((l2rv = l2_spec(&ch, l2_env, argl2spec)) != L2_OK) {
                    cp = l2_env_strerror(l2_env, l2rv); fprintf(stderr, "Error: logging failed to create stream from spec %s(%d)\n", cp, l2rv); CU(1); }
                if ((l2rv = l2_channel_link(l2_nch, L2_LINK_CHILD, ch, NULL)) != L2_OK) {
                    cp = l2_env_strerror(l2_env, l2rv); fprintf(stderr, "Error: logging failed to link child channel %s(%d)\n", cp, l2rv); CU(1); }

                free(argl2spec);
            }
        }

        /*  get right brother of current directive */
        if ((cfgrv = cfg_node_get(cfg, cfgdir, CFG_NODE_ATTR_RBROTH, &cfgdir)) != CFG_OK) {
            (void)cfg_error(cfg, cfgrv, &cp); fprintf(stderr, "Error: cfg_node_get(CFG_NODE_ATTR_RBROTH) failed with error %s (%d)\n", cp, cfgrv); CU(1); }
    }
    if ((l2rv = l2_channel_open(l2_nch)) != L2_OK) {
        cp = l2_env_strerror(l2_env, l2rv); fprintf(stderr, "Error: logging failed to open channel stream %s(%d)\n", cp, l2rv); CU(1); }
    l2_channel_log(l2_nch, L2_LEVEL_DEBUG, "Hello, World!"); //FIXME DEBUG

fprintf(stderr, "DEBUG: *END*, buf.base=0x%.8lx, buf.used=%d, buf.size=%d\n", (unsigned long)buf.base, (int)buf.used, (int)buf.size);
    CU(0);
    FIXMEopenlog(ident, logopt, facility);
CUS:
    if (cpISF != NULL)
        free(cpISF);
    if (cpIdent != NULL)
        free(cpIdent);
    if (l2_nch != NULL)
        l2_channel_destroy(l2_nch);
    if (l2_env != NULL)
        l2_env_destroy(l2_env);
#if 0
    if (cfg != NULL)
        if ((cfgrv = cfg_destroy(cfg)) != CFG_OK) {
            (void)cfg_error(cfg, cfgrv, &cp); fprintf(stderr, "Error: cfg_destroy() failed with error %s (%d)\n", cp, cfgrv); CU(1); }
#endif
    return;
}

void closelog(void)
{
    /* close open logfile*/
    if (ctx.log != NULL) {
        fclose(ctx.log);
        ctx.log = NULL;
    }
    return;
}

int setlogmask(int maskpri)
{
    int omask;

    /* remember the logging mask */
    omask = ctx.maskpri;
    if (maskpri != 0)
        ctx.maskpri = maskpri;
    return omask;
}

void syslog(int priority, const char *message, ...)
{
    va_list args;

    /* wrap around vsyslog(3) */
    va_start(args, message);
    vsyslog(priority, message, args);
    va_end(args);
    return;
}

#ifdef HAVE_VSYSLOG_USVALIST
void vsyslog(int priority, const char *fmt, __va_list args)
#else
void vsyslog(int priority, const char *fmt, va_list args)
#endif
{
    time_t now;
    int saved_errno;
    char buf[2048];
    char *cpBuf;
    int nBuf;
    char caMsg[2048];
    char *cpMsg;
    char *cpFmt;
    int i;
    char *cpTime;
    char *cpLevel;

    /* Check for invalid bits */
    if (priority & ~(LOG_PRIMASK|LOG_FACMASK))
        priority &= (LOG_PRIMASK|LOG_FACMASK);

    /* stop processing if mask disabled this call */
    if (!(LOG_MASK(LOG_PRI(priority)) & ctx.maskpri))
        return;

    /* make sure we have a reasonable default for facility */
    if ((priority & LOG_FACMASK) == 0)
        priority |= ctx.facility;

    /* remember errno for optional %m processing below */
    saved_errno = errno;

    /* open logfile now (if it was delayed) */
    if (ctx.log == NULL)
        if ((ctx.log = fopen(ctx.logfile, "a")) == NULL)
            return;

    /* determine current time */
    time(&now);
    cpTime = ctime(&now) + 4;

    /* determine logging level name */
    cpLevel = "unknown";
    for (i = 0; level2string[i].string != NULL; i++) {
        if (LOG_PRI(priority) == level2string[i].level) {
            cpLevel = level2string[i].string;
            break;
        }
    }
    
    /* start output generation */
    cpBuf = buf;
    sprintf(cpBuf, "%.15s <%s> %s", cpTime, cpLevel, ctx.ident);
    nBuf = strlen(cpBuf);

    /* optionally add process id */
    if (ctx.logopt & LOG_PID) {
        sprintf(cpBuf+nBuf, "[%d]", getpid());
        nBuf += strlen(cpBuf+nBuf);
    }

    /* end prefix */
    strcpy(cpBuf+nBuf, ": ");
    nBuf += 2;

    /* optionally expand %m in format string */
    cpFmt = (char *)fmt;
    if (strstr(cpFmt, "%m")) {
        cpMsg = caMsg;
        while (cpFmt[0] != '\0') {
            if (cpFmt[0] == '%' && cpFmt[1] == 'm') {
                strcpy(cpMsg, strerror(saved_errno));
                cpMsg += strlen(cpMsg);
                cpFmt += 2;
            } else {
                *cpMsg++ = *cpFmt++;
                *cpMsg = '\0';
            }
        }
        cpFmt = caMsg;
    }

    /* append message to output buffer */
    vsprintf(cpBuf+nBuf, cpFmt, args);
    nBuf += strlen(cpBuf+nBuf);

    /* append newline if still not present */
    if (cpBuf[nBuf-1] != '\n') {
        cpBuf[nBuf++] = '\n';
        cpBuf[nBuf] = '\0';
    }

    /* now finally write output buffer to logfile */
    fwrite(cpBuf, nBuf, 1, ctx.log);
    fflush(ctx.log);

#ifdef LOG_PERROR
    /* optionally also write output buffer to stderr */
    if (ctx.logopt & LOG_PERROR)
        fwrite(cpBuf, nBuf, 1, stderr);
#endif

    return;
}

fsl_rc_t readfileorallfiles(buf_t *buffer, const char *ident)
{
    fsl_rc_t rv;

    if ((rv = readfile(buffer, ident)) == FSL_OK)
        return FSL_OK;

    if (rv != FSL_ERR_SYS || errno != ENOENT)
        return rv;

    if ((rv = readallfiles(buffer)) != FSL_OK)
        return rv;

    return FSL_OK;
}

fsl_rc_t readfile(buf_t *buffer, const char *ident)
{
    fsl_rc_t rc;
    char *filename = NULL;

    if (ident == NULL || buffer == NULL)
        CU(FSL_ERR_ARG);

    if ((filename = (char *)malloc(strlen(FSL_CFGDIR) + 1 + strlen(FSL_PREFIX) + strlen(ident) + 1)) == NULL)
        CU(FSL_ERR_MEM);
    filename[0] = '\0';
    strcat(filename, FSL_CFGDIR);
    strcat(filename, "/");
    strcat(filename, FSL_PREFIX);
    strcat(filename, ident);

    CU(appendfiletobuffer(buffer, filename));
CUS:
    if (filename != NULL)
        free(filename);
    return rc;
}

fsl_rc_t readallfiles(buf_t *buffer)
{
    fsl_rc_t rc;
    DIR *dp;
    struct dirent *de;
    char *filename = NULL;

    if (buffer == NULL)
        CU(FSL_ERR_ARG);

    if ((dp = opendir(FSL_CFGDIR)) == NULL)
        CU(FSL_ERR_SYS);

    while ((de = readdir(dp)) != NULL) {
        if (   (de->d_type == DT_REG)
            && (de->d_namlen >= strlen(FSL_PREFIX))
            && (strncmp(de->d_name, FSL_PREFIX, strlen(FSL_PREFIX)) == 0)
              ) {
            if ((filename = (char *)malloc(strlen(FSL_CFGDIR) + 1 + de->d_namlen + 1)) == NULL)
                CU(FSL_ERR_MEM);
            filename[0] = '\0';
            strcat(filename, FSL_CFGDIR);
            strcat(filename, "/");
            strncat(filename, de->d_name, de->d_namlen);
            (void /*FIXME*/)appendfiletobuffer(buffer, filename);
            free(filename);
            filename = NULL;
        }
    }
    (void)closedir(dp);
    CU(FSL_OK);
CUS:
    if (filename != NULL)
        free(filename);
    return rc;
}

fsl_rc_t appendfiletobuffer(buf_t *buffer, const char *filename)
{
    fsl_rc_t rc;
    int fd = -1;
    int filesize;
    int fileread;
    int bufferneed;

    if (filename == NULL || buffer == NULL)
        CU(FSL_ERR_ARG);
fprintf(stderr, "DEBUG: appendfiletobuffer(..., %s)\n", filename);

    if ((fd = open(filename, O_RDONLY)) == -1)
        CU(FSL_ERR_SYS);

    if ((filesize = (int)lseek(fd, 0, SEEK_END)) == -1)
        CU(FSL_ERR_SYS);

    bufferneed = buffer->used + filesize;
    if (bufferneed > buffer->size) {
        if (buffer->base == NULL) {
            if ((buffer->base = (char *)malloc(bufferneed)) == NULL)
                CU(FSL_ERR_MEM);
            buffer->size = bufferneed;
            buffer->used = 0;
        }
        else {
            if ((buffer->base = (char *)realloc(buffer->base, bufferneed)) == NULL)
                CU(FSL_ERR_MEM);
            buffer->size = bufferneed;
        }
    }

    if (lseek(fd, 0, SEEK_SET) == -1)
        CU(FSL_ERR_SYS);

    if ((fileread = (int)read(fd, buffer->base + buffer->used, (size_t)filesize)) == -1)
        CU(FSL_ERR_SYS);

    if (fileread != filesize)
        CU(FSL_ERR_USE);

    buffer->used += filesize;
    CU(FSL_OK);
CUS:
    if (fd != -1)
        close(fd);
    return rc;
}

CVSTrac 2.0.1