Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • janitor-team/proposed/tzdata
  • xnox/tzdata
2 results
Show changes
Commits on Source (4)
tzdata (2022g-4) unstable; urgency=medium
* Fix configuration failure with relative /etc/localtime symlink
(Closes: #1030742)
* Fix exit status 10 for invalid /etc/localtime symlinks
-- Benjamin Drung <bdrung@debian.org> Tue, 07 Feb 2023 17:53:35 +0100
tzdata (2022g-3) unstable; urgency=medium
* Update Brazilian Portuguese debconf translation. (Closes: #1029004)
......
......@@ -5,7 +5,9 @@
"""Test debconf configuration."""
import contextlib
import os
import pathlib
import re
import subprocess
import sys
import typing
......@@ -38,8 +40,24 @@ class TestDebconf(unittest.TestCase):
["dpkg-reconfigure", "--frontend", "noninteractive", "tzdata"], check=True
)
@staticmethod
def _get_debconf_selections() -> dict[str, str]:
debconf_show = subprocess.run(
["debconf-show", "tzdata"], capture_output=True, check=True, text=True
)
debconf_re = re.compile("^[ *] ([^:]+): *(.*)$", flags=re.MULTILINE)
return dict(debconf_re.findall(debconf_show.stdout))
def _get_selection(self) -> str:
selections = self._get_debconf_selections()
area = selections["tzdata/Areas"]
zone = selections[f"tzdata/Zones/{area}"]
return f"{area}/{zone}"
def _get_timezone(self) -> str:
return str(self.etc_localtime.resolve().relative_to("/usr/share/zoneinfo"))
absolute_path = self.etc_localtime.parent / self.etc_localtime.readlink()
timezone = pathlib.Path(os.path.normpath(absolute_path))
return str(timezone.relative_to("/usr/share/zoneinfo"))
def _set_timezone(self, timezone: typing.Union[pathlib.Path, str]) -> None:
with contextlib.suppress(FileNotFoundError):
......@@ -61,6 +79,25 @@ class TestDebconf(unittest.TestCase):
stdout=subprocess.DEVNULL,
)
def test_broken_symlink(self) -> None:
"""Test pointing /etc/localtime to an invalid location."""
self._set_timezone(pathlib.Path("/bin/sh"))
self._reset_debconf()
self._call_dpkg_reconfigure()
self.assertEqual(self._get_timezone(), "Etc/UTC")
self.assertEqual(self._get_selection(), "Etc/UTC")
def test_broken_symlink_but_debconf_preseed(self) -> None:
"""Test broken /etc/localtime but existing debconf answers."""
self._set_timezone(pathlib.Path("/bin/sh"))
self._call_debconf_set_selections(
"tzdata tzdata/Areas select Pacific\n"
"tzdata tzdata/Zones/Pacific select Yap\n"
)
self._call_dpkg_reconfigure()
self.assertEqual(self._get_timezone(), "Pacific/Yap")
self.assertEqual(self._get_selection(), "Pacific/Yap")
def test_etc_localtime_precedes_debconf_preseed(self) -> None:
"""Test dpkg-reconfigure uses /etc/localtime over preseed."""
self._set_timezone("Asia/Jerusalem")
......@@ -70,6 +107,7 @@ class TestDebconf(unittest.TestCase):
)
self._call_dpkg_reconfigure()
self.assertEqual(self._get_timezone(), "Asia/Jerusalem")
self.assertEqual(self._get_selection(), "Asia/Jerusalem")
def test_default_to_utc(self) -> None:
"""Test dpkg-reconfigure defaults to Etc/UTC."""
......@@ -77,6 +115,7 @@ class TestDebconf(unittest.TestCase):
self._reset_debconf()
self._call_dpkg_reconfigure()
self.assertEqual(self._get_timezone(), "Etc/UTC")
self.assertEqual(self._get_selection(), "Etc/UTC")
def test_reconfigure_no_etc_timezone(self) -> None:
"""Test dpkg-reconfigure does not create /etc/timezone."""
......@@ -84,6 +123,7 @@ class TestDebconf(unittest.TestCase):
self._call_dpkg_reconfigure()
self.assertEqual(self._get_timezone(), "America/New_York")
self.assertFalse(self.etc_timezone.exists())
self.assertEqual(self._get_selection(), "America/New_York")
def test_reconfigure_updates_etc_timezone(self) -> None:
"""Test dpkg-reconfigure updates existing /etc/timezone."""
......@@ -92,6 +132,7 @@ class TestDebconf(unittest.TestCase):
self._call_dpkg_reconfigure()
self.assertEqual(self._get_timezone(), "Europe/Oslo")
self.assertEqual(self.etc_timezone.read_text(encoding="utf-8"), "Europe/Oslo\n")
self.assertEqual(self._get_selection(), "Europe/Oslo")
def test_reconfigure_fallback_to_etc_timezone(self) -> None:
"""Test dpkg-reconfigure reads /etc/timezone for missing /etc/localtime."""
......@@ -100,6 +141,14 @@ class TestDebconf(unittest.TestCase):
self._call_dpkg_reconfigure()
self.assertEqual(self._get_timezone(), "Europe/Kyiv")
self.assertEqual(self.etc_timezone.read_text(encoding="utf-8"), "Europe/Kyiv\n")
self.assertEqual(self._get_selection(), "Europe/Kyiv")
def test_reconfigure_symlinked_timezone(self) -> None:
"""Test dpkg-reconfigure for symlinked timezone."""
self._set_timezone("Arctic/Longyearbyen")
self._call_dpkg_reconfigure()
self.assertEqual(self._get_timezone(), "Arctic/Longyearbyen")
self.assertEqual(self._get_selection(), "Arctic/Longyearbyen")
def test_relative_symlink(self) -> None:
"""Test relative symlink /etc/localtime."""
......@@ -108,12 +157,14 @@ class TestDebconf(unittest.TestCase):
self._call_dpkg_reconfigure()
self.assertEqual(self._get_timezone(), "Europe/Berlin")
self.assertEqual(self.etc_localtime.readlink(), timezone)
self.assertEqual(self._get_selection(), "Europe/Berlin")
def test_update_obsolete_timezone(self) -> None:
"""Test updating obsolete timezone to current one."""
self._set_timezone("Mideast/Riyadh88")
self._call_dpkg_reconfigure()
self.assertEqual(self._get_timezone(), "Asia/Riyadh")
self.assertEqual(self._get_selection(), "Asia/Riyadh")
def test_preesed(self) -> None:
"""Test preseeding answers with non-existing /etc/localtime."""
......@@ -124,6 +175,7 @@ class TestDebconf(unittest.TestCase):
)
self._call_dpkg_reconfigure()
self.assertEqual(self._get_timezone(), "Europe/Berlin")
self.assertEqual(self._get_selection(), "Europe/Berlin")
def main() -> None:
......
......@@ -286,7 +286,8 @@ convert_timezone()
# Read timezone from /etc/localtime if it is a link
if [ -L "$DPKG_ROOT/etc/localtime" ] ; then
TIMEZONE="$(readlink -m "$DPKG_ROOT/etc/localtime")"
TIMEZONE="$(readlink "$DPKG_ROOT/etc/localtime")"
TIMEZONE="$(cd "$DPKG_ROOT/etc" && realpath -m -s "$TIMEZONE")"
TIMEZONE="${TIMEZONE#/usr/share/zoneinfo/}"
# Fall back to /etc/timezone if present
elif [ -e "$DPKG_ROOT/etc/timezone" ]; then
......@@ -297,44 +298,38 @@ elif [ -e "$DPKG_ROOT/etc/timezone" ]; then
fi
TIMEZONE="$(convert_timezone "$TIMEZONE")"
if [ -f "$DPKG_ROOT/usr/share/zoneinfo/$TIMEZONE" ] ; then
AREA="${TIMEZONE%%/*}"
ZONE="${TIMEZONE#*/}"
fi
# The timezone is already configured
if [ -L "$DPKG_ROOT/etc/localtime" ] ; then
# Don't ask the user, except if he/she explicitely asked that
if [ -z "$DEBCONF_RECONFIGURE" ] ; then
db_fset tzdata/Areas seen true
db_fset "tzdata/Zones/$AREA" seen true
fi
# The timezone has never been configured or is falsely configured
elif ! [ -L "$DPKG_ROOT/etc/localtime" ] || [ -n "$DEBCONF_RECONFIGURE" ] ; then
if [ -z "$AREA" ] || [ -z "$ZONE" ] ; then
RET=""
db_fget tzdata/Areas seen || RET=false
if [ "$RET" = true ] ; then
db_get tzdata/Areas
AREA=$RET
else
AREA="Etc"
fi
else
RET=""
db_fget tzdata/Areas seen || RET=false
if [ "$RET" = true ] ; then
db_get tzdata/Areas
AREA=$RET
else
AREA="Etc"
fi
RET=""
db_fget "tzdata/Zones/$AREA" seen || RET=false
if [ "$RET" = true ] ; then
db_get "tzdata/Zones/$AREA"
ZONE=$RET
else
ZONE="UTC"
fi
RET=""
db_fget "tzdata/Zones/$AREA" seen || RET=false
if [ "$RET" = true ] ; then
db_get "tzdata/Zones/$AREA"
ZONE=$RET
else
ZONE="UTC"
fi
db_fset tzdata/Areas seen false
db_fset "tzdata/Zones/$AREA" seen false
# The user want to handle the timezone by him/herself
else
exit 0
fi
# Initializes debconf default values from the ones found in
......
......@@ -10,7 +10,8 @@ get_timezone() {
if ! [ -L "$DPKG_ROOT/etc/localtime" ] ; then
return
fi
timezone="$(readlink -m "$DPKG_ROOT/etc/localtime")"
timezone="$(readlink "$DPKG_ROOT/etc/localtime")"
timezone="$(cd "$DPKG_ROOT/etc" && realpath -m -s "$timezone")"
echo "${timezone#/usr/share/zoneinfo/}"
}
......