]>
Commit | Line | Data |
---|---|---|
30f57724 | 1 | use anyhow::{bail, format_err, Error}; |
f3a8d1d7 WB |
2 | use serde_json::{json, Value}; |
3 | ||
4b40148c | 4 | use proxmox::api::{api, Router, Permission}; |
feaa1ad3 | 5 | use proxmox::tools::fs::{file_read_firstline, replace_file, CreateOptions}; |
b2b3485d | 6 | |
8cc3760e | 7 | use pbs_api_types::{NODE_SCHEMA, TIME_ZONE_SCHEMA, PRIV_SYS_MODIFY}; |
0463602a DM |
8 | |
9 | fn read_etc_localtime() -> Result<String, Error> { | |
13f8310c | 10 | // use /etc/timezone |
e18a6c9e | 11 | if let Ok(line) = file_read_firstline("/etc/timezone") { |
13f8310c WB |
12 | return Ok(line.trim().to_owned()); |
13 | } | |
0463602a | 14 | |
13f8310c | 15 | // otherwise guess from the /etc/localtime symlink |
30f57724 DM |
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(); | |
13f8310c WB |
20 | match link.rfind("/zoneinfo/") { |
21 | Some(pos) => Ok(link[(pos + 10)..].to_string()), | |
22 | None => Ok(link.to_string()), | |
23 | } | |
0463602a | 24 | } |
b2b3485d | 25 | |
4b40148c DM |
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> { | |
6a7be83e DM |
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; | |
0463602a | 63 | |
b2b3485d | 64 | Ok(json!({ |
0463602a DM |
65 | "timezone": read_etc_localtime()?, |
66 | "time": time, | |
67 | "localtime": localtime, | |
b2b3485d DM |
68 | })) |
69 | } | |
70 | ||
4b40148c DM |
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 | }, | |
74c08a57 DM |
84 | access: { |
85 | permission: &Permission::Privilege(&["system", "time"], PRIV_SYS_MODIFY, false), | |
86 | }, | |
4b40148c DM |
87 | )] |
88 | /// Set time zone | |
6049b71f | 89 | fn set_timezone( |
4b40148c DM |
90 | timezone: String, |
91 | _param: Value, | |
6049b71f | 92 | ) -> Result<Value, Error> { |
e6ffeb91 DM |
93 | let path = std::path::PathBuf::from(format!("/usr/share/zoneinfo/{}", timezone)); |
94 | ||
95 | if !path.exists() { | |
96 | bail!("No such timezone."); | |
97 | } | |
98 | ||
feaa1ad3 | 99 | replace_file("/etc/timezone", timezone.as_bytes(), CreateOptions::new())?; |
e6ffeb91 DM |
100 | |
101 | let _ = std::fs::remove_file("/etc/localtime"); | |
102 | ||
103 | use std::os::unix::fs::symlink; | |
104 | symlink(path, "/etc/localtime")?; | |
105 | ||
e6ffeb91 DM |
106 | Ok(Value::Null) |
107 | } | |
108 | ||
255f378a | 109 | pub const ROUTER: Router = Router::new() |
4b40148c DM |
110 | .get(&API_METHOD_GET_TIME) |
111 | .put(&API_METHOD_SET_TIMEZONE); |