]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
rtcwake: read accepted mode strings from /sys/power/state
authorSami Kerola <kerolasa@iki.fi>
Sun, 11 Jan 2015 09:37:59 +0000 (09:37 +0000)
committerKarel Zak <kzak@redhat.com>
Mon, 29 Jun 2015 11:39:37 +0000 (13:39 +0200)
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 <kzak@redhat.com>
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
Signed-off-by: Karel Zak <kzak@redhat.com>
sys-utils/rtcwake.c

index d457a5bf69fd6be1b212a34cd9a952f0bbb0f639..ebfd420e2ed814ba4de932e8aabff859a8a71a85 100644 (file)
@@ -39,6 +39,7 @@
 #include "optutils.h"
 #include "pathnames.h"
 #include "strutils.h"
+#include "strv.h"
 #include "timeutils.h"
 #include "xalloc.h"
 
 #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) {