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<(Option<u8>, String)> {
92 let mut result: Option<(Option<u8>, String)> = None;
93 let mut buf = [0u8; 4096];
94 loop {
95 match imp::uevent_recv_raw(fd, &mut buf) {
96 None => break,
97 Some(n) => {
98 if let Some(batt) = parse_battery(&buf[..n]) {
99 result = Some(batt);
100 }
101 }
102 }
103 }
104 result
105}
106
107pub fn uevent_recv(fd: &Fd, buf: &mut [u8]) -> Option<usize> {
110 imp::uevent_recv_raw(fd, buf)
111}
112
113fn parse_battery(msg: &[u8]) -> Option<(Option<u8>, String)> {
114 let parts: Vec<&str> = msg
115 .split(|&b| b == 0)
116 .filter_map(|s| std::str::from_utf8(s).ok())
117 .filter(|s| !s.is_empty())
118 .collect();
119
120 if !parts.iter().any(|s| *s == "SUBSYSTEM=power_supply") {
121 return None;
122 }
123
124 let cap = parts.iter()
125 .find_map(|s| s.strip_prefix("POWER_SUPPLY_CAPACITY="))
126 .and_then(|v| v.parse::<u8>().ok());
127
128 let status = parts.iter()
129 .find_map(|s| s.strip_prefix("POWER_SUPPLY_STATUS="))
130 .unwrap_or("Unknown")
131 .to_string();
132
133 Some((cap, status))
134}