From bd9bb92ca05b6e5590364a871f0add25aa99e2af Mon Sep 17 00:00:00 2001 From: Joachim Wiberg Date: Sat, 16 Apr 2022 23:59:32 +0200 Subject: [PATCH] Replace reboot(RB_SW_SUSPEND) w/ internal /sys/power/state API Signed-off-by: Joachim Wiberg --- src/api.c | 4 ++-- src/reboot.c | 6 ++++-- src/util.c | 34 ++++++++++++++++++++++++++++++++++ src/util.h | 2 ++ 4 files changed, 42 insertions(+), 4 deletions(-) diff --git a/src/api.c b/src/api.c index d100b679..5a643037 100644 --- a/src/api.c +++ b/src/api.c @@ -250,10 +250,10 @@ static int do_reboot(int cmd, char *buf, size_t len) case INIT_CMD_SUSPEND: _d("suspend"); sync(); - rc = reboot(RB_SW_SUSPEND); + rc = sys_suspend(); if (rc) { if (errno == EINVAL) - snprintf(buf, len, "Kernel does not support suspend."); + snprintf(buf, len, "Kernel does not support suspend to RAM."); else snprintf(buf, len, "Failed: %s", strerror(errno)); } diff --git a/src/reboot.c b/src/reboot.c index 62ed56fa..b70d2ad4 100644 --- a/src/reboot.c +++ b/src/reboot.c @@ -160,6 +160,8 @@ int reboot_main(int argc, char *argv[]) transform(NULL); if (force) { + sync(); + switch (cmd) { case CMD_REBOOT: c = reboot(RB_AUTOBOOT); @@ -174,9 +176,9 @@ int reboot_main(int argc, char *argv[]) break; case CMD_SUSPEND: - c = reboot(RB_SW_SUSPEND); + c = suspend(); if (c && errno == EINVAL) - errx(1, "Kernel does not support suspend."); + errx(1, "Kernel does not support suspend to RAM."); break; case CMD_UNKNOWN: diff --git a/src/util.c b/src/util.c index 2372e533..66a04e72 100644 --- a/src/util.c +++ b/src/util.c @@ -235,6 +235,40 @@ int fngetint(char *path, int *val) return 0; } +/* + * This is a replacement for the non-working reboot(RB_SW_SUSPEND). It + * checks for suspend to RAM support, assuming `mem_sleep` has a sane + * default, e.g. 'deep' or 's2idle'. The latter should be possible to + * select from finit.conf, but for now we go with the kernel default. + * For more information on kernel sleep states, see: + * https://www.kernel.org/doc/html/latest/admin-guide/pm/sleep-states.html + */ +int suspend(void) +{ + char buf[80]; + char *ptr; + + if (fnread(buf, sizeof(buf), "/sys/power/state") <= 0) { + opnotsup: + errno = EINVAL; + return 1; + } + + chomp(buf); + + ptr = strtok(buf, " "); + while (ptr) { + if (!strcmp(ptr, "mem")) + break; + + ptr = strtok(NULL, " "); + } + if (!ptr) + goto opnotsup; + + return fnwrite("mem", "/sys/power/state"); +} + int strtobytes(char *arg) { int mod = 0, bytes; diff --git a/src/util.h b/src/util.h index 2b4b79cf..cc879cd6 100644 --- a/src/util.h +++ b/src/util.h @@ -59,6 +59,8 @@ int fnread (char *buf, size_t len, char *fmt, ...) __attribute__ ((forma int fnwrite (char *value, char *fmt, ...) __attribute__ ((format (printf, 2, 3))); int fngetint (char *path, int *val); +int suspend (void); + int strtobytes (char *arg); char *sig2str (int sig); int str2sig (char *sig);