chiark / gitweb /
unit: add ConditionACPower=
authorLennart Poettering <lennart@poettering.net>
Tue, 25 Dec 2012 15:29:51 +0000 (16:29 +0100)
committerLennart Poettering <lennart@poettering.net>
Mon, 31 Dec 2012 20:24:26 +0000 (21:24 +0100)
TODO
man/systemd.unit.xml
src/ac-power/ac-power.c
src/core/condition.c
src/core/condition.h
src/core/load-fragment-gperf.gperf.m4
src/shared/util.c
src/shared/util.h

diff --git a/TODO b/TODO
index 3ec87c5..aa9292e 100644 (file)
--- a/TODO
+++ b/TODO
@@ -57,8 +57,6 @@ Features:
 
 * When shutdown.target is queued begin with an asynchronous sync()?
 
-* Add ConditionBatteryPower= or ConditionACPower=? (but definitely not both)
-
 * add API to close/reopen/get fd for journal client fd in libsystemd-journal.
 
 * maybe add API to send pairs of iovecs via sd_journal_send
@@ -240,8 +238,6 @@ Features:
 
 * system-wide seccomp filter
 
-* ability to pass fds into systemd
-
 * system.conf should have controls for cgroups
 
 * bind mount read-only the cgroup tree higher than nspawn
index bf91b4e..8570815 100644 (file)
                                 <term><varname>ConditionSecurity=</varname></term>
                                 <term><varname>ConditionCapability=</varname></term>
                                 <term><varname>ConditionHost=</varname></term>
+                                <term><varname>ConditionACPower=</varname></term>
                                 <term><varname>ConditionNull=</varname></term>
 
                                 <listitem><para>Before starting a unit
                                 The test may be negated by prepending
                                 an exclamation mark.</para>
 
+                                <para><varname>ConditionACPower=</varname>
+                                may may be used to check whether the
+                                system has AC power, or is exlcusively
+                                battery powered at the time of
+                                activation of the unit. This takes a
+                                boolean argument. If set to
+                                <varname>true</varname> the condition
+                                will hold only if at least one AC
+                                connector of the system is connected
+                                to a power source, or if no AC
+                                connectors are known. Conversely, if
+                                set to <varname>false</varname> the
+                                condition will hold only if there is
+                                at least one AC connector known and
+                                all AC connectors are disconnected
+                                from a power source.</para>
+
                                 <para>Finally,
                                 <varname>ConditionNull=</varname> may
                                 be used to add a constant condition
index 37313cf..bd1b6ec 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdlib.h>
-#include <stdbool.h>
-#include <errno.h>
-#include <string.h>
-#include <libudev.h>
-
 #include "util.h"
 
-static int on_ac_power(void) {
-        int r;
-
-        struct udev *udev;
-        struct udev_enumerate *e = NULL;
-        struct udev_list_entry *item = NULL, *first = NULL;
-        bool found_offline = false, found_online = false;
-
-        if (!(udev = udev_new())) {
-                r = -ENOMEM;
-                goto finish;
-        }
-
-        if (!(e = udev_enumerate_new(udev))) {
-                r = -ENOMEM;
-                goto finish;
-        }
-
-        if (udev_enumerate_add_match_subsystem(e, "power_supply") < 0) {
-                r = -EIO;
-                goto finish;
-        }
-
-        if (udev_enumerate_scan_devices(e) < 0) {
-                r = -EIO;
-                goto finish;
-        }
-
-        first = udev_enumerate_get_list_entry(e);
-        udev_list_entry_foreach(item, first) {
-                struct udev_device *d;
-                const char *type, *online;
-
-                if (!(d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item)))) {
-                        r = -ENOMEM;
-                        goto finish;
-                }
-
-                if (!(type = udev_device_get_sysattr_value(d, "type")))
-                        goto next;
-
-                if (!streq(type, "Mains"))
-                        goto next;
-
-                if (!(online = udev_device_get_sysattr_value(d, "online")))
-                        goto next;
-
-                if (streq(online, "1")) {
-                        found_online = true;
-                        break;
-                } else if (streq(online, "0"))
-                        found_offline = true;
-
-        next:
-                udev_device_unref(d);
-        }
-
-        r = found_online || !found_offline;
-
-finish:
-        if (e)
-                udev_enumerate_unref(e);
-
-        if (udev)
-                udev_unref(udev);
-
-        return r;
-}
-
 int main(int argc, char *argv[]) {
         int r;
 
         /* This is mostly intended to be used for scripts which want
          * to detect whether AC power is plugged in or not. */
 
-        if ((r = on_ac_power()) < 0) {
+        r = on_ac_power();
+        if (r < 0) {
                 log_error("Failed to read AC status: %s", strerror(-r));
                 return EXIT_FAILURE;
         }
 
-        return r == 0;
+        return r != 0 ? EXIT_SUCCESS : EXIT_FAILURE;
 }
index 32a37cc..b318492 100644 (file)
@@ -221,6 +221,16 @@ static bool test_host(const char *parameter) {
         return b;
 }
 
+static bool test_ac_power(const char *parameter) {
+        int r;
+
+        r = parse_boolean(parameter);
+        if (r < 0)
+                return true;
+
+        return (on_ac_power() != 0) == !!r;
+}
+
 bool condition_test(Condition *c) {
         assert(c);
 
@@ -294,6 +304,9 @@ bool condition_test(Condition *c) {
         case CONDITION_HOST:
                 return test_host(c->parameter) == !c->negate;
 
+        case CONDITION_AC_POWER:
+                return test_ac_power(c->parameter) == !c->negate;
+
         case CONDITION_NULL:
                 return !c->negate;
 
@@ -364,6 +377,7 @@ static const char* const condition_type_table[_CONDITION_TYPE_MAX] = {
         [CONDITION_VIRTUALIZATION] = "ConditionVirtualization",
         [CONDITION_SECURITY] = "ConditionSecurity",
         [CONDITION_HOST] = "ConditionHost",
+        [CONDITION_AC_POWER] = "ConditionACPower",
         [CONDITION_NULL] = "ConditionNull"
 };
 
index 03954e4..1797385 100644 (file)
@@ -40,6 +40,7 @@ typedef enum ConditionType {
         CONDITION_SECURITY,
         CONDITION_CAPABILITY,
         CONDITION_HOST,
+        CONDITION_AC_POWER,
         CONDITION_NULL,
         _CONDITION_TYPE_MAX,
         _CONDITION_TYPE_INVALID = -1
index 7212053..7fba0cf 100644 (file)
@@ -137,6 +137,7 @@ Unit.ConditionVirtualization,    config_parse_unit_condition_string, CONDITION_V
 Unit.ConditionSecurity,          config_parse_unit_condition_string, CONDITION_SECURITY,            0
 Unit.ConditionCapability,        config_parse_unit_condition_string, CONDITION_CAPABILITY,          0
 Unit.ConditionHost,              config_parse_unit_condition_string, CONDITION_HOST,                0
+Unit.ConditionACPower,           config_parse_unit_condition_string, CONDITION_AC_POWER,            0
 Unit.ConditionNull,              config_parse_unit_condition_null,   0,                             0
 m4_dnl
 Service.PIDFile,                 config_parse_unit_path_printf,      0,                             offsetof(Service, pid_file)
index 1779625..3f00db7 100644 (file)
@@ -5763,3 +5763,81 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz) {
 
         return obuf;
 }
+
+int on_ac_power(void) {
+        bool found_offline = false, found_online = false;
+        _cleanup_closedir_ DIR *d = NULL;
+
+        d = opendir("/sys/class/power_supply");
+        if (!d)
+                return -errno;
+
+        for (;;) {
+                struct dirent *de;
+                union dirent_storage buf;
+                _cleanup_free_ char *p = NULL;
+                _cleanup_close_ int fd = -1, device = -1;
+                char contents[6];
+                ssize_t n;
+                int k;
+
+                k = readdir_r(d, &buf.de, &de);
+                if (k != 0)
+                        return -k;
+
+                if (!de)
+                        break;
+
+                if (ignore_file(de->d_name))
+                        continue;
+
+                device = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_NOCTTY);
+                if (device < 0) {
+                        if (errno == ENOENT || errno == ENOTDIR)
+                                continue;
+
+                        return -errno;
+                }
+
+                fd = openat(device, "type", O_RDONLY|O_CLOEXEC|O_NOCTTY);
+                if (fd < 0) {
+                        if (errno == ENOENT)
+                                continue;
+
+                        return -errno;
+                }
+
+                n = read(fd, contents, sizeof(contents));
+                if (n < 0)
+                        return -errno;
+
+                if (n != 6 || memcmp(contents, "Mains\n", 6))
+                        continue;
+
+                close_nointr_nofail(fd);
+                fd = openat(device, "online", O_RDONLY|O_CLOEXEC|O_NOCTTY);
+                if (fd < 0) {
+                        if (errno == ENOENT)
+                                continue;
+
+                        return -errno;
+                }
+
+                n = read(fd, contents, sizeof(contents));
+                if (n < 0)
+                        return -errno;
+
+                if (n != 2 || contents[1] != '\n')
+                        return -EIO;
+
+                if (contents[0] == '1') {
+                        found_online = true;
+                        break;
+                } else if (contents[0] == '0')
+                        found_offline = true;
+                else
+                        return -EIO;
+        }
+
+        return found_online || !found_offline;
+}
index 25b349a..bb6602f 100644 (file)
@@ -561,3 +561,5 @@ const char *draw_special_char(DrawSpecialChar ch);
 char *strreplace(const char *text, const char *old_string, const char *new_string);
 
 char *strip_tab_ansi(char **p, size_t *l);
+
+int on_ac_power(void);