1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54#include "libbb.h"
55
56enum {
57 OPT_RFC2822 = (1 << 0),
58 OPT_SET = (1 << 1),
59 OPT_UTC = (1 << 2),
60 OPT_DATE = (1 << 3),
61 OPT_REFERENCE = (1 << 4),
62 OPT_TIMESPEC = (1 << 5) * ENABLE_FEATURE_DATE_ISOFMT,
63 OPT_HINT = (1 << 6) * ENABLE_FEATURE_DATE_ISOFMT,
64};
65
66static void maybe_set_utc(int opt)
67{
68 if (opt & OPT_UTC)
69 putenv((char*)"TZ=UTC0");
70}
71
72#if ENABLE_LONG_OPTS
73static const char date_longopts[] ALIGN1 =
74 "rfc-822\0" No_argument "R"
75 "rfc-2822\0" No_argument "R"
76 "set\0" Required_argument "s"
77 "utc\0" No_argument "u"
78
79 "date\0" Required_argument "d"
80 "reference\0" Required_argument "r"
81 ;
82#endif
83
84int date_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
85int date_main(int argc UNUSED_PARAM, char **argv)
86{
87 struct tm tm_time;
88 char buf_fmt_dt2str[64];
89 time_t tm;
90 unsigned opt;
91 int ifmt = -1;
92 char *date_str;
93 char *fmt_dt2str;
94 char *fmt_str2dt;
95 char *filename;
96 char *isofmt_arg = NULL;
97
98 opt_complementary = "d--s:s--d"
99 IF_FEATURE_DATE_ISOFMT(":R--I:I--R");
100 IF_LONG_OPTS(applet_long_options = date_longopts;)
101 opt = getopt32(argv, "Rs:ud:r:"
102 IF_FEATURE_DATE_ISOFMT("I::D:"),
103 &date_str, &date_str, &filename
104 IF_FEATURE_DATE_ISOFMT(, &isofmt_arg, &fmt_str2dt));
105 argv += optind;
106 maybe_set_utc(opt);
107
108 if (ENABLE_FEATURE_DATE_ISOFMT && (opt & OPT_TIMESPEC)) {
109 ifmt = 0;
110 if (isofmt_arg) {
111 static const char isoformats[] ALIGN1 =
112 "date\0""hours\0""minutes\0""seconds\0";
113 ifmt = index_in_substrings(isoformats, isofmt_arg);
114 if (ifmt < 0)
115 bb_show_usage();
116 }
117 }
118
119 fmt_dt2str = NULL;
120 if (argv[0] && argv[0][0] == '+') {
121 fmt_dt2str = &argv[0][1];
122 argv++;
123 }
124 if (!(opt & (OPT_SET | OPT_DATE))) {
125 opt |= OPT_SET;
126 date_str = argv[0];
127 if (date_str) {
128#if ENABLE_FEATURE_DATE_COMPAT
129 int len = strspn(date_str, "0123456789");
130 if (date_str[len] == '\0'
131 || (date_str[len] == '.'
132 && isdigit(date_str[len+1])
133 && isdigit(date_str[len+2])
134 && date_str[len+3] == '\0'
135 )
136 ) {
137
138
139
140
141 len -= 8;
142 if (len < 0 || len > 4 || (len & 1))
143 bb_error_msg_and_die(bb_msg_invalid_date, date_str);
144 if (len != 0) {
145 char buf[4];
146 memcpy(buf, date_str + 8, len);
147 memmove(date_str + len, date_str, 8);
148 memcpy(date_str, buf, len);
149 }
150 }
151#endif
152 argv++;
153 }
154 }
155 if (*argv)
156 bb_show_usage();
157
158
159
160
161 if (opt & OPT_REFERENCE) {
162 struct stat statbuf;
163 xstat(filename, &statbuf);
164 tm = statbuf.st_mtime;
165 } else {
166 time(&tm);
167 }
168 localtime_r(&tm, &tm_time);
169
170
171 if (date_str != NULL) {
172
173 tm_time.tm_sec = 0;
174 tm_time.tm_min = 0;
175 tm_time.tm_hour = 0;
176
177
178 if (ENABLE_FEATURE_DATE_ISOFMT && (opt & OPT_HINT)) {
179 if (strptime(date_str, fmt_str2dt, &tm_time) == NULL)
180 bb_error_msg_and_die(bb_msg_invalid_date, date_str);
181 } else {
182 parse_datestr(date_str, &tm_time);
183 }
184
185
186 tm_time.tm_isdst = -1;
187 tm = validate_tm_time(date_str, &tm_time);
188
189 maybe_set_utc(opt);
190
191
192 if ((opt & OPT_SET) && stime(&tm) < 0) {
193 bb_perror_msg("can't set date");
194 }
195 }
196
197
198
199
200 if (fmt_dt2str == NULL) {
201 int i;
202 fmt_dt2str = buf_fmt_dt2str;
203 if (ENABLE_FEATURE_DATE_ISOFMT && ifmt >= 0) {
204
205 strcpy(fmt_dt2str, "%Y-%m-%dT%H:%M:%S");
206 i = 8 + 3 * ifmt;
207 if (ifmt != 0) {
208
209 format_utc:
210 fmt_dt2str[i++] = '%';
211 fmt_dt2str[i++] = (opt & OPT_UTC) ? 'Z' : 'z';
212 }
213 fmt_dt2str[i] = '\0';
214 } else if (opt & OPT_RFC2822) {
215
216 if (ENABLE_LOCALE_SUPPORT)
217 setlocale(LC_TIME, "C");
218 strcpy(fmt_dt2str, "%a, %d %b %Y %H:%M:%S ");
219 i = sizeof("%a, %d %b %Y %H:%M:%S ")-1;
220 goto format_utc;
221 } else {
222 fmt_dt2str = (char*)"%a %b %e %H:%M:%S %Z %Y";
223 }
224 }
225
226#define date_buf bb_common_bufsiz1
227 if (*fmt_dt2str == '\0') {
228
229 date_buf[0] = '\0';
230 } else {
231
232 if (strncmp(fmt_dt2str, "%f", 2) == 0) {
233 fmt_dt2str = (char*)"%Y.%m.%d-%H:%M:%S";
234 }
235
236 strftime(date_buf, sizeof(date_buf), fmt_dt2str, &tm_time);
237 }
238 puts(date_buf);
239
240 return EXIT_SUCCESS;
241}
242