/* 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); }