diff --git a/Cargo.toml b/Cargo.toml index 75d86b75..899098f9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,6 +35,7 @@ members = [ "proxmox-system-management-api", "proxmox-tfa", "proxmox-time", + "proxmox-time-api", "proxmox-uuid", ] exclude = [ diff --git a/proxmox-time-api/Cargo.toml b/proxmox-time-api/Cargo.toml new file mode 100644 index 00000000..7eb5265d --- /dev/null +++ b/proxmox-time-api/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "proxmox-time-api" +version = "0.1.0" +authors.workspace = true +edition.workspace = true +license.workspace = true +repository.workspace = true +exclude.workspace = true +description = "Time Management API implementation" + +[dependencies] +anyhow.workspace = true +serde = { workspace = true, features = ["derive"] } + +proxmox-sys = { workspace = true, optional = true } +proxmox-schema = { workspace = true, features = ["api-macro", "api-types"] } +proxmox-time = { workspace = true, optional = true } +proxmox-product-config = { workspace = true, optional = true } + +[features] +default = [] +impl = [ + "dep:proxmox-product-config", + "dep:proxmox-sys", + "dep:proxmox-time", +] diff --git a/proxmox-time-api/debian/changelog b/proxmox-time-api/debian/changelog new file mode 100644 index 00000000..9c7e33ff --- /dev/null +++ b/proxmox-time-api/debian/changelog @@ -0,0 +1,6 @@ +rust-proxmox-time-api (0.1.0-1) bookworm; urgency=medium + + * initial packaging (split out from proxmox-system-management-api) + + -- Proxmox Support Team Thu, 30 May 2024 08:51:30 +0200 + diff --git a/proxmox-time-api/debian/control b/proxmox-time-api/debian/control new file mode 100644 index 00000000..34eff778 --- /dev/null +++ b/proxmox-time-api/debian/control @@ -0,0 +1,61 @@ +Source: rust-proxmox-time-api +Section: rust +Priority: optional +Build-Depends: debhelper (>= 12), + dh-cargo (>= 25), + cargo:native , + rustc:native , + libstd-rust-dev , + librust-anyhow-1+default-dev , + librust-proxmox-schema-3+api-macro-dev (>= 3.1.1-~~) , + librust-proxmox-schema-3+api-types-dev (>= 3.1.1-~~) , + librust-proxmox-schema-3+default-dev (>= 3.1.1-~~) , + librust-serde-1+default-dev , + librust-serde-1+derive-dev +Maintainer: Proxmox Support Team +Standards-Version: 4.6.2 +Vcs-Git: git://git.proxmox.com/git/proxmox.git +Vcs-Browser: https://git.proxmox.com/?p=proxmox.git +X-Cargo-Crate: proxmox-time-api +Rules-Requires-Root: no + +Package: librust-proxmox-time-api-dev +Architecture: any +Multi-Arch: same +Depends: + ${misc:Depends}, + librust-anyhow-1+default-dev, + librust-proxmox-schema-3+api-macro-dev (>= 3.1.1-~~), + librust-proxmox-schema-3+api-types-dev (>= 3.1.1-~~), + librust-proxmox-schema-3+default-dev (>= 3.1.1-~~), + librust-serde-1+default-dev, + librust-serde-1+derive-dev +Suggests: + librust-proxmox-time-api+impl-dev (= ${binary:Version}) +Provides: + librust-proxmox-time-api+default-dev (= ${binary:Version}), + librust-proxmox-time-api-0-dev (= ${binary:Version}), + librust-proxmox-time-api-0+default-dev (= ${binary:Version}), + librust-proxmox-time-api-0.1-dev (= ${binary:Version}), + librust-proxmox-time-api-0.1+default-dev (= ${binary:Version}), + librust-proxmox-time-api-0.1.0-dev (= ${binary:Version}), + librust-proxmox-time-api-0.1.0+default-dev (= ${binary:Version}) +Description: Time Management API implementation - Rust source code + Source code for Debianized Rust crate "proxmox-time-api" + +Package: librust-proxmox-time-api+impl-dev +Architecture: any +Multi-Arch: same +Depends: + ${misc:Depends}, + librust-proxmox-time-api-dev (= ${binary:Version}), + librust-proxmox-product-config-0.1+default-dev, + librust-proxmox-sys-0.5+default-dev (>= 0.5.5-~~), + librust-proxmox-time-1+default-dev (>= 1.1.6-~~) +Provides: + librust-proxmox-time-api-0+impl-dev (= ${binary:Version}), + librust-proxmox-time-api-0.1+impl-dev (= ${binary:Version}), + librust-proxmox-time-api-0.1.0+impl-dev (= ${binary:Version}) +Description: Time Management API implementation - feature "impl" + This metapackage enables feature "impl" for the Rust proxmox-time-api crate, by + pulling in any additional dependencies needed by that feature. diff --git a/proxmox-time-api/debian/debcargo.toml b/proxmox-time-api/debian/debcargo.toml new file mode 100644 index 00000000..b7864cdb --- /dev/null +++ b/proxmox-time-api/debian/debcargo.toml @@ -0,0 +1,7 @@ +overlay = "." +crate_src_path = ".." +maintainer = "Proxmox Support Team " + +[source] +vcs_git = "git://git.proxmox.com/git/proxmox.git" +vcs_browser = "https://git.proxmox.com/?p=proxmox.git" diff --git a/proxmox-time-api/src/api_types.rs b/proxmox-time-api/src/api_types.rs new file mode 100644 index 00000000..53764888 --- /dev/null +++ b/proxmox-time-api/src/api_types.rs @@ -0,0 +1,29 @@ +use serde::{Deserialize, Serialize}; + +use proxmox_schema::api; +use proxmox_schema::api_types::TIME_ZONE_SCHEMA; + +#[api( + properties: { + timezone: { + schema: TIME_ZONE_SCHEMA, + }, + time: { + type: i64, + description: "Seconds since 1970-01-01 00:00:00 UTC.", + minimum: 1_297_163_644, + }, + localtime: { + type: i64, + description: "Seconds since 1970-01-01 00:00:00 UTC. (local time)", + minimum: 1_297_163_644, + }, + } +)] +#[derive(Serialize, Deserialize)] +/// Server time and timezone. +pub struct ServerTimeInfo { + pub timezone: String, + pub time: i64, + pub localtime: i64, +} diff --git a/proxmox-time-api/src/lib.rs b/proxmox-time-api/src/lib.rs new file mode 100644 index 00000000..45b2073f --- /dev/null +++ b/proxmox-time-api/src/lib.rs @@ -0,0 +1,7 @@ +mod api_types; +pub use api_types::*; + +#[cfg(feature = "impl")] +mod time_impl; +#[cfg(feature = "impl")] +pub use time_impl::*; diff --git a/proxmox-time-api/src/time_impl.rs b/proxmox-time-api/src/time_impl.rs new file mode 100644 index 00000000..3d5aee6f --- /dev/null +++ b/proxmox-time-api/src/time_impl.rs @@ -0,0 +1,55 @@ +use anyhow::{bail, format_err, Error}; + +use proxmox_product_config::replace_system_config; +use proxmox_sys::fs::file_read_firstline; + +use super::ServerTimeInfo; + +pub fn read_etc_localtime() -> Result { + // use /etc/timezone + if let Ok(line) = file_read_firstline("/etc/timezone") { + return Ok(line.trim().to_owned()); + } + + // otherwise guess from the /etc/localtime symlink + let link = std::fs::read_link("/etc/localtime") + .map_err(|err| format_err!("failed to guess timezone - {}", err))?; + + let link = link.to_string_lossy(); + match link.rfind("/zoneinfo/") { + Some(pos) => Ok(link[(pos + 10)..].to_string()), + None => Ok(link.to_string()), + } +} + +pub fn set_timezone(timezone: String) -> Result<(), Error> { + let path = std::path::PathBuf::from(format!("/usr/share/zoneinfo/{}", timezone)); + + if !path.exists() { + bail!("No such timezone."); + } + + replace_system_config("/etc/timezone", timezone.as_bytes())?; + + let _ = std::fs::remove_file("/etc/localtime"); + + use std::os::unix::fs::symlink; + symlink(path, "/etc/localtime")?; + + Ok(()) +} + +/// Read server time and time zone settings. +pub fn get_server_time_info() -> Result { + let time = proxmox_time::epoch_i64(); + let tm = proxmox_time::localtime(time)?; + let offset = tm.tm_gmtoff; + + let localtime = time + offset; + + Ok(ServerTimeInfo { + timezone: read_etc_localtime()?, + time: time, + localtime: localtime, + }) +}