Paul Eggert wrote:
> After looking into how fprintftime affects GNU tar, I decided to change 
> GNU tar to not use fprintftime.
> 
> The initial impetus for this new change was that recent changes to 
> Gnulib broke the GNU tar build on macOS, and fixing that in the obvious 
> way would have caused fprintftime to drag in some extra multithreading 
> code that is not needed (tar is single-threaded). There didn't seem to 
> be a convenient way to prevent that.
> ...
> So I changed GNU tar to simply call the system strftime. (Calling 
> nstrftime, or even nstrftime-limited, seems like it would also drag in 
> the unwanted multithreaded code.)

Now that the 'nstrftime-limited' module no longer has any link dependency
(the dependency on CoreFoundation has been removed through yesterday's
patch, and the dependency on libpthread is removed by reducing functionality
on OpenBSD, AIX, Android, compared to the 'nstrftime' module), I propose
to use 'nstrftime-limited' instead of the system's strftime() function.

With this change, on macOS 12 (cfarm104.cfarm.net), when built with
--disable-nls, the 'tar' binary has minimal dependencies:

  $ otool -L build/src/tar
  build/src/tar:
        /usr/lib/libiconv.2.dylib (compatibility version 7.0.0, current version 
7.0.0)
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current 
version 1319.0.0)

This change

1) adds support for the %N specifier. Example (on GNU/Linux):

$ LC_ALL=de_DE.UTF-8 src/tar cf /tmp/foo.tar 
--checkpoint-action="echo=%{%H:%M:%S.%N}t" src/tar
src/tar: 14:25:25.%N
...

becomes

$ LC_ALL=de_DE.UTF-8 src/tar cf /tmp/foo.tar 
--checkpoint-action="echo=%{%H:%M:%S.%N}t" src/tar
src/tar: 14:25:39.005551857
src/tar: 14:25:39.005688164
...

2) removes a tautological timezone suffix on NetBSD and Solaris. Example (on
Solaris 11.4):

$ LC_ALL=fr_FR.UTF-8 src/tar cf /tmp/foo.tar --checkpoint-action="echo=%t" 
src/tar
src/tar: 20 novembre 2025 Ã  15:20:29 CET

becomes

$ LC_ALL=fr_FR.UTF-8 src/tar cf /tmp/foo.tar --checkpoint-action="echo=%t" 
src/tar
src/tar: 20 novembre 2025 Ã  15:21:34

3) probably also works around some other strftime() bugs listed in
gnulib/doc/posix-functions/strftime.texi.

Patch is attached.

>From a1037708e8bdf3e682409ee21b117519e837e952 Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Thu, 20 Nov 2025 14:30:02 +0100
Subject: [PATCH] Use nstrftime for %t conversion in --checkpoint-action.

* gnulib.modules: Add nstrftime-limited, time_rz.
* src/checkpoint.c: Include strftime.h.
(format_checkpoint_string): Use nstrftime instead of the system's strftime
function.
---
 gnulib.modules   | 2 ++
 src/checkpoint.c | 6 +++++-
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/gnulib.modules b/gnulib.modules
index 93c88934..01ba06dd 100644
--- a/gnulib.modules
+++ b/gnulib.modules
@@ -81,6 +81,7 @@ mkdirat
 mkdtemp
 mkfifoat
 modechange
+nstrftime-limited
 obstack
 openat
 openat2
@@ -113,6 +114,7 @@ stringeq
 strnlen
 symlinkat
 sys_stat-h
+time_rz
 timespec
 timespec-sub
 unlinkat
diff --git a/src/checkpoint.c b/src/checkpoint.c
index a07a54ea..0a0b9721 100644
--- a/src/checkpoint.c
+++ b/src/checkpoint.c
@@ -22,6 +22,7 @@
 
 #include <wordsplit.h>
 #include <flexmember.h>
+#include <strftime.h>
 
 #include <sys/ioctl.h>
 #include <termios.h>
@@ -316,8 +317,11 @@ format_checkpoint_string (FILE *fp, intmax_t len,
 		  {
 		    buf[0] = '\0';
 		    char const *fmt = arg ? arg : "%c";
-		    if (strftime (buf, sizeof buf, fmt, tm) != 0 || !buf[0])
+		    timezone_t tz = tzalloc (getenv ("TZ"));
+		    if (0 <= nstrftime (buf, sizeof buf, fmt, tm, tz,
+			                ts.tv_nsec))
 		      tmstr = buf;
+		    tzfree (tz);
 		  }
 		if (!tmstr)
 		  tmstr = timetostr (ts.tv_sec, buf);
-- 
2.51.0

Reply via email to