1 /*
2 * Common RTC functions
3 *
4 * Licensed under GPLv2, see file LICENSE in this source tree.
5 */
6
7 #include "libbb.h"
8 #include "rtc_.h"
9
rtc_adjtime_is_utc(void)10 int FAST_FUNC rtc_adjtime_is_utc(void)
11 {
12 int utc = 0;
13 FILE *f = fopen_for_read(ADJTIME_PATH);
14
15 if (f) {
16 char buffer[128];
17
18 while (fgets(buffer, sizeof(buffer), f)) {
19 if (is_prefixed_with(buffer, "UTC")) {
20 utc = 1;
21 break;
22 }
23 }
24 fclose(f);
25 }
26
27 return utc;
28 }
29
30 /* rtc opens are exclusive.
31 * Try to run two "hwclock -w" at the same time to see it.
32 * Users wouldn't expect that to fail merely because /dev/rtc
33 * was momentarily busy, let's try a bit harder on errno == EBUSY.
34 */
open_loop_on_busy(const char * name,int flags)35 static int open_loop_on_busy(const char *name, int flags)
36 {
37 int rtc;
38 /*
39 * Tested with two parallel "hwclock -w" loops.
40 * With try = 10, no failures with 2x1000000 loop iterations.
41 */
42 int try = 1000 / 20;
43 again:
44 errno = 0;
45 rtc = open(name, flags);
46 if (errno == EBUSY) {
47 usleep(20 * 1000);
48 if (--try != 0)
49 goto again;
50 /* EBUSY. Last try, exit on error instead of returning -1 */
51 return xopen(name, flags);
52 }
53 return rtc;
54 }
55
56 /* Never fails */
rtc_xopen(const char ** default_rtc,int flags)57 int FAST_FUNC rtc_xopen(const char **default_rtc, int flags)
58 {
59 int rtc;
60 const char *name =
61 "/dev/rtc""\0"
62 "/dev/rtc0""\0"
63 "/dev/misc/rtc""\0";
64
65 if (!*default_rtc)
66 goto try_name;
67 name = ""; /*else: we have rtc name, don't try other names */
68
69 for (;;) {
70 rtc = open_loop_on_busy(*default_rtc, flags);
71 if (rtc >= 0)
72 return rtc;
73 if (!name[0])
74 return xopen(*default_rtc, flags);
75 try_name:
76 *default_rtc = name;
77 name += strlen(name) + 1;
78 }
79 }
80
rtc_read_tm(struct tm * ptm,int fd)81 void FAST_FUNC rtc_read_tm(struct tm *ptm, int fd)
82 {
83 memset(ptm, 0, sizeof(*ptm));
84 xioctl(fd, RTC_RD_TIME, ptm);
85 ptm->tm_isdst = -1; /* "not known" */
86 }
87
rtc_tm2time(struct tm * ptm,int utc)88 time_t FAST_FUNC rtc_tm2time(struct tm *ptm, int utc)
89 {
90 char *oldtz = oldtz; /* for compiler */
91 time_t t;
92
93 if (utc) {
94 oldtz = getenv("TZ");
95 putenv((char*)"TZ=UTC0");
96 tzset();
97 }
98
99 t = mktime(ptm);
100
101 if (utc) {
102 unsetenv("TZ");
103 if (oldtz)
104 putenv(oldtz - 3);
105 tzset();
106 }
107
108 return t;
109 }
110