Manage Crontab on Synology

By Jimmy Bonney | June 15, 2013

Schedule / Agenda

As we’ve seen before, Synology’s NAS offer a Linux distribution that can be enhanced with many applications. As all Linux distributions (at least as far as I can tell), it comes with cron which allows to easily schedule tasks that need to be run on a regular basis.

We’ve shown previously how to add a task to cron but I have noticed that some of the tasks that I set up were disappearing on reboot. The crontab file was simply containing the default entries and I had to add again my custom tasks after each reboot. As this doesn’t really happen so often, it is easy to forget about it meaning that if those tasks are supposed to run backups for instance, then you might end up in situation were your backups do not run for a while.

It is well know that Synology cron management is a bit unsual compared to traditional Linux distributions. By default, crontab is only editable by root (/etc/crontab) and this needs to be done through a text editor rather than the usual crontab command. But there are a few other limitations that one can read here and there:

  • the who field can only be filled with root, otherwise the entry is removed after a reboot
  • the different fields need to be separated by a tab (no spaces), otherwise the entry is removed after a reboot

Crontab illustration

Luckily, John Kelly has recently uploaded a script on Synology forum, allowing to run crontab and validating the resulting file once updated. Start by creating a file:

1
nano /sbin/crontab

And paste the script content in it. Since I am more comfortable with nano, I simply replaced the default editor in the code below.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#!/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
#
SCRIPTNAME=`basename $0`

# 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=3
# Set to your editor of choice
EDITOR=nano

usage () {
  echo -e "Usage: $SCRIPTNAME [-l | -f | -e | -h]\n"
}

# Basic sanity checks.  Running as root.  One Parameter only.
[[ "`id -u`" =  "0" ]] || ( echo "Root only"; exit 1 )
[[ $# -ne 1 ]] && ( usage; exit 1 )

# Check for selected editor.  Default to vi
EDITOR=`/usr/bin/which $EDITOR`
[[ ! -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    "  -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"
  exit 0
}

check_new () {
  # Synocron is very picky. Check the file format

  ( # Start of output redirection block
    IFS="
"
    cat /etc/crontab | \
    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
  ) > $CHKCRON # end of output redirection block
  # Compare files and return the result
  diff /etc/crontab $CHKCRON >/dev/null 2>&1
  return $?
}

restart_cron () {
  echo "Refreshing cron daemon."
  /usr/syno/sbin/synoservice --restart crond
}

archive () { # Keep up to MAXVER versions
  ARCVER=$MAXVER
  while [[ $ARCVER -gt 1 ]]; do
    PRVVER=`expr $ARCVER - 1`
    mv -f $TMPNAME.$PRVVER $TMPNAME.$ARCVER
    ARCVER=$PRVVER
  done
  cp $TMPNAME ${TMPNAME}.1
}

edit_cron () {
  archive
  cp /etc/crontab ${TMPNAME}
  $EDITOR /etc/crontab
  diff /etc/crontab ${TMPNAME} >/dev/null 2>&1
  if [[ $? = 0 ]]; then
    echo "No changes made.  Doing nothing."
  else
    if check_new; then
      echo "Crontab altered."
      echo "Previous version saved in ${TMPNAME}"
      rm -f $CHKCRON
      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 $CHKCRON.  Restoring original version."
      cat /etc/crontab > $CHKCRON
      cat $TMPNAME > /etc/crontab
    fi
  fi
  exit 0
}

### Script flow ###################

while getopts lfhe flag; do
  case $flag in
  l) cat /etc/crontab; exit 0;;
  e) edit_cron;;
  f) restart_cron;;
  h) show_help;;
  ?) usage;;
  esac
done

## End of script flow #############

Save and close the file (ctrl + O, ctrl + X) and update the permissions (chmod 755 /sbin/crontab). From now on, you will be able to run the usual crontab commands:

  • crontab -l: list the crontab content
  • crontab -e: edit the crontab content and restart cron daemon if content is valid
  • crontab -f: restart cron daemon
  • crontab -h: show help

Big thanks to John Kelly for putting this together. This is a great help!



comments powered by Disqus