diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9d472cb --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +SOURCES/logrotate-3.8.6.tar.gz diff --git a/.logrotate.metadata b/.logrotate.metadata new file mode 100644 index 0000000..e522959 --- /dev/null +++ b/.logrotate.metadata @@ -0,0 +1 @@ +2c99e7e76f5f4bc95dbab63a72095974bade80cf SOURCES/logrotate-3.8.6.tar.gz diff --git a/README.md b/README.md deleted file mode 100644 index 0e7897f..0000000 --- a/README.md +++ /dev/null @@ -1,5 +0,0 @@ -The master branch has no content - -Look at the c7 branch if you are working with CentOS-7, or the c4/c5/c6 branch for CentOS-4, 5 or 6 - -If you find this file in a distro specific branch, it means that no content has been checked in yet diff --git a/SOURCES/logrotate-3.8.6-compress-subject.patch b/SOURCES/logrotate-3.8.6-compress-subject.patch new file mode 100644 index 0000000..9ccb0dc --- /dev/null +++ b/SOURCES/logrotate-3.8.6-compress-subject.patch @@ -0,0 +1,139 @@ +diff --git a/logrotate.c b/logrotate.c +index 4ef044e..9faf341 100644 +--- a/logrotate.c ++++ b/logrotate.c +@@ -662,22 +662,20 @@ static int mailLog(struct logInfo *log, char *logFile, char *mailCommand, + static int mailLogWrapper(char *mailFilename, char *mailCommand, + int logNum, struct logInfo *log) + { +- /* if the log is compressed (and we're not mailing a +- * file whose compression has been delayed), we need +- * to uncompress it */ +- if ((log->flags & LOG_FLAG_COMPRESS) && +- !((log->flags & LOG_FLAG_DELAYCOMPRESS) && +- (log->flags & LOG_FLAG_MAILFIRST))) { +- if (mailLog(log, mailFilename, mailCommand, +- log->uncompress_prog, log->logAddress, +- log->files[logNum])) +- return 1; +- } else { +- if (mailLog(log, mailFilename, mailCommand, NULL, +- log->logAddress, mailFilename)) +- return 1; +- } +- return 0; ++ /* if the log is compressed (and we're not mailing a ++ * file whose compression has been delayed), we need ++ * to uncompress it */ ++ if ((log->flags & LOG_FLAG_COMPRESS) && !(log->flags & LOG_FLAG_DELAYCOMPRESS)) { ++ if (mailLog(log, mailFilename, mailCommand, ++ log->uncompress_prog, log->logAddress, ++ (log->flags & LOG_FLAG_MAILFIRST) ? log->files[logNum] : mailFilename)) ++ return 1; ++ } else { ++ if (mailLog(log, mailFilename, mailCommand, NULL, ++ log->logAddress, mailFilename)) ++ return 1; ++ } ++ return 0; + } + + static int copyTruncate(char *currLog, char *saveLog, struct stat *sb, +diff --git a/test/test b/test/test +index e9ce46f..f7f3cf4 100755 +--- a/test/test ++++ b/test/test +@@ -132,6 +132,9 @@ createlogs() { + + checkmail() { + (echo -s $PWD/$1 user@myhost.org; echo $2) | diff -u - mail-out ++ if [ $? != 0 ]; then ++ exit 5 ++ fi + } + + checkoutput() { +@@ -429,7 +432,7 @@ test.log 0 + scriptout 0 foo + EOF + +-checkmail test.log first ++checkmail test.log.2.gz first + + # check rotation into a directory given as a relative pathname + cleanup 12 +@@ -1424,4 +1427,37 @@ fi + + rm -f *test.log* + ++cleanup 64 ++ ++# ------------------------------- Test 64 ------------------------------------ ++# filename in mail's subject with compress directive and maillast directive ++# should be the name of the removed log ++preptest test.log 64 1 0 ++ ++DATESTRING=$(/bin/date +%Y%m%d) ++ ++$RLR test-config.64 --force ++checkoutput < +Date: Fri, 7 Nov 2014 12:13:12 +0000 +Subject: [PATCH] Better error message when the config file has bad mode + +Upstream-commit: 367640762bef15ac0850113c591e3de7193c1764 +Signed-off-by: Kamil Dudka +--- + config.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/config.c b/config.c +index 700ad85..2a610de 100644 +--- a/config.c ++++ b/config.c +@@ -795,8 +795,8 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig) + + if (getuid() == ROOT_UID) { + if ((sb.st_mode & 07533) != 0400) { +- message(MESS_DEBUG, +- "Ignoring %s because of bad file mode.\n", ++ message(MESS_ERROR, ++ "Ignoring %s because of bad file mode - must be 0644 or 0444.\n", + configFile); + close(fd); + return 0; +-- +2.13.5 + diff --git a/SOURCES/logrotate-3.8.6-copy-and-copytruncate.patch b/SOURCES/logrotate-3.8.6-copy-and-copytruncate.patch new file mode 100644 index 0000000..505a999 --- /dev/null +++ b/SOURCES/logrotate-3.8.6-copy-and-copytruncate.patch @@ -0,0 +1,69 @@ +From ba18db9a3c47f3283bb3493a84946fe27d7b1bc4 Mon Sep 17 00:00:00 2001 +From: Kamil Dudka +Date: Tue, 20 Jun 2017 13:35:37 +0200 +Subject: [PATCH] make 'copy' and 'copytruncate' work together + +This commit fixes a regression introduced +by 3b26f4d8bbb338981aa2796c4076792c63d850c0. + +Upstream-commit: 65faf212e51115699f55f491d464f0ead9c2047e +Signed-off-by: Kamil Dudka +--- + logrotate.c | 5 ++++- + test/test | 13 +++++++++++++ + test/test-config.73.in | 4 ++++ + 3 files changed, 21 insertions(+), 1 deletion(-) + create mode 100644 test/test-config.73.in + +diff --git a/logrotate.c b/logrotate.c +index 20f6ea5..d5da299 100644 +--- a/logrotate.c ++++ b/logrotate.c +@@ -760,7 +760,10 @@ static int copyTruncate(char *currLog, char *saveLog, struct stat *sb, + message(MESS_DEBUG, "copying %s to %s\n", currLog, saveLog); + + if (!debug) { +- if ((fdcurr = open(currLog, ((flags & LOG_FLAG_COPY) ? O_RDONLY : O_RDWR) | O_NOFOLLOW)) < 0) { ++ /* read access is sufficient for 'copy' but not for 'copytruncate' */ ++ const int read_only = (flags & LOG_FLAG_COPY) ++ && !(flags & LOG_FLAG_COPYTRUNCATE); ++ if ((fdcurr = open(currLog, ((read_only) ? O_RDONLY : O_RDWR) | O_NOFOLLOW)) < 0) { + message(MESS_ERROR, "error opening %s: %s\n", currLog, + strerror(errno)); + return 1; +diff --git a/test/test b/test/test +index 54d57d2..bcdfe05 100755 +--- a/test/test ++++ b/test/test +@@ -1586,5 +1586,18 @@ EOF + rm -rf testdir adir + rm -rf testdir bdir + ++cleanup 73 ++ ++# ------------------------------- Test 73 ------------------------------------ ++# make sure that 'copy' and 'copytruncate' work together ++preptest test.log 73 2 ++ ++$RLR test-config.73 --force ++ ++checkoutput < +Date: Mon, 19 Sep 2016 02:25:33 +0100 +Subject: [PATCH 1/2] config.c: drop comparison of uid/gid with undetermined + values + +... loaded from uninitialized stat buffer on the stack of do_mkdir() + +If a directory is created (ie createolddir), struct sb must be updated +in order to get appropriate st_uid and st_gid. Test made later to known +if chown() should be performed is inadequate since sb is never updated. + +As per discussion in https://github.com/logrotate/logrotate/pull/59, +removing the comparison to unsure newly created directory always get +owner and group changed. + +Before: + ./logrotate -f /etc/logrotate.conf + uid: 250, sb.st_uid: 250 + gid: 250, sb.st_gid: 250 + +After: + ./logrotate -f /etc/logrotate.conf + uid: 250, sb.st_uid: 0 + gid: 250, sb.st_gid: 250 + +Closes #59 + +Upstream-commit: ae040a55d3a8f2bbce7860415b4ee479a024a334 +Signed-off-by: Kamil Dudka +--- + config.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/config.c b/config.c +index 493f3f7..e692ac9 100644 +--- a/config.c ++++ b/config.c +@@ -313,8 +313,7 @@ static int do_mkdir(const char *path, mode_t mode, uid_t uid, gid_t gid) { + path, strerror(errno)); + return -1; + } +- if ((uid != sb.st_uid || gid != sb.st_gid) && +- chown(path, uid, gid)) { ++ if (chown(path, uid, gid) != 0) { + message(MESS_ERROR, "error setting owner of %s to uid %d and gid %d: %s\n", + path, uid, gid, strerror(errno)); + return -1; +-- +2.7.4 + + +From d6962e20c9043152b63df6c1ca1de14161caa725 Mon Sep 17 00:00:00 2001 +From: Kamil Dudka +Date: Tue, 20 Sep 2016 18:56:24 +0200 +Subject: [PATCH 2/2] config.c: make 'createolddir' preserve sticky bit + +After calling chown() to set uid/gid on the created directory, re-apply +permission bits once again by chmod() because the sticky bit might have +been cleared by chown(). + +Upstream-commit: 3c76f48efa0d9d448528af3e40f757654458978c +Signed-off-by: Kamil Dudka +--- + config.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/config.c b/config.c +index e692ac9..64bb935 100644 +--- a/config.c ++++ b/config.c +@@ -318,7 +318,12 @@ static int do_mkdir(const char *path, mode_t mode, uid_t uid, gid_t gid) { + path, uid, gid, strerror(errno)); + return -1; + } +- } ++ if (chmod(path, mode) != 0) { ++ message(MESS_ERROR, "error setting permissions of %s to 0%o: %s\n", ++ path, mode, strerror(errno)); ++ return -1; ++ } ++ } + else if (!S_ISDIR(sb.st_mode)) { + message(MESS_ERROR, "path %s already exists, but it is not a directory\n", + path); +-- +2.7.4 + diff --git a/SOURCES/logrotate-3.8.6-diagnostic.patch b/SOURCES/logrotate-3.8.6-diagnostic.patch new file mode 100644 index 0000000..7aaf844 --- /dev/null +++ b/SOURCES/logrotate-3.8.6-diagnostic.patch @@ -0,0 +1,690 @@ +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 + diff --git a/SOURCES/logrotate-3.8.6-force.patch b/SOURCES/logrotate-3.8.6-force.patch new file mode 100644 index 0000000..7deabbd --- /dev/null +++ b/SOURCES/logrotate-3.8.6-force.patch @@ -0,0 +1,52 @@ +Index: /trunk/logrotate.c +=================================================================== +--- trunk/logrotate.c (revision 437) ++++ trunk/logrotate.c (revision 438) +@@ -831,9 +831,10 @@ + } + +- if (log->criterium == ROT_SIZE) { ++ if (force) { ++ /* user forced rotation of logs from command line */ ++ state->doRotate = 1; ++ } ++ else if (log->criterium == ROT_SIZE) { + state->doRotate = (sb.st_size >= log->threshhold); +- } else if (force) { +- /* user forced rotation of logs from command line */ +- state->doRotate = 1; + } else if (mktime(&state->lastRotated) - mktime(&now) > (25 * 3600)) { + /* 25 hours allows for DST changes as well as geographical moves */ +Index: /trunk/test/test +=================================================================== +--- trunk/test/test (revision 437) ++++ trunk/test/test (revision 438) +@@ -1335,3 +1335,16 @@ + EOF + ++cleanup 53 ++ ++# ------------------------------- Test 53 ------------------------------------ ++# test if --force works ++preptest test.log 53 1 0 ++ ++$RLR test-config.53 --force ++ ++checkoutput < +Date: Mon, 16 Feb 2015 07:42:18 +0000 +Subject: [PATCH] Fix crash when using long dateformat [nmerdan] + +Upstream-commit: 768b23c0bd94f973abf108f6e2cf4138c426f140 +Signed-off-by: Kamil Dudka +--- + logrotate.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/logrotate.c b/logrotate.c +index 82f561a..2abac3d 100644 +--- a/logrotate.c ++++ b/logrotate.c +@@ -1233,9 +1233,10 @@ int prerotateSingleLog(struct logInfo *log, int logNum, struct logState *state, + } + } + ++ /* adding 2 due to / and \0 being added by snprintf */ + rotNames->firstRotated = + malloc(strlen(rotNames->dirName) + strlen(rotNames->baseName) + +- strlen(fileext) + strlen(compext) + 30); ++ strlen(fileext) + strlen(compext) + DATEEXT_LEN + 2 ); + + if (log->flags & LOG_FLAG_DATEEXT) { + /* glob for compressed files with our pattern +-- +2.7.4 + diff --git a/SOURCES/logrotate-3.8.6-olddir-missingok.patch b/SOURCES/logrotate-3.8.6-olddir-missingok.patch new file mode 100644 index 0000000..99196ac --- /dev/null +++ b/SOURCES/logrotate-3.8.6-olddir-missingok.patch @@ -0,0 +1,99 @@ +From 1787a97828b512b4b15e618a26d0e508ec7a253b Mon Sep 17 00:00:00 2001 +From: Jan Kaluza +Date: Tue, 26 Jan 2016 12:43:21 +0100 +Subject: [PATCH] Fix 'olddir' usage with wildcard in the middle of path in the + pattern definition when the pattern did not match any log file. + +Upstream-commit: 73493ec38c5e806fa66d8c3f13259775da6282d9 +Signed-off-by: Kamil Dudka +--- + config.c | 24 ++++++++++++++++++------ + test/test | 21 +++++++++++++++++++++ + test/test-config.69.in | 10 ++++++++++ + 3 files changed, 49 insertions(+), 6 deletions(-) + create mode 100644 test/test-config.69.in + +diff --git a/config.c b/config.c +index 926d388..493f3f7 100644 +--- a/config.c ++++ b/config.c +@@ -1454,12 +1454,24 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig) + int rv; + dirName = ourDirName(newlog->files[i]); + if (stat(dirName, &sb2)) { +- message(MESS_ERROR, +- "%s:%d error verifying log file " +- "path %s: %s\n", configFile, lineNum, +- dirName, strerror(errno)); +- free(dirName); +- goto error; ++ if (!(newlog->flags & LOG_FLAG_MISSINGOK)) { ++ message(MESS_ERROR, ++ "%s:%d error verifying log file " ++ "path %s: %s\n", configFile, lineNum, ++ dirName, strerror(errno)); ++ free(dirName); ++ goto error; ++ } ++ else { ++ message(MESS_DEBUG, ++ "%s:%d verifying log file " ++ "path failed %s: %s, log is probably missing, " ++ "but missingok is set, so this is not an error.\n", ++ configFile, lineNum, ++ dirName, strerror(errno)); ++ free(dirName); ++ continue; ++ } + } + ld = alloca(strlen(dirName) + strlen(newlog->oldDir) + 2); + sprintf(ld, "%s/%s", dirName, newlog->oldDir); +diff --git a/test/test b/test/test +index 9d7618f..54d57d2 100755 +--- a/test/test ++++ b/test/test +@@ -1566,4 +1566,25 @@ test.log 0 + test.log.$DATESTRING 0 zero + EOF + ++cleanup 69 ++ ++# ------------------------------- Test 69 ------------------------------------ ++# Test olddir with wildcard in the pattern ++preptest test.log 69 1 0 ++rm -rf testdir adir bdir ++mkdir adir ++mkdir bdir ++cp test.log adir ++cp test.log bdir ++$RLR test-config.69 --force -v ++ ++checkoutput <flags & (LOG_FLAG_COPYTRUNCATE | LOG_FLAG_COPY))) { + message(MESS_ERROR, + "%s:%d olddir %s and log file %s " + "are on different devices\n", configFile, diff --git a/SOURCES/logrotate-3.8.6-r460.patch b/SOURCES/logrotate-3.8.6-r460.patch new file mode 100644 index 0000000..6805e7f --- /dev/null +++ b/SOURCES/logrotate-3.8.6-r460.patch @@ -0,0 +1,733 @@ +diff --git a/config.c b/config.c +index e6b6a53..e9992e3 100644 +--- a/config.c ++++ b/config.c +@@ -220,6 +220,61 @@ static char *readPath(const char *configFile, int lineNum, char *key, + return NULL; + } + ++static int readModeUidGid(const char *configFile, int lineNum, char *key, ++ const char *directive, mode_t *mode, uid_t *uid, ++ gid_t *gid) { ++ char u[200], g[200]; ++ int m; ++ char tmp; ++ int rc; ++ struct group *group; ++ struct passwd *pw = NULL; ++ ++ rc = sscanf(key, "%o %199s %199s%c", &m, u, g, &tmp); ++ /* We support 'key notation now */ ++ if (rc == 0) { ++ rc = sscanf(key, "%199s %199s%c", u, g, &tmp); ++ /* Simulate that we have read mode and keep the default value. */ ++ if (rc > 0) { ++ m = *mode; ++ rc += 1; ++ } ++ } ++ ++ if (rc == 4) { ++ message(MESS_ERROR, "%s:%d extra arguments for " ++ "%s\n", configFile, lineNum, directive); ++ return -1; ++ } ++ ++ if (rc > 0) { ++ *mode = m; ++ } ++ ++ if (rc > 1) { ++ pw = getpwnam(u); ++ if (!pw) { ++ message(MESS_ERROR, "%s:%d unknown user '%s'\n", ++ configFile, lineNum, u); ++ return -1; ++ } ++ *uid = pw->pw_uid; ++ endpwent(); ++ } ++ if (rc > 2) { ++ group = getgrnam(g); ++ if (!group) { ++ message(MESS_ERROR, "%s:%d unknown group '%s'\n", ++ configFile, lineNum, g); ++ return -1; ++ } ++ *gid = group->gr_gid; ++ endgrent(); ++ } ++ ++ return 0; ++} ++ + static char *readAddress(const char *configFile, int lineNum, char *key, + char **startPtr, char **buf, size_t length) + { +@@ -249,6 +304,55 @@ static char *readAddress(const char *configFile, int lineNum, char *key, + return NULL; + } + ++static int do_mkdir(const char *path, mode_t mode, uid_t uid, gid_t gid) { ++ struct stat sb; ++ ++ if (stat(path, &sb) != 0) { ++ if (mkdir(path, mode) != 0 && errno != EEXIST) { ++ message(MESS_ERROR, "error creating %s: %s\n", ++ path, strerror(errno)); ++ return -1; ++ } ++ if ((uid != sb.st_uid || gid != sb.st_gid) && ++ chown(path, uid, gid)) { ++ message(MESS_ERROR, "error setting owner of %s to uid %d and gid %d: %s\n", ++ path, uid, gid, strerror(errno)); ++ return -1; ++ } ++ } ++ else if (!S_ISDIR(sb.st_mode)) { ++ message(MESS_ERROR, "path %s already exists, but it is not a directory\n", ++ path); ++ errno = ENOTDIR; ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int mkpath(const char *path, mode_t mode, uid_t uid, gid_t gid) { ++ char *pp; ++ char *sp; ++ int rv; ++ char *copypath = strdup(path); ++ ++ rv = 0; ++ pp = copypath; ++ while (rv == 0 && (sp = strchr(pp, '/')) != 0) { ++ if (sp != pp) { ++ *sp = '\0'; ++ rv = do_mkdir(copypath, mode, uid, gid); ++ *sp = '/'; ++ } ++ pp = sp + 1; ++ } ++ if (rv == 0) { ++ rv = do_mkdir(path, mode, uid, gid); ++ } ++ free(copypath); ++ return rv; ++} ++ + static int checkFile(const char *fname) + { + int i; +@@ -330,6 +434,9 @@ static void copyLogInfo(struct logInfo *to, struct logInfo *from) + to->createGid = from->createGid; + to->suUid = from->suUid; + to->suGid = from->suGid; ++ to->olddirMode = from->olddirMode; ++ to->olddirUid = from->olddirUid; ++ to->olddirGid = from->olddirGid; + if (from->compress_options_count) { + poptDupArgv(from->compress_options_count, from->compress_options_list, + &to->compress_options_count, &to->compress_options_list); +@@ -539,6 +646,11 @@ int readAllConfigPaths(const char **paths) + .createMode = NO_MODE, + .createUid = NO_UID, + .createGid = NO_GID, ++ .olddirMode = NO_MODE, ++ .olddirUid = NO_UID, ++ .olddirGid = NO_GID, ++ .suUid = NO_UID, ++ .suGid = NO_GID, + .compress_options_list = NULL, + .compress_options_count = 0 + }; +@@ -579,13 +691,19 @@ static int globerr(const char *pathname, int theerr) + free(newlog->what); \ + newlog->what = NULL; \ + } while (0); ++#define RAISE_ERROR() \ ++ if (newlog != defConfig) { \ ++ state = STATE_ERROR; \ ++ continue; \ ++ } else { \ ++ goto error; \ ++ } + #define MAX_NESTING 16U + + static int readConfigFile(const char *configFile, struct logInfo *defConfig) + { + int fd; + char *buf, *endtag, *key = NULL; +- char foo; + off_t length; + int lineNum = 1; + unsigned long long multiplier; +@@ -595,11 +713,8 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig) + struct logInfo *newlog = defConfig; + char *start, *chptr; + char *dirName; +- struct group *group; + struct passwd *pw = NULL; + int rc; +- char createOwner[200], createGroup[200]; +- int createMode; + struct stat sb, sb2; + glob_t globResult; + const char **argv; +@@ -611,6 +726,7 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig) + static unsigned recursion_depth = 0U; + char *globerr_msg = NULL; + int in_config = 0; ++ int rv; + struct flock fd_lock = { + .l_start = 0, + .l_len = 0, +@@ -807,53 +923,22 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig) + } else if (!strcmp(key, "maillast")) { + newlog->flags &= ~LOG_FLAG_MAILFIRST; + } else if (!strcmp(key, "su")) { ++ mode_t tmp_mode = NO_MODE; + free(key); + key = isolateLine(&start, &buf, length); + if (key == NULL) + continue; + +- rc = sscanf(key, "%199s %199s%c", createOwner, +- createGroup, &foo); +- if (rc == 3) { +- message(MESS_ERROR, "%s:%d extra arguments for " +- "su\n", configFile, lineNum); +- if (newlog != defConfig) { +- state = STATE_ERROR; +- continue; +- } else { +- goto error; +- } ++ rv = readModeUidGid(configFile, lineNum, key, "su", ++ &tmp_mode, &newlog->suUid, ++ &newlog->suGid); ++ if (rv == -1) { ++ RAISE_ERROR(); + } +- +- if (rc > 0) { +- pw = getpwnam(createOwner); +- if (!pw) { +- message(MESS_ERROR, "%s:%d unknown user '%s'\n", +- configFile, lineNum, createOwner); +- if (newlog != defConfig) { +- state = STATE_ERROR; +- continue; +- } else { +- goto error; +- } +- } +- newlog->suUid = pw->pw_uid; +- endpwent(); +- } +- if (rc > 1) { +- group = getgrnam(createGroup); +- if (!group) { +- message(MESS_ERROR, "%s:%d unknown group '%s'\n", +- configFile, lineNum, createGroup); +- if (newlog != defConfig) { +- state = STATE_ERROR; +- continue; +- } else { +- goto error; +- } +- } +- newlog->suGid = group->gr_gid; +- endgrent(); ++ else if (tmp_mode != NO_MODE) { ++ message(MESS_ERROR, "%s:%d extra arguments for " ++ "su\n", configFile, lineNum); ++ RAISE_ERROR(); + } + + newlog->flags |= LOG_FLAG_SU; +@@ -863,65 +948,30 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig) + if (key == NULL) + continue; + +- rc = sscanf(key, "%o %199s %199s%c", &createMode, +- createOwner, createGroup, &foo); +- /* We support 'create notation now */ +- if (rc == 0) { +- rc = sscanf(key, "%199s %199s%c", +- createOwner, createGroup, &foo); +- /* Simulate that we have read createMode and se it +- * to NO_MODE. */ +- if (rc > 0) { +- createMode = NO_MODE; +- rc += 1; +- } +- } +- if (rc == 4) { +- message(MESS_ERROR, "%s:%d extra arguments for " +- "create\n", configFile, lineNum); +- if (newlog != defConfig) { +- state = STATE_ERROR; +- continue; +- } else { +- goto error; +- } ++ rv = readModeUidGid(configFile, lineNum, key, "create", ++ &newlog->createMode, &newlog->createUid, ++ &newlog->createGid); ++ if (rv == -1) { ++ RAISE_ERROR(); + } + +- if (rc > 0) +- newlog->createMode = createMode; +- +- if (rc > 1) { +- pw = getpwnam(createOwner); +- if (!pw) { +- message(MESS_ERROR, "%s:%d unknown user '%s'\n", +- configFile, lineNum, createOwner); +- if (newlog != defConfig) { +- state = STATE_ERROR; +- continue; +- } else { +- goto error; +- } +- } +- newlog->createUid = pw->pw_uid; +- endpwent(); +- } +- if (rc > 2) { +- group = getgrnam(createGroup); +- if (!group) { +- message(MESS_ERROR, "%s:%d unknown group '%s'\n", +- configFile, lineNum, createGroup); +- if (newlog != defConfig) { +- state = STATE_ERROR; +- continue; +- } else { +- goto error; +- } +- } +- newlog->createGid = group->gr_gid; +- endgrent(); ++ newlog->flags |= LOG_FLAG_CREATE; ++ } else if (!strcmp(key, "createolddir")) { ++ free(key); ++ key = isolateLine(&start, &buf, length); ++ if (key == NULL) ++ continue; ++ ++ rv = readModeUidGid(configFile, lineNum, key, "createolddir", ++ &newlog->olddirMode, &newlog->olddirUid, ++ &newlog->olddirGid); ++ if (rv == -1) { ++ RAISE_ERROR(); + } + +- newlog->flags |= LOG_FLAG_CREATE; ++ newlog->flags |= LOG_FLAG_OLDDIRCREATE; ++ } else if (!strcmp(key, "nocreateolddir")) { ++ newlog->flags &= ~LOG_FLAG_OLDDIRCREATE; + } else if (!strcmp(key, "nocreate")) { + newlog->flags &= ~LOG_FLAG_CREATE; + } else if (!strcmp(key, "size") || !strcmp(key, "minsize") || +@@ -945,12 +995,7 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig) + free(opt); + message(MESS_ERROR, "%s:%d unknown unit '%c'\n", + configFile, lineNum, key[l]); +- if (newlog != defConfig) { +- state = STATE_ERROR; +- continue; +- } else { +- goto error; +- } ++ RAISE_ERROR(); + } else { + multiplier = 1; + } +@@ -960,12 +1005,7 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig) + message(MESS_ERROR, "%s:%d bad size '%s'\n", + configFile, lineNum, key); + free(opt); +- if (newlog != defConfig) { +- state = STATE_ERROR; +- continue; +- } else { +- goto error; +- } ++ RAISE_ERROR(); + } + if (!strncmp(opt, "size", 4)) { + newlog->criterium = ROT_SIZE; +@@ -1015,12 +1055,7 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig) + message(MESS_ERROR, + "%s:%d bad rotation count '%s'\n", + configFile, lineNum, key); +- if (newlog != defConfig) { +- state = STATE_ERROR; +- continue; +- } else { +- goto error; +- } ++ RAISE_ERROR(); + } + } + else continue; +@@ -1034,12 +1069,7 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig) + if (*chptr || newlog->logStart < 0) { + message(MESS_ERROR, "%s:%d bad start count '%s'\n", + configFile, lineNum, key); +- if (newlog != defConfig) { +- state = STATE_ERROR; +- continue; +- } else { +- goto error; +- } ++ RAISE_ERROR(); + } + } + else continue; +@@ -1052,12 +1082,7 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig) + if (*chptr || newlog->rotateAge < 0) { + message(MESS_ERROR, "%s:%d bad maximum age '%s'\n", + configFile, lineNum, start); +- if (newlog != defConfig) { +- state = STATE_ERROR; +- continue; +- } else { +- goto error; +- } ++ RAISE_ERROR(); + } + } + else continue; +@@ -1069,12 +1094,7 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig) + freeLogItem(logAddress); + if (!(newlog->logAddress = readAddress(configFile, lineNum, + "mail", &start, &buf, length))) { +- if (newlog != defConfig) { +- state = STATE_ERROR; +- continue; +- } else { +- goto error; +- } ++ RAISE_ERROR(); + } + else continue; + } else if (!strcmp(key, "nomail")) { +@@ -1177,31 +1197,8 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig) + + if (!(newlog->oldDir = readPath(configFile, lineNum, + "olddir", &start, &buf, length))) { +- if (newlog != defConfig) { +- state = STATE_ERROR; +- continue; +- } else { +- goto error; +- } +- } +- +-#if 0 +- if (stat(newlog->oldDir, &sb)) { +- message(MESS_ERROR, "%s:%d error verifying olddir " +- "path %s: %s\n", configFile, lineNum, +- newlog->oldDir, strerror(errno)); +- free(newlog->oldDir); +- goto error; ++ RAISE_ERROR(); + } +- +- if (!S_ISDIR(sb.st_mode)) { +- message(MESS_ERROR, "%s:%d olddir path %s is not a " +- "directory\n", configFile, lineNum, +- newlog->oldDir); +- free(newlog->oldDir); +- goto error; +- } +-#endif + message(MESS_DEBUG, "olddir is now %s\n", newlog->oldDir); + } else if (!strcmp(key, "extension")) { + if ((key = isolateValue +@@ -1222,24 +1219,14 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig) + if (! + (newlog->compress_prog = + readPath(configFile, lineNum, "compress", &start, &buf, length))) { +- if (newlog != defConfig) { +- state = STATE_ERROR; +- continue; +- } else { +- goto error; +- } ++ RAISE_ERROR(); + } + + if (access(newlog->compress_prog, X_OK)) { + message(MESS_ERROR, + "%s:%d compression program %s is not an executable file\n", + configFile, lineNum, newlog->compress_prog); +- if (newlog != defConfig) { +- state = STATE_ERROR; +- continue; +- } else { +- goto error; +- } ++ RAISE_ERROR(); + } + + message(MESS_DEBUG, "compress_prog is now %s\n", +@@ -1252,24 +1239,14 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig) + (newlog->uncompress_prog = + readPath(configFile, lineNum, "uncompress", + &start, &buf, length))) { +- if (newlog != defConfig) { +- state = STATE_ERROR; +- continue; +- } else { +- goto error; +- } ++ RAISE_ERROR(); + } + + if (access(newlog->uncompress_prog, X_OK)) { + message(MESS_ERROR, + "%s:%d uncompression program %s is not an executable file\n", + configFile, lineNum, newlog->uncompress_prog); +- if (newlog != defConfig) { +- state = STATE_ERROR; +- continue; +- } else { +- goto error; +- } ++ RAISE_ERROR(); + } + + message(MESS_DEBUG, "uncompress_prog is now %s\n", +@@ -1285,12 +1262,7 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig) + } + + if (!(options = isolateLine(&start, &buf, length))) { +- if (newlog != defConfig) { +- state = STATE_ERROR; +- continue; +- } else { +- goto error; +- } ++ RAISE_ERROR(); + } + + if (poptParseArgvString(options, +@@ -1300,12 +1272,7 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig) + "%s:%d invalid compression options\n", + configFile, lineNum); + free(options); +- if (newlog != defConfig) { +- state = STATE_ERROR; +- continue; +- } else { +- goto error; +- } ++ RAISE_ERROR(); + } + + message(MESS_DEBUG, "compress_options is now %s\n", +@@ -1318,12 +1285,7 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig) + (newlog->compress_ext = + readPath(configFile, lineNum, "compress-ext", + &start, &buf, length))) { +- if (newlog != defConfig) { +- state = STATE_ERROR; +- continue; +- } else { +- goto error; +- } ++ RAISE_ERROR(); + } + + message(MESS_DEBUG, "compress_ext is now %s\n", +@@ -1484,45 +1446,57 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig) + globerr_msg = NULL; + if (!(newlog->flags & LOG_FLAG_MISSINGOK)) + goto error; +- } ++ } + +- if (newlog->oldDir) { ++ if (newlog->oldDir) { + for (i = 0; i < newlog->numFiles; i++) { + char *ld; ++ int rv; + dirName = ourDirName(newlog->files[i]); + if (stat(dirName, &sb2)) { +- message(MESS_ERROR, +- "%s:%d error verifying log file " +- "path %s: %s\n", configFile, lineNum, +- dirName, strerror(errno)); +- free(dirName); +- goto error; ++ message(MESS_ERROR, ++ "%s:%d error verifying log file " ++ "path %s: %s\n", configFile, lineNum, ++ dirName, strerror(errno)); ++ free(dirName); ++ goto error; + } +- ld = alloca(strlen(dirName) + strlen(newlog->oldDir) + +- 2); ++ ld = alloca(strlen(dirName) + strlen(newlog->oldDir) + 2); + sprintf(ld, "%s/%s", dirName, newlog->oldDir); + free(dirName); + +- if (newlog->oldDir[0] != '/') +- dirName = ld; +- else +- dirName = newlog->oldDir; +- if (stat(dirName, &sb)) { +- message(MESS_ERROR, "%s:%d error verifying olddir " +- "path %s: %s\n", configFile, lineNum, +- dirName, strerror(errno)); +- goto error; ++ if (newlog->oldDir[0] != '/') { ++ dirName = ld; ++ } ++ else { ++ dirName = newlog->oldDir; ++ } ++ ++ rv = stat(dirName, &sb); ++ if (rv) { ++ if (errno == ENOENT && newlog->flags & LOG_FLAG_OLDDIRCREATE) { ++ if (mkpath(dirName, newlog->olddirMode, ++ newlog->olddirUid, newlog->olddirGid)) { ++ goto error; ++ } ++ } ++ else { ++ message(MESS_ERROR, "%s:%d error verifying olddir " ++ "path %s: %s\n", configFile, lineNum, ++ dirName, strerror(errno)); ++ goto error; ++ } + } + + if (sb.st_dev != sb2.st_dev) { +- message(MESS_ERROR, +- "%s:%d olddir %s and log file %s " +- "are on different devices\n", configFile, +- lineNum, newlog->oldDir, newlog->files[i]); +- goto error; ++ message(MESS_ERROR, ++ "%s:%d olddir %s and log file %s " ++ "are on different devices\n", configFile, ++ lineNum, newlog->oldDir, newlog->files[i]); ++ goto error; + } + } +- } ++ } + + newlog = defConfig; + state = STATE_DEFINITION_END; +diff --git a/logrotate.8 b/logrotate.8 +index 8cb9c2f..2cd2370 100644 +--- a/logrotate.8 ++++ b/logrotate.8 +@@ -216,6 +216,16 @@ file for the omitted attributes. This option can be disabled using the + \fBnocreate\fR option. + + .TP ++\fBcreateolddir \fImode\fR \fIowner\fR \fIgroup\fR ++If the directory specified by \fBolddir\fR directive does not exist, it is ++created. \fImode\fR specifies the mode for the \fBolddir\fR directory ++in octal (the same as \fBchmod\fR(2)), \fIowner\fR specifies the user name ++who will own the \fBolddir\fR directory, and \fIgroup\fR specifies the group ++the \fBolddir\fR directory will belong to. This option can be disabled using the ++\fBnocreateolddir\fR option. ++ ++ ++.TP + \fBdaily\fR + Log files are rotated every day. + +@@ -350,6 +360,10 @@ Do not truncate the original log file in place after creating a copy + New log files are not created (this overrides the \fBcreate\fR option). + + .TP ++\fBnocreateolddir\fR ++\fBolddir\fR directory is not created by logrotate when it does not exist. ++ ++.TP + \fBnodelaycompress\fR + Do not postpone compression of the previous log file to the next rotation cycle + (this overrides the \fBdelaycompress\fR option). +diff --git a/logrotate.h b/logrotate.h +index 813418e..cf42703 100644 +--- a/logrotate.h ++++ b/logrotate.h +@@ -20,6 +20,7 @@ + #define LOG_FLAG_SHRED (1 << 10) + #define LOG_FLAG_SU (1 << 11) + #define LOG_FLAG_DATEYESTERDAY (1 << 12) ++#define LOG_FLAG_OLDDIRCREATE (1 << 13) + + #define NO_MODE ((mode_t) -1) + #define NO_UID ((uid_t) -1) +@@ -55,6 +56,9 @@ struct logInfo { + gid_t createGid; + uid_t suUid; /* switch user to this uid and group to this gid */ + gid_t suGid; ++ mode_t olddirMode; ++ uid_t olddirUid; ++ uid_t olddirGid; + /* these are at the end so they end up nil */ + const char **compress_options_list; + int compress_options_count; +diff --git a/test/test b/test/test +index 25b76a6..e9ce46f 100755 +--- a/test/test ++++ b/test/test +@@ -453,9 +453,15 @@ cleanup 13 + # ------------------------------- Test 13 ------------------------------------ + preptest test.log 13 1 0 + rm -rf testdir +-mkdir testdir + $RLR test-config.13 --force + ++ls -l|grep testdir|grep "drwx------." 2>/dev/null >/dev/null ++if [ $? != 0 ]; then ++ echo "testdir should have mode 2700, but it has:" ++ ls -l|grep testdir ++ exit 3 ++fi ++ + checkoutput </dev/null + if [ $? != 0 ]; then +- echo "test.log must not contain user:nobody:rwx" ++ echo "test.log must contain user:nobody:rwx" ++ getfacl test.log + exit 3 + fi + + getfacl test.log.1|grep "user:nobody:rwx" >/dev/null + if [ $? != 0 ]; then + echo "test.log.1 must contain user:nobody:rwx" ++ getfacl test.log.1 + exit 3 + fi + +diff --git a/test/test-config.13.in b/test/test-config.13.in +index 31a29ef..dc2efd5 100644 +--- a/test/test-config.13.in ++++ b/test/test-config.13.in +@@ -4,4 +4,5 @@ create + monthly + rotate 1 + olddir &DIR&/testdir ++ createolddir 700 &USER& &GROUP& + } diff --git a/SOURCES/logrotate-3.8.6-r465.patch b/SOURCES/logrotate-3.8.6-r465.patch new file mode 100644 index 0000000..24f846c --- /dev/null +++ b/SOURCES/logrotate-3.8.6-r465.patch @@ -0,0 +1,16 @@ +Index: /trunk/logrotate.8 +=================================================================== +--- a/logrotate.8 (revision 464) ++++ b/logrotate.8 (revision 465) +@@ -391,7 +391,8 @@ + .TP + \fBolddir \fIdirectory\fR +-Logs are moved into \fIdirectory\fR for rotation. The \fIdirectory\fR +-must be on the same physical device as the log file being rotated, +-and is assumed to be relative to the directory holding the log file ++Logs are moved into \fIdirectory\fR for rotation. The \fIdirectory\fR must be ++on the same physical device as the log file being rotated, unless \fBcopy\fR, ++\fBcopytruncate\fR or \fBrenamecopy\fR option is used. The \fIdirectory\fR ++is assumed to be relative to the directory holding the log file + unless an absolute path name is specified. When this option is used all + old versions of the log end up in \fIdirectory\fR. This option may be diff --git a/SOURCES/logrotate-3.8.6-selinux.patch b/SOURCES/logrotate-3.8.6-selinux.patch new file mode 100644 index 0000000..68ee1a9 --- /dev/null +++ b/SOURCES/logrotate-3.8.6-selinux.patch @@ -0,0 +1,234 @@ +From e90a98395a8c4bc265067519c450360481dff1f3 Mon Sep 17 00:00:00 2001 +From: Kamil Dudka +Date: Tue, 11 Oct 2016 18:41:56 +0200 +Subject: [PATCH 1/2] copyTruncate: factor out handling of SELinux context + +... to separate functions + +Closes #72 + +Upstream-commit: c5bff8adcece162746c68834fa1526dd45ca7bd0 +Signed-off-by: Kamil Dudka +--- + logrotate.c | 117 ++++++++++++++++++++++++++++++++++++++---------------------- + 1 file changed, 74 insertions(+), 43 deletions(-) + +diff --git a/logrotate.c b/logrotate.c +index 2abac3d..6270995 100644 +--- a/logrotate.c ++++ b/logrotate.c +@@ -251,6 +251,72 @@ static unsigned hashIndex(const char *fn) + return hash % hashSize; + } + ++static int setSecCtx(int fdSrc, const char *src, void **pPrevCtx) ++{ ++#ifdef WITH_SELINUX ++ security_context_t srcCtx; ++ *pPrevCtx = NULL; ++ ++ if (!selinux_enabled) ++ /* pretend success */ ++ return 0; ++ ++ /* read security context of fdSrc */ ++ if (fgetfilecon_raw(fdSrc, &srcCtx) < 0) { ++ if (errno == ENOTSUP) ++ /* pretend success */ ++ return 0; ++ ++ message(MESS_ERROR, "getting file context %s: %s\n", src, ++ strerror(errno)); ++ return selinux_enforce; ++ } ++ ++ /* save default security context for restoreSecCtx() */ ++ if (getfscreatecon_raw((security_context_t *)pPrevCtx) < 0) { ++ message(MESS_ERROR, "getting default context: %s\n", strerror(errno)); ++ return selinux_enforce; ++ } ++ ++ /* set default security context to match fdSrc */ ++ if (setfscreatecon_raw(srcCtx) < 0) { ++ message(MESS_ERROR, "setting default context to %s: %s\n", srcCtx, ++ strerror(errno)); ++ freecon(srcCtx); ++ return selinux_enforce; ++ } ++ ++ message(MESS_DEBUG, "set default create context to %s\n", srcCtx); ++ freecon(srcCtx); ++#else ++ (void) fdSrc; ++ (void) src; ++ (void) pPrevCtx; ++#endif ++ return 0; ++} ++ ++static void restoreSecCtx(void **pPrevCtx) ++{ ++#ifdef WITH_SELINUX ++ const security_context_t prevCtx = (security_context_t) *pPrevCtx; ++ if (!prevCtx) ++ /* no security context saved for restoration */ ++ return; ++ ++ /* set default security context to the previously stored one */ ++ if (selinux_enabled && setfscreatecon_raw(prevCtx) < 0) ++ message(MESS_ERROR, "setting default context to %s: %s\n", prevCtx, ++ strerror(errno)); ++ ++ /* free the memory allocated to save the security context */ ++ freecon(prevCtx); ++ *pPrevCtx = NULL; ++#else ++ (void) pPrevCtx; ++#endif ++} ++ + static struct logState *newState(const char *fn) + { + struct tm now = *localtime(&nowSecs); +@@ -679,6 +745,7 @@ static int copyTruncate(char *currLog, char *saveLog, struct stat *sb, + { + char buf[BUFSIZ]; + int fdcurr = -1, fdsave = -1; ++ void *prevCtx; + ssize_t cnt; + + message(MESS_DEBUG, "copying %s to %s\n", currLog, saveLog); +@@ -689,48 +756,18 @@ static int copyTruncate(char *currLog, char *saveLog, struct stat *sb, + strerror(errno)); + return 1; + } +-#ifdef WITH_SELINUX +- if (selinux_enabled) { +- security_context_t oldContext; +- if (fgetfilecon_raw(fdcurr, &oldContext) >= 0) { +- if (getfscreatecon_raw(&prev_context) < 0) { +- message(MESS_ERROR, +- "getting default context: %s\n", +- strerror(errno)); +- if (selinux_enforce) { +- freecon(oldContext); +- close(fdcurr); +- return 1; +- } +- } +- if (setfscreatecon_raw(oldContext) < 0) { +- message(MESS_ERROR, +- "setting file context %s to %s: %s\n", +- saveLog, oldContext, strerror(errno)); +- if (selinux_enforce) { +- freecon(oldContext); +- close(fdcurr); +- return 1; +- } +- } +- message(MESS_DEBUG, "set default create context\n"); +- freecon(oldContext); +- } else { +- if (errno != ENOTSUP) { +- message(MESS_ERROR, "getting file context %s: %s\n", +- currLog, strerror(errno)); +- if (selinux_enforce) { +- return 1; +- } +- } +- } ++ ++ if (setSecCtx(fdcurr, currLog, &prevCtx) != 0) { ++ /* error msg already printed */ ++ close(fdcurr); ++ return 1; + } +-#endif + #ifdef WITH_ACL + if ((prev_acl = acl_get_fd(fdcurr)) == NULL) { + if (!ACL_NOT_WELL_SUPPORTED(errno)) { + message(MESS_ERROR, "getting file ACL %s: %s\n", + currLog, strerror(errno)); ++ restoreSecCtx(&prevCtx); + close(fdcurr); + return 1; + } +@@ -738,13 +775,7 @@ static int copyTruncate(char *currLog, char *saveLog, struct stat *sb, + #endif /* WITH_ACL */ + fdsave = + createOutputFile(saveLog, O_WRONLY | O_CREAT, sb, prev_acl, 0); +-#ifdef WITH_SELINUX +- if (selinux_enabled) { +- setfscreatecon_raw(prev_context); +- freecon(prev_context); +- prev_context = NULL; +- } +-#endif ++ restoreSecCtx(&prevCtx); + #ifdef WITH_ACL + if (prev_acl) { + acl_free(prev_acl); +-- +2.7.4 + + +From 0ed7a45533a3d9d2237c742a2de03faba1b2e35f Mon Sep 17 00:00:00 2001 +From: Kamil Dudka +Date: Tue, 11 Oct 2016 18:53:18 +0200 +Subject: [PATCH 2/2] compressLogFile: explicitly preserve SELinux context + +If we use options 'compress' and 'sharedscripts' together, the rotated +(and compressed) log files may end up with a wrong security context in +case multiple files with different security contexts are rotated in a +row. + +Closes #72 + +Upstream-commit: 57458d5424eebf0c7912eefe955e4d7b0f49fd15 +Signed-off-by: Kamil Dudka +--- + logrotate.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/logrotate.c b/logrotate.c +index 6270995..20f6ea5 100644 +--- a/logrotate.c ++++ b/logrotate.c +@@ -558,6 +558,7 @@ static int compressLogFile(char *name, struct logInfo *log, struct stat *sb) + int outFile; + int i; + int status; ++ void *prevCtx; + + message(MESS_DEBUG, "compressing log with: %s\n", log->compress_prog); + if (debug) +@@ -578,11 +579,18 @@ static int compressLogFile(char *name, struct logInfo *log, struct stat *sb) + return 1; + } + ++ if (setSecCtx(inFile, name, &prevCtx) != 0) { ++ /* error msg already printed */ ++ close(inFile); ++ return 1; ++ } ++ + #ifdef WITH_ACL + if ((prev_acl = acl_get_fd(inFile)) == NULL) { + if (!ACL_NOT_WELL_SUPPORTED(errno)) { + message(MESS_ERROR, "getting file ACL %s: %s\n", + name, strerror(errno)); ++ restoreSecCtx(&prevCtx); + close(inFile); + return 1; + } +@@ -591,6 +599,7 @@ static int compressLogFile(char *name, struct logInfo *log, struct stat *sb) + + outFile = + createOutputFile(compressedName, O_RDWR | O_CREAT, sb, prev_acl, 0); ++ restoreSecCtx(&prevCtx); + #ifdef WITH_ACL + if (prev_acl) { + acl_free(prev_acl); +-- +2.7.4 + diff --git a/SOURCES/logrotate-3.8.6-sortglob.patch b/SOURCES/logrotate-3.8.6-sortglob.patch new file mode 100644 index 0000000..6537631 --- /dev/null +++ b/SOURCES/logrotate-3.8.6-sortglob.patch @@ -0,0 +1,209 @@ +diff --git a/logrotate.c b/logrotate.c +index 174a26b..4ef044e 100644 +--- a/logrotate.c ++++ b/logrotate.c +@@ -77,6 +77,11 @@ struct logNames { + char *baseName; + }; + ++struct compData { ++ int prefix_len; ++ const char *dformat; ++}; ++ + struct logStates { + LIST_HEAD(stateSet, logState) head; + } **states; +@@ -142,6 +147,34 @@ int switch_user_permanently(const struct logInfo *log) { + return 0; + } + ++static int compGlobResult(const void *result1, const void *result2, void *data) { ++ struct tm time; ++ time_t t1, t2; ++ struct compData *d = (struct compData *) data; ++ const char *r1 = *(const char **)(result1); ++ const char *r2 = *(const char **)(result2); ++ ++ memset(&time, 0, sizeof(struct tm)); ++ strptime(r1 + d->prefix_len, d->dformat, &time); ++ t1 = mktime(&time); ++ ++ memset(&time, 0, sizeof(struct tm)); ++ strptime(r2 + d->prefix_len, d->dformat, &time); ++ t2 = mktime(&time); ++ ++ if (t1 < t2) return -1; ++ if (t1 > t2) return 1; ++ return 0; ++} ++ ++static void sortGlobResult(glob_t *result, int prefix_len, const char *dformat) { ++ struct compData d; ++ if (!dformat || *dformat == '\0') return; ++ d.prefix_len = prefix_len; ++ d.dformat = dformat; ++ qsort_r(result->gl_pathv, result->gl_pathc, sizeof(char *), compGlobResult, &d); ++} ++ + static void unescape(char *arg) + { + char *p = arg; +@@ -923,7 +956,7 @@ int prerotateSingleLog(struct logInfo *log, int logNum, struct logState *state, + #define DATEEXT_LEN 64 + #define PATTERN_LEN (DATEEXT_LEN * 2) + char dext_str[DATEEXT_LEN]; +- char dformat[DATEEXT_LEN]; ++ char dformat[DATEEXT_LEN] = ""; + char dext_pattern[PATTERN_LEN]; + char *dext; + +@@ -1112,6 +1145,7 @@ int prerotateSingleLog(struct logInfo *log, int logNum, struct logState *state, + } + rc = glob(glob_pattern, 0, globerr, &globResult); + if (!rc && globResult.gl_pathc > 0) { ++ sortGlobResult(&globResult, strlen(rotNames->dirName) + 1 + strlen(rotNames->baseName), dformat); + for (i = 0; i < globResult.gl_pathc && !hasErrors; i++) { + struct stat sbprev; + +@@ -1176,6 +1210,7 @@ int prerotateSingleLog(struct logInfo *log, int logNum, struct logState *state, + /* remove the first (n - rotateCount) matches + * no real rotation needed, since the files have + * the date in their name */ ++ sortGlobResult(&globResult, strlen(rotNames->dirName) + 1 + strlen(rotNames->baseName), dformat); + for (i = 0; i < globResult.gl_pathc; i++) { + if (!stat((globResult.gl_pathv)[i], &fst_buf)) { + if ((i <= ((int) globResult.gl_pathc - rotateCount)) +diff --git a/test/test b/test/test +index 793bf77..25b76a6 100755 +--- a/test/test ++++ b/test/test +@@ -1347,4 +1347,73 @@ test.log 0 + test.log.1 0 zero + EOF + ++cleanup 54 ++ ++# ------------------------------- Test 54 ------------------------------------ ++# removing last log file when using %Y-%m-%d ++rm -f *test.log* ++preptest test.log 54 1 0 ++ ++DATE="" ++for i in {1..60} ++do ++ DATE=$(/bin/date "+%Y-%m-%d" --date "$i day ago" 2>/dev/null) ++ echo "x" > test.log-$DATE ++done ++ ++$RLR test-config.54 --force ++ ++if [ -e test.log-$DATE ]; then ++ echo "File test.log-$DATE should not exist (it should be deleted)" ++ exit 3 ++fi ++ ++rm -f *test.log* ++ ++cleanup 55 ++ ++# ------------------------------- Test 55 ------------------------------------ ++# removing last log file when using %s and hourly ++rm -f *test.log* ++preptest test.log 55 1 0 ++ ++DATE="" ++for i in {1..60} ++do ++ DATE=$(/bin/date "+%s" --date "$i hour ago" 2>/dev/null) ++ echo "x" > test.log-$DATE.gz ++done ++ ++$RLR test-config.55 --force ++ ++if [ -e test.log-$DATE.gz ]; then ++ echo "File test.log-$DATE.gz should not exist (it should be deleted)" ++ exit 3 ++fi ++ ++rm -f *test.log* ++ ++cleanup 56 ++ ++# ------------------------------- Test 56 ------------------------------------ ++# removing last log file when using %d-%m-%Y ++rm -f *test.log* ++preptest test.log 56 1 0 ++ ++DATE="" ++for i in {1..60} ++do ++ DATE=$(/bin/date "+%d-%m-%Y" --date "$i day ago" 2>/dev/null) ++ echo "x" > test.log-$DATE ++done ++ ++$RLR test-config.56 --force ++ ++if [ -e test.log-$DATE ]; then ++ echo "File test.log-$DATE should not exist (it should be deleted)" ++ exit 3 ++fi ++ ++rm -f *test.log* ++ + cleanup +diff --git a/test/test-config.54.in b/test/test-config.54.in +new file mode 100644 +index 0000000..c946af1 +--- /dev/null ++++ b/test/test-config.54.in +@@ -0,0 +1,8 @@ ++create ++ ++&DIR&/test.log { ++ daily ++ dateext ++ dateformat -%Y-%m-%d ++ rotate 60 ++} +diff --git a/test/test-config.55.in b/test/test-config.55.in +new file mode 100644 +index 0000000..8b10ad1 +--- /dev/null ++++ b/test/test-config.55.in +@@ -0,0 +1,21 @@ ++create ++ ++# continue and throw no error message when log file is not present ++missingok ++ ++# truncate the original log file in place after creating a copy ++copytruncate ++ ++# compress the file ++compress ++ ++# do only rotate when not empty ++notifempty ++ ++&DIR&/test.log { ++ hourly ++ dateext ++ dateformat -%s ++ rotate 60 ++ nosharedscripts ++} +diff --git a/test/test-config.56.in b/test/test-config.56.in +new file mode 100644 +index 0000000..adaf2a5 +--- /dev/null ++++ b/test/test-config.56.in +@@ -0,0 +1,8 @@ ++create ++ ++&DIR&/test.log { ++ daily ++ dateext ++ dateformat -%d-%m-%Y ++ rotate 60 ++} diff --git a/SOURCES/logrotate-3.8.6-state-clean.patch b/SOURCES/logrotate-3.8.6-state-clean.patch new file mode 100644 index 0000000..91ba272 --- /dev/null +++ b/SOURCES/logrotate-3.8.6-state-clean.patch @@ -0,0 +1,272 @@ +diff --git a/logrotate.c b/logrotate.c +index 9faf341..06b7100 100644 +--- a/logrotate.c ++++ b/logrotate.c +@@ -62,11 +62,12 @@ extern int asprintf(char **str, const char *fmt, ...); + #endif + + struct logState { +- char *fn; +- struct tm lastRotated; /* only tm_hour, tm_mday, tm_mon, tm_year are good! */ +- struct stat sb; +- int doRotate; +- LIST_ENTRY(logState) list; ++ char *fn; ++ struct tm lastRotated; /* only tm_hour, tm_mday, tm_mon, tm_year are good! */ ++ struct stat sb; ++ int doRotate; ++ int isUsed; /* True if there is real log file in system for this state. */ ++ LIST_ENTRY(logState) list; + }; + + struct logNames { +@@ -204,23 +205,17 @@ static void unescape(char *arg) + } + + #define HASH_SIZE_MIN 64 +-static int allocateHash(void) ++static int allocateHash(unsigned int hs) + { +- struct logInfo *log; +- unsigned int hs; + int i; + +- hs = 0; +- +- for (log = logs.tqh_first; log != NULL; log = log->list.tqe_next) +- hs += log->numFiles; +- +- hs *= 2; +- + /* Enforce some reasonable minimum hash size */ + if (hs < HASH_SIZE_MIN) + hs = HASH_SIZE_MIN; + ++ message(MESS_DEBUG, "Allocating hash table for state file, size %lu B\n", ++ hs * (sizeof(struct logStates *) + sizeof(struct logState) ) ); ++ + states = calloc(hs, sizeof(struct logStates *)); + if (states == NULL) { + message(MESS_ERROR, "could not allocate memory for " +@@ -271,6 +266,7 @@ static struct logState *newState(const char *fn) + } + + new->doRotate = 0; ++ new->isUsed = 0; + + memset(&new->lastRotated, 0, sizeof(new->lastRotated)); + new->lastRotated.tm_hour = now.tm_hour; +@@ -850,9 +846,10 @@ int findNeedRotating(struct logInfo *log, int logNum, int force) + return 1; + } + +- state = findState(log->files[logNum]); +- state->doRotate = 0; +- state->sb = sb; ++ state = findState(log->files[logNum]); ++ state->doRotate = 0; ++ state->sb = sb; ++ state->isUsed = 1; + + if ((sb.st_mode & S_IFMT) == S_IFLNK) { + message(MESS_DEBUG, " log %s is symbolic link. Rotation of symbolic" +@@ -1820,6 +1817,8 @@ static int writeState(char *stateFilename) + int fdsave; + struct stat sb; + char *tmpFilename = NULL; ++ struct tm now = *localtime(&nowSecs); ++ time_t now_time, last_time; + + tmpFilename = malloc(strlen(stateFilename) + 5 ); + if (tmpFilename == NULL) { +@@ -1924,9 +1923,22 @@ static int writeState(char *stateFilename) + if (bytes < 0) + error = bytes; + ++#define SECONDS_IN_YEAR 31556926 ++ + for (i = 0; i < hashSize && error == 0; i++) { + for (p = states[i]->head.lh_first; p != NULL && error == 0; + p = p->list.le_next) { ++ ++ /* Skip states which are not used for more than a year. */ ++ now_time = mktime(&now); ++ last_time = mktime(&p->lastRotated); ++ if (!p->isUsed && difftime(now_time, last_time) > SECONDS_IN_YEAR) { ++ message(MESS_DEBUG, "Removing %s from state file, " ++ "because it does not exist and has not been rotated for one year\n", ++ p->fn); ++ continue; ++ } ++ + error = fputc('"', f) == EOF; + for (chptr = p->fn; *chptr && error == 0; chptr++) { + switch (*chptr) { +@@ -2010,23 +2022,27 @@ static int readState(char *stateFilename) + + error = stat(stateFilename, &f_stat); + +- if ((error && errno == ENOENT) || (!error && f_stat.st_size == 0)) { +- /* create the file before continuing to ensure we have write +- access to the file */ +- f = fopen(stateFilename, "w"); +- if (!f) { +- message(MESS_ERROR, "error creating state file %s: %s\n", +- stateFilename, strerror(errno)); +- return 1; ++ if ((error && errno == ENOENT) || (!error && f_stat.st_size == 0)) { ++ /* create the file before continuing to ensure we have write ++ access to the file */ ++ f = fopen(stateFilename, "w"); ++ if (!f) { ++ message(MESS_ERROR, "error creating state file %s: %s\n", ++ stateFilename, strerror(errno)); ++ return 1; ++ } ++ fprintf(f, "logrotate state -- version 2\n"); ++ fclose(f); ++ ++ if (allocateHash(64) != 0) ++ return 1; ++ ++ return 0; ++ } else if (error) { ++ message(MESS_ERROR, "error stat()ing state file %s: %s\n", ++ stateFilename, strerror(errno)); ++ return 1; + } +- fprintf(f, "logrotate state -- version 2\n"); +- fclose(f); +- return 0; +- } else if (error) { +- message(MESS_ERROR, "error stat()ing state file %s: %s\n", +- stateFilename, strerror(errno)); +- return 1; +- } + + f = fopen(stateFilename, "r"); + if (!f) { +@@ -2050,6 +2066,13 @@ static int readState(char *stateFilename) + return 1; + } + ++ /* Try to estimate how many state entries we have in the state file. ++ * We expect single entry to have around 80 characters (Of course this is ++ * just an estimation). During the testing I've found out that 200 entries ++ * per single hash entry gives good mem/performance ratio. */ ++ if (allocateHash(f_stat.st_size / 80 / 200) != 0) ++ return 1; ++ + line++; + + while (fgets(buf, sizeof(buf) - 1, f)) { +@@ -2244,9 +2267,6 @@ int main(int argc, const char **argv) + poptFreeContext(optCon); + nowSecs = time(NULL); + +- if (allocateHash() != 0) +- return 1; +- + if (readState(stateFile)) + exit(1); + +diff --git a/test/test b/test/test +index f7f3cf4..4048197 100755 +--- a/test/test ++++ b/test/test +@@ -1460,4 +1460,61 @@ EOF + checkmail test.log-$DATESTRING zero + + ++cleanup 67 ++ ++# ------------------------------- Test 67 ------------------------------------ ++# firstaction and lastaction scripts should be called if no file is rotated ++preptest test.log 67 1 0 ++ ++DATESTRING=$(/bin/date +%Y%m%d) ++TODAY=$(/bin/date "+%Y-%m-%d" 2>/dev/null) ++ ++echo removed > "test.log$TODAY" ++ ++$RLR test-config.67 --force ++ ++cat scriptout|grep firstaction >/dev/null ++if [ $? != 0 ]; then ++ echo "scriptout should contain 'firstaction'" ++ exit 3 ++fi ++ ++cat scriptout|grep lastaction >/dev/null ++if [ $? != 0 ]; then ++ echo "scriptout should contain 'lastaction'" ++ exit 3 ++fi ++ ++cleanup 68 ++ ++# ------------------------------- Test 68 ------------------------------------ ++# Old state file entries should be removed when not used. Logrotate should ++# not freeze on big state file. ++preptest test.log 68 1 0 ++ ++cat > state << EOF ++logrotate state -- version 1 ++"$PWD/test.log" 2000-1-1 ++EOF ++ ++for i in {1..200000} ++do ++ echo "\"$PWD/removed.log$i\" 2000-1-1" >> state ++done ++ ++ ++$RLR test-config.68 --force ++ ++cat state|grep test.log >/dev/null ++if [ $? != 0 ]; then ++ echo "state file should contain 'test.log'" ++ exit 3 ++fi ++ ++cat state|grep removed.log >/dev/null ++if [ $? == 0 ]; then ++ echo "state file should not contain 'removed.log'" ++ exit 3 ++fi ++ + cleanup +diff --git a/test/test-config.67.in b/test/test-config.67.in +new file mode 100644 +index 0000000..69b9fff +--- /dev/null ++++ b/test/test-config.67.in +@@ -0,0 +1,16 @@ ++create ++ ++&DIR&/test.log { ++ daily ++ dateext ++ dateformat %Y-%m-%d ++ rotate 1 ++ ++ firstaction ++ echo "firstaction" > scriptout ++ endscript ++ ++ lastaction ++ echo "lastaction" >> scriptout ++ endscript ++} +diff --git a/test/test-config.68.in b/test/test-config.68.in +new file mode 100644 +index 0000000..e8e1c79 +--- /dev/null ++++ b/test/test-config.68.in +@@ -0,0 +1,6 @@ ++create ++ ++&DIR&/test.log { ++ daily ++ rotate 1 ++} diff --git a/SOURCES/logrotate-3.8.6-statusfile.patch b/SOURCES/logrotate-3.8.6-statusfile.patch new file mode 100644 index 0000000..b2076cf --- /dev/null +++ b/SOURCES/logrotate-3.8.6-statusfile.patch @@ -0,0 +1,61 @@ +From 42c95eacd3eb37f7846967295908fc4a9db81713 Mon Sep 17 00:00:00 2001 +From: Kamil Dudka +Date: Tue, 24 Jan 2017 18:26:32 +0100 +Subject: [PATCH] Resolves: #1381719 - make /var/lib/logrotate/logrotate.status + the default state file + +--- + config.h | 2 +- + examples/logrotate.cron | 2 +- + logrotate.8 | 5 +++-- + 3 files changed, 5 insertions(+), 4 deletions(-) + +diff --git a/config.h b/config.h +index d715c5a..31f21aa 100644 +--- a/config.h ++++ b/config.h +@@ -43,5 +43,5 @@ + #endif + + #ifndef STATEFILE +-#define STATEFILE "/var/lib/logrotate.status" ++#define STATEFILE "/var/lib/logrotate/logrotate.status" + #endif +diff --git a/examples/logrotate.cron b/examples/logrotate.cron +index c6d50d4..967932e 100644 +--- a/examples/logrotate.cron ++++ b/examples/logrotate.cron +@@ -1,6 +1,6 @@ + #!/bin/sh + +-/usr/sbin/logrotate /etc/logrotate.conf ++/usr/sbin/logrotate -s /var/lib/logrotate/logrotate.status /etc/logrotate.conf + EXITVALUE=$? + if [ $EXITVALUE != 0 ]; then + /usr/bin/logger -t logrotate "ALERT exited abnormally with [$EXITVALUE]" +diff --git a/logrotate.8 b/logrotate.8 +index 2cd2370..756e655 100644 +--- a/logrotate.8 ++++ b/logrotate.8 +@@ -59,7 +59,8 @@ and mail it to the recipient. The default mail command is \fB/bin/mail + \fB\-s\fR, \fB\-\-state \fR + Tells \fBlogrotate\fR to use an alternate state file. This is useful + if logrotate is being run as a different user for various sets of +-log files. The default state file is \fI/var/lib/logrotate.status\fR. ++log files. The default state file is ++\fI/var/lib/logrotate/logrotate.status\fR. + + .TP + \fB\-\-usage\fR +@@ -538,7 +539,7 @@ Log files are rotated if the current year is not the same as the last rotation. + .SH FILES + .PD 0 + .TP 27 +-\fI/var/lib/logrotate.status\fR ++\fI/var/lib/logrotate/logrotate.status\fR + Default state file. + .TP 27 + \fI/etc/logrotate.conf\fR +-- +2.7.4 + diff --git a/SOURCES/logrotate-3.8.6-su-username.patch b/SOURCES/logrotate-3.8.6-su-username.patch new file mode 100644 index 0000000..a125e58 --- /dev/null +++ b/SOURCES/logrotate-3.8.6-su-username.patch @@ -0,0 +1,36 @@ +From a2cbd1f7bf100d11c56b72952b782a37d4a3e9de Mon Sep 17 00:00:00 2001 +From: Ewald van Geffen +Date: Fri, 12 Aug 2016 17:41:53 +0200 +Subject: [PATCH] config.c: fix parsing of 'su' directive + +... to accept usernames starting with numeric symbols + +Closes #53 + +Upstream-commit: 6c0dfc4a3d3b0535a4848d4ccb92631016a20a2d +Signed-off-by: Kamil Dudka +--- + config.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/config.c b/config.c +index 64bb935..5e7951e 100644 +--- a/config.c ++++ b/config.c +@@ -230,7 +230,12 @@ static int readModeUidGid(const char *configFile, int lineNum, char *key, + struct group *group; + struct passwd *pw = NULL; + +- rc = sscanf(key, "%o %199s %199s%c", &m, u, g, &tmp); ++ if (!strcmp("su", directive)) ++ /* do not read for the 'su' directive */ ++ rc = 0; ++ else ++ rc = sscanf(key, "%o %199s %199s%c", &m, u, g, &tmp); ++ + /* We support 'key notation now */ + if (rc == 0) { + rc = sscanf(key, "%199s %199s%c", u, g, &tmp); +-- +2.7.4 + diff --git a/SOURCES/logrotate-3.8.6-upstream-url.patch b/SOURCES/logrotate-3.8.6-upstream-url.patch new file mode 100644 index 0000000..32f1de2 --- /dev/null +++ b/SOURCES/logrotate-3.8.6-upstream-url.patch @@ -0,0 +1,36 @@ +From d37f48f732cd83792c1af156bd8d5c7cc7e12f39 Mon Sep 17 00:00:00 2001 +From: Kamil Dudka +Date: Tue, 2 Aug 2016 16:54:20 +0200 +Subject: [PATCH] logrotate.8: update references to project page + +Reported-by: Paul Campbell +Bug: https://bugzilla.redhat.com/1357215 + +Upstream-commit: bd0edbb4f820abe424b75c8427a6b2e488265eca +Signed-off-by: Kamil Dudka +--- + logrotate.8 | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/logrotate.8 b/logrotate.8 +index 468ba0e..e48dd0b 100644 +--- a/logrotate.8 ++++ b/logrotate.8 +@@ -549,12 +549,12 @@ Configuration options. + .SH SEE ALSO + .BR gzip (1) + +- ++ + + .SH AUTHORS + .nf + Erik Troan, Preston Brown, Jan Kaluza. + +- ++ + + .fi +-- +2.13.5 + diff --git a/SOURCES/logrotate-3.8.6-weekly.patch b/SOURCES/logrotate-3.8.6-weekly.patch new file mode 100644 index 0000000..c720c89 --- /dev/null +++ b/SOURCES/logrotate-3.8.6-weekly.patch @@ -0,0 +1,162 @@ +From 7cb2dde2b3423158f5cba06df0df078ab3bee09b Mon Sep 17 00:00:00 2001 +From: Kamil Dudka +Date: Wed, 7 Dec 2016 16:34:13 +0100 +Subject: [PATCH] weekly: trigger the rotation more predictably + +... by ignoring the exact time. If the (absolute) day counter +advances by 7+ days since the last rotation, a new rotation is +triggered. + +Additionally, introduce an optional argument of the 'weekly' directive +to trigger the rotation on a selected day of the week. If the argument +is omitted, default to Sunday to preserve backward compatibility. + +Closes #93 + +Upstream-commit: bd2638856dbbb6c0a47beb85fe8a8a628160772e +Signed-off-by: Kamil Dudka +--- + config.c | 19 +++++++++++++++++++ + logrotate.8 | 12 ++++++------ + logrotate.c | 39 +++++++++++++++++++++++++++++---------- + logrotate.h | 3 ++- + 4 files changed, 56 insertions(+), 17 deletions(-) + +diff --git a/config.c b/config.c +index 5e7951e..700ad85 100644 +--- a/config.c ++++ b/config.c +@@ -410,6 +410,7 @@ static void copyLogInfo(struct logInfo *to, struct logInfo *from) + if (from->oldDir) + to->oldDir = strdup(from->oldDir); + to->criterium = from->criterium; ++ to->weekday = from->weekday; + to->threshhold = from->threshhold; + to->minsize = from->minsize; + to->maxsize = from->maxsize; +@@ -1050,7 +1051,25 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig) + } else if (!strcmp(key, "monthly")) { + newlog->criterium = ROT_MONTHLY; + } else if (!strcmp(key, "weekly")) { ++ unsigned weekday; ++ char tmp; + newlog->criterium = ROT_WEEKLY; ++ free(key); ++ key = isolateLine(&start, &buf, length); ++ if (key == NULL || key[0] == '\0') { ++ /* default to Sunday if no argument was given */ ++ newlog->weekday = 0; ++ continue; ++ } ++ ++ if (1 == sscanf(key, "%u%c", &weekday, &tmp) && weekday <= 7) { ++ /* use the selected weekday, 7 means "once per week" */ ++ newlog->weekday = weekday; ++ continue; ++ } ++ message(MESS_ERROR, "%s:%d bad weekly directive '%s'\n", ++ configFile, lineNum, key); ++ goto error; + } else if (!strcmp(key, "yearly")) { + newlog->criterium = ROT_YEARLY; + } else if (!strcmp(key, "rotate")) { +diff --git a/logrotate.8 b/logrotate.8 +index 2db6f65..468ba0e 100644 +--- a/logrotate.8 ++++ b/logrotate.8 +@@ -526,12 +526,12 @@ is replaced. At startup, the taboo extension list + contains .rpmsave, .rpmorig, ~, .disabled, .dpkg\-old, .dpkg\-dist, .dpkg\-new, .cfsaved, .ucf\-old, .ucf\-dist, .ucf\-new, .rpmnew, .swp, .cfsaved, .rhn\-cfg\-tmp\-* + + .TP +-\fBweekly\fR +-Log files are rotated if the current weekday is less than the weekday +-of the last rotation or if more than a week has passed since the last +-rotation. This is normally the same as rotating logs on the first day +-of the week, but it works better if \fIlogrotate\fR is not run every +-night. ++\fBweekly\fR [\fIweekday\fR] ++Log files are rotated once each \fIweekday\fR, or if the date is advanced by at ++least 7 days since the last rotation (while ignoring the exact time). The ++\fIweekday\fR intepretation is following: 0 means Sunday, 1 means Monday, ..., ++6 means Saturday; the special value 7 means each 7 days, irrespectively of ++weekday. Defaults to 0 if the \fIweekday\fR argument is omitted. + + .TP + \fByearly\fR +diff --git a/logrotate.c b/logrotate.c +index d5da299..e056ccd 100644 +--- a/logrotate.c ++++ b/logrotate.c +@@ -842,6 +842,27 @@ static int copyTruncate(char *currLog, char *saveLog, struct stat *sb, + return 0; + } + ++/* return value similar to mktime() but the exact time is ignored */ ++static time_t mktimeFromDateOnly(const struct tm *src) ++{ ++ /* explicit struct copy to retain C89 compatibility */ ++ struct tm tmp; ++ memcpy(&tmp, src, sizeof tmp); ++ ++ /* abstract out (nullify) fields expressing the exact time */ ++ tmp.tm_hour = 0; ++ tmp.tm_min = 0; ++ tmp.tm_sec = 0; ++ return mktime(&tmp); ++} ++ ++/* return by how many days the date was advanced but ignore exact time */ ++static int daysElapsed(const struct tm *now, const struct tm *last) ++{ ++ const time_t diff = mktimeFromDateOnly(now) - mktimeFromDateOnly(last); ++ return diff / (24 * 3600); ++} ++ + int findNeedRotating(struct logInfo *log, int logNum, int force) + { + struct stat sb; +@@ -924,18 +945,16 @@ int findNeedRotating(struct logInfo *log, int logNum, int force) + state->lastRotated.tm_mon != now.tm_mon || + state->lastRotated.tm_mday != now.tm_mday || + state->lastRotated.tm_hour != now.tm_hour) { ++ int days; + switch (log->criterium) { + case ROT_WEEKLY: +- /* rotate if: +- 1) the current weekday is before the weekday of the +- last rotation +- 2) more then a week has passed since the last +- rotation */ +- state->doRotate = ((now.tm_wday < state->lastRotated.tm_wday) +- || +- ((mktime(&now) - +- mktime(&state->lastRotated)) > +- (7 * 24 * 3600))); ++ days = daysElapsed(&now, &state->lastRotated); ++ /* rotate if date is advanced by 7+ days (exact time is ignored) */ ++ state->doRotate = (days >= 7) ++ /* ... or if we have not yet rotated today */ ++ || (days >= 1 ++ /* ... and the selected weekday is today */ ++ && now.tm_wday == log->weekday); + if (!state->doRotate) { + message(MESS_DEBUG, " log does not need rotating " + "(log has been rotated at %d-%d-%d %d:%d, " +diff --git a/logrotate.h b/logrotate.h +index cf42703..f2d2103 100644 +--- a/logrotate.h ++++ b/logrotate.h +@@ -36,8 +36,9 @@ struct logInfo { + char *oldDir; + enum { ROT_HOURLY, ROT_DAYS, ROT_WEEKLY, ROT_MONTHLY, ROT_YEARLY, ROT_SIZE + } criterium; ++ int weekday; /* used by ROT_WEEKLY only */ + unsigned long long threshhold; +- unsigned long long maxsize; ++ unsigned long long maxsize; + unsigned long long minsize; + int rotateCount; + int rotateAge; +-- +2.13.5 + diff --git a/SOURCES/rwtab b/SOURCES/rwtab new file mode 100644 index 0000000..3210e47 --- /dev/null +++ b/SOURCES/rwtab @@ -0,0 +1 @@ +dirs /var/lib/logrotate diff --git a/SPECS/logrotate.spec b/SPECS/logrotate.spec new file mode 100644 index 0000000..c22af07 --- /dev/null +++ b/SPECS/logrotate.spec @@ -0,0 +1,646 @@ +Summary: Rotates, compresses, removes and mails system log files +Name: logrotate +Version: 3.8.6 +Release: 15%{?dist} +License: GPL+ +Group: System Environment/Base +URL: https://github.com/logrotate/logrotate +Source: https://fedorahosted.org/releases/l/o/logrotate/logrotate-%{version}.tar.gz +Source1: rwtab +Patch0: logrotate-3.8.6-force.patch +Patch1: logrotate-3.8.6-r465.patch +Patch2: logrotate-3.8.6-sortglob.patch +Patch3: logrotate-3.8.6-r460.patch +Patch4: logrotate-3.8.6-compress-subject.patch +Patch5: logrotate-3.8.6-olddircopy.patch +Patch6: logrotate-3.8.6-state-clean.patch + +# fix #1381719 - make /var/lib/logrotate/logrotate.status the default state file +Patch7: logrotate-3.8.6-statusfile.patch + +# fix #1192936 - provide diagnostic in case log does not need rotating +Patch9: logrotate-3.8.6-diagnostic.patch + +# fix #1375638 - make olddir respect the missingok flag +Patch10: logrotate-3.8.6-olddir-missingok.patch + +# fix #1369438 - heap buffer overflow when using long date format +Patch11: logrotate-3.8.6-longdate-crash.patch + +# fix #1377335 - make 'createolddir' preserve sticky bit +Patch12: logrotate-3.8.6-createolddir.patch + +# fix #1374331 - preserve SELinux context with 'compress' and 'sharedscripts' +Patch13: logrotate-3.8.6-selinux.patch + +# fix #1387533 - make 'su' directive accept usernames starting with digits +Patch14: logrotate-3.8.6-su-username.patch + +# fix #1461907 - make 'copy' and 'copytruncate' work together +Patch15: logrotate-3.8.6-copy-and-copytruncate.patch + +# fix #1465720 - trigger weekly rotations more predictably +Patch16: logrotate-3.8.6-weekly.patch + +# fix #1472984 - improve the error message for bad config file mode +Patch17: logrotate-3.8.6-config-mode-err.patch + +# fix #1483800 - update references to project page +Patch18: logrotate-3.8.6-upstream-url.patch + +Requires: coreutils >= 5.92 popt +BuildRequires: libselinux-devel popt-devel libacl-devel acl +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) + +%description +The logrotate utility is designed to simplify the administration of +log files on a system which generates a lot of log files. Logrotate +allows for the automatic rotation compression, removal and mailing of +log files. Logrotate can be set to handle a log file daily, weekly, +monthly or when the log file gets to a certain size. Normally, +logrotate runs as a daily cron job. + +Install the logrotate package if you need a utility to deal with the +log files on your system. + +%prep +%setup -q + +%patch0 -p1 -b .force +%patch1 -p1 -b .r465 +%patch2 -p1 -b .sortglob +%patch3 -p1 -b .r460 +%patch4 -p1 -b .compressmail +%patch5 -p1 -b .olddircopy +%patch6 -p1 -b .stateclean +%patch7 -p1 +%patch9 -p1 +%patch10 -p1 +%patch11 -p1 +%patch12 -p1 +%patch13 -p1 +%patch14 -p1 +%patch15 -p1 +%patch16 -p1 +%patch17 -p1 +%patch18 -p1 + +%build +make %{?_smp_mflags} RPM_OPT_FLAGS="$RPM_OPT_FLAGS" WITH_SELINUX=yes WITH_ACL=yes + +%check +make test + +%install +rm -rf $RPM_BUILD_ROOT +make PREFIX=$RPM_BUILD_ROOT MANDIR=%{_mandir} install +mkdir -p $RPM_BUILD_ROOT/%{_sysconfdir}/logrotate.d +mkdir -p $RPM_BUILD_ROOT/%{_sysconfdir}/cron.daily +mkdir -p $RPM_BUILD_ROOT/%{_localstatedir}/lib/logrotate + +install -p -m 644 examples/logrotate-default $RPM_BUILD_ROOT/%{_sysconfdir}/logrotate.conf +install -p -m 755 examples/logrotate.cron $RPM_BUILD_ROOT/%{_sysconfdir}/cron.daily/logrotate + +# Make sure logrotate is able to run on read-only root +mkdir -p $RPM_BUILD_ROOT/%{_sysconfdir}/rwtab.d +install -m644 %{SOURCE1} $RPM_BUILD_ROOT%{_sysconfdir}/rwtab.d/logrotate + +%pre +# If /var/lib/logrotate/logrotate.status does not exist, create it and copy +# the /var/lib/logrotate.status in it (if it exists). We have to do that in pre +# script, otherwise the /var/lib/logrotate/logrotate.status would not be there, +# because during the update, it is removed/renamed. +if [ ! -d %{_localstatedir}/lib/logrotate/ -a -f %{_localstatedir}/lib/logrotate.status ]; then + mkdir -p %{_localstatedir}/lib/logrotate + cp -a %{_localstatedir}/lib/logrotate.status %{_localstatedir}/lib/logrotate +fi + +%clean +rm -rf $RPM_BUILD_ROOT + +%files +%defattr(-,root,root) +%doc CHANGES COPYING +%attr(0755, root, root) %{_sbindir}/logrotate +%attr(0644, root, root) %{_mandir}/man8/logrotate.8* +%attr(0644, root, root) %{_mandir}/man5/logrotate.conf.5* +%attr(0700, root, root) %config(noreplace) %{_sysconfdir}/cron.daily/logrotate +%attr(0644, root, root) %config(noreplace) %{_sysconfdir}/logrotate.conf +%attr(0755, root, root) %dir %{_sysconfdir}/logrotate.d +%attr(0755, root, root) %dir %{_localstatedir}/lib/logrotate +%attr(0644, root, root) %ghost %verify(not size md5 mtime) %{_localstatedir}/lib/logrotate/logrotate.status +%config(noreplace) %{_sysconfdir}/rwtab.d/logrotate + +%changelog +* Mon Sep 25 2017 Kamil Dudka - 3.8.6-15 +- fix #1483800 - update references to project page +- fix #1472984 - improve the error message for bad config file mode +- fix #1465720 - trigger weekly rotations more predictably +- fix #1461907 - make 'copy' and 'copytruncate' work together + +* Tue Jan 24 2017 Kamil Dudka - 3.8.6-14 +- fix #1381719 - make /var/lib/logrotate/logrotate.status the default state file +- fix #1387533 - make 'su' directive accept usernames starting with digits + +* Tue Sep 13 2016 Kamil Dudka - 3.8.6-13 +- fix #1393247 - migration of state file from previous versions of logrotate +- fix #1374331 - preserve SELinux context with 'compress' and 'sharedscripts' +- fix #1377335 - make 'createolddir' preserve sticky bit +- fix #1369438 - heap buffer overflow when using long date format +- fix #1375638 - make olddir respect the missingok flag + +* Thu Jul 14 2016 Kamil Dudka - 3.8.6-12 +- make the /var/lib/logrotate directory owned by logrotate (#1272236) + +* Mon Jul 11 2016 Kamil Dudka - 3.8.6-11 +- fix #1354203 - remove the fix for bug #1321980 + +* Fri Jul 01 2016 Kamil Dudka - 3.8.6-10 +- fix #1192936 - provide diagnostic in case log does not need rotating +- fix #1321980 - do not exit if status file is corrupted + +* Fri Jul 01 2016 Jan Kaluza - 3.8.6-9 +- fix #1272236 - add missing rwtab file + +* Fri Mar 11 2016 Jan Kaluza - 3.8.6-8 +- fix #1201252 - delete unused entries in state file, fix bad performance + with big state file +- fix #1272236 - move logrotate.status to /var/lib/logrotate and add it to rwtab.d + +* Mon Nov 09 2015 Jan Kaluza - 3.8.6-7 +- fix #1163437 - support olddir on different device with copy or copytruncate + +* Tue Oct 06 2015 Jan Kaluza - 3.8.6-6 +- fix #1244156 - make filename in subject consistent when used with compress + +* Thu Apr 23 2015 Jan Kaluza - 3.8.6-5 +- mention copy/copytruncate/renamecopy influence to olddir option (#1175292) +- delete last log when dateformat cannot be sorted alphabetically (#1174208) +- mark cron.daily/logrotate as config file (#1174207) +- create olddir diectory if it does not exist (#1187161) + +* Fri Jan 24 2014 Daniel Mach - 3.8.6-4 +- Mass rebuild 2014-01-24 + +* Fri Dec 27 2013 Daniel Mach - 3.8.6-3 +- Mass rebuild 2013-12-27 + +* Mon Oct 07 2013 Jan Kaluza - 3.8.6-2 +- fix -f/--force option (#1015017) +- use mode 0700 for crontab script (#1012764) + +* Wed Jul 31 2013 Jan Kaluza - 3.8.6-1 +- new upstream version 3.8.6 + +* Wed Jul 10 2013 Jan Kaluza - 3.8.5-2 +- fix #982409 - do not crash when no logs are rotated and "sharedscripts" and + "prerotate" is used + +* Mon Jun 10 2013 Jan Kaluza - 3.8.5-1 +- new upstream version 3.8.5 + +* Tue May 14 2013 Jan Kaluza - 3.8.4-2 +- do not try to parse config files bigger than 16MB +- remove unused patches + +* Tue Apr 30 2013 Jan Kaluza - 3.8.4-1 +- new upstream version 3.8.4 + +* Thu Feb 14 2013 Fedora Release Engineering - 3.8.3-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild + +* Thu Oct 04 2012 Jan Kaluza 3.8.3-1 +- new upstream version 3.8.3 + +* Thu Jul 19 2012 Jan Kaluza 3.8.2-1 +- new upstream version 3.8.2 +- tests are enabled during build + +* Thu Jul 19 2012 Fedora Release Engineering - 3.8.1-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Wed Jan 04 2012 Jan Kaluza 3.8.1-3 +- fix #736054 - check for missing '{' in config file + +* Mon Oct 03 2011 Jan Kaluza 3.8.1-2 +- fix #742731 - man page syntax, formatting, and spelling fixes + +* Tue Sep 06 2011 Jan Kaluza 3.8.1-1 +- new upstream version 3.8.1 + +* Mon Aug 08 2011 Jan Kaluza 3.8.0-5 +- fix #723797 - added maxsize option + +* Wed Aug 01 2011 Jan Kaluza 3.8.0-4 +- fix #726980 - work properly when acl_get_fd is supported, + but acl_set_fd is not + +* Fri Jul 22 2011 Jan Kaluza 3.8.0-3 +- fix #723547 - fixed size directive parsing + +* Wed Jul 20 2011 Jan Kaluza 3.8.0-2 +- fix #722825 - do not redirect logrotate output in cron script + +* Tue Jun 21 2011 Jan Kaluza 3.8.0-1 +- new upstream version 3.8.0 +- removed unused patches + +* Tue May 31 2011 Jan Kaluza 3.7.9-11 +- fix #709034 - work properly when ACLs are not supported + +* Mon May 30 2011 Jan Kaluza 3.7.9-10 +- fix #708367 - fixed mail directive parsing + +* Mon Mar 28 2011 Jan Kaluza 3.7.9-9 +- fix #689061 - added Url + +* Mon Mar 21 2011 Jan Kaluza 3.7.9-8 +- fix #688520 - fixed CVE-2011-1154, CVE-2011-1155 and CVE-2011-1098 + +* Tue Feb 08 2011 Fedora Release Engineering - 3.7.9-7 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild + +* Wed Feb 02 2011 Jan Kaluza 3.7.9-6 +- fix #671926 - fixed crash when tabooext is used in config file + +* Wed Dec 15 2010 Jan Kaluza 3.7.9-5 +- fix #661181 - fixed SIGBUS when config file is empty or 4096 bytes +- fix #666677 - preserve ACLs when rotating files + +* Tue Oct 19 2010 Jan Kaluza 3.7.9-4 +- fix #644309 - mention all logrotate params in man page + +* Wed Sep 29 2010 Jan Kaluza 3.7.9-3 +- fix #638629 - better size directive description + +* Mon Aug 09 2010 Jan Kaluza 3.7.9-2 +- fixed AUTHORS in man page + +* Mon Jun 28 2010 Jan Kaluza 3.7.9-1 +- new upstream version 3.7.9 + +* Tue Jun 22 2010 Jan Kaluza 3.7.8-12 +- fix #602643 - update manpage to reflect scripts changes +- fix #606675 - pass currently rotated file as argument to + postrotate/prerotate script in nosharedscripts mode + +* Tue Jun 15 2010 Jan Kaluza 3.7.8-11 +- fix #603040 - do not remove log if there is an error in + rotate process + +* Tue Apr 20 2010 Jan Kaluza 3.7.8-10 +- fix #602643 - logrotate "size" directive cannot exceed + 1895825408 bytes + +* Tue Apr 20 2010 Daniel Novotny 3.7.8-9 +- revert the "create 0640 root adm" permission change (#489038) + +* Tue Apr 06 2010 Daniel Novotny 3.7.8-8 +- fix #578115 - missingok problem with globs + +* Mon Jan 11 2010 Daniel Novotny 3.7.8-7 +- fix #489038 - RFE: useful permissions on log files + +* Wed Dec 09 2009 Henrique Martins 3.7.8-6 +- fix #545919 (rotate non-writable files when copy is set) + +* Tue Sep 29 2009 Daniel Novotny 3.7.8-5 +- fix #525659 (man page for logrotate.conf) + +* Thu Sep 17 2009 Daniel Novotny 3.7.8-4 +- fix #517321 (logrotate blocking anacron) + +* Sat Jul 25 2009 Fedora Release Engineering - 3.7.8-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild + +* Wed Feb 25 2009 Fedora Release Engineering - 3.7.8-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild + +* Mon Feb 02 2009 Daniel Novotny 3.7.8-1 +- new upstream version 3.7.8 + +* Fri Nov 21 2008 Daniel Novotny 3.7.7-4 +- fix #468926 (segfault with very large /var/log/messages) + +* Thu Nov 20 2008 Daniel Novotny 3.7.7-3 +- less aggressive approach to the fix + +* Thu Nov 20 2008 Daniel Novotny 3.7.7-2 +- fix #471463 (selinux problems with logrotate) + +* Mon May 19 2008 Tomas Smetana 3.7.7-1 +- new upstream version + +* Wed Apr 23 2008 Tomas Smetana 3.7.6-4 +- improve patch for #432330 +- fix #437748 - don't forget to close log files + +* Mon Feb 11 2008 Tomas Smetana 3.7.6-3 +- fix #432330 segfault on corrupted status file + +* Mon Jan 21 2008 Tomas Smetana 3.7.6-2.2 +- fix #429454 - logrotate fails due to invalid pointer + +* Wed Jan 09 2008 Tomas Smetana 3.7.6-2.1 +- fix the selinux patch + +* Wed Jan 09 2008 Tomas Smetana 3.7.6-2 +- fix #427274 - logrotate fails to preserve SELinux file contexts +- fix #427661 - SELinux stops vsftpd from working correctly + +* Thu Sep 27 2007 Tomas Smetana 3.7.6-1.3 +- popt-devel dependency was still missing + +* Thu Sep 27 2007 Tomas Smetana 3.7.6-1.2 +- add missing dependencies to spec file + +* Thu Aug 23 2007 Tomas Smetana 3.7.6-1.1 +- rebuild + +* Tue Aug 07 2007 Tomas Smetana 3.7.6-1 +- new upstream version +- fix #248565 logrotate never rotates /var/log/btmp +- fix compile warnings +- tabooext accepts wildcards (related #247816) +- fix minor errors and update man page (related #250059) +- fix handling of size directive (related #247410) + +* Thu May 31 2007 Tomas Smetana 3.7.5-5 +- fix ignoring pre/postrotate arguments (related #241766) + +* Wed May 23 2007 Tomas Smetana 3.7.5-4 +- use dateext in the default config file (#240292) +- add options to use shred for deleting files -- adapt patch sent by + Peter Eckersley (#239934) +- ignore .cfsaved files by default (#223476) + +* Sat Mar 31 2007 Peter Vrabec 3.7.5-3 +- add error checking before running prerotate and postrotate scripts + +* Thu Mar 29 2007 Peter Vrabec 3.7.5-2 +- fix error hadnling after prerotate, postrotate, firstaction + script failure. (http://qa.mandriva.com/show_bug.cgi?id=29979) + +* Thu Mar 01 2007 Peter Vrabec 3.7.5-1 +- new upstream release. + +* Fri Feb 09 2007 Peter Vrabec 3.7.4-13 +- another spec file fixes (#226104) + +* Thu Feb 08 2007 Peter Vrabec 3.7.4-12 +- fix problem with compress_options_list (#227706) +- fix spec file to meet Fedora standards (#226104) + +* Tue Jan 23 2007 Peter Vrabec 3.7.4-11 +- logrotate won't stop if there are some errors in configuration + or glob failures (#166510, #182062) + +* Wed Jan 10 2007 Peter Vrabec 3.7.4-10 +- fix some rpmlint issues + +* Tue Jan 09 2007 Peter Vrabec 3.7.4-9 +- allow multibyte characters in readPath() (#122145) + +* Fri Jan 05 2007 Peter Vrabec 3.7.4-8 +- "size" option was ignored in config files (#221341) + +* Sun Oct 01 2006 Jesse Keating - 3.7.4-7 +- rebuilt for unwind info generation, broken in gcc-4.1.1-21 + +* Tue Sep 26 2006 Peter Vrabec 3.7.4-6 +- fix leaking file descriptor (#205072) + +* Wed Aug 09 2006 Dan Walsh 3.7.4-5 +- Use selinux raw functions + +* Mon Jul 24 2006 Peter Vrabec 3.7.4-4 +- make error message, about ignoring certain config files, + a debug message instead (#196052) + +* Wed Jul 12 2006 Jesse Keating - 3.7.4-3.1 +- rebuild + +* Tue Jun 13 2006 Peter Vrabec 3.7.4-3 +- rename ENOSUP to ENOTSUP + +* Tue Jun 13 2006 Peter Vrabec 3.7.4-2 +- clean up a couple of SELinux problems. Patch from Daniel J. Walsh. + +* Wed May 17 2006 Peter Vrabec 3.7.4-1 +- add new "minsize" option (#173088) + +* Tue Mar 28 2006 Peter Vrabec 3.7.3-3 +- correct man page "extension" option description (#185318) + +* Fri Feb 10 2006 Jesse Keating - 3.7.3-2.2.1 +- bump again for double-long bug on ppc(64) + +* Tue Feb 07 2006 Jesse Keating - 3.7.3-2.2 +- rebuilt for new gcc4.1 snapshot and glibc changes + +* Fri Dec 09 2005 Jesse Keating +- rebuilt + +* Sun Nov 13 2005 Peter Vrabec 3.7.3-2 +- fix_free_segfaults (#172918) + +* Sat Nov 12 2005 Peter Vrabec 3.7.3-1 +- new upstream release +- indent sources + +* Fri Nov 11 2005 Peter Vrabec 3.7.2-12 +- fix_free_segfaults (#172918) + +* Mon Nov 07 2005 Peter Vrabec 3.7.2-11 +- man description for "nodateext" option (#171577) +- remove not working "pattern" option (#171577) + +* Tue Oct 25 2005 Peter Vrabec 3.7.2-10 +- some more clean up (#171587) + +* Thu Oct 20 2005 Peter Vrabec 3.7.2-9 +- fix_free_segfaults (#171093) + +* Tue Oct 18 2005 Peter Vrabec 3.7.2-8 +- fix leaks of tabooExts + +* Sat Oct 15 2005 Peter Vrabec 3.7.2-7 +- fix_free_segfaults (#170904) + +* Wed Oct 12 2005 Peter Vrabec 3.7.2-6 +- code clean up (#169885) + +* Mon Oct 10 2005 Peter Vrabec 3.7.2-5 +- fix bug introduced in logrotate 3.7.2-3(#169858) +- fix some memory leaks (#169888) + +* Fri Sep 23 2005 Peter Vrabec 3.7.2-4 +- do not run compression program in debug mode (#166912) + +* Wed Sep 07 2005 Peter Vrabec 3.7.2-3 +- even when sharedscript option used, do postrotate + script before compress (#167575) + +* Wed Aug 17 2005 Peter Vrabec 3.7.2-2 +- allow yearly rotations(#134612) + +* Mon Aug 01 2005 Peter Vrabec 3.7.2-1 +- new upstream release + +* Tue Jul 26 2005 Peter Vrabec 3.7.1-14 +- fix some "error running script" messages + +* Tue Jul 26 2005 Peter Vrabec 3.7.1-13 +- fix man page (#163458,#163366) + +* Wed Jun 22 2005 Peter Vrabec 3.7.1-12 +- enhance logrotate with "dateext", "maxage" + +* Thu Mar 31 2005 Dan Walsh 3.7.1-10 +- use security_getenforce() instead of selinux_getenforcemode + +* Thu Mar 17 2005 Dan Walsh 3.7.1-9 +- Add selinux_getenforce() calls to work when not in enforcing mode + +* Thu Mar 17 2005 Peter Vrabec 3.7.1-8 +- rebuild + +* Tue Feb 22 2005 Peter Vrabec +- do not use tmpfile to run script anymore (#149270) + +* Fri Feb 18 2005 Peter Vrabec +- remove logrotate-3.7.1-share.patch, it doesn't solve (#140353) + +* Mon Dec 13 2004 Peter Vrabec - 3.7.1-5 +- Add section to logrotate.conf for "/var/log/btmp" (#117844) + +* Mon Dec 13 2004 Peter Vrabec - 3.7.1-4 +- Typo and missing information in man page (#139346) + +* Mon Dec 06 2004 Peter Vrabec - 3.7.1-3 +- compressed logfiles and logrotate (#140353) + +* Tue Oct 19 2004 Miloslav Trmac - 3.7.1-2 +- Fix sending mails (#131583) +- Preserve file attributes when compressing files (#121523, original patch by + Daniel Himler) + +* Fri Jul 16 2004 Elliot Lee 3.7.1-1 +- Fix #126490 typo + +* Tue Jun 15 2004 Elliot Lee +- rebuilt + +* Fri Feb 13 2004 Elliot Lee +- rebuilt + +* Mon Jan 26 2004 Dan Walsh 3.6.10-4 +- fix is_selinux_enabled call + +* Fri Sep 5 2003 Dan Walsh 3.6.10-3 +- Turn off selinux + +* Fri Sep 5 2003 Dan Walsh 3.6.10-2.sel +- Turn on selinux + +* Wed Aug 06 2003 Erik Troan +- always use compressext for the extension for compressed + files; before compresscmd and compressext had to agree +- moved all compression to one code block +- compression, scripts don't use system() anymore +- compress and maillast didn't work together properly +- delaycompress and mailfirst didn't work properly +- don't use system() for mailing (or uncompressing) logs anymore +- use "-s" for speciying the subjected of mailed logs + +* Thu Jul 24 2003 Elliot Lee 3.6.10-1 +- Fix #100546, change selinux port. + +* Wed Jul 18 2003 Dan Walsh 3.6.9-2 +- Port to SELinux 2.5 + +* Wed Jul 09 2003 Elliot Lee 3.6.9-1 +- Fix #90229, #90274, #89458, #91408 + +* Mon Jan 20 2003 Elliot Lee 3.6.8-1 +- Old patch from pm@debian.org + +* Tue Jan 14 2003 Elliot Lee 3.6.7-1 +- Fixes from bugzilla + +* Fri Nov 15 2002 Elliot Lee 3.6.6-1 +- Commit patch from Fidelis Assis + +* Thu Jun 20 2002 Elliot Lee 3.6.5-1 +- Commit fix for #65299 + +* Mon Apr 15 2002 Elliot Lee 3.6.4-1 +- Commit fix for #62560 + +* Wed Mar 13 2002 Elliot Lee 3.6.3-1 +- Apply various bugfix patches from the openwall people + +* Tue Jan 29 2002 Elliot Lee 3.6.2-1 +- Fix bug #55809 (include logrotate.status in "files") +- Fix bug #58328 (incorrect error detection when reading state file) +- Allow 'G' size specifier from bug #57242 + +* Mon Dec 10 2001 Preston Brown +- noreplace config file + +* Wed Nov 28 2001 Preston Brown 3.6-1 +- patch from Alexander Kourakos to stop the shared + postrotate/prerotate scripts from running if none of the log(s) need + rotating. All log files are now checked for rotation in one batch, + rather than sequentially. +- more fixes from Paul Martin + +* Thu Nov 8 2001 Preston Brown 3.5.10-1 +- fix from paul martin for zero-length state files + +* Tue Sep 4 2001 Preston Brown +- fix segfault when logfile is in current directory. + +* Tue Aug 21 2001 Preston Brown +- fix URL for source location + +* Thu Aug 2 2001 Preston Brown +- man page cleanups, check for negative rotation counts + +* Mon Jul 2 2001 Preston Brown +- more minor manpage updates (#45625) + +* Thu Jun 21 2001 Preston Brown 3.5.6-1 +- enable LFS support (debian bug #100810) +- quote filenames for running compress commands or pre/postrotate cmds (#21348) +- deprecate "errors" directive (see bug #16544 for explanation) +- update man page +- configurable compression command by Colm Buckley + +* Fri Jun 1 2001 Preston Brown 3.5.5-1 +- be less strict about whitespace near filenames. Patch from Paul Martin . + +* Thu Jan 4 2001 Bill Nottingham +- %%defattr + +* Wed Jan 03 2001 Preston Brown +- see CHANGES + +* Tue Aug 15 2000 Erik Troan +- see CHANGES + +* Sun Jul 23 2000 Erik Troan +- see CHANGES + +* Tue Jul 11 2000 Erik Troan +- support spaces in filenames +- added sharedscripts + +* Sun Jun 18 2000 Matt Wilson +- use %%{_mandir} for man pages + +* Thu Feb 24 2000 Erik Troan +- don't rotate lastlog + +* Thu Feb 03 2000 Erik Troan +- gzipped manpages