1 /*
2  * rtcwake -- enter a system sleep state until specified wakeup time.
3  *
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.
7  *
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.
11  *
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.
15  *
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.
20  */
21 
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <getopt.h>
25 #include <linux/rtc.h>
26 #include <poll.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/ioctl.h>
31 #include <sys/stat.h>
32 #include <sys/time.h>
33 #include <sys/types.h>
34 #include <termios.h>
35 #include <time.h>
36 #include <unistd.h>
37 
38 #include "c.h"
39 #include "closestream.h"
40 #include "env.h"
41 #include "nls.h"
42 #include "optutils.h"
43 #include "pathnames.h"
44 #include "strutils.h"
45 #include "strv.h"
46 #include "timeutils.h"
47 #include "xalloc.h"
48 
49 #ifndef RTC_AF
50 # define RTC_AF		0x20	/* Alarm interrupt */
51 #endif
52 
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"
57 
58 enum rtc_modes {	/* manual page --mode option explains these. */
59 	OFF_MODE = 0,
60 	NO_MODE,
61 	ON_MODE,
62 	DISABLE_MODE,
63 	SHOW_MODE,
64 
65 	SYSFS_MODE	/* keep it last */
66 
67 };
68 
69 static const char *rtcwake_mode_string[] = {
70 	[OFF_MODE] = "off",
71 	[NO_MODE] = "no",
72 	[ON_MODE] = "on",
73 	[DISABLE_MODE] = "disable",
74 	[SHOW_MODE] = "show"
75 };
76 
77 enum clock_modes {
78 	CM_AUTO,
79 	CM_UTC,
80 	CM_LOCAL
81 };
82 
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 */
92 };
93 
usage(void)94 static void __attribute__((__noreturn__)) usage(void)
95 {
96 	FILE *out = stdout;
97 	fputs(USAGE_HEADER, out);
98 	fprintf(out,
99 	      _(" %s [options]\n"), program_invocation_short_name);
100 
101 	fputs(USAGE_SEPARATOR, out);
102 	fputs(_("Enter a system sleep state until a specified wakeup time.\n"), out);
103 
104 	fputs(USAGE_OPTIONS, out);
105 	fputs(_(" -a, --auto               reads the clock mode from adjust file (default)\n"), out);
106 	fprintf(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);
119 
120 	fputs(USAGE_SEPARATOR, out);
121 	printf(USAGE_HELP_OPTIONS(26));
122 	printf(USAGE_MAN_TAIL("rtcwake(8)"));
123 	exit(EXIT_SUCCESS);
124 }
125 
is_wakeup_enabled(const char * devname)126 static int is_wakeup_enabled(const char *devname)
127 {
128 	char	buf[128], *s;
129 	FILE	*f;
130 	size_t	skip = 0;
131 
132 	if (startswith(devname, "/dev/"))
133 		skip = 5;
134 	snprintf(buf, sizeof buf, SYS_WAKEUP_PATH_TEMPLATE, devname + skip);
135 	f = fopen(buf, "r");
136 	if (!f) {
137 		warn(_("cannot open %s"), buf);
138 		return 0;
139 	}
140 
141 	s = fgets(buf, sizeof buf, f);
142 	fclose(f);
143 	if (!s)
144 		return 0;
145 	s = strchr(buf, '\n');
146 	if (!s)
147 		return 0;
148 	*s = 0;
149 	/* wakeup events could be disabled or not supported */
150 	return strcmp(buf, "enabled") == 0;
151 }
152 
get_basetimes(struct rtcwake_control * ctl,int fd)153 static int get_basetimes(struct rtcwake_control *ctl, int fd)
154 {
155 	struct tm tm = { 0 };
156 	struct rtc_time	rtc;
157 
158 	/* This process works in RTC time, except when working
159 	 * with the system clock (which always uses UTC).
160 	 */
161 	if (ctl->clock_mode == CM_UTC)
162 		xsetenv("TZ", "UTC", 1);
163 	tzset();
164 	/* Read rtc and system clocks "at the same time", or as
165 	 * precisely (+/- a second) as we can read them.
166 	 */
167 	if (ioctl(fd, RTC_RD_TIME, &rtc) < 0) {
168 		warn(_("read rtc time failed"));
169 		return -1;
170 	}
171 
172 	ctl->sys_time = time(NULL);
173 	if (ctl->sys_time == (time_t)-1) {
174 		warn(_("read system time failed"));
175 		return -1;
176 	}
177 	/* Convert rtc_time to normal arithmetic-friendly form,
178 	 * updating tm.tm_wday as used by asctime().
179 	 */
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 */
187 
188 	ctl->rtc_time = mktime(&tm);
189 	if (ctl->rtc_time == (time_t)-1) {
190 		warn(_("convert rtc time failed"));
191 		return -1;
192 	}
193 
194 	if (ctl->verbose) {
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 		char s[64];
199 		printf("\tdelta   = %ld\n", 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 = %ld, (UTC) %s",
204 				(long) ctl->sys_time, asctime_r(&tm, s));
205 		gmtime_r(&ctl->rtc_time, &tm);
206 		printf("\trtctime = %ld, (UTC) %s",
207 				(long) ctl->rtc_time, asctime_r(&tm, s));
208 	}
209 	return 0;
210 }
211 
setup_alarm(struct rtcwake_control * ctl,int fd,time_t * wakeup)212 static int setup_alarm(struct rtcwake_control *ctl, int fd, time_t *wakeup)
213 {
214 	struct tm		tm;
215 	struct rtc_wkalrm	wake = { 0 };
216 
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...
220 	 *
221 	 * When clock_mode == CM_UTC this process's timezone is UTC, so
222 	 * we'll pass a UTC date to the RTC.
223 	 *
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;
237 	wake.enabled = 1;
238 
239 	if (!ctl->dryrun && ioctl(fd, RTC_WKALM_SET, &wake) < 0) {
240 		warn(_("set rtc wake alarm failed"));
241 		return -1;
242 	}
243 	return 0;
244 }
245 
get_sys_power_states(struct rtcwake_control * ctl)246 static char **get_sys_power_states(struct rtcwake_control *ctl)
247 {
248 	int fd = -1;
249 
250 	if (!ctl->possible_modes) {
251 		char buf[256] = { 0 };
252 		ssize_t ss;
253 
254 		fd = open(SYS_POWER_STATE_PATH, O_RDONLY);
255 		if (fd < 0)
256 			goto nothing;
257 		ss = read(fd, &buf, sizeof(buf) - 1);
258 		if (ss <= 0)
259 			goto nothing;
260 		buf[ss] = '\0';
261 		ctl->possible_modes = strv_split(buf, " \n");
262 		close(fd);
263 	}
264 	return ctl->possible_modes;
265 nothing:
266 	if (fd >= 0)
267 		close(fd);
268 	return NULL;
269 }
270 
wait_stdin(struct rtcwake_control * ctl)271 static void wait_stdin(struct rtcwake_control *ctl)
272 {
273 	struct pollfd fd[] = {
274 		{.fd = STDIN_FILENO, .events = POLLIN}
275 	};
276 	int tries = 0;
277 
278 	while (tries < 8 && poll(fd, 1, 10) == 1) {
279 		if (ctl->verbose)
280 			warnx(_("discarding stdin"));
281 		xusleep(250000);
282 		tcflush(STDIN_FILENO, TCIFLUSH);
283 		tries++;
284 	}
285 }
286 
suspend_system(struct rtcwake_control * ctl)287 static void suspend_system(struct rtcwake_control *ctl)
288 {
289 	FILE	*f = fopen(SYS_POWER_STATE_PATH, "w");
290 
291 	if (!f) {
292 		warn(_("cannot open %s"), SYS_POWER_STATE_PATH);
293 		return;
294 	}
295 
296 	if (!ctl->dryrun) {
297 		if (isatty(STDIN_FILENO))
298 			wait_stdin(ctl);
299 		fprintf(f, "%s\n", ctl->mode_str);
300 		fflush(f);
301 	}
302 	/* this executes after wake from suspend */
303 	if (close_stream(f))
304 		errx(EXIT_FAILURE, _("write error"));
305 }
306 
read_clock_mode(struct rtcwake_control * ctl)307 static int read_clock_mode(struct rtcwake_control *ctl)
308 {
309 	FILE *fp;
310 	char linebuf[ADJTIME_ZONE_BUFSIZ];
311 
312 	fp = fopen(ctl->adjfile, "r");
313 	if (!fp)
314 		return -1;
315 	/* skip two lines */
316 	if (skip_fline(fp) || skip_fline(fp)) {
317 		fclose(fp);
318 		return -1;
319 	}
320 	/* read third line */
321 	if (!fgets(linebuf, sizeof linebuf, fp)) {
322 		fclose(fp);
323 		return -1;
324 	}
325 
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);
332 
333 	fclose(fp);
334 	return 0;
335 }
336 
print_alarm(struct rtcwake_control * ctl,int fd)337 static int print_alarm(struct rtcwake_control *ctl, int fd)
338 {
339 	struct rtc_wkalrm wake;
340 	struct tm tm = { 0 };
341 	time_t alarm;
342 	char s[CTIME_BUFSIZ];
343 
344 	if (ioctl(fd, RTC_WKALM_RD, &wake) < 0) {
345 		warn(_("read rtc alarm failed"));
346 		return -1;
347 	}
348 
349 	if (wake.enabled != 1 || wake.time.tm_year == -1) {
350 		printf(_("alarm: off\n"));
351 		return 0;
352 	}
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 */
360 
361 	alarm = mktime(&tm);
362 	if (alarm == (time_t)-1) {
363 		warn(_("convert time failed"));
364 		return -1;
365 	}
366 	/* 0 if both UTC, or expresses diff if RTC in local time */
367 	alarm += ctl->sys_time - ctl->rtc_time;
368 	ctime_r(&alarm, s);
369 	printf(_("alarm: on  %s"), s);
370 
371 	return 0;
372 }
373 
get_rtc_mode(struct rtcwake_control * ctl,const char * s)374 static int get_rtc_mode(struct rtcwake_control *ctl, const char *s)
375 {
376 	size_t i;
377 	char **modes = get_sys_power_states(ctl), **m;
378 
379 	STRV_FOREACH(m, modes) {
380 		if (strcmp(s, *m) == 0)
381 			return SYSFS_MODE;
382 	}
383 
384 	for (i = 0; i < ARRAY_SIZE(rtcwake_mode_string); i++)
385 		if (!strcmp(s, rtcwake_mode_string[i]))
386 			return i;
387 
388 	return -EINVAL;
389 }
390 
open_dev_rtc(const char * devname)391 static int open_dev_rtc(const char *devname)
392 {
393 	int fd;
394 	char *devpath = NULL;
395 
396 	if (startswith(devname, "/dev"))
397 		devpath = xstrdup(devname);
398 	else
399 		xasprintf(&devpath, "/dev/%s", devname);
400 	fd = open(devpath, O_RDONLY | O_CLOEXEC);
401 	if (fd < 0)
402 		err(EXIT_FAILURE, _("%s: unable to find device"), devpath);
403 	free(devpath);
404 	return fd;
405 }
406 
list_modes(struct rtcwake_control * ctl)407 static void list_modes(struct rtcwake_control *ctl)
408 {
409 	size_t i;
410 	char **modes = get_sys_power_states(ctl), **m;
411 
412 	if (!modes)
413 		errx(EXIT_FAILURE, _("could not read: %s"), SYS_POWER_STATE_PATH);
414 
415 	STRV_FOREACH(m, modes)
416 		printf("%s ", *m);
417 
418 	for (i = 0; i < ARRAY_SIZE(rtcwake_mode_string); i++)
419 		printf("%s ", rtcwake_mode_string[i]);
420 	putchar('\n');
421 }
422 
main(int argc,char ** argv)423 int main(int argc, char **argv)
424 {
425 	struct rtcwake_control ctl = {
426 		.mode_str = "suspend",		/* default mode */
427 		.adjfile = _PATH_ADJTIME,
428 		.clock_mode = CM_AUTO
429 	};
430 	char *devname = DEFAULT_RTC_DEVICE;
431 	unsigned seconds = 0;
432 	int suspend = SYSFS_MODE;
433 	int rc = EXIT_SUCCESS;
434 	int t;
435 	int fd;
436 	time_t alarm = 0;
437 	enum {
438 		OPT_DATE = CHAR_MAX + 1,
439 		OPT_LIST
440 	};
441 	static const struct option long_options[] = {
442 		{ "adjfile",	required_argument,	NULL, 'A'      },
443 		{ "auto",	no_argument,		NULL, 'a'      },
444 		{ "dry-run",	no_argument,		NULL, 'n'      },
445 		{ "local",	no_argument,		NULL, 'l'      },
446 		{ "utc",	no_argument,		NULL, 'u'      },
447 		{ "verbose",	no_argument,		NULL, 'v'      },
448 		{ "version",	no_argument,		NULL, 'V'      },
449 		{ "help",	no_argument,		NULL, 'h'      },
450 		{ "mode",	required_argument,	NULL, 'm'      },
451 		{ "device",	required_argument,	NULL, 'd'      },
452 		{ "seconds",	required_argument,	NULL, 's'      },
453 		{ "time",	required_argument,	NULL, 't'      },
454 		{ "date",	required_argument,	NULL, OPT_DATE },
455 		{ "list-modes",	no_argument,		NULL, OPT_LIST },
456 		{ NULL, 0, NULL, 0 }
457 	};
458 	static const ul_excl_t excl[] = {
459 		{ 'a', 'l', 'u' },
460 		{ 's', 't', OPT_DATE },
461 		{ 0 },
462 	};
463 	int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
464 
465 	setlocale(LC_ALL, "");
466 	bindtextdomain(PACKAGE, LOCALEDIR);
467 	textdomain(PACKAGE);
468 	close_stdout_atexit();
469 
470 	while ((t = getopt_long(argc, argv, "A:ahd:lm:ns:t:uVv",
471 					long_options, NULL)) != EOF) {
472 		err_exclusive_options(t, long_options, excl, excl_st);
473 		switch (t) {
474 		case 'A':
475 			/* for better compatibility with hwclock */
476 			ctl.adjfile = optarg;
477 			break;
478 		case 'a':
479 			ctl.clock_mode = CM_AUTO;
480 			break;
481 		case 'd':
482 			devname = optarg;
483 			break;
484 		case 'l':
485 			ctl.clock_mode = CM_LOCAL;
486 			break;
487 
488 		case OPT_LIST:
489 			list_modes(&ctl);
490 			return EXIT_SUCCESS;
491 
492 		case 'm':
493 			if ((suspend = get_rtc_mode(&ctl, optarg)) < 0)
494 				errx(EXIT_FAILURE, _("unrecognized suspend state '%s'"), optarg);
495 			ctl.mode_str = optarg;
496 			break;
497 		case 'n':
498 			ctl.dryrun = 1;
499 			break;
500 		case 's':
501 			/* alarm time, seconds-to-sleep (relative) */
502 			seconds = strtou32_or_err(optarg, _("invalid seconds argument"));
503 			break;
504 		case 't':
505 			/* alarm time, time_t (absolute, seconds since epoch) */
506 			alarm = strtou32_or_err(optarg, _("invalid time argument"));
507 			break;
508 		case OPT_DATE:
509 		{	/* alarm time, see timestamp format from manual */
510 			usec_t p;
511 			if (parse_timestamp(optarg, &p) < 0)
512 				errx(EXIT_FAILURE, _("invalid time value \"%s\""), optarg);
513 			alarm = (time_t) (p / 1000000);
514 			break;
515 		}
516 		case 'u':
517 			ctl.clock_mode = CM_UTC;
518 			break;
519 		case 'v':
520 			ctl.verbose = 1;
521 			break;
522 
523 		case 'V':
524 			print_version(EXIT_SUCCESS);
525 		case 'h':
526 			usage();
527 		default:
528 			errtryhelp(EXIT_FAILURE);
529 		}
530 	}
531 
532 	if (ctl.clock_mode == CM_AUTO && read_clock_mode(&ctl) < 0) {
533 		printf(_("%s: assuming RTC uses UTC ...\n"),  program_invocation_short_name);
534 		ctl.clock_mode = CM_UTC;
535 	}
536 
537 	if (ctl.verbose)
538 		printf("%s",  ctl.clock_mode == CM_UTC ? _("Using UTC time.\n") :
539 				_("Using local time.\n"));
540 
541 	if (!alarm && !seconds && suspend != DISABLE_MODE && suspend != SHOW_MODE)
542 		errx(EXIT_FAILURE, _("must provide wake time (see --seconds, --time and --date options)"));
543 
544 	/* device must exist and (if we'll sleep) be wakeup-enabled */
545 	fd = open_dev_rtc(devname);
546 
547 	if (suspend != ON_MODE && suspend != NO_MODE && !is_wakeup_enabled(devname))
548 		errx(EXIT_FAILURE, _("%s not enabled for wakeup events"), devname);
549 
550 	/* relative or absolute alarm time, normalized to time_t */
551 	if (get_basetimes(&ctl, fd) < 0)
552 		exit(EXIT_FAILURE);
553 
554 	if (ctl.verbose)
555 		printf(_("alarm %ld, sys_time %ld, rtc_time %ld, seconds %u\n"),
556 				alarm, ctl.sys_time, ctl.rtc_time, seconds);
557 
558 	if (suspend != DISABLE_MODE && suspend != SHOW_MODE) {
559 		/* perform alarm setup when the show or disable modes are not set */
560 		if (alarm) {
561 			if (alarm < ctl.sys_time) {
562 				char s[CTIME_BUFSIZ];
563 
564 				ctime_r(&alarm, s);
565 				errx(EXIT_FAILURE, _("time doesn't go backward to %s"), s);
566 			}
567 			alarm -= ctl.sys_time - ctl.rtc_time;
568 		} else
569 			alarm = ctl.rtc_time + seconds + 1;
570 
571 		if (setup_alarm(&ctl, fd, &alarm) < 0)
572 			exit(EXIT_FAILURE);
573 
574 		if (suspend == NO_MODE || suspend == ON_MODE) {
575 			char s[CTIME_BUFSIZ];
576 
577 			ctime_r(&alarm, s);
578 			printf(_("%s: wakeup using %s at %s"),
579 				program_invocation_short_name, devname, s);
580 		} else {
581 			char s[CTIME_BUFSIZ];
582 
583 			ctime_r(&alarm, s);
584 			printf(_("%s: wakeup from \"%s\" using %s at %s"),
585 				program_invocation_short_name, ctl.mode_str, devname, s);
586 		}
587 		fflush(stdout);
588 		xusleep(10 * 1000);
589 	}
590 
591 	switch (suspend) {
592 	case NO_MODE:
593 		if (ctl.verbose)
594 			printf(_("suspend mode: no; leaving\n"));
595 		ctl.dryrun = 1;	/* to skip disabling alarm at the end */
596 		break;
597 	case OFF_MODE:
598 	{
599 		char *arg[5];
600 		int i = 0;
601 
602 		if (!access(_PATH_SHUTDOWN, X_OK)) {
603 			arg[i++] = _PATH_SHUTDOWN;
604 			arg[i++] = "-h";
605 			arg[i++] = "-P";
606 			arg[i++] = "now";
607 			arg[i]   = NULL;
608 		} else if (!access(_PATH_POWEROFF, X_OK)) {
609 			arg[i++] = _PATH_POWEROFF;
610 			arg[i]   = NULL;
611 		} else {
612 			arg[i] 	 = NULL;
613 		}
614 
615 		if (arg[0]) {
616 			if (ctl.verbose)
617 				printf(_("suspend mode: off; executing %s\n"),
618 						arg[0]);
619 			if (!ctl.dryrun) {
620 				execv(arg[0], arg);
621 				warn(_("failed to execute %s"), arg[0]);
622 				rc = EX_EXEC_ENOENT;
623 			}
624 		} else {
625 			/* Failed to find shutdown command */
626 			warn(_("failed to find shutdown command"));
627 			rc = EX_EXEC_ENOENT;
628 		}
629 		break;
630 	}
631 	case ON_MODE:
632 	{
633 		unsigned long data;
634 
635 		if (ctl.verbose)
636 			printf(_("suspend mode: on; reading rtc\n"));
637 		if (!ctl.dryrun) {
638 			do {
639 				t = read(fd, &data, sizeof data);
640 				if (t < 0) {
641 					warn(_("rtc read failed"));
642 					break;
643 				}
644 				if (ctl.verbose)
645 					printf("... %s: %03lx\n", devname, data);
646 			} while (!(data & RTC_AF));
647 		}
648 		break;
649 	}
650 	case DISABLE_MODE:
651 		/* just break, alarm gets disabled in the end */
652 		if (ctl.verbose)
653 			printf(_("suspend mode: disable; disabling alarm\n"));
654 		break;
655 	case SHOW_MODE:
656 		if (ctl.verbose)
657 			printf(_("suspend mode: show; printing alarm info\n"));
658 		if (print_alarm(&ctl, fd))
659 			rc = EXIT_FAILURE;
660 		ctl.dryrun = 1;	/* don't really disable alarm in the end, just show */
661 		break;
662 	default:
663 		if (ctl.verbose)
664 			printf(_("suspend mode: %s; suspending system\n"), ctl.mode_str);
665 		sync();
666 		suspend_system(&ctl);
667 	}
668 
669 	if (!ctl.dryrun) {
670 		struct rtc_wkalrm wake;
671 
672 		if (ioctl(fd, RTC_WKALM_RD, &wake) < 0) {
673 			warn(_("read rtc alarm failed"));
674 			rc = EXIT_FAILURE;
675 		} else {
676 			wake.enabled = 0;
677 			if (ioctl(fd, RTC_WKALM_SET, &wake) < 0) {
678 				warn(_("disable rtc alarm interrupt failed"));
679 				rc = EXIT_FAILURE;
680 			}
681 		}
682 	}
683 
684 	close(fd);
685 	return rc;
686 }
687