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