• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use log::LevelFilter;
2 use serde_json::{Map, Value};
3 
4 // Directory for Bluetooth hci devices
5 pub const HCI_DEVICES_DIR: &str = "/sys/class/bluetooth";
6 
7 // File to store the Bluetooth daemon to use (bluez or floss)
8 const BLUETOOTH_DAEMON_CURRENT: &str = "/var/lib/bluetooth/bluetooth-daemon.current";
9 
10 // File to store the config for BluetoothManager
11 const BTMANAGERD_CONF: &str = "/var/lib/bluetooth/btmanagerd.json";
12 
is_floss_enabled() -> bool13 pub fn is_floss_enabled() -> bool {
14     match std::fs::read(BLUETOOTH_DAEMON_CURRENT) {
15         Ok(v) => {
16             let content = std::str::from_utf8(&v);
17             match content {
18                 Ok(version) => version.contains("floss"),
19                 Err(_) => false,
20             }
21         }
22         Err(_) => false,
23     }
24 }
25 
write_floss_enabled(enabled: bool) -> bool26 pub fn write_floss_enabled(enabled: bool) -> bool {
27     std::fs::write(
28         BLUETOOTH_DAEMON_CURRENT,
29         match enabled {
30             true => "floss",
31             _ => "bluez",
32         },
33     )
34     .is_ok()
35 }
36 
read_config() -> std::io::Result<String>37 pub fn read_config() -> std::io::Result<String> {
38     std::fs::read_to_string(BTMANAGERD_CONF)
39 }
40 
get_log_level() -> Option<LevelFilter>41 pub fn get_log_level() -> Option<LevelFilter> {
42     get_log_level_internal(read_config().ok()?)
43 }
44 
get_log_level_internal(config: String) -> Option<LevelFilter>45 fn get_log_level_internal(config: String) -> Option<LevelFilter> {
46     serde_json::from_str::<Value>(config.as_str())
47         .ok()?
48         .get("log_level")?
49         .as_str()?
50         .parse::<LevelFilter>()
51         .ok()
52 }
53 
54 /// Returns whether hci N is enabled in config; defaults to true.
is_hci_n_enabled(n: i32) -> bool55 pub fn is_hci_n_enabled(n: i32) -> bool {
56     match read_config().ok().and_then(|config| is_hci_n_enabled_internal(config, n)) {
57         Some(v) => v,
58         _ => true,
59     }
60 }
61 
is_hci_n_enabled_internal(config: String, n: i32) -> Option<bool>62 fn is_hci_n_enabled_internal(config: String, n: i32) -> Option<bool> {
63     serde_json::from_str::<Value>(config.as_str())
64         .ok()?
65         .get(format!("hci{}", n))?
66         .as_object()?
67         .get("enabled")?
68         .as_bool()
69 }
70 
71 // When we initialize BluetoothManager, we need to make sure the file is a well-formatted json.
fix_config_file_format() -> bool72 pub fn fix_config_file_format() -> bool {
73     match read_config() {
74         Ok(s) => match serde_json::from_str::<Value>(s.as_str()) {
75             Ok(_) => true,
76             _ => std::fs::write(BTMANAGERD_CONF, "{}").is_ok(),
77         },
78         _ => std::fs::write(BTMANAGERD_CONF, "{}").is_ok(),
79     }
80 }
81 
modify_hci_n_enabled(n: i32, enabled: bool) -> bool82 pub fn modify_hci_n_enabled(n: i32, enabled: bool) -> bool {
83     if !fix_config_file_format() {
84         false
85     } else {
86         match read_config()
87             .ok()
88             .and_then(|config| modify_hci_n_enabled_internal(config, n, enabled))
89         {
90             Some(s) => std::fs::write(BTMANAGERD_CONF, s).is_ok(),
91             _ => false,
92         }
93     }
94 }
95 
modify_hci_n_enabled_internal(config: String, n: i32, enabled: bool) -> Option<String>96 fn modify_hci_n_enabled_internal(config: String, n: i32, enabled: bool) -> Option<String> {
97     let hci_interface = format!("hci{}", n);
98     let mut o = serde_json::from_str::<Value>(config.as_str()).ok()?;
99     match o.get_mut(hci_interface.clone()) {
100         Some(section) => {
101             section.as_object_mut()?.insert("enabled".to_string(), Value::Bool(enabled));
102             serde_json::ser::to_string_pretty(&o).ok()
103         }
104         _ => {
105             let mut entry_map = Map::new();
106             entry_map.insert("enabled".to_string(), Value::Bool(enabled));
107             o.as_object_mut()?.insert(hci_interface, Value::Object(entry_map));
108             serde_json::ser::to_string_pretty(&o).ok()
109         }
110     }
111 }
112 
list_hci_devices() -> Vec<i32>113 pub fn list_hci_devices() -> Vec<i32> {
114     hci_devices_string_to_int(list_hci_devices_string())
115 }
116 
list_hci_devices_string() -> Vec<String>117 fn list_hci_devices_string() -> Vec<String> {
118     match std::fs::read_dir(HCI_DEVICES_DIR) {
119         Ok(entries) => entries
120             .map(|e| e.unwrap().path().file_name().unwrap().to_str().unwrap().to_string())
121             .collect::<Vec<_>>(),
122         _ => Vec::new(),
123     }
124 }
125 
hci_devices_string_to_int(devices: Vec<String>) -> Vec<i32>126 fn hci_devices_string_to_int(devices: Vec<String>) -> Vec<i32> {
127     devices
128         .into_iter()
129         .filter_map(|e| if e.starts_with("hci") { e[3..].parse::<i32>().ok() } else { None })
130         .collect()
131 }
132 
list_pid_files(pid_dir: &str) -> Vec<String>133 pub fn list_pid_files(pid_dir: &str) -> Vec<String> {
134     match std::fs::read_dir(pid_dir) {
135         Ok(entries) => entries
136             .map(|e| e.unwrap().path().file_name().unwrap().to_str().unwrap().to_string())
137             .collect::<Vec<_>>(),
138         _ => Vec::new(),
139     }
140 }
141 
142 #[cfg(test)]
143 mod tests {
144     use super::*;
145 
is_hci_n_enabled_internal_wrapper(config: String, n: i32) -> bool146     fn is_hci_n_enabled_internal_wrapper(config: String, n: i32) -> bool {
147         is_hci_n_enabled_internal(config, n).or(Some(true)).unwrap()
148     }
149 
150     #[test]
parse_log_level()151     fn parse_log_level() {
152         assert_eq!(
153             get_log_level_internal("{\"log_level\": \"error\"}".to_string()).unwrap(),
154             LevelFilter::Error
155         );
156         assert_eq!(
157             get_log_level_internal("{\"log_level\": \"warn\"}".to_string()).unwrap(),
158             LevelFilter::Warn
159         );
160         assert_eq!(
161             get_log_level_internal("{\"log_level\": \"info\"}".to_string()).unwrap(),
162             LevelFilter::Info
163         );
164         assert_eq!(
165             get_log_level_internal("{\"log_level\": \"debug\"}".to_string()).unwrap(),
166             LevelFilter::Debug
167         );
168         assert_eq!(
169             get_log_level_internal("{\"log_level\": \"trace\"}".to_string()).unwrap(),
170             LevelFilter::Trace
171         );
172         assert_eq!(
173             get_log_level_internal("{\"log_level\": \"random\"}".to_string()).is_none(),
174             true
175         );
176     }
177 
178     #[test]
parse_hci0_enabled()179     fn parse_hci0_enabled() {
180         assert_eq!(
181             is_hci_n_enabled_internal_wrapper("{\"hci0\":\n{\"enabled\": true}}".to_string(), 0),
182             true
183         );
184     }
185 
186     #[test]
modify_hci0_enabled()187     fn modify_hci0_enabled() {
188         let modified_string =
189             modify_hci_n_enabled_internal("{\"hci0\":\n{\"enabled\": false}}".to_string(), 0, true)
190                 .unwrap();
191         assert_eq!(is_hci_n_enabled_internal_wrapper(modified_string, 0), true);
192     }
193 
194     #[test]
modify_hci0_enabled_from_empty()195     fn modify_hci0_enabled_from_empty() {
196         let modified_string = modify_hci_n_enabled_internal("{}".to_string(), 0, true).unwrap();
197         assert_eq!(is_hci_n_enabled_internal_wrapper(modified_string, 0), true);
198     }
199 
200     #[test]
parse_hci0_not_enabled()201     fn parse_hci0_not_enabled() {
202         assert_eq!(
203             is_hci_n_enabled_internal_wrapper("{\"hci0\":\n{\"enabled\": false}}".to_string(), 0),
204             false
205         );
206     }
207 
208     #[test]
parse_hci1_not_present()209     fn parse_hci1_not_present() {
210         assert_eq!(
211             is_hci_n_enabled_internal_wrapper("{\"hci0\":\n{\"enabled\": true}}".to_string(), 1),
212             true
213         );
214     }
215 
216     #[test]
test_hci_devices_string_to_int_none()217     fn test_hci_devices_string_to_int_none() {
218         assert_eq!(hci_devices_string_to_int(vec!["somethingelse".to_string()]), Vec::<i32>::new());
219     }
220 
221     #[test]
test_hci_devices_string_to_int_one()222     fn test_hci_devices_string_to_int_one() {
223         assert_eq!(hci_devices_string_to_int(vec!["hci0".to_string()]), vec![0]);
224     }
225 
226     #[test]
test_hci_devices_string_to_int_two()227     fn test_hci_devices_string_to_int_two() {
228         assert_eq!(
229             hci_devices_string_to_int(vec!["hci0".to_string(), "hci1".to_string()]),
230             vec![0, 1]
231         );
232     }
233 }
234