summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/date.c24
-rw-r--r--src/du.c17
-rw-r--r--src/ls.c23
-rw-r--r--src/pr.c23
-rw-r--r--src/stat.c26
5 files changed, 62 insertions, 51 deletions
diff --git a/src/date.c b/src/date.c
index 269570b1a..e73196b96 100644
--- a/src/date.c
+++ b/src/date.c
@@ -559,23 +559,23 @@ main (int argc, char **argv)
static bool
show_date (const char *format, struct timespec when, timezone_t tz)
{
- struct tm *tm;
+ struct tm tm;
- tm = localtime (&when.tv_sec);
- if (! tm)
+ if (localtime_rz (tz, &when.tv_sec, &tm))
+ {
+ if (format == rfc_2822_format)
+ setlocale (LC_TIME, "C");
+ fprintftime (stdout, format, &tm, tz, when.tv_nsec);
+ if (format == rfc_2822_format)
+ setlocale (LC_TIME, "");
+ fputc ('\n', stdout);
+ return true;
+ }
+ else
{
char buf[INT_BUFSIZE_BOUND (intmax_t)];
error (0, 0, _("time %s is out of range"),
quote (timetostr (when.tv_sec, buf)));
return false;
}
-
- if (format == rfc_2822_format)
- setlocale (LC_TIME, "C");
- fprintftime (stdout, format, tm, tz, when.tv_nsec);
- fputc ('\n', stdout);
- if (format == rfc_2822_format)
- setlocale (LC_TIME, "");
-
- return true;
}
diff --git a/src/du.c b/src/du.c
index 45c37037c..45339fefb 100644
--- a/src/du.c
+++ b/src/du.c
@@ -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:
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)
diff --git a/src/pr.c b/src/pr.c
index 8885fff4f..d4549a3bb 100644
--- a/src/pr.c
+++ b/src/pr.c
@@ -710,6 +710,9 @@ static char *custom_header;
/* (-D) Date format for the header. */
static char const *date_format;
+/* The local time zone rules, as per the TZ environment variable. */
+static timezone_t localtz;
+
/* Date and file name for the header. */
static char *date_text;
static char const *file_text;
@@ -1049,6 +1052,8 @@ main (int argc, char **argv)
? "%b %e %H:%M %Y"
: "%Y-%m-%d %H:%M");
+ localtz = tzalloc (getenv ("TZ"));
+
/* Now we can set a reasonable initial value: */
if (first_page_number == 0)
first_page_number = 1;
@@ -1611,7 +1616,7 @@ init_header (char const *filename, int desc)
struct stat st;
struct timespec t;
int ns;
- struct tm *tm;
+ struct tm tm;
/* If parallel files or standard input, use current date. */
if (STREQ (filename, "-"))
@@ -1627,18 +1632,18 @@ init_header (char const *filename, int desc)
}
ns = t.tv_nsec;
- tm = localtime (&t.tv_sec);
- if (tm == NULL)
+ if (localtime_rz (localtz, &t.tv_sec, &tm))
{
- buf = xmalloc (INT_BUFSIZE_BOUND (long int)
- + MAX (10, INT_BUFSIZE_BOUND (int)));
- sprintf (buf, "%ld.%09d", (long int) t.tv_sec, ns);
+ size_t bufsize
+ = nstrftime (NULL, SIZE_MAX, date_format, &tm, localtz, ns) + 1;
+ buf = xmalloc (bufsize);
+ nstrftime (buf, bufsize, date_format, &tm, localtz, ns);
}
else
{
- size_t bufsize = nstrftime (NULL, SIZE_MAX, date_format, tm, 0, ns) + 1;
- buf = xmalloc (bufsize);
- nstrftime (buf, bufsize, date_format, tm, 0, ns);
+ char secbuf[INT_BUFSIZE_BOUND (intmax_t)];
+ buf = xmalloc (sizeof secbuf + MAX (10, INT_BUFSIZE_BOUND (int)));
+ sprintf (buf, "%s.%09d", timetostr (t.tv_sec, secbuf), ns);
}
free (date_text);
diff --git a/src/stat.c b/src/stat.c
index e11e4318f..1742ff128 100644
--- a/src/stat.c
+++ b/src/stat.c
@@ -557,17 +557,27 @@ human_access (struct stat const *statbuf)
static char * ATTRIBUTE_WARN_UNUSED_RESULT
human_time (struct timespec t)
{
- static char str[MAX (INT_BUFSIZE_BOUND (intmax_t),
- (INT_STRLEN_BOUND (int) /* YYYY */
- + 1 /* because YYYY might equal INT_MAX + 1900 */
- + sizeof "-MM-DD HH:MM:SS.NNNNNNNNN +ZZZZ"))];
+ /* STR must be at least this big, either because localtime_rz fails,
+ or because the time zone is truly outlandish so that %z expands
+ to a long string. */
+ enum { intmax_bufsize = INT_BUFSIZE_BOUND (intmax_t) };
+
+ static char str[intmax_bufsize
+ + INT_STRLEN_BOUND (int) /* YYYY */
+ + 1 /* because YYYY might equal INT_MAX + 1900 */
+ + sizeof "-MM-DD HH:MM:SS.NNNNNNNNN +"];
static timezone_t tz;
if (!tz)
tz = tzalloc (getenv ("TZ"));
- struct tm const *tm = localtime (&t.tv_sec);
- if (tm == NULL)
- return timetostr (t.tv_sec, str);
- nstrftime (str, sizeof str, "%Y-%m-%d %H:%M:%S.%N %z", tm, tz, t.tv_nsec);
+ struct tm tm;
+ int ns = t.tv_nsec;
+ if (localtime_rz (tz, &t.tv_sec, &tm))
+ nstrftime (str, sizeof str, "%Y-%m-%d %H:%M:%S.%N %z", &tm, tz, ns);
+ else
+ {
+ char secbuf[INT_BUFSIZE_BOUND (intmax_t)];
+ sprintf (str, "%s.%09d", timetostr (t.tv_sec, secbuf), ns);
+ }
return str;
}