| 158 | |
| 159 | |
| 160 | def _get_unix_timezone(_root: str = "/") -> Timezone: |
| 161 | tzenv = os.environ.get("TZ") |
| 162 | if tzenv: |
| 163 | with contextlib.suppress(ValueError): |
| 164 | return _tz_from_env(tzenv) |
| 165 | |
| 166 | # Now look for distribution specific configuration files |
| 167 | # that contain the timezone name. |
| 168 | tzpath = Path(_root) / "etc" / "timezone" |
| 169 | if tzpath.is_file(): |
| 170 | tzfile_data = tzpath.read_bytes() |
| 171 | # Issue #3 was that /etc/timezone was a zoneinfo file. |
| 172 | # That's a misconfiguration, but we need to handle it gracefully: |
| 173 | if not tzfile_data.startswith(b"TZif2"): |
| 174 | etctz = tzfile_data.strip().decode() |
| 175 | # Get rid of host definitions and comments: |
| 176 | etctz, _, _ = etctz.partition(" ") |
| 177 | etctz, _, _ = etctz.partition("#") |
| 178 | return Timezone(etctz.replace(" ", "_")) |
| 179 | |
| 180 | # CentOS has a ZONE setting in /etc/sysconfig/clock, |
| 181 | # OpenSUSE has a TIMEZONE setting in /etc/sysconfig/clock and |
| 182 | # Gentoo has a TIMEZONE setting in /etc/conf.d/clock |
| 183 | # We look through these files for a timezone: |
| 184 | zone_re = re.compile(r'\s*(TIME)?ZONE\s*=\s*"([^"]+)?"') |
| 185 | |
| 186 | for filename in ("etc/sysconfig/clock", "etc/conf.d/clock"): |
| 187 | tzpath = Path(_root) / filename |
| 188 | if tzpath.is_file(): |
| 189 | data = tzpath.read_text().splitlines() |
| 190 | for line in data: |
| 191 | # Look for the ZONE= or TIMEZONE= setting. |
| 192 | match = zone_re.match(line) |
| 193 | if match: |
| 194 | etctz = match.group(2) |
| 195 | parts = list(reversed(etctz.replace(" ", "_").split(os.path.sep))) |
| 196 | tzpath_parts: list[str] = [] |
| 197 | while parts: |
| 198 | tzpath_parts.insert(0, parts.pop(0)) |
| 199 | with contextlib.suppress(InvalidTimezone): |
| 200 | return Timezone(os.path.sep.join(tzpath_parts)) |
| 201 | |
| 202 | # systemd distributions use symlinks that include the zone name, |
| 203 | # see manpage of localtime(5) and timedatectl(1) |
| 204 | tzpath = Path(_root) / "etc" / "localtime" |
| 205 | if tzpath.is_file() and tzpath.is_symlink(): |
| 206 | parts = [p.replace(" ", "_") for p in reversed(tzpath.resolve().parts)] |
| 207 | tzpath_parts: list[str] = [] # type: ignore[no-redef] |
| 208 | while parts: |
| 209 | tzpath_parts.insert(0, parts.pop(0)) |
| 210 | with contextlib.suppress(InvalidTimezone): |
| 211 | return Timezone(os.path.sep.join(tzpath_parts)) |
| 212 | |
| 213 | # No explicit setting existed. Use localtime |
| 214 | for filename in ("etc/localtime", "usr/local/etc/localtime"): |
| 215 | tzpath = Path(_root) / filename |
| 216 | if tzpath.is_file(): |
| 217 | with tzpath.open("rb") as f: |