https://gcc.gnu.org/bugzilla/show_bug.cgi?id=125467

            Bug ID: 125467
           Summary: std::chrono::current_zone() doesn't support symlink
                    chains
           Product: gcc
           Version: 16.1.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: libstdc++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: redi at gcc dot gnu.org
  Target Milestone: ---

Given a setup like:

$ ls -l /etc/localtime
lrwxrwxrwx. 1 root root 35 Mar 20 12:22 /etc/localtime -> /run/localtime
$ ls -l /run/localtime
lrwxrwxrwx. 1 root root 35 Mar 20 12:22 /run/localtime ->
/usr/share/zoneinfo/Europe/London

we fail to determine the system's time zone. We use readlink once on
/etc/localtime, but then we assume that it links directly to a tzif file under
/usr/share/zoneinfo

The https://www.freedesktop.org/software/systemd/man/latest/localtime.html spec
does seem to say it should be a symlink directly to the tzif files, but not all
platforms use systemd. Supporting the case above seems reasonable.

We need to decide whether we should just keep calling readlink until we get
EINVAL (meaning the target is no longer a symlink), then try to extract a time
zone name from the ultimate target, or whether we should call readlink then try
to extract a time zone name, and if that fails call readlink again and repeat.

The difference would matter for a setup like this, where tzdb links like "GB"
are represented as symlinks not hard links (not the standard way to install
it):

$ ls -l /etc/localtime
lrwxrwxrwx. 1 root root 35 Mar 20 12:22 /etc/localtime ->
/usr/share/zoneinfo/GB
$ ls -l /usr/share/zoneinfo/GB
lrwxrwxrwx. 1 root root 35 Mar 20 12:22 /usr/share/zoneinfo/GB -> Europe/London

If we follow the chain of symlinks all the way to the end then we resolve to
"Europe/London" and look that up, instead of looking up "GB". In this case,
that's fine because "GB" is a Link to the "Europe/London" Zone anyway:

L Europe/London GB

But in this setup with a custom "Europe/Cardiff" symlink it would be a problem:

$ ls -l /etc/localtime
lrwxrwxrwx. 1 root root 35 Mar 20 12:22 /etc/localtime ->
/usr/share/zoneinfo/Europe/Cardiff
$ ls -l /usr/share/zoneinfo/Europe/Cardiff
lrwxrwxrwx. 1 root root 35 Mar 20 12:22 /usr/share/zoneinfo/Europe/Cardiff ->
London

Here the ultimate target is just "London" and lookup for that would fail
because it's not a valid zone name. If we looked up "Europe/Cardiff" that would
also fail, because that's not in the tzdb either.

So maybe we should use realpath instead of readlink, which would resolve the
chain of symlinks to an absolute path. In all cases above we'd get the same
absolute path:

/usr/share/zoneinfo/Europe/London

which would be looked up as "London" and then as "Europe/London", and that
would match.

Just using realpath also means we only need one system call and don't need to
manually loop resolving each symlink.

Reply via email to