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>
This commit is contained in:
parent
254e9e58b7
commit
f87b73ab44
|
@ -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 (!ctl->possible_modes) {
|
||||
int fd;
|
||||
char buf[256] = { 0 };
|
||||
|
||||
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 (!(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;
|
||||
|
||||
while (i--)
|
||||
printf("%s%s", mode_str[i], i == 0 ? "" : " ");
|
||||
if (!modes)
|
||||
errx(EXIT_FAILURE, _("could not read: %s"), SYS_POWER_STATE_PATH);
|
||||
|
||||
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) {
|
||||
|
|
Loading…
Reference in New Issue