Skip to main content

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}