Stupid Cron Tricks

Have you ever wanted to make cron run a scheduled task on some weird interval like every 29 days? I was faced with that problem just the other day.

I was starting to get annoyed with DynDNS’s nag emails, asking me to either log in and “touch” my WRT54GL router’s host record every 30 days or to upgrade to a paid service that does not require a periodic touch.

Of course, you can create a cron job that calls programs like ez-ipupdate to automate this periodic touching. The problem is, even though cron is quite flexible, it does not support intervals of 29 days.

Why 29 days? If you touch the record any earlier than 28 days since the previous touch, DynDNS may flag you for abuse and disable your host record (in practice, I have been able to touch the record a handful of times within 28 days without being flagged, but why take a chance?). On the other hand, if you don’t touch the host record within 30 days, you get a nag email (and if you don’t touch it within 35 days, the record is deleted by DynDNS altogether). So, I figured that 29 days would be a safe value to use.

I thought I had solved the problem with the technique I described in this article. It did automatically touch the record during within the 28 to 35 day window but since it was based on a monthly cron job, I still got nag emails during 31-day months because 31 is greater than the 30 day nag email threshold.

So how did I solve the problem the second time around? I based my solution on Stephan Sokolow’s Crontab Timing Tricks article, but with a few minor changes. Here is the script that does most of the work:

#!/bin/sh
#
# Runs ez-ipupdate periodically (every $INTERVAL days).
# To automate this, call this script from a daily cron job.

let INTERVAL=29
let upSeconds=`cat /proc/uptime | cut -f1 -d.`
let days=$((${upSeconds}/86400))

echo `date`
echo interval = ${INTERVAL}
echo uptime in days = ${days}

if [ $days -lt $INTERVAL ]; then
  echo uptime less than interval, so no touch needed
elif [ $(( $days % $INTERVAL )) -ne 0 ]; then
  echo uptime is not a multiple of interval, so no touch needed
else
  echo uptime is a multiple of interval, a touch is needed
  echo doing touch
  rm -f /tmp/ez-ipupdate.cache
  /usr/sbin/ez-ipupdate -c /etc/ez-ipupdate.conf
fi

As you can see, ez-ipupdate is only called every 29 days, based on the system uptime.

Next, I created a cron job to automatically call the script daily:

1 0 * * * /usr/sbin/periodic-ez-ipupdate > /tmp/periodic-ez-ipupdate-cron.log 2>&1

Ya, It’s pretty cheesy but it works.

One caveat with my solution is that if the router is rebooted sooner than 29 days since the last reboot, my periodic-ez-ipupdate script will not be called. That’s okay though because the stock configuration of ez-ipupdate in OpenWrt White Russian RC6 automatically calls ez-ipupdate upon reboot. Note, however, if you frequently reboot your router, you will be flagged for abuse for sending too many unnecessary updates to DynDNS. Fortunately, I go several months between reboots of my router.

An obvious solution to the reboot problem would be to store the date of the last touch in a file and compare that to the current system date to see if 29 days had passed. The is a great solution if your router has a hard drive. However, the WRT54GL only has flash memory, which has a finite number of write cycles. Many manufacturers will tell you that you have at least 10,000 write cycles. But I have read that some chips can give you as little as 1,000 write cycles, so why take a chance? That’s why I used the uptime-based solution.

If this tip helped you, please leave me a comment!

7 comments to Stupid Cron Tricks

  • Hanno Foest

    My solution:

    #!/bin/sh

    while (true); do
    sleep 29d
    rm -f /tmp/ez-ipupdate.cache
    /usr/sbin/ez-ipupdate -c /etc/ez-ipupdate.conf 2>&1 | logger -t ez-ipupdate
    done

    called from S99done with
    /etc/init.d/dyndns &

    Yes, ugly, but it avoids the reboot issue you mentioned.

    BTW, there's no need to store the date of the last touch in any other file because there's already one: /tmp/ez-ipupdate.cache gets written with the last touch. Unfortunately, I didn't see an easy way for the "more than 29 days since writing that file" evaluation using the command line utilties OpenWRT offers. Maybe you have an idea?

    Anyway, thanks for the inspiration. :)

    Hanno

  • Jean-Roch Blais

    Thank’s for this script, I’m using a Leaf Bearing-uClibc firewall and had just to simply copy your script in directory /etc/cron.daily. It works that’s what counts !

    bye.

  • [...] Here is a better solution. January 8th, 2007 | Category: Linux, [...]

  • gernot schilling

    instead of using uptime, you could just replace
    >> let upSeconds=`cat /proc/uptime | cut -f1 -d.` <> let upSeconds=`date +%s` <> cat /proc/uptime | cut -f1 -d. <> cut -f1 -d. /proc/uptime <> echo uptime less than interval, so no touch needed <> echo “no need to update dyndns in january of 1970 (ip is not even invented!)” <<
    unless you want to run the script after January 19, 2038, in which case you should remove the first if case.

    ***:
    would a reboot (and a call to dyndns) not trigger a nag, because it is within the 28 day limit?

  • Wouldn’t it be enough just to set the proper max-interval option in ez-ipupdate .conf file?

  • I was not aware of the max-interval option. It might work but I haven’t tried it yet.

  • just set it to 60*60*24*29 and that could be “clean” solution :)

Leave a Reply

 

 

 

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>