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