aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2020-12-16 13:49:10 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2020-12-16 14:00:47 +0100
commit9e262f13c2e53490d69d3112ffd718c27de04d1f (patch)
tree0022d9f686beb5e4d7bfa7aa2a30513443ca7856
parenta97a795dcb41943943b8ecfe039e23673365af55 (diff)
downloadbusybox-w32-9e262f13c2e53490d69d3112ffd718c27de04d1f.tar.gz
busybox-w32-9e262f13c2e53490d69d3112ffd718c27de04d1f.tar.bz2
busybox-w32-9e262f13c2e53490d69d3112ffd718c27de04d1f.zip
hwclock: fix musl breakage of settimeofday(tz)
function old new delta set_kernel_timezone_and_clock - 119 +119 set_kernel_tz - 28 +28 hwclock_main 480 301 -179 ------------------------------------------------------------------------------ (add/remove: 2/0 grow/shrink: 0/1 up/down: 147/-179) Total: -32 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--util-linux/hwclock.c128
1 files changed, 75 insertions, 53 deletions
diff --git a/util-linux/hwclock.c b/util-linux/hwclock.c
index 791525fc2..44cb4794e 100644
--- a/util-linux/hwclock.c
+++ b/util-linux/hwclock.c
@@ -36,6 +36,19 @@
36#include <sys/utsname.h> 36#include <sys/utsname.h>
37#include "rtc_.h" 37#include "rtc_.h"
38 38
39
40//musl has no __MUSL__ or similar define to check for,
41//but its <sys/types.h> has these lines:
42// #define __NEED_fsblkcnt_t
43// #define __NEED_fsfilcnt_t
44#if defined(__linux__) && defined(__NEED_fsblkcnt_t) && defined(__NEED_fsfilcnt_t)
45# define LIBC_IS_MUSL 1
46# include <sys/syscall.h>
47#else
48# define LIBC_IS_MUSL 0
49#endif
50
51
39/* diff code is disabled: it's not sys/hw clock diff, it's some useless 52/* diff code is disabled: it's not sys/hw clock diff, it's some useless
40 * "time between hwclock was started and we saw CMOS tick" quantity. 53 * "time between hwclock was started and we saw CMOS tick" quantity.
41 * It's useless since hwclock is started at a random moment, 54 * It's useless since hwclock is started at a random moment,
@@ -116,26 +129,73 @@ static void show_clock(const char **pp_rtcname, int utc)
116#endif 129#endif
117} 130}
118 131
119static void to_sys_clock(const char **pp_rtcname, int utc) 132static void set_kernel_tz(const struct timezone *tz)
120{ 133{
121 struct timeval tv; 134#if LIBC_IS_MUSL
122 struct timezone tz; 135 /* musl libc does not pass tz argument to syscall
123 136 * because "it's deprecated by POSIX, therefore it's fine
124 tz.tz_minuteswest = timezone / 60; 137 * if we gratuitously break stuff" :(
125 /* ^^^ used to also subtract 60*daylight, but it's wrong:
126 * daylight!=0 means "this timezone has some DST
127 * during the year", not "DST is in effect now".
128 */ 138 */
129 tz.tz_dsttime = 0; 139#if !defined(SYS_settimeofday) && defined(SYS_settimeofday_time32)
130 140# define SYS_settimeofday SYS_settimeofday_time32
131 /* glibc v2.31+ returns an error if both args are non-NULL */ 141#endif
132 if (settimeofday(NULL, &tz)) 142 int ret = syscall(SYS_settimeofday, NULL, tz);
143#else
144 int ret = settimeofday(NULL, tz);
145#endif
146 if (ret)
133 bb_simple_perror_msg_and_die("settimeofday"); 147 bb_simple_perror_msg_and_die("settimeofday");
148}
149
150/*
151 * At system boot, kernel may set system time from RTC,
152 * but it knows nothing about timezones. If RTC is in local time,
153 * then system time is wrong - it is offset by timezone.
154 * --systz option corrects system time if RTC is in local time,
155 * and (always) sets in-kernel timezone.
156 *
157 * This is an alternate option to --hctosys that does not read the
158 * hardware clock.
159 *
160 * util-linux's code has this comment:
161 * RTC | settimeofday calls
162 * ------|-------------------------------------------------
163 * Local | 1) warps system time*, sets PCIL* and kernel tz
164 * UTC | 1st) locks warp_clock 2nd) sets kernel tz
165 * * only on first call after boot
166 * (PCIL is "persistent_clock_is_local" kernel internal flag,
167 * it makes kernel save RTC in local time, not UTC.)
168 */
169static void set_kernel_timezone_and_clock(int utc, const struct timeval *hctosys)
170{
171 time_t cur;
172 struct tm *broken;
173 struct timezone tz = { 0 };
174
175 /* if --utc, prevent kernel's warp_clock() with a dummy call */
176 if (utc)
177 set_kernel_tz(&tz);
178
179 /* Set kernel's timezone offset based on userspace one */
180 cur = time(NULL);
181 broken = localtime(&cur);
182 tz.tz_minuteswest = -broken->tm_gmtoff / 60;
183 /*tz.tz_dsttime = 0; already is */
184 set_kernel_tz(&tz); /* MIGHT warp_clock() if 1st call since boot */
185
186 if (hctosys) { /* it's --hctosys: set time too */
187 if (settimeofday(hctosys, NULL))
188 bb_simple_perror_msg_and_die("settimeofday");
189 }
190}
191
192static void to_sys_clock(const char **pp_rtcname, int utc)
193{
194 struct timeval tv;
134 195
135 tv.tv_sec = read_rtc(pp_rtcname, NULL, utc); 196 tv.tv_sec = read_rtc(pp_rtcname, NULL, utc);
136 tv.tv_usec = 0; 197 tv.tv_usec = 0;
137 if (settimeofday(&tv, NULL)) 198 return set_kernel_timezone_and_clock(utc, &tv);
138 bb_simple_perror_msg_and_die("settimeofday");
139} 199}
140 200
141static void from_sys_clock(const char **pp_rtcname, int utc) 201static void from_sys_clock(const char **pp_rtcname, int utc)
@@ -261,39 +321,6 @@ static void from_sys_clock(const char **pp_rtcname, int utc)
261 close(rtc); 321 close(rtc);
262} 322}
263 323
264/*
265 * At system boot, kernel may set system time from RTC,
266 * but it knows nothing about timezones. If RTC is in local time,
267 * then system time is wrong - it is offset by timezone.
268 * This option corrects system time if RTC is in local time,
269 * and (always) sets in-kernel timezone.
270 *
271 * This is an alternate option to --hctosys that does not read the
272 * hardware clock.
273 */
274static void set_system_clock_timezone(int utc)
275{
276 struct timeval tv;
277 struct tm *broken;
278 struct timezone tz;
279
280 gettimeofday(&tv, NULL);
281 broken = localtime(&tv.tv_sec);
282 tz.tz_minuteswest = timezone / 60;
283 if (broken->tm_isdst > 0)
284 tz.tz_minuteswest -= 60;
285 tz.tz_dsttime = 0;
286 gettimeofday(&tv, NULL);
287 if (!utc)
288 tv.tv_sec += tz.tz_minuteswest * 60;
289
290 /* glibc v2.31+ returns an error if both args are non-NULL */
291 if (settimeofday(NULL, &tz))
292 bb_simple_perror_msg_and_die("settimeofday");
293 if (settimeofday(&tv, NULL))
294 bb_simple_perror_msg_and_die("settimeofday");
295}
296
297//usage:#define hwclock_trivial_usage 324//usage:#define hwclock_trivial_usage
298//usage: IF_LONG_OPTS( 325//usage: IF_LONG_OPTS(
299//usage: "[-swu] [--systz] [--localtime] [-f FILE]" 326//usage: "[-swu] [--systz] [--localtime] [-f FILE]"
@@ -333,7 +360,6 @@ int hwclock_main(int argc UNUSED_PARAM, char **argv)
333 const char *rtcname = NULL; 360 const char *rtcname = NULL;
334 unsigned opt; 361 unsigned opt;
335 int utc; 362 int utc;
336
337#if ENABLE_LONG_OPTS 363#if ENABLE_LONG_OPTS
338 static const char hwclock_longopts[] ALIGN1 = 364 static const char hwclock_longopts[] ALIGN1 =
339 "localtime\0" No_argument "l" /* short opt is non-standard */ 365 "localtime\0" No_argument "l" /* short opt is non-standard */
@@ -345,10 +371,6 @@ int hwclock_main(int argc UNUSED_PARAM, char **argv)
345 "rtc\0" Required_argument "f" 371 "rtc\0" Required_argument "f"
346 ; 372 ;
347#endif 373#endif
348
349 /* Initialize "timezone" (libc global variable) */
350 tzset();
351
352 opt = getopt32long(argv, 374 opt = getopt32long(argv,
353 "^lurswtf:" "\0" "r--wst:w--rst:s--wrt:t--rsw:l--u:u--l", 375 "^lurswtf:" "\0" "r--wst:w--rst:s--wrt:t--rsw:l--u:u--l",
354 hwclock_longopts, 376 hwclock_longopts,
@@ -366,7 +388,7 @@ int hwclock_main(int argc UNUSED_PARAM, char **argv)
366 else if (opt & HWCLOCK_OPT_SYSTOHC) 388 else if (opt & HWCLOCK_OPT_SYSTOHC)
367 from_sys_clock(&rtcname, utc); 389 from_sys_clock(&rtcname, utc);
368 else if (opt & HWCLOCK_OPT_SYSTZ) 390 else if (opt & HWCLOCK_OPT_SYSTZ)
369 set_system_clock_timezone(utc); 391 set_kernel_timezone_and_clock(utc, NULL);
370 else 392 else
371 /* default HWCLOCK_OPT_SHOW */ 393 /* default HWCLOCK_OPT_SHOW */
372 show_clock(&rtcname, utc); 394 show_clock(&rtcname, utc);