diff --git a/src/tz_linux.rs b/src/tz_linux.rs index 6cff285..e2f7d28 100644 --- a/src/tz_linux.rs +++ b/src/tz_linux.rs @@ -13,19 +13,31 @@ fn etc_timezone() -> Result { } fn etc_localtime() -> Result { - // https://www.man7.org/linux/man-pages/man5/localtime.5.html - // https://www.cyberciti.biz/faq/openbsd-time-zone-howto/ - const PREFIX: &str = "/usr/share/zoneinfo/"; + // Per : + // “ The /etc/localtime file configures the system-wide timezone of the local system that is + // used by applications for presentation to the user. It should be an absolute or relative + // symbolic link pointing to /usr/share/zoneinfo/, followed by a timezone identifier such as + // "Europe/Berlin" or "Etc/UTC". The resulting link should lead to the corresponding binary + // tzfile(5) timezone data for the configured timezone. ” + // Systemd does not canonicalize the link, but only checks if it is prefixed by + // "/usr/share/zoneinfo/" or "../usr/share/zoneinfo/". So we do the same. + // + + const PREFIXES: &[&str] = &[ + "/usr/share/zoneinfo/", // absolute path + "../usr/share/zoneinfo/", // relative path + ]; let mut s = read_link("/etc/localtime")? .into_os_string() .into_string() .map_err(|_| crate::GetTimezoneError::FailedParsingString)?; - if !s.starts_with(PREFIX) { - return Err(crate::GetTimezoneError::FailedParsingString); + for &prefix in PREFIXES { + if s.starts_with(prefix) { + // Trim to the correct length without allocating. + s.replace_range(..prefix.len(), ""); + return Ok(s); + } } - - // Trim to the correct length without allocating. - s.replace_range(..PREFIX.len(), ""); - Ok(s) + Err(crate::GetTimezoneError::FailedParsingString) }