Sorry Hani, I couldn’t resist that title!

Yesterday I summarized my adventures with Linux and ACPI and WOL, culminating in a machine that would wake up from hibernation when a user initiated an SSH session from a remote (outside my apartment) network. I ended the post saying that there were two things left to do. Today I got those two things working!

First, the second thing. I said that when the computer in question, Stork booted there was a long (1 to 3 minutes) delay. It was something to do with the network card, becaues it only occurred when the card was installed. Different slots and combinations of BIOS settings made no difference.

Today I noticed that the 2.6.30 kernel has made it into unstable (it must have gone in during the past few days, as when I installed the machine three days ago it wasn’t available yet). I went ahead and installed it and rebooted and sure enough, the long delay is gone. I have a suspicion this is more to do with building a new initrd, and that I could probably have solved the problem by rebuilding the ram image for my previously installed kernel. I may go back and try this, but it’s working now anyway. Boot up time on a cold-start is less than 45 seconds, and resume from hibernation shaves another 20 off that. That includes a 4 second GRUB wait, which I may trim down.

The first problem was a desire to have the machine go into hibernate automatically, as a result of no activity. I decided that I would approach this with a cron script (which may or may not be the best short-term approach). I wrote a very simple script as below.

#!/bin/sh
#
# Hibernator cron job
# 2009 Nathan Blythe
#

# Delay to give the user time to log in.
#
sleep 60

# Anybody logged in?
#
if [ -z "$(users)" ]; then
  # Put the NIC in WOL modes u and g.
  #
  ethtool -s eth2 wol ug

  # Hibernate.
  #
  pm-hibernate
fi

There you have it; doesn’t get much simpler than that. I stored the file as /root/hibernator. I added a line to /etc/crontab that looks like this:

*/5  *  *  *  *  root  /root/hibernator

This tells cron to run the script every 5 minutes. So why the sleep 60 command in the script? Well I found that when the machine resumes it has a tendency to run the cron job immediately. This means that if you don’t have a bit of a delay between when the script starts and when it actually does the deed, the user won’t have time to finish logging in. The SSH packet arrives, the machine wakes, and before they can finish entering their password, it hibernates again.

A better cron job may be in the works. Running the script every 5 minutes gets the job done, but it means that when a user logs out there could be a 5 minute delay until the machine goes down or just a few seconds, depending on the time. A better system would run every 5 minutes or so and store the time at which it saw users to a file. Then if it doesn’t see users it checks if a certain amount of time has gone by (since the time in the file). If so, then it hibernates.

Furthermore, a better script would also do some lsof or netstat magic to determine if a user is logging in at the moment (remotely anyway… local users still have to beat the clock). I may work on such a script later.

A new problem has come up, however. I’ve realized that when I attempt to connect remotely, the SSH packet does indeed wake the system, but then the connection is not made until SSH is tried again. The packet that wakes the system is thrown away, and for whatever reason SSH doesn’t try again. I’ll have to think of a way around this. It could be I just use some port as a “wakeup” port… for instance, port 80. Issuing an HTTP request to my network wakes up the machine, after which SSH works. I’d prefer a more smooth system, but we’ll see.

Stay tuned for a better cron script!