2 * rtcwake -- enter a system sleep state until specified wakeup time.
4 * This uses cross-platform Linux interfaces to enter a system sleep state,
5 * and leave it no later than a specified time. It uses any RTC framework
6 * driver that supports standard driver model wakeup flags.
8 * This is normally used like the old "apmsleep" utility, to wake from a
9 * suspend state like ACPI S1 (standby) or S3 (suspend-to-RAM). Most
10 * platforms can implement those without analogues of BIOS, APM, or ACPI.
12 * On some systems, this can also be used like "nvram-wakeup", waking
13 * from states like ACPI S4 (suspend to disk). Not all systems have
14 * persistent media that are appropriate for such suspend modes.
16 * The best way to set the system's RTC is so that it holds the current
17 * time in UTC. Use the "-l" flag to tell this program that the system
18 * RTC uses a local timezone instead (maybe you dual-boot MS-Windows).
19 * That flag should not be needed on systems with adjtime support.
25 #include <linux/rtc.h>
30 #include <sys/ioctl.h>
33 #include <sys/types.h>
39 #include "closestream.h"
43 #include "pathnames.h"
46 #include "timeutils.h"
50 # define RTC_AF 0x20 /* Alarm interrupt */
53 #define ADJTIME_ZONE_BUFSIZ 8
54 #define SYS_WAKEUP_PATH_TEMPLATE "/sys/class/rtc/%s/device/power/wakeup"
55 #define SYS_POWER_STATE_PATH "/sys/power/state"
56 #define DEFAULT_RTC_DEVICE "/dev/rtc0"
58 enum rtc_modes
{ /* manual page --mode option explains these. */
65 SYSFS_MODE
/* keep it last */
69 static const char *rtcwake_mode_string
[] = {
73 [DISABLE_MODE
] = "disable",
83 struct rtcwake_control
{
84 char *mode_str
; /* name of the requested mode */
85 char **possible_modes
; /* modes listed in /sys/power/state */
86 char *adjfile
; /* adjtime file path */
87 enum clock_modes clock_mode
; /* hwclock timezone */
88 time_t sys_time
; /* system time */
89 time_t rtc_time
; /* hardware time */
90 unsigned int verbose
:1, /* verbose messaging */
91 dryrun
:1; /* do not set alarm, suspend system, etc */
94 static void __attribute__((__noreturn__
)) usage(void)
97 fputs(USAGE_HEADER
, out
);
99 _(" %s [options]\n"), program_invocation_short_name
);
101 fputs(USAGE_SEPARATOR
, out
);
102 fputs(_("Enter a system sleep state until a specified wakeup time.\n"), out
);
104 fputs(USAGE_OPTIONS
, out
);
105 fputs(_(" -a, --auto reads the clock mode from adjust file (default)\n"), out
);
107 _(" -A, --adjfile <file> specifies the path to the adjust file\n"
108 " the default is %s\n"), _PATH_ADJTIME
);
109 fputs(_(" --date <timestamp> date time of timestamp to wake\n"), out
);
110 fputs(_(" -d, --device <device> select rtc device (rtc0|rtc1|...)\n"), out
);
111 fputs(_(" -n, --dry-run does everything, but suspend\n"), out
);
112 fputs(_(" -l, --local RTC uses local timezone\n"), out
);
113 fputs(_(" --list-modes list available modes\n"), out
);
114 fputs(_(" -m, --mode <mode> standby|mem|... sleep mode\n"), out
);
115 fputs(_(" -s, --seconds <seconds> seconds to sleep\n"), out
);
116 fputs(_(" -t, --time <time_t> time to wake\n"), out
);
117 fputs(_(" -u, --utc RTC uses UTC\n"), out
);
118 fputs(_(" -v, --verbose verbose messages\n"), out
);
120 fputs(USAGE_SEPARATOR
, out
);
121 printf(USAGE_HELP_OPTIONS(26));
122 printf(USAGE_MAN_TAIL("rtcwake(8)"));
126 static int is_wakeup_enabled(const char *devname
)
132 if (startswith(devname
, "/dev/"))
134 snprintf(buf
, sizeof buf
, SYS_WAKEUP_PATH_TEMPLATE
, devname
+ skip
);
137 warn(_("cannot open %s"), buf
);
141 s
= fgets(buf
, sizeof buf
, f
);
145 s
= strchr(buf
, '\n');
149 /* wakeup events could be disabled or not supported */
150 return strcmp(buf
, "enabled") == 0;
153 static int get_basetimes(struct rtcwake_control
*ctl
, int fd
)
155 struct tm tm
= { 0 };
158 /* This process works in RTC time, except when working
159 * with the system clock (which always uses UTC).
161 if (ctl
->clock_mode
== CM_UTC
)
162 xsetenv("TZ", "UTC", 1);
164 /* Read rtc and system clocks "at the same time", or as
165 * precisely (+/- a second) as we can read them.
167 if (ioctl(fd
, RTC_RD_TIME
, &rtc
) < 0) {
168 warn(_("read rtc time failed"));
172 ctl
->sys_time
= time(NULL
);
173 if (ctl
->sys_time
== (time_t)-1) {
174 warn(_("read system time failed"));
177 /* Convert rtc_time to normal arithmetic-friendly form,
178 * updating tm.tm_wday as used by asctime().
180 tm
.tm_sec
= rtc
.tm_sec
;
181 tm
.tm_min
= rtc
.tm_min
;
182 tm
.tm_hour
= rtc
.tm_hour
;
183 tm
.tm_mday
= rtc
.tm_mday
;
184 tm
.tm_mon
= rtc
.tm_mon
;
185 tm
.tm_year
= rtc
.tm_year
;
186 tm
.tm_isdst
= -1; /* assume the system knows better than the RTC */
188 ctl
->rtc_time
= mktime(&tm
);
189 if (ctl
->rtc_time
== (time_t)-1) {
190 warn(_("convert rtc time failed"));
195 /* Unless the system uses UTC, either delta or tzone
196 * reflects a seconds offset from UTC. The value can
197 * help sort out problems like bugs in your C library. */
198 printf("\tdelta = %ld\n", ctl
->sys_time
- ctl
->rtc_time
);
199 printf("\ttzone = %ld\n", timezone
);
200 printf("\ttzname = %s\n", tzname
[daylight
]);
201 gmtime_r(&ctl
->rtc_time
, &tm
);
202 printf("\tsystime = %ld, (UTC) %s",
203 (long) ctl
->sys_time
, asctime(gmtime(&ctl
->sys_time
)));
204 printf("\trtctime = %ld, (UTC) %s",
205 (long) ctl
->rtc_time
, asctime(&tm
));
210 static int setup_alarm(struct rtcwake_control
*ctl
, int fd
, time_t *wakeup
)
213 struct rtc_wkalrm wake
= { 0 };
215 /* The wakeup time is in POSIX time (more or less UTC). Ideally
216 * RTCs use that same time; but PCs can't do that if they need to
217 * boot MS-Windows. Messy...
219 * When clock_mode == CM_UTC this process's timezone is UTC, so
220 * we'll pass a UTC date to the RTC.
222 * Else clock_mode == CM_LOCAL so the time given to the RTC will
223 * instead use the local time zone. */
224 tm
= localtime(wakeup
);
225 wake
.time
.tm_sec
= tm
->tm_sec
;
226 wake
.time
.tm_min
= tm
->tm_min
;
227 wake
.time
.tm_hour
= tm
->tm_hour
;
228 wake
.time
.tm_mday
= tm
->tm_mday
;
229 wake
.time
.tm_mon
= tm
->tm_mon
;
230 wake
.time
.tm_year
= tm
->tm_year
;
231 /* wday, yday, and isdst fields are unused */
232 wake
.time
.tm_wday
= -1;
233 wake
.time
.tm_yday
= -1;
234 wake
.time
.tm_isdst
= -1;
237 if (!ctl
->dryrun
&& ioctl(fd
, RTC_WKALM_SET
, &wake
) < 0) {
238 warn(_("set rtc wake alarm failed"));
244 static char **get_sys_power_states(struct rtcwake_control
*ctl
)
248 if (!ctl
->possible_modes
) {
249 char buf
[256] = { 0 };
252 fd
= open(SYS_POWER_STATE_PATH
, O_RDONLY
);
255 ss
= read(fd
, &buf
, sizeof(buf
) - 1);
259 ctl
->possible_modes
= strv_split(buf
, " \n");
262 return ctl
->possible_modes
;
269 static void wait_stdin(struct rtcwake_control
*ctl
)
271 struct pollfd fd
[] = {
272 {.fd
= STDIN_FILENO
, .events
= POLLIN
}
276 while (tries
< 8 && poll(fd
, 1, 10) == 1) {
278 warnx(_("discarding stdin"));
280 tcflush(STDIN_FILENO
, TCIFLUSH
);
285 static void suspend_system(struct rtcwake_control
*ctl
)
287 FILE *f
= fopen(SYS_POWER_STATE_PATH
, "w");
290 warn(_("cannot open %s"), SYS_POWER_STATE_PATH
);
295 if (isatty(STDIN_FILENO
))
297 fprintf(f
, "%s\n", ctl
->mode_str
);
300 /* this executes after wake from suspend */
302 errx(EXIT_FAILURE
, _("write error"));
305 static int read_clock_mode(struct rtcwake_control
*ctl
)
308 char linebuf
[ADJTIME_ZONE_BUFSIZ
];
310 fp
= fopen(ctl
->adjfile
, "r");
314 if (skip_fline(fp
) || skip_fline(fp
)) {
318 /* read third line */
319 if (!fgets(linebuf
, sizeof linebuf
, fp
)) {
324 if (strncmp(linebuf
, "UTC", 3) == 0)
325 ctl
->clock_mode
= CM_UTC
;
326 else if (strncmp(linebuf
, "LOCAL", 5) == 0)
327 ctl
->clock_mode
= CM_LOCAL
;
328 else if (ctl
->verbose
)
329 warnx(_("unexpected third line in: %s: %s"), ctl
->adjfile
, linebuf
);
335 static int print_alarm(struct rtcwake_control
*ctl
, int fd
)
337 struct rtc_wkalrm wake
;
338 struct tm tm
= { 0 };
341 if (ioctl(fd
, RTC_WKALM_RD
, &wake
) < 0) {
342 warn(_("read rtc alarm failed"));
346 if (wake
.enabled
!= 1 || wake
.time
.tm_year
== -1) {
347 printf(_("alarm: off\n"));
350 tm
.tm_sec
= wake
.time
.tm_sec
;
351 tm
.tm_min
= wake
.time
.tm_min
;
352 tm
.tm_hour
= wake
.time
.tm_hour
;
353 tm
.tm_mday
= wake
.time
.tm_mday
;
354 tm
.tm_mon
= wake
.time
.tm_mon
;
355 tm
.tm_year
= wake
.time
.tm_year
;
356 tm
.tm_isdst
= -1; /* assume the system knows better than the RTC */
359 if (alarm
== (time_t)-1) {
360 warn(_("convert time failed"));
363 /* 0 if both UTC, or expresses diff if RTC in local time */
364 alarm
+= ctl
->sys_time
- ctl
->rtc_time
;
365 printf(_("alarm: on %s"), ctime(&alarm
));
370 static int get_rtc_mode(struct rtcwake_control
*ctl
, const char *s
)
373 char **modes
= get_sys_power_states(ctl
), **m
;
375 STRV_FOREACH(m
, modes
) {
376 if (strcmp(s
, *m
) == 0)
380 for (i
= 0; i
< ARRAY_SIZE(rtcwake_mode_string
); i
++)
381 if (!strcmp(s
, rtcwake_mode_string
[i
]))
387 static int open_dev_rtc(const char *devname
)
390 char *devpath
= NULL
;
392 if (startswith(devname
, "/dev"))
393 devpath
= xstrdup(devname
);
395 xasprintf(&devpath
, "/dev/%s", devname
);
396 fd
= open(devpath
, O_RDONLY
| O_CLOEXEC
);
398 err(EXIT_FAILURE
, _("%s: unable to find device"), devpath
);
403 static void list_modes(struct rtcwake_control
*ctl
)
406 char **modes
= get_sys_power_states(ctl
), **m
;
409 errx(EXIT_FAILURE
, _("could not read: %s"), SYS_POWER_STATE_PATH
);
411 STRV_FOREACH(m
, modes
)
414 for (i
= 0; i
< ARRAY_SIZE(rtcwake_mode_string
); i
++)
415 printf("%s ", rtcwake_mode_string
[i
]);
419 int main(int argc
, char **argv
)
421 struct rtcwake_control ctl
= {
422 .mode_str
= "suspend", /* default mode */
423 .adjfile
= _PATH_ADJTIME
,
424 .clock_mode
= CM_AUTO
426 char *devname
= DEFAULT_RTC_DEVICE
;
427 unsigned seconds
= 0;
428 int suspend
= SYSFS_MODE
;
429 int rc
= EXIT_SUCCESS
;
434 OPT_DATE
= CHAR_MAX
+ 1,
437 static const struct option long_options
[] = {
438 { "adjfile", required_argument
, NULL
, 'A' },
439 { "auto", no_argument
, NULL
, 'a' },
440 { "dry-run", no_argument
, NULL
, 'n' },
441 { "local", no_argument
, NULL
, 'l' },
442 { "utc", no_argument
, NULL
, 'u' },
443 { "verbose", no_argument
, NULL
, 'v' },
444 { "version", no_argument
, NULL
, 'V' },
445 { "help", no_argument
, NULL
, 'h' },
446 { "mode", required_argument
, NULL
, 'm' },
447 { "device", required_argument
, NULL
, 'd' },
448 { "seconds", required_argument
, NULL
, 's' },
449 { "time", required_argument
, NULL
, 't' },
450 { "date", required_argument
, NULL
, OPT_DATE
},
451 { "list-modes", no_argument
, NULL
, OPT_LIST
},
454 static const ul_excl_t excl
[] = {
456 { 's', 't', OPT_DATE
},
459 int excl_st
[ARRAY_SIZE(excl
)] = UL_EXCL_STATUS_INIT
;
461 setlocale(LC_ALL
, "");
462 bindtextdomain(PACKAGE
, LOCALEDIR
);
464 close_stdout_atexit();
466 while ((t
= getopt_long(argc
, argv
, "A:ahd:lm:ns:t:uVv",
467 long_options
, NULL
)) != EOF
) {
468 err_exclusive_options(t
, long_options
, excl
, excl_st
);
471 /* for better compatibility with hwclock */
472 ctl
.adjfile
= optarg
;
475 ctl
.clock_mode
= CM_AUTO
;
481 ctl
.clock_mode
= CM_LOCAL
;
489 if ((suspend
= get_rtc_mode(&ctl
, optarg
)) < 0)
490 errx(EXIT_FAILURE
, _("unrecognized suspend state '%s'"), optarg
);
491 ctl
.mode_str
= optarg
;
497 /* alarm time, seconds-to-sleep (relative) */
498 seconds
= strtou32_or_err(optarg
, _("invalid seconds argument"));
501 /* alarm time, time_t (absolute, seconds since epoch) */
502 alarm
= strtou32_or_err(optarg
, _("invalid time argument"));
505 { /* alarm time, see timestamp format from manual */
507 if (parse_timestamp(optarg
, &p
) < 0)
508 errx(EXIT_FAILURE
, _("invalid time value \"%s\""), optarg
);
509 alarm
= (time_t) (p
/ 1000000);
513 ctl
.clock_mode
= CM_UTC
;
520 print_version(EXIT_SUCCESS
);
524 errtryhelp(EXIT_FAILURE
);
528 if (ctl
.clock_mode
== CM_AUTO
&& read_clock_mode(&ctl
) < 0) {
529 printf(_("%s: assuming RTC uses UTC ...\n"), program_invocation_short_name
);
530 ctl
.clock_mode
= CM_UTC
;
534 printf("%s", ctl
.clock_mode
== CM_UTC
? _("Using UTC time.\n") :
535 _("Using local time.\n"));
537 if (!alarm
&& !seconds
&& suspend
!= DISABLE_MODE
&& suspend
!= SHOW_MODE
)
538 errx(EXIT_FAILURE
, _("must provide wake time (see --seconds, --time and --date options)"));
540 /* device must exist and (if we'll sleep) be wakeup-enabled */
541 fd
= open_dev_rtc(devname
);
543 if (suspend
!= ON_MODE
&& suspend
!= NO_MODE
&& !is_wakeup_enabled(devname
))
544 errx(EXIT_FAILURE
, _("%s not enabled for wakeup events"), devname
);
546 /* relative or absolute alarm time, normalized to time_t */
547 if (get_basetimes(&ctl
, fd
) < 0)
551 printf(_("alarm %ld, sys_time %ld, rtc_time %ld, seconds %u\n"),
552 alarm
, ctl
.sys_time
, ctl
.rtc_time
, seconds
);
554 if (suspend
!= DISABLE_MODE
&& suspend
!= SHOW_MODE
) {
555 /* perform alarm setup when the show or disable modes are not set */
557 if (alarm
< ctl
.sys_time
)
558 errx(EXIT_FAILURE
, _("time doesn't go backward to %s"),
560 alarm
-= ctl
.sys_time
- ctl
.rtc_time
;
562 alarm
= ctl
.rtc_time
+ seconds
+ 1;
564 if (setup_alarm(&ctl
, fd
, &alarm
) < 0)
567 if (suspend
== NO_MODE
|| suspend
== ON_MODE
)
568 printf(_("%s: wakeup using %s at %s"),
569 program_invocation_short_name
, devname
,
572 printf(_("%s: wakeup from \"%s\" using %s at %s"),
573 program_invocation_short_name
, ctl
.mode_str
, devname
,
582 printf(_("suspend mode: no; leaving\n"));
583 ctl
.dryrun
= 1; /* to skip disabling alarm at the end */
590 if (!access(_PATH_SHUTDOWN
, X_OK
)) {
591 arg
[i
++] = _PATH_SHUTDOWN
;
596 } else if (!access(_PATH_POWEROFF
, X_OK
)) {
597 arg
[i
++] = _PATH_POWEROFF
;
605 printf(_("suspend mode: off; executing %s\n"),
609 warn(_("failed to execute %s"), arg
[0]);
613 /* Failed to find shutdown command */
614 warn(_("failed to find shutdown command"));
624 printf(_("suspend mode: on; reading rtc\n"));
627 t
= read(fd
, &data
, sizeof data
);
629 warn(_("rtc read failed"));
633 printf("... %s: %03lx\n", devname
, data
);
634 } while (!(data
& RTC_AF
));
639 /* just break, alarm gets disabled in the end */
641 printf(_("suspend mode: disable; disabling alarm\n"));
645 printf(_("suspend mode: show; printing alarm info\n"));
646 if (print_alarm(&ctl
, fd
))
648 ctl
.dryrun
= 1; /* don't really disable alarm in the end, just show */
652 printf(_("suspend mode: %s; suspending system\n"), ctl
.mode_str
);
654 suspend_system(&ctl
);
658 struct rtc_wkalrm wake
;
660 if (ioctl(fd
, RTC_WKALM_RD
, &wake
) < 0) {
661 warn(_("read rtc alarm failed"));
665 if (ioctl(fd
, RTC_WKALM_SET
, &wake
) < 0) {
666 warn(_("disable rtc alarm interrupt failed"));