> Eliminate dependancy on kernel header files. Naughty naughty.
[platform/upstream/busybox.git] / util-linux / hwclock.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * Mini hwclock implementation for busybox
4  *
5  * Copyright (C) 2002 Robert Griebl <griebl@gmx.de>
6  *
7  * 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 */
22
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 <sys/ioctl.h>
34 #include "busybox.h"
35
36
37 /* Copied from linux/rtc.h to eliminate the kernel dependancy */
38 struct linux_rtc_time {
39         int tm_sec;
40         int tm_min;
41         int tm_hour;
42         int tm_mday;
43         int tm_mon;
44         int tm_year;
45         int tm_wday;
46         int tm_yday;
47         int tm_isdst;
48 };
49                                     
50
51 #define RTC_SET_TIME   _IOW('p', 0x0a, struct linux_rtc_time) /* Set RTC time    */
52 #define RTC_RD_TIME    _IOR('p', 0x09, struct linux_rtc_time) /* Read RTC time   */
53
54
55 #ifdef CONFIG_FEATURE_HWCLOCK_LONGOPTIONS
56 # ifndef _GNU_SOURCE
57 #  define _GNU_SOURCE
58 # endif
59 #endif
60
61 #include <getopt.h>
62
63
64 enum OpMode {
65         SHOW,
66         SYSTOHC,
67         HCTOSYS
68 };
69
70
71 time_t read_rtc ( int utc )
72 {
73         int rtc;
74         struct tm tm;
75         char *oldtz = 0;
76         time_t t = 0;
77
78         if (( rtc = open ( "/dev/rtc", O_RDONLY )) < 0 ) {
79                 if (( rtc = open ( "/dev/misc/rtc", O_RDONLY )) < 0 )
80                         perror_msg_and_die ( "Could not access RTC" );
81         }
82         memset ( &tm, 0, sizeof( struct tm ));
83         if ( ioctl ( rtc, RTC_RD_TIME, &tm ) < 0 )
84                 perror_msg_and_die ( "Could not read time from RTC" );
85         tm. tm_isdst = -1; // not known
86         
87         close ( rtc );
88
89         if ( utc ) {    
90                 oldtz = getenv ( "TZ" );
91                 setenv ( "TZ", "UTC 0", 1 );
92                 tzset ( );
93         }
94         
95         t = mktime ( &tm );
96         
97         if ( utc ) {
98                 if ( oldtz )
99                         setenv ( "TZ", oldtz, 1 );
100                 else
101                         unsetenv ( "TZ" );
102                 tzset ( );
103         }
104         return t;
105 }
106
107 void write_rtc ( time_t t, int utc )
108 {
109         int rtc;
110         struct tm tm;
111
112         if (( rtc = open ( "/dev/rtc", O_WRONLY )) < 0 ) {
113                 if (( rtc = open ( "/dev/misc/rtc", O_WRONLY )) < 0 )
114                         perror_msg_and_die ( "Could not access RTC" );
115         }
116         
117         printf ( "1\n" );
118         
119         tm = *( utc ? gmtime ( &t ) : localtime ( &t ));
120         tm. tm_isdst = 0;
121         
122         printf ( "2\n") ;
123         
124         if ( ioctl ( rtc, RTC_SET_TIME, &tm ) < 0 )
125                 perror_msg_and_die ( "Could not set the RTC time" );
126         
127         close ( rtc );
128 }
129
130 int show_clock ( int utc )
131 {
132         struct tm *ptm;
133         time_t t;
134         char buffer [64];
135
136         t = read_rtc ( utc );           
137         ptm = localtime ( &t );  /* Sets 'tzname[]' */
138         
139         safe_strncpy ( buffer, ctime ( &t ), sizeof( buffer ));
140         if ( buffer [0] )
141                 buffer [xstrlen ( buffer ) - 1] = 0;
142         
143         //printf ( "%s  %.6f seconds %s\n", buffer, 0.0, utc ? "" : ( ptm-> tm_isdst ? tzname [1] : tzname [0] ));
144         printf ( "%s  %.6f seconds\n", buffer, 0.0 );
145         
146         return 0;
147 }
148
149 int to_sys_clock ( int utc )
150 {
151         struct timeval tv = { 0, 0 };
152         const struct timezone tz = { timezone/60 - 60*daylight, 0 };
153         
154         tv. tv_sec = read_rtc ( utc );
155
156         if ( settimeofday ( &tv, &tz ))
157                 perror_msg_and_die ( "settimeofday() failed" );
158
159         return 0;
160 }
161
162 int from_sys_clock ( int utc )
163 {
164         struct timeval tv = { 0, 0 };
165         struct timezone tz = { 0, 0 };
166
167         if ( gettimeofday ( &tv, &tz ))
168                 perror_msg_and_die ( "gettimeofday() failed" );
169
170         write_rtc ( tv. tv_sec, utc );
171         return 0;
172 }
173
174
175 int check_utc ( void )
176 {
177         int utc = 0;
178         FILE *f = fopen ( "/etc/adjtime", "r" );
179         
180         if ( f ) {
181                 char buffer [128];
182         
183                 while ( fgets ( buffer, sizeof( buffer ), f )) {
184                         int len = xstrlen ( buffer );
185                         
186                         while ( len && isspace ( buffer [len - 1] ))
187                                 len--;
188                                 
189                         buffer [len] = 0;
190                 
191                         if ( strncmp ( buffer, "UTC", 3 ) == 0 ) {
192                                 utc = 1;
193                                 break;
194                         }
195                 }
196                 fclose ( f );
197         }
198         return utc;
199 }
200
201 extern int hwclock_main ( int argc, char **argv )
202 {
203         int     opt;
204         enum OpMode mode = SHOW;
205         int utc = 0;
206         int utc_arg = 0;
207
208 #ifdef CONFIG_FEATURE_HWCLOCK_LONGOPTIONS
209         struct option long_options[] = {
210                 { "show",      0, 0, 'r' },
211                 { "utc",       0, 0, 'u' },
212                 { "localtime", 0, 0, 'l' },
213                 { "hctosys",   0, 0, 's' },
214                 { "systohc",   0, 0, 'w' },
215                 { 0,           0, 0, 0 }
216         };
217         
218         while (( opt = getopt_long ( argc, argv, "rwsul", long_options, 0 )) != EOF ) {
219 #else
220         while (( opt = getopt ( argc, argv, "rwsul" )) != EOF ) {
221 #endif
222                 switch ( opt ) {
223                 case 'r': 
224                         mode = SHOW; 
225                         break;
226                 case 'w': 
227                         mode = SYSTOHC;
228                         break;
229                 case 's': 
230                         mode = HCTOSYS;
231                         break;
232                 case 'u': 
233                         utc = 1;
234                         utc_arg = 1;
235                         break;
236                 case 'l': // -l is not supported by the normal hwclock (only --localtime)
237                         utc = 0;
238                         utc_arg = 1;
239                         break;
240                 default:
241                         show_usage();
242                         break;
243                 }
244         }
245
246         if ( !utc_arg )
247                 utc = check_utc ( );
248         
249         switch ( mode ) {
250         case SYSTOHC:
251                 return from_sys_clock ( utc );
252
253         case HCTOSYS:
254                 return to_sys_clock ( utc );
255
256         case SHOW:
257         default:
258                 return show_clock ( utc );      
259         }       
260 }
261
262