From f87b73ab44dc6273d9c89a0bf7f3a04c1ebfdd4b Mon Sep 17 00:00:00 2001 From: Sami Kerola Date: Sun, 11 Jan 2015 09:37:59 +0000 Subject: rtcwake: read accepted mode strings from /sys/power/state The rtcwake has various mode names that are internal to the command, listed in rtcwake_mode_string array, while some modes are dynamicaly listed in /sys/power/state. Together these form the allowed modes. [kzak@redhat.com: - cleanup strv usage] Reviewed-by: Karel Zak Signed-off-by: Sami Kerola Signed-off-by: Karel Zak --- sys-utils/rtcwake.c | 117 ++++++++++++++++++++++++++++------------------------ 1 file changed, 62 insertions(+), 55 deletions(-) (limited to 'sys-utils/rtcwake.c') diff --git a/sys-utils/rtcwake.c b/sys-utils/rtcwake.c index d457a5bf6..ebfd420e2 100644 --- a/sys-utils/rtcwake.c +++ b/sys-utils/rtcwake.c @@ -39,6 +39,7 @@ #include "optutils.h" #include "pathnames.h" #include "strutils.h" +#include "strv.h" #include "timeutils.h" #include "xalloc.h" @@ -53,28 +54,17 @@ #define DEFAULT_DEVICE "/dev/rtc0" enum rtc_modes { /* manual page --mode option explains these. */ - STANDBY_MODE = 0, - MEM_MODE, - FREEZE_MODE, - DISK_MODE, /* end of Documentation/power/states.txt modes */ - OFF_MODE, + OFF_MODE = 0, NO_MODE, ON_MODE, DISABLE_MODE, - SHOW_MODE + SHOW_MODE, + + SYSFS_MODE /* keep it last */ + }; -/* what system power mode to use? for now handle only standardized mode - * names; eventually when systems define their own state names, parse - * /sys/power/state - * - * "on" is used just to test the RTC alarm mechanism, bypassing all the - * wakeup-from-sleep infrastructure. */ -static const char *mode_str[] = { - [STANDBY_MODE] = "standby", - [MEM_MODE] = "mem", - [FREEZE_MODE] = "freeze", - [DISK_MODE] = "disk", +static const char *rtcwake_mode_string[] = { [OFF_MODE] = "off", [NO_MODE] = "no", [ON_MODE] = "on", @@ -89,6 +79,8 @@ enum clock_modes { }; struct rtcwake_control { + char *mode_str; /* name of the requested mode */ + char **possible_modes; /* modes listed in /sys/power/state */ char *adjfile; /* adjtime file path */ enum clock_modes clock_mode; /* hwclock timezone */ time_t sys_time; /* system time */ @@ -245,23 +237,24 @@ static int setup_alarm(struct rtcwake_control *ctl, int fd, time_t *wakeup) return 0; } -static int is_suspend_available(const int suspend) +static char **get_sys_power_states(struct rtcwake_control *ctl) { - int rc; - char buf[32]; - FILE *f = fopen(SYS_POWER_STATE_PATH, "r"); - - if (!f) - return -1; - if (fgets(buf, sizeof buf, f) == NULL) - rc = -1; - else - rc = strstr(buf, mode_str[suspend]) != NULL; - fclose(f); - return rc; + if (!ctl->possible_modes) { + int fd; + char buf[256] = { 0 }; + + if (!(fd = open(SYS_POWER_STATE_PATH, O_RDONLY))) + return NULL; + if (read(fd, &buf, sizeof buf) < 0) { + close(fd); + return NULL; + } + ctl->possible_modes = strv_split(buf, " \n"); + } + return ctl->possible_modes; } -static void suspend_system(struct rtcwake_control *ctl, int suspend) +static void suspend_system(struct rtcwake_control *ctl) { FILE *f = fopen(SYS_POWER_STATE_PATH, "w"); @@ -270,7 +263,7 @@ static void suspend_system(struct rtcwake_control *ctl, int suspend) return; } if (!ctl->dryrun) { - fprintf(f, "%s\n", mode_str[suspend]); + fprintf(f, "%s\n", ctl->mode_str); fflush(f); } /* this executes after wake from suspend */ @@ -338,13 +331,20 @@ static int print_alarm(struct rtcwake_control *ctl, int fd) return 0; } -static int get_mode(const char *optarg) +static int get_rtc_mode(struct rtcwake_control *ctl, const char *optarg) { - size_t i = ARRAY_SIZE(mode_str); + size_t i; + char **modes = get_sys_power_states(ctl), **m; - while (i--) - if (!strcmp(optarg, mode_str[i])) + STRV_FOREACH(m, modes) { + if (strcmp(optarg, *m) == 0) + return SYSFS_MODE; + } + + for (i = 0; i <= ARRAY_SIZE(rtcwake_mode_string); i++) + if (!strcmp(optarg, rtcwake_mode_string[i])) return i; + return -EINVAL; } @@ -364,25 +364,33 @@ static int open_dev_rtc(const char *devname) return fd; } -static void list_modes(void) +static void list_modes(struct rtcwake_control *ctl) { - int i = ARRAY_SIZE(mode_str); + size_t i; + char **modes = get_sys_power_states(ctl), **m; + + if (!modes) + errx(EXIT_FAILURE, _("could not read: %s"), SYS_POWER_STATE_PATH); - while (i--) - printf("%s%s", mode_str[i], i == 0 ? "" : " "); + STRV_FOREACH(m, modes) + printf("%s ", *m); + + for (i = 0; i < ARRAY_SIZE(rtcwake_mode_string); i++) + printf("%s ", rtcwake_mode_string[i]); putchar('\n'); } int main(int argc, char **argv) { struct rtcwake_control ctl = { + .mode_str = "suspend", /* default mode */ .adjfile = _PATH_ADJTIME, .clock_mode = CM_AUTO, 0 }; char *devname = DEFAULT_DEVICE; unsigned seconds = 0; - int suspend = STANDBY_MODE; + int suspend = SYSFS_MODE; int rc = EXIT_SUCCESS; int t; int fd; @@ -418,6 +426,7 @@ int main(int argc, char **argv) bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); atexit(close_stdout); + while ((t = getopt_long(argc, argv, "A:ahd:lm:ns:t:uVv", long_options, NULL)) != EOF) { err_exclusive_options(t, long_options, excl, excl_st); @@ -437,12 +446,13 @@ int main(int argc, char **argv) break; case OPT_LIST: - list_modes(); + list_modes(&ctl); return EXIT_SUCCESS; case 'm': - if ((suspend = get_mode(optarg)) < 0) + if ((suspend = get_rtc_mode(&ctl, optarg)) < 0) errx(EXIT_FAILURE, _("unrecognized suspend state '%s'"), optarg); + ctl.mode_str = optarg; break; case 'n': ctl.dryrun = 1; @@ -496,22 +506,18 @@ int main(int argc, char **argv) fd = open_dev_rtc(devname); if (suspend != ON_MODE && suspend != NO_MODE && !is_wakeup_enabled(devname)) errx(EXIT_FAILURE, _("%s not enabled for wakeup events"), devname); + /* relative or absolute alarm time, normalized to time_t */ if (get_basetimes(&ctl, fd) < 0) exit(EXIT_FAILURE); + if (ctl.verbose) printf(_("alarm %ld, sys_time %ld, rtc_time %ld, seconds %u\n"), alarm, ctl.sys_time, ctl.rtc_time, seconds); + if (suspend != DISABLE_MODE && suspend != SHOW_MODE) { - if ((suspend == STANDBY_MODE || suspend == MEM_MODE - || suspend == FREEZE_MODE || suspend == DISK_MODE) - && is_suspend_available(suspend) <= 0) { - errx(EXIT_FAILURE, _("suspend to \"%s\" unavailable"), - mode_str[suspend]); - } - /* care about alarm setup only if the show|disable - * modes are not set - */ + /* perform alarm setup when the show or disable modes are + * not set */ if (alarm) { if (alarm < ctl.sys_time) errx(EXIT_FAILURE, _("time doesn't go backward to %s"), @@ -527,11 +533,12 @@ int main(int argc, char **argv) ctime(&alarm)); else printf(_("%s: wakeup from \"%s\" using %s at %s"), - program_invocation_short_name, mode_str[suspend], devname, + program_invocation_short_name, ctl.mode_str, devname, ctime(&alarm)); fflush(stdout); xusleep(10 * 1000); } + switch (suspend) { case NO_MODE: if (ctl.verbose) @@ -591,9 +598,9 @@ int main(int argc, char **argv) break; default: if (ctl.verbose) - printf(_("suspend mode: %s; suspending system\n"), mode_str[suspend]); + printf(_("suspend mode: %s; suspending system\n"), ctl.mode_str); sync(); - suspend_system(&ctl, suspend); + suspend_system(&ctl); } if (!ctl.dryrun) { -- cgit v1.2.3-55-g7522