This patch is generated from the s26_logfile_daemon branch of HEAD in squid
Mon Aug 13 00:18:09 2007 GMT
See http://devel.squid-cache.org/

Index: squid/src/Makefile.am
diff -u squid/src/Makefile.am:1.51 squid/src/Makefile.am:1.44.2.8
--- squid/src/Makefile.am:1.51	Sun May 20 06:52:24 2007
+++ squid/src/Makefile.am	Tue May 22 01:36:05 2007
@@ -44,6 +44,8 @@
 UNLINKD = 
 endif
 
+LOGFILED = logfile-daemon
+
 if ENABLE_PINGER
 PINGER = pinger
 else
@@ -110,7 +112,8 @@
 libexec_PROGRAMS = \
 	$(PINGER) \
 	$(DNSSERVER) \
-	$(UNLINKD)
+	$(UNLINKD) \
+	$(LOGFILED)
 
 cf_gen_SOURCES = cf_gen.c defines.h debug.c
 nodist_cf_gen_SOURCES = globals.c
@@ -195,6 +198,12 @@
 	$(LEAKFINDERSOURCE) \
 	locrewrite.c \
 	logfile.c \
+	logfile_mod_daemon.c \
+	logfile_mod_daemon.h \
+	logfile_mod_stdio.c \
+	logfile_mod_stdio.h \
+	logfile_mod_syslog.c \
+	logfile_mod_syslog.h \
 	main.c \
 	mem.c \
 	MemPool.c \
@@ -332,6 +341,7 @@
 DEFAULT_PINGER		= $(libexecdir)/`echo pinger | sed '$(transform);s/$$/$(EXEEXT)/'`
 DEFAULT_UNLINKD		= $(libexecdir)/`echo unlinkd | sed '$(transform);s/$$/$(EXEEXT)/'`
 DEFAULT_DISKD		= $(libexecdir)/`echo diskd-daemon | sed '$(transform);s/$$/$(EXEEXT)/'`
+DEFAULT_LOGFILED	= $(libexecdir)/`echo logfile-daemon | sed '$(transform);s/$$/$(EXEEXT)/'`
 DEFAULT_ICON_DIR	= $(datadir)/icons
 DEFAULT_ERROR_DIR	= $(datadir)/errors/@ERR_DEFAULT_LANGUAGE@
 DEFAULT_MIB_PATH	= $(datadir)/mib.txt
@@ -379,6 +389,7 @@
 	s%@DEFAULT_UNLINKD@%$(DEFAULT_UNLINKD)%g;\
 	s%@DEFAULT_PINGER@%$(DEFAULT_PINGER)%g;\
 	s%@DEFAULT_DISKD@%$(DEFAULT_DISKD)%g;\
+	s%@DEFAULT_LOGFILED@%$(DEFAULT_LOGFILED)%g;\
 	s%@DEFAULT_CACHE_LOG@%$(DEFAULT_CACHE_LOG)%g;\
 	s%@DEFAULT_ACCESS_LOG@%$(DEFAULT_ACCESS_LOG)%g;\
 	s%@DEFAULT_STORE_LOG@%$(DEFAULT_STORE_LOG)%g;\
Index: squid/src/access_log.c
diff -u squid/src/access_log.c:1.40 squid/src/access_log.c:1.28.2.11
--- squid/src/access_log.c:1.40	Thu May 17 13:53:38 2007
+++ squid/src/access_log.c	Tue May 22 01:36:05 2007
@@ -1133,29 +1133,32 @@
     for (log = Config.Log.accesslogs; log; log = log->next) {
 	if (checklist && log->aclList && aclMatchAclList(log->aclList, checklist) != 1)
 	    continue;
-	switch (log->type) {
-	case CLF_AUTO:
-	    if (Config.onoff.common_log)
-		accessLogCommon(al, log->logfile);
-	    else
+	if (log->logfile) {
+	    logfileLineStart(log->logfile);
+	    switch (log->type) {
+	    case CLF_AUTO:
+		if (Config.onoff.common_log)
+		    accessLogCommon(al, log->logfile);
+		else
+		    accessLogSquid(al, log->logfile);
+		break;
+	    case CLF_SQUID:
 		accessLogSquid(al, log->logfile);
-	    break;
-	case CLF_SQUID:
-	    accessLogSquid(al, log->logfile);
-	    break;
-	case CLF_COMMON:
-	    accessLogCommon(al, log->logfile);
-	    break;
-	case CLF_CUSTOM:
-	    accessLogCustom(al, log);
-	    break;
-	case CLF_NONE:
-	    goto last;
-	default:
-	    fatalf("Unknown log format %d\n", log->type);
-	    break;
+		break;
+	    case CLF_COMMON:
+		accessLogCommon(al, log->logfile);
+		break;
+	    case CLF_CUSTOM:
+		accessLogCustom(al, log);
+		break;
+	    case CLF_NONE:
+		goto last;
+	    default:
+		fatalf("Unknown log format %d\n", log->type);
+		break;
+	    }
+	    logfileLineEnd(log->logfile);
 	}
-	logfileFlush(log->logfile);
 	if (!checklist)
 	    break;
     }
@@ -1235,7 +1238,7 @@
     for (log = Config.Log.accesslogs; log; log = log->next) {
 	if (log->type == CLF_NONE)
 	    continue;
-	log->logfile = logfileOpen(log->filename, MAX_URL << 1, 1);
+	log->logfile = logfileOpen(log->filename, Config.Log.logtype, MAX_URL << 2, 1);
 	LogfileStatus = LOG_ENABLE;
     }
 #if HEADERS_LOG
@@ -1454,7 +1457,6 @@
     logfileWrite(headerslog, &S, sizeof(S));
     logfileWrite(headerslog, hmask, sizeof(HttpHeaderMask));
     logfileWrite(headerslog, &ccmask, sizeof(int));
-    logfileFlush(headerslog);
 }
 
 #endif
Index: squid/src/cache_cf.c
diff -u squid/src/cache_cf.c:1.97 squid/src/cache_cf.c:1.81.2.5
--- squid/src/cache_cf.c:1.97	Fri Jul 20 14:52:58 2007
+++ squid/src/cache_cf.c	Sat Aug 11 18:12:37 2007
@@ -470,6 +470,7 @@
 #if USE_UNLINKD
     requirePathnameExists("unlinkd_program", Config.Program.unlinkd);
 #endif
+    requirePathnameExists("logfile_daemon", Config.Program.logfile_daemon);
     if (Config.Program.url_rewrite.command)
 	requirePathnameExists("url_rewrite_program", Config.Program.url_rewrite.command->key);
     if (Config.Program.location_rewrite.command)
Index: squid/src/cf.data.pre
diff -u squid/src/cf.data.pre:1.190 squid/src/cf.data.pre:1.147.2.8
--- squid/src/cf.data.pre:1.190	Tue Aug  7 05:51:57 2007
+++ squid/src/cf.data.pre	Sat Aug 11 18:12:37 2007
@@ -1262,6 +1262,27 @@
 NOCOMMENT_END
 DOC_END
 
+NAME: logtype
+TYPE: string
+LOC: Config.Log.logtype
+DEFAULT: stdio
+DOC_START
+	Usage:
+
+	logtype stdio|daemon|syslog
+
+	Choose the logging method used to write access and store logs, if enabled.
+DOC_END
+
+NAME: logfile_daemon
+TYPE: string
+DEFAULT: @DEFAULT_LOGFILED@
+LOC: Config.Program.logfile_daemon
+DOC_START
+	Specify the path to the logfile-writing daemon. This daemon is
+	used to write the access and store logs, if configured.
+DOC_END
+
 NAME: cache_log
 TYPE: string
 DEFAULT: @DEFAULT_CACHE_LOG@
Index: squid/src/logfile-daemon.c
diff -u /dev/null squid/src/logfile-daemon.c:1.1.2.12
--- /dev/null		Thu Jan  1 01:00:00 1970
+++ squid/src/logfile-daemon.c	Sat Sep  2 07:12:19 2006
@@ -0,0 +1,159 @@
+#include "config.h"
+
+#if HAVE_STDIO_H
+#include <stdio.h>
+#endif
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#if HAVE_ASSERT_H
+#include <assert.h>
+#endif
+#if HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#if HAVE_STRING_H
+#include <string.h>
+#endif
+#if HAVE_PATHS_H
+#include <paths.h>
+#endif
+
+#include "defines.h"
+
+#define SQUID_MAXPATHLEN 256
+#ifndef MAXPATHLEN
+#define MAXPATHLEN SQUID_MAXPATHLEN
+#endif
+
+/* parse buffer - ie, length of longest expected line */
+#define	LOGFILE_BUF_LEN		65536
+
+static void
+rotate(const char *path, int rotate_count)
+{
+#ifdef S_ISREG
+    struct stat sb;
+#endif
+    int i;
+    char from[MAXPATHLEN];
+    char to[MAXPATHLEN];
+    assert(path);
+#ifdef S_ISREG
+    if (stat(path, &sb) == 0)
+	if (S_ISREG(sb.st_mode) == 0)
+	    return;
+#endif
+    /* Rotate numbers 0 through N up one */
+    for (i = rotate_count; i > 1;) {
+	i--;
+	snprintf(from, MAXPATHLEN, "%s.%d", path, i - 1);
+	snprintf(to, MAXPATHLEN, "%s.%d", path, i);
+#if defined(_SQUID_OS2_) || defined(_SQUID_WIN32_)
+	remove(to);
+#endif
+	rename(from, to);
+    }
+    if (rotate_count > 0) {
+	snprintf(to, MAXPATHLEN, "%s.%d", path, 0);
+#if defined(_SQUID_OS2_) || defined(_SQUID_WIN32_)
+	remove(to);
+#endif
+	rename(path, to);
+    }
+}
+
+/*
+ * The commands:
+ *
+ * L<data>\n - logfile data
+ * R\n - rotate file
+ * T\n - truncate file
+ * O\n - repoen file
+ * F\n - flush file
+ * r<n>\n - set rotate count to <n>
+ * b<n>\n - 1 = buffer output, 0 = don't buffer output
+ */
+int
+main(int argc, char *argv[])
+{
+    int t;
+    FILE *fp;
+    char buf[LOGFILE_BUF_LEN];
+    int rotate_count = 10;
+    int do_buffer = 1;
+
+    if (argc < 2) {
+	printf("Error: usage: %s <logfile>\n", argv[0]);
+	exit(1);
+    }
+    fp = fopen(argv[1], "a");
+    if (fp == NULL) {
+	perror("fopen");
+	exit(1);
+    }
+    setbuf(stdout, NULL);
+    close(2);
+    t = open(_PATH_DEVNULL, O_RDWR);
+    assert(t > -1);
+    dup2(t, 2);
+
+    while (fgets(buf, LOGFILE_BUF_LEN, stdin)) {
+	/* First byte indicates what we're logging! */
+	switch (buf[0]) {
+	case 'L':
+	    if (buf[1] != '\0') {
+		fprintf(fp, "%s", buf + 1);
+	    }
+	    if (!do_buffer)
+		fflush(fp);
+	    break;
+	case 'R':
+	    fclose(fp);
+	    rotate(argv[1], rotate_count);
+	    fp = fopen(argv[1], "a");
+	    if (fp == NULL) {
+		perror("fopen");
+		exit(1);
+	    }
+	    break;
+	case 'T':
+	    break;
+	case 'O':
+	    break;
+	case 'r':
+	    //fprintf(fp, "SET ROTATE: %s\n", buf + 1);
+	    rotate_count = atoi(buf + 1);
+	    break;
+	case 'b':
+	    //fprintf(fp, "SET BUFFERED: %s\n", buf + 1);
+	    do_buffer = (buf[1] == '1');
+	    break;
+	case 'F':
+	    fflush(fp);
+	    break;
+	default:
+	    /* Just in case .. */
+	    fprintf(fp, "%s", buf);
+	    break;
+	}
+    }
+    fclose(fp);
+    fp = NULL;
+    exit(0);
+}
Index: squid/src/logfile.c
diff -u squid/src/logfile.c:1.15 squid/src/logfile.c:1.12.2.16
--- squid/src/logfile.c:1.15	Sat Sep  2 07:17:45 2006
+++ squid/src/logfile.c	Fri May 18 12:13:12 2007
@@ -34,133 +34,43 @@
 
 #include "squid.h"
 
-static void logfileWriteWrapper(Logfile * lf, const void *buf, size_t len);
-
+#include "logfile_mod_daemon.h"
 #if HAVE_SYSLOG
-
-/* Define LOG_AUTHPRIV as LOG_AUTH on systems still using the old deprecated LOG_AUTH */
-#if !defined(LOG_AUTHPRIV) && defined(LOG_AUTH)
-#define LOG_AUTHPRIV LOG_AUTH
+#include "logfile_mod_syslog.h"
 #endif
+#include "logfile_mod_stdio.h"
 
-typedef struct {
-    const char *name;
-    int value;
-} syslog_symbol_t;
-
-static int
-syslog_ntoa(const char *s)
-{
-#define syslog_symbol(a) #a, a
-    static syslog_symbol_t symbols[] =
-    {
-#ifdef LOG_AUTHPRIV
-	{syslog_symbol(LOG_AUTHPRIV)},
-#endif
-#ifdef LOG_DAEMON
-	{syslog_symbol(LOG_DAEMON)},
-#endif
-#ifdef LOG_LOCAL0
-	{syslog_symbol(LOG_LOCAL0)},
-#endif
-#ifdef LOG_LOCAL1
-	{syslog_symbol(LOG_LOCAL1)},
-#endif
-#ifdef LOG_LOCAL2
-	{syslog_symbol(LOG_LOCAL2)},
-#endif
-#ifdef LOG_LOCAL3
-	{syslog_symbol(LOG_LOCAL3)},
-#endif
-#ifdef LOG_LOCAL4
-	{syslog_symbol(LOG_LOCAL4)},
-#endif
-#ifdef LOG_LOCAL5
-	{syslog_symbol(LOG_LOCAL5)},
-#endif
-#ifdef LOG_LOCAL6
-	{syslog_symbol(LOG_LOCAL6)},
-#endif
-#ifdef LOG_LOCAL7
-	{syslog_symbol(LOG_LOCAL7)},
-#endif
-#ifdef LOG_USER
-	{syslog_symbol(LOG_USER)},
-#endif
-#ifdef LOG_ERR
-	{syslog_symbol(LOG_ERR)},
-#endif
-#ifdef LOG_WARNING
-	{syslog_symbol(LOG_WARNING)},
-#endif
-#ifdef LOG_NOTICE
-	{syslog_symbol(LOG_NOTICE)},
-#endif
-#ifdef LOG_INFO
-	{syslog_symbol(LOG_INFO)},
-#endif
-#ifdef LOG_DEBUG
-	{syslog_symbol(LOG_DEBUG)},
-#endif
-	{NULL, 0}
-    };
-    syslog_symbol_t *p;
-
-    for (p = symbols; p->name != NULL; ++p)
-	if (!strcmp(s, p->name) || !strcmp(s, p->name + 4))
-	    return p->value;
-    return 0;
-}
-
-#define PRIORITY_MASK (LOG_ERR | LOG_WARNING | LOG_NOTICE | LOG_INFO | LOG_DEBUG)
-#endif /* HAVE_SYSLOG */
+/* External code */
 
+CBDATA_TYPE(Logfile);
 Logfile *
-logfileOpen(const char *path, size_t bufsz, int fatal_flag)
+logfileOpen(const char *path, const char *type, size_t bufsz, int fatal_flag)
 {
-    Logfile *lf = xcalloc(1, sizeof(*lf));
+    Logfile *lf;
+    CBDATA_INIT_TYPE(Logfile);
+    lf = cbdataAlloc(Logfile);
+    int ret;
+    cbdataLock(lf);
+    debug(50, 1) ("Logfile: opening log %s\n", path);
     xstrncpy(lf->path, path, MAXPATHLEN);
+
+    /* need to call the per-logfile-type code */
+    if (strcmp(type, "stdio") == 0) {
+        ret = logfile_mod_stdio_open(lf, path, bufsz, fatal_flag);
+    } else if (strcmp(type, "daemon") == 0) {
+        ret = logfile_mod_daemon_open(lf, path, bufsz, fatal_flag);
 #if HAVE_SYSLOG
-    if (strcmp(path, "syslog") == 0 || strncmp(path, "syslog:", 7) == 0) {
-	lf->flags.syslog = 1;
-	lf->fd = -1;
-	if (path[6] != '\0') {
-	    const char *priority = path + 7;
-	    char *facility = (char *) strchr(priority, '|');
-	    if (facility) {
-		*facility++ = '\0';
-		lf->syslog_priority |= syslog_ntoa(facility);
-	    }
-	    lf->syslog_priority |= syslog_ntoa(priority);
-	}
-	if ((lf->syslog_priority & PRIORITY_MASK) == 0)
-	    lf->syslog_priority |= LOG_INFO;
-    } else
+    } else if (strcmp(type, "syslog") == 0) {
+        ret = logfile_mod_syslog_open(lf, path, bufsz, fatal_flag);
 #endif
-    {
-	int fd = file_open(path, O_WRONLY | O_CREAT | O_TEXT);
-	if (DISK_ERROR == fd) {
-	    if (ENOENT == errno && fatal_flag) {
-		fatalf("Cannot open '%s' because\n"
-		    "\tthe parent directory does not exist.\n"
-		    "\tPlease create the directory.\n", path);
-	    } else if (EACCES == errno && fatal_flag) {
-		fatalf("Cannot open '%s' for writing.\n"
-		    "\tThe parent directory must be writeable by the\n"
-		    "\tuser '%s', which is the cache_effective_user\n"
-		    "\tset in squid.conf.", path, Config.effectiveUser);
-	    } else {
-		debug(50, 1) ("logfileOpen: %s: %s\n", path, xstrerror());
-		safe_free(lf);
-		return NULL;
-	    }
-	}
-	lf->fd = fd;
-	if (bufsz > 0) {
-	    lf->buf = xmalloc(bufsz);
-	    lf->bufsz = bufsz;
-	}
+    } else {
+	    fatalf("logfileOpen: unknown logtype '%s'\n", type);
+    }
+    if (fatal_flag && ! ret) {
+        fatalf("logfileOpen: type %s path %s: couldn't open!\n", type, path);
     }
+    assert(lf->data != NULL);
+
     if (fatal_flag)
 	lf->flags.fatal = 1;
     return lf;
@@ -169,79 +79,37 @@
 void
 logfileClose(Logfile * lf)
 {
-    logfileFlush(lf);
-    if (lf->fd >= 0)
-	file_close(lf->fd);
-    if (lf->buf)
-	xfree(lf->buf);
-    xfree(lf);
+    debug(50, 1) ("Logfile: closing log %s\n", lf->path);
+    lf->f_flush(lf);
+    lf->f_close(lf);
+    cbdataUnlock(lf);
+    cbdataFree(lf);
 }
 
 void
 logfileRotate(Logfile * lf)
 {
-#ifdef S_ISREG
-    struct stat sb;
-#endif
-    int i;
-    char from[MAXPATHLEN];
-    char to[MAXPATHLEN];
-    assert(lf->path);
-    if (lf->flags.syslog)
-	return;
-#ifdef S_ISREG
-    if (stat(lf->path, &sb) == 0)
-	if (S_ISREG(sb.st_mode) == 0)
-	    return;
-#endif
-    debug(0, 1) ("logfileRotate: %s\n", lf->path);
-    /* Rotate numbers 0 through N up one */
-    for (i = Config.Log.rotateNumber; i > 1;) {
-	i--;
-	snprintf(from, MAXPATHLEN, "%s.%d", lf->path, i - 1);
-	snprintf(to, MAXPATHLEN, "%s.%d", lf->path, i);
-	xrename(from, to);
-    }
-    /* Rotate the current log to .0 */
-    logfileFlush(lf);
-    file_close(lf->fd);		/* always close */
-    if (Config.Log.rotateNumber > 0) {
-	snprintf(to, MAXPATHLEN, "%s.%d", lf->path, 0);
-	xrename(lf->path, to);
-    }
-    /* Reopen the log.  It may have been renamed "manually" */
-    lf->fd = file_open(lf->path, O_WRONLY | O_CREAT | O_TEXT);
-    if (DISK_ERROR == lf->fd && lf->flags.fatal) {
-	debug(50, 1) ("logfileRotate: %s: %s\n", lf->path, xstrerror());
-	fatalf("Cannot open %s: %s", lf->path, xstrerror());
-    }
+    debug(50, 1) ("logfileRotate: %s\n", lf->path);
+    lf->f_rotate(lf);
 }
 
+
 void
-logfileWrite(Logfile * lf, void *buf, size_t len)
+logfileWrite(Logfile * lf, char *buf, size_t len)
 {
-#if HAVE_SYSLOG
-    if (lf->flags.syslog) {
-	syslog(lf->syslog_priority, "%s", (char *) buf);
-	return;
-    }
-#endif
-    if (0 == lf->bufsz) {
-	/* buffering disabled */
-	logfileWriteWrapper(lf, buf, len);
-	return;
-    }
-    if (lf->offset > 0 && lf->offset + len > lf->bufsz)
-	logfileFlush(lf);
-    if (len > lf->bufsz) {
-	/* too big to fit in buffer */
-	logfileWriteWrapper(lf, buf, len);
-	return;
-    }
-    /* buffer it */
-    xmemcpy(lf->buf + lf->offset, buf, len);
-    lf->offset += len;
-    assert(lf->offset <= lf->bufsz);
+    lf->f_linewrite(lf, buf, len);
+}
+
+void
+logfileLineStart(Logfile * lf)
+{
+    lf->f_linestart(lf);
+}
+
+void
+logfileLineEnd(Logfile * lf)
+{
+    lf->f_lineend(lf);
 }
 
 void
@@ -280,25 +148,5 @@
 void
 logfileFlush(Logfile * lf)
 {
-    if (0 == lf->offset)
-	return;
-    logfileWriteWrapper(lf, lf->buf, (size_t) lf->offset);
-    lf->offset = 0;
-}
-
-/*
- * Aborts with fatal message if write() returns something other
- * than its length argument.
- */
-static void
-logfileWriteWrapper(Logfile * lf, const void *buf, size_t len)
-{
-    int s;
-    s = FD_WRITE_METHOD(lf->fd, buf, len);
-    fd_bytes(lf->fd, s, FD_WRITE);
-    if (s == len)
-	return;
-    if (!lf->flags.fatal)
-	return;
-    fatalf("logfileWrite: %s: %s\n", lf->path, xstrerror());
+    lf->f_flush(lf);
 }
Index: squid/src/logfile_mod_daemon.c
diff -u /dev/null squid/src/logfile_mod_daemon.c:1.1.2.3
--- /dev/null		Thu Jan  1 01:00:00 1970
+++ squid/src/logfile_mod_daemon.c	Mon May 14 18:38:31 2007
@@ -0,0 +1,354 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 50    Log file handling
+ * AUTHOR: Duane Wessels
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  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 of the License, 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., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#include "squid.h"
+#include "logfile_mod_daemon.h"
+
+/* How many buffers to keep before we say we've buffered too much */
+#define	LOGFILE_MAXBUFS		128
+
+/* Size of the logfile buffer */
+/* 
+ * For optimal performance this should match LOGFILE_BUFSIZ in logfile-daemon.c
+ */
+#define	LOGFILE_BUFSZ		32768
+
+/* How many seconds between warnings */
+#define	LOGFILE_WARN_TIME	30
+
+static LOGWRITE logfile_mod_daemon_writeline;
+static LOGLINESTART logfile_mod_daemon_linestart;
+static LOGLINEEND logfile_mod_daemon_lineend;
+static LOGROTATE logfile_mod_daemon_rotate;
+static LOGFLUSH logfile_mod_daemon_flush;
+static LOGCLOSE logfile_mod_daemon_close;
+
+static void logfile_mod_daemon_append(Logfile * lf, const char *buf, int len);
+
+struct _l_daemon {
+    int rfd, wfd;
+    char eol;
+    pid_t pid;
+    int flush_pending;
+    dlink_list bufs;
+    int nbufs;
+    int last_warned;
+};
+
+typedef struct _l_daemon l_daemon_t;
+
+/* Internal code */
+static void
+logfileNewBuffer(Logfile * lf)
+{
+    l_daemon_t *ll = (l_daemon_t *) lf->data;
+    logfile_buffer_t *b;
+
+    debug(50, 5) ("logfileNewBuffer: %s: new buffer\n", lf->path);
+
+    b = xcalloc(1, sizeof(logfile_buffer_t));
+    assert(b != NULL);
+    b->buf = xcalloc(1, LOGFILE_BUFSZ);
+    assert(b->buf != NULL);
+    b->size = LOGFILE_BUFSZ;
+    b->written_len = 0;
+    b->len = 0;
+    dlinkAddTail(b, &b->node, &ll->bufs);
+    ll->nbufs++;
+}
+
+static void
+logfileFreeBuffer(Logfile * lf, logfile_buffer_t * b)
+{
+    l_daemon_t *ll = (l_daemon_t *) lf->data;
+    assert(b != NULL);
+    dlinkDelete(&b->node, &ll->bufs);
+    ll->nbufs--;
+    xfree(b->buf);
+    xfree(b);
+}
+
+static void
+logfileHandleWrite(int fd, void *data)
+{
+    Logfile *lf = (Logfile *) data;
+    l_daemon_t *ll = (l_daemon_t *) lf->data;
+    int ret;
+    logfile_buffer_t *b;
+
+    /*
+     * We'll try writing the first entry until its done - if we
+     * get a partial write then we'll re-schedule until its completed.
+     * Its naive but it'll do for now.
+     */
+    b = ll->bufs.head->data;
+    assert(b != NULL);
+    ll->flush_pending = 0;
+
+    ret = FD_WRITE_METHOD(ll->wfd, b->buf + b->written_len, b->len - b->written_len);
+    debug(50, 3) ("logfileHandleWrite: %s: write returned %d\n", lf->path, ret);
+    if (ret < 0) {
+	if (ignoreErrno(errno)) {
+	    /* something temporary */
+	    goto reschedule;
+	}
+	debug(50, 1) ("logfileHandleWrite: %s: error writing (%s)\n", lf->path, xstrerror());
+	/* XXX should handle this better */
+	fatal("I don't handle this error well!");
+    }
+    if (ret == 0) {
+	/* error? */
+	debug(50, 1) ("logfileHandleWrite: %s: wrote 0 bytes?\n", lf->path);
+	/* XXX should handle this better */
+	fatal("I don't handle this error well!");
+    }
+    /* ret > 0, so something was written */
+    b->written_len += ret;
+    assert(b->written_len <= b->len);
+    if (b->written_len == b->len) {
+	/* written the whole buffer! */
+	logfileFreeBuffer(lf, b);
+	b = NULL;
+    }
+    /* Is there more to write? */
+    if (ll->bufs.head == NULL) {
+	goto finish;
+    }
+    /* there is, so schedule more */
+
+  reschedule:
+    commSetSelect(ll->wfd, COMM_SELECT_WRITE, logfileHandleWrite, lf, 0);
+    ll->flush_pending = 1;
+  finish:
+    return;
+}
+
+static void
+logfileQueueWrite(Logfile * lf)
+{
+    l_daemon_t *ll = (l_daemon_t *) lf->data;
+    if (ll->flush_pending || ll->bufs.head == NULL) {
+	return;
+    }
+    ll->flush_pending = 1;
+    if (ll->bufs.head) {
+	logfile_buffer_t *b = ll->bufs.head->data;
+	if (b->len + 2 <= b->size)
+	    logfile_mod_daemon_append(lf, "F\n", 2);
+    }
+    /* Ok, schedule a write-event */
+    commSetSelect(ll->wfd, COMM_SELECT_WRITE, logfileHandleWrite, lf, 0);
+}
+
+static void
+logfile_mod_daemon_append(Logfile * lf, const char *buf, int len)
+{
+    l_daemon_t *ll = (l_daemon_t *) lf->data;
+    logfile_buffer_t *b;
+    int s;
+
+    /* Is there a buffer? If not, create one */
+    if (ll->bufs.head == NULL) {
+	logfileNewBuffer(lf);
+    }
+    debug(50, 3) ("logfile_mod_daemon_append: %s: appending %d bytes\n", lf->path, len);
+    /* Copy what can be copied */
+    while (len > 0) {
+	b = ll->bufs.tail->data;
+	debug(50, 3) ("logfile_mod_daemon_append: current buffer has %d of %d bytes before append\n", b->len, b->size);
+	s = XMIN(len, (b->size - b->len));
+	xmemcpy(b->buf + b->len, buf, s);
+	len = len - s;
+	buf = buf + s;
+	b->len = b->len + s;
+	assert(b->len <= LOGFILE_BUFSZ);
+	assert(len >= 0);
+	if (len > 0) {
+	    logfileNewBuffer(lf);
+	}
+    }
+}
+
+/*
+ * only schedule a flush (write) if one isn't scheduled.
+ */
+static void
+logfileFlushEvent(void *data)
+{
+    Logfile *lf = (Logfile *) data;
+
+    /*
+     * This might work better if we keep track of when we wrote last and only
+     * schedule a write if we haven't done so in the last second or two.
+     */
+    logfileQueueWrite(lf);
+    eventAdd("logfileFlush", logfileFlushEvent, lf, 1.0, 1);
+}
+
+
+/* External code */
+
+int
+logfile_mod_daemon_open(Logfile *lf, const char *path, size_t bufsz, int fatal_flag)
+{
+    const char *args[5];
+    char *tmpbuf;
+    l_daemon_t *ll;
+
+    cbdataLock(lf);
+    debug(50, 1) ("Logfile Daemon: opening log %s\n", path);
+    ll = xcalloc(1, sizeof(*ll));
+    lf->data = ll;
+    ll->eol = 1;
+    {
+	args[0] = "(logfile-daemon)";
+	args[1] = path;
+	args[2] = NULL;
+	ll->pid = ipcCreate(IPC_STREAM, Config.Program.logfile_daemon, args, "logfile-daemon", &ll->rfd, &ll->wfd, NULL);
+	if (ll->pid < 0)
+	    fatal("Couldn't start logfile helper");
+    }
+    ll->nbufs = 0;
+
+    /* Queue the initial control data */
+    tmpbuf = (char *) xmalloc(BUFSIZ);
+    snprintf(tmpbuf, BUFSIZ, "r%d\nb%d\n", Config.Log.rotateNumber, Config.onoff.buffered_logs);
+    logfile_mod_daemon_append(lf, tmpbuf, strlen(tmpbuf));
+    xfree(tmpbuf);
+
+    /* Start the flush event */
+    eventAdd("logfileFlush", logfileFlushEvent, lf, 1.0, 1);
+
+    lf->f_close = logfile_mod_daemon_close;
+    lf->f_linewrite = logfile_mod_daemon_writeline;
+    lf->f_linestart = logfile_mod_daemon_linestart;
+    lf->f_lineend = logfile_mod_daemon_lineend;
+    lf->f_flush = logfile_mod_daemon_flush;
+    lf->f_rotate = logfile_mod_daemon_rotate;
+
+    return 1;
+}
+
+static void
+logfile_mod_daemon_close(Logfile * lf)
+{
+    l_daemon_t *ll = (l_daemon_t *) lf->data;
+    debug(50, 1) ("Logfile Daemon: closing log %s\n", lf->path);
+    logfileFlush(lf);
+    fd_close(ll->rfd);
+    fd_close(ll->wfd);
+    kill(ll->pid, SIGTERM);
+    eventDelete(logfileFlushEvent, lf);
+    xfree(ll);
+    lf->data = NULL;
+    cbdataUnlock(lf);
+}
+
+static void
+logfile_mod_daemon_rotate(Logfile * lf)
+{
+    char tb[3];
+    debug(50, 1) ("logfileRotate: %s\n", lf->path);
+    tb[0] = 'R';
+    tb[1] = '\n';
+    tb[2] = '\0';
+    logfile_mod_daemon_append(lf, tb, 2);
+}
+
+/*
+ * This routine assumes that up to one line is written. Don't try to
+ * call this routine with more than one line or subsequent lines
+ * won't be prefixed with the command type and confuse the logging
+ * daemon somewhat.
+ */
+static void
+logfile_mod_daemon_writeline(Logfile * lf, const char *buf, size_t len)
+{
+    l_daemon_t *ll = (l_daemon_t *) lf->data;
+    /* Make sure the logfile buffer isn't too large */
+    if (ll->nbufs > LOGFILE_MAXBUFS) {
+	if (ll->last_warned < squid_curtime - LOGFILE_WARN_TIME) {
+	    ll->last_warned = squid_curtime;
+	    debug(50, 1) ("Logfile: %s: queue is too large; some log messages have been lost.\n", lf->path);
+	}
+	return;
+    }
+    /* Append this data to the end buffer; create a new one if needed */
+    /* Are we eol? If so, prefix with our logfile command byte */
+    logfile_mod_daemon_append(lf, buf, len);
+}
+
+static void
+logfile_mod_daemon_linestart(Logfile * lf)
+{
+    l_daemon_t *ll = (l_daemon_t *) lf->data;
+    char tb[2];
+    assert(ll->eol == 1);
+    ll->eol = 0;
+    tb[0] = 'L';
+    tb[1] = '\0';
+    logfile_mod_daemon_append(lf, tb, 1);
+}
+
+static void
+logfile_mod_daemon_lineend(Logfile * lf)
+{
+    l_daemon_t *ll = (l_daemon_t *) lf->data;
+    logfile_buffer_t *b;
+    assert(ll->eol == 0);
+    ll->eol = 1;
+    /* Kick a write off if the head buffer is -full- */
+    if (ll->bufs.head != NULL) {
+	b = ll->bufs.head->data;
+	if (b->node.next != NULL || !Config.onoff.buffered_logs)
+	    logfileQueueWrite(lf);
+    }
+}
+
+static void
+logfile_mod_daemon_flush(Logfile * lf)
+{
+    l_daemon_t *ll = (l_daemon_t *) lf->data;
+    if (commUnsetNonBlocking(ll->wfd)) {
+	debug(50, 1) ("Logfile Daemon: Couldn't set the pipe blocking for flush! You're now missing some log entries.\n");
+	return;
+    }
+    while (ll->bufs.head != NULL) {
+	logfileHandleWrite(ll->wfd, lf);
+    }
+    if (commSetNonBlocking(ll->wfd)) {
+	fatalf("Logfile Daemon: %s: Couldn't set the pipe non-blocking for flush!\n", lf->path);
+	return;
+    }
+}
Index: squid/src/logfile_mod_daemon.h
diff -u /dev/null squid/src/logfile_mod_daemon.h:1.1.2.1
--- /dev/null		Thu Jan  1 01:00:00 1970
+++ squid/src/logfile_mod_daemon.h	Mon May 14 18:38:31 2007
@@ -0,0 +1,35 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 50    Log file handling
+ * AUTHOR: Duane Wessels
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  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 of the License, 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., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+extern int logfile_mod_daemon_open(Logfile *lf, const char *path, size_t bufsz, int fatal_flag);
Index: squid/src/logfile_mod_stdio.c
diff -u /dev/null squid/src/logfile_mod_stdio.c:1.1.2.4
--- /dev/null		Thu Jan  1 01:00:00 1970
+++ squid/src/logfile_mod_stdio.c	Mon May 14 18:38:31 2007
@@ -0,0 +1,230 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 50    Log file handling
+ * AUTHOR: Duane Wessels
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  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 of the License, 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., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#include "squid.h"
+#include "logfile_mod_stdio.h"
+
+typedef struct {
+	int fd;
+	char *buf;
+	int bufsz;
+	int offset;
+} l_stdio_t;
+
+/*
+ * Aborts with fatal message if write() returns something other
+ * than its length argument.
+ */
+static void
+logfileWriteWrapper(Logfile * lf, const void *buf, size_t len)
+{
+    l_stdio_t *ll = (l_stdio_t *) lf->data;
+    size_t s;
+    s = FD_WRITE_METHOD(ll->fd, (char const *)buf, len);
+    fd_bytes(ll->fd, s, FD_WRITE);
+
+    if (s == len)
+        return;
+
+    if (!lf->flags.fatal)
+        return;
+
+    fatalf("logfileWrite (stdio): %s: %s\n", lf->path, xstrerror());
+}
+
+static void
+logfile_mod_stdio_writeline(Logfile * lf, const char *buf, size_t len)
+{
+    l_stdio_t *ll = (l_stdio_t *) lf->data;
+
+    if (0 == ll->bufsz) {
+        /* buffering disabled */
+        logfileWriteWrapper(lf, buf, len);
+        return;
+    }
+
+    if (ll->offset > 0 && ll->offset + len > ll->bufsz)
+        logfileFlush(lf);
+
+    if (len > ll->bufsz) {
+        /* too big to fit in buffer */
+        logfileWriteWrapper(lf, buf, len);
+        return;
+    }
+
+    /* buffer it */
+    xmemcpy(ll->buf + ll->offset, buf, len);
+
+    ll->offset += len;
+
+    assert (ll->offset >= 0);
+
+    assert((size_t)ll->offset <= ll->bufsz);
+}
+
+static void
+logfile_mod_stdio_linestart(Logfile *lf)
+{
+}
+
+static void
+logfile_mod_stdio_lineend(Logfile *lf)
+{
+	lf->f_flush(lf);
+}
+
+static void
+logfile_mod_stdio_flush(Logfile *lf)
+{
+    l_stdio_t *ll = (l_stdio_t *) lf->data;
+    if (0 == ll->offset)
+        return;
+    logfileWriteWrapper(lf, ll->buf, (size_t) ll->offset);
+    ll->offset = 0;
+}
+
+static void
+logfile_mod_stdio_rotate(Logfile *lf)
+{
+#ifdef S_ISREG
+
+    struct stat sb;
+#endif
+
+    int i;
+    char from[MAXPATHLEN];
+    char to[MAXPATHLEN];
+    l_stdio_t *ll = (l_stdio_t *) lf->data;
+    assert(lf->path);
+
+#ifdef S_ISREG
+
+    if (stat(lf->path, &sb) == 0)
+        if (S_ISREG(sb.st_mode) == 0)
+            return;
+
+#endif
+
+    debug(0, 1) ("logfileRotate (stdio): %s\n", lf->path);
+
+    /* Rotate numbers 0 through N up one */
+    for (i = Config.Log.rotateNumber; i > 1;) {
+        i--;
+        snprintf(from, MAXPATHLEN, "%s.%d", lf->path, i - 1);
+        snprintf(to, MAXPATHLEN, "%s.%d", lf->path, i);
+        xrename(from, to);
+    }
+
+    /* Rotate the current log to .0 */
+    logfileFlush(lf);
+
+    file_close(ll->fd);         /* always close */
+
+    if (Config.Log.rotateNumber > 0) {
+        snprintf(to, MAXPATHLEN, "%s.%d", lf->path, 0);
+        xrename(lf->path, to);
+    }
+
+    /* Reopen the log.  It may have been renamed "manually" */
+    ll->fd = file_open(lf->path, O_WRONLY | O_CREAT | O_TEXT);
+
+    if (DISK_ERROR == ll->fd && lf->flags.fatal) {
+        debug(50, 1) ("logfileRotate (stdio): %s: %s\n", lf->path, xstrerror());
+        fatalf("Cannot open %s: %s", lf->path, xstrerror());
+    }
+
+}
+
+static void
+logfile_mod_stdio_close(Logfile *lf)
+{
+    l_stdio_t *ll = (l_stdio_t *) lf->data;
+    lf->f_flush(lf);
+
+    if (ll->fd >= 0)
+        file_close(ll->fd);
+
+    if (ll->buf)
+        xfree(ll->buf);
+
+    xfree(lf->data);
+    lf->data = NULL;
+}
+
+
+
+/*
+ * This code expects the path to be syslog:<priority>
+ */
+int
+logfile_mod_stdio_open(Logfile *lf, const char *path, size_t bufsz, int fatal_flag)
+{
+    l_stdio_t *ll;
+
+    ll = xcalloc(1, sizeof(*ll));
+    lf->data = ll;
+
+    ll->fd = file_open(path, O_WRONLY | O_CREAT | O_TEXT);
+
+    if (DISK_ERROR == ll->fd) {
+        if (ENOENT == errno && fatal_flag) {
+            fatalf("Cannot open '%s' because\n"
+                   "\tthe parent directory does not exist.\n"
+                   "\tPlease create the directory.\n", path);
+        } else if (EACCES == errno && fatal_flag) {
+            fatalf("Cannot open '%s' for writing.\n"
+                   "\tThe parent directory must be writeable by the\n"
+                   "\tuser '%s', which is the cache_effective_user\n"
+                   "\tset in squid.conf.", path, Config.effectiveUser);
+        } else {
+            debug(50, 1) ("logfileOpen (stdio): %s: %s\n", path, xstrerror());
+            return 0;
+        }
+    }
+
+    if (bufsz > 0) {
+       ll->buf = (char *) xmalloc(bufsz);
+        ll->bufsz = bufsz;
+    }
+
+    lf->f_close = logfile_mod_stdio_close;
+    lf->f_linewrite = logfile_mod_stdio_writeline;
+    lf->f_linestart = logfile_mod_stdio_linestart;
+    lf->f_lineend = logfile_mod_stdio_lineend;
+    lf->f_flush = logfile_mod_stdio_flush;
+    lf->f_rotate = logfile_mod_stdio_rotate;
+
+    return 1;
+}
+
Index: squid/src/logfile_mod_stdio.h
diff -u /dev/null squid/src/logfile_mod_stdio.h:1.1.2.1
--- /dev/null		Thu Jan  1 01:00:00 1970
+++ squid/src/logfile_mod_stdio.h	Mon May 14 18:38:31 2007
@@ -0,0 +1,35 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 50    Log file handling
+ * AUTHOR: Duane Wessels
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  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 of the License, 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., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+extern int logfile_mod_stdio_open(Logfile *lf, const char *path, size_t bufsz, int fatal_flag);
Index: squid/src/logfile_mod_syslog.c
diff -u /dev/null squid/src/logfile_mod_syslog.c:1.1.2.5
--- /dev/null		Thu Jan  1 01:00:00 1970
+++ squid/src/logfile_mod_syslog.c	Fri May 18 12:13:12 2007
@@ -0,0 +1,187 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 50    Log file handling
+ * AUTHOR: Duane Wessels
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  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 of the License, 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., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#include "squid.h"
+#if HAVE_SYSLOG
+#include "logfile_mod_syslog.h"
+
+/* Define LOG_AUTHPRIV as LOG_AUTH on systems still using the old deprecated LOG_AUTH */
+#if !defined(LOG_AUTHPRIV) && defined(LOG_AUTH)
+#define LOG_AUTHPRIV LOG_AUTH
+#endif
+
+typedef struct {
+    const char *name;
+    int value;
+} syslog_symbol_t;
+
+static int
+syslog_ntoa(const char *s)
+{
+#define syslog_symbol(a) #a, a
+    static syslog_symbol_t symbols[] =
+    {
+#ifdef LOG_AUTHPRIV
+	{syslog_symbol(LOG_AUTHPRIV)},
+#endif
+#ifdef LOG_DAEMON
+	{syslog_symbol(LOG_DAEMON)},
+#endif
+#ifdef LOG_LOCAL0
+	{syslog_symbol(LOG_LOCAL0)},
+#endif
+#ifdef LOG_LOCAL1
+	{syslog_symbol(LOG_LOCAL1)},
+#endif
+#ifdef LOG_LOCAL2
+	{syslog_symbol(LOG_LOCAL2)},
+#endif
+#ifdef LOG_LOCAL3
+	{syslog_symbol(LOG_LOCAL3)},
+#endif
+#ifdef LOG_LOCAL4
+	{syslog_symbol(LOG_LOCAL4)},
+#endif
+#ifdef LOG_LOCAL5
+	{syslog_symbol(LOG_LOCAL5)},
+#endif
+#ifdef LOG_LOCAL6
+	{syslog_symbol(LOG_LOCAL6)},
+#endif
+#ifdef LOG_LOCAL7
+	{syslog_symbol(LOG_LOCAL7)},
+#endif
+#ifdef LOG_USER
+	{syslog_symbol(LOG_USER)},
+#endif
+#ifdef LOG_ERR
+	{syslog_symbol(LOG_ERR)},
+#endif
+#ifdef LOG_WARNING
+	{syslog_symbol(LOG_WARNING)},
+#endif
+#ifdef LOG_NOTICE
+	{syslog_symbol(LOG_NOTICE)},
+#endif
+#ifdef LOG_INFO
+	{syslog_symbol(LOG_INFO)},
+#endif
+#ifdef LOG_DEBUG
+	{syslog_symbol(LOG_DEBUG)},
+#endif
+	{NULL, 0}
+    };
+    syslog_symbol_t *p;
+
+    for (p = symbols; p->name != NULL; ++p)
+	if (!strcmp(s, p->name) || !strcmp(s, p->name + 4))
+	    return p->value;
+    return 0;
+}
+
+typedef struct {
+	int syslog_priority;
+} l_syslog_t;
+
+#define PRIORITY_MASK (LOG_ERR | LOG_WARNING | LOG_NOTICE | LOG_INFO | LOG_DEBUG)
+
+static void
+logfile_mod_syslog_writeline(Logfile * lf, const char *buf, size_t len)
+{
+    l_syslog_t *ll = (l_syslog_t *) lf->data;
+    syslog(ll->syslog_priority, "%s", (char *) buf);
+}
+
+static void
+logfile_mod_syslog_linestart(Logfile *lf)
+{
+}
+
+static void
+logfile_mod_syslog_lineend(Logfile *lf)
+{
+}
+
+static void
+logfile_mod_syslog_flush(Logfile *lf)
+{
+}
+
+static void
+logfile_mod_syslog_rotate(Logfile *lf)
+{
+}
+
+static void
+logfile_mod_syslog_close(Logfile *lf)
+{
+	xfree(lf->data);
+	lf->data = NULL;
+}
+
+
+
+/*
+ * This code expects the path to be syslog:<priority>
+ */
+int
+logfile_mod_syslog_open(Logfile *lf, const char *path, size_t bufsz, int fatal_flag)
+{
+	l_syslog_t *ll;
+
+	ll = xcalloc(1, sizeof(*ll));
+	lf->data = ll;
+
+	if (path[6] != '\0') {
+	    const char *priority = path + 7;
+	    char *facility = (char *) strchr(priority, '|');
+	    if (facility) {
+		*facility++ = '\0';
+		ll->syslog_priority |= syslog_ntoa(facility);
+	    }
+	    ll->syslog_priority |= syslog_ntoa(priority);
+	}
+	if ((ll->syslog_priority & PRIORITY_MASK) == 0)
+	    ll->syslog_priority |= LOG_INFO;
+
+    lf->f_close = logfile_mod_syslog_close;
+    lf->f_linewrite = logfile_mod_syslog_writeline;
+    lf->f_linestart = logfile_mod_syslog_linestart;
+    lf->f_lineend = logfile_mod_syslog_lineend;
+    lf->f_flush = logfile_mod_syslog_flush;
+    lf->f_rotate = logfile_mod_syslog_rotate;
+
+    return 1;
+}
+#endif
Index: squid/src/logfile_mod_syslog.h
diff -u /dev/null squid/src/logfile_mod_syslog.h:1.1.2.1
--- /dev/null		Thu Jan  1 01:00:00 1970
+++ squid/src/logfile_mod_syslog.h	Mon May 14 18:38:31 2007
@@ -0,0 +1,35 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 50    Log file handling
+ * AUTHOR: Duane Wessels
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  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 of the License, 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., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+extern int logfile_mod_syslog_open(Logfile *lf, const char *path, size_t bufsz, int fatal_flag);
Index: squid/src/net_db.c
diff -u squid/src/net_db.c:1.24 squid/src/net_db.c:1.22.10.2
--- squid/src/net_db.c:1.24	Mon Feb 26 01:51:32 2007
+++ squid/src/net_db.c	Fri May 18 12:15:28 2007
@@ -387,7 +387,7 @@
      * logfileOpen() use O_TRUNC.
      */
     unlink(path);
-    lf = logfileOpen(path, 4096, 0);
+    lf = logfileOpen(path, Config.Log.logtype, 4096, 0);
     if (NULL == lf) {
 	debug(50, 1) ("netdbSaveState: %s: %s\n", path, xstrerror());
 	return;
Index: squid/src/protos.h
diff -u squid/src/protos.h:1.142 squid/src/protos.h:1.118.2.10
--- squid/src/protos.h:1.142	Sat Jul 14 22:51:51 2007
+++ squid/src/protos.h	Sat Aug 11 18:12:40 2007
@@ -1334,11 +1334,13 @@
 #endif
 
 /* logfile.c */
-extern Logfile *logfileOpen(const char *path, size_t bufsz, int);
+extern Logfile *logfileOpen(const char *path, const char *type, size_t bufsz, int);
 extern void logfileClose(Logfile * lf);
 extern void logfileRotate(Logfile * lf);
-extern void logfileWrite(Logfile * lf, void *buf, size_t len);
+extern void logfileWrite(Logfile * lf, char *buf, size_t len);
 extern void logfileFlush(Logfile * lf);
+extern void logfileLineStart(Logfile * lf);
+extern void logfileLineEnd(Logfile * lf);
 #if STDC_HEADERS
 extern void
 logfilePrintf(Logfile * lf, const char *fmt,...) PRINTF_FORMAT_ARG2;
Index: squid/src/referer.c
diff -u squid/src/referer.c:1.5 squid/src/referer.c:1.5.34.1
--- squid/src/referer.c:1.5	Sun Oct 13 14:46:16 2002
+++ squid/src/referer.c	Fri May 18 12:15:28 2007
@@ -49,7 +49,7 @@
 	debug(40, 1) ("Referer logging is disabled.\n");
 	return;
     }
-    refererlog = logfileOpen(Config.Log.referer, 0, 1);
+    refererlog = logfileOpen(Config.Log.referer, Config.Log.logtype, 0, 1);
 #endif
 }
 
Index: squid/src/store_log.c
diff -u squid/src/store_log.c:1.11 squid/src/store_log.c:1.8.32.3
--- squid/src/store_log.c:1.11	Sun Jan 21 06:04:11 2007
+++ squid/src/store_log.c	Sun Mar 11 15:02:49 2007
@@ -64,6 +64,7 @@
 	 * Because if we print it before the swap file number, it'll break
 	 * the existing log format.
 	 */
+	logfileLineStart(storelog);
 	logfilePrintf(storelog, "%9ld.%03d %-7s %02d %08X %s %4d %9ld %9ld %9ld %s %" PRINTF_OFF_T "/%" PRINTF_OFF_T " %s %s\n",
 	    (long int) current_time.tv_sec,
 	    (int) current_time.tv_usec / 1000,
@@ -80,8 +81,10 @@
 	    mem->inmem_hi - mem->reply->hdr_sz,
 	    RequestMethods[mem->method].str,
 	    rfc1738_escape_unescaped(mem->url));
+	logfileLineEnd(storelog);
     } else {
 	/* no mem object. Most RELEASE cases */
+	logfileLineStart(storelog);
 	logfilePrintf(storelog, "%9ld.%03d %-7s %02d %08X %s   ?         ?         ?         ? ?/? ?/? ? ?\n",
 	    (long int) current_time.tv_sec,
 	    (int) current_time.tv_usec / 1000,
@@ -89,6 +92,7 @@
 	    e->swap_dirn,
 	    e->swap_filen,
 	    storeKeyText(e->hash.key));
+	logfileLineEnd(storelog);
     }
 }
 
@@ -116,5 +120,5 @@
 	debug(20, 1) ("Store logging disabled\n");
 	return;
     }
-    storelog = logfileOpen(Config.Log.store, 0, 1);
+    storelog = logfileOpen(Config.Log.store, Config.Log.logtype, 0, 1);
 }
Index: squid/src/structs.h
diff -u squid/src/structs.h:1.150 squid/src/structs.h:1.126.2.13
--- squid/src/structs.h:1.150	Fri Jul 20 14:52:59 2007
+++ squid/src/structs.h	Sat Aug 11 18:12:40 2007
@@ -527,6 +527,7 @@
 #endif
 	logformat *logformats;
 	customlog *accesslogs;
+	char *logtype;
 	int rotateNumber;
     } Log;
     char *adminEmail;
@@ -559,6 +560,7 @@
 #if USE_SSL
 	char *ssl_password;
 #endif
+	char *logfile_daemon;
     } Program;
 #if USE_DNSSERVERS
     int dnsChildren;
@@ -2450,17 +2452,28 @@
     } shm;
 };
 
+struct _logfile_buffer {
+    char *buf;
+    int size;
+    int len;
+    int written_len;
+    dlink_node node;
+};
+
 struct _Logfile {
-    int fd;
     char path[MAXPATHLEN];
-    char *buf;
-    size_t bufsz;
-    ssize_t offset;
     struct {
 	unsigned int fatal;
-	unsigned int syslog;
     } flags;
-    int syslog_priority;
+
+    void *data;
+
+    LOGLINESTART * f_linestart;
+    LOGWRITE * f_linewrite;
+    LOGLINEEND * f_lineend;
+    LOGFLUSH * f_flush;
+    LOGROTATE * f_rotate;
+    LOGCLOSE * f_close;
 };
 
 struct _logformat {
Index: squid/src/typedefs.h
diff -u squid/src/typedefs.h:1.42 squid/src/typedefs.h:1.39.2.3
--- squid/src/typedefs.h:1.42	Sun Jan 21 06:04:14 2007
+++ squid/src/typedefs.h	Sun Mar 11 15:02:50 2007
@@ -213,6 +213,7 @@
 typedef struct _storefs_entry storefs_entry_t;
 typedef struct _storerepl_entry storerepl_entry_t;
 typedef struct _diskd_queue diskd_queue;
+typedef struct _logfile_buffer logfile_buffer_t;
 typedef struct _Logfile Logfile;
 typedef struct _logformat_token logformat_token;
 typedef struct _logformat logformat;
@@ -409,4 +410,11 @@
 
 typedef struct rms rms_t;
 
+typedef void LOGLINESTART(Logfile *);
+typedef void LOGWRITE(Logfile *, const char *, size_t len);
+typedef void LOGLINEEND(Logfile *);
+typedef void LOGFLUSH(Logfile *);
+typedef void LOGROTATE(Logfile *);
+typedef void LOGCLOSE(Logfile *);
+
 #endif /* SQUID_TYPEDEFS_H */
Index: squid/src/useragent.c
diff -u squid/src/useragent.c:1.7 squid/src/useragent.c:1.7.128.1
--- squid/src/useragent.c:1.7	Mon Jul 16 23:57:31 2001
+++ squid/src/useragent.c	Fri May 18 12:15:28 2007
@@ -48,7 +48,7 @@
 	debug(40, 1) ("User-Agent logging is disabled.\n");
 	return;
     }
-    useragentlog = logfileOpen(Config.Log.useragent, 0, 1);
+    useragentlog = logfileOpen(Config.Log.useragent, Config.Log.logtype, 0, 1);
 #endif
 }