+ vavar(struct hthead *, req);
+ vavar(int, fd);
+ int pfds[2];
+ struct hthead *resp;
+ struct bufio *cl, *hd;
+ struct stdiofd *cli, *hdi;
+ struct logdata data;
+
+ hd = NULL;
+ resp = NULL;
+ data = defdata;
+ data.req = req;
+ gettimeofday(&data.start, NULL);
+ cl = mtbioopen(fd, 1, 600, "r+", &cli);
+ if(socketpair(PF_UNIX, SOCK_STREAM, 0, pfds))
+ goto out;
+ hd = mtbioopen(pfds[1], 1, 600, "r+", &hdi);
+ if(sendreq(ch, req, pfds[0])) {
+ close(pfds[0]);
+ goto out;
+ }
+ close(pfds[0]);
+
+ if(passdata(cl, hd, &data.bytesin))
+ goto out;
+ if(bioflush(hd))
+ goto out;
+ shutdown(pfds[1], SHUT_WR);
+ if((resp = parseresponseb(hd)) == NULL)
+ goto out;
+ cli->sendrights = hdi->rights;
+ hdi->rights = -1;
+ data.resp = resp;
+ writerespb(cl, resp);
+ bioprintf(cl, "\r\n");
+ if(passdata(hd, cl, &data.bytesout))
+ goto out;
+ gettimeofday(&data.end, NULL);
+
+out:
+ logreq(&data);
+
+ freehthead(req);
+ if(resp != NULL)
+ freehthead(resp);
+ bioclose(cl);
+ if(hd != NULL)
+ bioclose(hd);
+}
+
+static void sighandler(int sig)
+{
+ if(sig == SIGHUP) {
+ if(filter)
+ exitioloop(2);
+ else
+ 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;
+ }
+ fcntl(fileno(new), F_SETFD, FD_CLOEXEC);
+ 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 listenloop(struct muth *mt, va_list args)
+{
+ vavar(int, lfd);