blob: 70ce1d58754a347aeccc32366c2e533f7426b91a [file] [log] [blame]
Elliott Hughese25a6412014-04-07 15:11:57 -07001#include <ctype.h>
2#include <errno.h>
3#include <fcntl.h>
4#include <inttypes.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08005#include <stdio.h>
6#include <stdlib.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08007#include <string.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08008#include <time.h>
Elliott Hughese25a6412014-04-07 15:11:57 -07009#include <unistd.h>
10
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080011#include <linux/android_alarm.h>
Greg Hackmann4a7bc602013-12-17 14:00:03 -080012#include <linux/rtc.h>
Olivier Baillyb93e5812010-11-17 11:47:23 -080013#include <sys/ioctl.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080014
Greg Hackmann4a7bc602013-12-17 14:00:03 -080015static int settime_alarm(struct timespec *ts) {
16 int fd, ret;
17
18 fd = open("/dev/alarm", O_RDWR);
19 if (fd < 0)
20 return fd;
21
Benoit Gobyd3407342014-01-09 18:59:23 -080022 ret = ioctl(fd, ANDROID_ALARM_SET_RTC, ts);
Greg Hackmann4a7bc602013-12-17 14:00:03 -080023 close(fd);
24 return ret;
25}
26
27static int settime_alarm_tm(struct tm *tm) {
28 time_t t;
29 struct timespec ts;
30
31 t = mktime(tm);
32 ts.tv_sec = t;
33 ts.tv_nsec = 0;
34 return settime_alarm(&ts);
35}
36
37static int settime_alarm_timeval(struct timeval *tv) {
38 struct timespec ts;
39
40 ts.tv_sec = tv->tv_sec;
41 ts.tv_nsec = tv->tv_usec * 1000;
42 return settime_alarm(&ts);
43}
44
45static int settime_rtc_tm(struct tm *tm) {
46 int fd, ret;
47 struct timeval tv;
48 struct rtc_time rtc;
49
50 fd = open("/dev/rtc0", O_RDWR);
51 if (fd < 0)
52 return fd;
53
54 tv.tv_sec = mktime(tm);
55 tv.tv_usec = 0;
56
57 ret = settimeofday(&tv, NULL);
58 if (ret < 0)
59 goto done;
60
61 memset(&rtc, 0, sizeof(rtc));
62 rtc.tm_sec = tm->tm_sec;
63 rtc.tm_min = tm->tm_min;
64 rtc.tm_hour = tm->tm_hour;
65 rtc.tm_mday = tm->tm_mday;
66 rtc.tm_mon = tm->tm_mon;
67 rtc.tm_year = tm->tm_year;
68 rtc.tm_wday = tm->tm_wday;
69 rtc.tm_yday = tm->tm_yday;
70 rtc.tm_isdst = tm->tm_isdst;
71
72 ret = ioctl(fd, RTC_SET_TIME, rtc);
73done:
74 close(fd);
75 return ret;
76}
77
78static int settime_rtc_timeval(struct timeval *tv) {
79 struct tm tm, *err;
80 time_t t = tv->tv_sec;
81
82 err = gmtime_r(&t, &tm);
83 if (!err)
84 return -1;
85
86 return settime_rtc_tm(&tm);
87}
88
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080089static void settime(char *s) {
90 struct tm tm;
91 int day = atoi(s);
92 int hour;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080093
94 while (*s && *s != '.')
95 s++;
96
97 if (*s)
98 s++;
99
100 hour = atoi(s);
101
102 tm.tm_year = day / 10000 - 1900;
103 tm.tm_mon = (day % 10000) / 100 - 1;
104 tm.tm_mday = (day % 100);
105 tm.tm_hour = hour / 10000;
106 tm.tm_min = (hour % 10000) / 100;
107 tm.tm_sec = (hour % 100);
108 tm.tm_isdst = -1;
109
Greg Hackmann4a7bc602013-12-17 14:00:03 -0800110 if (settime_alarm_tm(&tm) < 0)
111 settime_rtc_tm(&tm);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800112}
113
Elliott Hughese25a6412014-04-07 15:11:57 -0700114static char *parse_time(const char *str, struct timeval *ts) {
115 char *s;
116 long fs = 0; /* fractional seconds */
117
118 ts->tv_sec = strtoumax(str, &s, 10);
119
120 if (*s == '.') {
121 s++;
122 int count = 0;
123
124 /* read up to 6 digits (microseconds) */
125 while (*s && isdigit(*s)) {
126 if (++count < 7) {
127 fs = fs*10 + (*s - '0');
128 }
129 s++;
130 }
131
132 for (; count < 6; count++) {
133 fs *= 10;
134 }
135 }
136
137 ts->tv_usec = fs;
138 return s;
139}
140
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800141int date_main(int argc, char *argv[])
142{
Mark Salyzynaa907762014-05-08 09:31:43 -0700143 int c;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800144 int res;
Mark Salyzynaa907762014-05-08 09:31:43 -0700145 struct tm tm;
146 time_t t;
147 struct timeval tv;
148 char strbuf[260];
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800149
150 int useutc = 0;
151
152 tzset();
153
154 do {
155 c = getopt(argc, argv, "us:");
156 if (c == EOF)
157 break;
158 switch (c) {
159 case 'u':
160 useutc = 1;
161 break;
162 case 's':
163 settime(optarg);
164 break;
165 case '?':
166 fprintf(stderr, "%s: invalid option -%c\n",
167 argv[0], optopt);
168 exit(1);
169 }
170 } while (1);
171 if(optind + 2 < argc) {
172 fprintf(stderr,"%s [-u] [date]\n", argv[0]);
173 return 1;
174 }
175
176 int hasfmt = argc == optind + 1 && argv[optind][0] == '+';
177 if(optind == argc || hasfmt) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800178 time(&t);
179 if (useutc) {
180 gmtime_r(&t, &tm);
181 strftime(strbuf, sizeof(strbuf),
182 (hasfmt ? argv[optind] + 1 : "%a %b %e %H:%M:%S GMT %Y"),
183 &tm);
184 } else {
185 localtime_r(&t, &tm);
186 strftime(strbuf, sizeof(strbuf),
187 (hasfmt ? argv[optind] + 1 : "%a %b %e %H:%M:%S %Z %Y"),
188 &tm);
189 }
190 printf("%s\n", strbuf);
191 }
192 else if(optind + 1 == argc) {
193#if 0
194 struct tm *tmptr;
195 tmptr = getdate(argv[optind]);
196 if(tmptr == NULL) {
197 fprintf(stderr,"getdate_r failed\n");
198 return 1;
199 }
200 tm = *tmptr;
201#if 0
202 if(getdate_r(argv[optind], &tm) < 0) {
203 fprintf(stderr,"getdate_r failed %s\n", strerror(errno));
204 return 1;
205 }
206#endif
207#endif
208 //strptime(argv[optind], NULL, &tm);
209 //tv.tv_sec = mktime(&tm);
210 //tv.tv_usec = 0;
Elliott Hughese25a6412014-04-07 15:11:57 -0700211 parse_time(argv[optind], &tv);
Greg Hackmannc0575032013-12-17 13:59:06 -0800212 printf("time %s -> %lu.%lu\n", argv[optind], tv.tv_sec, tv.tv_usec);
Greg Hackmann4a7bc602013-12-17 14:00:03 -0800213 res = settime_alarm_timeval(&tv);
214 if (res < 0)
215 res = settime_rtc_timeval(&tv);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800216 if(res < 0) {
217 fprintf(stderr,"settimeofday failed %s\n", strerror(errno));
218 return 1;
219 }
220 }
221 else {
222 fprintf(stderr,"%s [-s 20070325.123456] [-u] [date]\n", argv[0]);
223 return 1;
224 }
225
226 return 0;
227}