source: MondoRescue/branches/3.3/mindi-busybox/libbb/time.c@ 3865

Last change on this file since 3865 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

  • Property svn:eol-style set to native
File size: 7.7 KB
RevLine 
[1765]1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
[2725]5 * Copyright (C) 2007 Denys Vlasenko
[1765]6 *
[2725]7 * Licensed under GPLv2, see file LICENSE in this source tree.
[1765]8 */
9#include "libbb.h"
10
[2725]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 /* Parse input and assign appropriately to ptm */
18#if ENABLE_DESKTOP
19 const char *endp;
20#endif
21
22 /* HH:MM */
23 if (sscanf(date_str, "%u:%u%c",
24 &ptm->tm_hour,
25 &ptm->tm_min,
[3621]26 &end) >= 2
27 ) {
[2725]28 /* no adjustments needed */
29 } else
30 /* mm.dd-HH:MM */
31 if (sscanf(date_str, "%u.%u-%u:%u%c",
32 &ptm->tm_mon, &ptm->tm_mday,
33 &ptm->tm_hour, &ptm->tm_min,
[3621]34 &end) >= 4
35 ) {
[2725]36 /* Adjust month from 1-12 to 0-11 */
37 ptm->tm_mon -= 1;
38 } else
39 /* yyyy.mm.dd-HH:MM */
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,
[3621]43 &end) >= 5
[2725]44 /* yyyy-mm-dd HH:MM */
[3621]45 || sscanf(date_str, "%u-%u-%u %u:%u%c", &ptm->tm_year,
[2725]46 &ptm->tm_mon, &ptm->tm_mday,
47 &ptm->tm_hour, &ptm->tm_min,
[3621]48 &end) >= 5
49 ) {
[2725]50 ptm->tm_year -= 1900; /* Adjust years */
51 ptm->tm_mon -= 1; /* Adjust month from 1-12 to 0-11 */
52 } else
53#if ENABLE_DESKTOP /* strptime is BIG: ~1k in uclibc, ~10k in glibc */
54 /* month_name d HH:MM:SS YYYY. Supported by GNU date */
55 if ((endp = strptime(date_str, "%b %d %T %Y", ptm)) != NULL
56 && *endp == '\0'
57 ) {
58 return; /* don't fall through to end == ":" check */
59 } else
60#endif
61 {
62 bb_error_msg_and_die(bb_msg_invalid_date, date_str);
63 }
64 if (end == ':') {
65 /* xxx:SS */
66 if (sscanf(last_colon + 1, "%u%c", &ptm->tm_sec, &end) == 1)
67 end = '\0';
68 /* else end != NUL and we error out */
69 }
[3621]70 } else
71 if (strchr(date_str, '-')
72 /* Why strchr('-') check?
73 * sscanf below will trash ptm->tm_year, this breaks
74 * if parse_str is "10101010" (iow, "MMddhhmm" form)
75 * because we destroy year. Do these sscanf
76 * only if we saw a dash in parse_str.
77 */
78 /* yyyy-mm-dd HH */
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 /* yyyy-mm-dd */
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; /* Adjust years */
90 ptm->tm_mon -= 1; /* Adjust month from 1-12 to 0-11 */
91 } else
92 if (date_str[0] == '@') {
[2725]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 /* Googled the following on an old date manpage:
104 *
105 * The canonical representation for setting the date/time is:
106 * cc Century (either 19 or 20)
107 * yy Year in abbreviated form (e.g. 89, 06)
108 * mm Numeric month, a number from 1 to 12
109 * dd Day, a number from 1 to 31
110 * HH Hour, a number from 0 to 23
111 * MM Minutes, a number from 0 to 59
112 * .SS Seconds, a number from 0 to 61 (with leap seconds)
113 * Everything but the minutes is optional
114 *
[3232]115 * "touch -t DATETIME" format: [[[[[YY]YY]MM]DD]hh]mm[.ss]
116 * Some, but not all, Unix "date DATETIME" commands
117 * move [[YY]YY] past minutes mm field (!).
118 * Coreutils date does it, and SUS mandates it.
119 * (date -s DATETIME does not support this format. lovely!)
120 * In bbox, this format is special-cased in date applet
121 * (IOW: this function assumes "touch -t" format).
[2725]122 */
[3232]123 unsigned cur_year = ptm->tm_year;
[2725]124 int len = strchrnul(date_str, '.') - date_str;
125
126 /* MM[.SS] */
127 if (len == 2 && sscanf(date_str, "%2u%2u%2u%2u""%2u%c" + 12,
128 &ptm->tm_min,
129 &end) >= 1) {
130 } else
131 /* HHMM[.SS] */
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 /* ddHHMM[.SS] */
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 /* mmddHHMM[.SS] */
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 /* Adjust month from 1-12 to 0-11 */
152 ptm->tm_mon -= 1;
153 } else
154 /* yymmddHHMM[.SS] */
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 /* Adjust month from 1-12 to 0-11 */
163 ptm->tm_mon -= 1;
[3232]164 if ((int)cur_year >= 50) { /* >= 1950 */
165 /* Adjust year: */
166 /* 1. Put it in the current century */
167 ptm->tm_year += (cur_year / 100) * 100;
168 /* 2. If too far in the past, +100 years */
169 if (ptm->tm_year < cur_year - 50)
170 ptm->tm_year += 100;
171 /* 3. If too far in the future, -100 years */
172 if (ptm->tm_year > cur_year + 50)
173 ptm->tm_year -= 100;
174 }
[2725]175 } else
176 /* ccyymmddHHMM[.SS] */
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; /* Adjust years */
185 ptm->tm_mon -= 1; /* Adjust month from 1-12 to 0-11 */
186 } else {
187 bb_error_msg_and_die(bb_msg_invalid_date, date_str);
188 }
[3621]189 ptm->tm_sec = 0; /* assume zero if [.SS] is not given */
[2725]190 if (end == '.') {
191 /* xxx.SS */
192 if (sscanf(strchr(date_str, '.') + 1, "%u%c",
193 &ptm->tm_sec, &end) == 1)
194 end = '\0';
195 /* else end != NUL and we error out */
196 }
197 }
198 if (end != '\0') {
199 bb_error_msg_and_die(bb_msg_invalid_date, date_str);
200 }
201}
202
203time_t FAST_FUNC validate_tm_time(const char *date_str, struct tm *ptm)
204{
205 time_t t = mktime(ptm);
206 if (t == (time_t) -1L) {
207 bb_error_msg_and_die(bb_msg_invalid_date, date_str);
208 }
209 return t;
210}
211
[3621]212static char* strftime_fmt(char *buf, unsigned len, time_t *tp, const char *fmt)
213{
214 time_t t;
215 if (!tp) {
216 tp = &t;
217 time(tp);
218 }
219 /* Returns pointer to NUL */
220 return buf + strftime(buf, len, fmt, localtime(tp));
221}
222
223char* FAST_FUNC strftime_HHMMSS(char *buf, unsigned len, time_t *tp)
224{
225 return strftime_fmt(buf, len, tp, "%H:%M:%S");
226}
227
228char* FAST_FUNC strftime_YYYYMMDDHHMMSS(char *buf, unsigned len, time_t *tp)
229{
230 return strftime_fmt(buf, len, tp, "%Y-%m-%d %H:%M:%S");
231}
232
[1765]233#if ENABLE_MONOTONIC_SYSCALL
[2725]234
[1765]235#include <sys/syscall.h>
[2725]236/* Old glibc (< 2.3.4) does not provide this constant. We use syscall
237 * directly so this definition is safe. */
238#ifndef CLOCK_MONOTONIC
239#define CLOCK_MONOTONIC 1
240#endif
[1765]241
242/* libc has incredibly messy way of doing this,
243 * typically requiring -lrt. We just skip all this mess */
[2725]244static void get_mono(struct timespec *ts)
[1765]245{
[2725]246 if (syscall(__NR_clock_gettime, CLOCK_MONOTONIC, ts))
247 bb_error_msg_and_die("clock_gettime(MONOTONIC) failed");
248}
249unsigned long long FAST_FUNC monotonic_ns(void)
250{
[1765]251 struct timespec ts;
[2725]252 get_mono(&ts);
253 return ts.tv_sec * 1000000000ULL + ts.tv_nsec;
254}
255unsigned long long FAST_FUNC monotonic_us(void)
256{
257 struct timespec ts;
258 get_mono(&ts);
[1765]259 return ts.tv_sec * 1000000ULL + ts.tv_nsec/1000;
260}
[2725]261unsigned long long FAST_FUNC monotonic_ms(void)
[1765]262{
263 struct timespec ts;
[2725]264 get_mono(&ts);
265 return ts.tv_sec * 1000ULL + ts.tv_nsec/1000000;
266}
267unsigned FAST_FUNC monotonic_sec(void)
268{
269 struct timespec ts;
270 get_mono(&ts);
[1765]271 return ts.tv_sec;
272}
[2725]273
[1765]274#else
[2725]275
276unsigned long long FAST_FUNC monotonic_ns(void)
[1765]277{
278 struct timeval tv;
279 gettimeofday(&tv, NULL);
[2725]280 return tv.tv_sec * 1000000000ULL + tv.tv_usec * 1000;
281}
282unsigned long long FAST_FUNC monotonic_us(void)
283{
284 struct timeval tv;
285 gettimeofday(&tv, NULL);
[1765]286 return tv.tv_sec * 1000000ULL + tv.tv_usec;
287}
[2725]288unsigned long long FAST_FUNC monotonic_ms(void)
[1765]289{
[2725]290 struct timeval tv;
291 gettimeofday(&tv, NULL);
292 return tv.tv_sec * 1000ULL + tv.tv_usec / 1000;
293}
294unsigned FAST_FUNC monotonic_sec(void)
295{
[1765]296 return time(NULL);
297}
[2725]298
[1765]299#endif
Note: See TracBrowser for help on using the repository browser.