/*
* Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
* 2002, 2003, 2004
* Ohio University.
*
* ---
*
* Starting with the release of tcptrace version 6 in 2001, tcptrace
* is licensed under the GNU General Public License (GPL). We believe
* that, among the available licenses, the GPL will do the best job of
* allowing tcptrace to continue to be a valuable, freely-available
* and well-maintained tool for the networking community.
*
* Previous versions of tcptrace were released under a license that
* was much less restrictive with respect to how tcptrace could be
* used in commercial products. Because of this, I am willing to
* consider alternate license arrangements as allowed in Section 10 of
* the GNU GPL. Before I would consider licensing tcptrace under an
* alternate agreement with a particular individual or company,
* however, I would have to be convinced that such an alternative
* would be to the greater benefit of the networking community.
*
* ---
*
* This file is part of Tcptrace.
*
* Tcptrace was originally written and continues to be maintained by
* Shawn Ostermann with the help of a group of devoted students and
* users (see the file 'THANKS'). The work on tcptrace has been made
* possible over the years through the generous support of NASA GRC,
* the National Science Foundation, and Sun Microsystems.
*
* Tcptrace is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Tcptrace is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tcptrace (in the file 'COPYING'); if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
* Author: Shawn Ostermann
* School of Electrical Engineering and Computer Science
* Ohio University
* Athens, OH
* ostermann@cs.ohiou.edu
* http://www.tcptrace.org/
*/
#include "tcptrace.h"
static char const GCC_UNUSED copyright[] =
"@(#)Copyright (c) 2004 -- Ohio University.\n";
static char const GCC_UNUSED rcsid[] =
"@(#)$Header: /usr/local/cvs/tcptrace/mfiles.c,v 5.10 2004/09/28 18:59:35 mramadas Exp $";
/*
* tcptrace.c - turn protocol monitor traces into xplot
*
* this set of functions allows a user to open "many files"
* dispite the open file max limit. (Uses LRU)
*
* Author: Shawn Ostermann
* Date: Tue Nov 1, 1994
*/
#include <errno.h>
struct mfile {
FILE *stream;
char *fname;
MFILE *next;
MFILE *prev;
long fptr;
};
/* local static routines */
static void Mcheck(MFILE *pmf);
static void Mfopen_internal(MFILE *pmf, char *mode);
static void Mf_totail(MFILE *pmf, MFILE *ptail);
static void Mf_unlink(MFILE *pmf);
static void M_closeold(void);
static void M_mkdirp(char *directory);
/* head and tail of LRU open file list */
MFILE mf_head; /* LEAST recently used */
MFILE mf_tail; /* MOST recently used */
MFILE mfc_head; /* closed files, LEAST recently closed */
MFILE mfc_tail; /* closed files, MOST recently closed */
void
Minit(void)
{
mf_head.next = &mf_tail;
mf_tail.prev = &mf_head;
mf_head.fname = "HEAD";
mf_tail.fname = "TAIL";
mfc_head.next = &mfc_tail;
mfc_tail.prev = &mfc_head;
mfc_head.fname = "CLOSED HEAD";
mfc_tail.fname = "CLOSED TAIL";
}
MFILE *
Mfopen(
char *fname,
char *mode)
{
MFILE *pmf;
char *directory;
char *prefix;
int len;
if ((strcmp(mode,"w") != 0) && (strcmp(mode,"a") != 0)){
fprintf(stderr,"Sorry, Mfopen works only for mode \"w\" or \"a\"\n");
exit(-1);
}
pmf = (MFILE *) MallocZ(sizeof(MFILE));
/* use the directory specified by the user, if requested */
if (output_file_dir == NULL)
directory = "";
else {
directory = ExpandFormat(output_file_dir);
M_mkdirp(directory);
}
/* attach a filename prefix, if the user asked for one */
if (output_file_prefix == NULL)
prefix = "";
else
prefix = ExpandFormat(output_file_prefix);
len=strlen(fname)+strlen(directory)+strlen(prefix)+2;
/* 2: for the slash and null */
pmf->fname = MallocZ(len);
snprintf(pmf->fname,len,"%s%s%s%s",
directory,
(*directory)?"/":"",
prefix,
fname);
// The 'b' in the file mode has no meaning in UNIX systems.
// It has meaning in Operating Systems like Windows that
// seem to treat text and binary files differently.
if (strcmp(mode,"w") == 0)
Mfopen_internal(pmf,"wb+");
else if (strcmp(mode,"a") == 0)
Mfopen_internal(pmf,"ab+");
else {
fprintf(stderr,"Mfopen: internal file mode inconsistancy\n");
exit(10);
}
/* put at the tail of the LRU list */
Mf_totail(pmf,&mf_tail);
return(pmf);
}
/* not really an mfiles thing, but works even when we're out of fd's */
int
Mfpipe(
int pipes[2])
{
int i;
for (i=0; i <= 2; ++i) {
if (pipe(pipes) == 0)
return(0);
if (errno != EMFILE) {
perror("pipe");
exit(-1);
}
M_closeold();
}
fprintf(stderr,"mfpipe - internal error, couldn't get pipes?\n");
exit(-1);
}
int
Mfileno(
MFILE *pmf)
{
/* Warning, I'll GIVE you the fd, but I won't guarantee that it'll stay */
/* where you want it if you call my functions back!!! */
Mcheck(pmf);
return(fileno(pmf->stream));
}
int
Mvfprintf(
MFILE *pmf,
char *format,
va_list ap)
{
int ret;
Mcheck(pmf);
ret = vfprintf(pmf->stream,format,ap);
return(ret);
}
int
Mfprintf(
MFILE *pmf,
char *format,
...)
{
va_list ap;
int ret;
va_start(ap,format);
Mcheck(pmf);
ret = vfprintf(pmf->stream,format,ap);
va_end(ap);
return(ret);
}
long
Mftell(
MFILE *pmf)
{
Mcheck(pmf);
return(ftell(pmf->stream));
}
int
Mfseek(
MFILE *pmf,
long offset,
int ptrname)
{
Mcheck(pmf);
return(fseek(pmf->stream, offset, ptrname));
}
int
Mfwrite(
void *buf,
u_long size,
u_long nitems,
MFILE *pmf)
{
Mcheck(pmf);
return(fwrite(buf,size,nitems,pmf->stream));
}
int
Mfclose(
MFILE *pmf)
{
int ret;
if (debug>1)
fprintf(stderr,"Mfclose: called for file '%s'\n", pmf->fname);
Mcheck(pmf);
ret=fclose(pmf->stream);
pmf->stream = NULL;
return(ret);
}
int
Mfflush(
MFILE *pmf)
{
Mcheck(pmf);
return(fflush(pmf->stream));
}
static void
Mfopen_internal(
MFILE *pmf,
char *mode)
{
FILE *stream;
stream = fopen(pmf->fname,mode);
if (stream == NULL) {
if (errno != EMFILE) {
perror(pmf->fname);
exit(-1);
}
M_closeold();
/* now, try again */
stream = fopen(pmf->fname,mode);
if (stream == NULL) {
perror("fopen (second try)");
exit(-1);
}
}
pmf->stream = stream;
/* seek back to where we were last time, if this was previously opened */
if (pmf->fptr != 0) {
if (fseek(stream, pmf->fptr, SEEK_SET) != 0) {
perror("fseek");
exit(-1);
}
}
return;
}
static void
M_closeold(void)
{
MFILE *closehim;
/* OK, close a file we haven't used for a while */
closehim = mf_head.next;
closehim->fptr = ftell(closehim->stream); /* remember current position */
fclose(closehim->stream);
closehim->stream = NULL;
/* put closed file at the tail of the closed LRU list */
Mf_unlink(closehim);
Mf_totail(closehim,&mfc_tail);
if (debug > 1)
fprintf(stderr,"Mfiles: too many files open, closed file '%s'\n",
closehim->fname);
}
static void
Mcheck(
MFILE *pmf)
{
/* make sure that it's open */
if (pmf->stream == NULL) {
if (debug > 1)
fprintf(stderr,"Mcheck: re-opening file '%s'\n", pmf->fname);
Mfopen_internal(pmf,"r+");
}
/* put at the tail of the LRU list */
if (mf_tail.prev != pmf) {
Mf_unlink(pmf);
Mf_totail(pmf,&mf_tail);
}
}
#ifdef OLD
static void
M_printlru(void)
{
MFILE *pmf;
for (pmf = &mf_head; pmf; pmf=pmf->next)
fprintf(stderr,"%s ==> ", pmf->fname);
fprintf(stderr,"NULL \n");
for (pmf = &mfc_head; pmf; pmf=pmf->next)
fprintf(stderr,"%s ==> ", pmf->fname);
fprintf(stderr,"NULL \n");
}
#endif /* OLD */
static void
Mf_unlink(
MFILE *pmf)
{
pmf->prev->next = pmf->next;
pmf->next->prev = pmf->prev;
}
static void
Mf_totail(
MFILE *pmf,
MFILE *ptail)
{
pmf->next = ptail;
pmf->prev = ptail->prev;
ptail->prev->next = pmf;
ptail->prev = pmf;
}
/* try to create all of the directories in the argument */
/* like mkdirp() under Solaris, but that apparently isn't standard */
static void
M_mkdirp(char *directory)
{
static dstring_t *pds = NULL;
char *pch;
char *temp;
if (access(directory,W_OK) == 0) {
/* it already exists */
return;
}
/* make a dynamic string to store the path components */
if (pds == NULL)
pds = DSNew();
if (debug)
fprintf(stderr,"Trying to create directory '%s'\n", directory);
/* walk the directory and try to create the components */
pch = directory;
while (pch) {
pch = strchr(pch,'/');
/* N.B. pch will be null on the last go around */
/* copy that much of the directory */
DSErase(pds);
if (pch)
DSAppendStringN(pds,directory,(1 + pch - directory));
else
DSAppendString(pds,directory); /* last loop */
temp = DSVal(pds);
/* try to create it */
if (mkdir(temp,0755) == -1) {
/* this will fail with EEXIST if the directory exists,
which is fine */
if (errno != EEXIST) {
/* couldn't make the directory */
perror(temp);
fprintf(stderr,
"Unable to create directory '%s' (as part of '%s')\n",
temp, directory);
exit(-1);
}
} else {
if (debug)
fprintf(stderr,"Created directory '%s'\n", temp);
}
/* if pch is NULL, then we're done and will fall out,
else we need to increment pch past the current '/' */
if (pch)
++pch;
}
}
syntax highlighted by Code2HTML, v. 0.9.1