From 240dbaa44f8e5ad51775c776fc3ce9cd2f19f037 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 25 Dec 2012 16:29:51 +0100 Subject: [PATCH] unit: add ConditionACPower= --- TODO | 4 -- man/systemd.unit.xml | 18 ++++++ src/ac-power/ac-power.c | 80 +-------------------------- src/core/condition.c | 14 +++++ src/core/condition.h | 1 + src/core/load-fragment-gperf.gperf.m4 | 1 + src/shared/util.c | 78 ++++++++++++++++++++++++++ src/shared/util.h | 2 + 8 files changed, 117 insertions(+), 81 deletions(-) diff --git a/TODO b/TODO index 3ec87c5a9..aa9292ec6 100644 --- 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 diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml index bf91b4eb1..8570815ad 100644 --- a/man/systemd.unit.xml +++ b/man/systemd.unit.xml @@ -790,6 +790,7 @@ ConditionSecurity= ConditionCapability= ConditionHost= + ConditionACPower= ConditionNull= Before starting a unit @@ -959,6 +960,23 @@ The test may be negated by prepending an exclamation mark. + ConditionACPower= + 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 + true 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 false the + condition will hold only if there is + at least one AC connector known and + all AC connectors are disconnected + from a power source. + Finally, ConditionNull= may be used to add a constant condition diff --git a/src/ac-power/ac-power.c b/src/ac-power/ac-power.c index 37313cf14..bd1b6ecc7 100644 --- a/src/ac-power/ac-power.c +++ b/src/ac-power/ac-power.c @@ -19,93 +19,19 @@ along with systemd; If not, see . ***/ -#include -#include -#include -#include -#include - #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; } diff --git a/src/core/condition.c b/src/core/condition.c index 32a37ccad..b3184922b 100644 --- a/src/core/condition.c +++ b/src/core/condition.c @@ -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" }; diff --git a/src/core/condition.h b/src/core/condition.h index 03954e40b..1797385d2 100644 --- a/src/core/condition.h +++ b/src/core/condition.h @@ -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 diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 7212053ca..7fba0cfb7 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -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) diff --git a/src/shared/util.c b/src/shared/util.c index 1779625c7..3f00db7f2 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -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; +} diff --git a/src/shared/util.h b/src/shared/util.h index 25b349a17..bb6602fb2 100644 --- a/src/shared/util.h +++ b/src/shared/util.h @@ -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); -- 2.30.2