summaryrefslogtreecommitdiff
path: root/src/ls.c
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2016-03-17 10:35:18 -0700
committerPaul Eggert <eggert@cs.ucla.edu>2016-03-17 10:36:33 -0700
commitdf88fce71651afb2c3456967a142db0ae4bf9906 (patch)
treeaa18160fb6d2ef669fcfc04e914da9d10b649287 /src/ls.c
parentc18b3699e1b8c4ad2739761f2b9c306ff2303322 (diff)
downloadcoreutils-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/ls.c')
-rw-r--r--src/ls.c23
1 files changed, 8 insertions, 15 deletions
diff --git a/src/ls.c b/src/ls.c
index d97603698..35720608c 100644
--- a/src/ls.c
+++ b/src/ls.c
@@ -3720,20 +3720,20 @@ long_time_expected_width (void)
if (width < 0)
{
time_t epoch = 0;
- struct tm const *tm = localtime (&epoch);
+ struct tm tm;
char buf[TIME_STAMP_LEN_MAXIMUM + 1];
- /* In case you're wondering if localtime can fail with an input time_t
+ /* In case you're wondering if localtime_rz can fail with an input time_t
value of 0, let's just say it's very unlikely, but not inconceivable.
The TZ environment variable would have to specify a time zone that
is 2**31-1900 years or more ahead of UTC. This could happen only on
a 64-bit system that blindly accepts e.g., TZ=UTC+20000000000000.
However, this is not possible with Solaris 10 or glibc-2.3.5, since
their implementations limit the offset to 167:59 and 24:00, resp. */
- if (tm)
+ if (localtime_rz (localtz, &epoch, &tm))
{
size_t len =
- align_nstrftime (buf, sizeof buf, long_time_format[0], tm,
+ align_nstrftime (buf, sizeof buf, long_time_format[0], &tm,
localtz, 0);
if (len != 0)
width = mbsnwidth (buf, len, 0);
@@ -3856,7 +3856,7 @@ print_long_format (const struct fileinfo *f)
size_t s;
char *p;
struct timespec when_timespec;
- struct tm *when_local;
+ struct tm when_local;
/* Compute the mode string, except remove the trailing space if no
file in this directory has an ACL or security context. */
@@ -3983,11 +3983,10 @@ print_long_format (const struct fileinfo *f)
p[-1] = ' ';
}
- when_local = localtime (&when_timespec.tv_sec);
s = 0;
*p = '\1';
- if (f->stat_ok && when_local)
+ if (f->stat_ok && localtime_rz (localtz, &when_timespec.tv_sec, &when_local))
{
struct timespec six_months_ago;
bool recent;
@@ -3997,13 +3996,7 @@ print_long_format (const struct fileinfo *f)
time, in case the file happens to have been modified since
the last time we checked the clock. */
if (timespec_cmp (current_time, when_timespec) < 0)
- {
- /* Note that gettime may call gettimeofday which, on some non-
- compliant systems, clobbers the buffer used for localtime's result.
- But it's ok here, because we use a gettimeofday wrapper that
- saves and restores the buffer around the gettimeofday call. */
- gettime (&current_time);
- }
+ gettime (&current_time);
/* Consider a time to be recent if it is within the past six months.
A Gregorian year has 365.2425 * 24 * 60 * 60 == 31556952 seconds
@@ -4019,7 +4012,7 @@ print_long_format (const struct fileinfo *f)
/* We assume here that all time zones are offset from UTC by a
whole number of seconds. */
s = align_nstrftime (p, TIME_STAMP_LEN_MAXIMUM + 1, fmt,
- when_local, localtz, when_timespec.tv_nsec);
+ &when_local, localtz, when_timespec.tv_nsec);
}
if (s || !*p)