--- 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;
}
|