/* ** OSSP fsl - Faking Syslog Library ** Copyright (c) 2002 Ralf S. Engelschall ** Copyright (c) 2002 The OSSP Project ** Copyright (c) 2002 Cable & Wireless Deutschland ** ** 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 #include #include #include #include #include #include #include #include #include #include #include /* standard include we re-implement */ #include /* 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; }