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