X-Git-Url: http://www.dolda2000.com/gitweb/?a=blobdiff_plain;f=src%2Faccesslog.c;h=5b0c7081152bb0abda657efc0db3eb7cf7a73cc6;hb=ca170d77b595e63bbbaba28ace23cc88e855c41a;hp=27663c4983b096fc182b97852f2584652e32bcd5;hpb=e3f12675774fa2bb0f68f2cea05f4285d1fc235c;p=ashd.git diff --git a/src/accesslog.c b/src/accesslog.c index 27663c4..5b0c708 100644 --- a/src/accesslog.c +++ b/src/accesslog.c @@ -25,6 +25,8 @@ #include #include #include +#include +#include #ifdef HAVE_CONFIG_H #include @@ -39,7 +41,7 @@ static int ch; static char *outname = NULL; static FILE *out; -static int flush = 1; +static int flush = 1, locklog = 1; static char *format; static struct timeval now; static volatile int reopen = 0; @@ -176,25 +178,101 @@ static void sighandler(int sig) reopen = 1; } +static int lockfile(FILE *file) +{ + struct flock ld; + + memset(&ld, 0, sizeof(ld)); + ld.l_type = F_WRLCK; + ld.l_whence = SEEK_SET; + ld.l_start = 0; + ld.l_len = 0; + return(fcntl(fileno(file), F_SETLK, &ld)); +} + +static void fetchpid(char *filename) +{ + int fd, ret; + struct flock ld; + + if((fd = open(filename, O_WRONLY)) < 0) { + fprintf(stderr, "accesslog: %s: %s\n", filename, strerror(errno)); + exit(1); + } + memset(&ld, 0, sizeof(ld)); + ld.l_type = F_WRLCK; + ld.l_whence = SEEK_SET; + ld.l_start = 0; + ld.l_len = 0; + ret = fcntl(fd, F_GETLK, &ld); + close(fd); + if(ret) { + fprintf(stderr, "accesslog: %s: %s\n", filename, strerror(errno)); + exit(1); + } + if(ld.l_type == F_UNLCK) { + fprintf(stderr, "accesslog: %s: not locked\n", filename); + exit(1); + } + printf("%i\n", (int)ld.l_pid); +} + static void reopenlog(void) { FILE *new; + struct stat olds, news; if(outname == NULL) { flog(LOG_WARNING, "accesslog: received SIGHUP but logging to stdout, so ignoring"); return; } + if(locklog) { + if(fstat(fileno(out), &olds)) { + flog(LOG_ERR, "accesslog: could not stat current logfile(?!): %s", strerror(errno)); + return; + } + if(!stat(outname, &news)) { + if((olds.st_dev == news.st_dev) && (olds.st_ino == news.st_ino)) { + /* + * This needs to be ignored, because if the same logfile + * is opened and then closed, the lock is lost. To quote + * the Linux fcntl(2) manpage: "This is bad." No kidding. + * + * Technically, there is a race condition here when the + * file has been stat'ed but not yet opened, where the old + * log file, having been previously renamed, changes name + * back to the name accesslog knows and is thus reopened + * regardlessly, but I think that might fit under the + * idiom "pathological case". It should, at least, not be + * a security problem. + */ + flog(LOG_INFO, "accesslog: received SIGHUP, but logfile has not changed, so ignoring"); + return; + } + } + } if((new = fopen(outname, "a")) == NULL) { flog(LOG_WARNING, "accesslog: could not reopen log file `%s' on SIGHUP: %s", outname, strerror(errno)); return; } + if(locklog) { + if(lockfile(new)) { + if((errno == EAGAIN) || (errno == EACCES)) { + flog(LOG_ERR, "accesslog: logfile is already locked; reverting to current log", strerror(errno)); + fclose(new); + return; + } else { + flog(LOG_WARNING, "accesslog: could not lock logfile, so no lock will be held: %s", strerror(errno)); + } + } + } fclose(out); out = new; } static void usage(FILE *out) { - fprintf(out, "usage: accesslog [-hFa] [-f FORMAT] OUTFILE CHILD [ARGS...]\n"); + fprintf(out, "usage: accesslog [-hFaL] [-f FORMAT] [-p PIDFILE] OUTFILE CHILD [ARGS...]\n"); } int main(int argc, char **argv) @@ -203,8 +281,11 @@ int main(int argc, char **argv) struct hthead *req; int fd; struct pollfd pfd[2]; + char *pidfile; + FILE *pidout; - while((c = getopt(argc, argv, "+hFaf:")) >= 0) { + pidfile = NULL; + while((c = getopt(argc, argv, "+hFaLf:p:P:")) >= 0) { switch(c) { case 'h': usage(stdout); @@ -212,9 +293,18 @@ int main(int argc, char **argv) case 'F': flush = 0; break; + case 'L': + locklog = 0; + break; case 'f': format = optarg; break; + case 'P': + fetchpid(optarg); + exit(0); + case 'p': + pidfile = optarg; + break; case 'a': format = "%A - - [%{%d/%b/%Y:%H:%M:%S %z}t] \"%m %u %v\" - - \"%R\" \"%G\""; break; @@ -241,11 +331,36 @@ int main(int argc, char **argv) exit(1); } } + if(locklog) { + if(lockfile(out)) { + if((errno == EAGAIN) || (errno == EACCES)) { + flog(LOG_ERR, "accesslog: logfile is already locked", strerror(errno)); + exit(1); + } else { + flog(LOG_WARNING, "accesslog: could not lock logfile: %s", strerror(errno)); + } + } + } if((ch = stdmkchild(argv + optind + 1, NULL, NULL)) < 0) { flog(LOG_ERR, "accesslog: could not fork child: %s", strerror(errno)); exit(1); } signal(SIGHUP, sighandler); + if(pidfile) { + if(!strcmp(pidfile, "-")) { + if(!outname) { + flog(LOG_ERR, "accesslog: cannot derive PID file name without an output file"); + exit(1); + } + pidfile = sprintf2("%s.pid", outname); + } + if((pidout = fopen(pidfile, "w")) == NULL) { + flog(LOG_ERR, "accesslog: could not open PID file %s for writing: %s", pidfile); + exit(1); + } + fprintf(pidout, "%i\n", (int)getpid()); + fclose(pidout); + } while(1) { if(reopen) { reopenlog(); @@ -276,5 +391,7 @@ int main(int argc, char **argv) if(pfd[1].revents & POLLHUP) break; } + if(pidfile != NULL) + unlink(pidfile); return(0); }