git: 88a198af3c20 - main - powerd: use nlsysevent if possible
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 08 Oct 2024 06:44:59 UTC
The branch main has been updated by bapt:
URL: https://cgit.FreeBSD.org/src/commit/?id=88a198af3c20730f638a60aa699f4d5aa1650512
commit 88a198af3c20730f638a60aa699f4d5aa1650512
Author: Baptiste Daroussin <bapt@FreeBSD.org>
AuthorDate: 2024-10-07 08:48:55 +0000
Commit: Baptiste Daroussin <bapt@FreeBSD.org>
CommitDate: 2024-10-08 06:40:58 +0000
powerd: use nlsysevent if possible
instead of depending on devd and its socket, try to use nlsysevent
instead. This makes powerd independant from devd.
Approved by: des
Reviewed by: des
Differential Revission: https://reviews.freebsd.org/D46972
---
usr.sbin/powerd/powerd.c | 113 ++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 106 insertions(+), 7 deletions(-)
diff --git a/usr.sbin/powerd/powerd.c b/usr.sbin/powerd/powerd.c
index 8517b4f2bf0b..7be24e0c01ad 100644
--- a/usr.sbin/powerd/powerd.c
+++ b/usr.sbin/powerd/powerd.c
@@ -29,17 +29,26 @@
#include <sys/param.h>
#include <sys/ioctl.h>
+#include <sys/linker.h>
+#include <sys/module.h>
#include <sys/sysctl.h>
#include <sys/resource.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/un.h>
+#include <netlink/netlink.h>
+#include <netlink/netlink_generic.h>
+#include <netlink/netlink_snl.h>
+#include <netlink/netlink_snl_generic.h>
+#include <netlink/netlink_sysevent.h>
+
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <libutil.h>
#include <signal.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -88,7 +97,8 @@ static int read_freqs(int *numfreqs, int **freqs, int **power,
int minfreq, int maxfreq);
static int set_freq(int freq);
static void acline_init(void);
-static void acline_read(void);
+static void acline_read(int rfds);
+static bool netlink_init(void);
static int devd_init(void);
static void devd_close(void);
static void handle_sigs(int sig);
@@ -117,6 +127,7 @@ typedef enum {
#ifdef USE_APM
ac_apm,
#endif
+ ac_acpi_netlink,
} acline_mode_t;
static acline_mode_t acline_mode;
static acline_mode_t acline_mode_user = ac_none;
@@ -124,6 +135,8 @@ static acline_mode_t acline_mode_user = ac_none;
static int apm_fd = -1;
#endif
static int devd_pipe = -1;
+static bool try_netlink = true;
+static struct snl_state ss;
#define DEVD_RETRY_INTERVAL 60 /* seconds */
static struct timeval tried_devd;
@@ -325,9 +338,48 @@ acline_init(void)
}
}
+struct nlevent {
+ const char *name;
+ const char *subsystem;
+ const char *type;
+ const char *data;
+};
+#define _OUT(_field) offsetof(struct nlevent, _field)
+static struct snl_attr_parser ap_nlevent_get[] = {
+ { .type = NLSE_ATTR_SYSTEM, .off = _OUT(name), .cb = snl_attr_get_string },
+ { .type = NLSE_ATTR_SUBSYSTEM, .off = _OUT(subsystem), .cb = snl_attr_get_string },
+ { .type = NLSE_ATTR_TYPE, .off = _OUT(type), .cb = snl_attr_get_string },
+ { .type = NLSE_ATTR_DATA, .off = _OUT(data), .cb = snl_attr_get_string },
+};
+#undef _OUT
+
+SNL_DECLARE_GENL_PARSER(nlevent_get_parser, ap_nlevent_get);
+
static void
-acline_read(void)
+acline_read(int rfds)
{
+ if (acline_mode == ac_acpi_netlink) {
+ struct nlmsghdr *hdr;
+ struct nlevent ne;
+ char *ptr;
+ int notify;
+
+ if (rfds == 0)
+ return;
+ hdr = snl_read_message(&ss);
+ if (hdr != NULL && hdr->nlmsg_type != NLMSG_ERROR) {
+ memset(&ne, 0, sizeof(ne));
+ if (!snl_parse_nlmsg(&ss, hdr, &nlevent_get_parser, &ne))
+ return;
+ if (strcmp(ne.subsystem, "ACAD") != 0)
+ return;
+ if ((ptr = strstr(ne.data, "notify=")) != NULL &&
+ sscanf(ptr, "notify=%x", ¬ify) == 1)
+ acline_status = (notify ? SRC_AC : SRC_BATTERY);
+ }
+ return;
+
+ }
if (acline_mode == ac_acpi_devd) {
char buf[DEVCTL_MAXBUF], *ptr;
ssize_t rlen;
@@ -383,10 +435,20 @@ acline_read(void)
#else
if (acline_mode == ac_sysctl &&
(acline_mode_user == ac_none ||
- acline_mode_user == ac_acpi_devd)) {
+ acline_mode_user == ac_acpi_devd ||
+ acline_mode_user == ac_acpi_netlink)) {
#endif
struct timeval now;
+ if (acline_mode_user != ac_acpi_devd && try_netlink) {
+ try_netlink = false; /* only try once */
+ if (netlink_init()) {
+ if (vflag)
+ warnx("using netlink for AC line status");
+ acline_mode = ac_acpi_netlink;
+ }
+ return;
+ }
gettimeofday(&now, NULL);
if (now.tv_sec > tried_devd.tv_sec + DEVD_RETRY_INTERVAL) {
if (devd_init() >= 0) {
@@ -399,6 +461,38 @@ acline_read(void)
}
}
+bool
+netlink_init(void)
+{
+ struct _getfamily_attrs attrs;
+
+ if (modfind("nlsysevent") < 0)
+ kldload("nlsysevent");
+ if (modfind("nlsysevent") < 0)
+ return (false);
+
+ if (!snl_init(&ss, NETLINK_GENERIC))
+ return (false);
+
+ if (!snl_get_genl_family_info(&ss, "nlsysevent", &attrs))
+ return (false);
+
+ for (unsigned int i = 0; i < attrs.mcast_groups.num_groups; i++) {
+ if (strcmp(attrs.mcast_groups.groups[i]->mcast_grp_name,
+ "ACPI") == 0) {
+ if (setsockopt(ss.fd, SOL_NETLINK,
+ NETLINK_ADD_MEMBERSHIP,
+ &attrs.mcast_groups.groups[i]->mcast_grp_id,
+ sizeof(attrs.mcast_groups.groups[i]->mcast_grp_id))
+ == -1) {
+ warnx("Cannot subscribe to \"ACPI\"");
+ return (false);
+ }
+ }
+ }
+ return (true);
+}
+
static int
devd_init(void)
{
@@ -460,6 +554,8 @@ parse_acline_mode(char *arg, int ch)
else if (strcmp(arg, "apm") == 0)
acline_mode_user = ac_apm;
#endif
+ else if (strcmp(arg, "netlink") == 0)
+ acline_mode_user = ac_acpi_netlink;
else
errx(1, "bad option: -%c %s", (char)ch, optarg);
}
@@ -485,7 +581,7 @@ main(int argc, char * argv[])
{
struct timeval timeout;
fd_set fdset;
- int nfds;
+ int nfds, rfds;
struct pidfh *pfh = NULL;
const char *pidfile = NULL;
int freq, curfreq, initfreq, *freqs, i, j, *mwatts, numfreqs, load;
@@ -638,7 +734,7 @@ main(int argc, char * argv[])
* If we are in adaptive mode and the current frequency is outside the
* user-defined range, adjust it to be within the user-defined range.
*/
- acline_read();
+ acline_read(0);
if (acline_status > SRC_UNKNOWN)
errx(1, "invalid AC line status %d", acline_status);
if ((acline_status == SRC_AC &&
@@ -683,6 +779,9 @@ main(int argc, char * argv[])
if (devd_pipe >= 0) {
FD_SET(devd_pipe, &fdset);
nfds = devd_pipe + 1;
+ } else if (acline_mode == ac_acpi_netlink) {
+ FD_SET(ss.fd, &fdset);
+ nfds = ss.fd + 1;
} else {
nfds = 0;
}
@@ -694,7 +793,7 @@ main(int argc, char * argv[])
to = poll_ival * 4;
timeout.tv_sec = to / 1000000;
timeout.tv_usec = to % 1000000;
- select(nfds, &fdset, NULL, &fdset, &timeout);
+ rfds = select(nfds, &fdset, NULL, &fdset, &timeout);
/* If the user requested we quit, print some statistics. */
if (exit_requested) {
@@ -706,7 +805,7 @@ main(int argc, char * argv[])
}
/* Read the current AC status and record the mode. */
- acline_read();
+ acline_read(rfds);
switch (acline_status) {
case SRC_AC:
mode = mode_ac;