Posts Tagged ‘cron’

fcron in, dcron out

Sunday, February 6th, 2011

Last month I wrote a post about how I like cron (dcron to be more exact), and this prompted hook to write me a comment about fcron, and how this was, in his opinion, a far superior implementation.

Among his selling points for fcron were that if the computer was powered off during the time a cronjob was scheduled to execute, one could have fcron execute it at the next system start-up instead.

That does indeed seem nifty, but as the really important cronjobs of mine are running on my laptop-turned-server, whose task it is to be up 24/7, those selling points seemed… unnecessary.

But as I had promised I would at least look into it (it didn’t hurt the slightest that hook graciously provided me with a wealth of information about fcron in the form of an article (in German, watch out for Google Translate, it WILL mangle the example fcron syntax in the article) he’d authored, and a post about his own fcrontab).

So I started reading about fcron, and it did indeed seem really nice, but I remained sceptical since dcron was providing me with everything I needed.

One thing I don’t feel is stressed enough in the resources which I have read about fcron is that old dcron entries WILL WORK, out of the box, in fcron as well.

That was a big stumbling block for me personally, the outlook of having to rewrite the entries in my crontab so that they would work in fcron.

Once I realized this wasn’t the case, I warmed up to fcron significantly. I decided to install it on my netbook first, to try it out and get acquainted with it.

From what I have come to understand, fcron can understand three types of syntax; the regular (as seen in dcron) “date specification-based” syntax, a “relative from system boot”-based syntax, and finally the “*ly”-based syntax (hourly, daily, weekly, etc.)

The “relative to system boot”-syntax is pretty smart, and I will probably use that a whole lot, while the “*ly”-syntax seems to me to increase the readability of when stuff will happen, but decrease control over when they actually happen (it would seem fcron only guarantees that a job scheduled to get executed “daily” will be executed daily, some time within the time span of the “day hours”.

I’m sure I will find uses for that type of rules as well, and as one can note from hook’s post, the “*ly”-syntax is the one he use the most.

fcron brings more than this to the table however. One can add options, either to individual entries, or globally.

It wasn’t until I came across these options, and started reading up on them, that I realized that adopting fcron would go down as my best decision of this month.

There are plenty of options, I suggest the MAN page (fcrontab(5)) for reading them all, but the ones that caught my eye for various reasons are:

  • bootrun – for making jobs run at start if they should have ran during downtime
  • first(X) – delay execution of “relative to boot” entry for X minutes
  • lavg(X, Y, Z) – I am not quite clear about how this work, yet, but if the load average (coincidentally I read a great post the other day which explained load averages pretty well (be sure to read the comments though)) is too high, the job is either not carried out, or queued for later execution
  • runas – (only available for root) Have the job execute as another user

Finally, there is one more option of significance to me. The one that makes fcron the best decision of the month: timezone(Continent/City).

Say that you, like me, live in Sweden (timezone Europe/Stockholm) and wish to send an automated good morning message to a friend in New York every morning at 0800 hours. (Yes, this is a VERY contrived example, you’ll have to use your own imagination as to why this might be cool)

If I’d set cron to just send the message at 0800 (Swedish local time) that would be 0200 hours over in New York. Of course, the arithmetic isn’t hard, I could just subtract the six hour time difference and be on my merry way… until daylight savings time… Reading up on that I realize that Europe and the US don’t switch on the same dates, and from what I can gather, not even during the same week.

fcron‘s ability to execute jobs based on a time specification, given the time in another timezone, makes this a complete non-issue (the lines about timezone in fcrontab(5) doesn’t mention it handling DST, but below it there is documentation for the old (which should NOT be used) tzdiff option, which states that tzdiff is stupid, can’t handle DST, but the timezone option will.

And that’s about it, all that is left for me is to again extend a big thank you to hook for recommending it. Rest assured that it has helped me save some time :)

:wq

Important Dates Notifier

Saturday, January 29th, 2011

I have never been especially good at remembering dates or appointments. My memory just doesn’t seem constructed to handle things like “on YYYY-MM-DD do X” (peculiarly enough, “on Friday next week, have X done” works much better).

I guess things relative to “now” works better for me (at least in the short term) than some abstract date some time into the future.

Luckily enough, I don’t seem to be the only one suffering from having an “appointment-impaired memory” so others have created calendar applications and what not.

These work great, the one I presently use, remind is awesome. But sometimes it isn’t “intrusive” enough.

There are some appointments/dates that are important enough that I would like for remind to hunt me down an alley and smack me over the head with the notification, as opposed to presenting it to me when I query it for today’s appointments.

So I put together a little shell script which push notifications (the ones I feel are the most important) to me via jabber.

The solution involves cron, remind, grep and a nifty little program called sendxmpp.

This script I have placed on my “laptop-made-server” which coincidentally also happens to be the central mercurial server, through which I synchronize the repositories on my desktop and netbook.

Which means that if I just take care to clone the specific repository containing my remind files to some place local on the server, I could have a cronjob pull and update that repository and it would thus always (as long as I have pushed changes made from the desktop/netbook) have the most up to date files available.

If setting up a repository server seems to big of a hassle, one could of course (at least with remind) have a master ~/.reminders file, which then invokes an INCLUDE expression.

This makes remind look in the specified directory for other files, and in that directory have one file for each computer (along the lines of .rem) and have each individual machine scp (and overwrite) their individual file every now and then.

In any case, once the server have fresh and updated sources of data, all it need do is execute the idn.sh script once every day (preferably early, this will work pretty well as the jabber-server I use caches all messages sent to me while I was offline, so once I log in again, I’ll get the notifications then).

As sendxmpp takes the message from STDIN, recipient-addresses as parameters, and parses a configuration file to divine what account should be used to send the message (I set up a “bot” account to send from, and then just authorized that bot in my primary jabber-account), I see no reason why someone couldn’t modify the script to instead (or in addition) use something like msmtp to send out and email instead.

The script itself, in its current form, is rather straightforward, although I’m sure there are still room for optimizations.

#!/bin/sh
TAGS="#Birthday #ATTENTION"

for t in `echo "$TAGS"`;
do
    rem | grep -i "$t" | while read line;
    do
        echo "$line" | sendxmpp recipient@jabber.example.org
    done
done
exit 0

Relevant parts of my crontab:

0   7   *   *   *       cd /home/patrik/remind-repo; /usr/bin/hg pull -u 2>&1
5   7   *   *   *       cd /home/patrik/idn-repo; /usr/bin/hg pull -u 2>&1
10  7   *   *   *       /bin/bash /home/patrik/bin/idn.sh 2>&1

In /home/patrik I have created symlinks /home/patrik/.remind -> /home/patrik/remind-repo/.remind and /home/patrik/.reminders -> /home/patrik/remind-repo/.reminders

And in /home/patrik/bin/ I have a symlink (idn.sh) to /home/patrik/idn-repo/idn.sh. So in case I change the script, like add a tag to look for or something (ok, that should be moved out to a configuration file, that will be part of the next version) that will be picked up as well, before the notifications goes out.

And that’s about it. Risk of forgetting something important: mitigated.

:wq

cron and at

Thursday, January 13th, 2011

There are, from my experience, two ways to schedule jobs to be executed later in the future. cron and at.

They are different kind of beasts, and thus suited for different tasks. cron will execute the job repeatedly every time it finds a time which matches the configured time.

at, on the other hand, is a one time only type of thing. While cron will re-read the task-list (crontab) over and over, attempting to find matches, at will scan the first item in its queue, and if a match is found, will pop that item off the list, executing the command.

So if something you need to act upon happens continually, go with cron, If it is a one time thing, use at.

So, then, how would one go about using the two?

Assuming you have both cron and at installed (sudo pacman -S dcron at on my system), and both are configured and up and running (again, for me (Archlinux), this entailed adding “crond” and “atd” to the DAEMONS array at the end of /etc/rc.conf)

DAEMONS=(... crond atd)

(This change, however, wouldn’t take place until the next time the system was rebooted and the rc.conf got re-read, and if you’d wish to avoid that, you could always start these services up manually by executing

sudo /etc/rc.d/crond start
sudo /etc/rc.d/atd start

So, now, using them:

For cron you run the command crontab -e (-e for edit, one could use -l for listing the contents of the crontab) which will drop you into your $EDITOR of choice.

The format of the crontab is this:

Minute Hour Day Month DayOfWeek Command

Valid inputs for Minute Hour Day and Month are reasonable numerics (what would a value greater than 59 mean for Minute? Or value greater than 23 for Hour? Or… you get the point.) or * (saying, all of them)

So for instance, to have the computer play you a really awful noise to wake you up at 0600 every Monday to Friday you’d do something along the lines of:

0 6 * * mon-fri       /bin/ls -R / | /usr/bin/aplay

Notice how I write the absolute path of all the binaries? The reason for this is that you can’t assume that cron will have set up any meaningful environment variables (like $PATH)

Anyway, what that example says is that on minute 0 of hour 6, on every day in every month, so long as the week day is in the range Monday to Friday, make a recursive listing of all the files on the computer, and pipe it to aplay.

I would STRONGLY advise AGAINST actually using that particular example, ever, as the only way to get rid of the noise once you’re up, would be to locate the aplay process (ps | grep ‘aplay’) and kill it.

Oh, which is a wonderful tool to have around to quickly discover the path to a binary:

$ which ls
/bin/ls

This could save some time :)

To disable a job in cron, simply enter crontab -e again, and remove the line outlining the job you no longer want done.

So what about at?

at has a couple of small binaries with which one manipulates atd: at, atq, atrm. With at we add jobs, with atq we list them, and atrm removes them.

Since you can execute any script (all jobs are executed in /bin/sh, so that might restrict it some) your own imagination of what is possible, is the limitation.

Just the other day I created a shell script on my web host (to which I have SSH  access) which would back up the front page of the site, and then replace it with another. This was to have the page behave differently during a specific date, and at the end of that day, the original front page would be brought back.

So on my local machine I scheduled two jobs, the first to execute the script changing the front page, and another, to execute a script changing it back to the way it was before.

echo "ssh user@webhost replace-frontpage.sh" | at midnight 2011-01-25
echo "ssh user@wenhost restore-frontpage.sh" | at midnight 2011-01-26

With atq I can now see that the jobs are there:

$ atq
36    Tue Jan 25 00:00:00 2011 a patrik
37    Wed Jan 26 00:00:00 2011 a patrik

I haven’t really figured out how to get detailed information about a specific job (so that I can double check that the right command was issued, but the again if I am the least bit unsure, I could just remove the job and start over again:

$ atrm 36
$ atq
37    Wed Jan 26 00:00:00 2011 a patrik

Now, one could of course emulate cron using at, if you write a script (which will be called by at once you create the job), and in that script you tell it to do whatever it is supposed to do, and then add itself to the at queue again.

This might sound less than useful (given the existence of cron, and I agree, if not for a small thing: in a script you can have conditionals, you can check things, and only add the script back to at given the existence of some preconditions.

I was thinking about creating a really aggressive “protect the LCD-screen backlighting LED”-script this way. I operated a script /usr/local/bin/ssaver which calls slock (to lock the screen) and xset dpms force off (to turn off backlighting). The problem was that I bound this script to be executed whenever I hit Ctrl+Alt+l, but if I wasn’t fast enough to let my fingers off the keyboard, the computer interpreted that as activity and turned the backlighting on again…

So I modified the script to add a little watch-dog script to at right before calling slock. Once every minute, this watch-dog script runs ps, tries to determine whether or not slock is still running, and if it is, run xset dpms force off, before scheduling a new check in a minute.

Initially it gave me a lot of grief with not finding a display to operate on, but thanks to brain0 I dealt with this.

/usr/local/bin/ssaver:

#!/bin/sh
/usr/local/bin/backlight-scheduler.sh &
slock
exit 0

/usr/local/bin/backlight-scheduler.sh:

#!/bin/sh
sleep 5
if [ `ps aux | grep 'slock' | grep -v 'grep' | wc -l` -ne 0 ];
then
    XAUTHORITY=/home/patrik/.Xauthority DISPLAY=:0.0 xset dpms force off
    echo "/usr/local/bin/backlight-scheduler.sh" | at now + 1 minutes
fi
exit 0

I am not quite happy with things, but it will have to do. The sleep in backlight-scheduler.sh is necessary as it would seem I cannot call slock before the script (seems as though slock locks up that process until a valid password has been entered), thus the sleep is necessary to delay the check, whether slock is up and running, until we can be reasonably sure that this is the case.

:wq