diff options
author | Paul Eggert <eggert@cs.ucla.edu> | 2016-03-17 10:35:18 -0700 |
---|---|---|
committer | Paul Eggert <eggert@cs.ucla.edu> | 2016-03-17 10:36:33 -0700 |
commit | df88fce71651afb2c3456967a142db0ae4bf9906 (patch) | |
tree | aa18160fb6d2ef669fcfc04e914da9d10b649287 /src/du.c | |
parent | c18b3699e1b8c4ad2739761f2b9c306ff2303322 (diff) | |
download | coreutils-df88fce71651afb2c3456967a142db0ae4bf9906.tar.xz |
date ls pr: fix time zone abbrs on SysV platforms
The problematic code computed a struct tm in one time zone, and
then printed it or converted it to a string in another. To be
portable the same time zone needs to be used for both operations.
On GNU platforms this is not an issue, but incorrect output can be
generated on System V style platforms like AIX where time zone
abbreviations are available only in the 'tzname' global variable.
Problem reported by Assaf Gordon in: http://bugs.gnu.org/23035
* NEWS: Document the bug.
* src/date.c (show_date):
* src/ls.c (long_time_expected_width, print_long_format):
* src/pr.c (init_header):
* src/stat.c (human_time): Use localtime_rz instead of localtime,
so that the time zone information is consistent for both localtime
and time-formatting functions like fprintftime and nstrftime. For
'stat' this change is mostly just a code cleanup but it also
causes stat to also print nanoseconds when printing time stamps
that are out of localtime range, as this is more consistent with
what other programs do. For programs other than 'stat' this fixes
bugs with time zone formats that use %Z.
* src/du.c, src/pr.c (localtz): New static var.
(main): Initialize it.
* src/du.c (show_date): New time zone argument, so that localtime
and fprintftime use the same time zone information. All callers
changed.
* tests/misc/time-style.sh: New file.
* tests/local.mk (all_tests): Add it.
* tests/misc/date.pl: Test alphabetic time zone abbreviations.
Diffstat (limited to 'src/du.c')
-rw-r--r-- | src/du.c | 17 |
1 files changed, 10 insertions, 7 deletions
@@ -182,6 +182,9 @@ static char const *time_style = NULL; /* Format used to display date / time. Controlled by --time-style */ static char const *time_format = NULL; +/* The local time zone rules, as per the TZ environment variable. */ +static timezone_t localtz; + /* The units to use when printing sizes. */ static uintmax_t output_block_size; @@ -372,19 +375,18 @@ hash_ins (struct di_set *di_set, ino_t ino, dev_t dev) in FORMAT. */ static void -show_date (const char *format, struct timespec when) +show_date (const char *format, struct timespec when, timezone_t tz) { - struct tm *tm = localtime (&when.tv_sec); - if (! tm) + struct tm tm; + if (localtime_rz (tz, &when.tv_sec, &tm)) + fprintftime (stdout, format, &tm, tz, when.tv_nsec); + else { char buf[INT_BUFSIZE_BOUND (intmax_t)]; char *when_str = timetostr (when.tv_sec, buf); error (0, 0, _("time %s is out of range"), quote (when_str)); fputs (when_str, stdout); - return; } - - fprintftime (stdout, format, tm, 0, when.tv_nsec); } /* Print N_BYTES. Convert it to a readable value before printing. */ @@ -412,7 +414,7 @@ print_size (const struct duinfo *pdui, const char *string) if (opt_time) { putchar ('\t'); - show_date (time_format, pdui->tmax); + show_date (time_format, pdui->tmax, localtz); } printf ("\t%s%c", string, opt_nul_terminate_output ? '\0' : '\n'); fflush (stdout); @@ -905,6 +907,7 @@ main (int argc, char **argv) (optarg ? XARGMATCH ("--time", optarg, time_args, time_types) : time_mtime); + localtz = tzalloc (getenv ("TZ")); break; case TIME_STYLE_OPTION: |