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. */
199 printf("\tdelta = %"PRId64
"\n", (int64_t) ctl
->sys_time
- ctl
->rtc_time
);
200 printf("\ttzone = %ld\n", timezone
);
201 printf("\ttzname = %s\n", tzname
[daylight
]);
202 gmtime_r(&ctl
->sys_time
, &tm
);
203 printf("\tsystime = %"PRId64
", (UTC) %s",
204 (int64_t) ctl
->sys_time
, asctime_r(&tm
, s
));
205 gmtime_r(&ctl
->rtc_time
, &tm
);
206 printf("\trtctime = %"PRId64
", (UTC) %s",
207 (int64_t) ctl
->rtc_time
, asctime_r(&tm
, s
));
212 static int setup_alarm(struct rtcwake_control
*ctl
, int fd
, time_t *wakeup
)
215 struct rtc_wkalrm wake
= { 0 };
217 /* The wakeup time is in POSIX time (more or less UTC). Ideally
218 * RTCs use that same time; but PCs can't do that if they need to
219 * boot MS-Windows. Messy...
221 * When clock_mode == CM_UTC this process's timezone is UTC, so
222 * we'll pass a UTC date to the RTC.
224 * Else clock_mode == CM_LOCAL so the time given to the RTC will
225 * instead use the local time zone. */
226 localtime_r(wakeup
, &tm
);
227 wake
.time
.tm_sec
= tm
.tm_sec
;
228 wake
.time
.tm_min
= tm
.tm_min
;
229 wake
.time
.tm_hour
= tm
.tm_hour
;
230 wake
.time
.tm_mday
= tm
.tm_mday
;
231 wake
.time
.tm_mon
= tm
.tm_mon
;
232 wake
.time
.tm_year
= tm
.tm_year
;
233 /* wday, yday, and isdst fields are unused */
234 wake
.time
.tm_wday
= -1;
235 wake
.time
.tm_yday
= -1;
236 wake
.time
.tm_isdst
= -1;
239 if (!ctl
->dryrun
&& ioctl(fd
, RTC_WKALM_SET
, &wake
) < 0) {
240 warn(_("set rtc wake alarm failed"));
246 static char **get_sys_power_states(struct rtcwake_control
*ctl
)
250 if (!ctl
->possible_modes
) {
251 char buf
[256] = { 0 };
254 fd
= open(SYS_POWER_STATE_PATH
, O_RDONLY
);
257 ss
= read(fd
, &buf
, sizeof(buf
) - 1);
261 ctl
->possible_modes
= strv_split(buf
, " \n");
264 return ctl
->possible_modes
;
271 static void wait_stdin(struct rtcwake_control
*ctl
)
273 struct pollfd fd
[] = {
274 {.fd
= STDIN_FILENO
, .events
= POLLIN
}
278 while (tries
< 8 && poll(fd
, 1, 10) == 1) {
280 warnx(_("discarding stdin"));
282 tcflush(STDIN_FILENO
, TCIFLUSH
);
287 static void suspend_system(struct rtcwake_control
*ctl
)
289 FILE *f
= fopen(SYS_POWER_STATE_PATH
, "w");
292 warn(_("cannot open %s"), SYS_POWER_STATE_PATH
);
297 if (isatty(STDIN_FILENO
))
299 fprintf(f
, "%s\n", ctl
->mode_str
);
302 /* this executes after wake from suspend */
304 errx(EXIT_FAILURE
, _("write error"));
307 static int read_clock_mode(struct rtcwake_control
*ctl
)
310 char linebuf
[ADJTIME_ZONE_BUFSIZ
];
312 fp
= fopen(ctl
->adjfile
, "r");
316 if (skip_fline(fp
) || skip_fline(fp
)) {
320 /* read third line */
321 if (!fgets(linebuf
, sizeof linebuf
, fp
)) {
326 if (strncmp(linebuf
, "UTC", 3) == 0)
327 ctl
->clock_mode
= CM_UTC
;
328 else if (strncmp(linebuf
, "LOCAL", 5) == 0)
329 ctl
->clock_mode
= CM_LOCAL
;
330 else if (ctl
->verbose
)
331 warnx(_("unexpected third line in: %s: %s"), ctl
->adjfile
, linebuf
);
337 static int print_alarm(struct rtcwake_control
*ctl
, int fd
)
339 struct rtc_wkalrm wake
;
340 struct tm tm
= { 0 };
342 char s
[CTIME_BUFSIZ
];
344 if (ioctl(fd
, RTC_WKALM_RD
, &wake
) < 0) {
345 warn(_("read rtc alarm failed"));
349 if (wake
.enabled
!= 1 || wake
.time
.tm_year
== -1) {
350 printf(_("alarm: off\n"));
353 tm
.tm_sec
= wake
.time
.tm_sec
;
354 tm
.tm_min
= wake
.time
.tm_min
;
355 tm
.tm_hour
= wake
.time
.tm_hour
;
356 tm
.tm_mday
= wake
.time
.tm_mday
;
357 tm
.tm_mon
= wake
.time
.tm_mon
;
358 tm
.tm_year
= wake
.time
.tm_year
;
359 tm
.tm_isdst
= -1; /* assume the system knows better than the RTC */
362 if (alarm
== (time_t)-1) {
363 warn(_("convert time failed"));
366 /* 0 if both UTC, or expresses diff if RTC in local time */
367 alarm
+= ctl
->sys_time
- ctl
->rtc_time
;
369 printf(_("alarm: on %s"), s
);
374 static int get_rtc_mode(struct rtcwake_control
*ctl
, const char *s
)
377 char **modes
= get_sys_power_states(ctl
), **m
;
379 STRV_FOREACH(m
, modes
) {
380 if (strcmp(s
, *m
) == 0)
384 for (i
= 0; i
< ARRAY_SIZE(rtcwake_mode_string
); i
++)
385 if (!strcmp(s
, rtcwake_mode_string
[i
]))
391 static int open_dev_rtc(const char *devname
)
394 char *devpath
= NULL
;
396 if (startswith(devname
, "/dev"))
397 devpath
= xstrdup(devname
);
399 xasprintf(&devpath
, "/dev/%s", devname
);
400 fd
= open(devpath
, O_RDONLY
| O_CLOEXEC
);
402 err(EXIT_FAILURE
, _("%s: unable to find device"), devpath
);
407 static void list_modes(struct rtcwake_control
*ctl
)
410 char **modes
= get_sys_power_states(ctl
), **m
;
413 errx(EXIT_FAILURE
, _("could not read: %s"), SYS_POWER_STATE_PATH
);
415 STRV_FOREACH(m
, modes
)
418 for (i
= 0; i
< ARRAY_SIZE(rtcwake_mode_string
); i
++)
419 printf("%s ", rtcwake_mode_string
[i
]);
423 int main(int argc
, char **argv
)
425 struct rtcwake_control ctl
= {
426 .mode_str
= "suspend", /* default mode */
427 .adjfile
= _PATH_ADJTIME
,
428 .clock_mode
= CM_AUTO
430 char *devname
= DEFAULT_RTC_DEVICE
;
431 int suspend
= SYSFS_MODE
;
432 int rc
= EXIT_SUCCESS
;
435 time_t alarm
= 0, seconds
= 0;
437 OPT_DATE
= CHAR_MAX
+ 1,
440 static const struct option long_options
[] = {
441 { "adjfile", required_argument
, NULL
, 'A' },
442 { "auto", no_argument
, NULL
, 'a' },
443 { "dry-run", no_argument
, NULL
, 'n' },
444 { "local", no_argument
, NULL
, 'l' },
445 { "utc", no_argument
, NULL
, 'u' },
446 { "verbose", no_argument
, NULL
, 'v' },
447 { "version", no_argument
, NULL
, 'V' },
448 { "help", no_argument
, NULL
, 'h' },
449 { "mode", required_argument
, NULL
, 'm' },
450 { "device", required_argument
, NULL
, 'd' },
451 { "seconds", required_argument
, NULL
, 's' },
452 { "time", required_argument
, NULL
, 't' },
453 { "date", required_argument
, NULL
, OPT_DATE
},
454 { "list-modes", no_argument
, NULL
, OPT_LIST
},
457 static const ul_excl_t excl
[] = {
459 { 's', 't', OPT_DATE
},
462 int excl_st
[ARRAY_SIZE(excl
)] = UL_EXCL_STATUS_INIT
;
464 setlocale(LC_ALL
, "");
465 bindtextdomain(PACKAGE
, LOCALEDIR
);
467 close_stdout_atexit();
469 while ((t
= getopt_long(argc
, argv
, "A:ahd:lm:ns:t:uVv",
470 long_options
, NULL
)) != EOF
) {
471 err_exclusive_options(t
, long_options
, excl
, excl_st
);
474 /* for better compatibility with hwclock */
475 ctl
.adjfile
= optarg
;
478 ctl
.clock_mode
= CM_AUTO
;
484 ctl
.clock_mode
= CM_LOCAL
;
492 if ((suspend
= get_rtc_mode(&ctl
, optarg
)) < 0)
493 errx(EXIT_FAILURE
, _("unrecognized suspend state '%s'"), optarg
);
494 ctl
.mode_str
= optarg
;
500 /* alarm time, seconds-to-sleep (relative) */
501 seconds
= strtotime_or_err(optarg
, _("invalid seconds argument"));
504 /* alarm time, time_t (absolute, seconds since epoch) */
505 alarm
= strtotime_or_err(optarg
, _("invalid time argument"));
508 { /* alarm time, see timestamp format from manual */
510 if (parse_timestamp(optarg
, &p
) < 0)
511 errx(EXIT_FAILURE
, _("invalid time value \"%s\""), optarg
);
512 alarm
= (time_t) (p
/ 1000000);
516 ctl
.clock_mode
= CM_UTC
;
523 print_version(EXIT_SUCCESS
);
527 errtryhelp(EXIT_FAILURE
);
531 if (ctl
.clock_mode
== CM_AUTO
&& read_clock_mode(&ctl
) < 0) {
532 printf(_("%s: assuming RTC uses UTC ...\n"), program_invocation_short_name
);
533 ctl
.clock_mode
= CM_UTC
;
537 printf("%s", ctl
.clock_mode
== CM_UTC
? _("Using UTC time.\n") :
538 _("Using local time.\n"));
540 if (!alarm
&& !seconds
&& suspend
!= DISABLE_MODE
&& suspend
!= SHOW_MODE
)
541 errx(EXIT_FAILURE
, _("must provide wake time (see --seconds, --time and --date options)"));
543 /* device must exist and (if we'll sleep) be wakeup-enabled */
544 fd
= open_dev_rtc(devname
);
546 if (suspend
!= ON_MODE
&& suspend
!= NO_MODE
&& !is_wakeup_enabled(devname
))
547 errx(EXIT_FAILURE
, _("%s not enabled for wakeup events"), devname
);
549 /* relative or absolute alarm time, normalized to time_t */
550 if (get_basetimes(&ctl
, fd
) < 0)
554 printf(_("alarm %"PRId64
", sys_time %"PRId64
", "
555 "rtc_time %"PRId64
", seconds %"PRIu64
"\n"),
556 (int64_t) alarm
, (int64_t) ctl
.sys_time
,
557 (int64_t) ctl
.rtc_time
,
560 if (suspend
!= DISABLE_MODE
&& suspend
!= SHOW_MODE
) {
561 /* perform alarm setup when the show or disable modes are not set */
563 if (alarm
< ctl
.sys_time
) {
564 char s
[CTIME_BUFSIZ
];
567 errx(EXIT_FAILURE
, _("time doesn't go backward to %s"), s
);
569 alarm
-= ctl
.sys_time
- ctl
.rtc_time
;
571 alarm
= ctl
.rtc_time
+ seconds
+ 1;
573 if (setup_alarm(&ctl
, fd
, &alarm
) < 0)
576 if (suspend
== NO_MODE
|| suspend
== ON_MODE
) {
577 char s
[CTIME_BUFSIZ
];
580 printf(_("%s: wakeup using %s at %s"),
581 program_invocation_short_name
, devname
, s
);
583 char s
[CTIME_BUFSIZ
];
586 printf(_("%s: wakeup from \"%s\" using %s at %s"),
587 program_invocation_short_name
, ctl
.mode_str
, devname
, s
);
596 printf(_("suspend mode: no; leaving\n"));
597 ctl
.dryrun
= 1; /* to skip disabling alarm at the end */
604 if (!access(_PATH_SHUTDOWN
, X_OK
)) {
605 arg
[i
++] = _PATH_SHUTDOWN
;
610 } else if (!access(_PATH_POWEROFF
, X_OK
)) {
611 arg
[i
++] = _PATH_POWEROFF
;
619 printf(_("suspend mode: off; executing %s\n"),
623 warn(_("failed to execute %s"), arg
[0]);
627 /* Failed to find shutdown command */
628 warn(_("failed to find shutdown command"));
638 printf(_("suspend mode: on; reading rtc\n"));
641 t
= read(fd
, &data
, sizeof data
);
643 warn(_("rtc read failed"));
647 printf("... %s: %03lx\n", devname
, data
);
648 } while (!(data
& RTC_AF
));
653 /* just break, alarm gets disabled in the end */
655 printf(_("suspend mode: disable; disabling alarm\n"));
659 printf(_("suspend mode: show; printing alarm info\n"));
660 if (print_alarm(&ctl
, fd
))
662 ctl
.dryrun
= 1; /* don't really disable alarm in the end, just show */
666 printf(_("suspend mode: %s; suspending system\n"), ctl
.mode_str
);
668 suspend_system(&ctl
);
672 struct rtc_wkalrm wake
;
674 if (ioctl(fd
, RTC_WKALM_RD
, &wake
) < 0) {
675 warn(_("read rtc alarm failed"));
679 if (ioctl(fd
, RTC_WKALM_SET
, &wake
) < 0) {
680 warn(_("disable rtc alarm interrupt failed"));