1 /* vi: set sw=4 ts=4: */
3 * Mini hwclock implementation for busybox
5 * Copyright (C) 2002 Robert Griebl <griebl@gmx.de>
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
11 #include <sys/ioctl.h>
13 #include <sys/utsname.h>
24 /* Copied from linux/rtc.h to eliminate the kernel dependency */
25 struct linux_rtc_time {
37 #define RTC_SET_TIME _IOW('p', 0x0a, struct linux_rtc_time) /* Set RTC time */
38 #define RTC_RD_TIME _IOR('p', 0x09, struct linux_rtc_time) /* Read RTC time */
40 #ifdef CONFIG_FEATURE_HWCLOCK_LONGOPTIONS
46 static time_t read_rtc(int utc)
53 if (( rtc = open ( "/dev/rtc", O_RDONLY )) < 0 ) {
54 if (( rtc = open ( "/dev/misc/rtc", O_RDONLY )) < 0 )
55 bb_perror_msg_and_die ( "Could not access RTC" );
57 memset ( &tm, 0, sizeof( struct tm ));
58 if ( ioctl ( rtc, RTC_RD_TIME, &tm ) < 0 )
59 bb_perror_msg_and_die ( "Could not read time from RTC" );
60 tm.tm_isdst = -1; /* not known */
65 oldtz = getenv ( "TZ" );
66 setenv ( "TZ", "UTC 0", 1 );
74 setenv ( "TZ", oldtz, 1 );
82 static void write_rtc(time_t t, int utc)
87 if (( rtc = open ( "/dev/rtc", O_WRONLY )) < 0 ) {
88 if (( rtc = open ( "/dev/misc/rtc", O_WRONLY )) < 0 )
89 bb_perror_msg_and_die ( "Could not access RTC" );
92 tm = *( utc ? gmtime ( &t ) : localtime ( &t ));
95 if ( ioctl ( rtc, RTC_SET_TIME, &tm ) < 0 )
96 bb_perror_msg_and_die ( "Could not set the RTC time" );
101 static int show_clock(int utc)
105 RESERVE_CONFIG_BUFFER(buffer, 64);
107 t = read_rtc ( utc );
108 ptm = localtime ( &t ); /* Sets 'tzname[]' */
110 safe_strncpy ( buffer, ctime ( &t ), 64);
112 buffer [bb_strlen ( buffer ) - 1] = 0;
114 //printf ( "%s %.6f seconds %s\n", buffer, 0.0, utc ? "" : ( ptm-> tm_isdst ? tzname [1] : tzname [0] ));
115 printf ( "%s %.6f seconds\n", buffer, 0.0 );
116 RELEASE_CONFIG_BUFFER(buffer);
121 static int to_sys_clock(int utc)
123 struct timeval tv = { 0, 0 };
124 const struct timezone tz = { timezone/60 - 60*daylight, 0 };
126 tv.tv_sec = read_rtc ( utc );
128 if ( settimeofday ( &tv, &tz ))
129 bb_perror_msg_and_die ( "settimeofday() failed" );
134 static int from_sys_clock(int utc)
136 struct timeval tv = { 0, 0 };
137 struct timezone tz = { 0, 0 };
139 if ( gettimeofday ( &tv, &tz ))
140 bb_perror_msg_and_die ( "gettimeofday() failed" );
142 write_rtc ( tv.tv_sec, utc );
146 #ifdef CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS
147 # define ADJTIME_PATH "/var/lib/hwclock/adjtime"
149 # define ADJTIME_PATH "/etc/adjtime"
151 static int check_utc(void)
154 FILE *f = fopen ( ADJTIME_PATH, "r" );
157 RESERVE_CONFIG_BUFFER(buffer, 128);
159 while ( fgets ( buffer, sizeof( buffer ), f )) {
160 int len = bb_strlen ( buffer );
162 while ( len && isspace ( buffer [len - 1] ))
167 if ( strncmp ( buffer, "UTC", 3 ) == 0 ) {
173 RELEASE_CONFIG_BUFFER(buffer);
178 #define HWCLOCK_OPT_LOCALTIME 0x01
179 #define HWCLOCK_OPT_UTC 0x02
180 #define HWCLOCK_OPT_SHOW 0x04
181 #define HWCLOCK_OPT_HCTOSYS 0x08
182 #define HWCLOCK_OPT_SYSTOHC 0x10
184 int hwclock_main ( int argc, char **argv )
189 #ifdef CONFIG_FEATURE_HWCLOCK_LONGOPTIONS
190 static const struct option hwclock_long_options[] = {
191 { "localtime", 0, 0, 'l' },
192 { "utc", 0, 0, 'u' },
193 { "show", 0, 0, 'r' },
194 { "hctosys", 0, 0, 's' },
195 { "systohc", 0, 0, 'w' },
198 bb_applet_long_options = hwclock_long_options;
201 bb_opt_complementally = "?:r--ws:w--rs:s--wr:l--u:u--l";
202 opt = bb_getopt_ulflags(argc, argv, "lursw");
204 /* If -u or -l wasn't given check if we are using utc */
205 if (opt & (HWCLOCK_OPT_UTC | HWCLOCK_OPT_LOCALTIME))
206 utc = opt & HWCLOCK_OPT_UTC;
210 if (opt & HWCLOCK_OPT_HCTOSYS) {
211 return to_sys_clock ( utc );
213 else if (opt & HWCLOCK_OPT_SYSTOHC) {
214 return from_sys_clock ( utc );
216 /* default HWCLOCK_OPT_SHOW */
217 return show_clock ( utc );