]> git.ipfire.org Git - thirdparty/util-linux.git/blame - sys-utils/rtcwake.c
flock: Change the 'exit status' man page section to make more sense
[thirdparty/util-linux.git] / sys-utils / rtcwake.c
CommitLineData
76700389
BW
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).
2148b051 19 * That flag should not be needed on systems with adjtime support.
76700389
BW
20 */
21
22#include <stdio.h>
23#include <getopt.h>
24#include <fcntl.h>
c41e1340 25#include <libgen.h>
76700389
BW
26#include <stdlib.h>
27#include <string.h>
28#include <unistd.h>
29#include <errno.h>
30#include <time.h>
31
32#include <sys/ioctl.h>
33#include <sys/time.h>
34#include <sys/types.h>
35
36#include <linux/rtc.h>
37
38#include "nls.h"
2ab428f6 39#include "xalloc.h"
77f5744c 40#include "pathnames.h"
07b336c9 41#include "strutils.h"
eb76ca98 42#include "c.h"
efb8854f 43#include "closestream.h"
76700389
BW
44
45/* constants from legacy PC/AT hardware */
46#define RTC_PF 0x40
47#define RTC_AF 0x20
48#define RTC_UF 0x10
49
50#define MAX_LINE 1024
51
76700389 52#define RTC_PATH "/sys/class/rtc/%s/device/power/wakeup"
d3cf5414 53#define SYS_POWER_STATE_PATH "/sys/power/state"
76700389 54#define DEFAULT_DEVICE "/dev/rtc0"
47bf8ef7 55#define DEFAULT_MODE "standby"
76700389
BW
56
57enum ClockMode {
58 CM_AUTO,
59 CM_UTC,
60 CM_LOCAL
61};
62
7528fae9 63static char *adjfile = _PATH_ADJTIME;
76700389 64static unsigned verbose;
569f3ca2 65static unsigned dryrun;
76700389
BW
66enum ClockMode clock_mode = CM_AUTO;
67
07b336c9 68static void __attribute__((__noreturn__)) usage(FILE *out)
76700389 69{
0e00261d 70 fputs(USAGE_HEADER, out);
704c7705
KZ
71 fprintf(out,
72 _(" %s [options]\n"), program_invocation_short_name);
73
0e00261d 74 fputs(USAGE_OPTIONS, out);
49ebda9b 75 fputs(_(" -a, --auto reads the clock mode from adjust file (default)\n"), out);
3a2f3e82
KZ
76 fprintf(out,
77 _(" -A, --adjfile <file> specifies the path to the adjust file\n"
7528fae9 78 " the default is %s\n"), _PATH_ADJTIME);
09e092ad
KZ
79 fputs(_(" -d, --device <device> select rtc device (rtc0|rtc1|...)\n"), out);
80 fputs(_(" -n, --dry-run does everything, but suspend\n"), out);
81 fputs(_(" -l, --local RTC uses local timezone\n"), out);
82 fputs(_(" -m, --mode <mode> standby|mem|... sleep mode\n"), out);
83 fputs(_(" -s, --seconds <seconds> seconds to sleep\n"), out);
84 fputs(_(" -t, --time <time_t> time to wake\n"), out);
85 fputs(_(" -u, --utc RTC uses UTC\n"), out);
86 fputs(_(" -v, --verbose verbose messages\n"), out);
704c7705 87
0e00261d
SK
88 printf(USAGE_SEPARATOR);
89 printf(USAGE_HELP);
90 printf(USAGE_VERSION);
91
92 printf(USAGE_MAN_TAIL("rtcwake(8)"));
07b336c9
KZ
93
94 exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
76700389
BW
95}
96
f8d87ab1 97static int is_wakeup_enabled(const char *devname)
76700389
BW
98{
99 char buf[128], *s;
100 FILE *f;
101
102 /* strip the '/dev/' from the devname here */
103 snprintf(buf, sizeof buf, RTC_PATH, devname + strlen("/dev/"));
104 f = fopen(buf, "r");
105 if (!f) {
289dcc90 106 warn(_("cannot open %s"), buf);
76700389
BW
107 return 0;
108 }
109 s = fgets(buf, sizeof buf, f);
110 fclose(f);
111 if (!s)
112 return 0;
113
114 s = strchr(buf, '\n');
115 if (!s)
116 return 0;
117 *s = 0;
118
119 /* wakeup events could be disabled or not supported */
120 return strcmp(buf, "enabled") == 0;
121}
122
123/* all times should be in UTC */
124static time_t sys_time;
125static time_t rtc_time;
126
127static int get_basetimes(int fd)
128{
129 struct tm tm;
130 struct rtc_time rtc;
131
132 /* this process works in RTC time, except when working
133 * with the system clock (which always uses UTC).
134 */
135 if (clock_mode == CM_UTC)
136 setenv("TZ", "UTC", 1);
137 tzset();
138
139 /* read rtc and system clocks "at the same time", or as
140 * precisely (+/- a second) as we can read them.
141 */
142 if (ioctl(fd, RTC_RD_TIME, &rtc) < 0) {
07b336c9 143 warn(_("read rtc time failed"));
f8d87ab1 144 return -1;
76700389
BW
145 }
146 sys_time = time(0);
147 if (sys_time == (time_t)-1) {
07b336c9 148 warn(_("read system time failed"));
f8d87ab1 149 return -1;
76700389
BW
150 }
151
152 /* convert rtc_time to normal arithmetic-friendly form,
153 * updating tm.tm_wday as used by asctime().
154 */
155 memset(&tm, 0, sizeof tm);
156 tm.tm_sec = rtc.tm_sec;
157 tm.tm_min = rtc.tm_min;
158 tm.tm_hour = rtc.tm_hour;
159 tm.tm_mday = rtc.tm_mday;
160 tm.tm_mon = rtc.tm_mon;
161 tm.tm_year = rtc.tm_year;
1da17ec6 162 tm.tm_isdst = -1; /* assume the system knows better than the RTC */
76700389
BW
163 rtc_time = mktime(&tm);
164
165 if (rtc_time == (time_t)-1) {
07b336c9 166 warn(_("convert rtc time failed"));
f8d87ab1 167 return -1;
76700389
BW
168 }
169
170 if (verbose) {
2148b051
DB
171 /* Unless the system uses UTC, either delta or tzone
172 * reflects a seconds offset from UTC. The value can
173 * help sort out problems like bugs in your C library.
174 */
175 printf("\tdelta = %ld\n", sys_time - rtc_time);
176 printf("\ttzone = %ld\n", timezone);
177
178 printf("\ttzname = %s\n", tzname[daylight]);
179 gmtime_r(&rtc_time, &tm);
180 printf("\tsystime = %ld, (UTC) %s",
76700389 181 (long) sys_time, asctime(gmtime(&sys_time)));
2148b051 182 printf("\trtctime = %ld, (UTC) %s",
76700389
BW
183 (long) rtc_time, asctime(&tm));
184 }
185
f8d87ab1 186 return 0;
76700389
BW
187}
188
189static int setup_alarm(int fd, time_t *wakeup)
190{
191 struct tm *tm;
192 struct rtc_wkalrm wake;
193
1b7c164c
DB
194 /* The wakeup time is in POSIX time (more or less UTC).
195 * Ideally RTCs use that same time; but PCs can't do that
196 * if they need to boot MS-Windows. Messy...
197 *
198 * When clock_mode == CM_UTC this process's timezone is UTC,
199 * so we'll pass a UTC date to the RTC.
200 *
201 * Else clock_mode == CM_LOCAL so the time given to the RTC
202 * will instead use the local time zone.
203 */
204 tm = localtime(wakeup);
76700389
BW
205
206 wake.time.tm_sec = tm->tm_sec;
207 wake.time.tm_min = tm->tm_min;
208 wake.time.tm_hour = tm->tm_hour;
209 wake.time.tm_mday = tm->tm_mday;
210 wake.time.tm_mon = tm->tm_mon;
211 wake.time.tm_year = tm->tm_year;
2148b051
DB
212 /* wday, yday, and isdst fields are unused by Linux */
213 wake.time.tm_wday = -1;
214 wake.time.tm_yday = -1;
215 wake.time.tm_isdst = -1;
76700389 216
fc181184 217 wake.enabled = 1;
569f3ca2 218
fc181184 219 /* First try the preferred RTC_WKALM_SET */
569f3ca2 220 if (!dryrun && ioctl(fd, RTC_WKALM_SET, &wake) < 0) {
fc181184
GB
221 wake.enabled = 0;
222 /* Fall back on the non-preferred way of setting wakeups; only
223 * works for alarms < 24 hours from now */
224 if ((rtc_time + (24 * 60 * 60)) > *wakeup) {
225 if (ioctl(fd, RTC_ALM_SET, &wake.time) < 0) {
07b336c9 226 warn(_("set rtc alarm failed"));
fc181184
GB
227 return -1;
228 }
229 if (ioctl(fd, RTC_AIE_ON, 0) < 0) {
07b336c9 230 warn(_("enable rtc alarm failed"));
fc181184
GB
231 return -1;
232 }
233 } else {
07b336c9 234 warn(_("set rtc wake alarm failed"));
fc181184 235 return -1;
76700389
BW
236 }
237 }
238
f8d87ab1 239 return 0;
76700389
BW
240}
241
e6d1dc94
LR
242static int is_suspend_available(const char *suspend)
243{
244 int rc;
245 char buf[32];
246 FILE *f = fopen(SYS_POWER_STATE_PATH, "r");
247
248 if (!f)
249 return -1;
250
251 if (fgets(buf, sizeof buf, f) == NULL)
252 rc = -1;
253 else
254 rc = strstr(buf, suspend) != NULL;
255
256 fclose(f);
257 return rc;
258}
259
76700389
BW
260static void suspend_system(const char *suspend)
261{
d3cf5414 262 FILE *f = fopen(SYS_POWER_STATE_PATH, "w");
76700389
BW
263
264 if (!f) {
289dcc90 265 warn(_("cannot open %s"), SYS_POWER_STATE_PATH);
76700389
BW
266 return;
267 }
268
569f3ca2
KZ
269 if (!dryrun) {
270 fprintf(f, "%s\n", suspend);
271 fflush(f);
272 }
76700389
BW
273
274 /* this executes after wake from suspend */
efb8854f
SK
275 if (close_stream(f))
276 errx(EXIT_FAILURE, _("write error"));
76700389
BW
277}
278
279
280static int read_clock_mode(void)
281{
282 FILE *fp;
283 char linebuf[MAX_LINE];
284
3a2f3e82 285 fp = fopen(adjfile, "r");
76700389 286 if (!fp)
f8d87ab1 287 return -1;
76700389
BW
288
289 /* skip first line */
290 if (!fgets(linebuf, MAX_LINE, fp)) {
291 fclose(fp);
f8d87ab1 292 return -1;
76700389
BW
293 }
294
295 /* skip second line */
296 if (!fgets(linebuf, MAX_LINE, fp)) {
297 fclose(fp);
f8d87ab1 298 return -1;
76700389
BW
299 }
300
301 /* read third line */
302 if (!fgets(linebuf, MAX_LINE, fp)) {
303 fclose(fp);
f8d87ab1 304 return -1;
76700389
BW
305 }
306
307 if (strncmp(linebuf, "UTC", 3) == 0)
308 clock_mode = CM_UTC;
309 else if (strncmp(linebuf, "LOCAL", 5) == 0)
310 clock_mode = CM_LOCAL;
311
312 fclose(fp);
313
f8d87ab1 314 return 0;
76700389
BW
315}
316
fcf67294
MO
317/**
318 * print basic alarm settings
319 */
320static int print_alarm(int fd)
321{
322 struct rtc_wkalrm wake;
323 struct rtc_time rtc;
324 struct tm tm;
325 time_t alarm;
326
327 /* First try the preferred RTC_WKALM_RD */
328 if (ioctl(fd, RTC_WKALM_RD, &wake) < 0) {
329 /* Fall back on the non-preferred way of reading wakeups; only
330 * works for alarms < 24 hours from now
331 *
332 * set wake.enabled to 1 and determine from value of the year-1
333 * means disabled
334 */
335 wake.enabled = 1;
336 if (ioctl(fd, RTC_ALM_READ, &wake.time) < 0) {
07b336c9 337 warn(_("read rtc alarm failed"));
fcf67294
MO
338 return -1;
339 }
340 }
341
342 if (wake.enabled != 1 || wake.time.tm_year == -1) {
343 printf(_("alarm: off\n"));
344 return 0;
345 }
346
347 rtc = wake.time;
348
349 memset(&tm, 0, sizeof tm);
350 tm.tm_sec = rtc.tm_sec;
351 tm.tm_min = rtc.tm_min;
352 tm.tm_hour = rtc.tm_hour;
353 tm.tm_mday = rtc.tm_mday;
354 tm.tm_mon = rtc.tm_mon;
355 tm.tm_year = rtc.tm_year;
356 tm.tm_isdst = -1; /* assume the system knows better than the RTC */
357
358 alarm = mktime(&tm);
359 if (alarm == (time_t)-1) {
07b336c9 360 warn(_("convert time failed"));
fcf67294
MO
361 return -1;
362 }
363
364 /* 0 if both UTC, or expresses diff if RTC in local time */
365 alarm += sys_time - rtc_time;
366
07b336c9 367 printf(_("alarm: on %s"), ctime(&alarm));
fcf67294
MO
368 return 0;
369}
370
76700389
BW
371int main(int argc, char **argv)
372{
373 char *devname = DEFAULT_DEVICE;
374 unsigned seconds = 0;
375 char *suspend = DEFAULT_MODE;
376
77f5744c 377 int rc = EXIT_SUCCESS;
76700389
BW
378 int t;
379 int fd;
380 time_t alarm = 0;
381
3a2f3e82
KZ
382 static const struct option long_options[] = {
383 {"adjfile", required_argument, 0, 'A'},
384 {"auto", no_argument, 0, 'a'},
385 {"dry-run", no_argument, 0, 'n'},
386 {"local", no_argument, 0, 'l'},
387 {"utc", no_argument, 0, 'u'},
388 {"verbose", no_argument, 0, 'v'},
389 {"version", no_argument, 0, 'V'},
390 {"help", no_argument, 0, 'h'},
391 {"mode", required_argument, 0, 'm'},
392 {"device", required_argument, 0, 'd'},
393 {"seconds", required_argument, 0, 's'},
394 {"time", required_argument, 0, 't'},
395 {0, 0, 0, 0 }
396 };
397
76700389
BW
398 setlocale(LC_ALL, "");
399 bindtextdomain(PACKAGE, LOCALEDIR);
400 textdomain(PACKAGE);
efb8854f 401 atexit(close_stdout);
76700389 402
3a2f3e82 403 while ((t = getopt_long(argc, argv, "A:ahd:lm:ns:t:uVv",
76700389
BW
404 long_options, NULL)) != EOF) {
405 switch (t) {
3a2f3e82
KZ
406 case 'A':
407 /* for better compatibility with hwclock */
408 adjfile = optarg;
409 break;
76700389
BW
410 case 'a':
411 /* CM_AUTO is default */
412 break;
413
414 case 'd':
c1196d3a 415 devname = optarg;
76700389
BW
416 break;
417
418 case 'l':
419 clock_mode = CM_LOCAL;
420 break;
421
422 /* what system power mode to use? for now handle only
423 * standardized mode names; eventually when systems
424 * define their own state names, parse
425 * /sys/power/state.
426 *
427 * "on" is used just to test the RTC alarm mechanism,
428 * bypassing all the wakeup-from-sleep infrastructure.
429 */
430 case 'm':
431 if (strcmp(optarg, "standby") == 0
432 || strcmp(optarg, "mem") == 0
433 || strcmp(optarg, "disk") == 0
434 || strcmp(optarg, "on") == 0
e4b0fc36 435 || strcmp(optarg, "no") == 0
77f5744c 436 || strcmp(optarg, "off") == 0
ece44f19 437 || strcmp(optarg, "freeze") == 0
c15dd93b 438 || strcmp(optarg, "disable") == 0
fcf67294 439 || strcmp(optarg, "show") == 0
76700389 440 ) {
c1196d3a 441 suspend = optarg;
76700389
BW
442 break;
443 }
07b336c9
KZ
444
445 errx(EXIT_FAILURE, _("unrecognized suspend state '%s'"),
446 optarg);
447 break;
76700389 448
569f3ca2
KZ
449 case 'n':
450 dryrun = 1;
451 break;
452
76700389
BW
453 /* alarm time, seconds-to-sleep (relative) */
454 case 's':
20a39982 455 seconds = strtou32_or_err(optarg, _("invalid seconds argument"));
76700389
BW
456 break;
457
458 /* alarm time, time_t (absolute, seconds since
459 * 1/1 1970 UTC)
460 */
461 case 't':
20a39982 462 alarm = strtou32_or_err(optarg, _("invalid time argument"));
76700389
BW
463 break;
464
465 case 'u':
466 clock_mode = CM_UTC;
467 break;
468
469 case 'v':
470 verbose++;
471 break;
472
473 case 'V':
217615e8
BS
474 printf(_("%s from %s\n"),
475 program_invocation_short_name, PACKAGE_STRING);
76700389
BW
476 exit(EXIT_SUCCESS);
477
478 case 'h':
07b336c9 479 usage(stdout);
76700389 480 default:
07b336c9 481 usage(stderr);
76700389
BW
482 }
483 }
484
485 if (clock_mode == CM_AUTO) {
f8d87ab1 486 if (read_clock_mode() < 0) {
07b336c9
KZ
487 printf(_("%s: assuming RTC uses UTC ...\n"),
488 program_invocation_short_name);
76700389
BW
489 clock_mode = CM_UTC;
490 }
76700389 491 }
2148b051
DB
492 if (verbose)
493 printf(clock_mode == CM_UTC ? _("Using UTC time.\n") :
494 _("Using local time.\n"));
76700389 495
fcf67294
MO
496 if (!alarm && !seconds && strcmp(suspend,"disable") &&
497 strcmp(suspend,"show")) {
498
07b336c9
KZ
499 warnx(_("must provide wake time (see -t and -s options)"));
500 usage(stderr);
76700389
BW
501 }
502
503 /* when devname doesn't start with /dev, append it */
504 if (strncmp(devname, "/dev/", strlen("/dev/")) != 0) {
505 char *new_devname;
506
2ab428f6 507 new_devname = xmalloc(strlen(devname) + strlen("/dev/") + 1);
76700389
BW
508
509 strcpy(new_devname, "/dev/");
510 strcat(new_devname, devname);
76700389
BW
511 devname = new_devname;
512 }
513
e4b0fc36 514 if (strcmp(suspend, "on") != 0 && strcmp(suspend, "no") != 0
07b336c9
KZ
515 && !is_wakeup_enabled(devname))
516 errx(EXIT_FAILURE, _("%s not enabled for wakeup events"), devname);
76700389
BW
517
518 /* this RTC must exist and (if we'll sleep) be wakeup-enabled */
77f5744c
KZ
519#ifdef O_CLOEXEC
520 fd = open(devname, O_RDONLY | O_CLOEXEC);
521#else
76700389 522 fd = open(devname, O_RDONLY);
77f5744c 523#endif
07b336c9 524 if (fd < 0)
289dcc90 525 err(EXIT_FAILURE, _("cannot open %s"), devname);
76700389
BW
526
527 /* relative or absolute alarm time, normalized to time_t */
f8d87ab1 528 if (get_basetimes(fd) < 0)
76700389
BW
529 exit(EXIT_FAILURE);
530 if (verbose)
531 printf(_("alarm %ld, sys_time %ld, rtc_time %ld, seconds %u\n"),
532 alarm, sys_time, rtc_time, seconds);
77f5744c 533
fcf67294 534 if (strcmp(suspend, "show") && strcmp(suspend, "disable")) {
e6d1dc94
LR
535 if (strcmp(suspend, "no") && strcmp(suspend, "on") &&
536 strcmp(suspend, "off") && is_suspend_available(suspend) <= 0) {
537 errx(EXIT_FAILURE, _("suspend to \"%s\" unavailable"), suspend);
538 }
539
fcf67294
MO
540 /* care about alarm setup only if the show|disable
541 * modes are not set
542 */
543 if (alarm) {
07b336c9
KZ
544 if (alarm < sys_time)
545 errx(EXIT_FAILURE, _("time doesn't go backward to %s"),
546 ctime(&alarm));
fcf67294
MO
547 alarm += sys_time - rtc_time;
548 } else
549 alarm = rtc_time + seconds + 1;
550
551 if (setup_alarm(fd, &alarm) < 0)
552 exit(EXIT_FAILURE);
76700389 553
07b336c9
KZ
554 if (strcmp(suspend, "no") == 0 || strcmp(suspend, "on") == 0)
555 printf(_("%s: wakeup using %s at %s"),
556 program_invocation_short_name, devname,
557 ctime(&alarm));
558 else
559 printf(_("%s: wakeup from \"%s\" using %s at %s"),
560 program_invocation_short_name, suspend, devname,
fcf67294
MO
561 ctime(&alarm));
562 fflush(stdout);
563 usleep(10 * 1000);
564 }
76700389 565
ecd55f96
KZ
566 if (strcmp(suspend, "no") == 0) {
567 if (verbose)
568 printf(_("suspend mode: no; leaving\n"));
07b336c9 569 dryrun = 1; /* to skip disabling alarm at the end */
ecd55f96 570
77f5744c 571 } else if (strcmp(suspend, "off") == 0) {
caf60f22 572 char *arg[5];
77f5744c
KZ
573 int i = 0;
574
ecd55f96
KZ
575 if (verbose)
576 printf(_("suspend mode: off; executing %s\n"),
577 _PATH_SHUTDOWN);
77f5744c 578 arg[i++] = _PATH_SHUTDOWN;
caf60f22 579 arg[i++] = "-h";
77f5744c
KZ
580 arg[i++] = "-P";
581 arg[i++] = "now";
582 arg[i] = NULL;
583
569f3ca2
KZ
584 if (!dryrun) {
585 execv(arg[0], arg);
77f5744c 586
07ff972e 587 warn(_("failed to execute %s"), _PATH_SHUTDOWN);
569f3ca2
KZ
588 rc = EXIT_FAILURE;
589 }
ecd55f96
KZ
590
591 } else if (strcmp(suspend, "on") == 0) {
76700389
BW
592 unsigned long data;
593
ecd55f96
KZ
594 if (verbose)
595 printf(_("suspend mode: on; reading rtc\n"));
596
569f3ca2
KZ
597 if (!dryrun) {
598 do {
599 t = read(fd, &data, sizeof data);
600 if (t < 0) {
07b336c9 601 warn(_("rtc read failed"));
569f3ca2
KZ
602 break;
603 }
604 if (verbose)
605 printf("... %s: %03lx\n", devname, data);
606 } while (!(data & RTC_AF));
607 }
ecd55f96 608
c15dd93b
MO
609 } else if (strcmp(suspend, "disable") == 0) {
610 /* just break, alarm gets disabled in the end */
611 if (verbose)
612 printf(_("suspend mode: disable; disabling alarm\n"));
fcf67294
MO
613
614 } else if(strcmp(suspend,"show") == 0) {
615 if (verbose)
616 printf(_("suspend mode: show; printing alarm info\n"));
617 if (print_alarm(fd))
618 rc = EXIT_FAILURE;
619 dryrun = 1; /* don't really disable alarm in the end, just show */
620
ecd55f96
KZ
621 } else {
622 if (verbose)
623 printf(_("suspend mode: %s; suspending system\n"), suspend);
624 sync();
625 suspend_system(suspend);
76700389
BW
626 }
627
829eab67
G
628 if (!dryrun) {
629 /* try to disable the alarm with the preferred RTC_WKALM_RD and
630 * RTC_WKALM_SET calls, if it fails fall back to RTC_AIE_OFF
631 */
632 struct rtc_wkalrm wake;
633
634 if (ioctl(fd, RTC_WKALM_RD, &wake) < 0) {
635 if (ioctl(fd, RTC_AIE_OFF, 0) < 0) {
636 warn(_("disable rtc alarm interrupt failed"));
637 rc = EXIT_FAILURE;
638 }
639 } else {
640 wake.enabled = 0;
641 if (ioctl(fd, RTC_WKALM_SET, &wake) < 0) {
642 warn(_("disable rtc alarm interrupt failed"));
643 rc = EXIT_FAILURE;
644 }
645 }
646 }
76700389
BW
647
648 close(fd);
77f5744c 649 return rc;
76700389 650}