Based on John Kelly’s original script:
#!/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. |
My version adds a -v
command for verifying crontabs without installing them.
Content © 2025 Richard Cook. All rights reserved.