Use Linux ACPI to power down system gracefully

ACPI stands for Advanced Configuration and Power Interface. It can be used to power off system gracefully, this is especially useful in the case of virtulized Linux system. Linux ACPI

ACPI was first released in 1996 by Compaq/Hewlett-Packard, Intel, Microsoft, Phoenix and Toshiba.
It allows control of power management from within the operating system. Typically it can be configured from within the operating system. This is unlike APM where configuration often involves rebooting and entering the BIOS configuration screens to set parameters.

ACPI has several different software components:

  1. A subsystem which controls hardware states and functions that may have previously been in the BIOS configuration. These states include:
    1. thermal control
    2. motherboard configuration
    3. power states (sleep, suspend)
    4. </li>
    5. a policy manager, which is software that sits on top of the operating system and allows user input on the system policies.
    6. the ACPI also has device drivers that control/monitor devices such as a laptop battery, SMBus (communication/transmission path) and EC (embedded controller).
    The above statement is a bit abstract, I will use the power button as example to show how it works. how poer button works From high level, when the power button is pressed, Linux kernel will receive ACPI message, and process it. Eventually linux kernel will publish the ACPI event to the userspace. These events can be seen by running acpi\_listen by simply starting "acpi\_listen". This can be easily verified if you have virtualbox and run a Linux VM (e.g. ubuntu). In the window running the virtual machine, click menu "Machine->ACPI shutdown", you will see below:
    weng@weng-VirtualBox:~$ acpi_listen
    button/power PBTN 00000080 00000000
    button/power LNXPWRBN:00 00000080 00000002
    Also VirtualBox will prompt the user to choose what action to take: shutdown, restart, sleep.. This is possible because there is "acpid" process running:
    weng@weng-u1604:~$ ps -ef | grep acpid
    root      5814     1  0 Jul15 ?        00:00:00 /usr/sbin/acpid
    weng      7806  5803  0 00:04 pts/18   00:00:00 grep --color=auto acpid
    weng@weng-u1604:~$ 
    acpid listens to ACPI events, and processing the event based on rules provisioned under /etc/acpi/events/, then invoke proper action:
    weng@weng-u1604:~$ cat /etc/acpi/powerbtn.sh 
    #!/bin/sh
    # /etc/acpi/powerbtn.sh
    # Initiates a shutdown when the power putton has been
    # pressed.
    
    [ -r /usr/share/acpi-support/power-funcs ] && . /usr/share/acpi-support/power-funcs
    
    # If logind is running, it already handles power button presses; desktop
    # environments put inhibitors to logind if they want to handle the key
    # themselves.
    if pidof systemd-logind >/dev/null; then
        exit 0
    fi
    
    # getXuser gets the X user belonging to the display in $displaynum.
    # If you want the foreground X user, use getXconsole!
    getXuser() {
            user=`pinky -fw | awk '{ if ($2 == ":'$displaynum'" || $(NF) == ":'$displaynum'" ) { print $1; exit; } }'`
            if [ x"$user" = x"" ]; then
                    startx=`pgrep -n startx`
                    if [ x"$startx" != x"" ]; then
                            user=`ps -o user --no-headers $startx`
                    fi
            fi
            if [ x"$user" != x"" ]; then
                    userhome=`getent passwd $user | cut -d: -f6`
                    export XAUTHORITY=$userhome/.Xauthority
            else
                    export XAUTHORITY=""
            fi
            export XUSER=$user
    }
    
    # Skip if we just in the middle of resuming.
    test -f /var/lock/acpisleep && exit 0
    
    # If the current X console user is running a power management daemon that
    # handles suspend/resume requests, let them handle policy This is effectively
    # the same as 'acpi-support's '/usr/share/acpi-support/policy-funcs' file.
    
    [ -r /usr/share/acpi-support/power-funcs ] && getXconsole
    PMS="gnome-settings-daemon kpowersave xfce4-power-manager"
    PMS="$PMS guidance-power-manager.py dalston-power-applet"
    PMS="$PMS mate-settings-daemon"
    PMS="$PMS unity-settings-daemon"
    
    if pidof x $PMS > /dev/null; then
            exit
    elif test "$XUSER" != "" && pidof dcopserver > /dev/null && test -x /usr/bin/dcop && /usr/bin/dcop --user $XUSER kded kded loadedModules | grep -q klaptopdaemon; then
            exit
    elif test "$XUSER" != "" && test -x /usr/bin/qdbus; then
            kded4pid=$(pgrep -n -u $XUSER kded4)
            if test "$kded4pid" != ""; then
                    dbusaddr=$(su - $XUSER -c "grep -z DBUS_SESSION_BUS_ADDRESS /proc/$kded4pid/environ")
                    if test "$dbusaddr" != "" && su - $XUSER -c "export $dbusaddr; qdbus org.kde.kded" | grep -q powerdevil; then
                            exit
                    fi
            fi
    fi
    
    # If all else failed, just initiate a plain shutdown.
    /sbin/shutdown -h now "Power button pressed"
    weng@weng-u1604:~$ 
    VirtualBox also provide tool "VBoxManage" to manage VM easily, one of them is to equvalent to the menu click, this can be achived by "VBoxManage controlvm <name|uuid> acpipowerbutton". Be sure the running Linux kernel (in VirtualBox case, it is VM kernel), need have ACPI related configuration enabled: either build as module or builtin.