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