From a74d1430b939c5c5ce5af3f40509b46acbbe14fb Mon Sep 17 00:00:00 2001 From: YodonTan Date: Mon, 31 Aug 2026 04:47:15 +0800 Subject: [PATCH] ohos: adapt uucore, hostid and date for aarch64-unknown-linux-ohos Fixes required to build uutils/coreutils on HarmonyOS (aarch64-unknown-linux-ohos): - uucore/fsext: statfs.f_type is u64 on OHOS; route it through the musl branch. - hostid: implement gethostid locally (read /etc/hostid, else hash hostname) because the OHOS SDK libc dropped the symbol. - date: pass through the system time zone ID from OH_TimeService_GetTimeZone and resolve it with embedded IANA tzdata (jiff-tzdb) via TimeZone::tzif, instead of relying on /etc/localtime or a POSIX-injected TZ. The OHOS-only helper is cfg-gated; non-OHOS code paths are byte-identical to upstream. utmpx is intentionally left untouched: upstream #14252 disables it on OHOS (no utmp data source there), and this PR defers to that approach. Also syncs fuzz/Cargo.lock after adding the jiff-tzdb dependency. Verified on-device: date matches system time (+0800 CST; 1987-06-01 -> +0900 CDT), hostid behaves, builds pass on the non-utmpx feature set. --- Cargo.lock | 1 + fuzz/Cargo.lock | 1 + src/uu/date/Cargo.toml | 6 ++++ src/uu/date/src/date.rs | 45 +++++++++++++++++++++++++++- src/uu/hostid/src/hostid.rs | 25 ++++++++++++++++ src/uucore/src/lib/features/fsext.rs | 5 ++-- 6 files changed, 80 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 09b0147fed3..7a831a766fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3478,6 +3478,7 @@ dependencies = [ "icu_locale", "jiff", "jiff-icu", + "jiff-tzdb", "libc", "parse_datetime", "rustix", diff --git a/fuzz/Cargo.lock b/fuzz/Cargo.lock index f7292d6aecd..eca33902ad1 100644 --- a/fuzz/Cargo.lock +++ b/fuzz/Cargo.lock @@ -1877,6 +1877,7 @@ dependencies = [ "icu_locale", "jiff", "jiff-icu", + "jiff-tzdb", "libc", "parse_datetime", "rustix", diff --git a/src/uu/date/Cargo.toml b/src/uu/date/Cargo.toml index 4c06844a7e7..13cd519cbf3 100644 --- a/src/uu/date/Cargo.toml +++ b/src/uu/date/Cargo.toml @@ -44,6 +44,12 @@ uucore = { workspace = true, features = ["parser", "i18n-datetime"] } libc = { workspace = true } rustix = { workspace = true, features = ["time"] } +[target.'cfg(target_env = "ohos")'.dependencies] +# OHOS has no /usr/share/zoneinfo or /etc/localtime: embed IANA tzdata so +# ohos_system_zone() can resolve the TimeService timezone ID directly (pass-through, +# no environment injection). +jiff-tzdb = "0.1" + [target.'cfg(windows)'.dependencies] windows-sys = { workspace = true, features = [ "Win32_Foundation", diff --git a/src/uu/date/src/date.rs b/src/uu/date/src/date.rs index f6296c48529..2433281890e 100644 --- a/src/uu/date/src/date.rs +++ b/src/uu/date/src/date.rs @@ -32,6 +32,36 @@ use windows_sys::Win32::{Foundation::SYSTEMTIME, System::SystemInformation::SetS use uucore::parser::shortcut_value_parser::ShortcutValueParser; +/// OHOS helper: pass through the system time zone ID returned by +/// TimeService (OH_TimeService_GetTimeZone, e.g. "Asia/Shanghai") and +/// resolve it against the embedded IANA tzdata (jiff-tzdb) so that +/// historial DST rules and transitions are preserved. jiff's +/// `try_system()` is useless on OHOS because both `/etc/localtime` and +/// the zoneinfo dirs are absent. +#[cfg(target_env = "ohos")] +fn ohos_system_zone() -> jiff::tz::TimeZone { + use core::ffi::{CStr, c_char}; + + #[link(name = "time_service_ndk")] + unsafe extern "C" { + fn OH_TimeService_GetTimeZone(tz: *mut c_char, len: u32) -> i32; + } + let mut buf = [0u8; 64]; + let rc = unsafe { OH_TimeService_GetTimeZone(buf.as_mut_ptr() as *mut c_char, 64) }; + if rc != 0 { + return jiff::tz::TimeZone::UTC; + } + let id = unsafe { CStr::from_ptr(buf.as_ptr() as *const c_char) } + .to_string_lossy() + .into_owned(); + if let Some((name, tzif)) = jiff_tzdb::get(&id) { + if let Ok(tz) = jiff::tz::TimeZone::tzif(name, tzif) { + return tz; + } + } + jiff::tz::TimeZone::UTC +} + // Options const DATE: &str = "date"; const HOURS: &str = "hours"; @@ -371,7 +401,14 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let now = if utc { Timestamp::now().to_zoned(TimeZone::UTC) } else { - Zoned::now() + #[cfg(target_env = "ohos")] + { + Timestamp::now().to_zoned(ohos_system_zone()) + } + #[cfg(not(target_env = "ohos"))] + { + Zoned::now() + } }; let set_to = match matches.get_one::(OPT_SET) { @@ -557,12 +594,18 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { translate!("date-error-cannot-set-date", "path" => path.quote(), "error" => e), ) })?; + #[cfg(target_env = "ohos")] + let date = ts.to_zoned(ohos_system_zone()); + #[cfg(not(target_env = "ohos"))] let date = ts.to_zoned(TimeZone::try_system().unwrap_or(TimeZone::UTC)); let iter = std::iter::once(Ok(ParsedDateTime::InRange(date))); Box::new(iter) } DateSource::Resolution => { let resolution = get_clock_resolution(); + #[cfg(target_env = "ohos")] + let date = resolution.to_zoned(ohos_system_zone()); + #[cfg(not(target_env = "ohos"))] let date = resolution.to_zoned(TimeZone::system()); let iter = std::iter::once(Ok(ParsedDateTime::InRange(date))); Box::new(iter) diff --git a/src/uu/hostid/src/hostid.rs b/src/uu/hostid/src/hostid.rs index c6fc47e4f72..c7dbfa495bf 100644 --- a/src/uu/hostid/src/hostid.rs +++ b/src/uu/hostid/src/hostid.rs @@ -7,12 +7,37 @@ use clap::Command; use core::ffi::c_long; +#[cfg(not(target_env = "ohos"))] use libc::gethostid; use std::io::{Write, stdout}; use uucore::{error::UResult, format_usage}; use uucore::translate; +// OHOS SDK libc no longer exports gethostid; replicate the glibc semantics: +// read /etc/hostid when present, otherwise hash the hostname. +#[cfg(target_env = "ohos")] +fn gethostid() -> c_long { + use std::fs::read; + if let Ok(data) = read("/etc/hostid") { + if data.len() >= 4 { + let n: u32 = u32::from_ne_bytes([data[0], data[1], data[2], data[3]]); + return n as c_long; + } + } + let mut name = [0u8; 256]; + if unsafe { libc::gethostname(name.as_mut_ptr() as *mut _, name.len()) } == 0 { + let end = name.iter().position(|&b| b == 0).unwrap_or(name.len()); + let mut h: u32 = 0x811c9dc5; + for &b in &name[..end] { + h ^= b as u32; + h = h.wrapping_mul(0x01000193); + } + return h as c_long; + } + 0 +} + #[uucore::main(no_signals)] pub fn uumain(args: impl uucore::Args) -> UResult<()> { uucore::clap_localization::handle_clap_result(uu_app(), args)?; diff --git a/src/uucore/src/lib/features/fsext.rs b/src/uucore/src/lib/features/fsext.rs index 0bca65ec960..de9c77dec97 100644 --- a/src/uucore/src/lib/features/fsext.rs +++ b/src/uucore/src/lib/features/fsext.rs @@ -799,7 +799,7 @@ impl FsMeta for StatFs { ))] fn fs_type(&self) -> i64 { #[cfg(all( - not(target_env = "musl"), + not(any(target_env = "musl", target_env = "ohos")), not(target_vendor = "apple"), not(target_os = "android"), not(target_os = "freebsd"), @@ -808,7 +808,7 @@ impl FsMeta for StatFs { ))] return self.f_type; #[cfg(all( - not(target_env = "musl"), + not(any(target_env = "musl", target_env = "ohos")), any( target_vendor = "apple", all(target_os = "android", target_pointer_width = "32"), @@ -820,6 +820,7 @@ impl FsMeta for StatFs { return self.f_type.into(); #[cfg(any( target_env = "musl", + target_env = "ohos", all(target_os = "android", target_pointer_width = "64"), ))] return self.f_type.try_into().unwrap();