Skip to content

Instantly share code, notes, and snippets.

@rcook
Forked from jbonney/crontab.sh
Last active August 7, 2021 04:42
Show Gist options
  • Save rcook/9149401 to your computer and use it in GitHub Desktop.
Save rcook/9149401 to your computer and use it in GitHub Desktop.
#!/bin/sh
#
# Provides missing crontab editing
# Note: Synology crond requires arguments separated by a TAB character
# and the crontab user field only supports root. These requirements are
# enforced by this script.
#
# John Kelly, 2013-05-03
# Richard Cook, 2014-02-21
#
SCRIPTPATH=$(readlink -f $0)
SCRIPTNAME=$(basename "$SCRIPTPATH")
# Default path to crontab file
CRONTABPATH=/etc/crontab
# Failed edits are kept in this file
CHKCRON=/etc/crontab.chk
# Previous version
TMPNAME=/etc/crontab.old
# Max versions to keep. One or greater
MAXVER=10
# Set to your editor of choice
EDITOR=nano
usage() {
echo -e "Usage: $SCRIPTNAME [-l | -v | -f | -e | -h]\n"
}
# Check for selected editor. Default to vi
EDITOR=$(/usr/bin/which $EDITOR 2>&1)
[[ ! -x "$EDITOR" ]] && EDITOR=/bin/vi
show_help() {
echo -e 'Provides basic access to the crontab file'
echo -e 'with simple format checks\n'
usage
echo ' -l : Lists the current contents of the root crontab file'
echo ' -v : Verifies the current contents of the root crontab file'
echo ' -f : Refreshes the cron daemon'
echo ' -e : Edits the crontab file and refreshes the cron daemon if'
echo ' the file is actually changed; otherwise does nothing'
echo -e ' -h : Shows this help text\n'
}
verify_crontab() {
# Synocron is very picky. Check the file format
( # Start of output redirection block
IFS="
"
cat $1 | \
while read LINE; do
# Find out if empty or the first character is a #
echo "$LINE" | awk '{print $1}' | egrep "^#|^$" > /dev/null 2>&1
if [[ $? = 0 ]]; then
# Copy over comment/blank lines exactly
echo "$LINE"
else
unset IFS
# test convert using tabs to compare results
echo "$LINE" | while read MIN HO MD MO WD WH COM; do
echo -e "$MIN\t$HO\t$MD\t$MO\t$WD\troot\t$COM"
done
IFS="
"
fi
done
) > $2 # end of output redirection block
# Compare files and return the result
diff $1 $2 > /dev/null 2>&1
return $?
}
restart_cron() {
echo 'Refreshing cron daemon.'
SYNOSERVICE=/usr/syno/sbin/synoservice
if [ -f $SYNOSERVICE ]; then
$SYNOSERVICE --restart crond
return
fi
CRONDRC=/usr/syno/etc/rc.d/S04crond.sh
if [ -f $CRONDRC ]; then
$CRONDRC stop
$CRONDRC start
return
fi
echo 'Don'"'"'t know how to restart cron service.'
exit 1
}
archive_crontabs() { # Keep up to MAXVER versions
ARCVER=$MAXVER
while [[ $ARCVER -gt 1 ]]; do
PRVVER=$(expr $ARCVER - 1)
if [ -f $TMPNAME.$PRVVER ]; then
mv -f $TMPNAME.$PRVVER $TMPNAME.$ARCVER
fi
ARCVER=$PRVVER
done
cp $TMPNAME $TMPNAME.1
}
edit_crontab() {
archive_crontabs
cp $1 $TMPNAME
$EDITOR $1
diff $1 $TMPNAME > /dev/null 2>&1
if [[ $? = 0 ]]; then
echo "No changes made. Doing nothing."
else
if verify_crontab $1 $2; then
echo 'Crontab altered.'
echo "Previous version saved in $TMPNAME"
rm -f $2
restart_cron
else
echo 'Crontab file is NOT in the correct Synology format.'
echo 'Please use TABs between fields and specify root in sixth field.'
echo "Your version is saved in $2. Restoring original version."
diff $1 $2 | cat -A
cat $1 > $2
cat $TMPNAME > $1
fi
fi
exit 0
}
check_command() {
if [[ "$COMMAND" != '' ]]; then
echo -e 'You must specify exactly one command.\n'
usage
exit 1
fi
}
COMMAND=
while getopts p:lvfeh FLAG; do
case $FLAG in
p) CRONTABPATH=$(readlink -f $OPTARG);;
l) check_command; COMMAND=l;;
v) check_command; COMMAND=v;;
f) check_command; COMMAND=f;;
e) check_command; COMMAND=e;;
h) check_command; COMMAND=h;;
esac
done
if [[ "$COMMAND" = '' ]]; then
usage
exit 1
fi
case $COMMAND in
l)
echo "crontab at $CRONTABPATH"
cat $CRONTABPATH;;
v)
TEMPPATH=$(mktemp)
if verify_crontab $CRONTABPATH $TEMPPATH; then
echo "crontab at $CRONTABPATH is valid"
else
echo "crontab at $CRONTABPATH is not valid:"
diff $CRONTABPATH $TEMPPATH | cat -A
fi
rm $TEMPPATH;;
f) restart_cron;;
e) edit_crontab $CRONTABPATH $CHKCRON;;
h) show_help;;
esac
The MIT License (MIT)
Copyright (c) 2014 Richard Cook
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.
@johnkdevnull
Copy link

You're enjoying yourself with my script :-) There's an updated version on the Synology forum for DSM 5 that uses killall -HUP crond to restart the daemon. Feel free to lift whatever parts you want.

Cheers
John K

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment