/* * This file is part of tcpflow by Jeremy Elson * Initial Release: 7 April 1999. * * This source code is under the GNU Public License (GPL). See * LICENSE for details. * * $Id: util.c,v 1.9 2001/08/08 19:39:40 jelson Exp $ * * $Log: util.c,v $ * Revision 1.9 2001/08/08 19:39:40 jelson * ARGH! These are changes that made up tcpflow 0.20, which for some reason I * did not check into the repository until now. (Which of couse means * I never tagged v0.20.... argh.) * * Changes include: * * -- portable signal handlers now used to do proper termination * * -- patch to allow tcpflow to read from tcpdump stored captures * * Revision 1.8 1999/04/14 03:02:39 jelson * added typecasts for portability * * Revision 1.7 1999/04/13 01:38:16 jelson * Added portability features with 'automake' and 'autoconf'. Added AUTHORS, * NEWS, README, etc files (currently empty) to conform to GNU standards. * * Various portability fixes, including the FGETPOS/FSETPOS macros; detection * of header files using autoconf; restructuring of debugging code to not * need vsnprintf. * */ static char *cvsid = "$Id: util.c,v 1.9 2001/08/08 19:39:40 jelson Exp $"; #include "tcpflow.h" static char *debug_prefix = NULL; extern int max_desired_fds; #define BUFSIZE 1024 /*************************************************************************/ /* Simple wrapper around the malloc() function */ void *check_malloc(size_t size) { void *ptr; if ((ptr = malloc(size)) == NULL) { DEBUG(0) ("Malloc failed - out of memory?"); exit(1); } return ptr; } /* * Remember our program name and process ID so we can use them later * for printing debug messages */ void init_debug(char *argv[]) { debug_prefix = MALLOC(char, strlen(argv[0]) + 16); sprintf(debug_prefix, "%s[%d]", argv[0], (int) getpid()); } /* * Print a debugging message, given a va_list */ void print_debug_message(char *fmt, va_list ap) { /* print debug prefix */ fprintf(stderr, "%s: ", debug_prefix); /* print the var-arg buffer passed to us */ vfprintf(stderr, fmt, ap); /* add newline */ fprintf(stderr, "\n"); (void) fflush(stderr); } /* Print a debugging or informational message */ void debug_real(char *fmt, ...) { va_list ap; va_start(ap, fmt); print_debug_message(fmt, ap); va_end(ap); } /* Print a debugging or informatioal message, then exit */ void die(char *fmt, ...) { va_list ap; va_start(ap, fmt); print_debug_message(fmt, ap); exit(1); } /* Copy argv into a newly malloced buffer. Arguments are concatenated * with spaces in between each argument. */ char *copy_argv(char *argv[]) { char **arg; char *buf; int total_length = 0; for (arg = argv; *arg != NULL; arg++) total_length += (strlen(*arg) + 1); /* length of arg plus space */ if (total_length == 0) return NULL; total_length++; /* add room for a null */ buf = MALLOC(char, total_length); *buf = 0; for (arg = argv; *arg != NULL; arg++) { strcat(buf, *arg); strcat(buf, " "); } return buf; } #define RING_SIZE 6 char *flow_filename(flow_t flow) { static char ring_buffer[RING_SIZE][48]; static int ring_pos = 0; ring_pos = (ring_pos + 1) % RING_SIZE; sprintf(ring_buffer[ring_pos], "%03d.%03d.%03d.%03d.%05d-%03d.%03d.%03d.%03d.%05d", (u_int8_t) ((flow.src & 0xff000000) >> 24), (u_int8_t) ((flow.src & 0x00ff0000) >> 16), (u_int8_t) ((flow.src & 0x0000ff00) >> 8), (u_int8_t) (flow.src & 0x000000ff), flow.sport, (u_int8_t) ((flow.dst & 0xff000000) >> 24), (u_int8_t) ((flow.dst & 0x00ff0000) >> 16), (u_int8_t) ((flow.dst & 0x0000ff00) >> 8), (u_int8_t) (flow.dst & 0x000000ff), flow.dport); return ring_buffer[ring_pos]; } #undef RING_SIZE /* Try to find the maximum number of FDs this system can have open */ int get_max_fds(void) { int max_descs = 0; const char *method; /* First, we'll try using getrlimit/setrlimit. This will probably * work on most systems. HAS_RLIMIT is defined in sysdep.h. */ #ifdef RLIMIT_NOFILE { struct rlimit limit; method = "rlimit"; if (getrlimit(RLIMIT_NOFILE, &limit) < 0) { perror("calling getrlimit"); exit(1); } /* set the current to the maximum or specified value */ if (max_desired_fds) limit.rlim_cur = max_desired_fds; else limit.rlim_cur = limit.rlim_max; if (setrlimit(RLIMIT_NOFILE, &limit) < 0) { perror("calling setrlimit"); exit(1); } #ifdef RLIM_INFINITY if (limit.rlim_max == RLIM_INFINITY) max_descs = MAX_FD_GUESS * 4; else #endif max_descs = limit.rlim_max; } /* rlimit didn't work, but you have OPEN_MAX */ #elif defined (OPEN_MAX) method = "OPEN_MAX"; max_descs = OPEN_MAX; /* Okay, you don't have getrlimit() and you don't have OPEN_MAX. * Time to try the POSIX sysconf() function. (See Stevens' * _Advanced Programming in the UNIX Environment_). */ #elif defined (_SC_OPEN_MAX) method = "POSIX sysconf"; errno = 0; if ((max_descs = sysconf(_SC_OPEN_MAX)) < 0) { if (errno == 0) max_descs = MAX_FD_GUESS * 4; else { perror("calling sysconf"); exit(1); } } /* if everything has failed, we'll just take a guess */ #else method = "random guess"; max_descs = MAX_FD_GUESS; #endif /* this must go here, after rlimit code */ if (max_desired_fds) { DEBUG(10) ("using only %d FDs", max_desired_fds); return max_desired_fds; } DEBUG(10) ("found max FDs to be %d using %s", max_descs, method); return max_descs; } /* An attempt at making signal() portable. * * If we detect sigaction, use that; * otherwise if we have setsig, use that; * otherwise, cross our fingers and hope for the best using plain old signal(). * * Our first choice is sigaction (sigaction() is POSIX; signal() is * not.) Taken from Stevens' _Advanced Programming in the UNIX * Environment_. */ RETSIGTYPE (*portable_signal(int signo, RETSIGTYPE (*func)(int)))(int) { #if defined(HAVE_SIGACTION) struct sigaction act, oact; memset(&act, 0, sizeof(act)); memset(&oact, 0, sizeof(oact)); act.sa_handler = func; sigemptyset(&act.sa_mask); act.sa_flags = 0; if (sigaction(signo, &act, &oact) < 0) return (SIG_ERR); return (oact.sa_handler); #elif defined(HAVE_SIGSET) return sigset(signo, func); #else return signal(signo, func); #endif /* HAVE_SIGACTION, HAVE_SIGSET */ }