#![allow(non_camel_case_types)]
#![allow(clippy::upper_case_acronyms)]
use core::{
arch::asm,
ffi::{c_char, c_int, c_long, c_uchar, c_ushort, c_void},
mem::MaybeUninit,
};
pub type size_t = usize;
type ssize_t = isize;
type time_t = i64;
type ino_t = u64;
type off_t = i64;
type dev_t = u64;
type nlink_t = u64;
type mode_t = u32;
type uid_t = u32;
type gid_t = u32;
type blksize_t = i64;
type blkcnt_t = i64;
pub type socklen_t = u32;
pub type sa_family_t = u16;
pub type in_addr_t = u32;
pub type in_port_t = u16;
const SYS_READ: u32 = 0;
const SYS_WRITE: u32 = 1;
const SYS_OPEN: u32 = 2;
const SYS_CLOSE: u32 = 3;
const SYS_FSTAT: u32 = 5;
const SYS_MMAP: u32 = 9;
const SYS_MPROTECT: u32 = 10;
const SYS_IOCTL: u32 = 16;
const SYS_ACCESS: u32 = 21;
const SYS_SOCKET: u32 = 41;
const SYS_CONNECT: u32 = 42;
const SYS_SETSOCKOPT: i32 = 54;
const SYS_EXIT: i32 = 60;
const SYS_FCNTL: i32 = 72;
const SYS_MKDIR: u32 = 83;
const SYS_EPOLL_CREATE: i32 = 213;
const SYS_EPOLL_WAIT: i32 = 232;
const SYS_EPOLL_CTL: i32 = 233;
const SYS_GETDENTS64: u32 = 217;
pub const EAGAIN: i32 = -11; const EACCES: i32 = -13; const ENOTTY: i32 = -25;
pub const O_CLOEXEC: c_int = 0x80000;
pub const O_DIRECTORY: c_int = 0x10000;
pub const O_RDONLY: c_int = 0;
pub const O_WRONLY: c_int = 1;
pub const O_CREAT: c_int = 64;
pub const O_TRUNC: c_int = 512;
pub const O_NONBLOCK: c_int = 2048;
pub const F_OK: i32 = 0;
pub const SOCK_STREAM: c_int = 1;
pub const SOCK_DGRAM: c_int = 2;
pub const SOCK_CLOEXEC: c_int = O_CLOEXEC;
pub const AF_INET: c_int = 2;
pub const IPPROTO_TCP: i32 = 6;
pub const TCP_FASTOPEN_CONNECT: i32 = 30;
pub const EPOLLIN: u32 = 0x001;
pub const EPOLL_CTL_ADD: c_int = 1;
pub const DT_REG: u8 = 8;
pub const PROT_NONE: c_int = 0;
pub const PROT_READ: c_int = 1;
pub const PROT_WRITE: c_int = 2;
pub const MAP_PRIVATE: c_int = 0x0002;
pub const MAP_ANONYMOUS: c_int = 0x0020;
pub const MAP_STACK: c_int = 0x020000;
pub const F_SETFL: c_int = 4;
const TCGETS: usize = 0x5401;
#[repr(C)]
pub struct in_addr {
pub s_addr: in_addr_t,
}
#[repr(C)]
pub struct sockaddr_in {
pub sin_family: sa_family_t,
pub sin_port: in_port_t,
pub sin_addr: in_addr,
pub sin_zero: [u8; 8],
}
#[repr(C)]
pub struct sockaddr {
pub sa_family: sa_family_t,
pub sa_data: [c_char; 14],
}
#[repr(C)]
pub struct linux_dirent64 {
pub d_ino: ino_t,
pub d_off: off_t,
pub d_reclen: c_ushort,
pub d_type: c_uchar,
pub d_name: c_char,
}
#[repr(C)]
pub struct Stat {
pub st_dev: dev_t,
pub st_ino: ino_t,
pub st_nlink: nlink_t,
pub st_mode: mode_t,
pub st_uid: uid_t,
pub st_gid: gid_t,
__pad0: c_int,
pub st_rdev: dev_t,
pub st_size: off_t,
pub st_blksize: blksize_t,
pub st_blocks: blkcnt_t,
pub st_atime: time_t,
pub st_atime_nsec: i64,
pub st_mtime: time_t,
pub st_mtime_nsec: i64,
pub st_ctime: time_t,
pub st_ctime_nsec: i64,
__unused: [i64; 3],
}
#[derive(Copy, Clone)]
#[repr(C, packed)]
pub struct epoll_event {
pub events: u32,
pub data: u64,
}
pub fn getrandom(buf: &mut [u8]) {
debug_assert!(
buf.len().is_multiple_of(8),
"getrandom buffer len must be multiple of 8"
);
let mut r: u64;
let mut i = 0;
while i < buf.len() {
unsafe {
asm!("RDRAND rax", out("rax") r);
buf[i..i + 8].copy_from_slice(&r.to_be_bytes());
}
i += 8;
}
}
pub fn read(fd: c_int, buf: *mut c_void, count: size_t) -> i32 {
let mut ret: i32;
unsafe {
asm!("syscall",
inlateout("eax") SYS_READ as i32 => ret,
in("edi") fd,
in("rsi") buf,
in("rdx") count,
lateout("rcx") _,
lateout("r11") _,
options(nostack)
);
}
ret
}
pub fn write(fd: c_int, buf: *const c_void, count: size_t) -> i32 {
let mut ret: i32;
unsafe {
asm!("syscall",
inlateout("eax") SYS_WRITE as i32 => ret,
in("edi") fd,
in("rsi") buf,
in("rdx") count,
lateout("rcx") _,
lateout("r11") _,
options(nostack)
);
}
ret
}
pub fn mmap(
addr: *mut c_void,
len: size_t,
prot: c_int,
flags: c_int,
fd: c_int,
offset: off_t,
) -> *mut c_void {
let mut ret: isize;
unsafe {
asm!("syscall",
inlateout("rax") SYS_MMAP as isize => ret,
in("rdi") addr,
in("rsi") len,
in("edx") prot,
in("r10d") flags,
in("r8d") fd,
in("r9") offset,
lateout("rcx") _,
lateout("r11") _,
options(nostack)
);
}
if ret < 0 {
core::ptr::null_mut()
} else {
ret as *mut c_void
}
}
pub fn mprotect(addr: *mut c_void, len: size_t, prot: c_int) -> c_int {
let mut ret: c_long;
unsafe {
asm!("syscall",
inlateout("rax") SYS_MPROTECT as c_long => ret,
in("rdi") addr,
in("rsi") len,
in("edx") prot,
lateout("rcx") _,
lateout("r11") _,
options(nostack)
);
}
ret as c_int
}
pub fn access(path: *const c_char, mode: c_int) -> c_int {
let mut ret: c_long;
unsafe {
asm!("syscall",
inlateout("rax") SYS_ACCESS as c_long => ret,
in("rdi") path,
in("esi") mode,
lateout("rcx") _,
lateout("r11") _,
options(nostack)
);
}
if ret < 0 { -1 } else { ret as c_int }
}
pub fn isatty(fd: c_int) -> bool {
let mut ret: c_long;
let mut termios = MaybeUninit::<[u8; 64]>::uninit();
unsafe {
asm!("syscall",
inlateout("rax") SYS_IOCTL as c_long => ret,
in("edi") fd,
in("rsi") TCGETS,
in("rdx") termios.as_mut_ptr(),
lateout("rcx") _,
lateout("r11") _,
options(nostack)
);
}
match ret {
0 => true,
x if x == ENOTTY as c_long => false,
_ => false,
}
}
pub fn mkdir(path: *const c_char, mode: u32) -> i32 {
let mut ret: i32;
unsafe {
asm!("syscall",
inout("eax") SYS_MKDIR => ret,
in("rdi") path,
in("esi") mode,
lateout("rcx") _,
lateout("r11") _,
options(nostack),
);
}
ret
}
pub fn getdents64(fd: c_int, dirp: *mut c_void, count: size_t) -> ssize_t {
let mut ret: ssize_t;
unsafe {
asm!("syscall",
inlateout("rax") SYS_GETDENTS64 as ssize_t => ret,
in("edi") fd,
in("rsi") dirp,
in("rdx") count,
lateout("rcx") _,
lateout("r11") _,
options(nostack)
);
}
if ret < 0 { -1 } else { ret }
}
pub fn open(path: *const c_char, flags: i32, mode: i32) -> Result<i32, &'static str> {
let mut result: i32;
unsafe {
asm!("syscall",
inout("eax") SYS_OPEN => result,
in("rdi") path,
in("esi") flags,
in("edx") mode,
lateout("rcx") _,
lateout("r11") _,
options(nostack)
);
}
if result == EACCES {
Err("Permission denied")
} else if result < 0 {
Err("SYS_OPEN error")
} else {
Ok(result)
}
}
pub fn close(fd: i32) -> i32 {
let mut ret: i32;
unsafe {
asm!("syscall",
inout("eax") SYS_CLOSE => ret,
in("edi") fd,
lateout("rcx") _,
lateout("r11") _,
options(nostack, nomem),
);
}
ret
}
pub fn stat(path: *const c_char, sb: &mut MaybeUninit<Stat>) -> Result<(), &'static str> {
let fd = open(path, O_RDONLY, 0)?;
let mut ret: i32;
unsafe {
asm!("syscall",
inout("eax") SYS_FSTAT => ret,
in("edi") fd,
in("rsi") sb as *mut MaybeUninit<Stat>,
lateout("rcx") _,
lateout("r11") _,
options(nostack),
);
}
if ret != 0 {
Err("fstat failed")
} else {
let _ = close(fd);
Ok(())
}
}
pub fn socket(domain: c_int, ty: c_int, protocol: c_int) -> i32 {
let mut ret: i32;
unsafe {
asm!("syscall",
inout("eax") SYS_SOCKET => ret,
in("edi") domain,
in("esi") ty,
in("edx") protocol,
lateout("rcx") _,
lateout("r11") _,
options(nostack),
);
}
ret
}
pub fn connect(socket: c_int, address: *const sockaddr, len: socklen_t) -> c_int {
let mut ret: c_int;
unsafe {
asm!("syscall",
inout("eax") SYS_CONNECT => ret,
in("edi") socket,
in("rsi") address,
in("edx") len,
lateout("rcx") _,
lateout("r11") _,
options(nostack),
);
}
ret
}
pub fn setsockopt(
socket: c_int,
level: c_int,
name: c_int,
value: *const c_void,
option_len: socklen_t,
) -> c_int {
let mut ret: c_int;
unsafe {
asm!("syscall",
inout("eax") SYS_SETSOCKOPT => ret,
in("edi") socket,
in("esi") level,
in("edx") name,
in("r10") value,
in("r8d") option_len,
lateout("rcx") _,
lateout("r11") _,
options(nostack),
);
}
ret
}
pub fn fcntl(fd: c_int, op: c_int, flags: c_int) -> c_int {
let mut ret: c_int;
unsafe {
asm!("syscall",
inout("eax") SYS_FCNTL => ret,
in("edi") fd,
in("esi") op,
in("edx") flags,
lateout("rcx") _,
lateout("r11") _,
options(nostack),
);
}
ret
}
pub fn epoll_create(size: c_int) -> c_int {
let mut ret: c_int;
unsafe {
asm!("syscall",
inout("eax") SYS_EPOLL_CREATE => ret,
in("edi") size,
lateout("rcx") _,
lateout("r11") _,
options(nostack),
);
}
ret
}
pub fn epoll_ctl(epfd: c_int, op: c_int, fd: c_int, event: *mut epoll_event) -> c_int {
let mut ret: c_int;
unsafe {
asm!("syscall",
inout("eax") SYS_EPOLL_CTL => ret,
in("edi") epfd,
in("esi") op,
in("edx") fd,
in("r10") event,
lateout("rcx") _,
lateout("r11") _,
options(nostack),
);
}
ret
}
pub fn epoll_wait(
epfd: c_int,
events: *mut epoll_event,
maxevents: c_int,
timeout: c_int,
) -> c_int {
let mut ret: c_int;
unsafe {
asm!("syscall",
inout("eax") SYS_EPOLL_WAIT => ret,
in("edi") epfd,
in("rsi") events,
in("edx") maxevents,
in("r10d") timeout,
lateout("rcx") _,
lateout("r11") _,
options(nostack),
);
}
ret
}
pub fn exit(exit_code: i32) -> ! {
unsafe {
asm!("syscall",
in("eax") SYS_EXIT,
in("edi") exit_code,
options(nostack, nomem, noreturn)
)
}
}