*
* Copyright (C) 2002 Robert Griebl <griebl@gmx.de>
*
- * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
*/
#include "libbb.h"
#include <sys/utsname.h>
#include "rtc_.h"
-#if ENABLE_FEATURE_HWCLOCK_LONG_OPTIONS
-# ifndef _GNU_SOURCE
-# define _GNU_SOURCE
-# endif
-#endif
-
-
/* diff code is disabled: it's not sys/hw clock diff, it's some useless
* "time between hwclock was started and we saw CMOS tick" quantity.
* It's useless since hwclock is started at a random moment,
while (1) {
rtc_read_tm(&tm_time, fd);
gettimeofday(sys_tv, NULL);
- if (before != tm_time.tm_sec)
+ if (before != (int)tm_time.tm_sec)
break;
}
}
#if SHOW_HWCLOCK_DIFF
struct timeval sys_tv;
#endif
- time_t t;
- char *cp;
+ time_t t = read_rtc(pp_rtcname, &sys_tv, utc);
- t = read_rtc(pp_rtcname, &sys_tv, utc);
- cp = ctime(&t);
+#if ENABLE_LOCALE_SUPPORT
+ /* Standard hwclock uses locale-specific output format */
+ char cp[64];
+ struct tm *ptm = localtime(&t);
+ strftime(cp, sizeof(cp), "%c", ptm);
+#else
+ char *cp = ctime(&t);
strchrnul(cp, '\n')[0] = '\0';
+#endif
+
#if !SHOW_HWCLOCK_DIFF
printf("%s 0.000000 seconds\n", cp);
#else
{
long diff = sys_tv.tv_sec - t;
if (diff < 0 /*&& tv.tv_usec != 0*/) {
- /* Why? */
- /* diff >= 0 is ok: diff < 0, can't just use tv.tv_usec: */
- /* 45.520820 43.520820 */
- /* - 44.000000 - 45.000000 */
- /* = 1.520820 = -1.479180, not -2.520820! */
+ /* Why we need diff++? */
+ /* diff >= 0 is ok: | diff < 0, can't just use tv.tv_usec: */
+ /* 45.520820 | 43.520820 */
+ /* - 44.000000 | - 45.000000 */
+ /* = 1.520820 | = -1.479180, not -2.520820! */
diff++;
- /* should be 1000000 - tv.tv_usec, but then we must check tv.tv_usec != 0 */
+ /* Should be 1000000 - tv.tv_usec, but then we must check tv.tv_usec != 0 */
sys_tv.tv_usec = 999999 - sys_tv.tv_usec;
}
printf("%s %ld.%06lu seconds\n", cp, diff, (unsigned long)sys_tv.tv_usec);
close(rtc);
}
+/*
+ * At system boot, kernel may set system time from RTC,
+ * but it knows nothing about timezones. If RTC is in local time,
+ * then system time is wrong - it is offset by timezone.
+ * This option corrects system time if RTC is in local time,
+ * and (always) sets in-kernel timezone.
+ *
+ * This is an alternate option to --hctosys that does not read the
+ * hardware clock.
+ */
+static void set_system_clock_timezone(int utc)
+{
+ struct timeval tv;
+ struct tm *broken;
+ struct timezone tz;
+
+ gettimeofday(&tv, NULL);
+ broken = localtime(&tv.tv_sec);
+ tz.tz_minuteswest = timezone / 60;
+ if (broken->tm_isdst)
+ tz.tz_minuteswest -= 60;
+ tz.tz_dsttime = 0;
+ gettimeofday(&tv, NULL);
+ if (!utc)
+ tv.tv_sec += tz.tz_minuteswest * 60;
+ if (settimeofday(&tv, &tz))
+ bb_perror_msg_and_die("settimeofday");
+}
+
+//usage:#define hwclock_trivial_usage
+//usage: IF_FEATURE_HWCLOCK_LONG_OPTIONS(
+//usage: "[-r|--show] [-s|--hctosys] [-w|--systohc] [-t|--systz]"
+//usage: " [-l|--localtime] [-u|--utc]"
+//usage: " [-f|--rtc FILE]"
+//usage: )
+//usage: IF_NOT_FEATURE_HWCLOCK_LONG_OPTIONS(
+//usage: "[-r] [-s] [-w] [-t] [-l] [-u] [-f FILE]"
+//usage: )
+//usage:#define hwclock_full_usage "\n\n"
+//usage: "Query and set hardware clock (RTC)\n"
+//usage: "\n -r Show hardware clock time"
+//usage: "\n -s Set system time from hardware clock"
+//usage: "\n -w Set hardware clock from system time"
+//usage: "\n -t Set in-kernel timezone, correct system time"
+//usage: "\n if hardware clock is in local time"
+//usage: "\n -u Assume hardware clock is kept in UTC"
+//usage: "\n -l Assume hardware clock is kept in local time"
+//usage: "\n -f FILE Use specified device (e.g. /dev/rtc2)"
+
#define HWCLOCK_OPT_LOCALTIME 0x01
#define HWCLOCK_OPT_UTC 0x02
#define HWCLOCK_OPT_SHOW 0x04
#define HWCLOCK_OPT_HCTOSYS 0x08
#define HWCLOCK_OPT_SYSTOHC 0x10
-#define HWCLOCK_OPT_RTCFILE 0x20
+#define HWCLOCK_OPT_SYSTZ 0x20
+#define HWCLOCK_OPT_RTCFILE 0x40
int hwclock_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int hwclock_main(int argc UNUSED_PARAM, char **argv)
#if ENABLE_FEATURE_HWCLOCK_LONG_OPTIONS
static const char hwclock_longopts[] ALIGN1 =
- "localtime\0" No_argument "l"
+ "localtime\0" No_argument "l" /* short opt is non-standard */
"utc\0" No_argument "u"
"show\0" No_argument "r"
"hctosys\0" No_argument "s"
"systohc\0" No_argument "w"
- "file\0" Required_argument "f"
+ "systz\0" No_argument "t" /* short opt is non-standard */
+ "rtc\0" Required_argument "f"
;
applet_long_options = hwclock_longopts;
#endif
- opt_complementary = "r--ws:w--rs:s--wr:l--u:u--l";
- opt = getopt32(argv, "lurswf:", &rtcname);
+ opt_complementary = "r--wst:w--rst:s--wrt:t--rsw:l--u:u--l";
+ opt = getopt32(argv, "lurswtf:", &rtcname);
/* If -u or -l wasn't given check if we are using utc */
if (opt & (HWCLOCK_OPT_UTC | HWCLOCK_OPT_LOCALTIME))
to_sys_clock(&rtcname, utc);
else if (opt & HWCLOCK_OPT_SYSTOHC)
from_sys_clock(&rtcname, utc);
+ else if (opt & HWCLOCK_OPT_SYSTZ)
+ set_system_clock_timezone(utc);
else
/* default HWCLOCK_OPT_SHOW */
show_clock(&rtcname, utc);