]>
Commit | Line | Data |
---|---|---|
f3a8d1d7 WB |
1 | use std::mem::{self, MaybeUninit}; |
2 | ||
3 | use chrono::prelude::*; | |
b2b3485d | 4 | use failure::*; |
f3a8d1d7 WB |
5 | use serde_json::{json, Value}; |
6 | ||
e18a6c9e | 7 | use proxmox::tools::fs::{file_read_firstline, file_set_contents}; |
b2b3485d | 8 | |
4ebf0eab | 9 | use crate::api2::types::*; |
f3a8d1d7 WB |
10 | use crate::api_schema::router::*; |
11 | use crate::api_schema::*; | |
0463602a DM |
12 | |
13 | fn 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 |
43 | fn 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 |
60 | fn 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(¶m, "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 |
83 | pub 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 |