Fun with acpid

Updated: Fri, Feb 12, 2010 - 2:29am

It doesn't seem glamorous, but it is indeed possible to have fun with acpid. acpid is a daemon that sits and listens for acpi events from the kernel. When it gets an event, it fires the rules you have configured.

Okay, so what's the use?

Let's start with a simple one. On my laptop, when it's unplugged and I shut the lid, I want the laptop to suspend. Now, these days, I'm using Ubuntu on my laptop. Ubuntu is configured with this behavior automatically. But I've found that it doesn't always work. Also, even when it works, it can be slow. The sleep-when-lid-is-shut behavior is controlled by gnome-power-manager. It seems strange to me that we would have this behavior be controlled by something so far up the stack. X and gnome may have a lot on their minds. Also, I may not even be running X.

Fortunately, acpid is much lower in the stack. It'll be running, X or no.

So we can program the sleep behavior into the acpid config files.

In Ubuntu, we are interested in the directory /etc/acpi. There are a bunch of scripts there that are fired in response to acpi events. The ones we are interested in are /etc/acpi/lid.sh and /etc/acpi/power.sh. They respond to the lid and the AC adaptor, respectively. (In Arch Linux, there is only one script, /etc/acpi/handler.sh. Instead of editing files, you'll be editing different parts of that file).

You'll notice that /etc/acpi/lid.sh calls /etc/acpi/local/lid.sh.pre before it runs, and /etc/acpi/local/lid.sh.post when it's done. We will edit the "pre" file, so that we don't get in the way of new versions of acpid from the distro. Note that these "pre" and "post" scripts must be marked as executable, or the main scripts will ignore them and not run them.

This is what I put in the lid.sh.pre script:

  1. #!/bin/sh
  2.  
  3. grep -q closed /proc/acpi/button/lid/*/state
  4. if [ $? = 0 ] ; then
  5. grep -q off-line /proc/acpi/ac_adapter/*/state
  6. if [ $? = 0 ] ; then
  7. pm-suspend
  8. fi
  9. fi

With this script, when the lid is shut, it will check if the power is plugged in. If not, it'll put the computer to sleep. We also need to do it the other way: When the power plug is removed, we need to check if the lid is shut.

For this, we look at the power.sh script, which fires when the power plug is removed or put in.

Unfortunately, ubuntu does not provide a power.sh.pre and power.sh.post. That means that when we make changes to this file, we may have to be a little careful when we update acpid.

The first thing I did was to add lines to call power.sh.pre and power.sh.post to the power.sh script.

My power.sh script now reads:

  1. #!/bin/sh
  2.  
  3. test -f /usr/share/acpi-support/key-constants || exit 0
  4.  
  5. . /usr/share/acpi-support/policy-funcs
  6.  
  7. [ -x /etc/acpi/local/power.sh.pre ] && /etc/acpi/local/power.sh.pre
  8. if [ -z "$*" ] && [ `CheckPolicy` = 0 ]; then
  9. exit;
  10. fi
  11.  
  12. pm-powersave $*
  13. [ -x /etc/acpi/local/power.sh.post ] && /etc/acpi/local/power.sh.post

Putting these lines in here allows me to put the main part of the code in /etc/acpi/local/power.sh.pre. The text of this is exactly the same as the text of lid.sh.pre.

So that was pretty fun, right? I've got a couple more things here.

I had a pretty old computer that I was working on once. I often found that Firefox would run away with the processor and cause such high load that it would take a minute or more just to get access to a console to kill firefox.

So I used acpid to hook up the power button to automatically kill firefox. When firefox runs away with the cpu, I hit the power button. That runs the /etc/acpid/powerbtn.sh script.

Just like with power.sh, this does not have the "pre" and "post" hooks. Therefore, I add those hooks. Here is my powerbtn.sh script:

  1. #!/bin/sh
  2. # /etc/acpi/powerbtn.sh
  3. # Initiates a shutdown when the power putton has been
  4. # pressed.
  5.  
  6. # Skip if we just in the middle of resuming.
  7. test -f /var/lock/acpisleep && exit 0
  8.  
  9. [ -x /etc/acpi/local/powerbtn.sh.pre ] && /etc/acpi/local/powerbtn.sh.pre
  10. # If gnome-power-manager, kded4, dalston-power-applet or xfce4-power-manager
  11. # are running, let them handle policy This is effectively the same as
  12. # 'acpi-support's '/usr/share/acpi-support/policy-funcs' file.
  13.  
  14. if pidof gnome-power-manager kded4 dalston-power-applet xfce4-power-manager > /dev/null; then
  15. exit
  16. fi
  17. [ -x /etc/acpi/local/powerbtn.sh.post ] && /etc/acpi/local/powerbtn.sh.post
  18.  
  19. # If all else failed, just initiate a plain shutdown.
  20. /sbin/shutdown -h now "Power button pressed"

Then, in /etc/acpi/local/powerbtn.sh.pre, I add, simply,

  1. #!/bin/sh
  2. pkill firefox

So there you have it. Fun with acpid. That was fun, right?

Your rating: None Average: 4 (2 votes)