blob: 412995cb17b43acad8d611d0d12798d0705fec48 [file] [log] [blame]
Robert Griebl1cd04452002-07-21 16:50:49 +00001/* vi: set sw=4 ts=4: */
2/*
Robert Griebl6859d762002-08-05 02:57:12 +00003 * Mini hwclock implementation for busybox
4 *
Robert Griebl1cd04452002-07-21 16:50:49 +00005 * Copyright (C) 2002 Robert Griebl <griebl@gmx.de>
6 *
Robert Griebl6859d762002-08-05 02:57:12 +00007 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21*/
Robert Griebl1cd04452002-07-21 16:50:49 +000022
23
24#include <sys/utsname.h>
25#include <stdlib.h>
26#include <unistd.h>
27#include <syslog.h>
28#include <string.h>
29#include <ctype.h>
30#include <fcntl.h>
31#include <sys/time.h>
32#include <time.h>
33#include <linux/rtc.h>
34#include <sys/ioctl.h>
35#include "busybox.h"
36
37#ifdef CONFIG_FEATURE_HWCLOCK_LONGOPTIONS
38# ifndef _GNU_SOURCE
39# define _GNU_SOURCE
40# endif
41#endif
42
43#include <getopt.h>
44
45
46enum OpMode {
47 SHOW,
48 SYSTOHC,
49 HCTOSYS
50};
51
52
53time_t read_rtc ( int utc )
54{
55 int rtc;
56 struct tm tm;
57 char *oldtz = 0;
58 time_t t = 0;
59
60 if (( rtc = open ( "/dev/rtc", O_RDONLY )) < 0 ) {
61 if (( rtc = open ( "/dev/misc/rtc", O_RDONLY )) < 0 )
62 perror_msg_and_die ( "Could not access RTC" );
63 }
64 memset ( &tm, 0, sizeof( struct tm ));
65 if ( ioctl ( rtc, RTC_RD_TIME, &tm ) < 0 )
66 perror_msg_and_die ( "Could not read time from RTC" );
67 tm. tm_isdst = -1; // not known
68
69 close ( rtc );
70
71 if ( utc ) {
72 oldtz = getenv ( "TZ" );
73 setenv ( "TZ", "UTC 0", 1 );
74 tzset ( );
75 }
76
77 t = mktime ( &tm );
78
79 if ( utc ) {
80 if ( oldtz )
81 setenv ( "TZ", oldtz, 1 );
82 else
83 unsetenv ( "TZ" );
84 tzset ( );
85 }
86 return t;
87}
88
89void write_rtc ( time_t t, int utc )
90{
91 int rtc;
92 struct tm tm;
93
94 if (( rtc = open ( "/dev/rtc", O_WRONLY )) < 0 ) {
95 if (( rtc = open ( "/dev/misc/rtc", O_WRONLY )) < 0 )
96 perror_msg_and_die ( "Could not access RTC" );
97 }
98
99 printf ( "1\n" );
100
101 tm = *( utc ? gmtime ( &t ) : localtime ( &t ));
102 tm. tm_isdst = 0;
103
104 printf ( "2\n") ;
105
106 if ( ioctl ( rtc, RTC_SET_TIME, &tm ) < 0 )
107 perror_msg_and_die ( "Could not set the RTC time" );
108
109 close ( rtc );
110}
111
112int show_clock ( int utc )
113{
114 struct tm *ptm;
115 time_t t;
116 char buffer [64];
117
118 t = read_rtc ( utc );
119 ptm = localtime ( &t ); /* Sets 'tzname[]' */
120
121 safe_strncpy ( buffer, ctime ( &t ), sizeof( buffer ));
122 if ( buffer [0] )
123 buffer [xstrlen ( buffer ) - 1] = 0;
124
125 //printf ( "%s %.6f seconds %s\n", buffer, 0.0, utc ? "" : ( ptm-> tm_isdst ? tzname [1] : tzname [0] ));
126 printf ( "%s %.6f seconds\n", buffer, 0.0 );
127
128 return 0;
129}
130
131int to_sys_clock ( int utc )
132{
133 struct timeval tv = { 0, 0 };
134 const struct timezone tz = { timezone/60 - 60*daylight, 0 };
135
136 tv. tv_sec = read_rtc ( utc );
137
138 if ( settimeofday ( &tv, &tz ))
139 perror_msg_and_die ( "settimeofday() failed" );
140
141 return 0;
142}
143
144int from_sys_clock ( int utc )
145{
146 struct timeval tv = { 0, 0 };
147 struct timezone tz = { 0, 0 };
148
149 if ( gettimeofday ( &tv, &tz ))
150 perror_msg_and_die ( "gettimeofday() failed" );
151
152 write_rtc ( tv. tv_sec, utc );
153 return 0;
154}
155
156
157int check_utc ( void )
158{
159 int utc = 0;
160 FILE *f = fopen ( "/etc/adjtime", "r" );
161
162 if ( f ) {
163 char buffer [128];
164
165 while ( fgets ( buffer, sizeof( buffer ), f )) {
166 int len = xstrlen ( buffer );
167
168 while ( len && isspace ( buffer [len - 1] ))
169 len--;
170
171 buffer [len] = 0;
172
173 if ( strncmp ( buffer, "UTC", 3 ) == 0 ) {
174 utc = 1;
175 break;
176 }
177 }
178 fclose ( f );
179 }
180 return utc;
181}
182
183extern int hwclock_main ( int argc, char **argv )
184{
185 int opt;
186 enum OpMode mode = SHOW;
187 int utc = 0;
188 int utc_arg = 0;
189
190#ifdef CONFIG_FEATURE_HWCLOCK_LONGOPTIONS
191 struct option long_options[] = {
192 { "show", 0, 0, 'r' },
193 { "utc", 0, 0, 'u' },
194 { "localtime", 0, 0, 'l' },
195 { "hctosys", 0, 0, 's' },
196 { "systohc", 0, 0, 'w' },
197 { 0, 0, 0, 0 }
198 };
199
200 while (( opt = getopt_long ( argc, argv, "rwsul", long_options, 0 )) != EOF ) {
201#else
202 while (( opt = getopt ( argc, argv, "rwsul" )) != EOF ) {
203#endif
204 switch ( opt ) {
205 case 'r':
206 mode = SHOW;
207 break;
208 case 'w':
209 mode = SYSTOHC;
210 break;
211 case 's':
212 mode = HCTOSYS;
213 break;
214 case 'u':
215 utc = 1;
216 utc_arg = 1;
217 break;
218 case 'l': // -l is not supported by the normal hwclock (only --localtime)
219 utc = 0;
220 utc_arg = 1;
221 break;
222 default:
223 show_usage();
224 break;
225 }
226 }
227
228 if ( !utc_arg )
229 utc = check_utc ( );
230
231 switch ( mode ) {
232 case SYSTOHC:
233 return from_sys_clock ( utc );
234
235 case HCTOSYS:
236 return to_sys_clock ( utc );
237
238 case SHOW:
239 default:
240 return show_clock ( utc );
241 }
242}
243
244