Contents of /tags/mkinitrd-6_1_12/busybox/coreutils/date.c
Parent Directory | Revision Log
Revision 939 -
(show annotations)
(download)
Tue Nov 17 21:24:51 2009 UTC (14 years, 10 months ago) by niro
File MIME type: text/plain
File size: 6801 byte(s)
Tue Nov 17 21:24:51 2009 UTC (14 years, 10 months ago) by niro
File MIME type: text/plain
File size: 6801 byte(s)
tagged 'mkinitrd-6_1_12'
1 | /* vi: set sw=4 ts=4: */ |
2 | /* |
3 | * Mini date implementation for busybox |
4 | * |
5 | * by Matthew Grant <grantma@anathoth.gen.nz> |
6 | * |
7 | * iso-format handling added by Robert Griebl <griebl@gmx.de> |
8 | * bugfixes and cleanup by Bernhard Reutner-Fischer |
9 | * |
10 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. |
11 | */ |
12 | |
13 | #include "libbb.h" |
14 | |
15 | /* This 'date' command supports only 2 time setting formats, |
16 | all the GNU strftime stuff (its in libc, lets use it), |
17 | setting time using UTC and displaying it, as well as |
18 | an RFC 2822 compliant date output for shell scripting |
19 | mail commands */ |
20 | |
21 | /* Input parsing code is always bulky - used heavy duty libc stuff as |
22 | much as possible, missed out a lot of bounds checking */ |
23 | |
24 | /* Default input handling to save surprising some people */ |
25 | |
26 | |
27 | #define DATE_OPT_RFC2822 0x01 |
28 | #define DATE_OPT_SET 0x02 |
29 | #define DATE_OPT_UTC 0x04 |
30 | #define DATE_OPT_DATE 0x08 |
31 | #define DATE_OPT_REFERENCE 0x10 |
32 | #define DATE_OPT_TIMESPEC 0x20 |
33 | #define DATE_OPT_HINT 0x40 |
34 | |
35 | static void maybe_set_utc(int opt) |
36 | { |
37 | if (opt & DATE_OPT_UTC) |
38 | putenv((char*)"TZ=UTC0"); |
39 | } |
40 | |
41 | int date_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
42 | int date_main(int argc UNUSED_PARAM, char **argv) |
43 | { |
44 | struct tm tm_time; |
45 | time_t tm; |
46 | unsigned opt; |
47 | int ifmt = -1; |
48 | char *date_str; |
49 | char *fmt_dt2str; |
50 | char *fmt_str2dt; |
51 | char *filename; |
52 | char *isofmt_arg = NULL; |
53 | |
54 | opt_complementary = "d--s:s--d" |
55 | USE_FEATURE_DATE_ISOFMT(":R--I:I--R"); |
56 | opt = getopt32(argv, "Rs:ud:r:" |
57 | USE_FEATURE_DATE_ISOFMT("I::D:"), |
58 | &date_str, &date_str, &filename |
59 | USE_FEATURE_DATE_ISOFMT(, &isofmt_arg, &fmt_str2dt)); |
60 | argv += optind; |
61 | maybe_set_utc(opt); |
62 | |
63 | if (ENABLE_FEATURE_DATE_ISOFMT && (opt & DATE_OPT_TIMESPEC)) { |
64 | ifmt = 0; /* default is date */ |
65 | if (isofmt_arg) { |
66 | static const char isoformats[] ALIGN1 = |
67 | "date\0""hours\0""minutes\0""seconds\0"; |
68 | ifmt = index_in_strings(isoformats, isofmt_arg); |
69 | if (ifmt < 0) |
70 | bb_show_usage(); |
71 | } |
72 | } |
73 | |
74 | fmt_dt2str = NULL; |
75 | if (argv[0] && argv[0][0] == '+') { |
76 | fmt_dt2str = &argv[0][1]; /* Skip over the '+' */ |
77 | argv++; |
78 | } |
79 | if (!(opt & (DATE_OPT_SET | DATE_OPT_DATE))) { |
80 | opt |= DATE_OPT_SET; |
81 | date_str = argv[0]; /* can be NULL */ |
82 | if (date_str) |
83 | argv++; |
84 | } |
85 | if (*argv) |
86 | bb_show_usage(); |
87 | |
88 | /* Now we have parsed all the information except the date format |
89 | which depends on whether the clock is being set or read */ |
90 | |
91 | if (opt & DATE_OPT_REFERENCE) { |
92 | struct stat statbuf; |
93 | xstat(filename, &statbuf); |
94 | tm = statbuf.st_mtime; |
95 | } else |
96 | time(&tm); |
97 | memcpy(&tm_time, localtime(&tm), sizeof(tm_time)); |
98 | |
99 | /* If date string is given, update tm_time, and maybe set date */ |
100 | if (date_str != NULL) { |
101 | /* Zero out fields - take her back to midnight! */ |
102 | tm_time.tm_sec = 0; |
103 | tm_time.tm_min = 0; |
104 | tm_time.tm_hour = 0; |
105 | |
106 | /* Process any date input to UNIX time since 1 Jan 1970 */ |
107 | if (ENABLE_FEATURE_DATE_ISOFMT && (opt & DATE_OPT_HINT)) { |
108 | if (strptime(date_str, fmt_str2dt, &tm_time) == NULL) |
109 | bb_error_msg_and_die(bb_msg_invalid_date, date_str); |
110 | } else { |
111 | char end = '\0'; |
112 | const char *last_colon = strrchr(date_str, ':'); |
113 | |
114 | if (last_colon != NULL) { |
115 | /* Parse input and assign appropriately to tm_time */ |
116 | |
117 | if (sscanf(date_str, "%u:%u%c", |
118 | &tm_time.tm_hour, |
119 | &tm_time.tm_min, |
120 | &end) >= 2) { |
121 | /* no adjustments needed */ |
122 | } else if (sscanf(date_str, "%u.%u-%u:%u%c", |
123 | &tm_time.tm_mon, &tm_time.tm_mday, |
124 | &tm_time.tm_hour, &tm_time.tm_min, |
125 | &end) >= 4) { |
126 | /* Adjust dates from 1-12 to 0-11 */ |
127 | tm_time.tm_mon -= 1; |
128 | } else if (sscanf(date_str, "%u.%u.%u-%u:%u%c", &tm_time.tm_year, |
129 | &tm_time.tm_mon, &tm_time.tm_mday, |
130 | &tm_time.tm_hour, &tm_time.tm_min, |
131 | &end) >= 5) { |
132 | tm_time.tm_year -= 1900; /* Adjust years */ |
133 | tm_time.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */ |
134 | } else if (sscanf(date_str, "%u-%u-%u %u:%u%c", &tm_time.tm_year, |
135 | &tm_time.tm_mon, &tm_time.tm_mday, |
136 | &tm_time.tm_hour, &tm_time.tm_min, |
137 | &end) >= 5) { |
138 | tm_time.tm_year -= 1900; /* Adjust years */ |
139 | tm_time.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */ |
140 | //TODO: coreutils 6.9 also accepts "YYYY-MM-DD HH" (no minutes) |
141 | } else { |
142 | bb_error_msg_and_die(bb_msg_invalid_date, date_str); |
143 | } |
144 | if (end == ':') { |
145 | if (sscanf(last_colon + 1, "%u%c", &tm_time.tm_sec, &end) == 1) |
146 | end = '\0'; |
147 | /* else end != NUL and we error out */ |
148 | } |
149 | } else { |
150 | if (sscanf(date_str, "%2u%2u%2u%2u%u%c", &tm_time.tm_mon, |
151 | &tm_time.tm_mday, &tm_time.tm_hour, &tm_time.tm_min, |
152 | &tm_time.tm_year, &end) < 4) |
153 | bb_error_msg_and_die(bb_msg_invalid_date, date_str); |
154 | /* correct for century - minor Y2K problem here? */ |
155 | if (tm_time.tm_year >= 1900) { |
156 | tm_time.tm_year -= 1900; |
157 | } |
158 | /* adjust date */ |
159 | tm_time.tm_mon -= 1; |
160 | if (end == '.') { |
161 | if (sscanf(strchr(date_str, '.') + 1, "%u%c", |
162 | &tm_time.tm_sec, &end) == 1) |
163 | end = '\0'; |
164 | /* else end != NUL and we error out */ |
165 | } |
166 | } |
167 | if (end != '\0') { |
168 | bb_error_msg_and_die(bb_msg_invalid_date, date_str); |
169 | } |
170 | } |
171 | /* Correct any day of week and day of year etc. fields */ |
172 | tm_time.tm_isdst = -1; /* Be sure to recheck dst. */ |
173 | tm = mktime(&tm_time); |
174 | if (tm < 0) { |
175 | bb_error_msg_and_die(bb_msg_invalid_date, date_str); |
176 | } |
177 | maybe_set_utc(opt); |
178 | |
179 | /* if setting time, set it */ |
180 | if ((opt & DATE_OPT_SET) && stime(&tm) < 0) { |
181 | bb_perror_msg("cannot set date"); |
182 | } |
183 | } |
184 | |
185 | /* Display output */ |
186 | |
187 | /* Deal with format string */ |
188 | if (fmt_dt2str == NULL) { |
189 | int i; |
190 | fmt_dt2str = xzalloc(32); |
191 | if (ENABLE_FEATURE_DATE_ISOFMT && ifmt >= 0) { |
192 | strcpy(fmt_dt2str, "%Y-%m-%d"); |
193 | if (ifmt > 0) { |
194 | i = 8; |
195 | fmt_dt2str[i++] = 'T'; |
196 | fmt_dt2str[i++] = '%'; |
197 | fmt_dt2str[i++] = 'H'; |
198 | if (ifmt > 1) { |
199 | fmt_dt2str[i++] = ':'; |
200 | fmt_dt2str[i++] = '%'; |
201 | fmt_dt2str[i++] = 'M'; |
202 | if (ifmt > 2) { |
203 | fmt_dt2str[i++] = ':'; |
204 | fmt_dt2str[i++] = '%'; |
205 | fmt_dt2str[i++] = 'S'; |
206 | } |
207 | } |
208 | format_utc: |
209 | fmt_dt2str[i++] = '%'; |
210 | fmt_dt2str[i] = (opt & DATE_OPT_UTC) ? 'Z' : 'z'; |
211 | } |
212 | } else if (opt & DATE_OPT_RFC2822) { |
213 | /* Undo busybox.c for date -R */ |
214 | if (ENABLE_LOCALE_SUPPORT) |
215 | setlocale(LC_TIME, "C"); |
216 | strcpy(fmt_dt2str, "%a, %d %b %Y %H:%M:%S "); |
217 | i = 22; |
218 | goto format_utc; |
219 | } else /* default case */ |
220 | fmt_dt2str = (char*)"%a %b %e %H:%M:%S %Z %Y"; |
221 | } |
222 | |
223 | #define date_buf bb_common_bufsiz1 |
224 | if (*fmt_dt2str == '\0') { |
225 | /* With no format string, just print a blank line */ |
226 | date_buf[0] = '\0'; |
227 | } else { |
228 | /* Handle special conversions */ |
229 | if (strncmp(fmt_dt2str, "%f", 2) == 0) { |
230 | fmt_dt2str = (char*)"%Y.%m.%d-%H:%M:%S"; |
231 | } |
232 | |
233 | /* Generate output string */ |
234 | strftime(date_buf, sizeof(date_buf), fmt_dt2str, &tm_time); |
235 | } |
236 | puts(date_buf); |
237 | |
238 | return EXIT_SUCCESS; |
239 | } |