File: //sbin/cron-apt
#!/bin/sh
#
# Copyright (C) 2002-2011,2013,2017 Ola Lundqvist <ola@inguza.com>
# Copyright (C) 2004-2011,2013,2017 Marc Haber <mh+debian-bugs@zugschlus.de>
# Copyright (C) 2004,2007,2013 Bob Proulx <bob@proulx.com>
# Copyright (C) 2004 Marc Sherman <msherman@projectile.ca>
# Copyright (C) 2004 David Weinehall
# Copyright (C) 2003 Sean Finney <seanius@seanius.net>
# Copyright (C) 2002 Marcel Kolaja <marcel@solnet.cz>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301 USA.
#
# Changes:
# 2017-12-04 Marc Haber <mh+debian-bugs@zugschlus.de>
# Insert a diff mark to ease automatic processing.
# Introduced a log directory statement for mail file.
# 2017-09-22 Ola Lundqvist <ola@inguza.com> and
# Marc Haber <mh+debian-bugs@zugschlus.de>
# Introduced the possibility to set a subject prefix.
# 2013-05-24 Ola Lundqvist <ola@inguza.com>
# Applied a patch from Marc Haber <mh+debian-bugs@zugschlus.de>
# to handle the case when cksum return a shorter string than
# four digits. See Debian bug #689914 for more information.
# Using suggestions from Bob Proulx <bob@proulx.com>
# the solution was changed to use awk instead of cut.
# In addition to that awk is used to generate random data in
# the case /dev/urandom is not available.
# This is a modified version of the code Bob suggested but using
# nanoseconds instead of minutes and seconds.
# 2011-11-03 Ola Lundqvist <ola@inguza.com>
# Applied a patch from Marc Haber <mh+debian-bugs@zugschlus.de>
# so that the $OPTIONS variable is now included in debug output.
# 2011-03-21 Ola Lundqvist <ola@inguza.com>
# Correction so that also very long apt commands can be
# managed properly.
# 2009-03-24 Ola Lundqvist <ola@inguza.com>
# Correction so that it do syslog instead of sending mail
# when the syslog parameter is set to changes. Thanks to
# Boris Trautmann for spotting this problem.
# 2007-08-02 Ola Lundqvist <ola@inguza.com>
# Added support for *_HERE variables in the action.d files.
# They are copied to the * variable before the action loop
# and then restored in the end of the loop.
# Marc Haber gave the idea to have variables that are applicable
# for only the action item.
# Also moved out the functions so they can be tested separately.
# 2007-08-01 Ola Lundqvist <ola@inguza.com>
# Changed so that the tmp size checking is done later.
# 2007-07-31 Ola Lundqvist <ola@inguza.com>
# Based on a patch from Marc Haber <mh+debian-bugs@zugschlus.de>
# cron-apt now fail more gracefully if the mail command is not
# available.
# Applied patch from Marc Haber <mh+debian-bugs@zugschlus.de> to
# make a more graceful check if the tmp directory is full.
# Modified the patch so it is configurable.
# 2007-07-21 Bob Proulx <bob@proulx.com>, Ola Lundqvist <ola@inguza.com>
# Correction of MAILONMSGSDIR and SYSLOGONMSGSDIR.
# 2007-07-06 Ola Lundqvist <ola@inguza.com>
# Check refrain file even after sleep.
# 2006-11-26 Ola Lundqvist <ola@inguza.com>
# Corrected stupid syntax error.
# 2006-11-23 Ola Lundqvist <ola@inguza.com>
# Make sure that initlog is removed on exit.
# 2006-04-30 Marc Haber <mh+debian-bugs@zugschlus.de>
# Move dotlock code so that now the entire cron-apt run
# is protected by locking
# 2005-10-09 Marc Haber <mh+debian-bugs@zugschlus.de>
# Add $APTCOMMAND to the CRON-APT line output.
# 2005-10-07 Ola Lundqvist <ola@inguza.com>
# Changed name for DIFF ignore option.
# 2005-10-07 Marc Haber <mh+debian-bugs@zugschlus.de>
# Support for DIFF ignore directive and better hostname handling.
# 2005-04-20 Ola Lundqvist <ola@inguza.com>
# Modified refrain file system to make file name configurable.
# 2005-04-20 Marc Haber <mh+debian-bugs@zugschlus.de>
# Added support for refrain file.
# 2004-12-25 Marc Sherman <msherman@projectile.ca>
# Added configurable support for aptitude instead of apt-get.
# 2004-09-23 Ola Lundqvist <ola@inguza.com>
# Escaped changes file data so '/' can be used in action.d lines.
# 2004-09-19 Marc Haber <mh+debian-bugs@zugschlus.de>
# Add warning if dotlockfile not found.
# 2004-09-12 Ola Lundqvist <ola@inguza.com>
# Modified patch from Marc Haber to avoid symlink attacks.
# Also use nicer cleaning.
# 2004-09-12 Marc Haber <mh+debian-bugs@zugschlus.de>
# Patch to have multiple cron-apt running at the same time
# without messing up the changelog.
# 2004-09-07 Marc Haber <mh+debian-bugs@zugschlus.de>
# Patch to achieve run-parts behaviour.
# 2004-08-13 Ola Lundqvist <ola@inguza.com>
# Bugfixes.
# Made *ON=changes available to more than only mail.
# 2004-08-12 Ola Lundqvist <ola@inguza.com>
# Added support for mailon=changes.
# Marc Haber <mh+debian-bugs@zugschlus.de> give me the patch
# that I have modified.
# Fixed some other bugs that was introduced by me.
# Added support for syslogon.
# 2004-08-09 Ola Lundqvist <ola@inguza.com>
# Cleaned up some code and fixed a minor logging bug.
# Better argument checking code. Can now handle more than
# one option.
# Changed from status passing from echo to file.
# Fixed so that stdout argument really works.
# 2004-08-08 Ola Lundqvist <ola@inguza.com>
# Fixed variable bug.
# Cleaned up the code.
# Fixed output function framework so it works as expected.
# Better option handling and local output option.
# 2004-07-22 Ola Lundqvist <ola@inguza.com>
# Made it more POSIX compliant by using /dev/random if the
# RANDOM variable do not contain a value. Thanks to
# Bob Proulx <bob@proulx.com> and David Weinehall for the idea.
# Also changed -a and -o to && and ||, as Bob suggested.
# 2003-07-10 Ola Lundqvist <ola@inguza.com>
# Always run even if there was an error last time is now the
# default. Fix so that you can write RUNSLEEP=0 too.
# 2003-07-10 Ola Lundqvist <ola@inguza.com>
# Added runsleep configuration option.
# Now cron-apt is aware of the DEBIAN_FRONTEND = noninteractive
# ENVIRONMENT.
# 2003-07-10 Ola Lundqvist <ola@inguza.com>
# Patch for mailon=output option from Sean Finney
# <seanius@seanius.net>.
# 2003-04-17 Ola Lundqvist <ola@inguza.com>
# Added mailon=output option using patch from Sean Finney
# <seanius@seanius.net>.
# 2002-08-14 Ola Lundqvist <ola@inguza.com>
# Implemented mail on upgrade only using patches from Marcel Kolaja
# <marcel@solnet.cz>. Thanks a lot for these patches.
# 2002-04-07 Ola Lundqvist <ola@inguza.com>
# Added skipping of comment lines in action files.
# Added exra config.d directory.
# Rewrote the mail and log part to make it more flexible.
# Christian Perrier <Christian.Perrier@onera.fr> was the
# one that needed this flexibility.
# Also added skipping of backup files (*~).
# 2002-03-05 Ola Lundqvist <ola@inguza.com>
# Made it complete so it can be released.
# 2002-03-03 Ola Lundqvist <ola@inguza.com>
# Wrote the beginning.
# 2002-04-24 Ola Lundqvist <ola@inguza.com>
# Added a default path. Thanks to Donovan Baarda
# <abo@minkirri.apana.org.au> for pointing it out.
export PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin
UMASK_TIGHT="077"
UMASK_APT="022"
umask $UMASK_TIGHT
############################# arguments #######################################
STDOUT=""
ALLCONFIGS=""
while [ -n "$*" ] ; do
if [ "$1" = "--help" ] ; then
echo "USAGE: cron-apt [-i] [-s] [configfiles]"
exit 0
elif [ "$1" = "-i" ] ; then
RUNIMMEDIATELY="yes"
shift
elif [ "$1" = "-s" ] ; then
DEBUG=always
STDOUT=yes
shift
else
CONFIG="$1"
ALLCONFIGS="$ALLCONFIGS $CONFIG"
shift
fi
done
if [ -z "$CONFIG" ] ; then
CONFIG=/etc/cron-apt/config
ALLCONFIGS="$CONFIG"
fi
############################## lib and tmp dirs ###############################
LIBDIR="/var/lib/cron-apt"
SHAREDIR="/usr/share/cron-apt"
CONFIGDIRNAME="$(echo $CONFIG | sed 's|/|_-_|g')"
TMPDIR=$(mktemp -d -t cron-apt.XXXXXX)
if [ $? -ne 0 ]; then
echo >&2 "Error: Can not create a safe temporary directory."
exit 1
fi
INITLOG="$TMPDIR/initlog"
RUNERROR="$TMPDIR/runerror"
RUNSYSLOG="$TMPDIR/runsyslog"
RUNLOG="$TMPDIR/runlog"
RUNMAIL="$TMPDIR/runmail"
ACTIONERROR="$TMPDIR/actionerror"
ACTIONSYSLOG="$TMPDIR/actionsyslog"
ACTIONLOG="$TMPDIR/actionlog"
ACTIONMAIL="$TMPDIR/actionmail"
TEMP="$TMPDIR/temp"
MAIL="$TMPDIR/mail"
DIFF="$TMPDIR/difftemp"
STATUS="$TMPDIR/status"
LOCKFILE="$LIBDIR/lockfile"
MAILCHDIR="$LIBDIR/$CONFIGDIRNAME/mailchanges"
ERROR="$TMPDIR/$CONFIGDIRNAME-error"
############################## defaults #######################################
ACTIONDIR="/etc/cron-apt/action.d"
ACTIONCONFDIR="/etc/cron-apt/config.d"
MAILMSGDIR="/etc/cron-apt/mailmsg.d"
MAILONMSGSDIR="/etc/cron-apt/mailonmsgs"
SYSLOGONMSGSDIR="/etc/cron-apt/syslogonmsgs"
REFRAINFILE="/etc/cron-apt/refrain"
NOLOCKWARN=""
ERRORMSGDIR="/etc/cron-apt/errormsg.d"
SYSLOGMSGDIR="/etc/cron-apt/syslogmsg.d"
LOGMSGDIR="/etc/cron-apt/logmsg.d"
LOGDIR="/var/log/cron-apt"
LOG="$LOGDIR/log"
LASTFULLMESSAGE="$LOGDIR/lastfullmessage"
DIFFONCHANGES="prepend"
SUBJECTPREFIX="CRON-APT"
MAILTO="root"
MAILWIDTH="900"
# error, always, never
SYSLOGON="upgrade"
# error, always
MAILON="error"
# error, never
EXITON="error"
# verbose, error
DEBUG="verbose"
# general options
OPTIONS="-o quiet=1"
# do always run as default
DONTRUN=""
# Random sleep time before run
RUNSLEEP="3600"
# Minimum amount of discspace needed in /tmp
MINTMPDIRSIZE=10
# The command to use (can be aptitude instead)
APTCOMMAND="/usr/bin/apt-get"
# If HOSTNAME is non-empty, the contents will be used to generate the
# e-mail subject for notifications sent out. If HOSTNAME is empty, the
# output of $(uname -n) will be used.
HOSTNAME=""
# Ignore lines matching this regexp to determine whether changes occurred
# for MAILON="changes".
DIFFIGNORE=""
# What to do with the diff when *ON=changes.
# Value: prepend (prepend to the output)
# append (append to the output)
# only (only show the diff, not the output itself)
# (else do nothing)
DIFFONCHANGES=prepend
export DEBIAN_FRONTEND="noninteractive"
export LANG="C"
export LC_ALL="C"
# Read configuration.
for cfg in $ALLCONFIGS; do
if [ -f "$cfg" ] ; then
. "$cfg"
else
echo >&2 "The config file $cfg does not exist."
fi
done
if [ -t 0 ]; then
RUNIMMEDIATELY="yes"
fi
if test "$RUNIMMEDIATELY" = "yes"; then
RUNSLEEP=
fi
############################## functions ######################################
. $SHAREDIR/functions
############################### check #########################################
if ! [ -d "$LIBDIR/$CONFIGDIRNAME" ]; then
mkdir -p "$LIBDIR/$CONFIGDIRNAME"
fi
if ! [ -d "$MAILCHDIR" ]; then
mkdir -p "$MAILCHDIR"
fi
################## terminate if $REFRAINFILE exists ##################
if [ -e "$REFRAINFILE" ]; then
exit 0
fi
# Check for space in tmp
checktmpsize
############################### sleep #########################################
echo "CRON-APT RUN [$CONFIG]: $(date)" > "$INITLOG"
if [ -n "$RUNSLEEP" ] ; then
if [ $RUNSLEEP -gt 0 ] ; then
if [ -z "$RANDOM" ] ; then
# A fix for shells that do not have this bash feature.
if [ -e /dev/urandom ] ; then
RANDOM=$(dd if=/dev/urandom count=1 2> /dev/null | cksum | awk '{print$1}')
else
RANDOM=$(awk -v rs=$RUNSLEEP -v s=$$$(date +%N) 'BEGIN{srand(s);print(int(rs*rand()));}')
fi
fi
TIME=$(($RANDOM % $RUNSLEEP))
sleep $TIME
echo "CRON-APT SLEEP: $TIME, $(date)" >> "$INITLOG"
# Check refrain file again
if [ -e "$REFRAINFILE" ]; then
exit 0
fi
fi
fi
# Check for space in tmp again
checktmpsize
################## try to take out a lock, terminate if unsuccessful ##########
if [ -x /usr/bin/dotlockfile ] ; then
if ! dotlockfile -l -p -r 10 $LOCKFILE; then
# create log entry
echo > $MAIL "cannot acquire cron-apt lock."
onexit
exit 1
fi
else
if [ -z "$NOLOCKWARN" ]; then
echo > $TEMP "WARNING: dotlockfile not installed. If you don't want to see this"
echo >> $TEMP " Warning any more, set NOLOCKWARN in the configuration file."
createerrorinfo "startup"
fi
fi
################## initialize various log files ##############################
cp "$INITLOG" "$RUNMAIL"
cp "$INITLOG" "$RUNLOG"
cp "$INITLOG" "$RUNSYSLOG"
cp "$INITLOG" "$RUNERROR"
rm -f "$INITLOG"
############################### script ########################################
# Always run onexit before exit.
for ACTION in $(run_parts "$ACTIONDIR") ; do
ACTIONF=$(echo $ACTION | sed "s|$ACTIONDIR/||")
if [ -f "$ACTIONCONFDIR/$ACTIONF" ] ; then
. "$ACTIONCONFDIR/$ACTIONF"
fi
echo "CRON-APT ACTION: $ACTIONF" > "$ACTIONERROR"
echo "CRON-APT ACTION: $ACTIONF" > "$ACTIONMAIL"
echo "CRON-APT ACTION: $ACTIONF" > "$ACTIONLOG"
echo "CRON-APT ACTION: $ACTIONF" > "$ACTIONSYSLOG"
herevariables_store
cat "$ACTIONDIR/$ACTIONF" | \
sed -e "s/#.*$//;" | \
grep -v "^[[:space:]]*$" | {
while read LINE ; do
echo "CRON-APT LINE: $APTCOMMAND $OPTIONS $LINE" > "$TEMP"
UMASK_SAVE=$(umask)
umask $UMASK_APT
$APTCOMMAND $OPTIONS $LINE >> $TEMP 2>&1
RET=$?
umask $UMASK_SAVE
if [ $RET -ne 0 ]; then
# ---
# An error has occured.
createerrorinfo $ACTIONF
# SYSLOG
if [ "$SYSLOGON" = "error" ] || [ "$SYSLOGON" = "upgrade" ] ; then
createsysloginfo $ACTIONF
fi
# MAIL
if [ "$MAILON" = "error" ] || [ "$MAILON" = "upgrade" ] ; then
createmailinfo $ACTIONF
fi
# DEBUG
if [ "$DEBUG" = "error" ] ; then
createloginfo $ACTIONF
fi
# EXIT
if [ "$EXITON" = "error" ] ; then
echo exit > "$STATUS"
#exit
fi
else
# ---
# No error has occured.
if grep -q 'The following packages will be upgraded' "$TEMP" ; then
# ---
# Upgrade has happend
# SYSLOG
if [ "$SYSLOGON" = "upgrade" ] ; then
createsysloginfo $ACTIONF
fi
# MAIL
if [ "$MAILON" = "upgrade" ] ; then
createmailinfo $ACTIONF
fi
# DEBUG
if [ "$DEBUG" = "upgrade" ] ; then
createloginfo $ACTIONF
fi
fi
fi
# ---
# Independent of error or not
# SYSLOG
if [ "$SYSLOGON" = "always" ] ; then
createsysloginfo $ACTIONF
fi
# MAIL
if [ "$MAILON" = "always" ] ; then
createmailinfo $ACTIONF
fi
# DEBUG
if [ "$DEBUG" = "verbose" ] || [ "$DEBUG" = "always" ] ; then
createloginfo $ACTIONF
fi
if grep -qvE '^[[:space:]]*$|CRON-APT' "$TEMP"; then
# ---
# Now we have output
if [ "$SYSLOGON" = "output" ]; then
createsysloginfo $ACTIONF
fi
if [ "$MAILON" = "output" ]; then
createmailinfo $ACTIONF
fi
if [ "$DEBUG" = "upgrade" ] ; then
createloginfo $ACTIONF
fi
fi
TLINE=$(echo "$LINE" | md5sum | sed -e "s/[[:space:]].*//;")
if [ -n "$DIFFIGNORE" ]; then
DIFFIGNORELINE="--ignore-matching-lines=$DIFFIGNORE"
fi
echo "CRON-APT DIFF" > "$DIFF"
if [ ! -r "$MAILCHDIR/$ACTIONF-$TLINE" ] || ! diff $DIFFIGNORELINE -u "$MAILCHDIR/$ACTIONF-$TLINE" "$TEMP" >> "$DIFF" ; then
cp "$TEMP" "$MAILCHDIR/$ACTIONF-$TLINE"
# What to do with diff
# OBS! FROM NOW ON "$TEMP" CAN HAVE DIFF INFORMATION IN IT!
if [ -n "$DIFF" ] && [ -r "$DIFF" ] ; then
if [ "$DIFFONCHANGES" = "only" ] ; then
cp "$DIFF" "$TEMP"
elif [ "$DIFFONCHANGES" = "append" ] ; then
cat "$DIFF" >> "$TEMP"
elif [ "$DIFFONCHANGES" = "prepend" ] ; then
echo "----- DIFF END HERE -----" >> "$DIFF"
cat "$TEMP" >> "$DIFF"
mv "$DIFF" "$TEMP"
fi
fi
# ---
# We have changes
# MAIL
if [ "$MAILON" = "changes" ] ; then
createmailinfo $ACTIONF
fi
# SYSLOG
if [ "$SYSLOGON" = "changes" ] ; then
createsysloginfo $ACTIONF
fi
# DEBUG
if [ "$DEBUG" = "changes" ] ; then
createloginfo $ACTIONF
fi
fi
rm -f "$DIFF"
done
#exit
}
if [ -e "$STATUS" ] ; then
if grep exit "$STATUS" > /dev/null 2>&1 ; then
rm -f "$STATUS"
onexit
exit
fi
rm -f "$STATUS"
fi
herevariables_restore
done
onexit