- updated a few copyright/left file headers
[oweals/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 <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
46 enum OpMode {
47         SHOW,
48         SYSTOHC,
49         HCTOSYS
50 };
51
52
53 time_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
89 void 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
112 int 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
131 int 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
144 int 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
157 int 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
183 extern 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