cadmus_core/device/time.rs
1use anyhow::Error;
2use chrono_tz::Tz;
3use std::ffi::CString;
4use std::path::Path;
5
6const ZONEINFO_DIR: &str = "/etc/zoneinfo";
7const LOCALTIME: &str = "/etc/localtime";
8const TIMEZONE_FILE: &str = "/etc/timezone";
9
10unsafe extern "C" {
11 fn tzset();
12}
13
14/// Sets the system timezone on Kobo devices.
15///
16/// # Kobo
17///
18/// This function performs three operations to ensure the timezone change is persistent and
19/// immediately reflected in the running process:
20///
21/// 1. Creates `/etc/localtime` as a symlink to the appropriate zoneinfo file (recognized by
22/// system utilities and the C library).
23/// 2. Writes the timezone name to `/etc/timezone` for persistence across reboots.
24/// 3. Updates the current process's timezone state by setting the `TZ` environment variable
25/// and calling `libc::tzset()`. This ensures that subsequent calls to libc time functions
26/// in this process reflect the new timezone immediately, rather than the system-wide
27/// timezone being adopted only after the process restarts.
28///
29/// # Errors
30///
31/// Returns an error if any filesystem operations fail.
32pub fn set_system_timezone(tz: Tz) -> Result<(), Error> {
33 cfg_select! {
34 feature = "kobo" => {
35 let tz_name = tz.to_string();
36 let tz_path = Path::new(ZONEINFO_DIR).join(&tz_name);
37
38 std::fs::remove_file(LOCALTIME).ok();
39 std::os::unix::fs::symlink(&tz_path, LOCALTIME)?;
40 std::fs::write(TIMEZONE_FILE, &tz_name)?;
41
42 unsafe {
43 let tz_cstr = CString::new(tz_name.as_str())?;
44 libc::setenv(c"TZ".as_ptr(), tz_cstr.as_ptr(), 1);
45 tzset();
46 }
47
48 tracing::info!(tz = %tz_name, "system timezone updated");
49 Ok(())
50 }
51 _ => unimplemented!("set_system_timezone is only available on Kobo devices")
52 }
53}