Hello community, here is the log from the commit of package logrotate for openSUSE:Factory checked in at 2015-07-05 17:57:32 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/logrotate (Old) and /work/SRC/openSUSE:Factory/.logrotate.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "logrotate" Changes: -------- --- /work/SRC/openSUSE:Factory/logrotate/logrotate.changes 2015-05-22 16:32:31.000000000 +0200 +++ /work/SRC/openSUSE:Factory/.logrotate.new/logrotate.changes 2015-07-05 17:57:33.000000000 +0200 @@ -1,0 +2,22 @@ +Mon Jun 22 12:53:44 UTC 2015 - kstreit...@suse.com + +- update to 3.9.1 + * 3.9.1 + - Fix off-by-one error which can lead to crash when copytruncate + is used. + * 3.9.0 + - Fix crash when using long dateformat. [nmerdan] + - Add support for %H dateformat. [czchen] + - Fix regression introduced in 3.8.9 when when rotating multiple + logs when one of them is missing. + - In the debug mode, do not skip the code-path which handles the + case when the last rotation does not exist. [Sergey Vidishev] + - Show more precise description when "log does not need rotating". + - Add new -l option to log verbose output to file. The file is + overwritten on every logrotate execution. + - Allow rotation of sparse files with copytruncate. + * update logrotate-addextension.patch +- use spec-cleaner +- remove unused PreReq tags + +------------------------------------------------------------------- Old: ---- logrotate-3.8.9.tar.gz New: ---- logrotate-3.9.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ logrotate.spec ++++++ --- /var/tmp/diff_new_pack.MQlKxd/_old 2015-07-05 17:57:34.000000000 +0200 +++ /var/tmp/diff_new_pack.MQlKxd/_new 2015-07-05 17:57:34.000000000 +0200 @@ -16,14 +16,13 @@ # -Url: https://fedorahosted.org/releases/l/o/logrotate - Name: logrotate -Version: 3.8.9 +Version: 3.9.1 Release: 0 Summary: Rotate, compress, remove, and mail system log files License: GPL-2.0+ Group: System/Base +Url: https://fedorahosted.org/releases/l/o/logrotate Source: https://fedorahosted.org/releases/l/o/%{name}/%{name}-%{version}.tar.gz Source100: %{name}-rpmlintrc Source101: %{name}.service @@ -39,9 +38,6 @@ BuildRequires: libselinux-devel BuildRequires: popt-devel BuildRequires: pkgconfig(systemd) >= 197 -PreReq: %fillup_prereq -PreReq: /bin/mv -PreReq: /bin/rm Requires: xz BuildRoot: %{_tmppath}/%{name}-%{version}-build %{?systemd_requires} @@ -64,12 +60,12 @@ %patch5 -p1 %build -make %{?_smp_mflags} CC="%__cc" RPM_OPT_FLAGS="%{optflags}" \ +make %{?_smp_mflags} CC="gcc" RPM_OPT_FLAGS="%{optflags}" \ WITH_SELINUX=yes \ WITH_ACL=yes %check -make test +make %{?_smp_mflags} test %install make PREFIX=%{buildroot} install @@ -77,8 +73,8 @@ mkdir -p %{buildroot}%{_prefix}/sbin install -m 644 examples/logrotate-default %{buildroot}%{_sysconfdir}/logrotate.conf install -m 644 examples/logrotate.wtmp %{buildroot}%{_sysconfdir}/logrotate.d/wtmp -install -D -m 0644 %{S:101} %{buildroot}%{_unitdir}/%{name}.service -install -D -m 0644 %{S:102} %{buildroot}%{_unitdir}/%{name}.timer +install -D -m 0644 %{SOURCE101} %{buildroot}%{_unitdir}/%{name}.service +install -D -m 0644 %{SOURCE102} %{buildroot}%{_unitdir}/%{name}.timer %pre #only the timer can be enabled/disabled/masked ! @@ -86,9 +82,9 @@ %post %{remove_and_set MAX_DAYS_FOR_LOG_FILES} -if [ -f /etc/logrotate.d/aaa_base ] ; then +if [ -f %{_sysconfdir}/logrotate.d/aaa_base ] ; then echo "Saving old logrotate system configuration" - mv -v /etc/logrotate.d/aaa_base /etc/logrotate.d.aaa_base.save + mv -v %{_sysconfdir}/logrotate.d/aaa_base %{_sysconfdir}/logrotate.d.aaa_base.save fi %service_add_post %{name}.service %{name}.timer @@ -106,7 +102,7 @@ %{_mandir}/man8/logrotate.8* %{_mandir}/man5/logrotate.conf.5* %config %{_sysconfdir}/logrotate.conf -%config(noreplace)/etc/logrotate.d/wtmp +%config(noreplace)%{_sysconfdir}/logrotate.d/wtmp %{_unitdir}/%{name}.service %{_unitdir}/%{name}.timer ++++++ logrotate-3.8.9.tar.gz -> logrotate-3.9.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/logrotate-3.8.9/CHANGES new/logrotate-3.9.1/CHANGES --- old/logrotate-3.8.9/CHANGES 2015-02-13 07:11:21.000000000 +0100 +++ new/logrotate-3.9.1/CHANGES 2015-04-03 09:39:35.000000000 +0200 @@ -1,3 +1,17 @@ +3.9.0 -> 3.9.1 + - Fix off-by-one error which can lead to crash when copytruncate is used. +3.8.9 -> 3.9.0 + - Fix crash when using long dateformat. [nmerdan] + - Add support for %H dateformat. [czchen] + - Fix regression introduced in 3.8.9 when when rotating multiple + logs when one of them is missing. + - In the debug mode, do not skip the code-path which handles the case when + the last rotation does not exist. [Sergey Vidishev] + - Show more precise description when "log does not need rotating".\ + - Add new -l option to log verbose output to file. The file is overwritten + on every logrotate execution. + - Allow rotation of sparse files with copytruncate. + 3.8.8 -> 3.8.9 - Add new directive "createolddir" and "nocreateolddir". These directives can be used to create the directory specified by olddir with particular diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/logrotate-3.8.9/Makefile new/logrotate-3.9.1/Makefile --- old/logrotate-3.8.9/Makefile 2015-02-13 07:11:21.000000000 +0100 +++ new/logrotate-3.9.1/Makefile 2015-04-03 09:39:35.000000000 +0200 @@ -1,7 +1,7 @@ VERSION = $(shell awk '/Version:/ { print $$2 }' logrotate.spec) OS_NAME = $(shell uname -s) LFS = $(shell echo `getconf LFS_CFLAGS 2>/dev/null`) -CFLAGS = -Wall -D_GNU_SOURCE -D$(OS_NAME) -DVERSION=\"$(VERSION)\" -DHAVE_STRPTIME=1 -DHAVE_QSORT $(RPM_OPT_FLAGS) $(LFS) +CFLAGS = -Wall -D_GNU_SOURCE -D$(OS_NAME) -DVERSION=\"$(VERSION)\" -DHAVE_STRPTIME=1 -DHAVE_QSORT -DHAVE_STRUCT_STAT_ST_BLOCKS -DHAVE_STRUCT_STAT_ST_BLKSIZE $(RPM_OPT_FLAGS) $(LFS) PROG = logrotate MAN = logrotate.8 MAN5 = logrotate.conf.5 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/logrotate-3.8.9/configure.ac new/logrotate-3.9.1/configure.ac --- old/logrotate-3.8.9/configure.ac 2015-02-13 07:11:21.000000000 +0100 +++ new/logrotate-3.9.1/configure.ac 2015-04-03 09:39:35.000000000 +0200 @@ -1,4 +1,4 @@ -AC_INIT([logrotate],[3.8.9]) +AC_INIT([logrotate],[3.9.1]) AM_INIT_AUTOMAKE AC_DEFINE(_GNU_SOURCE) @@ -7,6 +7,8 @@ AC_PROG_CC AC_PROG_CC_STDC +AC_STRUCT_ST_BLKSIZE +AC_STRUCT_ST_BLOCKS AC_CHECK_LIB([popt],[poptParseArgvString],, AC_MSG_ERROR([libpopt required but not found])) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/logrotate-3.8.9/log.c new/logrotate-3.9.1/log.c --- old/logrotate-3.8.9/log.c 2015-02-13 07:11:21.000000000 +0100 +++ new/logrotate-3.9.1/log.c 2015-04-03 09:39:35.000000000 +0200 @@ -37,75 +37,48 @@ 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); - va_end(args); - if (level == MESS_FATAL) - exit(1); + 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 (messageFile != NULL) { + va_start(args, format); + log_once(messageFile, level, format, args); + va_end(args); } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/logrotate-3.8.9/log.h new/logrotate-3.9.1/log.h --- old/logrotate-3.8.9/log.h 2015-02-13 07:11:21.000000000 +0100 +++ new/logrotate-3.9.1/log.h 2015-04-03 09:39:35.000000000 +0200 @@ -18,9 +18,6 @@ #else ; #endif -#if 0 -void log(int fd, char *format, ...); -#endif void logSetErrorFile(FILE * f); void logSetMessageFile(FILE * f); void logSetFlags(int flags); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/logrotate-3.8.9/logrotate.8 new/logrotate-3.9.1/logrotate.8 --- old/logrotate-3.8.9/logrotate.8 2015-02-13 07:11:21.000000000 +0100 +++ new/logrotate-3.9.1/logrotate.8 2015-04-03 09:39:35.000000000 +0200 @@ -48,6 +48,12 @@ correctly. .TP +\fB\-l <log_file>\fR +Tells \fBlogrotate\fR to log verbose output into the log_file. The verbose +output logged to that file is the same as when running \fBlogrotate\fR with +\fB-v\fR switch. The log file is overwritten on every logrotate execution. + +.TP \fB\-m\fR, \fB\-\-mail <command>\fR Tells \fBlogrotate\fR which command to use when mailing logs. This command should accept two arguments: 1) the subject of the message, and @@ -239,10 +245,11 @@ .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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/logrotate-3.8.9/logrotate.c new/logrotate-3.9.1/logrotate.c --- old/logrotate-3.8.9/logrotate.c 2015-02-13 07:11:21.000000000 +0100 +++ new/logrotate-3.9.1/logrotate.c 2015-04-03 09:39:35.000000000 +0200 @@ -20,6 +20,7 @@ #include <locale.h> #include <sys/types.h> #include <utime.h> +#include <stdint.h> #if defined(SunOS) #include <limits.h> @@ -72,8 +73,6 @@ #define DOEXIT exit #endif -#define ERROR_STOP_ROTATION 1 -#define ERROR_CONTINUE_ROTATION 2 struct logState { char *fn; @@ -740,12 +739,133 @@ return 0; } +/* Use a heuristic to determine whether stat buffer SB comes from a file + with sparse blocks. If the file has fewer blocks than would normally + be needed for a file of its size, then at least one of the blocks in + the file is a hole. In that case, return true. */ +static int is_probably_sparse(struct stat const *sb) +{ +#if defined(HAVE_STRUCT_STAT_ST_BLOCKS) && defined(HAVE_STRUCT_STAT_ST_BLKSIZE) + return (S_ISREG (sb->st_mode) + && sb->st_blocks < sb->st_size / sb->st_blksize); +#else + return 0; +#endif +} + +#define MIN(a,b) ((a) < (b) ? (a) : (b)) + +/* Return whether the buffer consists entirely of NULs. + Note the word after the buffer must be non NUL. */ + +static inline int is_nul (void const *buf, size_t bufsize) +{ + char const *cbuf = buf; + char const *cp = buf; + + /* Find the first nonzero *byte*, or the sentinel. */ + while (*cp++ == 0) + continue; + + return cbuf + bufsize < cp; +} + +static size_t full_write(int fd, const void *buf, size_t count) +{ + size_t total = 0; + const char *ptr = (const char *) buf; + + while (count > 0) + { + size_t n_rw; + for (;;) + { + n_rw = write (fd, buf, count); + if (errno == EINTR) + continue; + else + break; + } + if (n_rw == (size_t) -1) + break; + if (n_rw == 0) + break; + total += n_rw; + ptr += n_rw; + count -= n_rw; + } + + return total; +} + +static int sparse_copy(int src_fd, int dest_fd, struct stat *sb, + const char *saveLog, const char *currLog) +{ + int make_holes = is_probably_sparse(sb); + size_t max_n_read = SIZE_MAX; + int last_write_made_hole = 0; + off_t total_n_read = 0; + char buf[BUFSIZ + 1]; + + while (max_n_read) { + int make_hole = 0; + + ssize_t n_read = read (src_fd, buf, MIN (max_n_read, BUFSIZ)); + if (n_read < 0) { + if (errno == EINTR) { + continue; + } + message(MESS_ERROR, "error reading %s: %s\n", + currLog, strerror(errno)); + return 0; + } + + if (n_read == 0) + break; + + max_n_read -= n_read; + total_n_read += n_read; + + if (make_holes) { + /* Sentinel required by is_nul(). */ + buf[n_read] = '\1'; + + if ((make_hole = is_nul(buf, n_read))) { + if (lseek (dest_fd, n_read, SEEK_CUR) < 0) { + message(MESS_ERROR, "error seeking %s: %s\n", + saveLog, strerror(errno)); + return 0; + } + } + } + + if (!make_hole) { + size_t n = n_read; + if (full_write (dest_fd, buf, n) != n) { + message(MESS_ERROR, "error writing to %s: %s\n", + saveLog, strerror(errno)); + return 0; + } + } + + last_write_made_hole = make_hole; + } + + if (last_write_made_hole) { + if (ftruncate(dest_fd, total_n_read) < 0) { + message(MESS_ERROR, "error ftruncate %s: %s\n", + saveLog, strerror(errno)); + return 0; + } + } + + return 1; +} + static int copyTruncate(char *currLog, char *saveLog, struct stat *sb, int flags) { - char buf[BUFSIZ]; int fdcurr = -1, fdsave = -1; - ssize_t cnt; message(MESS_DEBUG, "copying %s to %s\n", currLog, saveLog); @@ -753,7 +873,7 @@ if ((fdcurr = open(currLog, ((flags & LOG_FLAG_COPY) ? O_RDONLY : O_RDWR) | O_NOFOLLOW)) < 0) { message(MESS_ERROR, "error opening %s: %s\n", currLog, strerror(errno)); - return ERROR_CONTINUE_ROTATION; + return 1; } #ifdef WITH_SELINUX if (selinux_enabled) { @@ -822,21 +942,10 @@ return 1; } - while ((cnt = read(fdcurr, buf, sizeof(buf))) > 0) { - if (write(fdsave, buf, cnt) != cnt) { - message(MESS_ERROR, "error writing to %s: %s\n", - saveLog, strerror(errno)); + if (sparse_copy(fdcurr, fdsave, sb, saveLog, currLog) != 1) { close(fdcurr); close(fdsave); return 1; - } - } - if (cnt != 0) { - message(MESS_ERROR, "error reading %s: %s\n", - currLog, strerror(errno)); - close(fdcurr); - close(fdsave); - return 1; } } @@ -928,8 +1037,15 @@ /* 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) { + 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, @@ -952,49 +1068,90 @@ ((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"); + } + } + else if (!state->doRotate) { + message(MESS_DEBUG, " log does not need rotating " + "(log has been already rotated)"); } - - if (log->maxsize && sb.st_size > log->maxsize) - state->doRotate = 1; /* 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"); - } else { - message(MESS_DEBUG, " log does not need rotating\n"); } return 0; @@ -1099,6 +1256,7 @@ 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) - 1); j += 10; @@ -1250,9 +1408,10 @@ } } + /* 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 @@ -1411,10 +1570,9 @@ } /* if the last rotation doesn't exist, that's okay */ - if (!debug && rotNames->disposeName - && access(rotNames->disposeName, F_OK)) { + if (rotNames->disposeName && access(rotNames->disposeName, F_OK)) { message(MESS_DEBUG, - "log %s doesn't exist -- won't try to " "dispose of it\n", + "log %s doesn't exist -- won't try to dispose of it\n", rotNames->disposeName); free(rotNames->disposeName); rotNames->disposeName = NULL; @@ -1501,7 +1659,7 @@ if (!ACL_NOT_WELL_SUPPORTED(errno)) { message(MESS_ERROR, "getting file ACL %s: %s\n", log->files[logNum], strerror(errno)); - hasErrors |= 1; + hasErrors = 1; } } #endif /* WITH_ACL */ @@ -1517,12 +1675,7 @@ message(MESS_ERROR, "failed to rename %s to %s: %s\n", log->files[logNum], tmpFilename, strerror(errno)); - if (errno == ENOENT) { - hasErrors |= ERROR_CONTINUE_ROTATION; - } - else { - hasErrors |= 1; - } + hasErrors = 1; } } else { @@ -1533,7 +1686,7 @@ message(MESS_ERROR, "failed to rename %s to %s: %s\n", log->files[logNum], tmpFilename, strerror(errno)); - hasErrors |= 1; + hasErrors = 1; } } @@ -1587,7 +1740,7 @@ } #endif if (fd < 0) - hasErrors |= 1; + hasErrors = 1; else { close(fd); } @@ -1605,7 +1758,7 @@ if (!hasErrors && log->flags & (LOG_FLAG_COPYTRUNCATE | LOG_FLAG_COPY) && !(log->flags & LOG_FLAG_TMPFILENAME)) { - hasErrors |= + hasErrors = copyTruncate(log->files[logNum], rotNames->finalName, &state->sb, log->flags); } @@ -1680,7 +1833,6 @@ int i, j; int hasErrors = 0; int logHasErrors[log->numFiles]; - int logHasScriptErrors[log->numFiles]; int numRotated = 0; struct logState **state; struct logNames **rotNames; @@ -1752,7 +1904,6 @@ for (i = 0; i < log->numFiles; i++) { logHasErrors[i] = findNeedRotating(log, i, force); hasErrors |= logHasErrors[i]; - logHasScriptErrors[i] = 0; /* sure is a lot of findStating going on .. */ if ((findState(log->files[i]))->doRotate) @@ -1821,8 +1972,7 @@ "error running non-shared prerotate script " "for %s of '%s'\n", log->files[j], log->pattern); } - logHasScriptErrors[j] = 1; - logHasErrors[j] = 1; + logHasErrors[j] = 1; hasErrors = 1; } } @@ -1831,7 +1981,8 @@ for (i = j; ((log->flags & LOG_FLAG_SHAREDSCRIPTS) && i < log->numFiles) || (!(log->flags & LOG_FLAG_SHAREDSCRIPTS) && i == j); i++) { - if (!logHasScriptErrors[i] && !(logHasErrors[i] & ERROR_STOP_ROTATION)) { + if (! ( (logHasErrors[i] && !(log->flags & LOG_FLAG_SHAREDSCRIPTS)) + || (hasErrors && (log->flags & LOG_FLAG_SHAREDSCRIPTS)) ) ) { logHasErrors[i] |= rotateSingleLog(log, i, state[i], rotNames[i]); hasErrors |= logHasErrors[i]; @@ -1840,7 +1991,7 @@ if (log->post && (!( - (((logHasErrors[j] & ERROR_STOP_ROTATION) || !state[j]->doRotate) && !(log->flags & LOG_FLAG_SHAREDSCRIPTS)) + ((logHasErrors[j] || !state[j]->doRotate) && !(log->flags & LOG_FLAG_SHAREDSCRIPTS)) || (hasErrors && (log->flags & LOG_FLAG_SHAREDSCRIPTS)) )) ) { @@ -1859,8 +2010,7 @@ "error running non-shared postrotate script " "for %s of '%s'\n", log->files[j], log->pattern); } - logHasScriptErrors[j] = 1; - logHasErrors[j] = 1; + logHasErrors[j] = 1; hasErrors = 1; } } @@ -1869,7 +2019,8 @@ for (i = j; ((log->flags & LOG_FLAG_SHAREDSCRIPTS) && i < log->numFiles) || (!(log->flags & LOG_FLAG_SHAREDSCRIPTS) && i == j); i++) { - if (!logHasScriptErrors[i] && !(logHasErrors[i] & ERROR_STOP_ROTATION)) { + if (! ( (logHasErrors[i] && !(log->flags & LOG_FLAG_SHAREDSCRIPTS)) + || (hasErrors && (log->flags & LOG_FLAG_SHAREDSCRIPTS)) ) ) { logHasErrors[i] |= postrotateSingleLog(log, i, state[i], rotNames[i]); hasErrors |= logHasErrors[i]; @@ -2273,6 +2424,8 @@ { int force = 0; char *stateFile = STATEFILE; + char *logFile = NULL; + FILE *logFd = 0; int rc = 0; int arg; const char **files; @@ -2290,6 +2443,7 @@ "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} }; @@ -2309,6 +2463,15 @@ 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/logrotate-3.8.9/logrotate.spec new/logrotate-3.9.1/logrotate.spec --- old/logrotate-3.8.9/logrotate.spec 2015-02-13 07:11:21.000000000 +0100 +++ new/logrotate-3.9.1/logrotate.spec 2015-04-03 09:39:35.000000000 +0200 @@ -1,6 +1,6 @@ Summary: Rotates, compresses, removes and mails system log files Name: logrotate -Version: 3.8.9 +Version: 3.9.1 Release: 1 License: GPL+ Group: System Environment/Base @@ -52,6 +52,12 @@ %attr(0644, root, root) %verify(not size md5 mtime) %config(noreplace) %{_localstatedir}/lib/logrotate.status %changelog +* Fri Apr 03 2015 Jan Kaluza <jkal...@redhat.com> 3.9.1-1 +- new upstream version + +* Fri Apr 03 2015 Jan Kaluza <jkal...@redhat.com> 3.9.0-1 +- new upstream version + * Fri Feb 13 2015 Jan Kaluza <jkal...@redhat.com> 3.8.9-1 - new upstream version diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/logrotate-3.8.9/test/test new/logrotate-3.9.1/test/test --- old/logrotate-3.8.9/test/test 2015-02-13 07:11:20.000000000 +0100 +++ new/logrotate-3.9.1/test/test 2015-04-03 09:39:35.000000000 +0200 @@ -539,7 +539,7 @@ # ------------------------------- 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 @@ -549,6 +549,14 @@ 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 <<EOF test.log 0 zero EOF @@ -809,24 +817,28 @@ getfacl test.log|grep "user:nobody:rwx" >/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 @@ -1124,7 +1136,7 @@ # ------------------------------- Test 45 ------------------------------------ # Test that prerotate and postrotate scripts are not called when sharedscripts -# is defined and one rotation fails. File test.log should still be rotated. +# is defined and one rotation fails preptest test.log 45 1 touch scriptout @@ -1139,8 +1151,7 @@ rm -f error.log checkoutput <<EOF -test.log 0 -test.log.1 0 zero +test.log 0 zero scriptout 0 EOF @@ -1494,21 +1505,111 @@ cleanup 60 # ------------------------------- Test 60 ------------------------------------ -# Rotation should continue even when first log is removed during rotation -preptest test.log 60 1 -echo test2 > test2.log +# Test we log debug output using -l option when passed. +preptest test.log 61 1 0 + +$RLR test-config.61 --force -l ./logrotate.log -$RLR test-config.60 2>error.log +DATESTRING=$(/bin/date +%Y-%m-%d-%H) -grep "error opening" error.log >/dev/null +grep "reading config file test-config.61" logrotate.log >/dev/null if [ $? != 0 ]; then - echo "No error printed, but there should be one." + echo "There is no log output in logrotate.log" exit 3 fi +rm -f logrotate.log + checkoutput <<EOF -test2.log 0 -test2.log.1 0 test2 +test.log 0 +test.log.$DATESTRING 0 zero +EOF + +cleanup 61 + +# ------------------------------- Test 61 ------------------------------------ +preptest test.log 61 1 0 + +$RLR test-config.61 --force + +DATESTRING=$(/bin/date +%Y-%m-%d-%H) + +checkoutput <<EOF +test.log 0 +test.log.$DATESTRING 0 zero +EOF + +cleanup 62 + +# ------------------------------- Test 62 ------------------------------------ +# Rotate sparse file +preptest test.log 24 1 0 + +echo -n zero > test.log +truncate -s 10M test.log +echo x >> test.log + +cp test.log test.example + +SIZE_SPARSE_OLD=$(du test.log|awk '{print $1}') +SIZE_OLD=$(du --apparent-size test.log|awk '{print $1}') +$RLR test-config.24 --force +SIZE_NEW=$(du --apparent-size test.log.1|awk '{print $1}') +SIZE_SPARSE_NEW=$(du test.log.1|awk '{print $1}') + +if [ $SIZE_OLD != $SIZE_NEW ]; then + echo "Bad apparent size of sparse logs" + echo "test.log: $SIZE_OLD" + echo "test.log.1: $SIZE_NEW" + exit 3 +fi + +if [ $SIZE_SPARSE_OLD -gt 100 ] || [ $SIZE_SPARSE_NEW -gt 100 ]; then + echo "Bad size of sparse logs" + echo "test.log: $SIZE_SPARSE_OLD" + echo "test.log.1: $SIZE_SPARSE_NEW" + exit 3 +fi + +checkoutput <<EOF +test.log 0 +test.log.1 0 zerox +EOF + +cleanup 63 + +# ------------------------------- Test 63 ------------------------------------ +# Rotate sparse file, no data should be lost when hole is in the end of file +preptest test.log 24 1 0 + +echo -n zero > test.log +truncate -s 10M test.log + +cp test.log test.example + +SIZE_SPARSE_OLD=$(du test.log|awk '{print $1}') +SIZE_OLD=$(du --apparent-size test.log|awk '{print $1}') +$RLR test-config.24 --force +SIZE_NEW=$(du --apparent-size test.log.1|awk '{print $1}') +SIZE_SPARSE_NEW=$(du test.log.1|awk '{print $1}') + +if [ $SIZE_OLD != $SIZE_NEW ]; then + echo "Bad apparent size of sparse logs" + echo "test.log: $SIZE_OLD" + echo "test.log.1: $SIZE_NEW" + exit 3 +fi + +if [ $SIZE_SPARSE_OLD -gt 100 ] || [ $SIZE_SPARSE_NEW -gt 100 ]; then + echo "Bad size of sparse logs" + echo "test.log: $SIZE_SPARSE_OLD" + echo "test.log.1: $SIZE_SPARSE_NEW" + exit 3 +fi + +checkoutput <<EOF +test.log 0 +test.log.1 0 zero EOF cleanup diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/logrotate-3.8.9/test/test-config.60.in new/logrotate-3.9.1/test/test-config.60.in --- old/logrotate-3.8.9/test/test-config.60.in 2015-02-13 07:11:20.000000000 +0100 +++ new/logrotate-3.9.1/test/test-config.60.in 1970-01-01 01:00:00.000000000 +0100 @@ -1,13 +0,0 @@ -create - -&DIR&/test.log &DIR&/test2.log { - size 1 - rotate 5 - sharedscripts - copytruncate - prerotate - if [ -e test.log ]; then - rm test.log - fi - endscript -} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/logrotate-3.8.9/test/test-config.61.in new/logrotate-3.9.1/test/test-config.61.in --- old/logrotate-3.8.9/test/test-config.61.in 1970-01-01 01:00:00.000000000 +0100 +++ new/logrotate-3.9.1/test/test-config.61.in 2015-04-03 09:39:35.000000000 +0200 @@ -0,0 +1,8 @@ +create + +&DIR&/test.log { + daily + dateext + dateformat .%Y-%m-%d-%H + rotate 1 +} ++++++ logrotate-addextension.patch ++++++ --- /var/tmp/diff_new_pack.MQlKxd/_old 2015-07-05 17:57:34.000000000 +0200 +++ /var/tmp/diff_new_pack.MQlKxd/_new 2015-07-05 17:57:34.000000000 +0200 @@ -1,9 +1,9 @@ Index: test/test =================================================================== ---- test/test.orig 2013-10-10 10:43:36.000000000 +0200 -+++ test/test 2013-11-07 21:46:37.112487860 +0100 -@@ -1511,4 +1511,27 @@ - test2.log.1 0 test2 +--- test/test.orig ++++ test/test +@@ -1599,4 +1599,27 @@ test.log 0 + test.log.1 0 zero EOF +# check rotation with extension appended to the filename @@ -32,9 +32,9 @@ cleanup Index: config.c =================================================================== ---- config.c.orig 2013-07-25 14:13:02.780567373 +0200 -+++ config.c 2013-07-25 14:13:04.196582364 +0200 -@@ -530,6 +530,7 @@ int readAllConfigPaths(const char **path +--- config.c.orig ++++ config.c +@@ -637,6 +637,7 @@ int readAllConfigPaths(const char **path .preremove = NULL, .logAddress = NULL, .extension = NULL, @@ -42,7 +42,7 @@ .compress_prog = NULL, .uncompress_prog = NULL, .compress_ext = NULL, -@@ -1217,6 +1218,19 @@ static int readConfigFile(const char *co +@@ -1220,6 +1221,19 @@ static int readConfigFile(const char *co message(MESS_DEBUG, "extension is now %s\n", newlog->extension); @@ -64,9 +64,9 @@ Index: logrotate.8 =================================================================== ---- logrotate.8.orig 2013-07-25 14:13:02.780567373 +0200 -+++ logrotate.8 2013-07-25 14:13:04.196582364 +0200 -@@ -265,6 +265,15 @@ configured to be run by cron daily. You +--- logrotate.8.orig ++++ logrotate.8 +@@ -283,6 +283,15 @@ configured to be run by cron daily. You and run \fIlogrotate\fR hourly to be able to really rotate logs hourly. .TP @@ -84,9 +84,9 @@ option (\fBifempty\fR is the default). Index: logrotate.c =================================================================== ---- logrotate.c.orig 2013-07-25 14:13:02.781567384 +0200 -+++ logrotate.c 2013-07-25 14:13:04.196582364 +0200 -@@ -964,6 +964,24 @@ int prerotateSingleLog(struct logInfo *l +--- logrotate.c.orig ++++ logrotate.c +@@ -1216,6 +1216,24 @@ int prerotateSingleLog(struct logInfo *l rotNames->baseName = strdup(ourBaseName(log->files[logNum])); @@ -113,9 +113,9 @@ (rotNames-> Index: logrotate.h =================================================================== ---- logrotate.h.orig 2013-07-25 14:13:02.781567384 +0200 -+++ logrotate.h 2013-07-25 14:13:04.196582364 +0200 -@@ -44,6 +44,7 @@ struct logInfo { +--- logrotate.h.orig ++++ logrotate.h +@@ -54,6 +54,7 @@ struct logInfo { char *pre, *post, *first, *last, *preremove; char *logAddress; char *extension; @@ -125,8 +125,8 @@ char *compress_ext; Index: test/test-config.100.in =================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ test/test-config.100.in 2013-07-25 14:13:04.196582364 +0200 +--- /dev/null ++++ test/test-config.100.in @@ -0,0 +1,7 @@ +create + @@ -137,8 +137,8 @@ +} Index: test/test-config.101.in =================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ test/test-config.101.in 2013-07-25 14:13:04.196582364 +0200 +--- /dev/null ++++ test/test-config.101.in @@ -0,0 +1,7 @@ +create +