coreshift_core/
netlink.rs1use crate::CoreError;
11use crate::reactor::Fd;
12
13#[cfg(target_os = "android")]
14mod imp {
15 use super::*;
16 use std::os::unix::io::AsRawFd;
17
18 fn errno() -> i32 {
19 std::io::Error::last_os_error().raw_os_error().unwrap_or(0)
20 }
21
22 pub fn uevent_open() -> Result<Fd, CoreError> {
23 unsafe {
24 let fd = libc::socket(
25 libc::AF_NETLINK,
26 libc::SOCK_RAW | libc::SOCK_CLOEXEC | libc::SOCK_NONBLOCK,
27 libc::NETLINK_KOBJECT_UEVENT,
28 );
29 if fd < 0 {
30 return Err(CoreError::sys(errno(), "netlink socket"));
31 }
32 let mut addr: libc::sockaddr_nl = std::mem::zeroed();
33 addr.nl_family = libc::AF_NETLINK as u16;
34 addr.nl_pid = 0;
35 addr.nl_groups = 1; let r = libc::bind(
37 fd,
38 &addr as *const _ as *const libc::sockaddr,
39 std::mem::size_of::<libc::sockaddr_nl>() as libc::socklen_t,
40 );
41 if r < 0 {
42 libc::close(fd);
43 return Err(CoreError::sys(errno(), "netlink bind"));
44 }
45 Fd::from_owned_raw_fd(fd, "netlink_uevent")
46 }
47 }
48
49 pub fn uevent_recv_raw(fd: &Fd, buf: &mut [u8]) -> Option<usize> {
50 let n = unsafe {
51 libc::recv(
52 fd.as_raw_fd(),
53 buf.as_mut_ptr() as *mut libc::c_void,
54 buf.len(),
55 libc::MSG_DONTWAIT,
56 )
57 };
58 if n > 0 { Some(n as usize) } else { None }
59 }
60}
61
62#[cfg(not(target_os = "android"))]
63mod imp {
64 use super::*;
65
66 pub fn uevent_open() -> Result<Fd, CoreError> {
67 Err(CoreError::sys(libc::ENOSYS, "netlink uevent: android only"))
68 }
69
70 pub fn uevent_recv_raw(_fd: &Fd, _buf: &mut [u8]) -> Option<usize> {
71 None
72 }
73}
74
75pub fn uevent_open() -> Result<Fd, CoreError> {
82 imp::uevent_open()
83}
84
85pub fn uevent_drain_battery(fd: &Fd) -> Option<(u8, String)> {
91 let mut result: Option<(u8, String)> = None;
92 let mut buf = [0u8; 4096];
93 loop {
94 match imp::uevent_recv_raw(fd, &mut buf) {
95 None => break,
96 Some(n) => {
97 if let Some(batt) = parse_battery(&buf[..n]) {
98 result = Some(batt);
99 }
100 }
101 }
102 }
103 result
104}
105
106fn parse_battery(msg: &[u8]) -> Option<(u8, String)> {
107 let parts: Vec<&str> = msg
108 .split(|&b| b == 0)
109 .filter_map(|s| std::str::from_utf8(s).ok())
110 .filter(|s| !s.is_empty())
111 .collect();
112
113 if !parts.iter().any(|s| *s == "SUBSYSTEM=power_supply") {
114 return None;
115 }
116
117 let cap = parts.iter()
118 .find_map(|s| s.strip_prefix("POWER_SUPPLY_CAPACITY="))
119 .and_then(|v| v.parse::<u8>().ok())?;
120
121 let status = parts.iter()
122 .find_map(|s| s.strip_prefix("POWER_SUPPLY_STATUS="))
123 .unwrap_or("Unknown")
124 .to_string();
125
126 Some((cap, status))
127}