]> git.ipfire.org Git - thirdparty/util-linux.git/blame - hwclock/rtc.c
hwclock: remove misleading information
[thirdparty/util-linux.git] / hwclock / rtc.c
CommitLineData
7eda085c
KZ
1/* rtc.c - Use /dev/rtc for clock access */
2#include <unistd.h> /* for close() */
3#include <fcntl.h> /* for O_RDONLY */
5213517f 4#include <errno.h>
63cccae4 5#include <sysexits.h>
7eda085c 6#include <sys/ioctl.h>
d03dd608 7#include <sys/time.h> /* for struct timeval */
7eda085c
KZ
8
9#include "clock.h"
10#include "nls.h"
11
12/*
13 * Get defines for rtc stuff.
14 *
15 * Getting the rtc defines is nontrivial.
16 * The obvious way is by including <linux/mc146818rtc.h>
17 * but that again includes <asm/io.h> which again includes ...
18 * and on sparc and alpha this gives compilation errors for
19 * many kernel versions. So, we give the defines ourselves here.
20 * Moreover, some Sparc person decided to be incompatible, and
21 * used a struct rtc_time different from that used in mc146818rtc.h.
22 */
23
24/* On Sparcs, there is a <asm/rtc.h> that defines different ioctls
25 (that are required on my machine). However, this include file
26 does not exist on other architectures. */
27/* One might do:
28#ifdef __sparc__
29#include <asm/rtc.h>
30#endif
31 */
32/* The following is roughly equivalent */
33struct sparc_rtc_time
34{
35 int sec; /* Seconds (0-59) */
36 int min; /* Minutes (0-59) */
37 int hour; /* Hour (0-23) */
38 int dow; /* Day of the week (1-7) */
39 int dom; /* Day of the month (1-31) */
40 int month; /* Month of year (1-12) */
41 int year; /* Year (0-99) */
42};
43
44#define RTCGET _IOR('p', 20, struct sparc_rtc_time)
45#define RTCSET _IOW('p', 21, struct sparc_rtc_time)
46
47
48/* non-sparc stuff */
49#if 0
50#include <linux/version.h>
51/* Check if the /dev/rtc interface is available in this version of
52 the system headers. 131072 is linux 2.0.0. */
53#if LINUX_VERSION_CODE >= 131072
54#include <linux/mc146818rtc.h>
55#endif
56#endif
57
58/* struct rtc_time is present since 1.3.99 */
59/* Earlier (since 1.3.89), a struct tm was used. */
60struct linux_rtc_time {
61 int tm_sec;
62 int tm_min;
63 int tm_hour;
64 int tm_mday;
65 int tm_mon;
66 int tm_year;
67 int tm_wday;
68 int tm_yday;
69 int tm_isdst;
70};
71
72/* RTC_RD_TIME etc have this definition since 1.99.9 (pre2.0-9) */
73#ifndef RTC_RD_TIME
74#define RTC_RD_TIME _IOR('p', 0x09, struct linux_rtc_time)
75#define RTC_SET_TIME _IOW('p', 0x0a, struct linux_rtc_time)
76#define RTC_UIE_ON _IO('p', 0x03) /* Update int. enable on */
77#define RTC_UIE_OFF _IO('p', 0x04) /* Update int. enable off */
78#endif
79/* RTC_EPOCH_READ and RTC_EPOCH_SET are present since 2.0.34 and 2.1.89 */
80#ifndef RTC_EPOCH_READ
81#define RTC_EPOCH_READ _IOR('p', 0x0d, unsigned long) /* Read epoch */
82#define RTC_EPOCH_SET _IOW('p', 0x0e, unsigned long) /* Set epoch */
83#endif
84
88681c5f
KZ
85/* /dev/rtc is conventionally chardev 10/135
86 * ia64 uses /dev/efirtc, chardev 10/136
87 * devfs (obsolete) used /dev/misc/... for miscdev
88 * new RTC framework + udev uses dynamic major and /dev/rtc0.../dev/rtcN
89 * ... so we need an overridable default
90 */
7eda085c 91
88681c5f
KZ
92/* default or user defined dev (by hwclock --rtc=<path>) */
93char *rtc_dev_name;
364cda48 94
27f9db17
KZ
95static int rtc_dev_fd = -1;
96
97static void
98close_rtc(void) {
99 if (rtc_dev_fd != -1)
100 close(rtc_dev_fd);
101 rtc_dev_fd = -1;
102}
103
364cda48
KZ
104static int
105open_rtc(void) {
88681c5f
KZ
106 char *fls[] = {
107#ifdef __ia64__
108 "/dev/efirtc",
109 "/dev/misc/efirtc",
110#endif
111 "/dev/rtc",
112 "/dev/rtc0",
113 "/dev/misc/rtc",
114 NULL
115 };
5d1f6bae
MK
116 char **p;
117
27f9db17
KZ
118 if (rtc_dev_fd != -1)
119 return rtc_dev_fd;
120
5d1f6bae
MK
121 /* --rtc option has been given */
122 if (rtc_dev_name)
27f9db17
KZ
123 rtc_dev_fd = open(rtc_dev_name, O_RDONLY);
124 else {
125 for (p=fls; *p; ++p) {
126 rtc_dev_fd = open(*p, O_RDONLY);
127
128 if (rtc_dev_fd < 0 && (errno == ENOENT || errno == ENODEV))
129 continue;
130 rtc_dev_name = *p;
131 break;
132 }
133 if (rtc_dev_fd < 0)
134 rtc_dev_name = *fls; /* default for error messages */
5d1f6bae 135 }
27f9db17
KZ
136
137 if (rtc_dev_fd != 1)
138 atexit(close_rtc);
139 return rtc_dev_fd;
63cccae4
KZ
140}
141
142static int
143open_rtc_or_exit(void) {
144 int rtc_fd = open_rtc();
145
146 if (rtc_fd < 0) {
147 outsyserr(_("open() of %s failed"), rtc_dev_name);
88058a71 148 hwclock_exit(EX_OSFILE);
364cda48
KZ
149 }
150 return rtc_fd;
151}
152
7eda085c
KZ
153static int
154do_rtc_read_ioctl(int rtc_fd, struct tm *tm) {
364cda48
KZ
155 int rc = -1;
156 char *ioctlname;
7eda085c 157
7eda085c 158#ifdef __sparc__
364cda48
KZ
159 /* some but not all sparcs use a different ioctl and struct */
160 struct sparc_rtc_time stm;
161
162 ioctlname = "RTCGET";
163 rc = ioctl(rtc_fd, RTCGET, &stm);
164 if (rc == 0) {
165 tm->tm_sec = stm.sec;
166 tm->tm_min = stm.min;
167 tm->tm_hour = stm.hour;
168 tm->tm_mday = stm.dom;
169 tm->tm_mon = stm.month - 1;
170 tm->tm_year = stm.year - 1900;
171 tm->tm_wday = stm.dow - 1;
172 tm->tm_yday = -1; /* day in the year */
173 }
7eda085c 174#endif
364cda48
KZ
175 if (rc == -1) { /* no sparc, or RTCGET failed */
176 ioctlname = "RTC_RD_TIME";
177 rc = ioctl(rtc_fd, RTC_RD_TIME, tm);
178 }
179 if (rc == -1) {
180 perror(ioctlname);
181 fprintf(stderr, _("ioctl() to %s to read the time failed.\n"),
182 rtc_dev_name);
cdedde03 183 return -1;
364cda48
KZ
184 }
185
186 tm->tm_isdst = -1; /* don't know whether it's dst */
187 return 0;
188}
7eda085c
KZ
189
190static int
191busywait_for_rtc_clock_tick(const int rtc_fd) {
192/*----------------------------------------------------------------------------
193 Wait for the top of a clock tick by reading /dev/rtc in a busy loop until
9abb2685 194 we see it.
7eda085c
KZ
195-----------------------------------------------------------------------------*/
196 struct tm start_time;
197 /* The time when we were called (and started waiting) */
198 struct tm nowtime;
7eda085c 199 int rc;
982a4a5d 200 struct timeval begin, now;
7eda085c
KZ
201
202 if (debug)
364cda48
KZ
203 printf(_("Waiting in loop for time from %s to change\n"),
204 rtc_dev_name);
7eda085c
KZ
205
206 rc = do_rtc_read_ioctl(rtc_fd, &start_time);
207 if (rc)
208 return 1;
209
210 /* Wait for change. Should be within a second, but in case something
982a4a5d
KZ
211 * weird happens, we have a time limit (1.5s) on this loop to reduce the
212 * impact of this failure.
213 */
214 gettimeofday(&begin, NULL);
215 do {
216 rc = do_rtc_read_ioctl(rtc_fd, &nowtime);
217 if (rc || start_time.tm_sec != nowtime.tm_sec)
218 break;
219 gettimeofday(&now, NULL);
220 if (time_diff(now, begin) > 1.5) {
7eda085c
KZ
221 fprintf(stderr, _("Timed out waiting for time change.\n"));
222 return 2;
223 }
982a4a5d 224 } while(1);
7eda085c
KZ
225
226 if (rc)
227 return 3;
228 return 0;
229}
230
7eda085c
KZ
231static int
232synchronize_to_clock_tick_rtc(void) {
233/*----------------------------------------------------------------------------
234 Same as synchronize_to_clock_tick(), but just for /dev/rtc.
235-----------------------------------------------------------------------------*/
236int rtc_fd; /* File descriptor of /dev/rtc */
237int ret;
238
27f9db17 239 rtc_fd = open_rtc();
7eda085c 240 if (rtc_fd == -1) {
364cda48 241 outsyserr(_("open() of %s failed"), rtc_dev_name);
7eda085c
KZ
242 ret = 1;
243 } else {
244 int rc; /* Return code from ioctl */
245 /* Turn on update interrupts (one per second) */
442d61c6 246#if defined(__alpha__) || defined(__sparc__)
7eda085c
KZ
247 /* Not all alpha kernels reject RTC_UIE_ON, but probably they should. */
248 rc = -1;
249 errno = EINVAL;
250#else
251 rc = ioctl(rtc_fd, RTC_UIE_ON, 0);
252#endif
63cccae4 253 if (rc == -1 && (errno == ENOTTY || errno == EINVAL)) {
7eda085c
KZ
254 /* This rtc device doesn't have interrupt functions. This is typical
255 on an Alpha, where the Hardware Clock interrupts are used by the
256 kernel for the system clock, so aren't at the user's disposal.
257 */
66ee8158 258 if (debug)
364cda48
KZ
259 printf(_("%s does not have interrupt functions. "),
260 rtc_dev_name);
7eda085c 261 ret = busywait_for_rtc_clock_tick(rtc_fd);
66ee8158 262 } else if (rc == 0) {
d03dd608 263#ifdef Wait_until_update_interrupt
7eda085c
KZ
264 unsigned long dummy;
265
266 /* this blocks until the next update interrupt */
267 rc = read(rtc_fd, &dummy, sizeof(dummy));
d03dd608
KZ
268 ret = 1;
269 if (rc == -1)
364cda48
KZ
270 outsyserr(_("read() to %s to wait for clock tick failed"),
271 rtc_dev_name);
d03dd608 272 else
7eda085c 273 ret = 0;
d03dd608
KZ
274#else
275 /* Just reading rtc_fd fails on broken hardware: no update
276 interrupt comes and a bootscript with a hwclock call hangs */
277 fd_set rfds;
278 struct timeval tv;
279
280 /* Wait up to five seconds for the next update interrupt */
281 FD_ZERO(&rfds);
282 FD_SET(rtc_fd, &rfds);
283 tv.tv_sec = 5;
284 tv.tv_usec = 0;
285 rc = select(rtc_fd + 1, &rfds, NULL, NULL, &tv);
286 ret = 1;
287 if (rc == -1)
288 outsyserr(_("select() to %s to wait for clock tick failed"),
289 rtc_dev_name);
290 else if (rc == 0)
291 fprintf(stderr, _("select() to %s to wait for clock tick timed out\n"),
292 rtc_dev_name);
293 else
294 ret = 0;
295#endif
296
7eda085c
KZ
297 /* Turn off update interrupts */
298 rc = ioctl(rtc_fd, RTC_UIE_OFF, 0);
299 if (rc == -1)
364cda48
KZ
300 outsyserr(_("ioctl() to %s to turn off update interrupts failed"),
301 rtc_dev_name);
7eda085c 302 } else {
66ee8158 303 outsyserr(_("ioctl() to %s to turn on update interrupts "
364cda48 304 "failed unexpectedly"), rtc_dev_name);
7eda085c
KZ
305 ret = 1;
306 }
7eda085c
KZ
307 }
308 return ret;
309}
310
311
312static int
313read_hardware_clock_rtc(struct tm *tm) {
55a4a75c 314 int rtc_fd, rc;
7eda085c 315
63cccae4 316 rtc_fd = open_rtc_or_exit();
7eda085c 317
364cda48 318 /* Read the RTC time/date, return answer via tm */
55a4a75c 319 rc = do_rtc_read_ioctl(rtc_fd, tm);
7eda085c 320
55a4a75c 321 return rc;
7eda085c
KZ
322}
323
324
325static int
326set_hardware_clock_rtc(const struct tm *new_broken_time) {
364cda48 327/*-------------------------------------------------------------------------
7eda085c
KZ
328 Set the Hardware Clock to the broken down time <new_broken_time>.
329 Use ioctls to "rtc" device /dev/rtc.
364cda48
KZ
330 -------------------------------------------------------------------------*/
331 int rc = -1;
332 int rtc_fd;
333 char *ioctlname;
334
63cccae4
KZ
335 rtc_fd = open_rtc_or_exit();
336
7eda085c 337#ifdef __sparc__
364cda48
KZ
338 {
339 struct sparc_rtc_time stm;
340
341 stm.sec = new_broken_time->tm_sec;
342 stm.min = new_broken_time->tm_min;
343 stm.hour = new_broken_time->tm_hour;
344 stm.dom = new_broken_time->tm_mday;
345 stm.month = new_broken_time->tm_mon + 1;
346 stm.year = new_broken_time->tm_year + 1900;
347 stm.dow = new_broken_time->tm_wday + 1;
348
349 ioctlname = "RTCSET";
350 rc = ioctl(rtc_fd, RTCSET, &stm);
351 }
7eda085c 352#endif
364cda48
KZ
353 if (rc == -1) { /* no sparc, or RTCSET failed */
354 ioctlname = "RTC_SET_TIME";
355 rc = ioctl(rtc_fd, RTC_SET_TIME, new_broken_time);
356 }
357
358 if (rc == -1) {
359 perror(ioctlname);
360 fprintf(stderr, _("ioctl() to %s to set the time failed.\n"),
361 rtc_dev_name);
88058a71 362 hwclock_exit(EX_IOERR);
364cda48
KZ
363 }
364
365 if (debug)
366 printf(_("ioctl(%s) was successful.\n"), ioctlname);
367
364cda48 368 return 0;
7eda085c
KZ
369}
370
371
372static int
373get_permissions_rtc(void) {
374 return 0;
375}
376
377static struct clock_ops rtc = {
88681c5f 378 "/dev interface to clock",
7eda085c
KZ
379 get_permissions_rtc,
380 read_hardware_clock_rtc,
381 set_hardware_clock_rtc,
382 synchronize_to_clock_tick_rtc,
383};
384
385/* return &rtc if /dev/rtc can be opened, NULL otherwise */
386struct clock_ops *
387probe_for_rtc_clock(){
364cda48 388 int rtc_fd = open_rtc();
27f9db17 389 if (rtc_fd >= 0)
364cda48 390 return &rtc;
364cda48
KZ
391 if (debug)
392 outsyserr(_("Open of %s failed"), rtc_dev_name);
393 return NULL;
7eda085c
KZ
394}
395
396
397
398int
399get_epoch_rtc(unsigned long *epoch_p, int silent) {
400/*----------------------------------------------------------------------------
401 Get the Hardware Clock epoch setting from the kernel.
402----------------------------------------------------------------------------*/
403 int rtc_fd;
404
364cda48 405 rtc_fd = open_rtc();
7eda085c
KZ
406 if (rtc_fd < 0) {
407 if (!silent) {
9abb2685 408 if (errno == ENOENT)
7eda085c
KZ
409 fprintf(stderr, _(
410 "To manipulate the epoch value in the kernel, we must "
411 "access the Linux 'rtc' device driver via the device special "
364cda48
KZ
412 "file %s. This file does not exist on this system.\n"),
413 rtc_dev_name);
9abb2685 414 else
364cda48 415 outsyserr(_("Unable to open %s"), rtc_dev_name);
7eda085c
KZ
416 }
417 return 1;
418 }
419
420 if (ioctl(rtc_fd, RTC_EPOCH_READ, epoch_p) == -1) {
421 if (!silent)
364cda48 422 outsyserr(_("ioctl(RTC_EPOCH_READ) to %s failed"), rtc_dev_name);
7eda085c
KZ
423 return 1;
424 }
425
426 if (debug)
66ee8158 427 printf(_("we have read epoch %ld from %s "
364cda48 428 "with RTC_EPOCH_READ ioctl.\n"), *epoch_p, rtc_dev_name);
7eda085c 429
7eda085c
KZ
430 return 0;
431}
432
433
434
435int
436set_epoch_rtc(unsigned long epoch) {
437/*----------------------------------------------------------------------------
438 Set the Hardware Clock epoch in the kernel.
439----------------------------------------------------------------------------*/
440 int rtc_fd;
441
442 if (epoch < 1900) {
443 /* kernel would not accept this epoch value */
444 /* Hmm - bad habit, deciding not to do what the user asks
445 just because one believes that the kernel might not like it. */
446 fprintf(stderr, _("The epoch value may not be less than 1900. "
447 "You requested %ld\n"), epoch);
448 return 1;
449 }
450
364cda48 451 rtc_fd = open_rtc();
7eda085c 452 if (rtc_fd < 0) {
9abb2685 453 if (errno == ENOENT)
7eda085c
KZ
454 fprintf(stderr, _("To manipulate the epoch value in the kernel, we must "
455 "access the Linux 'rtc' device driver via the device special "
364cda48
KZ
456 "file %s. This file does not exist on this system.\n"),
457 rtc_dev_name);
7eda085c 458 else
364cda48 459 outsyserr(_("Unable to open %s"), rtc_dev_name);
7eda085c
KZ
460 return 1;
461 }
462
463 if (debug)
464 printf(_("setting epoch to %ld "
364cda48 465 "with RTC_EPOCH_SET ioctl to %s.\n"), epoch, rtc_dev_name);
7eda085c
KZ
466
467 if (ioctl(rtc_fd, RTC_EPOCH_SET, epoch) == -1) {
468 if (errno == EINVAL)
66ee8158 469 fprintf(stderr, _("The kernel device driver for %s "
364cda48 470 "does not have the RTC_EPOCH_SET ioctl.\n"), rtc_dev_name);
9abb2685 471 else
364cda48 472 outsyserr(_("ioctl(RTC_EPOCH_SET) to %s failed"), rtc_dev_name);
7eda085c
KZ
473 return 1;
474 }
475
7eda085c
KZ
476 return 0;
477}