Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 34 additions & 15 deletions data/hex_syslogd/hex_trim_syslog.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,41 @@
# Drop /var/log/messages.N retentions, oldest first, until the whole messages set
# fits the byte budget config_syslogd computes (SYSLOG_DISK_PERC of the partition).
#
# Stops at .2 and never removes messages.1. This runs from logrotate's postrotate,
# which fires *before* compression, so messages.1 is the file logrotate is about to
# compress in this same cycle -- removing it under logrotate's feet makes the cycle
# log "unable to open /var/log/messages.1 for compression: No such file or
# directory", the same class of error installing this script was meant to stop.
# Generations are discovered from what is on disk rather than counted down from a
# literal, because both halves of the old loop had drifted out of step with the
# files it was supposed to match:
#
# - it tested `-e /var/log/messages.$I` only, and every rotated generation is
# compressed. WriteLogRotateConf always emits `compress` and the global conf sets
# no `dateext`, so at postrotate time the directory holds `messages`, a still
# uncompressed `messages.1`, and `messages.2.gz` onward. The one unsuffixed
# generation that ever exists is `.1` -- which this must not touch, see below --
# so the loop could never match anything at all.
# - it started at I=14, mirroring the old global `rotate 14`. That is now
# `retention * 24` (336 at the default), so even with .gz matching it would have
# scanned 2..14 of up to 336 -- and a log that reaches 336 generations is exactly
# the busy log the budget exists for.
#
# Taking the list from the filesystem removes the coupling that broke twice.
#
# messages.1 is deliberately skipped. This runs from logrotate's postrotate, which
# fires *before* compression, so .1 is the file logrotate is about to compress in
# this same cycle -- removing it under logrotate's feet makes the cycle log
# "unable to open /var/log/messages.1 for compression: No such file or directory".
# Nothing is lost from the budget by waiting: the next rotation renames .1 to .2,
# and this becomes eligible to remove it one cycle later.
# and it becomes eligible one cycle later.
LIMIT=$1
I=14
total=`du -c /var/log/messages* |grep total |awk '{print $1}'`
while [ $total -gt $LIMIT -a $I -gt 1 ]; do
NAME=/var/log/messages.$I
if [ -e $NAME ]; then
logger "syslog message total size exceeded the limit. Removing retentions."
rm -f $NAME
total=`du -c /var/log/messages* |grep total |awk '{print $1}'`
fi
I=$((I-1))

# oldest first: sort by generation number, highest first, .gz or not
for NAME in `ls /var/log/messages.* 2>/dev/null |
sed -n 's|^/var/log/messages\.\([0-9][0-9]*\)\(\.gz\)\{0,1\}$|\1 &|p' |
sort -rn | awk '{print $2}'`; do
[ $total -gt $LIMIT ] || break
case "$NAME" in
/var/log/messages.1|/var/log/messages.1.gz) continue ;;
esac
logger "syslog message total size exceeded the limit. Removing retentions."
rm -f $NAME
total=`du -c /var/log/messages* |grep total |awk '{print $1}'`
done
1 change: 0 additions & 1 deletion rootfs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,6 @@ full_rootfs_install::
$(Q)sed -i -e "s/.*PermitRootLogin .*/PermitRootLogin yes/" -e "s/.*PasswordAuthentication .*/PasswordAuthentication yes/" $(ROOTDIR)/etc/ssh/sshd_config
$(Q)ln -sf /lib/systemd/system/systemd-hexctl-user.service $(ROOTDIR)/etc/systemd/system/multi-user.target.wants/systemd-hexctl-user.service
$(Q)chroot $(ROOTDIR) systemctl disable crond sshd
$(Q)chroot $(ROOTDIR) mv /etc/cron.daily/logrotate /etc/cron.hourly/ || true
$(Q)chroot $(ROOTDIR) mv /etc/logrotate.d/rsyslog /etc/logrotate.d/rsyslog.disabled
$(Q)chroot $(ROOTDIR) bash -c "rm -rf /usr/local/share/* /usr/share/{man,doc,licenses} /usr/src /usr/local/src /var/{log,cache}/* /tmp/* /lib/.build-id"

Expand Down
25 changes: 25 additions & 0 deletions src/hex_sdk_library/logrotate/logrotate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,34 @@ WriteDefLogRotateConf(int retention = 4)
return false;
}

// retention is a number of DAYS -- that is what cubesys.log.default.retention
// promises operators ("Set log file retention policy in days") and what the
// audit expectation is built on. logrotate's `rotate` counts GENERATIONS, so
// on its own it only ever approximates that promise, and the approximation
// holds exactly while a log rotates once per day and no more.
//
// The two bounds do different work, which is why both are emitted:
//
// rotate caps the number of files a busy log can leave behind. On the
// shipped daily schedule that is also its age, one generation per
// day.
// maxage caps their age directly, and is the only one of the two that says
// anything about a log that rotates *rarely*. `notifempty` and a
// quiet service mean generations can sit for months and still be
// well inside a count of 14 -- without maxage they are kept
// indefinitely, long past the window the tuning advertises.
//
// What neither covers, and is worth knowing rather than papering over: if
// something rotates a log more than once in a day -- an operator's
// `logrotate -f`, a fixpack or enabler driving a rotation -- `rotate` spends a
// generation without spending a day and the window shrinks below the
// advertised days. That is long-standing behaviour and this does not change
// it; sizing `rotate` past the count needed for a daily schedule would, at the
// cost of keeping far more files than the schedule can ever produce.
fprintf(fout, "daily\n");
fprintf(fout, "su root syslog\n");
fprintf(fout, "rotate %d\n", retention);
fprintf(fout, "maxage %d\n", retention);
fprintf(fout, "create\n");
fprintf(fout, "include /etc/logrotate.d\n");

Expand Down