/* ** Copyright (C) 2001-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@ */ #include "silk.h" RCSIDENT("$SiLK: iochecks.c 6675 2007-03-16 15:32:43Z mthomas $"); #include "utils.h" #include "iochecks.h" #include "rwpack.h" static char *pseudoArgv[2] = {(char *)NULL, (char *)NULL}; #define ALLOW_STDERR 0 /* * malloc an iochecksInfo struct, initialize it, and return its ptr */ iochecksInfoStruct_t *iochecksSetup( uint8_t maxPass, uint8_t maxFail, int argc, char **argv) { iochecksInfoStruct_t *ioISP; /* check input */ if (maxPass > MAX_PASS_DESTINATIONS) { skAppPrintErr("Too many pass destinations; only %d allowed", MAX_PASS_DESTINATIONS); return NULL; } if (maxFail > MAX_FAIL_DESTINATIONS) { skAppPrintErr("Too many fail destinations; only %d allowed", MAX_FAIL_DESTINATIONS); return NULL; } /* create it */ ioISP = calloc(1, sizeof(iochecksInfoStruct_t)); if (ioISP == NULL) { return NULL; } /* initialize */ ioISP->maxPassDestinations = maxPass; ioISP->maxFailDestinations = maxFail; ioISP->argc = argc; ioISP->argv = argv; return ioISP; } /* * Add fPath as a 'pass' destination. See header for details. */ int iochecksPassDestinations( iochecksInfoStruct_t *ioISP, const char *fPath, int ttyOK) { const int i = ioISP->passCount; /* convenience variable */ int rv = 1; /* return status */ if (ioISP->passCount >= ioISP->maxPassDestinations) { skAppPrintErr("Too many pass destinations"); return rv; } ioISP->passFPath[i] = strdup(fPath); if (NULL == ioISP->passFPath[i]) { skAppPrintErr("Out of memory!"); return rv; } ioISP->passCount++; if (strcmp(ioISP->passFPath[i], "stdout") == 0 ) { if (!ttyOK && FILEIsATty(stdout)) { skAppPrintErr("Will not print binary output to" " a terminal (stdout)"); goto END; } if (ioISP->stdoutUsed) { skAppPrintErr("Multiple outputs are trying to use stdout"); goto END; } ioISP->stdoutUsed = 1; ioISP->passFD[i] = stdout; rv = 0; goto END; } if (strcmp(ioISP->passFPath[i], "stderr") == 0 ) { #if ALLOW_STDERR if (!ttyOK && FILEIsATty(stderr)) { skAppPrintErr("Will not print binary output to" " a terminal (stderr)"); goto END; } if (ioISP->stderrUsed) { skAppPrintErr("Multiple outputs are trying to use stderr"); goto END; } ioISP->stderrUsed = 1; ioISP->passFD[i] = stderr; rv = 0; goto END; #else /* ALLOW_STDERR */ skAppPrintErr("stderr not a valid output device. Abort"); goto END; #endif /* ALLOW_STDERR */ } if (strcmp(ioISP->passFPath[i], "/dev/null") == 0 ) { /* this is OK but do not open the file nor treat it as real file */ free(ioISP->passFPath[i]); ioISP->devnullUsed = 1; ioISP->passFPath[i] = NULL; ioISP->passCount--; rv = 0; goto END; } if (fileExists(ioISP->passFPath[i])) { /* * dont allow existing non-null non-fifo files to be overwritten by * accident */ if (fileSize(ioISP->passFPath[i]) > 0 && !isFIFO(ioISP->passFPath[i])){ skAppPrintErr(("Output file '%s' exists.\n" "\tIf you really want to overwrite this file, " "remove it manually and\n\tthen run %s again."), ioISP->passFPath[i], skAppName()); goto END; } } if (openFile(ioISP->passFPath[i], 1 /* write */, &ioISP->passFD[i], &ioISP->passIsPipe[i])) { skAppPrintErr("Unable to open output file '%s'", ioISP->passFPath[i]); goto END; } /* success! */ rv = 0; END: if (rv != 0) { if (ioISP->passFPath[i]) { free(ioISP->passFPath[i]); ioISP->passFPath[i] = NULL; --ioISP->passCount; } } return rv; } /* * Add fPath as a 'fail' destination. See header for details. */ int iochecksFailDestinations( iochecksInfoStruct_t *ioISP, const char *fPath, int ttyOK) { const int i = ioISP->failCount; /* convenience variable */ int rv = 1; /* return status */ if (ioISP->failCount >= ioISP->maxFailDestinations) { skAppPrintErr("Too many fail destinations."); return 1; } ioISP->failFPath[i] = strdup(fPath); if (NULL == ioISP->failFPath[i]) { skAppPrintErr("Out of memory!"); return 1; } ioISP->failCount++; if (strcmp(ioISP->failFPath[i], "stdout") == 0 ) { if (!ttyOK && FILEIsATty(stdout)) { skAppPrintErr("Will not print binary output to" " a terminal (stdout)"); goto END; } if (ioISP->stdoutUsed) { skAppPrintErr("Multiple outputs are trying to use stdout"); goto END; } ioISP->stdoutUsed = 1; ioISP->failFD[i] = stdout; rv = 0; goto END; } if (strcmp(ioISP->failFPath[i], "stderr") == 0 ) { #if ALLOW_STDERR if (!ttyOK && FILEIsATty(stderr)) { skAppPrintErr("Will not print binary output to" " a terminal (stderr)"); goto END; } if (ioISP->stderrUsed) { skAppPrintErr("Multiple outputs are trying to use stderr"); goto END; } ioISP->stderrUsed = 1; ioISP->failFD[i] = stderr; rv = 0; goto END; #else /* ALLOW_STDERR */ skAppPrintErr("stderr not a valid output device. Abort"); goto END; #endif /* ALLOW_STDERR */ } if (strcmp(ioISP->failFPath[i], "/dev/null") == 0 ) { /* this is OK but do not open the file nor treat it as real file */ free(ioISP->failFPath[i]); ioISP->devnullUsed = 1; ioISP->failFPath[i] = NULL; ioISP->failCount--; rv = 0; goto END; } if (fileExists(ioISP->failFPath[i])) { /* * dont allow existing non-null non-fifo files to be overwritten by * accident */ if (fileSize(ioISP->failFPath[i]) > 0 && !isFIFO(ioISP->failFPath[i])){ skAppPrintErr(("Output file '%s' exists.\n" "If you really want to overwrite this file, " "remove it manually and then re-run %s."), ioISP->failFPath[i], skAppName()); goto END; } } if (openFile(ioISP->failFPath[i], 1 /* write */, &ioISP->failFD[i], &ioISP->failIsPipe[i])) { skAppPrintErr("Unable to open output file '%s'", ioISP->failFPath[i]); goto END; } /* success! */ rv = 0; END: if (rv != 0) { if (ioISP->failFPath[i]) { free(ioISP->failFPath[i]); ioISP->failFPath[i] = NULL; --ioISP->failCount; } } return rv; } /* * Add fPath as an 'all' destination'. See header for details. Note * that this is an rwIOS stream. */ int iochecksAllDestinations( iochecksInfoStruct_t *ioISP, const char *fPath) { if (ioISP->inputCopyFD != NULL) { skAppPrintErr("Too many destinations for all."); return 1; } if (strcmp(fPath, "stdout") == 0 ) { if (FILEIsATty(stdout)) { skAppPrintErr("Will not print binary output to" " a terminal (stdout)"); return 1; } if (ioISP->stdoutUsed) { skAppPrintErr("Multiple outputs are trying to use stdout"); return 1; } ioISP->stdoutUsed = 1; } if (strcmp(fPath, "stderr") == 0 ) { #if ALLOW_STDERR if (FILEIsATty(stderr)) { skAppPrintErr("Will not print binary output to" " a terminal (stderr)"); return 1; } if (ioISP->stderrUsed) { skAppPrintErr("Multiple outputs are trying to use stderr"); return 1; } ioISP->stderrUsed = 1; #else /* ALLOW_STDERR */ skAppPrintErr("stderr not a valid output device. Abort"); return 1; #endif /* ALLOW_STDERR */ } if (rwioCreate(&(ioISP->inputCopyFD), fPath, SK_RWIO_WRITE)) { skAppPrintErr("unable to create copy stream %s", fPath); return 1; } ioISP->inputCopyFPath = ioISP->inputCopyFD->fPath; return 0; } /* * Set up ioISP to read data from 'stream_name' */ int iochecksInputSource( iochecksInfoStruct_t *ioISP, const char *stream_name) { /* check the function's input */ assert(ioISP); if (stream_name == NULL) { return 1; } /* can only be called one time */ if (ioISP->inputPipeFlag != 0) { if (0 == strcmp(stream_name, pseudoArgv[0])) { /* stream names match; don't warn */ return 0; } skAppPrintErr(("Can only read from one input stream.\n" "\t Multiple streams '%s' and '%s' given."), pseudoArgv[0], stream_name); return 1; } /* stream_name must be "stdin" or name of a FIFO */ if (strcmp(stream_name, "stdin") == 0) { if (FILEIsATty(stdin)) { skAppPrintErr("stdin is connected to a terminal."); return 1; } } else if (!isFIFO(stream_name)) { /* not a FIFO */ skAppPrintErr("input-source '%s' doesn't exist or isn't a pipe", stream_name); return 1; } /* delay opening: this is handled in openFile and relatives */ ioISP->inputPipeFlag = 1; pseudoArgv[0] = strdup(stream_name); if (NULL == pseudoArgv[0]) { return 1; } return 0; } /* * If STDIN is not a terminal and if we don't have any other input, * add STDIN as an input stream. */ int iochecksAcceptFromStdin(iochecksInfoStruct_t *ioISP) { if (FILEIsATty(stdin)) { return 0; } /* Ignore STDIN if a previous input pipe was explicitly set. */ if (ioISP->inputPipeFlag != 0) { return 0; } /* Ignore STDIN if files given explicitly on command line. */ if (ioISP->firstFile < ioISP->argc) { return 0; } /* Set up to read from STDIN. Delay opening: this is handled in * openFile and relatives. */ ioISP->inputPipeFlag = 1; pseudoArgv[0] = strdup("stdin"); if (NULL == pseudoArgv[0]) { return 1; } return 0; } /* * Check that we have the required number of input sources, and no * more than one. See header for details. */ int iochecksInputs( iochecksInfoStruct_t *ioISP, int zeroFilesOK) { if (ioISP->inputPipeFlag) { /* can either specify input-pipe or give input files but not both */ if( ioISP->firstFile < ioISP->argc ) { skAppPrintErr("Too many inputs: Cannot read data from both %s\n" "\t and from filenames listed on the command line.", pseudoArgv[0]); return 1; } ioISP->firstFile = 0; ioISP->fileCount = 1; ioISP->fnArray = &pseudoArgv[0]; return 0; } /* files given explicitly. check that we have SOME to process */ if( ioISP->firstFile >= ioISP->argc ) { if (zeroFilesOK) { ioISP->fileCount = 0; return 0; } else { skAppPrintErr("No input: No filenames listed on the command line\n" "\t and no data to read from stdin."); return 1; } } /* some to process from command line */ ioISP->fileCount = ioISP->argc - ioISP->firstFile; ioISP->fnArray = &ioISP->argv[ioISP->firstFile]; ioISP->firstFile = 0; return 0; } /* * Cleanup */ void iochecksTeardown(iochecksInfoStruct_t *ioISP) { int i; int rv; if (pseudoArgv[0] != NULL) { free(pseudoArgv[0]); pseudoArgv[0] = NULL; } if (NULL == ioISP) { return; } for (i = 0; i < ioISP->passCount; ++i) { if (ioISP->passFPath[i]) { free(ioISP->passFPath[i]); ioISP->passFPath[i] = NULL; } } for (i = 0; i < ioISP->failCount; ++i) { if (ioISP->failFPath[i]) { free(ioISP->failFPath[i]); ioISP->failFPath[i] = NULL; } } if (ioISP->inputCopyFD) { rv = rwioClose(ioISP->inputCopyFD); if (rv) { rwioPrintLastErr(ioISP->inputCopyFD, rv, &skAppPrintErr); } rwioDestroy(&(ioISP->inputCopyFD)); ioISP->inputCopyFD = NULL; ioISP->inputCopyFPath = NULL; } free(ioISP); } int iochecksOpenCopyDest(iochecksInfoStruct_t *ioISP) { int rv; if (ioISP->inputCopyFD == NULL) { return 0; } if ((rv = rwioOpen(ioISP->inputCopyFD)) || (rv = rwioWriteHeader(ioISP->inputCopyFD))) { rwioPrintLastErr(ioISP->inputCopyFD, rv, &skAppPrintErr); return rv; } return 0; } /* ** Local variables: ** mode:c ** indent-tabs-mode:nil ** c-basic-offset:4 ** End: */