/* Copyright (C) 2001 Beau Kuiper
This program 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, or (at your option)
any later version.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "ftpd.h"
#define FALSE 0
#define TRUE !FALSE
int signumber;
void sighandler(int signum)
{
signumber = signum;
}
int openfifo(char *fifoname)
{
struct stat inf;
if (stat(fifoname, &inf) == -1)
{
/* try creating it */
if (mknod(fifoname, S_IFIFO | 0600, 0) == -1)
return(-1);
}
else
{
/* make sure it is a fifo */
if (!S_ISFIFO(inf.st_mode))
{
errno = EEXIST;
return(-1);
}
}
return(open(fifoname, O_RDONLY));
}
int reopenlog(char *logfile, int *logfd)
{
int newlogfd;
newlogfd = open(logfile, O_APPEND | O_CREAT | O_WRONLY, 0600);
if (newlogfd != -1)
{
close(*logfd);
*logfd = newlogfd;
}
return(newlogfd != -1);
}
char *reloadlogfile(char *fconfig)
{
CONFIGFILECACHE *cfiledata;
int line, error, section;
char *newlogfile;
cfiledata = loadconfigcache(fconfig, &line, &error);
if (cfiledata == NULL)
return(NULL);
section = getsectionid(cfiledata, "logger");
if (section == -1)
goto error;
loadstrfromconfig(cfiledata, section, "logfile",
&newlogfile, NULL);
if (!newlogfile)
goto error;
if (newlogfile[0] != '/')
goto error;
newlogfile = strdupwrapper(newlogfile);
/* free config info */
freeconfigcache(cfiledata);
return(newlogfile);
error:
freeconfigcache(cfiledata);
return(NULL);
}
void usage(char *name)
{
printf("mudlogd, handles muddleftpd logging and rotation.\n\n");
printf("Usage: %s [-V][-h][-c configfile]\n\n", name);
printf(" -V Show version information.\n");
printf(" -h Show usage information.\n");
printf(" -c configfile Specify config file mudlogd to run using.\n\n");
exit(1);
}
int main(int argc, char **argv)
{
CONFIGFILECACHE *cfiledata;
struct sigaction sig1act;
char *fconfig = NULL;
char *fifoname = NULL;
char *logoutname = NULL;
int section, line, error;
int ch, f;
int outfile, infile;
extern char *optarg;
char *newlogfile = NULL;
while((ch = getopt(argc, argv, "Vc:h")) != EOF)
{
switch(ch)
{
case 'V':
showversion("mudlogd");
break;
case 'c':
fconfig = optarg;
break;
case 'h':
default:
usage(argv[0]);
}
}
if (fconfig == NULL)
fconfig = CONFIGFILE;
cfiledata = loadconfigcache(fconfig, &line, &error);
/* obtain scratchfile name */
if (cfiledata == NULL)
ERRORMSGFATAL(safe_snprintf("Could not load line %d of config file: %s", line, config_errorstr(error)));
section = getsectionid(cfiledata, "logger");
if (section == -1)
ERRORMSGFATAL("Could not find logger section in config file");
loadstrfromconfig(cfiledata, section, "fifoname",
&fifoname, NULL);
if (!fifoname)
ERRORMSGFATAL("fifoname not specified in config file");
if (fifoname[0] != '/')
ERRORMSGFATAL("fifoname is not a valid absolute filename");
fifoname = strdupwrapper(fifoname);
loadstrfromconfig(cfiledata, section, "logfile",
&logoutname, NULL);
if (!logoutname)
ERRORMSGFATAL("logfile not specified in config file");
if (logoutname[0] != '/')
ERRORMSGFATAL("logfile is not a valid absolute filename");
logoutname = strdupwrapper(logoutname);
/* free config info */
freeconfigcache(cfiledata);
/* open the log file, make sure it works before returning to the user */
outfile = open(logoutname, O_APPEND | O_CREAT | O_WRONLY, 0600);
if (outfile == -1)
ERRORMSGFATAL(safe_snprintf("could not open logfile (%s)", strerror(errno)));
f = fork();
if (f == -1)
ERRORMSGFATAL("could not fork()");
else if (f == 0)
{
int len, doquit, schedrotate;
char data[4096];
char lastch = '\n';
setsid();
signumber = 0;
sig1act.sa_handler = sighandler;
sig1act.sa_flags = 0;
sigaction(SIGUSR1, &sig1act, NULL);
sig1act.sa_handler = sighandler;
sig1act.sa_flags = 0;
sigaction(SIGHUP, &sig1act, NULL);
while(1)
{
schedrotate = FALSE;
/* reopen the fifo channel, ignoring any signals for now */
do
{
infile = openfifo(fifoname);
if ((infile == -1) && (errno == EINTR))
schedrotate = TRUE;
signumber = 0;
}
while ((infile == -1) && (errno == EINTR));
if (infile == -1)
ERRORMSGFATAL(safe_snprintf("could not open fifo file (%s)", strerror(errno)));
doquit = FALSE;
while(!doquit)
{
if (schedrotate && (lastch == '\n'))
{
if (newlogfile)
{
if (reopenlog(newlogfile, &outfile))
{
freewrapper(logoutname);
logoutname = newlogfile;
}
else
freewrapper(newlogfile);
newlogfile = NULL;
}
else
reopenlog(logoutname, &outfile);
schedrotate = FALSE;
}
errno = 0;
len = read(infile, data, 4096);
if (signumber != 0)
{
if (signumber == SIGUSR1)
{
if (lastch == '\n')
reopenlog(logoutname, &outfile);
else
schedrotate = TRUE;
}
else if (signumber == SIGHUP)
{
/* load config again */
newlogfile = reloadlogfile(fconfig);
if (newlogfile)
{
if (lastch == '\n')
{
if (reopenlog(newlogfile, &outfile))
{
freewrapper(logoutname);
logoutname = newlogfile;
}
else
freewrapper(newlogfile);
newlogfile = NULL;
}
else
schedrotate = TRUE;
}
}
signumber = 0;
}
if (len > 0)
{
lastch = data[len-1];
len = write(outfile, data, len);
}
if ((len <= 0) && (errno != EINTR))
doquit = TRUE;
}
close(infile);
}
}
/* not reached but shuts the compiler up */
exit(0);
}
syntax highlighted by Code2HTML, v. 0.9.1