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;
94 if (sizeof(t) <= sizeof(long))
95 t = bb_strtol(date_str + 1, NULL, 10);
96 else
97 t = bb_strtoll(date_str + 1, NULL, 10);
98 if (!errno) {
99 struct tm *lt = localtime(&t);
100 if (lt) {
101 *ptm = *lt;
102 return;
103 }
104 }
105 end = '1';
106 } else {
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127 unsigned cur_year = ptm->tm_year;
128 int len = strchrnul(date_str, '.') - date_str;
129
130
131 if (len == 2 && sscanf(date_str, "%2u%2u%2u%2u""%2u%c" + 12,
132 &ptm->tm_min,
133 &end) >= 1) {
134 } else
135
136 if (len == 4 && sscanf(date_str, "%2u%2u%2u""%2u%2u%c" + 9,
137 &ptm->tm_hour,
138 &ptm->tm_min,
139 &end) >= 2) {
140 } else
141
142 if (len == 6 && sscanf(date_str, "%2u%2u""%2u%2u%2u%c" + 6,
143 &ptm->tm_mday,
144 &ptm->tm_hour,
145 &ptm->tm_min,
146 &end) >= 3) {
147 } else
148
149 if (len == 8 && sscanf(date_str, "%2u""%2u%2u%2u%2u%c" + 3,
150 &ptm->tm_mon,
151 &ptm->tm_mday,
152 &ptm->tm_hour,
153 &ptm->tm_min,
154 &end) >= 4) {
155
156 ptm->tm_mon -= 1;
157 } else
158
159 if (len == 10 && sscanf(date_str, "%2u%2u%2u%2u%2u%c",
160 &ptm->tm_year,
161 &ptm->tm_mon,
162 &ptm->tm_mday,
163 &ptm->tm_hour,
164 &ptm->tm_min,
165 &end) >= 5) {
166
167 ptm->tm_mon -= 1;
168 if ((int)cur_year >= 50) {
169
170
171 ptm->tm_year += (cur_year / 100) * 100;
172
173 if (ptm->tm_year < cur_year - 50)
174 ptm->tm_year += 100;
175
176 if (ptm->tm_year > cur_year + 50)
177 ptm->tm_year -= 100;
178 }
179 } else
180
181 if (len == 12 && sscanf(date_str, "%4u%2u%2u%2u%2u%c",
182 &ptm->tm_year,
183 &ptm->tm_mon,
184 &ptm->tm_mday,
185 &ptm->tm_hour,
186 &ptm->tm_min,
187 &end) >= 5) {
188 ptm->tm_year -= 1900;
189 ptm->tm_mon -= 1;
190 } else {
191 err:
192 bb_error_msg_and_die(bb_msg_invalid_date, date_str);
193 }
194 ptm->tm_sec = 0;
195 if (end == '.') {
196
197 if (sscanf(strchr(date_str, '.') + 1, "%u%c",
198 &ptm->tm_sec, &end) == 1)
199 end = '\0';
200
201 }
202
203
204
205
206
207 if (ptm->tm_sec > 60
208 || ptm->tm_min > 59
209 || ptm->tm_hour > 23
210 || ptm->tm_mday > 31
211 || ptm->tm_mon > 11
212 ) {
213 goto err;
214 }
215 }
216 if (end != '\0') {
217 bb_error_msg_and_die(bb_msg_invalid_date, date_str);
218 }
219}
220
221time_t FAST_FUNC validate_tm_time(const char *date_str, struct tm *ptm)
222{
223 time_t t = mktime(ptm);
224 if (t == (time_t) -1L) {
225 bb_error_msg_and_die(bb_msg_invalid_date, date_str);
226 }
227 return t;
228}
229
230static char* strftime_fmt(char *buf, unsigned len, time_t *tp, const char *fmt)
231{
232 time_t t;
233 if (!tp) {
234 tp = &t;
235 time(tp);
236 }
237
238 return buf + strftime(buf, len, fmt, localtime(tp));
239}
240
241char* FAST_FUNC strftime_HHMMSS(char *buf, unsigned len, time_t *tp)
242{
243 return strftime_fmt(buf, len, tp, "%H:%M:%S");
244}
245
246char* FAST_FUNC strftime_YYYYMMDDHHMMSS(char *buf, unsigned len, time_t *tp)
247{
248 return strftime_fmt(buf, len, tp, "%Y-%m-%d %H:%M:%S");
249}
250
251#if ENABLE_MONOTONIC_SYSCALL
252
253
254
255#ifndef CLOCK_MONOTONIC
256#define CLOCK_MONOTONIC 1
257#endif
258
259static void get_mono(struct timespec *ts)
260{
261 if (clock_gettime(CLOCK_MONOTONIC, ts))
262 bb_simple_error_msg_and_die("clock_gettime(MONOTONIC) failed");
263}
264unsigned long long FAST_FUNC monotonic_ns(void)
265{
266 struct timespec ts;
267 get_mono(&ts);
268 return ts.tv_sec * 1000000000ULL + ts.tv_nsec;
269}
270unsigned long long FAST_FUNC monotonic_us(void)
271{
272 struct timespec ts;
273 get_mono(&ts);
274 return ts.tv_sec * 1000000ULL + ts.tv_nsec/1000;
275}
276unsigned long long FAST_FUNC monotonic_ms(void)
277{
278 struct timespec ts;
279 get_mono(&ts);
280 return ts.tv_sec * 1000ULL + ts.tv_nsec/1000000;
281}
282unsigned FAST_FUNC monotonic_sec(void)
283{
284 struct timespec ts;
285 get_mono(&ts);
286 return ts.tv_sec;
287}
288
289#else
290
291unsigned long long FAST_FUNC monotonic_ns(void)
292{
293 struct timeval tv;
294 xgettimeofday(&tv);
295 return tv.tv_sec * 1000000000ULL + tv.tv_usec * 1000;
296}
297unsigned long long FAST_FUNC monotonic_us(void)
298{
299 struct timeval tv;
300 xgettimeofday(&tv);
301 return tv.tv_sec * 1000000ULL + tv.tv_usec;
302}
303unsigned long long FAST_FUNC monotonic_ms(void)
304{
305 struct timeval tv;
306 xgettimeofday(&tv);
307 return tv.tv_sec * 1000ULL + tv.tv_usec / 1000;
308}
309unsigned FAST_FUNC monotonic_sec(void)
310{
311 return time(NULL);
312}
313
314#endif
315