]> git.proxmox.com Git - proxmox-backup.git/blame - src/api2/node/time.rs
use const api definitions
[proxmox-backup.git] / src / api2 / node / time.rs
CommitLineData
f3a8d1d7
WB
1use std::mem::{self, MaybeUninit};
2
3use chrono::prelude::*;
b2b3485d 4use failure::*;
f3a8d1d7
WB
5use serde_json::{json, Value};
6
e18a6c9e 7use proxmox::tools::fs::{file_read_firstline, file_set_contents};
b2b3485d 8
4ebf0eab 9use crate::api2::types::*;
f3a8d1d7
WB
10use crate::api_schema::router::*;
11use crate::api_schema::*;
0463602a
DM
12
13fn read_etc_localtime() -> Result<String, Error> {
13f8310c 14 // use /etc/timezone
e18a6c9e 15 if let Ok(line) = file_read_firstline("/etc/timezone") {
13f8310c
WB
16 return Ok(line.trim().to_owned());
17 }
0463602a 18
13f8310c 19 // otherwise guess from the /etc/localtime symlink
f3a8d1d7 20 let mut buf = MaybeUninit::<[u8; 64]>::uninit();
13f8310c 21 let len = unsafe {
f3a8d1d7
WB
22 libc::readlink(
23 "/etc/localtime".as_ptr() as *const _,
24 buf.as_mut_ptr() as *mut _,
25 mem::size_of_val(&buf),
26 )
13f8310c
WB
27 };
28 if len <= 0 {
29 bail!("failed to guess timezone");
30 }
31 let len = len as usize;
f3a8d1d7
WB
32 let buf = unsafe {
33 (*buf.as_mut_ptr())[len] = 0;
34 buf.assume_init()
35 };
13f8310c
WB
36 let link = std::str::from_utf8(&buf[..len])?;
37 match link.rfind("/zoneinfo/") {
38 Some(pos) => Ok(link[(pos + 10)..].to_string()),
39 None => Ok(link.to_string()),
40 }
0463602a 41}
b2b3485d 42
6049b71f
DM
43fn get_time(
44 _param: Value,
45 _info: &ApiMethod,
dd5495d6 46 _rpcenv: &mut dyn RpcEnvironment,
6049b71f 47) -> Result<Value, Error> {
0463602a
DM
48 let datetime = Local::now();
49 let offset = datetime.offset();
50 let time = datetime.timestamp();
51 let localtime = time + (offset.fix().local_minus_utc() as i64);
52
b2b3485d 53 Ok(json!({
0463602a
DM
54 "timezone": read_etc_localtime()?,
55 "time": time,
56 "localtime": localtime,
b2b3485d
DM
57 }))
58}
59
6049b71f
DM
60fn set_timezone(
61 param: Value,
62 _info: &ApiMethod,
dd5495d6 63 _rpcenv: &mut dyn RpcEnvironment,
6049b71f 64) -> Result<Value, Error> {
e18a6c9e 65 let timezone = crate::tools::required_string_param(&param, "timezone")?;
e6ffeb91
DM
66
67 let path = std::path::PathBuf::from(format!("/usr/share/zoneinfo/{}", timezone));
68
69 if !path.exists() {
70 bail!("No such timezone.");
71 }
72
e18a6c9e 73 file_set_contents("/etc/timezone", timezone.as_bytes(), None)?;
e6ffeb91
DM
74
75 let _ = std::fs::remove_file("/etc/localtime");
76
77 use std::os::unix::fs::symlink;
78 symlink(path, "/etc/localtime")?;
79
e6ffeb91
DM
80 Ok(Value::Null)
81}
82
255f378a
DM
83pub const ROUTER: Router = Router::new()
84 .get(
85 &ApiMethod::new(
86 &ApiHandler::Sync(&get_time),
87 &ObjectSchema::new(
88 "Read server time and time zone settings.",
89 &[ ("node", false, &NODE_SCHEMA) ],
e6ffeb91 90 )
255f378a
DM
91 ).returns(
92 &ObjectSchema::new(
93 "Returns server time and timezone.",
94 &[
95 ("timezone", false, &StringSchema::new("Time zone").schema()),
96 ("time", false, &IntegerSchema::new("Seconds since 1970-01-01 00:00:00 UTC.")
97 .minimum(1_297_163_644)
98 .schema()
99 ),
100 ("localtime", false, &IntegerSchema::new("Seconds since 1970-01-01 00:00:00 UTC. (local time)")
101 .minimum(1_297_163_644)
102 .schema()
103 ),
104 ],
105 ).schema()
e6ffeb91 106 )
255f378a
DM
107 )
108 .put(
109 &ApiMethod::new(
110 &ApiHandler::Sync(&set_timezone),
111 &ObjectSchema::new(
112 "Set time zone.",
113 &[
114 ("node", false, &NODE_SCHEMA),
115 ("timezone", false, &StringSchema::new(
116 "Time zone. The file '/usr/share/zoneinfo/zone.tab' contains the list of valid names.")
117 .schema()
118 ),
119 ],
120 )
121 ).protected(true).reload_timezone(true)
122 );
123