diff options
Diffstat (limited to 'www/squid25/files/customlog-2.5.patch')
-rw-r--r-- | www/squid25/files/customlog-2.5.patch | 1597 |
1 files changed, 0 insertions, 1597 deletions
diff --git a/www/squid25/files/customlog-2.5.patch b/www/squid25/files/customlog-2.5.patch deleted file mode 100644 index 3e8c2a542204..000000000000 --- a/www/squid25/files/customlog-2.5.patch +++ /dev/null @@ -1,1597 +0,0 @@ -! This patch is sourced from http://devel.squid-cache.org/customlog/ -! Modified diff paths to apply cleanly - -Index: src/access_log.c -diff -u src/access_log.c:1.15.6.8 src/access_log.c:1.15.6.3.2.15 ---- src/access_log.c:1.15.6.8 Tue Mar 29 18:17:46 2005 -+++ src/access_log.c Mon May 15 03:58:22 2006 -@@ -36,9 +36,6 @@ - - #include "squid.h" - --static void accessLogSquid(AccessLogEntry * al); --static void accessLogCommon(AccessLogEntry * al); --static Logfile *logfile = NULL; - #if HEADERS_LOG - static Logfile *headerslog = NULL; - #endif -@@ -234,8 +231,768 @@ - return username_quote(name); - } - -+static char * -+log_quoted_string(const char *str) -+{ -+ char *out = xmalloc(strlen(str) * 2 + 1); -+ char *p = out; -+ while (*str) { -+ int l = strcspn(str, "\"\\\r\n\t"); -+ memcpy(p, str, l); -+ str += l; -+ p += l; -+ switch (*str) { -+ case '\0': -+ break; -+ case '\r': -+ *p++ = '\\'; -+ *p++ = 'r'; -+ str++; -+ break; -+ case '\n': -+ *p++ = '\\'; -+ *p++ = 'n'; -+ str++; -+ break; -+ case '\t': -+ *p++ = '\\'; -+ *p++ = 't'; -+ str++; -+ break; -+ default: -+ *p++ = '\\'; -+ *p++ = *str; -+ str++; -+ break; -+ } -+ } -+ *p++ = '\0'; -+ return out; -+} -+ -+/* -+ * Bytecodes for the configureable logformat stuff -+ */ -+typedef enum { -+ LFT_NONE, /* dummy */ -+ LFT_STRING, -+ -+ LFT_CLIENT_IP_ADDRESS, -+ LFT_CLIENT_FQDN, -+/*LFT_CLIENT_PORT, */ -+ -+/*LFT_SERVER_IP_ADDRESS, */ -+ LFT_SERVER_IP_OR_PEER_NAME, -+/*LFT_SERVER_PORT, */ -+ -+ LFT_LOCAL_IP, -+ LFT_LOCAL_PORT, -+/*LFT_LOCAL_NAME, */ -+ -+ LFT_TIME_SECONDS_SINCE_EPOCH, -+ LFT_TIME_SUBSECOND, -+ LFT_TIME_LOCALTIME, -+ LFT_TIME_GMT, -+ LFT_TIME_TO_HANDLE_REQUEST, -+ -+ LFT_REQUEST_HEADER, -+ LFT_REQUEST_HEADER_ELEM, -+ LFT_REQUEST_ALL_HEADERS, -+ -+ LFT_REPLY_HEADER, -+ LFT_REPLY_HEADER_ELEM, -+ LFT_REPLY_ALL_HEADERS, -+ -+ LFT_USER_NAME, -+ LFT_USER_LOGIN, -+ LFT_USER_IDENT, -+/*LFT_USER_REALM, */ -+/*LFT_USER_SCHEME, */ -+ -+ LFT_HTTP_CODE, -+/*LFT_HTTP_STATUS, */ -+ -+ LFT_SQUID_STATUS, -+/*LFT_SQUID_ERROR, */ -+ LFT_SQUID_HIERARCHY, -+ -+ LFT_MIME_TYPE, -+ -+ LFT_REQUEST_METHOD, -+ LFT_REQUEST_URI, -+/*LFT_REQUEST_QUERY, * // * this is not needed. see strip_query_terms */ -+ LFT_REQUEST_VERSION, -+ -+/*LFT_REQUEST_SIZE_TOTAL, */ -+/*LFT_REQUEST_SIZE_LINE, */ -+/*LFT_REQUEST_SIZE_HEADERS, */ -+/*LFT_REQUEST_SIZE_BODY, */ -+/*LFT_REQUEST_SIZE_BODY_NO_TE, */ -+ -+ LFT_REPLY_SIZE_TOTAL, -+/*LFT_REPLY_SIZE_LINE, */ -+/*LFT_REPLY_SIZE_HEADERS, */ -+/*LFT_REPLY_SIZE_BODY, */ -+/*LFT_REPLY_SIZE_BODY_NO_TE, */ -+ -+#ifdef HAVE_EXTACL_LOG -+ LFT_EXT_LOG, -+#endif -+ -+ LFT_PERCENT /* special string cases for escaped chars */ -+} logformat_bcode_t; -+ -+enum log_quote { -+ LOG_QUOTE_NONE = 0, -+ LOG_QUOTE_QUOTES, -+ LOG_QUOTE_BRAKETS, -+ LOG_QUOTE_URL, -+ LOG_QUOTE_RAW -+}; -+struct _logformat_token { -+ logformat_bcode_t type; -+ union { -+ char *string; -+ struct { -+ char *header; -+ char *element; -+ char separator; -+ } header; -+ char *timespec; -+ } data; -+ unsigned char width; -+ unsigned char precision; -+ enum log_quote quote:3; -+ unsigned int left:1; -+ unsigned int space:1; -+ unsigned int zero:1; -+ int divisor; -+ logformat_token *next; /* todo: move from linked list to array */ -+}; -+ -+struct logformat_token_table_entry { -+ const char *config; -+ logformat_bcode_t token_type; -+ int options; -+}; -+ -+struct logformat_token_table_entry logformat_token_table[] = -+{ -+ -+ {">a", LFT_CLIENT_IP_ADDRESS}, -+/*{ ">p", LFT_CLIENT_PORT}, */ -+ {">A", LFT_CLIENT_FQDN}, -+ -+/*{ "<a", LFT_SERVER_IP_ADDRESS }, */ -+/*{ "<p", LFT_SERVER_PORT }, */ -+ {"<A", LFT_SERVER_IP_OR_PEER_NAME}, -+ -+ {"la", LFT_LOCAL_IP}, -+ {"lp", LFT_LOCAL_PORT}, -+/*{ "lA", LFT_LOCAL_NAME }, */ -+ -+ {"ts", LFT_TIME_SECONDS_SINCE_EPOCH}, -+ {"tu", LFT_TIME_SUBSECOND}, -+ {"tl", LFT_TIME_LOCALTIME}, -+ {"tg", LFT_TIME_GMT}, -+ {"tr", LFT_TIME_TO_HANDLE_REQUEST}, -+ -+ {">h", LFT_REQUEST_HEADER}, -+ {"<h", LFT_REPLY_HEADER}, -+ -+ {"un", LFT_USER_NAME}, -+ {"ul", LFT_USER_LOGIN}, -+/*{ "ur", LFT_USER_REALM }, */ -+/*{ "us", LFT_USER_SCHEME }, */ -+ {"ui", LFT_USER_IDENT}, -+ -+ {"Hs", LFT_HTTP_CODE}, -+/*{ "Ht", LFT_HTTP_STATUS }, */ -+ -+ {"Ss", LFT_SQUID_STATUS}, -+/*{ "Se", LFT_SQUID_ERROR }, */ -+ {"Sh", LFT_SQUID_HIERARCHY}, -+ -+ {"mt", LFT_MIME_TYPE}, -+ -+ {"rm", LFT_REQUEST_METHOD}, -+ {"ru", LFT_REQUEST_URI}, /* doesn't include the query-string */ -+/* { "rq", LFT_REQUEST_QUERY }, * / / * the query-string, INCLUDING the leading ? */ -+ {">v", LFT_REQUEST_VERSION}, -+ {"rv", LFT_REQUEST_VERSION}, -+ -+/*{ ">st", LFT_REQUEST_SIZE_TOTAL }, */ -+/*{ ">sl", LFT_REQUEST_SIZE_LINE }, * / / * the request line "GET ... " */ -+/*{ ">sh", LFT_REQUEST_SIZE_HEADERS }, */ -+/*{ ">sb", LFT_REQUEST_SIZE_BODY }, */ -+/*{ ">sB", LFT_REQUEST_SIZE_BODY_NO_TE }, */ -+ -+ {"<st", LFT_REPLY_SIZE_TOTAL}, -+/*{ "<sl", LFT_REPLY_SIZE_LINE }, * / / * the reply line (protocol, code, text) */ -+/*{ "<sh", LFT_REPLY_SIZE_HEADERS }, */ -+/*{ "<sb", LFT_REPLY_SIZE_BODY }, */ -+/*{ "<sB", LFT_REPLY_SIZE_BODY_NO_TE }, */ -+ -+#ifdef HAVE_EXTACL_LOG -+ {"ea", LFT_EXT_LOG}, -+#endif -+ -+ {"%", LFT_PERCENT}, -+ -+ {NULL, LFT_NONE} /* this must be last */ -+}; -+ -+static void -+accessLogCustom(AccessLogEntry * al, customlog * log) -+{ -+ logformat *lf; -+ Logfile *logfile; -+ logformat_token *fmt; -+ static MemBuf mb = MemBufNULL; -+ char tmp[1024]; -+ String sb = StringNull; -+ -+ memBufReset(&mb); -+ -+ lf = log->logFormat; -+ logfile = log->logfile; -+ for (fmt = lf->format; fmt != NULL; fmt = fmt->next) { /* for each token */ -+ const char *out = NULL; -+ int quote = 0; -+ long int outint = 0; -+ int doint = 0; -+ int dofree = 0; -+ switch (fmt->type) { -+ case LFT_NONE: -+ out = ""; -+ break; -+ case LFT_STRING: -+ out = fmt->data.string; -+ break; -+ case LFT_CLIENT_IP_ADDRESS: -+ out = inet_ntoa(al->cache.caddr); -+ break; -+ -+ case LFT_CLIENT_FQDN: -+ out = fqdncache_gethostbyaddr(al->cache.caddr, FQDN_LOOKUP_IF_MISS); -+ if (!out) -+ out = inet_ntoa(al->cache.caddr); -+ break; -+ -+ /* case LFT_CLIENT_PORT: */ -+ -+ /* case LFT_SERVER_IP_ADDRESS: */ -+ -+ case LFT_SERVER_IP_OR_PEER_NAME: -+ out = al->hier.host; -+ break; -+ -+ /* case LFT_SERVER_PORT: */ -+ -+ case LFT_LOCAL_IP: -+ if (al->request) -+ out = inet_ntoa(al->request->my_addr); -+ break; -+ -+ case LFT_LOCAL_PORT: -+ if (al->request) { -+ outint = al->request->my_port; -+ doint = 1; -+ } -+ break; -+ -+ case LFT_TIME_SECONDS_SINCE_EPOCH: -+ outint = current_time.tv_sec; -+ doint = 1; -+ break; -+ -+ case LFT_TIME_SUBSECOND: -+ outint = current_time.tv_usec / fmt->divisor; -+ doint = 1; -+ break; -+ -+ -+ case LFT_TIME_LOCALTIME: -+ case LFT_TIME_GMT: -+ { -+ const char *spec; -+ struct tm *t; -+ spec = fmt->data.timespec; -+ if (!spec) -+ spec = "%d/%b/%Y:%H:%M:%S %z"; -+ if (fmt->type == LFT_TIME_LOCALTIME) -+ t = localtime(&squid_curtime); -+ else -+ t = gmtime(&squid_curtime); -+ strftime(tmp, sizeof(tmp), spec, t); -+ out = tmp; -+ } -+ break; -+ -+ case LFT_TIME_TO_HANDLE_REQUEST: -+ outint = al->cache.msec; -+ doint = 1; -+ break; -+ -+ case LFT_REQUEST_HEADER: -+ if (al->request) -+ sb = httpHeaderGetByName(&al->request->header, fmt->data.header.header); -+ out = strBuf(sb); -+ quote = 1; -+ break; -+ -+ case LFT_REPLY_HEADER: -+ if (al->reply) -+ sb = httpHeaderGetByName(&al->reply->header, fmt->data.header.header); -+ out = strBuf(sb); -+ quote = 1; -+ break; -+ -+ case LFT_REQUEST_HEADER_ELEM: -+ if (al->request) -+ sb = httpHeaderGetByNameListMember(&al->request->header, fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator); -+ out = strBuf(sb); -+ quote = 1; -+ break; -+ -+ case LFT_REPLY_HEADER_ELEM: -+ if (al->reply) -+ sb = httpHeaderGetByNameListMember(&al->reply->header, fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator); -+ out = strBuf(sb); -+ quote = 1; -+ break; -+ -+ case LFT_REQUEST_ALL_HEADERS: -+ out = al->headers.request; -+ quote = 1; -+ break; -+ -+ case LFT_REPLY_ALL_HEADERS: -+ out = al->headers.reply; -+ quote = 1; -+ break; -+ -+ case LFT_USER_NAME: -+ out = accessLogFormatName(al->cache.authuser ? -+ al->cache.authuser : al->cache.rfc931); -+ dofree = 1; -+ break; -+ -+ case LFT_USER_LOGIN: -+ out = accessLogFormatName(al->cache.authuser); -+ dofree = 1; -+ break; -+ -+ case LFT_USER_IDENT: -+ out = accessLogFormatName(al->cache.rfc931); -+ dofree = 1; -+ break; -+ -+ /* case LFT_USER_REALM: */ -+ /* case LFT_USER_SCHEME: */ -+ -+ case LFT_HTTP_CODE: -+ outint = al->http.code; -+ doint = 1; -+ break; -+ -+ /* case LFT_HTTP_STATUS: -+ * out = statusline->text; -+ * quote = 1; -+ * break; -+ */ -+ -+ case LFT_SQUID_STATUS: -+ out = log_tags[al->cache.code]; -+ break; -+ -+ /* case LFT_SQUID_ERROR: */ -+ -+ case LFT_SQUID_HIERARCHY: -+ if (al->hier.ping.timedout) -+ memBufAppend(&mb, "TIMEOUT_", 8); -+ out = hier_strings[al->hier.code]; -+ break; -+ -+ case LFT_MIME_TYPE: -+ out = al->http.content_type; -+ break; -+ -+ case LFT_REQUEST_METHOD: -+ out = al->private.method_str; -+ break; -+ -+ case LFT_REQUEST_URI: -+ out = al->url; -+ break; -+ -+ case LFT_REQUEST_VERSION: -+ snprintf(tmp, sizeof(tmp), "%d.%d", (int) al->http.version.major, (int) al->http.version.minor); -+ out = tmp; -+ break; -+ -+ /*case LFT_REQUEST_SIZE_TOTAL: */ -+ /*case LFT_REQUEST_SIZE_LINE: */ -+ /*case LFT_REQUEST_SIZE_HEADERS: */ -+ /*case LFT_REQUEST_SIZE_BODY: */ -+ /*case LFT_REQUEST_SIZE_BODY_NO_TE: */ -+ -+ case LFT_REPLY_SIZE_TOTAL: -+ outint = al->cache.size; -+ doint = 1; -+ break; -+ -+ /*case LFT_REPLY_SIZE_LINE: */ -+ /*case LFT_REPLY_SIZE_HEADERS: */ -+ /*case LFT_REPLY_SIZE_BODY: */ -+ /*case LFT_REPLY_SIZE_BODY_NO_TE: */ -+ -+#ifdef HAVE_EXTACL_LOG -+ case LFT_EXT_LOG: -+ if (al->request) -+ out = strBuf(al->request->extacl_log); -+ -+ quote = 1; -+ break; -+#endif -+ -+ case LFT_PERCENT: -+ out = "%"; -+ break; -+ } -+ -+ if (doint) { -+ snprintf(tmp, sizeof(tmp), "%0*ld", fmt->zero ? (int) fmt->width : 0, outint); -+ out = tmp; -+ } -+ if (out && *out) { -+ if (quote || fmt->quote != LOG_QUOTE_NONE) { -+ char *newout = NULL; -+ int newfree = 0; -+ switch (fmt->quote) { -+ case LOG_QUOTE_NONE: -+ newout = rfc1738_escape_unescaped(out); -+ break; -+ case LOG_QUOTE_QUOTES: -+ newout = log_quoted_string(out); -+ newfree = 1; -+ break; -+ case LOG_QUOTE_BRAKETS: -+ newout = log_quote(out); -+ newfree = 1; -+ break; -+ case LOG_QUOTE_URL: -+ newout = rfc1738_escape(out); -+ break; -+ case LOG_QUOTE_RAW: -+ break; -+ } -+ if (newout) { -+ if (dofree) -+ safe_free(out); -+ out = newout; -+ dofree = newfree; -+ } -+ } -+ if (fmt->width) { -+ if (fmt->left) -+ memBufPrintf(&mb, "%-*s", (int) fmt->width, out); -+ else -+ memBufPrintf(&mb, "%*s", (int) fmt->width, out); -+ } else -+ memBufAppend(&mb, out, strlen(out)); -+ } else { -+ memBufAppend(&mb, "-", 1); -+ } -+ if (fmt->space) -+ memBufAppend(&mb, " ", 1); -+ stringClean(&sb); -+ if (dofree) -+ safe_free(out); -+ } -+ logfilePrintf(logfile, "%s\n", mb.buf); -+} -+ -+/* parses a single token. Returns the token length in characters, -+ * and fills in the lt item with the token information. -+ * def is for sure null-terminated -+ */ -+static int -+accessLogGetNewLogFormatToken(logformat_token * lt, char *def, enum log_quote *quote) -+{ -+ char *cur = def; -+ struct logformat_token_table_entry *lte; -+ int l; -+ -+ memset(lt, 0, sizeof(*lt)); -+ l = strcspn(cur, "%"); -+ if (l > 0) { -+ char *cp; -+ /* it's a string for sure, until \0 or the next % */ -+ cp = xmalloc(l + 1); -+ xstrncpy(cp, cur, l + 1); -+ lt->type = LFT_STRING; -+ lt->data.string = cp; -+ while (l > 0) { -+ switch (*cur) { -+ case '"': -+ if (*quote == LOG_QUOTE_NONE) -+ *quote = LOG_QUOTE_QUOTES; -+ else if (*quote == LOG_QUOTE_QUOTES) -+ *quote = LOG_QUOTE_NONE; -+ break; -+ case '[': -+ if (*quote == LOG_QUOTE_NONE) -+ *quote = LOG_QUOTE_BRAKETS; -+ break; -+ case ']': -+ if (*quote == LOG_QUOTE_BRAKETS) -+ *quote = LOG_QUOTE_NONE; -+ break; -+ } -+ cur++; -+ l--; -+ } -+ goto done; -+ } -+ if (!*cur) -+ goto done; -+ cur++; -+ switch (*cur) { -+ case '"': -+ lt->quote = LOG_QUOTE_QUOTES; -+ cur++; -+ break; -+ case '\'': -+ lt->quote = LOG_QUOTE_RAW; -+ cur++; -+ break; -+ case '[': -+ lt->quote = LOG_QUOTE_BRAKETS; -+ cur++; -+ break; -+ case '#': -+ lt->quote = LOG_QUOTE_URL; -+ cur++; -+ break; -+ default: -+ lt->quote = *quote; -+ break; -+ } -+ if (*cur == '-') { -+ lt->left = 1; -+ cur++; -+ } -+ if (*cur == '0') { -+ lt->zero = 1; -+ cur++; -+ } -+ if (isdigit(*cur)) -+ lt->width = strtol(cur, &cur, 10); -+ if (*cur == '.') -+ lt->precision = strtol(cur + 1, &cur, 10); -+ if (*cur == '{') { -+ char *cp; -+ cur++; -+ l = strcspn(cur, "}"); -+ cp = xmalloc(l + 1); -+ xstrncpy(cp, cur, l + 1); -+ lt->data.string = cp; -+ cur += l; -+ if (*cur == '}') -+ cur++; -+ } -+ lt->type = LFT_NONE; -+ for (lte = logformat_token_table; lte->config != NULL; lte++) { -+ if (strncmp(lte->config, cur, strlen(lte->config)) == 0) { -+ lt->type = lte->token_type; -+ cur += strlen(lte->config); -+ break; -+ } -+ } -+ if (lt->type == LFT_NONE) { -+ fatalf("Can't parse configuration token: '%s'\n", -+ def); -+ } -+ if (*cur == ' ') { -+ lt->space = 1; -+ cur++; -+ } -+ done: -+ switch (lt->type) { -+ case LFT_REQUEST_HEADER: -+ case LFT_REPLY_HEADER: -+ if (lt->data.string) { -+ char *header = lt->data.string; -+ char *cp = strchr(header, ':'); -+ if (cp) { -+ *cp++ = '\0'; -+ if (*cp == ',' || *cp == ';' || *cp == ':') -+ lt->data.header.separator = *cp++; -+ else -+ lt->data.header.separator = ','; -+ lt->data.header.element = cp; -+ lt->type = (lt->type == LFT_REQUEST_HEADER) ? -+ LFT_REQUEST_HEADER_ELEM : -+ LFT_REPLY_HEADER_ELEM; -+ } -+ lt->data.header.header = header; -+ } else { -+ lt->type = (lt->type == LFT_REQUEST_HEADER) ? -+ LFT_REQUEST_ALL_HEADERS : -+ LFT_REPLY_ALL_HEADERS; -+ Config.onoff.log_mime_hdrs = 1; -+ } -+ break; -+ case LFT_CLIENT_FQDN: -+ Config.onoff.log_fqdn = 1; -+ break; -+ case LFT_TIME_SUBSECOND: -+ lt->divisor = 1000; -+ if (lt->precision) { -+ int i; -+ lt->divisor = 1000000; -+ for (i = lt->precision; i > 1; i--) -+ lt->divisor /= 10; -+ if (!lt->divisor) -+ lt->divisor = 0; -+ } -+ break; -+ default: -+ break; -+ } -+ return (cur - def); -+} -+ -+int -+accessLogParseLogFormat(logformat_token ** fmt, char *def) -+{ -+ char *cur, *eos; -+ logformat_token *new_lt, *last_lt; -+ enum log_quote quote = LOG_QUOTE_NONE; -+ -+ debug(46, 1) ("accessLogParseLogFormat: got definition '%s'\n", def); -+ -+ /* very inefficent parser, but who cares, this needs to be simple */ -+ /* First off, let's tokenize, we'll optimize in a second pass. -+ * A token can either be a %-prefixed sequence (usually a dynamic -+ * token but it can be an escaped sequence), or a string. */ -+ cur = def; -+ eos = def + strlen(def); -+ *fmt = new_lt = last_lt = xmalloc(sizeof(logformat_token)); -+ cur += accessLogGetNewLogFormatToken(new_lt, cur, "e); -+ while (cur < eos) { -+ new_lt = xmalloc(sizeof(logformat_token)); -+ last_lt->next = new_lt; -+ last_lt = new_lt; -+ cur += accessLogGetNewLogFormatToken(new_lt, cur, "e); -+ } -+ return 1; -+} -+ -+void -+accessLogDumpLogFormat(StoreEntry * entry, const char *name, logformat * definitions) -+{ -+ logformat_token *t; -+ logformat *format; -+ struct logformat_token_table_entry *te; -+ debug(46, 0) ("accessLogDumpLogFormat called\n"); -+ -+ for (format = definitions; format; format = format->next) { -+ debug(46, 0) ("Dumping logformat definition for %s\n", format->name); -+ storeAppendPrintf(entry, "logformat %s ", format->name); -+ for (t = format->format; t; t = t->next) { -+ if (t->type == LFT_STRING) -+ storeAppendPrintf(entry, "%s", t->data.string); -+ else { -+ char argbuf[256]; -+ char *arg = NULL; -+ logformat_bcode_t type = t->type; -+ -+ switch (type) { -+ /* special cases */ -+ case LFT_STRING: -+ break; -+ case LFT_REQUEST_HEADER_ELEM: -+ case LFT_REPLY_HEADER_ELEM: -+ if (t->data.header.separator != ',') -+ snprintf(argbuf, sizeof(argbuf), "%s:%c%s", t->data.header.header, t->data.header.separator, t->data.header.element); -+ else -+ snprintf(argbuf, sizeof(argbuf), "%s:%s", t->data.header.header, t->data.header.element); -+ -+ arg = argbuf; -+ type = (type == LFT_REQUEST_HEADER_ELEM) ? -+ LFT_REQUEST_HEADER : -+ LFT_REPLY_HEADER; -+ break; -+ -+ case LFT_REQUEST_ALL_HEADERS: -+ case LFT_REPLY_ALL_HEADERS: -+ type = (type == LFT_REQUEST_ALL_HEADERS) ? -+ LFT_REQUEST_HEADER : -+ LFT_REPLY_HEADER; -+ break; -+ -+ default: -+ if (t->data.string) -+ arg = t->data.string; -+ break; -+ } -+ storeAppend(entry, "%", 1); -+ switch (t->quote) { -+ case LOG_QUOTE_QUOTES: -+ storeAppend(entry, "\"", 1); -+ break; -+ case LOG_QUOTE_BRAKETS: -+ storeAppend(entry, "[", 1); -+ break; -+ case LOG_QUOTE_URL: -+ storeAppend(entry, "#", 1); -+ break; -+ case LOG_QUOTE_RAW: -+ storeAppend(entry, "'", 1); -+ break; -+ case LOG_QUOTE_NONE: -+ break; -+ } -+ if (t->left) -+ storeAppend(entry, "-", 1); -+ if (t->zero) -+ storeAppend(entry, "0", 1); -+ if (t->width) -+ storeAppendPrintf(entry, "%d", (int) t->width); -+ if (t->precision) -+ storeAppendPrintf(entry, ".%d", (int) t->precision); -+ if (arg) -+ storeAppendPrintf(entry, "{%s}", arg); -+ for (te = logformat_token_table; te->config != NULL; te++) { -+ if (te->token_type == t->type) { -+ storeAppendPrintf(entry, "%s", te->config); -+ break; -+ } -+ } -+ if (t->space) -+ storeAppend(entry, " ", 1); -+ assert(te->config != NULL); -+ } -+ } -+ } -+ storeAppend(entry, "\n", 1); -+} -+ -+void -+accessLogFreeLogFormat(logformat_token ** tokens) -+{ -+ while (*tokens) { -+ logformat_token *token = *tokens; -+ *tokens = token->next; -+ safe_free(token->data.string); -+ xfree(token); -+ } -+} -+ - static void --accessLogSquid(AccessLogEntry * al) -+accessLogSquid(AccessLogEntry * al, Logfile * logfile) - { - const char *client = NULL; - char *user = NULL; -@@ -261,10 +1018,19 @@ - al->hier.host, - al->http.content_type); - safe_free(user); -+ if (Config.onoff.log_mime_hdrs) { -+ char *ereq = log_quote(al->headers.request); -+ char *erep = log_quote(al->headers.reply); -+ logfilePrintf(logfile, " [%s] [%s]\n", ereq, erep); -+ safe_free(ereq); -+ safe_free(erep); -+ } else { -+ logfilePrintf(logfile, "\n"); -+ } - } - - static void --accessLogCommon(AccessLogEntry * al) -+accessLogCommon(AccessLogEntry * al, Logfile * logfile) - { - const char *client = NULL; - char *user1 = NULL, *user2 = NULL; -@@ -288,11 +1054,21 @@ - hier_strings[al->hier.code]); - safe_free(user1); - safe_free(user2); -+ if (Config.onoff.log_mime_hdrs) { -+ char *ereq = log_quote(al->headers.request); -+ char *erep = log_quote(al->headers.reply); -+ logfilePrintf(logfile, " [%s] [%s]\n", ereq, erep); -+ safe_free(ereq); -+ safe_free(erep); -+ } else { -+ logfilePrintf(logfile, "\n"); -+ } - } - - void --accessLogLog(AccessLogEntry * al) -+accessLogLog(AccessLogEntry * al, aclCheck_t * checklist) - { -+ customlog *log; - if (LogfileStatus != LOG_ENABLE) - return; - if (al->url == NULL) -@@ -306,20 +1082,38 @@ - if (al->hier.host[0] == '\0') - xstrncpy(al->hier.host, dash_str, SQUIDHOSTNAMELEN); - -- if (Config.onoff.common_log) -- accessLogCommon(al); -- else -- accessLogSquid(al); -- if (Config.onoff.log_mime_hdrs) { -- char *ereq = log_quote(al->headers.request); -- char *erep = log_quote(al->headers.reply); -- logfilePrintf(logfile, " [%s] [%s]\n", ereq, erep); -- safe_free(ereq); -- safe_free(erep); -- } else { -- logfilePrintf(logfile, "\n"); -+ 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 -+ 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; -+ } -+ logfileFlush(log->logfile); -+ if (!checklist) -+ break; - } -- logfileFlush(logfile); -+ last: -+ (void) 0; /* NULL statement for label */ -+ - #if MULTICAST_MISS_STREAM - if (al->cache.code != LOG_TCP_MISS) - (void) 0; -@@ -346,12 +1140,15 @@ - void - accessLogRotate(void) - { -+ customlog *log; - #if FORW_VIA_DB - fvdbClear(); - #endif -- if (NULL == logfile) -- return; -- logfileRotate(logfile); -+ for (log = Config.Log.accesslogs; log; log = log->next) { -+ if (log->logfile) { -+ logfileRotate(log->logfile); -+ } -+ } - #if HEADERS_LOG - logfileRotate(headerslog); - #endif -@@ -360,10 +1157,13 @@ - void - accessLogClose(void) - { -- if (NULL == logfile) -- return; -- logfileClose(logfile); -- logfile = NULL; -+ customlog *log; -+ for (log = Config.Log.accesslogs; log; log = log->next) { -+ if (log->logfile) { -+ logfileClose(log->logfile); -+ log->logfile = NULL; -+ } -+ } - #if HEADERS_LOG - logfileClose(headerslog); - headerslog = NULL; -@@ -383,11 +1183,14 @@ - void - accessLogInit(void) - { -+ customlog *log; - assert(sizeof(log_tags) == (LOG_TYPE_MAX + 1) * sizeof(char *)); -- if (strcasecmp(Config.Log.access, "none") == 0) -- return; -- logfile = logfileOpen(Config.Log.access, MAX_URL << 1, 1); -- LogfileStatus = LOG_ENABLE; -+ for (log = Config.Log.accesslogs; log; log = log->next) { -+ if (log->type == CLF_NONE) -+ continue; -+ log->logfile = logfileOpen(log->filename, MAX_URL << 1, 1); -+ LogfileStatus = LOG_ENABLE; -+ } - #if HEADERS_LOG - headerslog = logfileOpen("/usr/local/squid/logs/headers.log", MAX_URL << 1, 0); - assert(NULL != headerslog); -Index: src/cache_cf.c -diff -u src/cache_cf.c:1.38.6.29 src/cache_cf.c:1.38.6.11.4.10 ---- src/cache_cf.c:1.38.6.29 Wed Oct 26 19:13:24 2005 -+++ src/cache_cf.c Fri Mar 3 18:27:50 2006 -@@ -60,6 +60,14 @@ - static void dump_cachedir_option_readonly(StoreEntry * e, const char *option, SwapDir * sd); - static void parse_cachedir_option_maxsize(SwapDir * sd, const char *option, const char *value, int reconfiguring); - static void dump_cachedir_option_maxsize(StoreEntry * e, const char *option, SwapDir * sd); -+static void parse_logformat(logformat ** logformat_definitions); -+static void parse_access_log(customlog ** customlog_definitions); -+static void dump_logformat(StoreEntry * entry, const char *name, logformat * definitions); -+static void dump_access_log(StoreEntry * entry, const char *name, customlog * definitions); -+static void free_logformat(logformat ** definitions); -+static void free_access_log(customlog ** definitions); -+ -+ - static struct cache_dir_option common_cachedir_options[] = - { - {"read-only", parse_cachedir_option_readonly, dump_cachedir_option_readonly}, -@@ -2625,3 +2633,144 @@ - return t; - } - } -+ -+static void -+parse_logformat(logformat ** logformat_definitions) -+{ -+ logformat *nlf; -+ char *name, *def; -+ -+ if ((name = strtok(NULL, w_space)) == NULL) -+ self_destruct(); -+ if ((def = strtok(NULL, "\r\n")) == NULL) -+ self_destruct(); -+ -+ debug(3, 1) ("Logformat for '%s' is '%s'\n", name, def); -+ -+ nlf = xcalloc(1, sizeof(logformat)); -+ nlf->name = xstrdup(name); -+ if (!accessLogParseLogFormat(&nlf->format, def)) -+ self_destruct(); -+ nlf->next = *logformat_definitions; -+ *logformat_definitions = nlf; -+} -+ -+static void -+parse_access_log(customlog ** logs) -+{ -+ const char *filename, *logdef_name; -+ customlog *cl; -+ logformat *lf; -+ -+ cl = xcalloc(1, sizeof(*cl)); -+ -+ if ((filename = strtok(NULL, w_space)) == NULL) -+ self_destruct(); -+ -+ if (strcmp(filename, "none") == 0) { -+ cl->type = CLF_NONE; -+ goto done; -+ } -+ if ((logdef_name = strtok(NULL, w_space)) == NULL) -+ logdef_name = "auto"; -+ -+ debug(3, 9) ("Log definition name '%s' file '%s'\n", logdef_name, filename); -+ -+ cl->filename = xstrdup(filename); -+ -+ /* look for the definition pointer corresponding to this name */ -+ lf = Config.Log.logformats; -+ while (lf != NULL) { -+ debug(3, 9) ("Comparing against '%s'\n", lf->name); -+ if (strcmp(lf->name, logdef_name) == 0) -+ break; -+ lf = lf->next; -+ } -+ if (lf != NULL) { -+ cl->type = CLF_CUSTOM; -+ cl->logFormat = lf; -+ } else if (strcmp(logdef_name, "auto") == 0) { -+ cl->type = CLF_AUTO; -+ } else if (strcmp(logdef_name, "squid") == 0) { -+ cl->type = CLF_SQUID; -+ } else if (strcmp(logdef_name, "common") == 0) { -+ cl->type = CLF_COMMON; -+ } else { -+ debug(3, 0) ("Log format '%s' is not defined\n", logdef_name); -+ self_destruct(); -+ } -+ -+ done: -+ aclParseAclList(&cl->aclList); -+ -+ while (*logs) -+ logs = &(*logs)->next; -+ *logs = cl; -+} -+ -+static void -+dump_logformat(StoreEntry * entry, const char *name, logformat * definitions) -+{ -+ accessLogDumpLogFormat(entry, name, definitions); -+} -+ -+static void -+dump_access_log(StoreEntry * entry, const char *name, customlog * logs) -+{ -+ customlog *log; -+ for (log = logs; log; log = log->next) { -+ storeAppendPrintf(entry, "%s ", name); -+ switch (log->type) { -+ case CLF_CUSTOM: -+ storeAppendPrintf(entry, "%s %s", log->filename, log->logFormat->name); -+ break; -+ case CLF_NONE: -+ storeAppendPrintf(entry, "none"); -+ break; -+ case CLF_SQUID: -+ storeAppendPrintf(entry, "%s squid", log->filename); -+ break; -+ case CLF_COMMON: -+ storeAppendPrintf(entry, "%s squid", log->filename); -+ break; -+ case CLF_AUTO: -+ if (log->aclList) -+ storeAppendPrintf(entry, "%s auto", log->filename); -+ else -+ storeAppendPrintf(entry, "%s", log->filename); -+ break; -+ case CLF_UNKNOWN: -+ break; -+ } -+ if (log->aclList) -+ dump_acl_list(entry, log->aclList); -+ storeAppendPrintf(entry, "\n"); -+ } -+} -+ -+static void -+free_logformat(logformat ** definitions) -+{ -+ while (*definitions) { -+ logformat *format = *definitions; -+ *definitions = format->next; -+ accessLogFreeLogFormat(&format->format); -+ xfree(format); -+ } -+} -+ -+static void -+free_access_log(customlog ** definitions) -+{ -+ while (*definitions) { -+ customlog *log = *definitions; -+ *definitions = log->next; -+ -+ log->logFormat = NULL; -+ log->type = CLF_UNKNOWN; -+ if (log->aclList) -+ aclDestroyAclList(&log->aclList); -+ safe_free(log->filename); -+ xfree(log); -+ } -+} -Index: src/cf.data.pre -diff -u src/cf.data.pre:1.49.2.86 src/cf.data.pre:1.49.2.40.2.18 ---- src/cf.data.pre:1.49.2.86 Sat Feb 25 19:13:57 2006 -+++ src/cf.data.pre Fri Mar 3 18:27:50 2006 -@@ -834,16 +834,97 @@ - (hard coded at 1 MB). - DOC_END - -- --NAME: cache_access_log --TYPE: string --DEFAULT: @DEFAULT_ACCESS_LOG@ --LOC: Config.Log.access -+NAME: logformat -+TYPE: logformat -+LOC: Config.Log.logformats -+DEFAULT: none - DOC_START -- Logs the client request activity. Contains an entry for -- every HTTP and ICP queries received. To disable, enter "none". --DOC_END -+ Usage: -+ -+ logformat <name> <format specification> -+ -+ Defines an access log format. -+ -+ The <format specification> is a string with embedded % format codes -+ -+ % format codes all follow the same basic structure where all but -+ the formatcode is optional. Output strings are automatically escaped -+ as required according to their context and the output format -+ modifiers are usually not needed, but can be specified if an explicit -+ output format is desired. -+ -+ % ["|[|'|#] [-] [[0]width] [{argument}] formatcode -+ -+ " output in quoted string format -+ [ output in squid text log format as used by log_mime_hdrs -+ # output in URL quoted format -+ ' output as-is -+ -+ - left aligned -+ width field width. If starting with 0 then the -+ output is zero padded -+ {arg} argument such as header name etc -+ -+ Format codes: -+ -+ >a Client source IP address -+ >A Client FQDN -+ <A Server IP address or peer name -+ la Local IP address (http_port) -+ lp Local port number (http_port) -+ ts Seconds since epoch -+ tu subsecond time (milliseconds) -+ tl Local time. Optional strftime format argument -+ default %d/%b/%Y:%H:%M:%S %z -+ tg GMT time. Optional strftime format argument -+ default %d/%b/%Y:%H:%M:%S %z -+ tr Response time (milliseconds) -+ >h Request header. Optional header name argument -+ on the format header[:[separator]element] -+ <h Reply header. Optional header name argument -+ as for >h -+ un User name -+ ul User login -+ ui User ident -+ Hs HTTP status code -+ Ss Squid request status (TCP_MISS etc) -+ Sh Squid hierarchy status (DEFAULT_PARENT etc) -+ mt MIME content type -+ rm Request method (GET/POST etc) -+ ru Request URL -+ rv Request protocol version -+ ea Log string returned by external acl -+ <st Reply size including HTTP headers -+ % a literal % character -+ -+logformat squid %ts.%03tu %6tr %>a %Ss/%03Hs %<st %rm %ru %un %Sh/%<A %mt -+logformat squidmime %ts.%03tu %6tr %>a %Ss/%03Hs %<st %rm %ru %un %Sh/%<A %mt [%>h] [%<h] -+logformat common %>a %ui %un [%tl] "%rm %ru HTTP/%rv" %Hs %<st %Ss:%Sh -+logformat combined %>a %ui %un [%tl] "%rm %ru HTTP/%rv" %Hs %<st "%{Referer}>h" "%{User-Agent}>h" %Ss:%Sh -+DOC_END -+ -+NAME: access_log cache_access_log -+TYPE: access_log -+LOC: Config.Log.accesslogs -+DEFAULT: none -+DOC_START -+ These files log client request activities. Has a line every HTTP or -+ ICP request. The format is: -+ access_log <filepath> [<logformat name> [acl acl ...]] -+ -+ Will log to the specified file using the specified format (which -+ must be defined in a logformat directive) those entries which match -+ ALL the acl's specified (which must be defined in acl clauses). -+ If no acl is specified, all requests will be logged to this file. -+ -+ To disable logging of a request use the filepath "none", in which case -+ a logformat name should not be specified. - -+ To log the request via syslog specify a filepath of "syslog" -+NOCOMMENT_START -+access_log @DEFAULT_ACCESS_LOG@ squid -+NOCOMMENT_END -+DOC_END - - NAME: cache_log - TYPE: string -@@ -2440,6 +2521,17 @@ - no limit imposed. - DOC_END - -+NAME: log_access -+TYPE: acl_access -+LOC: Config.accessList.log -+DEFAULT: none -+COMMENT: allow|deny acl acl... -+DOC_START -+ This options allows you to control which requests gets logged -+ to access.log (see cache_access_log directive). Requests denied -+ for logging will also not be accounted for in performance counters. -+DOC_END -+ - COMMENT_START - ADMINISTRATIVE PARAMETERS - ----------------------------------------------------------------------------- -Index: src/client_side.c -diff -u src/client_side.c:1.47.2.76 src/client_side.c:1.47.2.31.2.15 ---- src/client_side.c:1.47.2.76 Fri Mar 10 19:16:31 2006 -+++ src/client_side.c Mon Apr 24 08:22:33 2006 -@@ -871,14 +871,18 @@ - http->al.cache.code = http->log_type; - http->al.cache.msec = tvSubMsec(http->start, current_time); - if (request) { -- Packer p; -- MemBuf mb; -- memBufDefInit(&mb); -- packerToMemInit(&p, &mb); -- httpHeaderPackInto(&request->header, &p); -+ if (Config.onoff.log_mime_hdrs) { -+ Packer p; -+ MemBuf mb; -+ memBufDefInit(&mb); -+ packerToMemInit(&p, &mb); -+ httpHeaderPackInto(&request->header, &p); -+ http->al.headers.request = xstrdup(mb.buf); -+ packerClean(&p); -+ memBufClean(&mb); -+ } - http->al.http.method = request->method; - http->al.http.version = request->http_ver; -- http->al.headers.request = xstrdup(mb.buf); - http->al.hier = request->hier; - if (request->auth_user_request) { - if (authenticateUserRequestUsername(request->auth_user_request)) -@@ -888,12 +892,17 @@ - } - if (conn->rfc931[0]) - http->al.cache.rfc931 = conn->rfc931; -- packerClean(&p); -- memBufClean(&mb); - } -- accessLogLog(&http->al); -- clientUpdateCounters(http); -- clientdbUpdate(conn->peer.sin_addr, http->log_type, PROTO_HTTP, http->out.size); -+ http->al.request = request; -+ if (!http->acl_checklist) -+ http->acl_checklist = clientAclChecklistCreate(Config.accessList.http, http); -+ http->acl_checklist->reply = http->reply; -+ if (!Config.accessList.log || aclCheckFast(Config.accessList.log, http->acl_checklist)) { -+ http->al.reply = http->reply; -+ accessLogLog(&http->al, http->acl_checklist); -+ clientUpdateCounters(http); -+ clientdbUpdate(conn->peer.sin_addr, http->log_type, PROTO_HTTP, http->out.size); -+ } - } - if (http->acl_checklist) - aclChecklistFree(http->acl_checklist); -@@ -904,6 +913,7 @@ - safe_free(http->al.headers.request); - safe_free(http->al.headers.reply); - safe_free(http->al.cache.authuser); -+ http->al.request = NULL; - safe_free(http->redirect.location); - stringClean(&http->range_iter.boundary); - if ((e = http->entry)) { -Index: src/icp_v2.c -diff -u src/icp_v2.c:1.5 src/icp_v2.c:1.5.60.1 ---- src/icp_v2.c:1.5 Fri May 4 06:39:12 2001 -+++ src/icp_v2.c Sat Jun 21 05:45:26 2003 -@@ -63,7 +63,7 @@ - al.cache.size = len; - al.cache.code = logcode; - al.cache.msec = delay; -- accessLogLog(&al); -+ accessLogLog(&al, NULL); - } - - void -Index: src/logfile.c -diff -u src/logfile.c:1.5.38.3 src/logfile.c:1.5.38.3.4.4 ---- src/logfile.c:1.5.38.3 Mon Jan 20 19:15:11 2003 -+++ src/logfile.c Sun May 21 16:56:52 2006 -@@ -36,36 +36,127 @@ - - static void logfileWriteWrapper(Logfile * lf, const void *buf, size_t len); - -+#if HAVE_SYSLOG -+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 */ -+ - Logfile * - logfileOpen(const char *path, size_t bufsz, int fatal_flag) - { -- int fd; -- Logfile *lf; -- 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()); -- return NULL; -+ Logfile *lf = xcalloc(1, sizeof(*lf)); -+ xstrncpy(lf->path, path, MAXPATHLEN); -+#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 = 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 -+#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; - } - } -- lf = xcalloc(1, sizeof(*lf)); -- lf->fd = fd; - if (fatal_flag) - lf->flags.fatal = 1; -- xstrncpy(lf->path, path, MAXPATHLEN); -- if (bufsz > 0) { -- lf->buf = xmalloc(bufsz); -- lf->bufsz = bufsz; -- } - return lf; - } - -@@ -73,7 +164,8 @@ - logfileClose(Logfile * lf) - { - logfileFlush(lf); -- file_close(lf->fd); -+ if (lf->fd >= 0) -+ file_close(lf->fd); - if (lf->buf) - xfree(lf->buf); - xfree(lf); -@@ -89,6 +181,8 @@ - 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) -@@ -120,6 +214,12 @@ - void - logfileWrite(Logfile * lf, void *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); -Index: src/protos.h -diff -u src/protos.h:1.41.6.34 src/protos.h:1.41.6.14.2.10 ---- src/protos.h:1.41.6.34 Sat Feb 25 19:13:57 2006 -+++ src/protos.h Fri Mar 3 18:27:52 2006 -@@ -34,11 +34,14 @@ - #ifndef SQUID_PROTOS_H - #define SQUID_PROTOS_H - --extern void accessLogLog(AccessLogEntry *); -+extern void accessLogLog(AccessLogEntry *, aclCheck_t * checklist); - extern void accessLogRotate(void); - extern void accessLogClose(void); - extern void accessLogInit(void); - extern const char *accessLogTime(time_t); -+extern int accessLogParseLogFormat(logformat_token ** fmt, char *def); -+extern void accessLogDumpLogFormat(StoreEntry * entry, const char *name, logformat * definitions); -+extern void accessLogFreeLogFormat(logformat_token ** fmt); - extern void hierarchyNote(HierarchyLogEntry *, hier_code, const char *); - #if FORW_VIA_DB - extern void fvdbCountVia(const char *key); -Index: src/structs.h -diff -u src/structs.h:1.48.2.46 src/structs.h:1.48.2.11.2.14 ---- src/structs.h:1.48.2.46 Fri Mar 10 19:16:31 2006 -+++ src/structs.h Mon Apr 24 08:22:34 2006 -@@ -465,7 +465,6 @@ - char *as_whois_server; - struct { - char *log; -- char *access; - char *store; - char *swap; - #if USE_USERAGENT_LOG -@@ -477,6 +476,8 @@ - #if WIP_FWD_LOG - char *forward; - #endif -+ logformat *logformats; -+ customlog *accesslogs; - int rotateNumber; - } Log; - char *adminEmail; -@@ -623,6 +624,7 @@ - acl_access *AlwaysDirect; - acl_access *ASlists; - acl_access *noCache; -+ acl_access *log; - #if SQUID_SNMP - acl_access *snmp; - #endif -@@ -1061,6 +1063,8 @@ - const char *method_str; - } private; - HierarchyLogEntry hier; -+ HttpReply *reply; -+ request_t *request; - }; - - struct _clientHttpRequest { -@@ -2210,8 +2214,32 @@ - size_t bufsz; - ssize_t offset; - struct { -- unsigned int fatal:1; -+ unsigned int fatal; -+ unsigned int syslog; - } flags; -+ int syslog_priority; -+}; -+ -+struct _logformat { -+ char *name; -+ logformat_token *format; -+ logformat *next; -+}; -+ -+struct _customlog { -+ char *filename; -+ acl_list *aclList; -+ logformat *logFormat; -+ Logfile *logfile; -+ customlog *next; -+ enum { -+ CLF_UNKNOWN, -+ CLF_AUTO, -+ CLF_CUSTOM, -+ CLF_SQUID, -+ CLF_COMMON, -+ CLF_NONE -+ } type; - }; - - struct cache_dir_option { -Index: src/typedefs.h -diff -u src/typedefs.h:1.25.6.8 src/typedefs.h:1.25.6.2.2.6 ---- src/typedefs.h:1.25.6.8 Sat Mar 26 18:16:17 2005 -+++ src/typedefs.h Thu May 26 21:34:16 2005 -@@ -209,6 +209,9 @@ - typedef struct _storerepl_entry storerepl_entry_t; - typedef struct _diskd_queue diskd_queue; - typedef struct _Logfile Logfile; -+typedef struct _logformat_token logformat_token; -+typedef struct _logformat logformat; -+typedef struct _customlog customlog; - typedef struct _RemovalPolicy RemovalPolicy; - typedef struct _RemovalPolicyWalker RemovalPolicyWalker; - typedef struct _RemovalPurgeWalker RemovalPurgeWalker; |