From 6f82b806add1e25ac266600bf19408fa90fedfd7 Mon Sep 17 00:00:00 2001 From: Joachim Wiberg Date: Tue, 11 May 2021 07:02:49 +0200 Subject: [PATCH] plugins: new sys condition event monitor (wip) Signed-off-by: Joachim Wiberg --- plugins/Makefile.am | 4 +- plugins/sys.c | 196 ++++++++++++++++++++++++++++++++++++++++++++ src/cond-w.c | 2 +- src/cond.h | 6 +- 4 files changed, 203 insertions(+), 5 deletions(-) create mode 100644 plugins/sys.c diff --git a/plugins/Makefile.am b/plugins/Makefile.am index 9fdcc1d0..72414775 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -7,7 +7,7 @@ AM_CPPFLAGS += $(lite_CFLAGS) if STATIC noinst_LTLIBRARIES = libplug.la -libplug_la_SOURCES = bootmisc.c modprobe.c rtc.c pidfile.c procps.c tty.c urandom.c usr.c +libplug_la_SOURCES = bootmisc.c modprobe.c rtc.c pidfile.c procps.c sys.c tty.c urandom.c usr.c if BUILD_ALSA_UTILS_PLUGIN libplug_la_SOURCES += alsa-utils.c @@ -34,7 +34,7 @@ libplug_la_SOURCES += resolvconf.c endif else -pkglib_LTLIBRARIES = bootmisc.la modprobe.la rtc.la pidfile.la procps.la tty.la urandom.la usr.la +pkglib_LTLIBRARIES = bootmisc.la modprobe.la rtc.la pidfile.la procps.la sys.la tty.la urandom.la usr.la if BUILD_ALSA_UTILS_PLUGIN pkglib_LTLIBRARIES += alsa-utils.la diff --git a/plugins/sys.c b/plugins/sys.c new file mode 100644 index 00000000..c3167cc0 --- /dev/null +++ b/plugins/sys.c @@ -0,0 +1,196 @@ +/* System condtion event monitor for the Finit condition engine + * + * Copyright (c) 2021 Joachim Wiberg + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include "finit.h" +#include "cond.h" +#include "pid.h" +#include "plugin.h" +#include "iwatch.h" + +#define _PATH_SYSFS_PWR "/sys/class/power_supply" + +static struct iwatch iw_sys; +static int num_ac; + +static void check_online(char *path, int clear) +{ + char cond[MAX_COND_LEN] = COND_SYS; + int val; + + if (fngetint(path, &val)) + return; + + strlcat(cond, "pwr/ac", sizeof(cond)); + if (val) + cond_set_oneshot(cond); + else if (clear) + cond_clear(cond); +} + +static void sys_callback(void *arg, int fd, int events) +{ + static char ev_buf[8 *(sizeof(struct inotify_event) + NAME_MAX + 1) + 1]; + struct inotify_event *ev; + ssize_t sz; + size_t off; + + sz = read(fd, ev_buf, sizeof(ev_buf) - 1); + if (sz <= 0) { + _pe("invalid inotify event"); + return; + } + ev_buf[sz] = 0; + + for (off = 0; off < (size_t)sz; off += sizeof(*ev) + ev->len) { + struct iwatch_path *iwp; + + if (off + sizeof(*ev) > (size_t)sz) + break; + + ev = (struct inotify_event *)&ev_buf[off]; + if (off + sizeof(*ev) + ev->len > (size_t)sz) + break; + + _d("name %s, event: 0x%08x", ev->name, ev->mask); + if (!ev->mask) + continue; + + /* Find base path for this event */ + iwp = iwatch_find_by_wd(&iw_sys, ev->wd); + if (!iwp) + continue; + + check_online(iwp->path, 1); + } +} + +static int is_ac(char *path, size_t len) +{ + char type[32] = { 0 }; + char *types[] = { + "Mains", + "USB", + "BrickID", + "Wireless", + NULL + }; + FILE *fp; + int i; + + strlcat(path, "/type", len); + fp = fopen(path, "r"); + if (!fp) + return 0; + + if (!fgets(type, sizeof(type), fp)) { + fclose(fp); + return 0; + } + fclose(fp); + + for (i = 0; types[i]; i++) { + if (!strncmp(type, types[i], strlen(types[i]))) + return 1; + } + + return 0; +} + +static void sys_init(void *arg) +{ + struct dirent **d = NULL; + char path[384]; + int i, n; + + if (mkpath(pid_runpath(_PATH_CONDSYS, path, sizeof(path)), 0755) && errno != EEXIST) { + _pe("Failed creating %s condition directory, %s", COND_SYS, _PATH_CONDSYS); + return; + } + + n = scandir(_PATH_SYSFS_PWR, &d, NULL, alphasort); + if (n <= 0) { + iwatch_exit(&iw_sys); + return; + } + + for (i = 0; i < n; i++) { + char *nm = d[i]->d_name; + + snprintf(path, sizeof(path), "%s/%s", _PATH_SYSFS_PWR, nm); + if (is_ac(path, sizeof(path))) { + num_ac++; + + snprintf(path, sizeof(path), "%s/%s/online", _PATH_SYSFS_PWR, nm); + check_online(path, 0); + + if (iwatch_add(&iw_sys, path, 0)) + _pe("Failed setting up pwr monitor for %s", path); + } + free(d[i]); + } + free(d); +} + +static plugin_t plugin = { + .name = __FILE__, + .hook[HOOK_BASEFS_UP] = { .cb = sys_init }, +}; + +PLUGIN_INIT(plugin_init) +{ + int fd; + + if (!fisdir(_PATH_SYSFS_PWR)) { + _w("System does not have %s, disabling AC power monitor.", _PATH_SYSFS_PWR); + return; + } + + fd = iwatch_init(&iw_sys); + if (fd < 0) + return; + + plugin.io.fd = fd; + plugin.io.cb = sys_callback; + plugin.io.flags = PLUGIN_IO_READ; + + plugin_register(&plugin); +} + +PLUGIN_EXIT(plugin_exit) +{ + iwatch_exit(&iw_sys); + plugin_unregister(&plugin); +} + +/** + * Local Variables: + * indent-tabs-mode: t + * c-file-style: "linux" + * End: + */ diff --git a/src/cond-w.c b/src/cond-w.c index 40e1383b..d0a4bda9 100644 --- a/src/cond-w.c +++ b/src/cond-w.c @@ -163,7 +163,7 @@ int cond_set_path(const char *path, enum cond_state next) return next != prev; } -/* Should only be used by cond_set*(), cond_clear(), and usr plugin! */ +/* Should only be used by cond_set*(), cond_clear(), and usr/sys plugins! */ void cond_update(const char *name) { svc_t *svc, *iter = NULL; diff --git a/src/cond.h b/src/cond.h index dc2d990f..e011fc31 100644 --- a/src/cond.h +++ b/src/cond.h @@ -5,12 +5,14 @@ #include #define COND_BASE "finit/cond" -#define COND_USR "usr/" #define COND_PID "pid/" +#define COND_SYS "sys/" +#define COND_USR "usr/" #define _PATH_COND _PATH_VARRUN COND_BASE "/" -#define _PATH_CONDUSR _PATH_COND COND_USR #define _PATH_CONDPID _PATH_COND COND_PID +#define _PATH_CONDSYS _PATH_COND COND_SYS +#define _PATH_CONDUSR _PATH_COND COND_USR #define _PATH_RECONF _PATH_COND "reconf" typedef enum cond_state {