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