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 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 8*/ 9 10#include <sys/utsname.h> 11#include <getopt.h> 12#include "libbb.h" 13 14/* Copied from linux/rtc.h to eliminate the kernel dependency */ 15struct linux_rtc_time { 16 int tm_sec; 17 int tm_min; 18 int tm_hour; 19 int tm_mday; 20 int tm_mon; 21 int tm_year; 22 int tm_wday; 23 int tm_yday; 24 int tm_isdst; 25}; 26 27#define RTC_SET_TIME _IOW('p', 0x0a, struct linux_rtc_time) /* Set RTC time */ 28#define RTC_RD_TIME _IOR('p', 0x09, struct linux_rtc_time) /* Read RTC time */ 29 30#if ENABLE_FEATURE_HWCLOCK_LONG_OPTIONS 31# ifndef _GNU_SOURCE 32# define _GNU_SOURCE 33# endif 34#endif 35 36static const char *rtcname; 37 38static int xopen_rtc(int flags) 39{ 40 int rtc; 41 42 if (!rtcname) { 43 rtc = open("/dev/rtc", flags); 44 if (rtc >= 0) 45 return rtc; 46 rtc = open("/dev/rtc0", flags); 47 if (rtc >= 0) 48 return rtc; 49 rtcname = "/dev/misc/rtc"; 50 } 51 return xopen(rtcname, flags); 52} 53 54static time_t read_rtc(int utc) 55{ 56 struct tm tm; 57 char *oldtz = 0; 58 time_t t = 0; 59 int rtc = xopen_rtc(O_RDONLY); 60 61 memset(&tm, 0, sizeof(struct tm)); 62 xioctl(rtc, RTC_RD_TIME, &tm); 63 tm.tm_isdst = -1; /* not known */ 64 65 close(rtc); 66 67 if (utc) { 68 oldtz = getenv("TZ"); 69 putenv((char*)"TZ=UTC0"); 70 tzset(); 71 } 72 73 t = mktime(&tm); 74 75 if (utc) { 76 unsetenv("TZ"); 77 if (oldtz) 78 putenv(oldtz - 3); 79 tzset(); 80 } 81 return t; 82} 83 84static void write_rtc(time_t t, int utc) 85{ 86 struct tm tm; 87 int rtc = xopen_rtc(O_WRONLY); 88 89 tm = *(utc ? gmtime(&t) : localtime(&t)); 90 tm.tm_isdst = 0; 91 92 xioctl(rtc, RTC_SET_TIME, &tm); 93 94 close(rtc); 95} 96 97static void show_clock(int utc) 98{ 99 //struct tm *ptm; 100 time_t t; 101 char *cp; 102 103 t = read_rtc(utc); 104 //ptm = localtime(&t); /* Sets 'tzname[]' */ 105 106 cp = ctime(&t); 107 if (cp[0]) 108 cp[strlen(cp) - 1] = '\0'; 109 110 //printf("%s %.6f seconds %s\n", cp, 0.0, utc ? "" : (ptm->tm_isdst ? tzname[1] : tzname[0])); 111 printf("%s 0.000000 seconds\n", cp); 112} 113 114static void to_sys_clock(int utc) 115{ 116 struct timeval tv; 117 const struct timezone tz = { timezone/60 - 60*daylight, 0 }; 118 119 tv.tv_sec = read_rtc(utc); 120 tv.tv_usec = 0; 121 if (settimeofday(&tv, &tz)) 122 bb_perror_msg_and_die("settimeofday() failed"); 123} 124 125static void from_sys_clock(int utc) 126{ 127 struct timeval tv; 128 129 gettimeofday(&tv, NULL); 130 //if (gettimeofday(&tv, NULL)) 131 // bb_perror_msg_and_die("gettimeofday() failed"); 132 write_rtc(tv.tv_sec, utc); 133} 134 135#if ENABLE_FEATURE_HWCLOCK_ADJTIME_FHS 136# define ADJTIME_PATH "/var/lib/hwclock/adjtime" 137#else 138# define ADJTIME_PATH "/etc/adjtime" 139#endif 140static int check_utc(void) 141{ 142 int utc = 0; 143 FILE *f = fopen(ADJTIME_PATH, "r"); 144 145 if (f) { 146 RESERVE_CONFIG_BUFFER(buffer, 128); 147 148 while (fgets(buffer, sizeof(buffer), f)) { 149 int len = strlen(buffer); 150 151 while (len && isspace(buffer[len - 1])) 152 len--; 153 154 buffer[len] = 0; 155 156 if (strncmp(buffer, "UTC", 3) == 0) { 157 utc = 1; 158 break; 159 } 160 } 161 fclose(f); 162 RELEASE_CONFIG_BUFFER(buffer); 163 } 164 return utc; 165} 166 167#define HWCLOCK_OPT_LOCALTIME 0x01 168#define HWCLOCK_OPT_UTC 0x02 169#define HWCLOCK_OPT_SHOW 0x04 170#define HWCLOCK_OPT_HCTOSYS 0x08 171#define HWCLOCK_OPT_SYSTOHC 0x10 172#define HWCLOCK_OPT_RTCFILE 0x20 173 174int hwclock_main(int argc, char **argv); 175int hwclock_main(int argc, char **argv) 176{ 177 unsigned opt; 178 int utc; 179 180#if ENABLE_FEATURE_HWCLOCK_LONG_OPTIONS 181 static const char hwclock_longopts[] ALIGN1 = 182 "localtime\0" No_argument "l" 183 "utc\0" No_argument "u" 184 "show\0" No_argument "r" 185 "hctosys\0" No_argument "s" 186 "systohc\0" No_argument "w" 187 "file\0" Required_argument "f" 188 ; 189 applet_long_options = hwclock_longopts; 190#endif 191 opt_complementary = "r--ws:w--rs:s--wr:l--u:u--l"; 192 opt = getopt32(argv, "lurswf:", &rtcname); 193 194 /* If -u or -l wasn't given check if we are using utc */ 195 if (opt & (HWCLOCK_OPT_UTC | HWCLOCK_OPT_LOCALTIME)) 196 utc = opt & HWCLOCK_OPT_UTC; 197 else 198 utc = check_utc(); 199 200 if (opt & HWCLOCK_OPT_HCTOSYS) { 201 to_sys_clock(utc); 202 return 0; 203 } 204 if (opt & HWCLOCK_OPT_SYSTOHC) { 205 from_sys_clock(utc); 206 return 0; 207 } 208 /* default HWCLOCK_OPT_SHOW */ 209 show_clock(utc); 210 return 0; 211} 212