Magellan Linux

Diff of /trunk/mkinitrd-magellan/busybox/util-linux/hwclock.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 983 by niro, Fri Apr 24 18:33:46 2009 UTC revision 984 by niro, Sun May 30 11:32:42 2010 UTC
# Line 7  Line 7 
7   * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.   * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8  */  */
9    
 #include <sys/utsname.h>  
10  #include "libbb.h"  #include "libbb.h"
11    /* After libbb.h, since it needs sys/types.h on some systems */
12    #include <sys/utsname.h>
13  #include "rtc_.h"  #include "rtc_.h"
14    
15  #if ENABLE_FEATURE_HWCLOCK_LONG_OPTIONS  #if ENABLE_FEATURE_HWCLOCK_LONG_OPTIONS
# Line 17  Line 18 
18  # endif  # endif
19  #endif  #endif
20    
 static const char *rtcname;  
21    
22  static time_t read_rtc(int utc)  /* diff code is disabled: it's not sys/hw clock diff, it's some useless
23     * "time between hwclock was started and we saw CMOS tick" quantity.
24     * It's useless since hwclock is started at a random moment,
25     * thus the quantity is also random, useless. Showing 0.000000 does not
26     * deprive us from any useful info.
27     *
28     * SHOW_HWCLOCK_DIFF code in this file shows the difference between system
29     * and hw clock. It is useful, but not compatible with standard hwclock.
30     * Thus disabled.
31     */
32    #define SHOW_HWCLOCK_DIFF 0
33    
34    
35    #if !SHOW_HWCLOCK_DIFF
36    # define read_rtc(pp_rtcname, sys_tv, utc) read_rtc(pp_rtcname, utc)
37    #endif
38    static time_t read_rtc(const char **pp_rtcname, struct timeval *sys_tv, int utc)
39  {  {
40   time_t ret;   struct tm tm_time;
41   int fd;   int fd;
42    
43   fd = rtc_xopen(&rtcname, O_RDONLY);   fd = rtc_xopen(pp_rtcname, O_RDONLY);
  ret = rtc_read_time(fd, utc);  
  close(fd);  
   
  return ret;  
 }  
44    
45  static void write_rtc(time_t t, int utc)   rtc_read_tm(&tm_time, fd);
 {  
  struct tm tm;  
  int rtc = rtc_xopen(&rtcname, O_WRONLY);  
46    
47   tm = *(utc ? gmtime(&t) : localtime(&t));  #if SHOW_HWCLOCK_DIFF
48   tm.tm_isdst = 0;   {
49     int before = tm_time.tm_sec;
50     while (1) {
51     rtc_read_tm(&tm_time, fd);
52     gettimeofday(sys_tv, NULL);
53     if (before != tm_time.tm_sec)
54     break;
55     }
56     }
57    #endif
58    
59   xioctl(rtc, RTC_SET_TIME, &tm);   if (ENABLE_FEATURE_CLEAN_UP)
60     close(fd);
61    
62   close(rtc);   return rtc_tm2time(&tm_time, utc);
63  }  }
64    
65  static void show_clock(int utc)  static void show_clock(const char **pp_rtcname, int utc)
66  {  {
67   //struct tm *ptm;  #if SHOW_HWCLOCK_DIFF
68     struct timeval sys_tv;
69    #endif
70   time_t t;   time_t t;
71   char *cp;   char *cp;
72    
73   t = read_rtc(utc);   t = read_rtc(pp_rtcname, &sys_tv, utc);
  //ptm = localtime(&t);  /* Sets 'tzname[]' */  
   
74   cp = ctime(&t);   cp = ctime(&t);
75   if (cp[0])   strchrnul(cp, '\n')[0] = '\0';
76   cp[strlen(cp) - 1] = '\0';  #if !SHOW_HWCLOCK_DIFF
   
  //printf("%s  %.6f seconds %s\n", cp, 0.0, utc ? "" : (ptm->tm_isdst ? tzname[1] : tzname[0]));  
77   printf("%s  0.000000 seconds\n", cp);   printf("%s  0.000000 seconds\n", cp);
78    #else
79     {
80     long diff = sys_tv.tv_sec - t;
81     if (diff < 0 /*&& tv.tv_usec != 0*/) {
82     /* Why? */
83     /* diff >= 0 is ok:   diff < 0, can't just use tv.tv_usec: */
84     /*   45.520820          43.520820 */
85     /* - 44.000000        - 45.000000 */
86     /* =  1.520820        = -1.479180, not -2.520820! */
87     diff++;
88     /* should be 1000000 - tv.tv_usec, but then we must check tv.tv_usec != 0 */
89     sys_tv.tv_usec = 999999 - sys_tv.tv_usec;
90     }
91     printf("%s  %ld.%06lu seconds\n", cp, diff, (unsigned long)sys_tv.tv_usec);
92     }
93    #endif
94  }  }
95    
96  static void to_sys_clock(int utc)  static void to_sys_clock(const char **pp_rtcname, int utc)
97  {  {
98   struct timeval tv;   struct timeval tv;
99   const struct timezone tz = { timezone/60 - 60*daylight, 0 };   struct timezone tz;
100    
101     tz.tz_minuteswest = timezone/60 - 60*daylight;
102     tz.tz_dsttime = 0;
103    
104   tv.tv_sec = read_rtc(utc);   tv.tv_sec = read_rtc(pp_rtcname, NULL, utc);
105   tv.tv_usec = 0;   tv.tv_usec = 0;
106   if (settimeofday(&tv, &tz))   if (settimeofday(&tv, &tz))
107   bb_perror_msg_and_die("settimeofday() failed");   bb_perror_msg_and_die("settimeofday");
108  }  }
109    
110  static void from_sys_clock(int utc)  static void from_sys_clock(const char **pp_rtcname, int utc)
111  {  {
112    #define TWEAK_USEC 200
113     struct tm tm_time;
114   struct timeval tv;   struct timeval tv;
115     unsigned adj = TWEAK_USEC;
116     int rtc = rtc_xopen(pp_rtcname, O_WRONLY);
117    
118     /* Try to catch the moment when whole second is close */
119     while (1) {
120     unsigned rem_usec;
121     time_t t;
122    
123     gettimeofday(&tv, NULL);
124    
125     t = tv.tv_sec;
126     rem_usec = 1000000 - tv.tv_usec;
127     if (rem_usec < 1024) {
128     /* Less than 1ms to next second. Good enough */
129     small_rem:
130     t++;
131     }
132    
133     /* Prepare tm */
134     if (utc)
135     gmtime_r(&t, &tm_time); /* may read /etc/xxx (it takes time) */
136     else
137     localtime_r(&t, &tm_time); /* same */
138     tm_time.tm_isdst = 0;
139    
140     /* gmtime/localtime took some time, re-get cur time */
141     gettimeofday(&tv, NULL);
142    
143     if (tv.tv_sec < t /* may happen if rem_usec was < 1024 */
144     || (tv.tv_sec == t && tv.tv_usec < 1024)
145     ) {
146     /* We are not too far into next second. Good. */
147     break;
148     }
149     adj += 32; /* 2^(10-5) = 2^5 = 32 iterations max */
150     if (adj >= 1024) {
151     /* Give up trying to sync */
152     break;
153     }
154    
155     /* Try to sync up by sleeping */
156     rem_usec = 1000000 - tv.tv_usec;
157     if (rem_usec < 1024) {
158     goto small_rem; /* already close, don't sleep */
159     }
160     /* Need to sleep.
161     * Note that small adj on slow processors can make us
162     * to always overshoot tv.tv_usec < 1024 check on next
163     * iteration. That's why adj is increased on each iteration.
164     * This also allows it to be reused as a loop limiter.
165     */
166     usleep(rem_usec - adj);
167     }
168    
169     xioctl(rtc, RTC_SET_TIME, &tm_time);
170    
171     /* Debug aid to find "good" TWEAK_USEC.
172     * Look for a value which makes tv_usec close to 999999 or 0.
173     * for 2.20GHz Intel Core 2: TWEAK_USEC ~= 200
174     */
175     //bb_error_msg("tv.tv_usec:%d adj:%d", (int)tv.tv_usec, adj);
176    
177   gettimeofday(&tv, NULL);   if (ENABLE_FEATURE_CLEAN_UP)
178   //if (gettimeofday(&tv, NULL))   close(rtc);
  // bb_perror_msg_and_die("gettimeofday() failed");  
  write_rtc(tv.tv_sec, utc);  
179  }  }
180    
181  #define HWCLOCK_OPT_LOCALTIME   0x01  #define HWCLOCK_OPT_LOCALTIME   0x01
# Line 92  static void from_sys_clock(int utc) Line 188  static void from_sys_clock(int utc)
188  int hwclock_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;  int hwclock_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
189  int hwclock_main(int argc UNUSED_PARAM, char **argv)  int hwclock_main(int argc UNUSED_PARAM, char **argv)
190  {  {
191     const char *rtcname = NULL;
192   unsigned opt;   unsigned opt;
193   int utc;   int utc;
194    
# Line 116  int hwclock_main(int argc UNUSED_PARAM, Line 213  int hwclock_main(int argc UNUSED_PARAM,
213   utc = rtc_adjtime_is_utc();   utc = rtc_adjtime_is_utc();
214    
215   if (opt & HWCLOCK_OPT_HCTOSYS)   if (opt & HWCLOCK_OPT_HCTOSYS)
216   to_sys_clock(utc);   to_sys_clock(&rtcname, utc);
217   else if (opt & HWCLOCK_OPT_SYSTOHC)   else if (opt & HWCLOCK_OPT_SYSTOHC)
218   from_sys_clock(utc);   from_sys_clock(&rtcname, utc);
219   else   else
220   /* default HWCLOCK_OPT_SHOW */   /* default HWCLOCK_OPT_SHOW */
221   show_clock(utc);   show_clock(&rtcname, utc);
222    
223   return 0;   return 0;
224  }  }

Legend:
Removed from v.983  
changed lines
  Added in v.984