1
2
3
4
5
6
7
8
9#include "libbb.h"
10
11void FAST_FUNC parse_datestr(const char *date_str, struct tm *ptm)
12{
13 char end = '\0';
14 const char *last_colon = strrchr(date_str, ':');
15
16 if (last_colon != NULL) {
17
18#if ENABLE_DESKTOP
19 const char *endp;
20#endif
21
22
23 if (sscanf(date_str, "%u:%u%c",
24 &ptm->tm_hour,
25 &ptm->tm_min,
26 &end) >= 2
27 ) {
28
29 } else
30
31 if (sscanf(date_str, "%u.%u-%u:%u%c",
32 &ptm->tm_mon, &ptm->tm_mday,
33 &ptm->tm_hour, &ptm->tm_min,
34 &end) >= 4
35 ) {
36
37 ptm->tm_mon -= 1;
38 } else
39
40 if (sscanf(date_str, "%u.%u.%u-%u:%u%c", &ptm->tm_year,
41 &ptm->tm_mon, &ptm->tm_mday,
42 &ptm->tm_hour, &ptm->tm_min,
43 &end) >= 5
44
45 || sscanf(date_str, "%u-%u-%u %u:%u%c", &ptm->tm_year,
46 &ptm->tm_mon, &ptm->tm_mday,
47 &ptm->tm_hour, &ptm->tm_min,
48 &end) >= 5
49 ) {
50 ptm->tm_year -= 1900;
51 ptm->tm_mon -= 1;
52 } else
53#if ENABLE_DESKTOP
54
55 if ((endp = strptime(date_str, "%b %d %T %Y", ptm)) != NULL
56 && *endp == '\0'
57 ) {
58 return;
59 } else
60#endif
61 {
62 bb_error_msg_and_die(bb_msg_invalid_date, date_str);
63 }
64 if (end == ':') {
65
66 if (sscanf(last_colon + 1, "%u%c", &ptm->tm_sec, &end) == 1)
67 end = '\0';
68
69 }
70 } else
71 if (strchr(date_str, '-')
72
73
74
75
76
77
78
79 && (sscanf(date_str, "%u-%u-%u %u%c", &ptm->tm_year,
80 &ptm->tm_mon, &ptm->tm_mday,
81 &ptm->tm_hour,
82 &end) >= 4
83
84 || sscanf(date_str, "%u-%u-%u%c", &ptm->tm_year,
85 &ptm->tm_mon, &ptm->tm_mday,
86 &end) >= 3
87 )
88 ) {
89 ptm->tm_year -= 1900;
90 ptm->tm_mon -= 1;
91 } else
92 if (date_str[0] == '@') {
93 time_t t = bb_strtol(date_str + 1, NULL, 10);
94 if (!errno) {
95 struct tm *lt = localtime(&t);
96 if (lt) {
97 *ptm = *lt;
98 return;
99 }
100 }
101 end = '1';
102 } else {
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123 unsigned cur_year = ptm->tm_year;
124 int len = strchrnul(date_str, '.') - date_str;
125
126
127 if (len == 2 && sscanf(date_str, "%2u%2u%2u%2u""%2u%c" + 12,
128 &ptm->tm_min,
129 &end) >= 1) {
130 } else
131
132 if (len == 4 && sscanf(date_str, "%2u%2u%2u""%2u%2u%c" + 9,
133 &ptm->tm_hour,
134 &ptm->tm_min,
135 &end) >= 2) {
136 } else
137
138 if (len == 6 && sscanf(date_str, "%2u%2u""%2u%2u%2u%c" + 6,
139 &ptm->tm_mday,
140 &ptm->tm_hour,
141 &ptm->tm_min,
142 &end) >= 3) {
143 } else
144
145 if (len == 8 && sscanf(date_str, "%2u""%2u%2u%2u%2u%c" + 3,
146 &ptm->tm_mon,
147 &ptm->tm_mday,
148 &ptm->tm_hour,
149 &ptm->tm_min,
150 &end) >= 4) {
151
152 ptm->tm_mon -= 1;
153 } else
154
155 if (len == 10 && sscanf(date_str, "%2u%2u%2u%2u%2u%c",
156 &ptm->tm_year,
157 &ptm->tm_mon,
158 &ptm->tm_mday,
159 &ptm->tm_hour,
160 &ptm->tm_min,
161 &end) >= 5) {
162
163 ptm->tm_mon -= 1;
164 if ((int)cur_year >= 50) {
165
166
167 ptm->tm_year += (cur_year / 100) * 100;
168
169 if (ptm->tm_year < cur_year - 50)
170 ptm->tm_year += 100;
171
172 if (ptm->tm_year > cur_year + 50)
173 ptm->tm_year -= 100;
174 }
175 } else
176
177 if (len == 12 && sscanf(date_str, "%4u%2u%2u%2u%2u%c",
178 &ptm->tm_year,
179 &ptm->tm_mon,
180 &ptm->tm_mday,
181 &ptm->tm_hour,
182 &ptm->tm_min,
183 &end) >= 5) {
184 ptm->tm_year -= 1900;
185 ptm->tm_mon -= 1;
186 } else {
187 err:
188 bb_error_msg_and_die(bb_msg_invalid_date, date_str);
189 }
190 ptm->tm_sec = 0;
191 if (end == '.') {
192
193 if (sscanf(strchr(date_str, '.') + 1, "%u%c",
194 &ptm->tm_sec, &end) == 1)
195 end = '\0';
196
197 }
198
199
200
201
202
203 if (ptm->tm_sec > 60
204 || ptm->tm_min > 59
205 || ptm->tm_hour > 23
206 || ptm->tm_mday > 31
207 || ptm->tm_mon > 11
208 ) {
209 goto err;
210 }
211 }
212 if (end != '\0') {
213 bb_error_msg_and_die(bb_msg_invalid_date, date_str);
214 }
215}
216
217time_t FAST_FUNC validate_tm_time(const char *date_str, struct tm *ptm)
218{
219 time_t t = mktime(ptm);
220 if (t == (time_t) -1L) {
221 bb_error_msg_and_die(bb_msg_invalid_date, date_str);
222 }
223 return t;
224}
225
226static char* strftime_fmt(char *buf, unsigned len, time_t *tp, const char *fmt)
227{
228 time_t t;
229 if (!tp) {
230 tp = &t;
231 time(tp);
232 }
233
234 return buf + strftime(buf, len, fmt, localtime(tp));
235}
236
237char* FAST_FUNC strftime_HHMMSS(char *buf, unsigned len, time_t *tp)
238{
239 return strftime_fmt(buf, len, tp, "%H:%M:%S");
240}
241
242char* FAST_FUNC strftime_YYYYMMDDHHMMSS(char *buf, unsigned len, time_t *tp)
243{
244 return strftime_fmt(buf, len, tp, "%Y-%m-%d %H:%M:%S");
245}
246
247#if ENABLE_MONOTONIC_SYSCALL
248
249#include <sys/syscall.h>
250
251
252#ifndef CLOCK_MONOTONIC
253#define CLOCK_MONOTONIC 1
254#endif
255
256
257
258static void get_mono(struct timespec *ts)
259{
260 if (syscall(__NR_clock_gettime, CLOCK_MONOTONIC, ts))
261 bb_error_msg_and_die("clock_gettime(MONOTONIC) failed");
262}
263unsigned long long FAST_FUNC monotonic_ns(void)
264{
265 struct timespec ts;
266 get_mono(&ts);
267 return ts.tv_sec * 1000000000ULL + ts.tv_nsec;
268}
269unsigned long long FAST_FUNC monotonic_us(void)
270{
271 struct timespec ts;
272 get_mono(&ts);
273 return ts.tv_sec * 1000000ULL + ts.tv_nsec/1000;
274}
275unsigned long long FAST_FUNC monotonic_ms(void)
276{
277 struct timespec ts;
278 get_mono(&ts);
279 return ts.tv_sec * 1000ULL + ts.tv_nsec/1000000;
280}
281unsigned FAST_FUNC monotonic_sec(void)
282{
283 struct timespec ts;
284 get_mono(&ts);
285 return ts.tv_sec;
286}
287
288#else
289
290unsigned long long FAST_FUNC monotonic_ns(void)
291{
292 struct timeval tv;
293 gettimeofday(&tv, NULL);
294 return tv.tv_sec * 1000000000ULL + tv.tv_usec * 1000;
295}
296unsigned long long FAST_FUNC monotonic_us(void)
297{
298 struct timeval tv;
299 gettimeofday(&tv, NULL);
300 return tv.tv_sec * 1000000ULL + tv.tv_usec;
301}
302unsigned long long FAST_FUNC monotonic_ms(void)
303{
304 struct timeval tv;
305 gettimeofday(&tv, NULL);
306 return tv.tv_sec * 1000ULL + tv.tv_usec / 1000;
307}
308unsigned FAST_FUNC monotonic_sec(void)
309{
310 return time(NULL);
311}
312
313#endif
314