From b337e0e9e5c88b4b7af7c509993a6d842b5b90c8 Mon Sep 17 00:00:00 2001 From: Ken McDonell Date: Mon, 11 Sep 2023 17:06:24 +1000 Subject: [PATCH] pmie: add -o|--format option to control output format with archives MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since most rule actions are "fake" when processing performance data from archives, the -o option provides some rudimentary control over the format of the output messages when rule actions are executed. The meta-fields supported in the -o option are (from pmie(1)) ... %a The name of the action, e.g. print, syslog, etc. %d The date and time in ctime(3) format when the action would have been executed. %f The name of the configuration file containing the action being exe‐ cuted, else if the rules were read from standard input. %l The (approximate) line number in the configuration file for the ac‐ tion being executed. %m The message component of the action. %u The date and time when the action would have been executed in ex‐ tended ctime(3) format with microsecond precision for the time. %% A literal percent character. The default output format is equivalent to a format of %a %d: %m. Resolves https://github.com/performancecopilot/pcp/issues/1799. --- man/man1/pmie.1 | 59 +++++++++++- qa/1912 | 96 +++++++++++++++++++ qa/1912.out | 31 ++++++ qa/1913 | 37 ++++++++ qa/1913.out | 95 +++++++++++++++++++ qa/group | 2 + src/pmie/src/GNUmakefile | 4 +- src/pmie/src/act.sk | 198 ++++++++++++++++++++++++++++++++++++++- src/pmie/src/dstruct.h | 1 + src/pmie/src/fun.h | 1 + src/pmie/src/lexicon.c | 9 +- src/pmie/src/pmie.c | 15 ++- src/pmie/src/syntax.c | 23 +++++ 13 files changed, 558 insertions(+), 13 deletions(-) create mode 100755 qa/1912 create mode 100644 qa/1912.out create mode 100755 qa/1913 create mode 100644 qa/1913.out diff --git a/man/man1/pmie.1 b/man/man1/pmie.1 index 0815f6d621..46f4515d9c 100644 --- a/man/man1/pmie.1 +++ b/man/man1/pmie.1 @@ -29,6 +29,7 @@ [\f3\-m\f1 \f2note\f1] [\f3\-j\f1 \f2stompfile\f1] [\f3\-n\f1 \f2pmnsfile\f1] +[\f3\-o\f1 \f2format\f1] [\f3\-O\f1 \f2offset\f1] [\f3\-S\f1 \f2starttime\f1] [\f3\-t\f1 \f2interval\f1] @@ -242,6 +243,18 @@ section below. An alternative Performance Metrics Name Space (PMNS) is loaded from the file .IR pmnsfile . .TP +\fB\-o\fR \fIformat\fR, \fB\-\-format\fR=\fIformat\fR +When precessing performance data from an archive, the +.B \-o +option may be used to specify an alternate output +.I format +when a rule action is executed. +See the +.B "DIFFERENCES IN HOST AND ARCHIVE MODES" +section for a description of how the output +.I format +may be constructed. +.TP \fB\-O\fR \fIorigin\fR, \fB\-\-origin\fR=\fIorigin\fR Specify the \fIorigin\fP of the time window. See @@ -1326,6 +1339,49 @@ or a shell command that might not even work on the host where is being run, are all examples of ``badness'' to be avoided. Rather the output is text in a regular format suitable for post-processing with a range of filters and performance analysis tools. +.PP +The output format can be changed using the +.B \-o +option which consists of literal characters with the following +embedded ``meta-field'' tokens: +.TP 4n +\f(CB%a\fR +The name of the action, e.g. +.BR print , +.BR syslog , +etc. +.TP 4n +\f(CB%d\fR +The date and time in +.BR ctime (3) +format when the action would have been executed. +.TP 4n +\f(CB%f\fR +The name of the configuration file containing the action being +executed, else +.B +if the rules were read from standard input. +.TP 4n +\f(CB%l\fR +The (approximate) line number in the configuration file for the action being +executed. +.TP 4n +\f(CB%m\fR +The message component of the action. +.TP 4n +\f(CB%u\fR +The date and time when the action would have been executed in +extended +.BR ctime (3) +format with microsecond precision for the time. +.TP 4n +\f(CB%%\fR +A literal percent character. +.PP +The default output format is equivalent to a +.I format +of +.BR "%a %d: %m" . .SH SIGNALS If .B pmie @@ -1466,13 +1522,14 @@ a cross-platform dialog box. .BR pmcd (1), .BR pmconfirm (1), .BR pmdumplog (1), -.BR pmieconf (1), .BR pmie_check (1), +.BR pmieconf (1), .BR pmie_daily (1), .BR pminfo (1), .BR pmlogger (1), .BR pmval (1), .BR systemd (1), +.BR ctime (3), .BR PMAPI (3), .BR pcp.conf (5), .BR pcp.env (5) diff --git a/qa/1912 b/qa/1912 new file mode 100755 index 0000000000..7d5750da1a --- /dev/null +++ b/qa/1912 @@ -0,0 +1,96 @@ +#!/bin/sh +# PCP QA Test No. 1912 +# pmie -o testing +# +# non-valgrind variant, see qa/1913 for the valgrind variant +# +# Copyright (c) 2023 Ken McDonell. All Rights Reserved. +# + +if [ $# -eq 0 ] +then + seq=`basename $0` + echo "QA output created by $seq" +else + # use $seq from caller, unless not set + [ -n "$seq" ] || seq=`basename $0` + echo "QA output created by `basename $0` $*" +fi + +# get standard environment, filters and checks +. ./common.product +. ./common.filter +. ./common.check + +$sudo rm -rf $tmp $tmp.* $seq.full + +do_valgrind=false +if [ "$1" = "--valgrind" ] +then + _check_valgrind + do_valgrind=true +elif which valgrind >/dev/null 2>&1 +then + [ $PCPQA_VALGRIND = both ] || \ + _notrun "valgrind variant qa/1913 will be run" +fi + +_cleanup() +{ + cd $here + $sudo rm -rf $tmp $tmp.* +} + +status=0 # success is the default! +trap "_cleanup; exit \$status" 0 1 2 3 15 + +_filter() +{ + sed \ + -e "s@$tmp@TMP@g" \ + -e '/evaluator exiting/d' \ +# end +} + +# real QA test starts here + +cat <$tmp.config +// suff at the beginning +sample.wrap.long > 0 +// stuff in the middle + -> print "yippee %v"; +// stuff at the end +End-of-File + +# base tests ... +# +for fmt in "%a %d: %m" "%% %m %" "%%a=%a= %%d=%d= %%f=%f= %%l=%l= %%m=%m= %%u=%u=" \ + "%m" "prologue %M epilogue" "%" +do + echo + echo "-- $fmt --" + + if $do_valgrind + then + _run_valgrind pmie -t 2 -z -c $tmp.config -a archives/wrap -o "$fmt" + else + pmie -t 2 -z -c $tmp.config -a archives/wrap -o "$fmt" 2>&1 + fi \ + | _filter +done + +# config on stdin, ... +# +echo +echo "-- misc tests --" +( cat $tmp.config $tmp.config ) \ +| if $do_valgrind +then + _run_valgrind pmie -t 2 -z -a archives/wrap -o "[%f:%l] %m" +else + pmie -t 2 -z -a archives/wrap -o "[%f:%l] %m" 2>&1 +fi \ +| _filter + +# success, all done +exit diff --git a/qa/1912.out b/qa/1912.out new file mode 100644 index 0000000000..15f6fb8527 --- /dev/null +++ b/qa/1912.out @@ -0,0 +1,31 @@ +QA output created by 1912 + +-- %a %d: %m -- +pmie: timezone set to local timezone from archives/wrap +print Mon Dec 1 16:08:22 1997: yippee 1144454022 + +-- %% %m % -- +pmie: timezone set to local timezone from archives/wrap +% yippee 1144454022 % + +-- %%a=%a= %%d=%d= %%f=%f= %%l=%l= %%m=%m= %%u=%u= -- +pmie: timezone set to local timezone from archives/wrap +%a=print= %d=Mon Dec 1 16:08:22 1997= %f=TMP.config= %l=4= %m=yippee 1144454022= %u=Mon Dec 1 16:08:22.423728 1997= + +-- %m -- +pmie: timezone set to local timezone from archives/wrap +yippee 1144454022 + +-- prologue %M epilogue -- +pmie: timezone set to local timezone from archives/wrap +Warning: unrecognized field specifier '%M' in format +prologue %M epilogue + +-- % -- +pmie: timezone set to local timezone from archives/wrap +% + +-- misc tests -- +pmie: timezone set to local timezone from archives/wrap +[:4] yippee 1144454022 +[:9] yippee 1144454022 diff --git a/qa/1913 b/qa/1913 new file mode 100755 index 0000000000..a9b339567a --- /dev/null +++ b/qa/1913 @@ -0,0 +1,37 @@ +#!/bin/sh +# PCP QA Test No. 1913 +# pmie -o testing +# +# valgrind variant, see qa/1912 for the non-valgrind variant +# +# check-group-include: pmie +# +# Copyright (c) 2023 Ken McDonell. All Rights Reserved. +# + +seq=`basename $0` +echo "QA output created by $seq" + +# get standard environment, filters and checks +. ./common.product +. ./common.filter +. ./common.check + +_check_valgrind + +_cleanup() +{ + cd $here + $sudo rm -rf $tmp $tmp.* +} + +status=0 # success is the default! +$sudo rm -rf $tmp $tmp.* $seq.full +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# real QA test starts here +export seq +./1912 --valgrind + +# success, all done +exit diff --git a/qa/1913.out b/qa/1913.out new file mode 100644 index 0000000000..6ada4dc6d3 --- /dev/null +++ b/qa/1913.out @@ -0,0 +1,95 @@ +QA output created by 1913 +QA output created by 1912 --valgrind + +-- %a %d: %m -- +=== std out === +pmie: timezone set to local timezone from archives/wrap +print Mon Dec 1 16:08:22 1997: yippee 1144454022 +=== std err === +=== filtered valgrind report === +Memcheck, a memory error detector +Command: pmie -t 2 -z -c TMP.config -a archives/wrap -o %a\ %d:\ %m +LEAK SUMMARY: +definitely lost: 0 bytes in 0 blocks +indirectly lost: 0 bytes in 0 blocks +ERROR SUMMARY: 0 errors from 0 contexts ... + +-- %% %m % -- +=== std out === +pmie: timezone set to local timezone from archives/wrap +% yippee 1144454022 % +=== std err === +=== filtered valgrind report === +Memcheck, a memory error detector +Command: pmie -t 2 -z -c TMP.config -a archives/wrap -o %%\ %m\ % +LEAK SUMMARY: +definitely lost: 0 bytes in 0 blocks +indirectly lost: 0 bytes in 0 blocks +ERROR SUMMARY: 0 errors from 0 contexts ... + +-- %%a=%a= %%d=%d= %%f=%f= %%l=%l= %%m=%m= %%u=%u= -- +=== std out === +pmie: timezone set to local timezone from archives/wrap +%a=print= %d=Mon Dec 1 16:08:22 1997= %f=TMP.config= %l=4= %m=yippee 1144454022= %u=Mon Dec 1 16:08:22.423728 1997= +=== std err === +=== filtered valgrind report === +Memcheck, a memory error detector +Command: pmie -t 2 -z -c TMP.config -a archives/wrap -o %%a=%a=\ %%d=%d=\ %%f=%f=\ %%l=%l=\ %%m=%m=\ %%u=%u= +LEAK SUMMARY: +definitely lost: 0 bytes in 0 blocks +indirectly lost: 0 bytes in 0 blocks +ERROR SUMMARY: 0 errors from 0 contexts ... + +-- %m -- +=== std out === +pmie: timezone set to local timezone from archives/wrap +yippee 1144454022 +=== std err === +=== filtered valgrind report === +Memcheck, a memory error detector +Command: pmie -t 2 -z -c TMP.config -a archives/wrap -o %m +LEAK SUMMARY: +definitely lost: 0 bytes in 0 blocks +indirectly lost: 0 bytes in 0 blocks +ERROR SUMMARY: 0 errors from 0 contexts ... + +-- prologue %M epilogue -- +=== std out === +pmie: timezone set to local timezone from archives/wrap +prologue %M epilogue +=== std err === +Warning: unrecognized field specifier '%M' in format +=== filtered valgrind report === +Memcheck, a memory error detector +Command: pmie -t 2 -z -c TMP.config -a archives/wrap -o prologue\ %M\ epilogue +LEAK SUMMARY: +definitely lost: 0 bytes in 0 blocks +indirectly lost: 0 bytes in 0 blocks +ERROR SUMMARY: 0 errors from 0 contexts ... + +-- % -- +=== std out === +pmie: timezone set to local timezone from archives/wrap +% +=== std err === +=== filtered valgrind report === +Memcheck, a memory error detector +Command: pmie -t 2 -z -c TMP.config -a archives/wrap -o % +LEAK SUMMARY: +definitely lost: 0 bytes in 0 blocks +indirectly lost: 0 bytes in 0 blocks +ERROR SUMMARY: 0 errors from 0 contexts ... + +-- misc tests -- +=== std out === +pmie: timezone set to local timezone from archives/wrap +[:4] yippee 1144454022 +[:9] yippee 1144454022 +=== std err === +=== filtered valgrind report === +Memcheck, a memory error detector +Command: pmie -t 2 -z -a archives/wrap -o [%f:%l]\ %m +LEAK SUMMARY: +definitely lost: 0 bytes in 0 blocks +indirectly lost: 0 bytes in 0 blocks +ERROR SUMMARY: 0 errors from 0 contexts ... diff --git a/qa/group b/qa/group index 9946cc425a..dbd906ac28 100644 --- a/qa/group +++ b/qa/group @@ -2079,6 +2079,8 @@ x11 1901 pmlogger local 1902 help local 1906 pmseries libpcp_web local +1912 pmie local +1913 pmie local valgrind 1914 atop local 1927 pmda.sockets local 1931 pmda.bpf local diff --git a/src/pmie/src/GNUmakefile b/src/pmie/src/GNUmakefile index 1782f70cc6..4a50c85f1f 100644 --- a/src/pmie/src/GNUmakefile +++ b/src/pmie/src/GNUmakefile @@ -22,7 +22,7 @@ CFILES = pmie.c symbol.c dstruct.c lexicon.c syntax.c pragmatics.c eval.c \ show.c match_inst.c systemlog.c stomp.c andor.c HFILES = fun.h dstruct.h eval.h lexicon.h pragmatics.h stats.h \ - show.h symbol.h syntax.h systemlog.h stomp.h andor.h + show.h symbol.h syntax.h systemlog.h stomp.h andor.h act.h SKELETAL = hdr.sk fetch.sk misc.sk aggregate.sk unary.sk binary.sk \ merge.sk act.sk binary_str.sk @@ -52,6 +52,8 @@ install: default lexicon.o syntax.o: grammar.h +syntax.o: act.h + fun.o: fun.h fun.c: $(SKELETAL) meta diff --git a/src/pmie/src/act.sk b/src/pmie/src/act.sk index 35773ab319..b7c0627f4c 100644 --- a/src/pmie/src/act.sk +++ b/src/pmie/src/act.sk @@ -375,13 +375,146 @@ actArg(Expr *x) /* * fake actions for archive mode */ + +/* first -f|--format support ... */ +typedef struct { + int type; + void *data; +} msg_fmt; + +#define FMT_UNKNOWN -1 +#define FMT_STR 0 +#define FMT_ACTION 1 +#define FMT_DATETIME 2 +#define FMT_FILE 3 +#define FMT_LINENO 4 +#define FMT_MSG 5 +#define FMT_USECDATE 6 +#define FMT_END 99 + +static msg_fmt *parse_fmt(char *fmt) +{ + msg_fmt *res = NULL; + msg_fmt *rp; + int npart = 0; + char *p; + char *q; + + p = q = fmt; + + while (*q) { + if (*q == '%') { + int type = FMT_UNKNOWN; + if (q > p) { + /* string before % */ + npart++; + if ((rp = (msg_fmt *)realloc(res, npart*sizeof(msg_fmt))) == NULL) { + fprintf(stderr, "parse_fmt: realloc for part %d failed\n", npart); + free(res); + return NULL; + } + res = rp; + rp = &res[npart-1]; + rp->type = FMT_STR; + rp->data = (void *)strndup(p, q-p); + } + /* look at next char ... */ + switch (q[1]) { + case 'a': + type = FMT_ACTION; + break; + + case 'd': + type = FMT_DATETIME; + break; + + case 'f': + type = FMT_FILE; + break; + + case 'l': + type = FMT_LINENO; + break; + + case 'm': + type = FMT_MSG; + break; + + case 'u': + type = FMT_USECDATE; + break; + + case '%': + p = ++q; + break; + case '\0': + p = q; + break; + default: + fprintf(stderr, "Warning: unrecognized field specifier '%%%c' in format\n", q[1]); + p = q; + break; + } + if (type != FMT_UNKNOWN) { + npart++; + if ((rp = (msg_fmt *)realloc(res, npart*sizeof(msg_fmt))) == NULL) { + fprintf(stderr, "parse_fmt: realloc for part %d (field %%%c) failed\n", npart, q[1]); + free(res); + return NULL; + } + res = rp; + rp = &res[npart-1]; + rp->type = type; + rp->data = NULL; + ++q; + p = ++q; + } + else + ++q; + } + else + ++q; + } + + if (*p != '\0') { + /* trailing string */ + npart++; + if ((rp = (msg_fmt *)realloc(res, npart*sizeof(msg_fmt))) == NULL) { + fprintf(stderr, "parse_fmt: realloc for part %d failed\n", npart); + free(res); + return NULL; + } + res = rp; + rp = &res[npart-1]; + rp->type = FMT_STR; + rp->data = (void *)strndup(p, q-p); + } + + /* end-of-format */ + npart++; + if ((rp = (msg_fmt *)realloc(res, npart*sizeof(msg_fmt))) == NULL) { + fprintf(stderr, "parse_fmt: realloc for part END failed\n"); + free(res); + return NULL; + } + res = rp; + rp = &res[npart-1]; + rp->type = FMT_END; + rp->data = NULL; + + return res; +} + void actFake(Expr *x) { - Expr *arg1 = x->arg1; - Expr *arg2 = x->arg2; - time_t clock = (time_t)now; - char bfr[26]; + Expr *arg1 = x->arg1; + Expr *arg2 = x->arg2; + aux_action *aap = (aux_action *)x->auxdata; + time_t clock = (time_t)now; + char bfr[26]; + static msg_fmt *fmt = NULL; + extern char *format; if ((arg2 == NULL) || (x->smpls[0].stamp == 0) || @@ -392,7 +525,62 @@ actFake(Expr *x) x->smpls[0].stamp = now; pmCtime(&clock, bfr); bfr[24] = '\0'; - printf("%s %s: %s\n", opStrings(x->op), bfr, (char *)arg1->ring); + + if (format != NULL && fmt == NULL) { + /* + * one-trip for -o|--format option + */ + fmt = parse_fmt(format); + if (fmt == NULL) { + /* fallback to default */ + format = NULL; + } + } + + if (format) { + int i; + /* -o|--format in play */ + for (i = 0; ; i++) { + switch (fmt[i].type) { + case FMT_STR: + printf("%s", (char *)fmt[i].data); + break; + case FMT_ACTION: + printf("%s", opStrings(x->op)); + break; + case FMT_DATETIME: + printf("%s", bfr); + break; + case FMT_FILE: + printf("%s", aap->fname); + break; + case FMT_LINENO: + printf("%d", aap->lineno); + break; + case FMT_MSG: + printf("%s", (char *)arg1->ring); + break; + case FMT_USECDATE: + /* + * bfr[18] is where the time (in seconds) from + * pmCtime() ends + */ + printf("%19.19s.", bfr); + printf("%06ld", (long)((now - clock) * 1000000)); + printf("%s", &bfr[19]); + break; + case FMT_END: + putchar('\n'); + break; + } + if (fmt[i].type == FMT_END) + break; + } + } + else { + /* default */ + printf("%s %s: %s\n", opStrings(x->op), bfr, (char *)arg1->ring); + } } } diff --git a/src/pmie/src/dstruct.h b/src/pmie/src/dstruct.h index 16026d1846..7f5962cf10 100644 --- a/src/pmie/src/dstruct.h +++ b/src/pmie/src/dstruct.h @@ -107,6 +107,7 @@ typedef struct expr { struct expr *arg1; /* NULL || (Expr *) */ struct expr *arg2; /* NULL || (Expr *) */ struct expr *parent; /* parent of this Expr */ + void *auxdata; /* auxiliary data, if any */ /* evaluator */ Eval *eval; /* evaluator function */ diff --git a/src/pmie/src/fun.h b/src/pmie/src/fun.h index ee82aea3c6..1b1c0ecc26 100644 --- a/src/pmie/src/fun.h +++ b/src/pmie/src/fun.h @@ -23,6 +23,7 @@ #include "dstruct.h" #include "andor.h" +#include "act.h" #define ROTATE(x) if ((x)->nsmpls > 1) rotate(x); #define EVALARG(x) if ((x)->op < NOP) ((x)->eval)(x); diff --git a/src/pmie/src/lexicon.c b/src/pmie/src/lexicon.c index 1d243d6dd8..b6b5e7cbdc 100644 --- a/src/pmie/src/lexicon.c +++ b/src/pmie/src/lexicon.c @@ -3,7 +3,7 @@ * * There is enough lookahead to enable use of '/' as both an arithmetic * and units operator. Nested macro expansion is supported using a stack - * of input contexts (see definition of LexIn in file syntax.y). + * of input contexts (see definition of LexIn in file lexicon.h). *********************************************************************** * * Copyright (c) 1995-2002 Silicon Graphics, Inc. All Rights Reserved. @@ -134,7 +134,6 @@ static LexEntry2 unitab[] = { static char *token; /* current token buffer */ - /*********************************************************************** * local functions ***********************************************************************/ @@ -160,7 +159,9 @@ unwind(void) static int nextc(void) { - int c = '\0'; + int c = '\0'; + extern char *configfile; + extern int rule_lineno; if (lin) { if (lin->lookin != lin->lookout) { @@ -423,6 +424,7 @@ yylex(void) char *p, *q; int i; char nbuf[LEX_MAX+1]; /* for getting macro name */ + extern int rule_lineno; /* token from previous invocation */ if (ahead) { @@ -784,6 +786,7 @@ yylex(void) if ((d = nextc()) == '>') { if (pmDebugOptions.appl0) fprintf(stderr, "yylex() -> OPERATOR \"->\"\n"); + rule_lineno = lin->lno; return ARROW; } prevc(d); diff --git a/src/pmie/src/pmie.c b/src/pmie/src/pmie.c index ced8d09258..d87cbca4b1 100644 --- a/src/pmie/src/pmie.c +++ b/src/pmie/src/pmie.c @@ -51,6 +51,10 @@ char *clientid; int runfromcontrol; +char *format; /* for -o|--format */ +char *configfile; +int rule_lineno; + static FILE *logfp; static char logfile[MAXPATHLEN]; static char perffile[MAXPATHLEN]; /* /var/tmp/ file name */ @@ -109,6 +113,7 @@ static pmLongOptions longopts[] = { PMAPI_OPTIONS_HEADER("Reporting options"), { "buffer", 0, 'b', 0, "one line buffered output stream, stdout on stderr" }, { "timestamp", 0, 'e', 0, "force timestamps to be reported with -V, -v or -W" }, + { "format", 1, 'o', "FORMAT", "output format for rule actions in archive mode" }, { "quiet", 0, 'q', 0, "quiet mode, default diagnostics suppressed" }, { "", 0, 'v', 0, "verbose mode, expression values printed" }, { "verbose", 0, 'V', 0, "verbose mode, annotated expression values printed" }, @@ -120,7 +125,7 @@ static pmLongOptions longopts[] = { static pmOptions opts = { .flags = PM_OPTFLAG_STDOUT_TZ, - .short_options = "a:A:bc:CdD:efFHh:j:l:m:n:O:PqS:t:T:U:vVWXxzZ:?", + .short_options = "a:A:bc:CdD:efFHh:j:l:m:n:o:O:PqS:t:T:U:vVWXxzZ:?", .long_options = longopts, .short_usage = "[options] [filename ...]", .override = override, @@ -485,7 +490,6 @@ sigbadproc(int sig) static void getargs(int argc, char *argv[]) { - char *configfile = NULL; char *commandlog = NULL; char *subopts; char *subopt; @@ -611,6 +615,10 @@ getargs(int argc, char *argv[]) runfromcontrol = (strcmp(opts.optarg, "pmie_check") == 0); break; + case 'o': /* output format for actions in archive mode */ + format = opts.optarg; + break; + case 'U': /* run as named user */ username = opts.optarg; isdaemon = 1; @@ -811,7 +819,8 @@ getargs(int argc, char *argv[]) } else { /* list of 1/more filenames */ while (opts.optind < argc) { - load(argv[opts.optind]); + configfile = argv[opts.optind]; + load(configfile); opts.optind++; } } diff --git a/src/pmie/src/syntax.c b/src/pmie/src/syntax.c index 3752877830..b5f4a05776 100644 --- a/src/pmie/src/syntax.c +++ b/src/pmie/src/syntax.c @@ -34,6 +34,7 @@ #include "pragmatics.h" #include "eval.h" #include "show.h" +#include "act.h" @@ -323,6 +324,9 @@ Expr * actExpr(int op, Expr *arg1, Expr *arg2) { Expr *x; + extern char *format; + extern char *configfile; + extern int rule_lineno; /* error guard */ if (arg1 == NULL) return NULL; @@ -332,6 +336,25 @@ actExpr(int op, Expr *arg1, Expr *arg2) newRingBfr(x); findEval(x); + /* + * add auxdata in fake actions for archive mode with -o|--format + * in case format contains %f or %l + */ + if (archives && format && + (op == ACT_SHELL || op == ACT_ALARM || op == ACT_SYSLOG || + op == ACT_PRINT || op == ACT_STOMP)) { + aux_action *aap; + aap = (aux_action *)alloc(sizeof(aux_action)); + if (configfile == NULL) + aap->fname = ""; + else { + /* need strdup here because configfile may change */ + aap->fname = strdup(configfile); + } + aap->lineno = rule_lineno; + x->auxdata = (void *)aap; + } + return x; }