]> git.proxmox.com Git - proxmox-backup.git/blob - src/api2/node/time.rs
88f64117da7a307e18e5cdd1615118231a05dda3
[proxmox-backup.git] / src / api2 / node / time.rs
1 use anyhow::{bail, format_err, Error};
2 use serde_json::{json, Value};
3
4 use proxmox_sys::fs::{file_read_firstline, replace_file, CreateOptions};
5 use proxmox_router::{Router, Permission};
6 use proxmox_schema::api;
7
8 use pbs_api_types::{NODE_SCHEMA, TIME_ZONE_SCHEMA, PRIV_SYS_MODIFY};
9
10 fn read_etc_localtime() -> Result<String, Error> {
11 // use /etc/timezone
12 if let Ok(line) = file_read_firstline("/etc/timezone") {
13 return Ok(line.trim().to_owned());
14 }
15
16 // otherwise guess from the /etc/localtime symlink
17 let link = std::fs::read_link("/etc/localtime").
18 map_err(|err| format_err!("failed to guess timezone - {}", err))?;
19
20 let link = link.to_string_lossy();
21 match link.rfind("/zoneinfo/") {
22 Some(pos) => Ok(link[(pos + 10)..].to_string()),
23 None => Ok(link.to_string()),
24 }
25 }
26
27 #[api(
28 input: {
29 properties: {
30 node: {
31 schema: NODE_SCHEMA,
32 },
33 },
34 },
35 returns: {
36 description: "Returns server time and timezone.",
37 properties: {
38 timezone: {
39 schema: TIME_ZONE_SCHEMA,
40 },
41 time: {
42 type: i64,
43 description: "Seconds since 1970-01-01 00:00:00 UTC.",
44 minimum: 1_297_163_644,
45 },
46 localtime: {
47 type: i64,
48 description: "Seconds since 1970-01-01 00:00:00 UTC. (local time)",
49 minimum: 1_297_163_644,
50 },
51 }
52 },
53 access: {
54 permission: &Permission::Anybody,
55 },
56 )]
57 /// Read server time and time zone settings.
58 fn get_time(_param: Value) -> Result<Value, Error> {
59 let time = proxmox_time::epoch_i64();
60 let tm = proxmox_time::localtime(time)?;
61 let offset = tm.tm_gmtoff;
62
63 let localtime = time + offset;
64
65 Ok(json!({
66 "timezone": read_etc_localtime()?,
67 "time": time,
68 "localtime": localtime,
69 }))
70 }
71
72 #[api(
73 protected: true,
74 reload_timezone: true,
75 input: {
76 properties: {
77 node: {
78 schema: NODE_SCHEMA,
79 },
80 timezone: {
81 schema: TIME_ZONE_SCHEMA,
82 },
83 },
84 },
85 access: {
86 permission: &Permission::Privilege(&["system", "time"], PRIV_SYS_MODIFY, false),
87 },
88 )]
89 /// Set time zone
90 fn set_timezone(
91 timezone: String,
92 _param: Value,
93 ) -> Result<Value, Error> {
94 let path = std::path::PathBuf::from(format!("/usr/share/zoneinfo/{}", timezone));
95
96 if !path.exists() {
97 bail!("No such timezone.");
98 }
99
100 replace_file("/etc/timezone", timezone.as_bytes(), CreateOptions::new(), true)?;
101
102 let _ = std::fs::remove_file("/etc/localtime");
103
104 use std::os::unix::fs::symlink;
105 symlink(path, "/etc/localtime")?;
106
107 Ok(Value::Null)
108 }
109
110 pub const ROUTER: Router = Router::new()
111 .get(&API_METHOD_GET_TIME)
112 .put(&API_METHOD_SET_TIMEZONE);