Monday, July 16, 2012

Ubuntu: Automating Locking and Suspending

Locking and Suspending from the Terminal

The first thing to note is that suspending the computer does not lock the computer. They are separate actions.

To lock the screen.
gnome-screensaver-command --lock

To suspend the computer, check out this article on How To Suspend Ubuntu from the Terminal. If you're simply running this from the terminal either by typing or using a script, I would suggest method 3 as it does not require sudo.
gnome-screensaver-command --lock
dbus-send --print-reply --system --dest=org.freedesktop.UPower /org/freedesktop/UPower org.freedesktop.UPower.Suspend

Locking and Suspending from cron (Problems)

Note: If you don't care about the problems and just want the solution, skip down to the next section.

If you had the above in a script that you could run from the terminal, it follows that you could run this script from a cron. Perhaps the scenario is that you wanted to lock down and suspend a particular computer at work every day at 5pm.

The script would look like this.
gnome-screensaver-command --lock
dbus-send --print-reply --system --dest=org.freedesktop.UPower /org/freedesktop/UPower org.freedesktop.UPower.Suspend

Let's say it was stored in ~/bin/ Remember to make sure that it's executable.
chmod +x ~/bin/

When you run this in the terminal, your computer locks and suspends. Everything is fine.

Next, you would edit your crontab.
crontab -e

And place the following in it. The output from standard out and error is logged to a log file.
0 5 * * * /home/user/bin/ > /home/user/logs/lock-suspend.log 2>&1

You then wait for 5pm to come around and lo-and-behold, nothing happens.

Knowing that cron logs to /var/syslog/log, you go and check it and find that the cron job ran, but an error occurred.

Since the script was logged to /home/user/log/lock-suspend.log, you check it out and find the following errors.
** Message: Failed to get session bus: Command line `dbus-launch --autolaunch=364dc0936e296ffa0881a3e90000000a --binary-syntax --close-stderr' exited with non-zero exit status 1: Autolaunch error: X11 initialization failed.\n
Error org.freedesktop.UPower.GeneralError: not authorized

What does this mean?

After much Googling, I came across this thread. It explained that the first message came about because cron does not have access to the same environment as the terminal. More specifically, it is missing the environment variable DBUS_SESSION_BUS_ADDRESS.

I did not look much further into the second error though. I assume it is because cron does not have access to the dbus. This was easily solvable though as there are several methods to suspend, for instance method 2.
sudo pm-suspend

Locking and Suspend from cron (Solution)

In order to solve the first problem, we need to figure out what should go into the environment variable DBUS_SESSION_BUS_ADDRESS.

When you first login, DBUS_SESSION_BUS_ADDRESS is set for you. We can grab this and write it to file. Add the following to your .bashrc file.
set | grep DBUS_SESSION_BUS_ADDRESS > ~/.DBUS_temp

Now we need to modify the script. However, before we do that, we need to think about the solution to the second problem. Since we'll be using sudo to run pm-suspend, the cron job must be run as root instead of as the current user. We will need to modify the script expecting root to be running the script.

Note that in order to set the DBUS_SESSION_BUS_ADDRESS environment variable, we use source. However, in order to use source, we must use bash instead of sh.

The full script.
source /home/user/.DBUS_temp
su -c "gnome-screensaver-command --lock" user

Now modify the root's crontab.
sudo crontab -e

And add the following.
0 5 * * * /home/user/bin/ > /home/user/log/lock-suspend.log 2>&1

Come 5pm, the computer locks and suspends gracefully and you can relax knowing that your data is safe and you're saving the planet by reducing power usage.

1 comment:

  1. Only thing I was not sure about was if value of this ever changes, so I added this line to my /home/userxxx/.profile script :
    set | grep DBUS_SESSION_BUS_ADDRESS > ~/.DBUS_temp