/* ** Copyright (C) 2005-2007 by Carnegie Mellon University. ** ** @OPENSOURCE_HEADER_START@ ** ** Use of the SILK system and related source code is subject to the terms ** of the following licenses: ** ** GNU Public License (GPL) Rights pursuant to Version 2, June 1991 ** Government Purpose License Rights (GPLR) pursuant to DFARS 252.225-7013 ** ** NO WARRANTY ** ** ANY INFORMATION, MATERIALS, SERVICES, INTELLECTUAL PROPERTY OR OTHER ** PROPERTY OR RIGHTS GRANTED OR PROVIDED BY CARNEGIE MELLON UNIVERSITY ** PURSUANT TO THIS LICENSE (HEREINAFTER THE "DELIVERABLES") ARE ON AN ** "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY ** KIND, EITHER EXPRESS OR IMPLIED AS TO ANY MATTER INCLUDING, BUT NOT ** LIMITED TO, WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE, ** MERCHANTABILITY, INFORMATIONAL CONTENT, NONINFRINGEMENT, OR ERROR-FREE ** OPERATION. CARNEGIE MELLON UNIVERSITY SHALL NOT BE LIABLE FOR INDIRECT, ** SPECIAL OR CONSEQUENTIAL DAMAGES, SUCH AS LOSS OF PROFITS OR INABILITY ** TO USE SAID INTELLECTUAL PROPERTY, UNDER THIS LICENSE, REGARDLESS OF ** WHETHER SUCH PARTY WAS AWARE OF THE POSSIBILITY OF SUCH DAMAGES. ** LICENSEE AGREES THAT IT WILL NOT MAKE ANY WARRANTY ON BEHALF OF ** CARNEGIE MELLON UNIVERSITY, EXPRESS OR IMPLIED, TO ANY PERSON ** CONCERNING THE APPLICATION OF OR THE RESULTS TO BE OBTAINED WITH THE ** DELIVERABLES UNDER THIS LICENSE. ** ** Licensee hereby agrees to defend, indemnify, and hold harmless Carnegie ** Mellon University, its trustees, officers, employees, and agents from ** all claims or demands made against them (and any related losses, ** expenses, or attorney's fees) arising out of, or relating to Licensee's ** and/or its sub licensees' negligent use or willful misuse of or ** negligent conduct or willful misconduct regarding the Software, ** facilities, or other rights or assistance granted by Carnegie Mellon ** University under this License, including, but not limited to, any ** claims of product liability, personal injury, death, damage to ** property, or violation of any laws or regulations. ** ** Carnegie Mellon University Software Engineering Institute authored ** documents are sponsored by the U.S. Department of Defense under ** Contract F19628-00-C-0003. Carnegie Mellon University retains ** copyrights in all material produced under this contract. The U.S. ** Government retains a non-exclusive, royalty-free license to publish or ** reproduce these documents, or allow others to do so, for U.S. ** Government purposes only pursuant to the copyright license under the ** contract clause at 252.227.7013. ** ** @OPENSOURCE_HEADER_END@ */ /* ** Read rwrec input and write the output to every known rw-format. ** */ #include "silk.h" RCSIDENT("$SiLK: rwallformats.c 6947 2007-04-17 21:12:48Z mthomas $"); #include "sksite.h" #include "utils.h" #include "rwpack.h" #include "iochecks.h" #include "skvector.h" /* LOCAL DEFINES AND TYPEDEFS */ /* where to write --help output */ #define USAGE_FH stdout /* LOCAL FUNCTIONS */ static void appUsageLong(void); /* never returns */ static void appTeardown(void); static void appSetup(int argc, char **argv); /* never returns when error */ static int appOptionsHandler(clientData, int, const char *); static size_t openOutputs(const char *basename, const rwRec *rwrec); static int closeOutputs(void); static int rwallProcessFile(const char *filename); /* LOCAL VARIABLES */ /* basename of outputs. Will append -{B,L}--.dat to this. */ static const char *rwall_basename = NULL; /* iochecks */ static iochecksInfoStruct_t *ioISP = NULL; /* vector of output stream */ static sk_vector_t *rwio_vec = NULL; /* reference to argc and argv for filter output */ static int g_argc; static char **g_argv; /* file types to output */ static unsigned int stream_type[] = { FT_RWAUGMENTED, FT_RWAUGROUTING, FT_RWAUGWEB, FT_RWAUGSNMPOUT, FT_RWFILTER, FT_RWGENERIC, FT_RWNOTROUTED, FT_RWROUTED, FT_RWSPLIT, FT_RWWWW }; /* OPTIONS SETUP */ typedef enum _appOptionsEnum { OPT_BASENAME } appOptionsEnum; static struct option appOptions[] = { {"basename", REQUIRED_ARG, 0, OPT_BASENAME}, {0,0,0,0} /* sentinel entry */ }; static const char *appHelp[] = { "basename for output files", (char *)NULL }; /* FUNCTION DEFINITIONS */ /* * appUsageLong(); * * Print complete usage information to USAGE_FH. Pass this * function to skOptionsSetUsageCallback(); optionsParse() will * call this funciton and then exit the program when the --help * option is given. */ static void appUsageLong(void) { #define USAGE_MSG \ ("[SWITCHES]\n" \ "\tRead SiLK Flow records as input and write them to files\n" \ "\tusing every known SiLK Flow file format and byte order\n") FILE *fh = USAGE_FH; skAppStandardUsage(fh, USAGE_MSG, appOptions, appHelp); sksiteOptionsUsage(fh); } /* * appTeardown() * * Teardown all modules, close all files, and tidy up all * application state. * * This function is idempotent. */ static void appTeardown(void) { static int teardownFlag = 0; if (teardownFlag) { return; } teardownFlag = 1; closeOutputs(); iochecksTeardown(ioISP); skAppUnregister(); } /* * appSetup(argc, argv); * * Perform all the setup for this application include setting up * required modules, parsing options, etc. This function should be * passed the same arguments that were passed into main(). * * Returns to the caller if all setup succeeds. If anything fails, * this function will cause the application to exit with a FAILURE * exit status. */ static void appSetup(int argc, char **argv) { /* verify same number of options and help strings */ assert((sizeof(appHelp)/sizeof(char *)) == (sizeof(appOptions)/sizeof(struct option))); /* register the application */ skAppRegister(argv[0]); skOptionsSetUsageCallback(&appUsageLong); /* register the options */ if (optionsRegister(appOptions, (optHandler)appOptionsHandler, NULL) || sksiteOptionsRegister(SK_SITE_FLAG_CONFIG_FILE)) { skAppPrintErr("unable to register options"); exit(EXIT_FAILURE); } /* Set up the ioChecks module */ ioISP = iochecksSetup(0, 0, argc, argv); /* parse the options */ ioISP->firstFile = optionsParse(argc, argv); assert(ioISP->firstFile <= argc); if (ioISP->firstFile < 0) { /* options parsing should print error */ skAppUsage(); } /* ensure the site config is available */ if (sksiteConfigure(1)) { exit(EXIT_FAILURE); } /* Use STDIN as an input stream if it is not a TTY; make certain * we have some input and we are either reading from STDIN or * using files listed the command line, but not both. */ if (iochecksAcceptFromStdin(ioISP) || iochecksInputs(ioISP, 0)) { skAppUsage(); } if (atexit(appTeardown) < 0) { skAppPrintErr("unable to register appTeardown() with atexit()"); appTeardown(); exit(EXIT_FAILURE); } return; /* OK */ } /* * status = appOptionsHandler(cData, opt_index, opt_arg); * * This function is passed to optionsRegister(); it will be called * by optionsParse() for each user-specified switch that the * application has registered; it should handle the switch as * required---typically by setting global variables---and return 1 * if the switch processing failed or 0 if it succeeded. Returning * a non-zero from from the handler causes optionsParse() to return * a negative value. * * The clientData in 'cData' is typically ignored; 'opt_index' is * the index number that was specified as the last value for each * struct option in appOptions[]; 'opt_arg' is the user's argument * to the switch for options that have a REQUIRED_ARG or an * OPTIONAL_ARG. */ static int appOptionsHandler( clientData UNUSED(cData), int opt_index, const char *opt_arg) { switch ((appOptionsEnum)opt_index) { case OPT_BASENAME: rwall_basename = opt_arg; break; } return 0; /* OK */ } /* * number_inputs = openOutputs(basename, rwrec); * * Open an output stream for every known type-version-endian * combination; create the files based on the value given in * 'basename'. For formats with times in the header, use the time * specified in the 'rwrec'. Returns the number of output streams * created, or 0 for an error. */ static size_t openOutputs(const char *basename, const rwRec *first_rec) { const size_t num_types = (sizeof(stream_type)/sizeof(unsigned int)); const silk_endian_t endians[] = {SILK_ENDIAN_BIG, SILK_ENDIAN_LITTLE}; const char *endian_name[] = {"B", "L"}; unsigned int num_compmethod; unsigned int t, e, c; fileVersion_t v; silk_endian_t byte_order; rwIOStruct_t *rwIOS; int rv = LIBRW_OK; char path[PATH_MAX]; char format_name[SK_MAX_STRLEN_FILE_FORMAT+1]; /* find the number of compression methods */ for (num_compmethod = 0; sksiteCompmethodIsValid(num_compmethod); ++num_compmethod) ; /* no-op */ rwio_vec = skVectorNew(sizeof(rwRec*)); if (rwio_vec == NULL) { skAppPrintErr("Cannot create vector"); return 0; } /* loop over compression methods */ for (c = 0; c < num_compmethod; ++c) { /* loop over formats */ for (t = 0; t < num_types; ++t) { /* loop over versions of that format */ v = 0; while (1) { /* only RWGENERIC supports v=0 */ if (v == 0) { if (stream_type[t] != FT_RWGENERIC) { goto NEXT_VERSION; } } /* loop over byte-orders */ for (e = 0; e < 2; ++e) { byte_order = endians[e]; sksiteFileformatGetName(format_name, sizeof(format_name), stream_type[t]); if ((size_t)snprintf(path, sizeof(path), "%s%s%s-v%d-c%u-%s.dat", ((basename != NULL) ? basename : ""), ((basename != NULL) ? "-" : ""), format_name, v, c, endian_name[e]) >= sizeof(path)) { skAppPrintErr("file name overflow"); return 0; } /* open the file */ rv = LIBRW_OK; if ( !rv) { rv = rwioCreate(&rwIOS, path, SK_RWIO_WRITE); } if ( !rv) { rv = rwioSetFileType(rwIOS, stream_type[t]); } if ( !rv) { rv = rwioSetFileVersion(rwIOS, v); } if ( !rv) { rv = rwioSetFileByteorder(rwIOS, byte_order); } if ( !rv) { rv = rwioSetCompression(rwIOS, c); } if ( !rv) { rv = rwioOpen(rwIOS); } if ( !rv) { rv = rwioSetFileSTime(rwIOS, first_rec->sTime, 1); if (rv == LIBRW_ERR_UNSUPPORT_TYPE) { rv = LIBRW_OK; } } if ( !rv) { rv = rwioAppendToHistoryArgv(rwIOS, g_argc, g_argv); if (rv == LIBRW_ERR_UNSUPPORT_TYPE) { rv = LIBRW_OK; } } if (rv) { if (rv == LIBRW_ERR_UNSUPPORT_COMPRESS) { /* unsupported compression method. ignore * this compression method. */ goto NEXT_COMPMETHOD; } if (rv == LIBRW_ERR_UNSUPPORT_VERSION) { /* Reached max version for this type. Try * next type. */ rwioDestroy(&rwIOS); goto NEXT_TYPE; } /* Unexpected error. Bail */ rwioPrintLastErr(rwIOS, rv, &skAppPrintErr); skAppPrintErr("Error opening '%s'\n", path); rwioDestroy(&rwIOS); return 0; } if (skVectorAppendValue(rwio_vec, &rwIOS)) { skAppPrintErr("Cannot add stream to vector"); return 0; } } /* for e */ NEXT_VERSION: ++v; } /* while 1 */ NEXT_TYPE: ; } /* for t */ NEXT_COMPMETHOD: ; } /* for c */ if (rwio_vec == NULL) { return 0; } return skVectorGetCount(rwio_vec); } /* * status = closeOutputs(); * * Close all the output streams. */ static int closeOutputs(void) { size_t num_streams; size_t i; rwIOStruct_t *rwIOS; int rv; if (rwio_vec == NULL) { return 0; } num_streams = skVectorGetCount(rwio_vec); for (i = 0; i < num_streams; ++i) { (void)skVectorGetValue(&rwIOS, rwio_vec, i); rv = rwCloseFile(rwIOS); if (rv != LIBRW_OK) { rwioPrintLastErr(rwIOS, rv, &skAppPrintErr); } } skVectorDestroy(rwio_vec); rwio_vec = NULL; return 0; } /* * status = rwallProcessFile(input_path); * * Open input_path and write its contents to every known file * format. Will open the output files if required. Returns 0 on * success, or -1 if there is a problem opening, reading, or * writing. */ static int rwallProcessFile(const char *name) { static size_t num_streams = 0; size_t i; rwIOStruct_t *rwio_in; rwIOStruct_t *rwio_out; size_t closed_streams = 0; rwRec rwrec; int rv = 0; rwio_in = rwOpenFile(name, NULL); if (rwio_in == NULL) { skAppPrintErr("Cannot open input stream '%s'\n", name); return -1; } if (!rwRead(rwio_in, &rwrec)) { goto END; } if (num_streams == 0) { num_streams = openOutputs(rwall_basename, &rwrec); if (num_streams == 0) { skAppPrintErr("Could not open any output streams"); rv = -1; goto END; } } do { for (i = 0; i < num_streams; ++i) { (void)skVectorGetValue(&rwio_out, rwio_vec, i); if (rwio_out == NULL) { continue; } rv = rwWrite(rwio_out, &rwrec); if (LIBRW_OK != rv) { rwioPrintLastErr(rwio_out, rv, &skAppPrintErr); if (LIBRW_ERROR_IS_FATAL(rv)) { rwCloseFile(rwio_out); rwio_out = NULL; skVectorSetValue(rwio_vec, i, rwio_out); ++closed_streams; if (closed_streams == num_streams) { rv = -1; goto END; } } } } } while (rwRead(rwio_in, &rwrec)); END: (void)rwCloseFile(rwio_in); return rv; } int main(int argc, char **argv) { int counter; g_argc = argc; g_argv = argv; appSetup(argc, argv); /* never returns on error */ /* Process the files from command line or stdin */ for(counter = ioISP->firstFile; counter < ioISP->fileCount ; ++counter) { if (rwallProcessFile(ioISP->fnArray[counter])) { break; } } /* done */ appTeardown(); return 0; } /* ** Local Variables: ** mode:c ** indent-tabs-mode:nil ** c-basic-offset:4 ** End: */