Changeset 2725 in MondoRescue for branches/2.2.9/mindi-busybox/coreutils/date.c
- Timestamp:
- Feb 25, 2011, 9:26:54 PM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/2.2.9/mindi-busybox/coreutils/date.c
r1765 r2725 6 6 * 7 7 * iso-format handling added by Robert Griebl <griebl@gmx.de> 8 * bugfixes and cleanup by Bernhard Fischer8 * bugfixes and cleanup by Bernhard Reutner-Fischer 9 9 * 10 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.10 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 11 11 */ 12 13 #include "libbb.h"14 12 15 13 /* This 'date' command supports only 2 time setting formats, … … 22 20 much as possible, missed out a lot of bounds checking */ 23 21 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 22 //applet:IF_DATE(APPLET(date, _BB_DIR_BIN, _BB_SUID_DROP)) 23 24 //kbuild:lib-$(CONFIG_DATE) += date.o 25 26 //config:config DATE 27 //config: bool "date" 28 //config: default y 29 //config: help 30 //config: date is used to set the system date or display the 31 //config: current time in the given format. 32 //config: 33 //config:config FEATURE_DATE_ISOFMT 34 //config: bool "Enable ISO date format output (-I)" 35 //config: default y 36 //config: depends on DATE 37 //config: help 38 //config: Enable option (-I) to output an ISO-8601 compliant 39 //config: date/time string. 40 //config: 41 //config:# defaults to "no": stat's nanosecond field is a bit non-portable 42 //config:config FEATURE_DATE_NANO 43 //config: bool "Support %[num]N nanosecond format specifier" 44 //config: default n 45 //config: depends on DATE && PLATFORM_LINUX # syscall(__NR_clock_gettime) 46 //config: help 47 //config: Support %[num]N format specifier. Adds ~250 bytes of code. 48 //config: 49 //config:config FEATURE_DATE_COMPAT 50 //config: bool "Support weird 'date MMDDhhmm[[YY]YY][.ss]' format" 51 //config: default y 52 //config: depends on DATE 53 //config: help 54 //config: System time can be set by 'date -s DATE' and simply 'date DATE', 55 //config: but formats of DATE string are different. 'date DATE' accepts 56 //config: a rather weird MMDDhhmm[[YY]YY][.ss] format with completely 57 //config: unnatural placement of year between minutes and seconds. 58 //config: date -s (and other commands like touch -d) use more sensible 59 //config: formats (for one, ISO format YYYY-MM-DD hh:mm:ss.ssssss). 60 //config: 61 //config: With this option off, 'date DATE' is 'date -s DATE' support 62 //config: the same format. With it on, 'date DATE' additionally supports 63 //config: MMDDhhmm[[YY]YY][.ss] format. 64 65 /* GNU coreutils 6.9 man page: 66 * date [OPTION]... [+FORMAT] 67 * date [-u|--utc|--universal] [MMDDhhmm[[CC]YY][.ss]] 68 * -d, --date=STRING 69 * display time described by STRING, not `now' 70 * -f, --file=DATEFILE 71 * like --date once for each line of DATEFILE 72 * -r, --reference=FILE 73 * display the last modification time of FILE 74 * -R, --rfc-2822 75 * output date and time in RFC 2822 format. 76 * Example: Mon, 07 Aug 2006 12:34:56 -0600 77 * --rfc-3339=TIMESPEC 78 * output date and time in RFC 3339 format. 79 * TIMESPEC='date', 'seconds', or 'ns' 80 * Date and time components are separated by a single space: 81 * 2006-08-07 12:34:56-06:00 82 * -s, --set=STRING 83 * set time described by STRING 84 * -u, --utc, --universal 85 * print or set Coordinated Universal Time 86 * 87 * Busybox: 88 * long options are not supported 89 * -f is not supported 90 * -I seems to roughly match --rfc-3339, but -I has _optional_ param 91 * (thus "-I seconds" doesn't work, only "-Iseconds"), 92 * and does not support -Ins 93 * -D FMT is a bbox extension for _input_ conversion of -d DATE 94 */ 95 96 //usage:#define date_trivial_usage 97 //usage: "[OPTIONS] [+FMT] [TIME]" 98 //usage:#define date_full_usage "\n\n" 99 //usage: "Display time (using +FMT), or set time\n" 100 //usage: "\nOptions:" 101 //usage: IF_NOT_LONG_OPTS( 102 //usage: "\n [-s] TIME Set time to TIME" 103 //usage: "\n -u Work in UTC (don't convert to local time)" 104 //usage: "\n -R Output RFC-2822 compliant date string" 105 //usage: ) IF_LONG_OPTS( 106 //usage: "\n [-s,--set] TIME Set time to TIME" 107 //usage: "\n -u,--utc Work in UTC (don't convert to local time)" 108 //usage: "\n -R,--rfc-2822 Output RFC-2822 compliant date string" 109 //usage: ) 110 //usage: IF_FEATURE_DATE_ISOFMT( 111 //usage: "\n -I[SPEC] Output ISO-8601 compliant date string" 112 //usage: "\n SPEC='date' (default) for date only," 113 //usage: "\n 'hours', 'minutes', or 'seconds' for date and" 114 //usage: "\n time to the indicated precision" 115 //usage: ) 116 //usage: IF_NOT_LONG_OPTS( 117 //usage: "\n -r FILE Display last modification time of FILE" 118 //usage: "\n -d TIME Display TIME, not 'now'" 119 //usage: ) IF_LONG_OPTS( 120 //usage: "\n -r,--reference FILE Display last modification time of FILE" 121 //usage: "\n -d,--date TIME Display TIME, not 'now'" 122 //usage: ) 123 //usage: IF_FEATURE_DATE_ISOFMT( 124 //usage: "\n -D FMT Use FMT for -d TIME conversion" 125 //usage: ) 126 //usage: "\n" 127 //usage: "\nRecognized TIME formats:" 128 //usage: "\n hh:mm[:ss]" 129 //usage: "\n [YYYY.]MM.DD-hh:mm[:ss]" 130 //usage: "\n YYYY-MM-DD hh:mm[:ss]" 131 //usage: "\n [[[[[YY]YY]MM]DD]hh]mm[.ss]" 132 //usage: 133 //usage:#define date_example_usage 134 //usage: "$ date\n" 135 //usage: "Wed Apr 12 18:52:41 MDT 2000\n" 136 137 #include "libbb.h" 138 #if ENABLE_FEATURE_DATE_NANO 139 # include <sys/syscall.h> 140 #endif 141 142 enum { 143 OPT_RFC2822 = (1 << 0), /* R */ 144 OPT_SET = (1 << 1), /* s */ 145 OPT_UTC = (1 << 2), /* u */ 146 OPT_DATE = (1 << 3), /* d */ 147 OPT_REFERENCE = (1 << 4), /* r */ 148 OPT_TIMESPEC = (1 << 5) * ENABLE_FEATURE_DATE_ISOFMT, /* I */ 149 OPT_HINT = (1 << 6) * ENABLE_FEATURE_DATE_ISOFMT, /* D */ 150 }; 34 151 35 152 static void maybe_set_utc(int opt) 36 153 { 37 if (opt & DATE_OPT_UTC)154 if (opt & OPT_UTC) 38 155 putenv((char*)"TZ=UTC0"); 39 156 } 40 157 41 int date_main(int argc, char **argv); 42 int date_main(int argc, char **argv) 158 #if ENABLE_LONG_OPTS 159 static const char date_longopts[] ALIGN1 = 160 "rfc-822\0" No_argument "R" 161 "rfc-2822\0" No_argument "R" 162 "set\0" Required_argument "s" 163 "utc\0" No_argument "u" 164 /* "universal\0" No_argument "u" */ 165 "date\0" Required_argument "d" 166 "reference\0" Required_argument "r" 167 ; 168 #endif 169 170 int date_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 171 int date_main(int argc UNUSED_PARAM, char **argv) 43 172 { 44 time_t tm;173 struct timespec ts; 45 174 struct tm tm_time; 175 char buf_fmt_dt2str[64]; 46 176 unsigned opt; 47 177 int ifmt = -1; 48 char *date_str = NULL;49 char * date_fmt = NULL;50 char *f ilename = NULL;51 char * isofmt_arg;52 char * hintfmt_arg;178 char *date_str; 179 char *fmt_dt2str; 180 char *fmt_str2dt; 181 char *filename; 182 char *isofmt_arg = NULL; 53 183 54 184 opt_complementary = "d--s:s--d" 55 USE_FEATURE_DATE_ISOFMT(":R--I:I--R"); 185 IF_FEATURE_DATE_ISOFMT(":R--I:I--R"); 186 IF_LONG_OPTS(applet_long_options = date_longopts;) 56 187 opt = getopt32(argv, "Rs:ud:r:" 57 USE_FEATURE_DATE_ISOFMT("I::D:"),188 IF_FEATURE_DATE_ISOFMT("I::D:"), 58 189 &date_str, &date_str, &filename 59 USE_FEATURE_DATE_ISOFMT(, &isofmt_arg, &hintfmt_arg)); 190 IF_FEATURE_DATE_ISOFMT(, &isofmt_arg, &fmt_str2dt)); 191 argv += optind; 60 192 maybe_set_utc(opt); 61 193 62 if (ENABLE_FEATURE_DATE_ISOFMT && (opt & DATE_OPT_TIMESPEC)) { 63 if (!isofmt_arg) { 64 ifmt = 0; /* default is date */ 65 } else { 66 static const char *const isoformats[] = { 67 "date", "hours", "minutes", "seconds" 68 }; 69 70 for (ifmt = 0; ifmt < 4; ifmt++) 71 if (!strcmp(isofmt_arg, isoformats[ifmt])) 72 goto found; 73 /* parse error */ 74 bb_show_usage(); 75 found: ; 76 } 77 } 78 79 /* XXX, date_fmt == NULL from this always */ 80 if ((date_fmt == NULL) && (optind < argc) && (argv[optind][0] == '+')) { 81 date_fmt = &argv[optind][1]; /* Skip over the '+' */ 82 } else if (date_str == NULL) { 83 opt |= DATE_OPT_SET; 84 date_str = argv[optind]; 85 } 194 if (ENABLE_FEATURE_DATE_ISOFMT && (opt & OPT_TIMESPEC)) { 195 ifmt = 0; /* default is date */ 196 if (isofmt_arg) { 197 static const char isoformats[] ALIGN1 = 198 "date\0""hours\0""minutes\0""seconds\0"; /* ns? */ 199 ifmt = index_in_substrings(isoformats, isofmt_arg); 200 if (ifmt < 0) 201 bb_show_usage(); 202 } 203 } 204 205 fmt_dt2str = NULL; 206 if (argv[0] && argv[0][0] == '+') { 207 fmt_dt2str = &argv[0][1]; /* skip over the '+' */ 208 argv++; 209 } 210 if (!(opt & (OPT_SET | OPT_DATE))) { 211 opt |= OPT_SET; 212 date_str = argv[0]; /* can be NULL */ 213 if (date_str) { 214 #if ENABLE_FEATURE_DATE_COMPAT 215 int len = strspn(date_str, "0123456789"); 216 if (date_str[len] == '\0' 217 || (date_str[len] == '.' 218 && isdigit(date_str[len+1]) 219 && isdigit(date_str[len+2]) 220 && date_str[len+3] == '\0' 221 ) 222 ) { 223 /* Dreaded MMDDhhmm[[CC]YY][.ss] format! 224 * It does not match -d or -s format. 225 * Some users actually do use it. 226 */ 227 len -= 8; 228 if (len < 0 || len > 4 || (len & 1)) 229 bb_error_msg_and_die(bb_msg_invalid_date, date_str); 230 if (len != 0) { /* move YY or CCYY to front */ 231 char buf[4]; 232 memcpy(buf, date_str + 8, len); 233 memmove(date_str + len, date_str, 8); 234 memcpy(date_str, buf, len); 235 } 236 } 237 #endif 238 argv++; 239 } 240 } 241 if (*argv) 242 bb_show_usage(); 86 243 87 244 /* Now we have parsed all the information except the date format 88 89 90 if ( filename) {245 * which depends on whether the clock is being set or read */ 246 247 if (opt & OPT_REFERENCE) { 91 248 struct stat statbuf; 92 249 xstat(filename, &statbuf); 93 tm = statbuf.st_mtime; 94 } else 95 time(&tm); 96 memcpy(&tm_time, localtime(&tm), sizeof(tm_time)); 97 /* Zero out fields - take her back to midnight! */ 250 ts.tv_sec = statbuf.st_mtime; 251 #if ENABLE_FEATURE_DATE_NANO 252 ts.tv_nsec = statbuf.st_mtim.tv_nsec; 253 /* some toolchains use .st_mtimensec instead of st_mtim.tv_nsec */ 254 #endif 255 } else { 256 #if ENABLE_FEATURE_DATE_NANO 257 /* libc has incredibly messy way of doing this, 258 * typically requiring -lrt. We just skip all this mess */ 259 syscall(__NR_clock_gettime, CLOCK_REALTIME, &ts); 260 #else 261 time(&ts.tv_sec); 262 #endif 263 } 264 localtime_r(&ts.tv_sec, &tm_time); 265 266 /* If date string is given, update tm_time, and maybe set date */ 98 267 if (date_str != NULL) { 268 /* Zero out fields - take her back to midnight! */ 99 269 tm_time.tm_sec = 0; 100 270 tm_time.tm_min = 0; … … 102 272 103 273 /* Process any date input to UNIX time since 1 Jan 1970 */ 104 if (ENABLE_FEATURE_DATE_ISOFMT && (opt & DATE_OPT_HINT)) { 105 strptime(date_str, hintfmt_arg, &tm_time); 106 } else if (strchr(date_str, ':') != NULL) { 107 /* Parse input and assign appropriately to tm_time */ 108 109 if (sscanf(date_str, "%d:%d:%d", &tm_time.tm_hour, &tm_time.tm_min, 110 &tm_time.tm_sec) == 3) { 111 /* no adjustments needed */ 112 } else if (sscanf(date_str, "%d:%d", &tm_time.tm_hour, 113 &tm_time.tm_min) == 2) { 114 /* no adjustments needed */ 115 } else if (sscanf(date_str, "%d.%d-%d:%d:%d", &tm_time.tm_mon, 116 &tm_time.tm_mday, &tm_time.tm_hour, 117 &tm_time.tm_min, &tm_time.tm_sec) == 5) { 118 /* Adjust dates from 1-12 to 0-11 */ 119 tm_time.tm_mon -= 1; 120 } else if (sscanf(date_str, "%d.%d-%d:%d", &tm_time.tm_mon, 121 &tm_time.tm_mday, 122 &tm_time.tm_hour, &tm_time.tm_min) == 4) { 123 /* Adjust dates from 1-12 to 0-11 */ 124 tm_time.tm_mon -= 1; 125 } else if (sscanf(date_str, "%d.%d.%d-%d:%d:%d", &tm_time.tm_year, 126 &tm_time.tm_mon, &tm_time.tm_mday, 127 &tm_time.tm_hour, &tm_time.tm_min, 128 &tm_time.tm_sec) == 6) { 129 tm_time.tm_year -= 1900; /* Adjust years */ 130 tm_time.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */ 131 } else if (sscanf(date_str, "%d.%d.%d-%d:%d", &tm_time.tm_year, 132 &tm_time.tm_mon, &tm_time.tm_mday, 133 &tm_time.tm_hour, &tm_time.tm_min) == 5) { 134 tm_time.tm_year -= 1900; /* Adjust years */ 135 tm_time.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */ 136 } else { 274 if (ENABLE_FEATURE_DATE_ISOFMT && (opt & OPT_HINT)) { 275 if (strptime(date_str, fmt_str2dt, &tm_time) == NULL) 137 276 bb_error_msg_and_die(bb_msg_invalid_date, date_str); 138 }139 277 } else { 140 int nr; 141 char *cp; 142 143 nr = sscanf(date_str, "%2d%2d%2d%2d%d", &tm_time.tm_mon, 144 &tm_time.tm_mday, &tm_time.tm_hour, &tm_time.tm_min, 145 &tm_time.tm_year); 146 147 if (nr < 4 || nr > 5) { 148 bb_error_msg_and_die(bb_msg_invalid_date, date_str); 149 } 150 151 cp = strchr(date_str, '.'); 152 if (cp) { 153 nr = sscanf(cp + 1, "%2d", &tm_time.tm_sec); 154 if (nr != 1) { 155 bb_error_msg_and_die(bb_msg_invalid_date, date_str); 156 } 157 } 158 159 /* correct for century - minor Y2K problem here? */ 160 if (tm_time.tm_year >= 1900) { 161 tm_time.tm_year -= 1900; 162 } 163 /* adjust date */ 164 tm_time.tm_mon -= 1; 278 parse_datestr(date_str, &tm_time); 165 279 } 166 280 167 281 /* Correct any day of week and day of year etc. fields */ 168 tm_time.tm_isdst = -1; /* Be sure to recheck dst. */ 169 tm = mktime(&tm_time); 170 if (tm < 0) { 171 bb_error_msg_and_die(bb_msg_invalid_date, date_str); 172 } 282 tm_time.tm_isdst = -1; /* Be sure to recheck dst */ 283 ts.tv_sec = validate_tm_time(date_str, &tm_time); 284 173 285 maybe_set_utc(opt); 174 286 175 287 /* if setting time, set it */ 176 if ((opt & DATE_OPT_SET) && stime(&tm) < 0) {177 bb_perror_msg("can not set date");288 if ((opt & OPT_SET) && stime(&ts.tv_sec) < 0) { 289 bb_perror_msg("can't set date"); 178 290 } 179 291 } … … 182 294 183 295 /* Deal with format string */ 184 185 if (date_fmt == NULL) { 296 if (fmt_dt2str == NULL) { 186 297 int i; 187 date_fmt = xzalloc(32);298 fmt_dt2str = buf_fmt_dt2str; 188 299 if (ENABLE_FEATURE_DATE_ISOFMT && ifmt >= 0) { 189 strcpy(date_fmt, "%Y-%m-%d"); 190 if (ifmt > 0) { 191 i = 8; 192 date_fmt[i++] = 'T'; 193 date_fmt[i++] = '%'; 194 date_fmt[i++] = 'H'; 195 if (ifmt > 1) { 196 date_fmt[i++] = ':'; 197 date_fmt[i++] = '%'; 198 date_fmt[i++] = 'M'; 199 } 200 if (ifmt > 2) { 201 date_fmt[i++] = ':'; 202 date_fmt[i++] = '%'; 203 date_fmt[i++] = 'S'; 204 } 300 /* -I[SPEC]: 0:date 1:hours 2:minutes 3:seconds */ 301 strcpy(fmt_dt2str, "%Y-%m-%dT%H:%M:%S"); 302 i = 8 + 3 * ifmt; 303 if (ifmt != 0) { 304 /* TODO: if (ifmt==4) i += sprintf(&fmt_dt2str[i], ",%09u", nanoseconds); */ 205 305 format_utc: 206 date_fmt[i++] = '%'; 207 date_fmt[i] = (opt & DATE_OPT_UTC) ? 'Z' : 'z'; 208 } 209 } else if (opt & DATE_OPT_RFC2822) { 210 /* Undo busybox.c for date -R */ 306 fmt_dt2str[i++] = '%'; 307 fmt_dt2str[i++] = (opt & OPT_UTC) ? 'Z' : 'z'; 308 } 309 fmt_dt2str[i] = '\0'; 310 } else if (opt & OPT_RFC2822) { 311 /* -R. undo busybox.c setlocale */ 211 312 if (ENABLE_LOCALE_SUPPORT) 212 313 setlocale(LC_TIME, "C"); 213 strcpy( date_fmt, "%a, %d %b %Y %H:%M:%S ");214 i = 22;314 strcpy(fmt_dt2str, "%a, %d %b %Y %H:%M:%S "); 315 i = sizeof("%a, %d %b %Y %H:%M:%S ")-1; 215 316 goto format_utc; 216 } else /* default case */ 217 date_fmt = (char*)"%a %b %e %H:%M:%S %Z %Y"; 218 } 317 } else { /* default case */ 318 fmt_dt2str = (char*)"%a %b %e %H:%M:%S %Z %Y"; 319 } 320 } 321 #if ENABLE_FEATURE_DATE_NANO 322 else { 323 /* User-specified fmt_dt2str */ 324 /* Search for and process "%N" */ 325 char *p = fmt_dt2str; 326 while ((p = strchr(p, '%')) != NULL) { 327 int n, m; 328 unsigned pres, scale; 329 330 p++; 331 if (*p == '%') { 332 p++; 333 continue; 334 } 335 n = strspn(p, "0123456789"); 336 if (p[n] != 'N') { 337 p += n; 338 continue; 339 } 340 /* We have "%[nnn]N" */ 341 p[-1] = '\0'; 342 p[n] = '\0'; 343 scale = 1; 344 pres = 9; 345 if (n) { 346 pres = xatoi_positive(p); 347 if (pres == 0) 348 pres = 9; 349 m = 9 - pres; 350 while (--m >= 0) 351 scale *= 10; 352 } 353 354 m = p - fmt_dt2str; 355 p += n + 1; 356 fmt_dt2str = xasprintf("%s%0*u%s", fmt_dt2str, pres, (unsigned)ts.tv_nsec / scale, p); 357 p = fmt_dt2str + m; 358 } 359 } 360 #endif 219 361 220 362 #define date_buf bb_common_bufsiz1 221 if (* date_fmt== '\0') {363 if (*fmt_dt2str == '\0') { 222 364 /* With no format string, just print a blank line */ 223 365 date_buf[0] = '\0'; 224 366 } else { 225 367 /* Handle special conversions */ 226 227 if (strncmp(date_fmt, "%f", 2) == 0) { 228 date_fmt = (char*)"%Y.%m.%d-%H:%M:%S"; 229 } 230 368 if (strncmp(fmt_dt2str, "%f", 2) == 0) { 369 fmt_dt2str = (char*)"%Y.%m.%d-%H:%M:%S"; 370 } 231 371 /* Generate output string */ 232 strftime(date_buf, sizeof(date_buf), date_fmt, &tm_time);372 strftime(date_buf, sizeof(date_buf), fmt_dt2str, &tm_time); 233 373 } 234 374 puts(date_buf);
Note:
See TracChangeset
for help on using the changeset viewer.