From e804f560400d329f25d401064a4b9fb1826ee242 Mon Sep 17 00:00:00 2001 From: jkaluza Date: Mon, 23 Feb 2015 14:52:53 +0000 Subject: [PATCH 1/7] Add support for %H dateformat [czchen] Upstream-commit: 9edfa9f40fa4aa20b010c829d10eedb3e1bf985b Signed-off-by: Kamil Dudka --- logrotate.8 | 9 +++++---- logrotate.c | 1 + test/test | 14 ++++++++++++++ test/test-config.61.in | 8 ++++++++ 4 files changed, 28 insertions(+), 4 deletions(-) create mode 100644 test/test-config.61.in diff --git a/logrotate.8 b/logrotate.8 index 2cd2370..89dd82a 100644 --- a/logrotate.8 +++ b/logrotate.8 @@ -238,10 +238,11 @@ the \fBdateformat\fR and \fBdateyesterday\fR options. .TP \fBdateformat\fR \fIformat_string\fR Specify the extension for \fBdateext\fR using the notation similar to -\fBstrftime\fR(3) function. Only %Y %m %d and %s specifiers are allowed. -The default value is \-%Y%m%d. Note that also the character separating log -name from the extension is part of the dateformat string. The system clock -must be set past Sep 9th 2001 for %s to work correctly. +\fBstrftime\fR(3) function. Only %Y %m %d %H and %s specifiers are allowed. +The default value is \-%Y%m%d except hourly, which uses \-%Y%m%d%H as default +value. Note that also the character separating log name from the extension is +part of the dateformat string. The system clock must be set past Sep 9th 2001 +for %s to work correctly. Note that the datestamps generated by this format must be lexically sortable (i.e., first the year, then the month then the day. e.g., 2001/12/01 is ok, but 01/12/2001 is not, since 01/11/2002 would sort lower while it is later). diff --git a/logrotate.c b/logrotate.c index c81c6cd..7bb3484 100644 --- a/logrotate.c +++ b/logrotate.c @@ -1033,6 +1033,7 @@ int prerotateSingleLog(struct logInfo *log, int logNum, struct logState *state, j += 10; /* strlen("[0-9][0-9]") */ case 'm': case 'd': + case 'H': strncat(dext_pattern, "[0-9][0-9]", sizeof(dext_pattern) - strlen(dext_pattern)); j += 10; diff --git a/test/test b/test/test index 6a86e39..3363d42 100755 --- a/test/test +++ b/test/test @@ -1517,4 +1517,18 @@ if [ $? == 0 ]; then exit 3 fi +cleanup 61 + +# ------------------------------- Test 61 ------------------------------------ +preptest test.log 61 1 0 + +$RLR test-config.61 --force + +DATESTRING=$(/bin/date +%Y-%m-%d-%H) + +checkoutput < Date: Wed, 1 Apr 2015 12:51:50 +0000 Subject: [PATCH 2/7] Show better message when log does not need rotating Upstream-commit: 3d91c5bed7a1c178d9b3499f0adc545ebac9f281 Signed-off-by: Kamil Dudka --- logrotate.c | 47 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/logrotate.c b/logrotate.c index 7bb3484..32d26b9 100644 --- a/logrotate.c +++ b/logrotate.c @@ -864,6 +864,10 @@ int findNeedRotating(struct logInfo *log, int logNum, int force) } else if (log->criterium == ROT_SIZE) { state->doRotate = (sb.st_size >= log->threshhold); + if (!state->doRotate) { + message(MESS_DEBUG, " log does not need rotating " + "(log size is below the 'size' threshold)\n"); + } } else if (mktime(&state->lastRotated) - mktime(&now) > (25 * 3600)) { /* 25 hours allows for DST changes as well as geographical moves */ message(MESS_ERROR, @@ -886,36 +890,75 @@ int findNeedRotating(struct logInfo *log, int logNum, int force) ((mktime(&now) - mktime(&state->lastRotated)) > (7 * 24 * 3600))); + if (!state->doRotate) { + message(MESS_DEBUG, " log does not need rotating " + "(log has been rotated at %d-%d-%d %d:%d, " + "that is not week ago yet)\n", state->lastRotated.tm_year, + state->lastRotated.tm_mon, state->lastRotated.tm_mday, + state->lastRotated.tm_hour, state->lastRotated.tm_min); + } break; case ROT_HOURLY: state->doRotate = ((now.tm_hour != state->lastRotated.tm_hour) || (now.tm_mday != state->lastRotated.tm_mday) || (now.tm_mon != state->lastRotated.tm_mon) || (now.tm_year != state->lastRotated.tm_year)); + if (!state->doRotate) { + message(MESS_DEBUG, " log does not need rotating " + "(log has been rotated at %d-%d-%d %d:%d, " + "that is not hour ago yet)\n", state->lastRotated.tm_year, + state->lastRotated.tm_mon, state->lastRotated.tm_mday, + state->lastRotated.tm_hour, state->lastRotated.tm_min); + } break; case ROT_DAYS: /* FIXME: only days=1 is implemented!! */ state->doRotate = ((now.tm_mday != state->lastRotated.tm_mday) || (now.tm_mon != state->lastRotated.tm_mon) || (now.tm_year != state->lastRotated.tm_year)); + if (!state->doRotate) { + message(MESS_DEBUG, " log does not need rotating " + "(log has been rotated at %d-%d-%d %d:%d, " + "that is not day ago yet)\n", state->lastRotated.tm_year, + state->lastRotated.tm_mon, state->lastRotated.tm_mday, + state->lastRotated.tm_hour, state->lastRotated.tm_min); + } break; case ROT_MONTHLY: /* rotate if the logs haven't been rotated this month or this year */ state->doRotate = ((now.tm_mon != state->lastRotated.tm_mon) || (now.tm_year != state->lastRotated.tm_year)); + if (!state->doRotate) { + message(MESS_DEBUG, " log does not need rotating " + "(log has been rotated at %d-%d-%d %d:%d, " + "that is not month ago yet)\n", state->lastRotated.tm_year, + state->lastRotated.tm_mon, state->lastRotated.tm_mday, + state->lastRotated.tm_hour, state->lastRotated.tm_min); + } break; case ROT_YEARLY: /* rotate if the logs haven't been rotated this year */ state->doRotate = (now.tm_year != state->lastRotated.tm_year); + if (!state->doRotate) { + message(MESS_DEBUG, " log does not need rotating " + "(log has been rotated at %d-%d-%d %d:%d, " + "that is not year ago yet)\n", state->lastRotated.tm_year, + state->lastRotated.tm_mon, state->lastRotated.tm_mday, + state->lastRotated.tm_hour, state->lastRotated.tm_min); + } break; default: /* ack! */ state->doRotate = 0; break; } - if (log->minsize && sb.st_size < log->minsize) + if (log->minsize && sb.st_size < log->minsize) { state->doRotate = 0; + message(MESS_DEBUG, " log does not need rotating " + "('misinze' directive is used and the log " + "size is smaller than the minsize value"); + } } if (log->maxsize && sb.st_size > log->maxsize) @@ -927,8 +970,6 @@ int findNeedRotating(struct logInfo *log, int logNum, int force) if (state->doRotate) { message(MESS_DEBUG, " log needs rotating\n"); - } else { - message(MESS_DEBUG, " log does not need rotating\n"); } return 0; -- 2.5.5 From 8ed44537bcca96f33d5283a5500faa876d80cd07 Mon Sep 17 00:00:00 2001 From: jkaluza Date: Wed, 1 Apr 2015 12:57:54 +0000 Subject: [PATCH 3/7] Follow-up of previous commit. Also print info when log is empty. Upstream-commit: c0549cfbcc663e540c003f7b2640ee3ebc5960a1 Signed-off-by: Kamil Dudka --- logrotate.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/logrotate.c b/logrotate.c index 32d26b9..8257ffe 100644 --- a/logrotate.c +++ b/logrotate.c @@ -862,6 +862,9 @@ int findNeedRotating(struct logInfo *log, int logNum, int force) /* user forced rotation of logs from command line */ state->doRotate = 1; } + else if (log->maxsize && sb.st_size > log->maxsize) { + state->doRotate = 1; + } else if (log->criterium == ROT_SIZE) { state->doRotate = (sb.st_size >= log->threshhold); if (!state->doRotate) { @@ -960,13 +963,17 @@ int findNeedRotating(struct logInfo *log, int logNum, int force) "size is smaller than the minsize value"); } } - - if (log->maxsize && sb.st_size > log->maxsize) - state->doRotate = 1; + else if (!state->doRotate) { + message(MESS_DEBUG, " log does not need rotating " + "(log has been already rotated)"); + } /* The notifempty flag overrides the normal criteria */ - if (!(log->flags & LOG_FLAG_IFEMPTY) && !sb.st_size) + if (state->doRotate && !(log->flags & LOG_FLAG_IFEMPTY) && !sb.st_size) { state->doRotate = 0; + message(MESS_DEBUG, " log does not need rotating " + "(log is empty)"); + } if (state->doRotate) { message(MESS_DEBUG, " log needs rotating\n"); -- 2.5.5 From e92d35acfc02380b70f1bf925a8a0e15cc193d9c Mon Sep 17 00:00:00 2001 From: jkaluza Date: Thu, 2 Apr 2015 07:09:43 +0000 Subject: [PATCH 4/7] Add new -l option to log debug output to file Upstream-commit: 2c583abe53972aa6f834b56345b40cb294b0b3a4 Signed-off-by: Kamil Dudka --- log.c | 77 ++++++++++++++++++++----------------------------------------- log.h | 3 --- logrotate.c | 12 ++++++++++ test/test | 37 ++++++++++++++++++++++++++++- 4 files changed, 73 insertions(+), 56 deletions(-) diff --git a/log.c b/log.c index f0ef130..824aa82 100644 --- a/log.c +++ b/log.c @@ -37,75 +37,48 @@ void logClearFlags(int newFlags) flags &= ~newFlags; } -#if 0 -void log(int fd, char *format, ...) +static void log_once(FILE *where, int level, char *format, va_list args) { - int i = 0; - char *buf = NULL; - va_list args; - int size; - - va_start(args, format); - - do { - i += 1000; - if (buf) - free(buf); - buf = malloc(i); - size = vsnprintf(buf, i, format, args); - } while (size >= i); - - write(fd, buf, size); - - free(buf); - - va_end(args); -} -#endif - -void message(int level, char *format, ...) -{ - va_list args; - FILE *where = NULL; - int showTime = 0; - - if (errorFile == NULL) - errorFile = stderr; - if (messageFile == NULL) - messageFile = stderr; - where = errorFile; - - if (level >= logLevel) { - va_start(args, format); + int showTime = 0; switch (level) { case MESS_DEBUG: - where = messageFile; - showTime = 1; - break; - + showTime = 1; + break; case MESS_NORMAL: case MESS_VERBOSE: - where = messageFile; - break; - + break; default: - if (flags & LOG_TIMES) + if (flags & LOG_TIMES) fprintf(where, "%ld: ", (long) time(NULL)); - fprintf(errorFile, "error: "); - break; + fprintf(where, "error: "); + break; } if (showTime && (flags & LOG_TIMES)) { - fprintf(where, "%ld:", (long) time(NULL)); + fprintf(where, "%ld:", (long) time(NULL)); } vfprintf(where, format, args); fflush(where); + if (level == MESS_FATAL) + exit(1); +} + +void message(int level, char *format, ...) +{ + va_list args; + + if (level >= logLevel) { + va_start(args, format); + log_once(stderr, level, format, args); va_end(args); + } - if (level == MESS_FATAL) - exit(1); + if (messageFile != NULL) { + va_start(args, format); + log_once(messageFile, level, format, args); + va_end(args); } } diff --git a/log.h b/log.h index f3b6da5..49a4ce8 100644 --- a/log.h +++ b/log.h @@ -18,9 +18,6 @@ void message(int level, char *format, ...) #else ; #endif -#if 0 -void log(int fd, char *format, ...); -#endif void logSetErrorFile(FILE * f); void logSetMessageFile(FILE * f); void logSetFlags(int flags); diff --git a/logrotate.c b/logrotate.c index 8257ffe..b803685 100644 --- a/logrotate.c +++ b/logrotate.c @@ -2239,6 +2239,8 @@ int main(int argc, const char **argv) { int force = 0; char *stateFile = STATEFILE; + char *logFile = NULL; + FILE *logFd = 0; int rc = 0; int arg; const char **files; @@ -2256,6 +2258,7 @@ int main(int argc, const char **argv) "Path of state file", "statefile"}, {"verbose", 'v', 0, 0, 'v', "Display messages during rotation"}, + {"log", 'l', POPT_ARG_STRING, &logFile, 'l', "Log file"}, {"version", '\0', POPT_ARG_NONE, NULL, 'V', "Display version information"}, POPT_AUTOHELP {0, 0, 0, 0, 0} }; @@ -2275,6 +2278,15 @@ int main(int argc, const char **argv) case 'v': logSetLevel(MESS_DEBUG); break; + case 'l': + logFd = fopen(logFile, "w"); + if (!logFd) { + message(MESS_ERROR, "error opening log file %s: %s\n", + logFile, strerror(errno)); + break; + } + logSetMessageFile(logFd); + break; case 'V': fprintf(stderr, "logrotate %s\n", VERSION); poptFreeContext(optCon); diff --git a/test/test b/test/test index 3363d42..1584def 100755 --- a/test/test +++ b/test/test @@ -531,7 +531,7 @@ cleanup 17 # ------------------------------- Test 17 ------------------------------------ preptest test.log 17 1 0 # log with 1 byte should not be rotated -$RLR test-config.17 2>error.log +$RLR test-config.17 -l logrotate.log 2>error.log grep "unexpected } (missing previous '{')" error.log >/dev/null if [ $? != 0 ]; then @@ -541,6 +541,14 @@ fi rm error.log +grep "reading config file test-config.17" logrotate.log >/dev/null +if [ $? != 0 ]; then + echo "There is no log output in logrotate.log" + exit 3 +fi + +rm -f logrotate.log + checkoutput </dev/null if [ $? != 0 ]; then echo "test.log must have user:nobody:rwx ACL" + getfacl test.log exit 3 fi getfacl test.log|grep "group::---" >/dev/null if [ $? != 0 ]; then echo "test.log must have group::--- ACL" + getfacl test.log exit 3 fi getfacl test.log.1|grep "user:nobody:rwx" >/dev/null if [ $? != 0 ]; then echo "test.log.1 must have user:nobody:rwx ACL" + getfacl test.log.1 exit 3 fi getfacl test.log.1|grep "group::---" >/dev/null if [ $? != 0 ]; then echo "test.log.1 must have group::--- ACL" + getfacl test.log.1 exit 3 fi @@ -1427,6 +1439,29 @@ fi rm -f *test.log* +cleanup 60 + +# ------------------------------- Test 60 ------------------------------------ +# Test we log debug output using -l option when passed. +preptest test.log 61 1 0 + +$RLR test-config.61 --force -l ./logrotate.log + +DATESTRING=$(/bin/date +%Y-%m-%d-%H) + +grep "reading config file test-config.61" logrotate.log >/dev/null +if [ $? != 0 ]; then + echo "There is no log output in logrotate.log" + exit 3 +fi + +rm -f logrotate.log + +checkoutput < Date: Wed, 21 Oct 2015 09:23:06 +1300 Subject: [PATCH 5/7] Support system dates back to the year 1970 The system time on Linux can be set back as far as 1970 (the epoch time). Currently logrotate stops working correctly if the time goes before 1996. This value (1996) appears to have been hard coded since the code was written back in 1996. Testing and code analysis shows this can simply be modified to 1970. Upstream-commit: bdbfea38a154b45832daf9c188d1829da2e63996 Signed-off-by: Kamil Dudka --- logrotate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logrotate.c b/logrotate.c index b803685..8fff0eb 100644 --- a/logrotate.c +++ b/logrotate.c @@ -2151,7 +2151,7 @@ static int readState(char *stateFilename) } /* Hack to hide earlier bug */ - if ((year != 1900) && (year < 1996 || year > 2100)) { + if ((year != 1900) && (year < 1970 || year > 2100)) { message(MESS_ERROR, "bad year %d for file %s in state file %s\n", year, argv[0], stateFilename); -- 2.5.5 From c1ef91cc688c94392f6f82c0348fe51f766c4dbd Mon Sep 17 00:00:00 2001 From: Rolf Eike Beer Date: Mon, 4 Jan 2016 10:14:31 +0100 Subject: [PATCH 6/7] fix Y2k bug in debug messages tm_year has the year since 1900, so without this change the message look like this: considering log /var/log/apache2/access_log log does not need rotating (log has been rotated at 116-0-4 3:10, that is not week ago yet) Upstream-commit: b2e01e89f8d677758898ffb93fd9bc31575d965f Signed-off-by: Kamil Dudka --- logrotate.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/logrotate.c b/logrotate.c index 8fff0eb..66b8ae3 100644 --- a/logrotate.c +++ b/logrotate.c @@ -896,7 +896,7 @@ int findNeedRotating(struct logInfo *log, int logNum, int force) if (!state->doRotate) { message(MESS_DEBUG, " log does not need rotating " "(log has been rotated at %d-%d-%d %d:%d, " - "that is not week ago yet)\n", state->lastRotated.tm_year, + "that is not week ago yet)\n", 1900 + state->lastRotated.tm_year, state->lastRotated.tm_mon, state->lastRotated.tm_mday, state->lastRotated.tm_hour, state->lastRotated.tm_min); } @@ -909,7 +909,7 @@ int findNeedRotating(struct logInfo *log, int logNum, int force) if (!state->doRotate) { message(MESS_DEBUG, " log does not need rotating " "(log has been rotated at %d-%d-%d %d:%d, " - "that is not hour ago yet)\n", state->lastRotated.tm_year, + "that is not hour ago yet)\n", 1900 + state->lastRotated.tm_year, state->lastRotated.tm_mon, state->lastRotated.tm_mday, state->lastRotated.tm_hour, state->lastRotated.tm_min); } @@ -922,7 +922,7 @@ int findNeedRotating(struct logInfo *log, int logNum, int force) if (!state->doRotate) { message(MESS_DEBUG, " log does not need rotating " "(log has been rotated at %d-%d-%d %d:%d, " - "that is not day ago yet)\n", state->lastRotated.tm_year, + "that is not day ago yet)\n", 1900 + state->lastRotated.tm_year, state->lastRotated.tm_mon, state->lastRotated.tm_mday, state->lastRotated.tm_hour, state->lastRotated.tm_min); } @@ -935,7 +935,7 @@ int findNeedRotating(struct logInfo *log, int logNum, int force) if (!state->doRotate) { message(MESS_DEBUG, " log does not need rotating " "(log has been rotated at %d-%d-%d %d:%d, " - "that is not month ago yet)\n", state->lastRotated.tm_year, + "that is not month ago yet)\n", 1900 + state->lastRotated.tm_year, state->lastRotated.tm_mon, state->lastRotated.tm_mday, state->lastRotated.tm_hour, state->lastRotated.tm_min); } @@ -946,7 +946,7 @@ int findNeedRotating(struct logInfo *log, int logNum, int force) if (!state->doRotate) { message(MESS_DEBUG, " log does not need rotating " "(log has been rotated at %d-%d-%d %d:%d, " - "that is not year ago yet)\n", state->lastRotated.tm_year, + "that is not year ago yet)\n", 1900 + state->lastRotated.tm_year, state->lastRotated.tm_mon, state->lastRotated.tm_mday, state->lastRotated.tm_hour, state->lastRotated.tm_min); } -- 2.5.5 From 62299605c344ecaf9d7b86e028e7e8ad66786820 Mon Sep 17 00:00:00 2001 From: Rolf Eike Beer Date: Mon, 4 Jan 2016 10:18:22 +0100 Subject: [PATCH 7/7] fix month formatting in debug messages The month in struct tm is given in range 0..11, which can lead to messages like this: considering log /var/log/apache2/access_log log does not need rotating (log has been rotated at 116-0-4 3:10, that is not week ago yet) Upstream-commit: 8cbfb079579a1d8b98f1878cec35c269fa1ac5a2 Signed-off-by: Kamil Dudka --- logrotate.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/logrotate.c b/logrotate.c index 66b8ae3..c695db4 100644 --- a/logrotate.c +++ b/logrotate.c @@ -897,7 +897,7 @@ int findNeedRotating(struct logInfo *log, int logNum, int force) message(MESS_DEBUG, " log does not need rotating " "(log has been rotated at %d-%d-%d %d:%d, " "that is not week ago yet)\n", 1900 + state->lastRotated.tm_year, - state->lastRotated.tm_mon, state->lastRotated.tm_mday, + 1 + state->lastRotated.tm_mon, state->lastRotated.tm_mday, state->lastRotated.tm_hour, state->lastRotated.tm_min); } break; @@ -910,7 +910,7 @@ int findNeedRotating(struct logInfo *log, int logNum, int force) message(MESS_DEBUG, " log does not need rotating " "(log has been rotated at %d-%d-%d %d:%d, " "that is not hour ago yet)\n", 1900 + state->lastRotated.tm_year, - state->lastRotated.tm_mon, state->lastRotated.tm_mday, + 1 + state->lastRotated.tm_mon, state->lastRotated.tm_mday, state->lastRotated.tm_hour, state->lastRotated.tm_min); } break; @@ -923,7 +923,7 @@ int findNeedRotating(struct logInfo *log, int logNum, int force) message(MESS_DEBUG, " log does not need rotating " "(log has been rotated at %d-%d-%d %d:%d, " "that is not day ago yet)\n", 1900 + state->lastRotated.tm_year, - state->lastRotated.tm_mon, state->lastRotated.tm_mday, + 1 + state->lastRotated.tm_mon, state->lastRotated.tm_mday, state->lastRotated.tm_hour, state->lastRotated.tm_min); } break; @@ -936,7 +936,7 @@ int findNeedRotating(struct logInfo *log, int logNum, int force) message(MESS_DEBUG, " log does not need rotating " "(log has been rotated at %d-%d-%d %d:%d, " "that is not month ago yet)\n", 1900 + state->lastRotated.tm_year, - state->lastRotated.tm_mon, state->lastRotated.tm_mday, + 1 + state->lastRotated.tm_mon, state->lastRotated.tm_mday, state->lastRotated.tm_hour, state->lastRotated.tm_min); } break; @@ -947,7 +947,7 @@ int findNeedRotating(struct logInfo *log, int logNum, int force) message(MESS_DEBUG, " log does not need rotating " "(log has been rotated at %d-%d-%d %d:%d, " "that is not year ago yet)\n", 1900 + state->lastRotated.tm_year, - state->lastRotated.tm_mon, state->lastRotated.tm_mday, + 1 + state->lastRotated.tm_mon, state->lastRotated.tm_mday, state->lastRotated.tm_hour, state->lastRotated.tm_min); } break; -- 2.5.5