Index: ossp-pkg/fsl/fsl.c RCS File: /v/ossp/cvs/ossp-pkg/fsl/fsl.c,v rcsdiff -q -kk '-r1.10' '-r1.11' -u '/v/ossp/cvs/ossp-pkg/fsl/fsl.c,v' 2>/dev/null --- fsl.c 2002/07/17 15:26:36 1.10 +++ fsl.c 2002/07/18 11:26:59 1.11 @@ -92,26 +92,10 @@ 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[] = { +} syslogfacility2string[] = { { LOG_AUTH, "auth" }, { LOG_AUTHPRIV, "authpriv" }, { LOG_CONSOLE, "console" }, @@ -137,13 +121,38 @@ { 0, NULL } }; +static struct { + int level; + char *string; + l2_level_t deflevelmap; +} sysloglevel2string[] = { + { LOG_EMERG, "emerg", L2_LEVEL_PANIC }, + { LOG_ALERT, "alert", L2_LEVEL_PANIC }, + { LOG_CRIT, "crit", L2_LEVEL_CRITICAL }, + { LOG_ERR, "err", L2_LEVEL_ERROR }, + { LOG_WARNING, "warning", L2_LEVEL_WARNING }, + { LOG_NOTICE, "notice", L2_LEVEL_NOTICE }, + { LOG_INFO, "info", L2_LEVEL_INFO }, + { LOG_DEBUG, "debug", L2_LEVEL_DEBUG }, + { 0, NULL, 0 } +}; + +typedef struct { + int syslog; + l2_level_t l2; +} levelmap_t; + /* internal context structure */ static struct { l2_env_t *l2_env; l2_channel_t *l2_nch; + levelmap_t *levelmap; + int maskpri; } ctx = { NULL, NULL, + NULL, + LOG_PRIMASK }; void traverse(cfg_t *cfg, cfg_node_t *cfgnode) @@ -244,6 +253,9 @@ cfg_node_t *cfgarg; cfg_node_type_t cfgtype; int cfgnumc; + int cfgnume; + char *cfgargtoka[3]; //FIXME hardcoded maximum number of arguments + char *cfgargtok; char *argident; char *argmatch; char *argl2spec; @@ -279,11 +291,25 @@ l2_env_destroy(ctx.l2_env); ctx.l2_env = NULL; } + if (ctx.levelmap != NULL) { + free(ctx.levelmap); + ctx.levelmap = NULL; + } /*FIXME this should be available to the user to help him finding out what the application passes along * currently we completely ignore logopt LOG_CONS, LOG_NDELAY, LOG_PERROR, LOG_PID */ + /* create default sysloglevel to l2_level mapping */ + for (i = 0; sysloglevel2string[i].string != NULL; i++); + if ((ctx.levelmap = (levelmap_t *)malloc(i * sizeof(levelmap_t))) == NULL) { + fprintf(stderr, "Error: malloc() failed\n"); CU(1); } + for (i = 0; sysloglevel2string[i].string != NULL; i++) { + ctx.levelmap[i].syslog = sysloglevel2string[i].level; + ctx.levelmap[i].l2 = sysloglevel2string[i].deflevelmap; + fprintf(stderr, "DEBUG: ctx.levelmap[%d].syslog = 0x%.8lx, ctx.levelmap[%d].l2 = 0x%.8lx\n", i, (unsigned long)ctx.levelmap[i].syslog, i, (unsigned long)ctx.levelmap[i].l2); + } + /* create L2 environment */ if ((l2rv = l2_env_create(&ctx.l2_env)) != L2_OK) { cp = l2_env_strerror(ctx.l2_env, l2rv); fprintf(stderr, "Error: failed to create L2 environment (%d)\n", l2rv); CU(1); } @@ -306,9 +332,9 @@ 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; + for (i = 0; syslogfacility2string[i].string != NULL; i++) { + if (facility == syslogfacility2string[i].facility) { + cpFacility = syslogfacility2string[i].string; break; } } @@ -318,14 +344,12 @@ 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) { + if ((rv = readfileorallfiles(&buf, ident)) != FSL_OK) { fprintf(stderr, "DEBUG: error %d, system %s(%d)\n", rv, strerror(errno), errno); CU(1); } + 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 ((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); } @@ -348,98 +372,124 @@ 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 */ + /* check if operating on a directive */ 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); } + fprintf(stderr, "Error: first argument 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) { + fprintf(stderr, "Error: expected first argument, got %d\n", cfgtype); CU(1); } + if ((cfgrv = cfg_node_get(cfg, cfgarg, CFG_NODE_ATTR_TOKEN, &cfgargtok)) != 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); } + if (cfgargtok == NULL) { + fprintf(stderr, "Error: first argument has NULL data\n"); CU(1); } + cfgargtoka[0] = cfgargtok; + + cfgnume = 0; + if (strcmp(cfgargtoka[0], "ident") == 0) + cfgnume = 3; + if (strcmp(cfgargtoka[0], "default") == 0) + cfgnume = 3; + if (strcmp(cfgargtoka[0], "map") == 0) + cfgnume = 3; + if (cfgnume == 0) { + fprintf(stderr, "Error: syntax error, invalid argument \"%s\"\n", cfgargtoka[0]); CU(1); } + if (cfgnume != cfgnumc) { + fprintf(stderr, "Error: directive missing arguments, expected %d, got %d\n", cfgnume, cfgnumc); CU(1); } + + for (i = 1; i < cfgnume; i++) { + + /* 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 %d is NULL\n", i); 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 %d\n", i); CU(1); } + if ((cfgrv = cfg_node_get(cfg, cfgarg, CFG_NODE_ATTR_TOKEN, &cfgargtok)) != 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 (cfgargtok == NULL) { + fprintf(stderr, "Error: argument %d has NULL data\n", i); CU(1); } + cfgargtoka[i] = cfgargtok; + } - /* 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); } + if ((strcmp(cfgargtoka[0], "ident") == 0) || (strcmp(cfgargtoka[0], "default") == 0)) { //FIXME currently default and ident are identical - /* 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); } + argident = cfgargtoka[0]; + argmatch = cfgargtoka[1]; + argl2spec = cfgargtoka[2]; + + /* 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, ctx.l2_env, argl2spec)) != L2_OK) { + cp = l2_env_strerror(ctx.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(ctx.l2_nch, L2_LINK_CHILD, ch, NULL)) != L2_OK) { + cp = l2_env_strerror(ctx.l2_env, l2rv); fprintf(stderr, "Error: logging failed to link child channel %s(%d)\n", cp, l2rv); 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, ctx.l2_env, argl2spec)) != L2_OK) { - cp = l2_env_strerror(ctx.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(ctx.l2_nch, L2_LINK_CHILD, ch, NULL)) != L2_OK) { - cp = l2_env_strerror(ctx.l2_env, l2rv); fprintf(stderr, "Error: logging failed to link child channel %s(%d)\n", cp, l2rv); CU(1); } + free(argl2spec); + } + } + } + else if (strcmp(cfgargtoka[0], "map") == 0) { + + unsigned int levelmask; - free(argl2spec); + for (i = 0; sysloglevel2string[i].string != NULL; i++) { + if (strcmp(sysloglevel2string[i].string, cfgargtoka[1]) == 0) { + if ((l2rv = l2_util_s2l(cfgargtoka[2], strlen(cfgargtoka[2]), ',', &levelmask)) != L2_OK) {; + cp = l2_env_strerror(ctx.l2_env, l2rv); fprintf(stderr, "Error: illegal l2 mask \"%s\" %s(%d)\n", cfgargtoka[2], cp, l2rv); CU(1); } + ctx.levelmap[i].l2 = levelmask; + fprintf(stderr, "DEBUG: ctx.levelmap[%d].syslog = 0x%.8lx, ctx.levelmap[%d].l2 = 0x%.8lx\n", i, (unsigned long)ctx.levelmap[i].syslog, i, (unsigned long)ctx.levelmap[i].l2); + break; + } } + if (sysloglevel2string[i].string == NULL) { + fprintf(stderr, "Error: trying to map unknown syslog level \"%s\"\n", cfgargtoka[1]); CU(1); } } + else { + fprintf(stderr, "Error: internal, argument \"%s\" not implemented\n", cfgargtoka[0]); CU(1); } /* get right brother of current directive */ if ((cfgrv = cfg_node_get(cfg, cfgdir, CFG_NODE_ATTR_RBROTH, &cfgdir)) != CFG_OK) { @@ -448,6 +498,8 @@ if ((l2rv = l2_channel_open(ctx.l2_nch)) != L2_OK) { cp = l2_env_strerror(ctx.l2_env, l2rv); fprintf(stderr, "Error: logging failed to open channel stream %s(%d)\n", cp, l2rv); CU(1); } + ctx.maskpri = LOG_UPTO(LOG_DEBUG); + CU(0); CUS: if (cpISF != NULL) @@ -461,6 +513,9 @@ #endif if (buf.base != NULL) free(buf.base); + if (rc != 0) + exit(rc); + fprintf(stderr, "DEBUG: ------------------------------------------------------------\n"); return; } @@ -479,16 +534,14 @@ int setlogmask(int maskpri) { -#if 0 - int omask; + int oldmask; + //FIXME this is currently a no-op. Should we care about maskpri, set l2 global mask or continue to ignore? /* remember the logging mask */ - omask = ctx.maskpri; + oldmask = ctx.maskpri; if (maskpri != 0) ctx.maskpri = maskpri; - return omask; -#endif - return maskpri; //FIXME + return oldmask; } void syslog(int priority, const char *message, ...) @@ -508,10 +561,22 @@ void vsyslog(int priority, const char *fmt, va_list args) #endif { + unsigned int levelmask; + int i; + if (ctx.l2_nch == NULL) return; - l2_channel_vlog(ctx.l2_nch, L2_LEVEL_DEBUG, fmt, args); + priority &= LOG_PRIMASK; /* strip off facility */ + + levelmask = 0; + for (i = 0; sysloglevel2string[i].string != NULL; i++) { + fprintf(stderr, "DEBUG: ctx.levelmap[%d].syslog = 0x%.8lx, ctx.levelmap[%d].l2 = 0x%.8lx\n", i, (unsigned long)ctx.levelmap[i].syslog, i, (unsigned long)ctx.levelmap[i].l2); + if (ctx.levelmap[i].syslog == priority) + levelmask |= ctx.levelmap[i].l2; + } + fprintf(stderr, "DEBUG: prioriy=0x%.8lx > levelmask=0x%.8lx\n", (unsigned long)priority, (unsigned long)levelmask); + l2_channel_vlog(ctx.l2_nch, levelmask, fmt, args); return; }