]> git.ipfire.org Git - thirdparty/util-linux.git/blame - sys-utils/hwclock-rtc.c
sys-utils: cleanup license lines, add SPDX
[thirdparty/util-linux.git] / sys-utils / hwclock-rtc.c
CommitLineData
ef71b8f1 1/*
68a2ade7
KZ
2 * SPDX-License-Identifier: GPL-2.0-or-later
3 *
9abd5e4b
KZ
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
ef71b8f1
SK
9 * rtc.c - Use /dev/rtc for clock access
10 */
998f392a 11#include <asm/ioctl.h>
5213517f 12#include <errno.h>
c7fc54b9
TW
13#include <linux/rtc.h>
14#include <linux/types.h>
998f392a
SK
15#include <fcntl.h>
16#include <stdio.h>
17#include <stdlib.h>
7eda085c 18#include <sys/ioctl.h>
998f392a
SK
19#include <sys/select.h>
20#include <sys/time.h>
21#include <time.h>
22#include <unistd.h>
7eda085c 23
f78a9021 24#include "monotonic.h"
511a5126
KZ
25#include "strutils.h"
26#include "xalloc.h"
7eda085c
KZ
27#include "nls.h"
28
c7f75390
KZ
29#include "hwclock.h"
30
511a5126
KZ
31#ifndef RTC_PARAM_GET
32struct rtc_param {
c7fc54b9 33 __u64 param;
511a5126 34 union {
c7fc54b9
TW
35 __u64 uvalue;
36 __s64 svalue;
37 __u64 ptr;
511a5126 38 };
c7fc54b9
TW
39 __u32 index;
40 __u32 __pad;
511a5126
KZ
41};
42
43# define RTC_PARAM_GET _IOW('p', 0x13, struct rtc_param)
44# define RTC_PARAM_SET _IOW('p', 0x14, struct rtc_param)
45
46# define RTC_PARAM_FEATURES 0
47# define RTC_PARAM_CORRECTION 1
48# define RTC_PARAM_BACKUP_SWITCH_MODE 2
49#endif /* RTC_PARAM_GET */
50
63d81834
KZ
51static const struct hwclock_param hwclock_params[] =
52{
53 { RTC_PARAM_FEATURES, "features", N_("supported features") },
54 { RTC_PARAM_CORRECTION, "correction", N_("time correction") },
55 { RTC_PARAM_BACKUP_SWITCH_MODE, "bsm", N_("backup switch mode") },
56 { }
57};
58
59const struct hwclock_param *get_hwclock_params(void)
60{
61 return hwclock_params;
62}
63
ef71b8f1
SK
64/*
65 * /dev/rtc is conventionally chardev 10/135
88681c5f
KZ
66 * ia64 uses /dev/efirtc, chardev 10/136
67 * devfs (obsolete) used /dev/misc/... for miscdev
68 * new RTC framework + udev uses dynamic major and /dev/rtc0.../dev/rtcN
69 * ... so we need an overridable default
70 */
7eda085c 71
88681c5f 72/* default or user defined dev (by hwclock --rtc=<path>) */
067b6028 73static const char *rtc_dev_name;
27f9db17
KZ
74static int rtc_dev_fd = -1;
75
ef71b8f1
SK
76static void close_rtc(void)
77{
27f9db17
KZ
78 if (rtc_dev_fd != -1)
79 close(rtc_dev_fd);
80 rtc_dev_fd = -1;
81}
82
336f7c5f 83static int open_rtc(const struct hwclock_control *ctl)
ef71b8f1 84{
e08dddbc 85 static const char * const fls[] = {
88681c5f
KZ
86#ifdef __ia64__
87 "/dev/efirtc",
88 "/dev/misc/efirtc",
89#endif
88681c5f 90 "/dev/rtc0",
1811900a 91 "/dev/rtc",
067b6028 92 "/dev/misc/rtc"
88681c5f 93 };
067b6028 94 size_t i;
5d1f6bae 95
27f9db17
KZ
96 if (rtc_dev_fd != -1)
97 return rtc_dev_fd;
98
5d1f6bae 99 /* --rtc option has been given */
336f7c5f
SK
100 if (ctl->rtc_dev_name) {
101 rtc_dev_name = ctl->rtc_dev_name;
27f9db17 102 rtc_dev_fd = open(rtc_dev_name, O_RDONLY);
336f7c5f 103 } else {
067b6028 104 for (i = 0; i < ARRAY_SIZE(fls); i++) {
de4568f7 105 if (ctl->verbose)
067b6028
SK
106 printf(_("Trying to open: %s\n"), fls[i]);
107 rtc_dev_fd = open(fls[i], O_RDONLY);
27f9db17 108
b3fc2a3c
KZ
109 if (rtc_dev_fd < 0) {
110 if (errno == ENOENT || errno == ENODEV)
111 continue;
112 if (ctl->verbose)
113 warn(_("cannot open %s"), fls[i]);
114 }
067b6028 115 rtc_dev_name = fls[i];
27f9db17
KZ
116 break;
117 }
118 if (rtc_dev_fd < 0)
119 rtc_dev_name = *fls; /* default for error messages */
5d1f6bae 120 }
926ffe74 121 if (rtc_dev_fd != -1)
27f9db17
KZ
122 atexit(close_rtc);
123 return rtc_dev_fd;
63cccae4
KZ
124}
125
336f7c5f 126static int open_rtc_or_exit(const struct hwclock_control *ctl)
ef71b8f1 127{
336f7c5f 128 int rtc_fd = open_rtc(ctl);
63cccae4
KZ
129
130 if (rtc_fd < 0) {
067b6028 131 warn(_("cannot open rtc device"));
c47a8f2a 132 hwclock_exit(ctl, EXIT_FAILURE);
364cda48
KZ
133 }
134 return rtc_fd;
135}
136
ef71b8f1
SK
137static int do_rtc_read_ioctl(int rtc_fd, struct tm *tm)
138{
364cda48 139 int rc = -1;
a423fe19 140 struct rtc_time rtc_tm = { 0 };
fc35f2db 141
a423fe19 142 rc = ioctl(rtc_fd, RTC_RD_TIME, &rtc_tm);
364cda48 143
364cda48 144 if (rc == -1) {
bed96b1c
TW
145 warn(_("ioctl(RTC_RD_NAME) to %s to read the time failed"),
146 rtc_dev_name);
cdedde03 147 return -1;
364cda48
KZ
148 }
149
a423fe19
KZ
150 /* kernel uses private struct tm definition to be self contained */
151 tm->tm_sec = rtc_tm.tm_sec;
152 tm->tm_min = rtc_tm.tm_min;
153 tm->tm_hour = rtc_tm.tm_hour;
154 tm->tm_mday = rtc_tm.tm_mday;
155 tm->tm_mon = rtc_tm.tm_mon;
156 tm->tm_year = rtc_tm.tm_year;
157 tm->tm_wday = rtc_tm.tm_wday;
158 tm->tm_yday = rtc_tm.tm_yday;
ef71b8f1 159 tm->tm_isdst = -1; /* don't know whether it's dst */
364cda48
KZ
160 return 0;
161}
7eda085c 162
ef71b8f1 163/*
0411a57e
WP
164 * Wait for the top of a clock tick by reading /dev/rtc in a busy loop
165 * until we see it. This function is used for rtc drivers without ioctl
166 * interrupts. This is typical on an Alpha, where the Hardware Clock
167 * interrupts are used by the kernel for the system clock, so aren't at
168 * the user's disposal.
ef71b8f1 169 */
336f7c5f
SK
170static int busywait_for_rtc_clock_tick(const struct hwclock_control *ctl,
171 const int rtc_fd)
ef71b8f1 172{
0bc13e01 173 struct tm start_time = { 0 };
ef71b8f1 174 /* The time when we were called (and started waiting) */
0bc13e01 175 struct tm nowtime = { 0 };
ef71b8f1 176 int rc;
cf8c1917 177 struct timeval begin = { 0 }, now = { 0 };
ef71b8f1 178
de4568f7 179 if (ctl->verbose) {
0411a57e
WP
180 printf("ioctl(%d, RTC_UIE_ON, 0): %s\n",
181 rtc_fd, strerror(errno));
ef71b8f1
SK
182 printf(_("Waiting in loop for time from %s to change\n"),
183 rtc_dev_name);
0411a57e 184 }
ef71b8f1 185
4a6f658c
WP
186 if (do_rtc_read_ioctl(rtc_fd, &start_time))
187 return 1;
ef71b8f1
SK
188
189 /*
190 * Wait for change. Should be within a second, but in case
191 * something weird happens, we have a time limit (1.5s) on this loop
192 * to reduce the impact of this failure.
193 */
f78a9021 194 gettime_monotonic(&begin);
ef71b8f1
SK
195 do {
196 rc = do_rtc_read_ioctl(rtc_fd, &nowtime);
197 if (rc || start_time.tm_sec != nowtime.tm_sec)
198 break;
f78a9021 199 gettime_monotonic(&now);
ef71b8f1 200 if (time_diff(now, begin) > 1.5) {
111c05d3 201 warnx(_("Timed out waiting for time change."));
4a6f658c 202 return 1;
ef71b8f1
SK
203 }
204 } while (1);
205
206 if (rc)
4a6f658c
WP
207 return 1;
208 return 0;
7eda085c
KZ
209}
210
ef71b8f1
SK
211/*
212 * Same as synchronize_to_clock_tick(), but just for /dev/rtc.
213 */
336f7c5f 214static int synchronize_to_clock_tick_rtc(const struct hwclock_control *ctl)
ef71b8f1
SK
215{
216 int rtc_fd; /* File descriptor of /dev/rtc */
4bfd519e 217 int ret = 1;
ef71b8f1 218
336f7c5f 219 rtc_fd = open_rtc(ctl);
ef71b8f1 220 if (rtc_fd == -1) {
067b6028 221 warn(_("cannot open rtc device"));
4bfd519e 222 return ret;
042f62df
RP
223 }
224
225 /* Turn on update interrupts (one per second) */
226 int rc = ioctl(rtc_fd, RTC_UIE_ON, 0);
227
228 if (rc != -1) {
229 /*
230 * Just reading rtc_fd fails on broken hardware: no
231 * update interrupt comes and a bootscript with a
232 * hwclock call hangs
233 */
234 fd_set rfds;
235 struct timeval tv;
236
237 /*
238 * Wait up to ten seconds for the next update
239 * interrupt
240 */
241 FD_ZERO(&rfds);
242 FD_SET(rtc_fd, &rfds);
243 tv.tv_sec = 10;
244 tv.tv_usec = 0;
245 rc = select(rtc_fd + 1, &rfds, NULL, NULL, &tv);
246 if (0 < rc)
247 ret = 0;
248 else if (rc == 0) {
249 warnx(_("select() to %s to wait for clock tick timed out"),
250 rtc_dev_name);
251 } else
252 warn(_("select() to %s to wait for clock tick failed"),
253 rtc_dev_name);
254 /* Turn off update interrupts */
255 rc = ioctl(rtc_fd, RTC_UIE_OFF, 0);
256 if (rc == -1)
257 warn(_("ioctl() to %s to turn off update interrupts failed"),
258 rtc_dev_name);
c8650db3
ŁS
259 } else if (errno == ENOTTY || errno == EINVAL) {
260 /* rtc ioctl interrupts are unimplemented */
261 ret = busywait_for_rtc_clock_tick(ctl, rtc_fd);
262 } else
263 warn(_("ioctl(%d, RTC_UIE_ON, 0) to %s failed"),
264 rtc_fd, rtc_dev_name);
ef71b8f1 265 return ret;
7eda085c
KZ
266}
267
336f7c5f
SK
268static int read_hardware_clock_rtc(const struct hwclock_control *ctl,
269 struct tm *tm)
ef71b8f1 270{
55a4a75c 271 int rtc_fd, rc;
7eda085c 272
336f7c5f 273 rtc_fd = open_rtc_or_exit(ctl);
7eda085c 274
364cda48 275 /* Read the RTC time/date, return answer via tm */
55a4a75c 276 rc = do_rtc_read_ioctl(rtc_fd, tm);
7eda085c 277
55a4a75c 278 return rc;
7eda085c
KZ
279}
280
ef71b8f1
SK
281/*
282 * Set the Hardware Clock to the broken down time <new_broken_time>. Use
283 * ioctls to "rtc" device /dev/rtc.
284 */
336f7c5f
SK
285static int set_hardware_clock_rtc(const struct hwclock_control *ctl,
286 const struct tm *new_broken_time)
ef71b8f1 287{
364cda48
KZ
288 int rc = -1;
289 int rtc_fd;
a423fe19 290 struct rtc_time rtc_tm = { 0 };
364cda48 291
336f7c5f 292 rtc_fd = open_rtc_or_exit(ctl);
63cccae4 293
a423fe19
KZ
294 /* kernel uses private struct tm definition to be self contained */
295 rtc_tm.tm_sec = new_broken_time->tm_sec;
296 rtc_tm.tm_min = new_broken_time->tm_min;
297 rtc_tm.tm_hour = new_broken_time->tm_hour;
298 rtc_tm.tm_mday = new_broken_time->tm_mday;
299 rtc_tm.tm_mon = new_broken_time->tm_mon;
300 rtc_tm.tm_year = new_broken_time->tm_year;
301 rtc_tm.tm_wday = new_broken_time->tm_wday;
302 rtc_tm.tm_yday = new_broken_time->tm_yday;
303 rtc_tm.tm_isdst = new_broken_time->tm_isdst;
304
305 rc = ioctl(rtc_fd, RTC_SET_TIME, &rtc_tm);
fc35f2db 306
364cda48 307 if (rc == -1) {
bed96b1c
TW
308 warn(_("ioctl(RTC_SET_TIME) to %s to set the time failed"),
309 rtc_dev_name);
c47a8f2a 310 hwclock_exit(ctl, EXIT_FAILURE);
364cda48
KZ
311 }
312
de4568f7 313 if (ctl->verbose)
bed96b1c 314 printf(_("ioctl(RTC_SET_TIME) was successful.\n"));
364cda48 315
364cda48 316 return 0;
7eda085c
KZ
317}
318
ef71b8f1
SK
319static int get_permissions_rtc(void)
320{
7eda085c
KZ
321 return 0;
322}
323
df4f1a66
KZ
324static const char *get_device_path(void)
325{
326 return rtc_dev_name;
327}
328
e08dddbc 329static const struct clock_ops rtc_interface = {
8f729d60 330 N_("Using the rtc interface to the clock."),
7eda085c
KZ
331 get_permissions_rtc,
332 read_hardware_clock_rtc,
333 set_hardware_clock_rtc,
334 synchronize_to_clock_tick_rtc,
df4f1a66 335 get_device_path,
7eda085c
KZ
336};
337
338/* return &rtc if /dev/rtc can be opened, NULL otherwise */
e08dddbc 339const struct clock_ops *probe_for_rtc_clock(const struct hwclock_control *ctl)
ef71b8f1 340{
bd078689
SK
341 const int rtc_fd = open_rtc(ctl);
342
343 if (rtc_fd < 0)
344 return NULL;
345 return &rtc_interface;
7eda085c
KZ
346}
347
bd078689 348#ifdef __alpha__
ef71b8f1
SK
349/*
350 * Get the Hardware Clock epoch setting from the kernel.
351 */
af68bd01 352int get_epoch_rtc(const struct hwclock_control *ctl, unsigned long *epoch_p)
ef71b8f1
SK
353{
354 int rtc_fd;
355
336f7c5f 356 rtc_fd = open_rtc(ctl);
ef71b8f1 357 if (rtc_fd < 0) {
cbc36f79 358 warn(_("cannot open %s"), rtc_dev_name);
ef71b8f1
SK
359 return 1;
360 }
361
362 if (ioctl(rtc_fd, RTC_EPOCH_READ, epoch_p) == -1) {
f613c3c2
WP
363 warn(_("ioctl(%d, RTC_EPOCH_READ, epoch_p) to %s failed"),
364 rtc_fd, rtc_dev_name);
ef71b8f1
SK
365 return 1;
366 }
7eda085c 367
de4568f7 368 if (ctl->verbose)
f613c3c2
WP
369 printf(_("ioctl(%d, RTC_EPOCH_READ, epoch_p) to %s succeeded.\n"),
370 rtc_fd, rtc_dev_name);
7eda085c 371
ef71b8f1 372 return 0;
7eda085c
KZ
373}
374
ef71b8f1
SK
375/*
376 * Set the Hardware Clock epoch in the kernel.
377 */
336f7c5f 378int set_epoch_rtc(const struct hwclock_control *ctl)
ef71b8f1
SK
379{
380 int rtc_fd;
f7599b4f 381 unsigned long epoch;
ef71b8f1 382
9bf8088f 383 errno = 0;
f7599b4f
WP
384 epoch = strtoul(ctl->epoch_option, NULL, 10);
385
386 /* There were no RTC clocks before 1900. */
9bf8088f 387 if (errno || epoch < 1900 || epoch == ULONG_MAX) {
f7599b4f 388 warnx(_("invalid epoch '%s'."), ctl->epoch_option);
ef71b8f1
SK
389 return 1;
390 }
391
336f7c5f 392 rtc_fd = open_rtc(ctl);
ef71b8f1 393 if (rtc_fd < 0) {
cbc36f79 394 warn(_("cannot open %s"), rtc_dev_name);
ef71b8f1
SK
395 return 1;
396 }
7eda085c 397
f7599b4f 398 if (ioctl(rtc_fd, RTC_EPOCH_SET, epoch) == -1) {
f613c3c2
WP
399 warn(_("ioctl(%d, RTC_EPOCH_SET, %lu) to %s failed"),
400 rtc_fd, epoch, rtc_dev_name);
ef71b8f1
SK
401 return 1;
402 }
7eda085c 403
de4568f7 404 if (ctl->verbose)
f613c3c2
WP
405 printf(_("ioctl(%d, RTC_EPOCH_SET, %lu) to %s succeeded.\n"),
406 rtc_fd, epoch, rtc_dev_name);
407
ef71b8f1 408 return 0;
7eda085c 409}
bd078689 410#endif /* __alpha__ */
6097b12d 411
63d81834
KZ
412
413
c7fc54b9 414static int resolve_rtc_param_alias(const char *alias, __u64 *value)
6097b12d
BK
415{
416 const struct hwclock_param *param = &hwclock_params[0];
417
418 while (param->name) {
419 if (!strcmp(alias, param->name)) {
420 *value = param->id;
421 return 0;
422 }
423 param++;
424 }
425
426 return 1;
427}
428
c7fc54b9
TW
429/* kernel uapi __u64 can be defined differently than uint64_t */
430static int strtoku64(const char *str, __u64 *num, int base)
431{
432 return ul_strtou64(str, (uint64_t *) &num, base);
433}
434
6097b12d
BK
435/*
436 * Get the Hardware Clock parameter setting from the kernel.
437 */
511a5126
KZ
438int get_param_rtc(const struct hwclock_control *ctl,
439 const char *name, uint64_t *id, uint64_t *value)
6097b12d
BK
440{
441 int rtc_fd;
511a5126 442 struct rtc_param param = { .param = 0 };
6097b12d
BK
443
444 /* handle name */
511a5126 445 if (resolve_rtc_param_alias(name, &param.param) != 0
c7fc54b9 446 && strtoku64(name, &param.param, 0) != 0) {
511a5126
KZ
447 warnx(_("could not convert parameter name to number"));
448 return 1;
6097b12d
BK
449 }
450
451 /* get parameter */
452 rtc_fd = open_rtc(ctl);
453 if (rtc_fd < 0) {
454 warn(_("cannot open %s"), rtc_dev_name);
455 return 1;
456 }
457
511a5126 458 if (ioctl(rtc_fd, RTC_PARAM_GET, &param) == -1) {
6097b12d
BK
459 warn(_("ioctl(%d, RTC_PARAM_GET, param) to %s failed"),
460 rtc_fd, rtc_dev_name);
461 return 1;
462 }
463
511a5126
KZ
464 if (id)
465 *id = param.param;
47577bb5 466 if (value)
511a5126
KZ
467 *value = param.uvalue;
468
6097b12d
BK
469 if (ctl->verbose)
470 printf(_("ioctl(%d, RTC_PARAM_GET, param) to %s succeeded.\n"),
471 rtc_fd, rtc_dev_name);
472
473 return 0;
474}
b22b78b1
BK
475
476/*
477 * Set the Hardware Clock parameter in the kernel.
478 */
511a5126 479int set_param_rtc(const struct hwclock_control *ctl, const char *opt0)
b22b78b1 480{
511a5126
KZ
481 int rtc_fd, rc = 1;
482 struct rtc_param param = { .param = 0 };
483 char *tok, *opt = xstrdup(opt0);
b22b78b1
BK
484
485 /* handle name */
511a5126
KZ
486 tok = strtok(opt, "=");
487 if (resolve_rtc_param_alias(tok, &param.param) != 0
c7fc54b9 488 && strtoku64(tok, &param.param, 0) != 0) {
511a5126
KZ
489 warnx(_("could not convert parameter name to number"));
490 goto done;
b22b78b1
BK
491 }
492
493 /* handle value */
494 tok = strtok(NULL, "=");
495 if (!tok) {
496 warnx(_("expected <param>=<value>"));
511a5126 497 goto done;
b22b78b1 498 }
c7fc54b9 499 if (strtoku64(tok, &param.uvalue, 0) != 0) {
b22b78b1 500 warnx(_("could not convert parameter value to number"));
511a5126 501 goto done;
b22b78b1
BK
502 }
503
504 /* set parameter */
505 rtc_fd = open_rtc(ctl);
506 if (rtc_fd < 0) {
507 warnx(_("cannot open %s"), rtc_dev_name);
508 return 1;
509 }
510
511 if (ioctl(rtc_fd, RTC_PARAM_SET, &param) == -1) {
512 warn(_("ioctl(%d, RTC_PARAM_SET, param) to %s failed"),
513 rtc_fd, rtc_dev_name);
511a5126 514 goto done;
b22b78b1
BK
515 }
516
517 if (ctl->verbose)
518 printf(_("ioctl(%d, RTC_PARAM_SET, param) to %s succeeded.\n"),
519 rtc_fd, rtc_dev_name);
520
511a5126
KZ
521 rc = 0;
522done:
523 free(opt);
524 return rc;
b22b78b1 525}
76cf1753
RV
526
527#ifndef RTC_VL_DATA_INVALID
528#define RTC_VL_DATA_INVALID 0x1
529#endif
530#ifndef RTC_VL_BACKUP_LOW
531#define RTC_VL_BACKUP_LOW 0x2
532#endif
533#ifndef RTC_VL_BACKUP_EMPTY
534#define RTC_VL_BACKUP_EMPTY 0x4
535#endif
536#ifndef RTC_VL_ACCURACY_LOW
537#define RTC_VL_ACCURACY_LOW 0x8
538#endif
539#ifndef RTC_VL_BACKUP_SWITCH
540#define RTC_VL_BACKUP_SWITCH 0x10
541#endif
542
543int rtc_vl_read(const struct hwclock_control *ctl)
544{
545 unsigned int vl;
546 int rtc_fd;
547 size_t i;
548 static const struct vl_bit {
549 unsigned int bit;
550 const char *desc;
551 } vl_bits[] = {
552 { RTC_VL_DATA_INVALID, N_("Voltage too low, RTC data is invalid") },
553 { RTC_VL_BACKUP_LOW, N_("Backup voltage is low") },
554 { RTC_VL_BACKUP_EMPTY, N_("Backup empty or not present") },
555 { RTC_VL_ACCURACY_LOW, N_("Voltage is low, RTC accuracy is reduced") },
556 { RTC_VL_BACKUP_SWITCH, N_("Backup switchover happened") },
557 };
558
559 rtc_fd = open_rtc(ctl);
560 if (rtc_fd < 0) {
561 warnx(_("cannot open %s"), rtc_dev_name);
562 return 1;
563 }
564
565 if (ioctl(rtc_fd, RTC_VL_READ, &vl) == -1) {
566 warn(_("ioctl(%d, RTC_VL_READ) on %s failed"),
567 rtc_fd, rtc_dev_name);
568 return 1;
569 }
570
571 if (ctl->verbose) {
572 printf(_("ioctl(%d, RTC_VL_READ) on %s returned 0x%x\n"),
573 rtc_fd, rtc_dev_name, vl);
574 }
575
576 for (i = 0; i < ARRAY_SIZE(vl_bits); ++i) {
577 const struct vl_bit *vlb = &vl_bits[i];
578
579 if (vl & vlb->bit) {
580 printf("0x%02x - %s\n", vlb->bit, vlb->desc);
581 vl &= ~vlb->bit;
582 }
583 }
584 if (vl)
585 printf("0x%02x - unknown bit(s)\n", vl);
586
587 return 0;
588}
589
590int rtc_vl_clear(const struct hwclock_control *ctl)
591{
592 int rtc_fd;
593
594 rtc_fd = open_rtc(ctl);
595 if (rtc_fd < 0) {
596 warnx(_("cannot open %s"), rtc_dev_name);
597 return 1;
598 }
599
600 if (ioctl(rtc_fd, RTC_VL_CLR) == -1) {
601 warn(_("ioctl(%d, RTC_VL_CLEAR) on %s failed"),
602 rtc_fd, rtc_dev_name);
603 return 1;
604 }
605
606 if (ctl->verbose)
607 printf(_("ioctl(%d, RTC_VL_CLEAR) on %s succeeded.\n"),
608 rtc_fd, rtc_dev_name);
609
610 return 0;
611}