#[cfg(feature = "alloc")]
use alloc::vec::Vec;
use core::ptr;
#[cfg(target_env = "musl")]
pub type IoctlReq = libc::c_int;
#[cfg(not(target_env = "musl"))]
pub type IoctlReq = libc::c_ulong;
pub const PATH_MAX: usize = 4096;
#[inline]
pub fn path_to_cstr(path: &[u8], buf: &mut [u8; PATH_MAX]) -> bool {
if path.len() >= PATH_MAX {
return false;
}
buf[..path.len()].copy_from_slice(path);
buf[path.len()] = 0;
true
}
pub fn write_all(fd: i32, buf: &[u8]) -> isize {
let mut written = 0;
while written < buf.len() {
let ret = unsafe {
libc::write(
fd,
buf[written..].as_ptr() as *const libc::c_void,
buf.len() - written,
)
};
if ret < 0 {
return ret;
}
written += ret as usize;
}
written as isize
}
pub fn write_all_fd(fd: i32, buf: &[u8]) -> isize {
write_all(fd, buf)
}
pub fn write_all_count(fd: i32, buf: &[u8]) -> usize {
let mut written = 0;
while written < buf.len() {
let ret = unsafe {
libc::write(
fd,
buf[written..].as_ptr() as *const libc::c_void,
buf.len() - written,
)
};
if ret < 0 {
break;
}
written += ret as usize;
}
written
}
pub fn write_str(fd: i32, s: &[u8]) -> isize {
write_all(fd, s)
}
pub fn write_num(fd: i32, mut n: u64) -> isize {
if n == 0 {
return write_str(fd, b"0");
}
let mut buf = [0u8; 20];
let mut i = buf.len();
while n > 0 {
i -= 1;
buf[i] = b'0' + (n % 10) as u8;
n /= 10;
}
write_all(fd, &buf[i..])
}
pub fn write_signed(fd: i32, n: i64) -> isize {
if n < 0 {
write_str(fd, b"-");
write_num(fd, (-n) as u64)
} else {
write_num(fd, n as u64)
}
}
pub fn read(fd: i32, buf: &mut [u8]) -> isize {
unsafe {
libc::read(fd, buf.as_mut_ptr() as *mut libc::c_void, buf.len())
}
}
#[cfg(feature = "alloc")]
pub fn read_all(fd: i32) -> Vec<u8> {
let mut result = Vec::new();
let mut buf = [0u8; 4096];
loop {
let n = read(fd, &mut buf);
if n <= 0 {
break;
}
result.extend_from_slice(&buf[..n as usize]);
}
result
}
pub fn open(path: &[u8], flags: i32, mode: u32) -> i32 {
let mut path_buf = [0u8; 4096];
if path.len() >= path_buf.len() {
return -1;
}
path_buf[..path.len()].copy_from_slice(path);
path_buf[path.len()] = 0;
unsafe { libc::open(path_buf.as_ptr() as *const i8, flags, mode) }
}
pub fn close(fd: i32) -> i32 {
unsafe { libc::close(fd) }
}
#[inline]
pub fn stat_zeroed() -> libc::stat {
unsafe { core::mem::zeroed() }
}
pub fn stat(path: &[u8], buf: &mut libc::stat) -> i32 {
let mut path_buf = [0u8; 4096];
if path.len() >= path_buf.len() {
return -1;
}
path_buf[..path.len()].copy_from_slice(path);
path_buf[path.len()] = 0;
unsafe { libc::stat(path_buf.as_ptr() as *const i8, buf) }
}
pub fn lstat(path: &[u8], buf: &mut libc::stat) -> i32 {
let mut path_buf = [0u8; 4096];
if path.len() >= path_buf.len() {
return -1;
}
path_buf[..path.len()].copy_from_slice(path);
path_buf[path.len()] = 0;
unsafe { libc::lstat(path_buf.as_ptr() as *const i8, buf) }
}
pub fn fstat(fd: i32, buf: &mut libc::stat) -> i32 {
unsafe { libc::fstat(fd, buf) }
}
pub fn mkdir(path: &[u8], mode: u32) -> i32 {
let mut path_buf = [0u8; 4096];
if path.len() >= path_buf.len() {
return -1;
}
path_buf[..path.len()].copy_from_slice(path);
path_buf[path.len()] = 0;
unsafe { libc::mkdir(path_buf.as_ptr() as *const i8, mode as libc::mode_t) }
}
pub fn rmdir(path: &[u8]) -> i32 {
let mut path_buf = [0u8; 4096];
if path.len() >= path_buf.len() {
return -1;
}
path_buf[..path.len()].copy_from_slice(path);
path_buf[path.len()] = 0;
unsafe { libc::rmdir(path_buf.as_ptr() as *const i8) }
}
pub fn unlink(path: &[u8]) -> i32 {
let mut path_buf = [0u8; 4096];
if path.len() >= path_buf.len() {
return -1;
}
path_buf[..path.len()].copy_from_slice(path);
path_buf[path.len()] = 0;
unsafe { libc::unlink(path_buf.as_ptr() as *const i8) }
}
pub fn rename(old: &[u8], new: &[u8]) -> i32 {
let mut old_buf = [0u8; 4096];
let mut new_buf = [0u8; 4096];
if old.len() >= old_buf.len() || new.len() >= new_buf.len() {
return -1;
}
old_buf[..old.len()].copy_from_slice(old);
old_buf[old.len()] = 0;
new_buf[..new.len()].copy_from_slice(new);
new_buf[new.len()] = 0;
unsafe { libc::rename(old_buf.as_ptr() as *const i8, new_buf.as_ptr() as *const i8) }
}
pub fn symlink(target: &[u8], linkpath: &[u8]) -> i32 {
let mut target_buf = [0u8; 4096];
let mut link_buf = [0u8; 4096];
if target.len() >= target_buf.len() || linkpath.len() >= link_buf.len() {
return -1;
}
target_buf[..target.len()].copy_from_slice(target);
target_buf[target.len()] = 0;
link_buf[..linkpath.len()].copy_from_slice(linkpath);
link_buf[linkpath.len()] = 0;
unsafe { libc::symlink(target_buf.as_ptr() as *const i8, link_buf.as_ptr() as *const i8) }
}
pub fn link(old: &[u8], new: &[u8]) -> i32 {
let mut old_buf = [0u8; 4096];
let mut new_buf = [0u8; 4096];
if old.len() >= old_buf.len() || new.len() >= new_buf.len() {
return -1;
}
old_buf[..old.len()].copy_from_slice(old);
old_buf[old.len()] = 0;
new_buf[..new.len()].copy_from_slice(new);
new_buf[new.len()] = 0;
unsafe { libc::link(old_buf.as_ptr() as *const i8, new_buf.as_ptr() as *const i8) }
}
pub fn chmod(path: &[u8], mode: u32) -> i32 {
let mut path_buf = [0u8; 4096];
if path.len() >= path_buf.len() {
return -1;
}
path_buf[..path.len()].copy_from_slice(path);
path_buf[path.len()] = 0;
unsafe { libc::chmod(path_buf.as_ptr() as *const i8, mode as libc::mode_t) }
}
pub fn chdir(path: &[u8]) -> i32 {
let mut path_buf = [0u8; 4096];
if path.len() >= path_buf.len() {
return -1;
}
path_buf[..path.len()].copy_from_slice(path);
path_buf[path.len()] = 0;
unsafe { libc::chdir(path_buf.as_ptr() as *const i8) }
}
#[cfg(feature = "alloc")]
pub fn getcwd() -> Option<Vec<u8>> {
let mut buf = [0u8; 4096];
let ret = unsafe { libc::getcwd(buf.as_mut_ptr() as *mut i8, buf.len()) };
if ret.is_null() {
None
} else {
let len = buf.iter().position(|&c| c == 0).unwrap_or(buf.len());
Some(buf[..len].to_vec())
}
}
#[cfg(not(feature = "alloc"))]
pub fn getcwd(buf: &mut [u8]) -> bool {
let ret = unsafe { libc::getcwd(buf.as_mut_ptr() as *mut i8, buf.len()) };
!ret.is_null()
}
pub fn readlink(path: &[u8], buf: &mut [u8]) -> isize {
let mut path_buf = [0u8; 4096];
if path.len() >= path_buf.len() { return -1; }
path_buf[..path.len()].copy_from_slice(path);
path_buf[path.len()] = 0;
unsafe { libc::readlink(path_buf.as_ptr() as *const i8, buf.as_mut_ptr() as *mut i8, buf.len()) }
}
pub fn realpath(path: &[u8], buf: &mut [u8]) -> isize {
let mut path_buf = [0u8; 4096];
if path.len() >= path_buf.len() { return -1; }
path_buf[..path.len()].copy_from_slice(path);
path_buf[path.len()] = 0;
let ret = unsafe { libc::realpath(path_buf.as_ptr() as *const i8, buf.as_mut_ptr() as *mut i8) };
if ret.is_null() {
-1
} else {
strlen_arr(buf) as isize
}
}
pub fn opendir(path: &[u8]) -> *mut libc::DIR {
let mut path_buf = [0u8; 4096];
if path.len() >= path_buf.len() {
return ptr::null_mut();
}
path_buf[..path.len()].copy_from_slice(path);
path_buf[path.len()] = 0;
unsafe { libc::opendir(path_buf.as_ptr() as *const i8) }
}
#[allow(clippy::not_unsafe_ptr_arg_deref)]
pub fn readdir(dir: *mut libc::DIR) -> *mut libc::dirent {
unsafe { libc::readdir(dir) }
}
#[allow(clippy::not_unsafe_ptr_arg_deref)]
pub fn closedir(dir: *mut libc::DIR) -> i32 {
unsafe { libc::closedir(dir) }
}
pub fn getuid() -> u32 {
unsafe { libc::getuid() }
}
pub fn geteuid() -> u32 {
unsafe { libc::geteuid() }
}
pub fn getgid() -> u32 {
unsafe { libc::getgid() }
}
pub fn getegid() -> u32 {
unsafe { libc::getegid() }
}
pub fn access(path: &[u8], mode: i32) -> i32 {
let mut path_buf = [0u8; 4096];
if path.len() >= path_buf.len() {
return -1;
}
path_buf[..path.len()].copy_from_slice(path);
path_buf[path.len()] = 0;
unsafe { libc::access(path_buf.as_ptr() as *const i8, mode) }
}
pub fn getpid() -> i32 {
unsafe { libc::getpid() }
}
pub fn getppid() -> i32 {
unsafe { libc::getppid() }
}
#[cfg(feature = "alloc")]
pub fn gethostname() -> Option<Vec<u8>> {
let mut buf = [0u8; 256];
let ret = unsafe { libc::gethostname(buf.as_mut_ptr() as *mut i8, buf.len()) };
if ret != 0 {
None
} else {
let len = buf.iter().position(|&c| c == 0).unwrap_or(buf.len());
Some(buf[..len].to_vec())
}
}
pub fn sleep(secs: u32) {
unsafe { libc::sleep(secs); }
}
pub fn usleep(usecs: u32) {
unsafe { libc::usleep(usecs); }
}
pub fn dup(fd: i32) -> i32 {
unsafe { libc::dup(fd) }
}
pub fn dup2(old: i32, new: i32) -> i32 {
unsafe { libc::dup2(old, new) }
}
pub fn lseek(fd: i32, offset: i64, whence: i32) -> i64 {
unsafe { libc::lseek(fd, offset as libc::off_t, whence) as i64 }
}
pub fn ftruncate(fd: i32, length: i64) -> i32 {
unsafe { libc::ftruncate(fd, length as libc::off_t) }
}
pub fn sync() {
unsafe { libc::sync(); }
}
pub fn isatty(fd: i32) -> bool {
unsafe { libc::isatty(fd) != 0 }
}
#[cfg(feature = "alloc")]
pub fn ttyname(fd: i32) -> Option<Vec<u8>> {
let ptr = unsafe { libc::ttyname(fd) };
if ptr.is_null() {
None
} else {
let mut len = 0;
while unsafe { *ptr.add(len) } != 0 {
len += 1;
}
let slice = unsafe { core::slice::from_raw_parts(ptr as *const u8, len) };
Some(slice.to_vec())
}
}
pub fn getenv(name: &[u8]) -> Option<&'static [u8]> {
let mut name_buf = [0u8; 256];
if name.len() >= name_buf.len() {
return None;
}
name_buf[..name.len()].copy_from_slice(name);
name_buf[name.len()] = 0;
let ptr = unsafe { libc::getenv(name_buf.as_ptr() as *const i8) };
if ptr.is_null() {
None
} else {
let len = strlen(ptr as *const u8);
Some(unsafe { core::slice::from_raw_parts(ptr as *const u8, len) })
}
}
pub fn setenv(name: &[u8], value: &[u8], overwrite: bool) -> i32 {
if name.is_empty() || name.contains(&b'=') {
return -1;
}
let mut name_buf = [0u8; 256];
let mut value_buf = [0u8; 4096];
if name.len() >= name_buf.len() || value.len() >= value_buf.len() {
return -1;
}
name_buf[..name.len()].copy_from_slice(name);
name_buf[name.len()] = 0;
value_buf[..value.len()].copy_from_slice(value);
value_buf[value.len()] = 0;
unsafe {
libc::setenv(
name_buf.as_ptr() as *const i8,
value_buf.as_ptr() as *const i8,
if overwrite { 1 } else { 0 },
)
}
}
pub fn unsetenv(name: &[u8]) -> i32 {
if name.is_empty() || name.contains(&b'=') {
return -1;
}
let mut name_buf = [0u8; 256];
if name.len() >= name_buf.len() {
return -1;
}
name_buf[..name.len()].copy_from_slice(name);
name_buf[name.len()] = 0;
unsafe { libc::unsetenv(name_buf.as_ptr() as *const i8) }
}
pub fn kill(pid: i32, sig: i32) -> i32 {
unsafe { libc::kill(pid, sig) }
}
#[allow(clippy::not_unsafe_ptr_arg_deref)]
pub fn execve(path: &[u8], argv: *const *const i8, envp: *const *const i8) -> i32 {
let mut path_buf = [0u8; 4096];
if path.len() >= path_buf.len() {
return -1;
}
path_buf[..path.len()].copy_from_slice(path);
path_buf[path.len()] = 0;
unsafe { libc::execve(path_buf.as_ptr() as *const i8, argv, envp) }
}
pub fn fork() -> i32 {
unsafe { libc::fork() }
}
#[allow(clippy::not_unsafe_ptr_arg_deref)]
pub fn wait(status: *mut i32) -> i32 {
unsafe { libc::wait(status) }
}
#[allow(clippy::not_unsafe_ptr_arg_deref)]
pub fn waitpid(pid: i32, status: *mut i32, options: i32) -> i32 {
unsafe { libc::waitpid(pid, status, options) }
}
pub fn uname(buf: &mut libc::utsname) -> i32 {
unsafe { libc::uname(buf) }
}
pub fn exit(code: i32) -> ! {
unsafe { libc::_exit(code); }
}
#[allow(clippy::not_unsafe_ptr_arg_deref)]
pub fn strlen(s: *const u8) -> usize {
const MAX_STRLEN: usize = 1024 * 1024; let mut len = 0;
while len < MAX_STRLEN {
if unsafe { *s.add(len) } == 0 {
break;
}
len += 1;
}
len
}
pub fn strlen_arr(s: &[u8]) -> usize {
s.iter().position(|&c| c == 0).unwrap_or(s.len())
}
pub unsafe fn cstr_to_slice(s: *const u8) -> &'static [u8] {
debug_assert!(!s.is_null(), "cstr_to_slice called with null pointer");
let len = strlen(s);
unsafe { core::slice::from_raw_parts(s, len) }
}
pub fn bytes_eq(a: &[u8], b: &[u8]) -> bool {
a.len() == b.len() && a.iter().zip(b).all(|(x, y)| x == y)
}
pub fn starts_with(s: &[u8], prefix: &[u8]) -> bool {
s.len() >= prefix.len() && &s[..prefix.len()] == prefix
}
pub unsafe fn dirent_name(entry: *const libc::dirent) -> (&'static [u8], usize) {
debug_assert!(!entry.is_null(), "dirent_name called with null pointer");
unsafe {
let name_ptr = (*entry).d_name.as_ptr();
let mut len = 0;
while len < 255 && *name_ptr.add(len) != 0 {
len += 1;
}
let slice = core::slice::from_raw_parts(name_ptr as *const u8, len);
(slice, len)
}
}