diff --git a/tools/bgpgrep/bgpgrep.1.in b/tools/bgpgrep/bgpgrep.1.in index 12f4052..30f703d 100755 --- a/tools/bgpgrep/bgpgrep.1.in +++ b/tools/bgpgrep/bgpgrep.1.in @@ -17,7 +17,9 @@ utility reads each possibly compressed Multithreaded Routing Toolkit (MRT) dump file specified by .IR FILES -and formats its contents to standard output. +and formats its contents to standard output (or any custom output file +as specified by +.IR OPTIONS ). .IR @UTILITY@ may optionally evaluate a predicate defined by .IR EXPRESSION @@ -37,8 +39,8 @@ regardless of any filtering rule. prints diagnostics to standard error, it detects and tolerates data corruption as much as possible. Corruption within a BGP message causes only the affected message to be -dropped. Unrecoverable corruption within the entire MRT dump file causes -the whole file to be dropped, +dropped. Though unrecoverable errors affecting the entire MRT dump file may +require it to be dropped as a whole, .IR @UTILITY@ will then move to the next file in .IR FILES , @@ -46,7 +48,7 @@ if any. .P Such events are always reported with reasonable diagnostic errors. Parsed data up to the corruption point may still be printed to -standard output. +regular output. .SH OPTIONS .IR @UTILITY@ @@ -74,6 +76,15 @@ may ease visualization by surrounding some output with color escape sequences, on terminals that support this feature. This option forces colored text output off. +.IP "\fB\-o \fI\fP" 10 +Write output to +.BR file . +Instead of using standard output, +.IR @UTILITY@ +shall format MRT contents to the specified file. If option occurs +multiple times, last specified file is used. This option forces colored +text output off. + .IP "\fB\-h or \-\-help\fP" 10 Prints a short help message, summarizing .IR @UTILITY@ @@ -582,8 +593,11 @@ supported compression formats. If the file extension is not recognized, or there is no extension, then it is assumed to be uncompressed. .SH STDOUT -The standard output is used to print a human readable text representation of -BGP message data, nothing else shall be written to the standard output. +Unless redirected explicitly via +.IR OPTIONS , +the standard output is used to print a human readable text +representation of BGP message data, nothing else shall be written +to the standard output. .IR @UTILITY@ may detect and treat as error whenever the standard output is a regular file, and is the same file as any of the @@ -597,7 +611,9 @@ section. .SH STDERR The standard error is used only for diagnostic messages and error reporting. -Any BGP message output is exclusive to standard output. +Any BGP message output is exclusive to standard output or any file explicitly +specified by +.IR OPTIONS . .SH EXAMPLES This section contains some useful examples, starting from trivial ones, diff --git a/tools/bgpgrep/bgpgrep.c b/tools/bgpgrep/bgpgrep.c index e6b0486..a681e8f 100755 --- a/tools/bgpgrep/bgpgrep.c +++ b/tools/bgpgrep/bgpgrep.c @@ -38,6 +38,7 @@ BgpgrepState S; typedef enum { NO_COLOR_FLAG, DUMP_BYTECODE_FLAG, + OUTPUT_FLAG, NUM_FLAGS } BgpgrepOpt; @@ -49,6 +50,9 @@ static Optflag options[] = { [DUMP_BYTECODE_FLAG] = { '-', "dump-bytecode", NULL, "Dump BGP VM bytecode to stderr (debug)", ARG_NONE }, + [OUTPUT_FLAG] = { + 'o', NULL, "file", "Write output to file", ARG_REQ + }, [NUM_FLAGS] = { '\0' } }; @@ -63,34 +67,14 @@ static void Bgpgrep_SetupCommandLine(char *argv0) com_shortDescr = "Filter and print BGP data within MRT dumps"; com_longDescr = "Reads MRT dumps in various formats, applying filtering rules\n" - "to each BGP message therein, then outputs every passing message to stdout.\n" + "to each BGP message therein, then outputs every passing message\n" + "to stdout (or any custom output file defined by OPTIONS).\n" "If - is found inside FILES, then input is read from stdin.\n" "If no FILES arguments are provided, then input\n" "is implicitly expected from stdin.\n" "Any diagnostic message is logged to stderr."; } -static void Bgpgrep_ApplyProgramOptions(void) -{ - S.noColor = options[NO_COLOR_FLAG].flagged; - S.dumpBytecode = options[DUMP_BYTECODE_FLAG].flagged; -} - -static int CountFileArguments(int argc, char **argv) -{ - int i; - - for (i = 0; i < argc; i++) { - const char *arg = argv[i]; - if (arg[0] == '-' && arg[1] != '\0') - break; - if (strcmp(arg, "(") == 0 || strcmp(arg, "!") == 0) - break; - } - - return i; -} - void Bgpgrep_Fatal(const char *fmt, ...) { va_list va; @@ -126,6 +110,46 @@ void Bgpgrep_Warning(const char *fmt, ...) Sys_Print(STDERR, "\n"); } +static void Bgpgrep_ApplyProgramOptions(void) +{ + S.noColor = options[NO_COLOR_FLAG].flagged; + S.dumpBytecode = options[DUMP_BYTECODE_FLAG].flagged; + if (options[OUTPUT_FLAG].flagged) { + const char *filename = options[OUTPUT_FLAG].optarg; + + Fildes fd = Sys_Fopen(filename, FM_WRITE, /*hints=*/0); + if (fd == FILDES_BAD) + Bgpgrep_Fatal("Can't open output file \"%s\"", filename); + + S.outf = STM_FILDES(fd); + S.outfOps = Stm_FildesOps; + + S.noColor = TRUE; + } else { + S.outf = STM_CONHN(STDOUT); + S.outfOps = Stm_ConOps; + } + if (!S.noColor && Sys_IsVt100Console(STDOUT)) + S.outFmt = Bgp_IsolarioFmtWc; // console supports colors + else + S.outFmt = Bgp_IsolarioFmt; +} + +static int CountFileArguments(int argc, char **argv) +{ + int i; + + for (i = 0; i < argc; i++) { + const char *arg = argv[i]; + if (arg[0] == '-' && arg[1] != '\0') + break; + if (strcmp(arg, "(") == 0 || strcmp(arg, "!") == 0) + break; + } + + return i; +} + void Bgpgrep_DropMessage(const char *fmt, ...) { va_list va; @@ -278,11 +302,6 @@ NOINLINE static void Bgpgrep_HandleBgpError(BgpRet err, Srcloc *loc, void *obj) static void Bgpgrep_Init(void) { - if (!S.noColor && Sys_IsVt100Console(STDOUT)) - S.outFmt = Bgp_IsolarioFmtWc; // console supports colors - else - S.outFmt = Bgp_IsolarioFmt; - Mrtrecord *rec = &S.rec; Bgpmsg *msg = &S.msg; @@ -389,6 +408,9 @@ static int Bgpgrep_CleanupAndExit(void) t = tn; } + + if (S.outfOps->Close) S.outfOps->Close(S.outf); + return (S.nerrors > 0) ? EXIT_FAILURE : EXIT_SUCCESS; } diff --git a/tools/bgpgrep/bgpgrep_dump.c b/tools/bgpgrep/bgpgrep_dump.c index 26f197d..5207927 100755 --- a/tools/bgpgrep/bgpgrep_dump.c +++ b/tools/bgpgrep/bgpgrep_dump.c @@ -68,7 +68,7 @@ static void FixBgpAttributeTableForRib(Bgpattrtab tab, Boolean isRibv2) static void OutputBgp4mp(const Mrthdr *hdr, Bgpattrtab tab) { S.lenientBgpErrors = TRUE; - S.outFmt->DumpBgp4mp(hdr, STM_CONHN(STDOUT), Stm_ConOps, tab); + S.outFmt->DumpBgp4mp(hdr, S.outf, S.outfOps, tab); S.lenientBgpErrors = FALSE; } @@ -104,7 +104,7 @@ void BgpgrepD_Bgp4mp(void) static void OutputZebra(const Mrthdr *hdr, Bgpattrtab tab) { S.lenientBgpErrors = TRUE; - S.outFmt->DumpZebra(hdr, STM_CONHN(STDOUT), Stm_ConOps, tab); + S.outFmt->DumpZebra(hdr, S.outf, S.outfOps, tab); S.lenientBgpErrors = FALSE; } @@ -149,7 +149,7 @@ static void OutputRibv2(const Mrthdr *hdr, Bgpattrtab tab) { S.lenientBgpErrors = TRUE; - S.outFmt->DumpRibv2(hdr, peerent, ent, STM_CONHN(STDOUT), Stm_ConOps, tab); + S.outFmt->DumpRibv2(hdr, peerent, ent, S.outf, S.outfOps, tab); S.lenientBgpErrors = FALSE; } @@ -219,7 +219,7 @@ void BgpgrepD_TableDumpv2(void) static void OutputRib(const Mrthdr *hdr, const Mrtribent *ent, Bgpattrtab tab) { S.lenientBgpErrors = TRUE; - S.outFmt->DumpRib(hdr, ent, STM_CONHN(STDOUT), Stm_ConOps, tab); + S.outFmt->DumpRib(hdr, ent, S.outf, S.outfOps, tab); S.lenientBgpErrors = FALSE; } diff --git a/tools/bgpgrep/bgpgrep_local.h b/tools/bgpgrep/bgpgrep_local.h index 9b9ed4d..2490a68 100755 --- a/tools/bgpgrep/bgpgrep_local.h +++ b/tools/bgpgrep/bgpgrep_local.h @@ -104,12 +104,15 @@ typedef jmp_buf frame_buf; typedef struct BgpgrepState BgpgrepState; struct BgpgrepState { - const char *filename; // current file being processed + // Output const BgpDumpfmt *outFmt; + void *outf; + const StmOps *outfOps; // MRT input file stream - void *inf; // NOTE: may be NULL even in a file is open - const StmOps *infOps; // if NULL no file is open + const char *filename; // current file being processed + void *inf; // NOTE: may be NULL even in a file is open + const StmOps *infOps; // if NULL no file is open // Miscellaneous global flags and data Boolean8 noColor;