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