From 305ad302f294ec2f8d3b4fc585d67438d462ac69 Mon Sep 17 00:00:00 2001 From: Joachim Wiberg Date: Sun, 7 Mar 2021 10:28:54 +0100 Subject: [PATCH] Refactor, reduce code duplication Signed-off-by: Joachim Wiberg --- configure.ac | 2 + src/Makefile.am | 6 ++- src/logit.c | 70 +-------------------------------- src/logrotate.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++++ src/utmp-api.c | 69 ++------------------------------ 5 files changed, 113 insertions(+), 136 deletions(-) create mode 100644 src/logrotate.c diff --git a/configure.ac b/configure.ac index f1373966..3e2b986e 100644 --- a/configure.ac +++ b/configure.ac @@ -153,6 +153,8 @@ AS_IF([test "x$enable_logit" != "xno"], [ AS_IF([test "x$enable_logrotate" != "xno"], [ AC_DEFINE(LOGROTATE_ENABLED, 1, [Enable built-in rotation of /var/log/wtmp et al.])]) +AM_CONDITIONAL(LOGROTATE, [test "x$enable_logrotate" = "xyes"]) + ### With features ############################################################################## AS_IF([test "x$with_config" != "xno"], [ AS_IF([test "x$conf" = "xyes"], [ diff --git a/src/Makefile.am b/src/Makefile.am index 833224dc..926f53f4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -19,7 +19,7 @@ endif if LOGIT pkglibexec_PROGRAMS = logit -logit_SOURCES = logit.c +logit_SOURCES = logit.c logrotate.c logit_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99 logit_CFLAGS += $(lite_CFLAGS) logit_LDADD = $(lite_LIBS) @@ -44,6 +44,10 @@ finit_SOURCES = api.c cgroup.c cgroup.h \ tty.c tty.h \ util.c util.h \ utmp-api.c utmp-api.h +if LOGROTATE +finit_SOURCES += logrotate.c +endif + pkginclude_HEADERS = cond.h finit.h helpers.h log.h plugin.h svc.h finit_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99 diff --git a/src/logit.c b/src/logit.c index b98d9c86..009f41e5 100644 --- a/src/logit.c +++ b/src/logit.c @@ -33,77 +33,9 @@ #include static const char version_info[] = PACKAGE_NAME " v" PACKAGE_VERSION; +extern int logrotate(char *file, int num, off_t sz); -static int create(char *path, mode_t mode, uid_t uid, gid_t gid) -{ - return mknod(path, S_IFREG | mode, 0) || chown(path, uid, gid); -} - -/* - * This function triggers a log rotates of @file when size >= @sz bytes - * At most @num old versions are kept and by default it starts gzipping - * .2 and older log files. If gzip is not available in $PATH then @num - * files are kept uncompressed. - */ -static int logrotate(char *file, int num, off_t sz) -{ - int cnt; - struct stat st; - - if (stat(file, &st)) - return 1; - - if (sz > 0 && S_ISREG(st.st_mode) && st.st_size > sz) { - if (num > 0) { - size_t len = strlen(file) + 10 + 1; - char ofile[len]; - char nfile[len]; - - /* First age zipped log files */ - for (cnt = num; cnt > 2; cnt--) { - snprintf(ofile, len, "%s.%d.gz", file, cnt - 1); - snprintf(nfile, len, "%s.%d.gz", file, cnt); - - /* May fail because ofile doesn't exist yet, ignore. */ - if (rename(ofile, nfile) && errno != ENOENT) - syslog(LOG_ERR, "Failed logrotate %s: %s", - ofile, strerror(errno)); - } - - for (cnt = num; cnt > 0; cnt--) { - snprintf(ofile, len, "%s.%d", file, cnt - 1); - snprintf(nfile, len, "%s.%d", file, cnt); - - /* May fail because ofile doesn't exist yet, ignore. */ - if (rename(ofile, nfile) && errno != ENOENT) { - syslog(LOG_ERR, "Failed logrotate %s: %s", - ofile, strerror(errno)); - continue; - } - - if (cnt == 2 && fexist(nfile)) { - if (systemf("gzip %s", nfile)) - continue; /* no gzip, probably */ - - (void)remove(nfile); - } - } - - if (rename(file, nfile)) - goto fallback; - create(file, st.st_mode, st.st_uid, st.st_gid); - } else { - fallback: - if (truncate(file, 0)) - syslog(LOG_ERR, "Failed truncating %s during logrotate: %s", - file, strerror(errno)); - } - } - - return 0; -} - static int checksz(FILE *fp, off_t sz) { struct stat st; diff --git a/src/logrotate.c b/src/logrotate.c new file mode 100644 index 00000000..eb3c3a3b --- /dev/null +++ b/src/logrotate.c @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2018-2021 Joachim Wiberg + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +static int recreate(char *path, mode_t mode, uid_t uid, gid_t gid) +{ + if (mknod(path, S_IFREG | mode, 0) || chown(path, uid, gid)) { + syslog(LOG_ERR, "Failed recreating %s: %s", path, strerror(errno)); + return -1; + } + + return 0; +} + +/* + * This function triggers a log rotates of @file when size >= @sz bytes + * At most @num old versions are kept and by default it starts gzipping + * .2 and older log files. If gzip is not available in $PATH then @num + * files are kept uncompressed. + */ +int logrotate(char *file, int num, off_t sz) +{ + int cnt; + struct stat st; + + if (stat(file, &st)) + return 1; + + if (sz > 0 && S_ISREG(st.st_mode) && st.st_size > sz) { + if (num > 0) { + size_t len = strlen(file) + 10 + 1; + char ofile[len]; + char nfile[len]; + + /* First age zipped log files */ + for (cnt = num; cnt > 2; cnt--) { + snprintf(ofile, len, "%s.%d.gz", file, cnt - 1); + snprintf(nfile, len, "%s.%d.gz", file, cnt); + + /* May fail because ofile doesn't exist yet, ignore. */ + if (rename(ofile, nfile) && errno != ENOENT) + syslog(LOG_ERR, "Failed logrotate %s: %s", + ofile, strerror(errno)); + } + + for (cnt = num; cnt > 0; cnt--) { + snprintf(ofile, len, "%s.%d", file, cnt - 1); + snprintf(nfile, len, "%s.%d", file, cnt); + + /* May fail because ofile doesn't exist yet, ignore. */ + if (rename(ofile, nfile) && errno != ENOENT) { + syslog(LOG_ERR, "Failed logrotate %s: %s", + ofile, strerror(errno)); + continue; + } + + if (cnt == 2 && fexist(nfile)) { + if (systemf("gzip %s", nfile)) + continue; /* no gzip, probably */ + + (void)remove(nfile); + } + } + + if (rename(file, nfile)) + goto fallback; + recreate(file, st.st_mode, st.st_uid, st.st_gid); + } else { + fallback: + if (truncate(file, 0)) + syslog(LOG_ERR, "Failed truncating %s during logrotate: %s", + file, strerror(errno)); + } + } + + return 0; +} diff --git a/src/utmp-api.c b/src/utmp-api.c index 9fb82810..8b0ba19a 100644 --- a/src/utmp-api.c +++ b/src/utmp-api.c @@ -35,6 +35,9 @@ #define MAX_NO 5 #define MAX_SZ 100 * 1024 +extern int logrotate(char *file, int num, off_t sz); + + static void utmp_strncpy(char *dst, const char *src, size_t dlen) { size_t i; @@ -46,72 +49,6 @@ static void utmp_strncpy(char *dst, const char *src, size_t dlen) dst[i] = 0; } -#ifdef LOGROTATE_ENABLED -/* - * This function triggers a log rotates of @file when size >= @sz bytes - * At most @num old versions are kept and by default it starts gzipping - * .2 and older log files. If gzip is not available in $PATH then @num - * files are kept uncompressed. - */ -static int logrotate(char *file, int num, off_t sz) -{ - int cnt; - struct stat st; - - if (stat(file, &st)) - return 1; - - if (sz > 0 && S_ISREG(st.st_mode) && st.st_size > sz) { - if (num > 0) { - size_t len = strlen(file) + 10 + 1; - char ofile[len]; - char nfile[len]; - - /* First age zipped log files */ - for (cnt = num; cnt > 2; cnt--) { - snprintf(ofile, len, "%s.%d.gz", file, cnt - 1); - snprintf(nfile, len, "%s.%d.gz", file, cnt); - - /* May fail because ofile doesn't exist yet, ignore. */ - if (rename(ofile, nfile) && errno != ENOENT) - logit(LOG_ERR, "Failed logrotate %s: %s", - ofile, strerror(errno)); - } - - for (cnt = num; cnt > 0; cnt--) { - snprintf(ofile, len, "%s.%d", file, cnt - 1); - snprintf(nfile, len, "%s.%d", file, cnt); - - /* May fail because ofile doesn't exist yet, ignore. */ - if (rename(ofile, nfile) && errno != ENOENT) { - logit(LOG_ERR, "Failed logrotate %s: %s", - ofile, strerror(errno)); - continue; - } - - if (cnt == 2 && fexist(nfile)) { - if (systemf("gzip %s", nfile)) - continue; /* no gzip, probably */ - - (void)remove(nfile); - } - } - - if (rename(file, nfile)) - goto fallback; - create(file, st.st_mode, st.st_uid, st.st_gid); - } else { - fallback: - if (truncate(file, 0)) - logit(LOG_ERR, "Failed truncating %s during logrotate: %s", - file, strerror(errno)); - } - } - - return 0; -} -#endif /* LOGROTATE_ENABLED */ - /* * Rotate /var/log/wtmp (+ btmp?) and /run/utmp *