hwclock.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  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. #include <sys/ioctl.h>
  23. #include <sys/time.h>
  24. #include <sys/utsname.h>
  25. #include <ctype.h>
  26. #include <fcntl.h>
  27. #include <getopt.h>
  28. #include <stdlib.h>
  29. #include <string.h>
  30. #include <syslog.h>
  31. #include <time.h>
  32. #include <unistd.h>
  33. #include "busybox.h"
  34. /* Copied from linux/rtc.h to eliminate the kernel dependency */
  35. struct linux_rtc_time {
  36. int tm_sec;
  37. int tm_min;
  38. int tm_hour;
  39. int tm_mday;
  40. int tm_mon;
  41. int tm_year;
  42. int tm_wday;
  43. int tm_yday;
  44. int tm_isdst;
  45. };
  46. #define RTC_SET_TIME _IOW('p', 0x0a, struct linux_rtc_time) /* Set RTC time */
  47. #define RTC_RD_TIME _IOR('p', 0x09, struct linux_rtc_time) /* Read RTC time */
  48. #ifdef CONFIG_FEATURE_HWCLOCK_LONGOPTIONS
  49. # ifndef _GNU_SOURCE
  50. # define _GNU_SOURCE
  51. # endif
  52. #endif
  53. static time_t read_rtc(int utc)
  54. {
  55. int rtc;
  56. struct tm tm;
  57. char *oldtz = 0;
  58. time_t t = 0;
  59. if (( rtc = open ( "/dev/rtc", O_RDONLY )) < 0 ) {
  60. if (( rtc = open ( "/dev/misc/rtc", O_RDONLY )) < 0 )
  61. bb_perror_msg_and_die ( "Could not access RTC" );
  62. }
  63. memset ( &tm, 0, sizeof( struct tm ));
  64. if ( ioctl ( rtc, RTC_RD_TIME, &tm ) < 0 )
  65. bb_perror_msg_and_die ( "Could not read time from RTC" );
  66. tm. tm_isdst = -1; // not known
  67. close ( rtc );
  68. if ( utc ) {
  69. oldtz = getenv ( "TZ" );
  70. setenv ( "TZ", "UTC 0", 1 );
  71. tzset ( );
  72. }
  73. t = mktime ( &tm );
  74. if ( utc ) {
  75. if ( oldtz )
  76. setenv ( "TZ", oldtz, 1 );
  77. else
  78. unsetenv ( "TZ" );
  79. tzset ( );
  80. }
  81. return t;
  82. }
  83. static void write_rtc(time_t t, int utc)
  84. {
  85. int rtc;
  86. struct tm tm;
  87. if (( rtc = open ( "/dev/rtc", O_WRONLY )) < 0 ) {
  88. if (( rtc = open ( "/dev/misc/rtc", O_WRONLY )) < 0 )
  89. bb_perror_msg_and_die ( "Could not access RTC" );
  90. }
  91. tm = *( utc ? gmtime ( &t ) : localtime ( &t ));
  92. tm. tm_isdst = 0;
  93. if ( ioctl ( rtc, RTC_SET_TIME, &tm ) < 0 )
  94. bb_perror_msg_and_die ( "Could not set the RTC time" );
  95. close ( rtc );
  96. }
  97. static int show_clock(int utc)
  98. {
  99. struct tm *ptm;
  100. time_t t;
  101. char buffer [64];
  102. t = read_rtc ( utc );
  103. ptm = localtime ( &t ); /* Sets 'tzname[]' */
  104. safe_strncpy ( buffer, ctime ( &t ), sizeof( buffer ));
  105. if ( buffer [0] )
  106. buffer [bb_strlen ( buffer ) - 1] = 0;
  107. //printf ( "%s %.6f seconds %s\n", buffer, 0.0, utc ? "" : ( ptm-> tm_isdst ? tzname [1] : tzname [0] ));
  108. printf ( "%s %.6f seconds\n", buffer, 0.0 );
  109. return 0;
  110. }
  111. static int to_sys_clock(int utc)
  112. {
  113. struct timeval tv = { 0, 0 };
  114. const struct timezone tz = { timezone/60 - 60*daylight, 0 };
  115. tv. tv_sec = read_rtc ( utc );
  116. if ( settimeofday ( &tv, &tz ))
  117. bb_perror_msg_and_die ( "settimeofday() failed" );
  118. return 0;
  119. }
  120. static int from_sys_clock(int utc)
  121. {
  122. struct timeval tv = { 0, 0 };
  123. struct timezone tz = { 0, 0 };
  124. if ( gettimeofday ( &tv, &tz ))
  125. bb_perror_msg_and_die ( "gettimeofday() failed" );
  126. write_rtc ( tv. tv_sec, utc );
  127. return 0;
  128. }
  129. #ifdef CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS
  130. # define ADJTIME_PATH "/var/lib/hwclock/adjtime"
  131. #else
  132. # define ADJTIME_PATH "/etc/adjtime"
  133. #endif
  134. static int check_utc(void)
  135. {
  136. int utc = 0;
  137. FILE *f = fopen ( ADJTIME_PATH, "r" );
  138. if ( f ) {
  139. char buffer [128];
  140. while ( fgets ( buffer, sizeof( buffer ), f )) {
  141. int len = bb_strlen ( buffer );
  142. while ( len && isspace ( buffer [len - 1] ))
  143. len--;
  144. buffer [len] = 0;
  145. if ( strncmp ( buffer, "UTC", 3 ) == 0 ) {
  146. utc = 1;
  147. break;
  148. }
  149. }
  150. fclose ( f );
  151. }
  152. return utc;
  153. }
  154. #define HWCLOCK_OPT_LOCALTIME 0x01
  155. #define HWCLOCK_OPT_UTC 0x02
  156. #define HWCLOCK_OPT_SHOW 0x04
  157. #define HWCLOCK_OPT_HCTOSYS 0x08
  158. #define HWCLOCK_OPT_SYSTOHC 0x10
  159. int hwclock_main ( int argc, char **argv )
  160. {
  161. unsigned long opt;
  162. int utc;
  163. #ifdef CONFIG_FEATURE_HWCLOCK_LONGOPTIONS
  164. static const struct option hwclock_long_options[] = {
  165. { "localtime", 0, 0, 'l' },
  166. { "utc", 0, 0, 'u' },
  167. { "show", 0, 0, 'r' },
  168. { "hctosys", 0, 0, 's' },
  169. { "systohc", 0, 0, 'w' },
  170. { 0, 0, 0, 0 }
  171. };
  172. bb_applet_long_options = hwclock_long_options;
  173. #endif
  174. bb_opt_complementally = "?:r--ws:w--rs:s--wr:l--u:u--l";
  175. opt = bb_getopt_ulflags(argc, argv, "lursw");
  176. /* If -u or -l wasn't given check if we are using utc */
  177. if (opt & (HWCLOCK_OPT_UTC | HWCLOCK_OPT_LOCALTIME))
  178. utc = opt & HWCLOCK_OPT_UTC;
  179. else
  180. utc = check_utc();
  181. if (opt & HWCLOCK_OPT_HCTOSYS) {
  182. return to_sys_clock ( utc );
  183. }
  184. else if (opt & HWCLOCK_OPT_SYSTOHC) {
  185. return from_sys_clock ( utc );
  186. } else {
  187. /* default HWCLOCK_OPT_SHOW */
  188. return show_clock ( utc );
  189. }
  190. }