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