6 |
* |
* |
7 |
* Licensed under GPL version 2, see file LICENSE in this tarball for details. |
* Licensed under GPL version 2, see file LICENSE in this tarball for details. |
8 |
*/ |
*/ |
|
|
|
9 |
#include "libbb.h" |
#include "libbb.h" |
10 |
|
|
11 |
|
void 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 |
|
/* Parse input and assign appropriately to ptm */ |
18 |
|
|
19 |
|
/* HH:MM */ |
20 |
|
if (sscanf(date_str, "%u:%u%c", |
21 |
|
&ptm->tm_hour, |
22 |
|
&ptm->tm_min, |
23 |
|
&end) >= 2) { |
24 |
|
/* no adjustments needed */ |
25 |
|
} else |
26 |
|
/* mm.dd-HH:MM */ |
27 |
|
if (sscanf(date_str, "%u.%u-%u:%u%c", |
28 |
|
&ptm->tm_mon, &ptm->tm_mday, |
29 |
|
&ptm->tm_hour, &ptm->tm_min, |
30 |
|
&end) >= 4) { |
31 |
|
/* Adjust month from 1-12 to 0-11 */ |
32 |
|
ptm->tm_mon -= 1; |
33 |
|
} else |
34 |
|
/* yyyy.mm.dd-HH:MM */ |
35 |
|
if (sscanf(date_str, "%u.%u.%u-%u:%u%c", &ptm->tm_year, |
36 |
|
&ptm->tm_mon, &ptm->tm_mday, |
37 |
|
&ptm->tm_hour, &ptm->tm_min, |
38 |
|
&end) >= 5) { |
39 |
|
ptm->tm_year -= 1900; /* Adjust years */ |
40 |
|
ptm->tm_mon -= 1; /* Adjust month from 1-12 to 0-11 */ |
41 |
|
} else |
42 |
|
/* yyyy-mm-dd HH:MM */ |
43 |
|
if (sscanf(date_str, "%u-%u-%u %u:%u%c", &ptm->tm_year, |
44 |
|
&ptm->tm_mon, &ptm->tm_mday, |
45 |
|
&ptm->tm_hour, &ptm->tm_min, |
46 |
|
&end) >= 5) { |
47 |
|
ptm->tm_year -= 1900; /* Adjust years */ |
48 |
|
ptm->tm_mon -= 1; /* Adjust month from 1-12 to 0-11 */ |
49 |
|
//TODO: coreutils 6.9 also accepts "yyyy-mm-dd HH" (no minutes) |
50 |
|
} else { |
51 |
|
bb_error_msg_and_die(bb_msg_invalid_date, date_str); |
52 |
|
} |
53 |
|
if (end == ':') { |
54 |
|
/* xxx:SS */ |
55 |
|
if (sscanf(last_colon + 1, "%u%c", &ptm->tm_sec, &end) == 1) |
56 |
|
end = '\0'; |
57 |
|
/* else end != NUL and we error out */ |
58 |
|
} |
59 |
|
} else { |
60 |
|
/* Googled the following on an old date manpage: |
61 |
|
* |
62 |
|
* The canonical representation for setting the date/time is: |
63 |
|
* cc Century (either 19 or 20) |
64 |
|
* yy Year in abbreviated form (e.g. 89, 06) |
65 |
|
* mm Numeric month, a number from 1 to 12 |
66 |
|
* dd Day, a number from 1 to 31 |
67 |
|
* HH Hour, a number from 0 to 23 |
68 |
|
* MM Minutes, a number from 0 to 59 |
69 |
|
* .SS Seconds, a number from 0 to 61 (with leap seconds) |
70 |
|
* Everything but the minutes is optional |
71 |
|
* |
72 |
|
* This coincides with the format of "touch -t TIME" |
73 |
|
*/ |
74 |
|
int len = strchrnul(date_str, '.') - date_str; |
75 |
|
|
76 |
|
/* MM[.SS] */ |
77 |
|
if (len == 2 && sscanf(date_str, "%2u%2u%2u%2u""%2u%c" + 12, |
78 |
|
&ptm->tm_min, |
79 |
|
&end) >= 1) { |
80 |
|
} else |
81 |
|
/* HHMM[.SS] */ |
82 |
|
if (len == 4 && sscanf(date_str, "%2u%2u%2u""%2u%2u%c" + 9, |
83 |
|
&ptm->tm_hour, |
84 |
|
&ptm->tm_min, |
85 |
|
&end) >= 2) { |
86 |
|
} else |
87 |
|
/* ddHHMM[.SS] */ |
88 |
|
if (len == 6 && sscanf(date_str, "%2u%2u""%2u%2u%2u%c" + 6, |
89 |
|
&ptm->tm_mday, |
90 |
|
&ptm->tm_hour, |
91 |
|
&ptm->tm_min, |
92 |
|
&end) >= 3) { |
93 |
|
} else |
94 |
|
/* mmddHHMM[.SS] */ |
95 |
|
if (len == 8 && sscanf(date_str, "%2u""%2u%2u%2u%2u%c" + 3, |
96 |
|
&ptm->tm_mon, |
97 |
|
&ptm->tm_mday, |
98 |
|
&ptm->tm_hour, |
99 |
|
&ptm->tm_min, |
100 |
|
&end) >= 4) { |
101 |
|
/* Adjust month from 1-12 to 0-11 */ |
102 |
|
ptm->tm_mon -= 1; |
103 |
|
} else |
104 |
|
/* yymmddHHMM[.SS] */ |
105 |
|
if (len == 10 && sscanf(date_str, "%2u%2u%2u%2u%2u%c", |
106 |
|
&ptm->tm_year, |
107 |
|
&ptm->tm_mon, |
108 |
|
&ptm->tm_mday, |
109 |
|
&ptm->tm_hour, |
110 |
|
&ptm->tm_min, |
111 |
|
&end) >= 5) { |
112 |
|
/* Adjust month from 1-12 to 0-11 */ |
113 |
|
ptm->tm_mon -= 1; |
114 |
|
} else |
115 |
|
/* ccyymmddHHMM[.SS] */ |
116 |
|
if (len == 12 && sscanf(date_str, "%4u%2u%2u%2u%2u%c", |
117 |
|
&ptm->tm_year, |
118 |
|
&ptm->tm_mon, |
119 |
|
&ptm->tm_mday, |
120 |
|
&ptm->tm_hour, |
121 |
|
&ptm->tm_min, |
122 |
|
&end) >= 5) { |
123 |
|
ptm->tm_year -= 1900; /* Adjust years */ |
124 |
|
ptm->tm_mon -= 1; /* Adjust month from 1-12 to 0-11 */ |
125 |
|
} else { |
126 |
|
bb_error_msg_and_die(bb_msg_invalid_date, date_str); |
127 |
|
} |
128 |
|
if (end == '.') { |
129 |
|
/* xxx.SS */ |
130 |
|
if (sscanf(strchr(date_str, '.') + 1, "%u%c", |
131 |
|
&ptm->tm_sec, &end) == 1) |
132 |
|
end = '\0'; |
133 |
|
/* else end != NUL and we error out */ |
134 |
|
} |
135 |
|
} |
136 |
|
if (end != '\0') { |
137 |
|
bb_error_msg_and_die(bb_msg_invalid_date, date_str); |
138 |
|
} |
139 |
|
} |
140 |
|
|
141 |
|
time_t FAST_FUNC validate_tm_time(const char *date_str, struct tm *ptm) |
142 |
|
{ |
143 |
|
time_t t = mktime(ptm); |
144 |
|
if (t == (time_t) -1L) { |
145 |
|
bb_error_msg_and_die(bb_msg_invalid_date, date_str); |
146 |
|
} |
147 |
|
return t; |
148 |
|
} |
149 |
|
|
150 |
#if ENABLE_MONOTONIC_SYSCALL |
#if ENABLE_MONOTONIC_SYSCALL |
151 |
|
|
152 |
#include <sys/syscall.h> |
#include <sys/syscall.h> |
175 |
get_mono(&ts); |
get_mono(&ts); |
176 |
return ts.tv_sec * 1000000ULL + ts.tv_nsec/1000; |
return ts.tv_sec * 1000000ULL + ts.tv_nsec/1000; |
177 |
} |
} |
178 |
|
unsigned long long FAST_FUNC monotonic_ms(void) |
179 |
|
{ |
180 |
|
struct timespec ts; |
181 |
|
get_mono(&ts); |
182 |
|
return ts.tv_sec * 1000ULL + ts.tv_nsec/1000000; |
183 |
|
} |
184 |
unsigned FAST_FUNC monotonic_sec(void) |
unsigned FAST_FUNC monotonic_sec(void) |
185 |
{ |
{ |
186 |
struct timespec ts; |
struct timespec ts; |
202 |
gettimeofday(&tv, NULL); |
gettimeofday(&tv, NULL); |
203 |
return tv.tv_sec * 1000000ULL + tv.tv_usec; |
return tv.tv_sec * 1000000ULL + tv.tv_usec; |
204 |
} |
} |
205 |
|
unsigned long long FAST_FUNC monotonic_ms(void) |
206 |
|
{ |
207 |
|
struct timeval tv; |
208 |
|
gettimeofday(&tv, NULL); |
209 |
|
return tv.tv_sec * 1000ULL + tv.tv_usec / 1000; |
210 |
|
} |
211 |
unsigned FAST_FUNC monotonic_sec(void) |
unsigned FAST_FUNC monotonic_sec(void) |
212 |
{ |
{ |
213 |
return time(NULL); |
return time(NULL); |