summaryrefslogtreecommitdiffstats
path: root/sys-utils/rtcwake.c
diff options
context:
space:
mode:
authorSami Kerola2015-01-11 10:37:59 +0100
committerKarel Zak2015-06-29 13:39:37 +0200
commitf87b73ab44dc6273d9c89a0bf7f3a04c1ebfdd4b (patch)
tree1e4f5574eb4ee6a9729d188ec5ca424bf9336acb /sys-utils/rtcwake.c
parentrtcwake: make some command line options mutually exclusive (diff)
downloadkernel-qcow2-util-linux-f87b73ab44dc6273d9c89a0bf7f3a04c1ebfdd4b.tar.gz
kernel-qcow2-util-linux-f87b73ab44dc6273d9c89a0bf7f3a04c1ebfdd4b.tar.xz
kernel-qcow2-util-linux-f87b73ab44dc6273d9c89a0bf7f3a04c1ebfdd4b.zip
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 <kzak@redhat.com> Signed-off-by: Sami Kerola <kerolasa@iki.fi> Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'sys-utils/rtcwake.c')
-rw-r--r--sys-utils/rtcwake.c117
1 files changed, 62 insertions, 55 deletions
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) {