1#![allow(non_camel_case_types)]
9#![allow(clippy::upper_case_acronyms)]
10
11use core::{
12 arch::asm,
13 ffi::{c_char, c_int, c_long, c_uchar, c_ushort, c_void},
14 mem::MaybeUninit,
15};
16
17pub type size_t = usize;
18type ssize_t = isize;
19type time_t = i64;
20type ino_t = u64;
21type off_t = i64;
22type dev_t = u64;
23type nlink_t = u64;
24type mode_t = u32;
25type uid_t = u32;
26type gid_t = u32;
27type blksize_t = i64;
28type blkcnt_t = i64;
29
30pub type socklen_t = u32;
31pub type sa_family_t = u16;
32pub type in_addr_t = u32;
33pub type in_port_t = u16;
34
35const SYS_READ: u32 = 0;
37const SYS_WRITE: u32 = 1;
38const SYS_OPEN: u32 = 2;
39const SYS_CLOSE: u32 = 3;
40const SYS_FSTAT: u32 = 5;
41const SYS_MMAP: u32 = 9;
42const SYS_MPROTECT: u32 = 10;
43const SYS_IOCTL: u32 = 16;
44const SYS_ACCESS: u32 = 21;
45const SYS_SOCKET: u32 = 41;
46const SYS_CONNECT: u32 = 42;
47const SYS_SETSOCKOPT: i32 = 54;
48const SYS_EXIT: i32 = 60;
49const SYS_FCNTL: i32 = 72;
50const SYS_MKDIR: u32 = 83;
51const SYS_EPOLL_CREATE: i32 = 213;
52const SYS_EPOLL_WAIT: i32 = 232;
53const SYS_EPOLL_CTL: i32 = 233;
54const SYS_GETDENTS64: u32 = 217;
55
56pub const EAGAIN: i32 = -11; const EACCES: i32 = -13; const ENOTTY: i32 = -25; pub const O_CLOEXEC: c_int = 0x80000;
62pub const O_DIRECTORY: c_int = 0x10000;
63
64pub const O_RDONLY: c_int = 0;
65pub const O_WRONLY: c_int = 1;
66pub const O_CREAT: c_int = 64;
68pub const O_TRUNC: c_int = 512;
69pub const O_NONBLOCK: c_int = 2048;
70
71pub const F_OK: i32 = 0;
72
73pub const SOCK_STREAM: c_int = 1;
74pub const SOCK_DGRAM: c_int = 2;
75pub const SOCK_CLOEXEC: c_int = O_CLOEXEC;
76pub const AF_INET: c_int = 2;
77pub const IPPROTO_TCP: i32 = 6;
78pub const TCP_FASTOPEN_CONNECT: i32 = 30;
79pub const EPOLLIN: u32 = 0x001;
80pub const EPOLL_CTL_ADD: c_int = 1;
81
82pub const DT_REG: u8 = 8;
83
84pub const PROT_NONE: c_int = 0;
85pub const PROT_READ: c_int = 1;
86pub const PROT_WRITE: c_int = 2;
87
88pub const MAP_PRIVATE: c_int = 0x0002;
89pub const MAP_ANONYMOUS: c_int = 0x0020;
90pub const MAP_STACK: c_int = 0x020000;
91
92pub const F_SETFL: c_int = 4;
93const TCGETS: usize = 0x5401;
94
95#[repr(C)]
96pub struct in_addr {
97 pub s_addr: in_addr_t,
98}
99
100#[repr(C)]
101pub struct sockaddr_in {
102 pub sin_family: sa_family_t,
103 pub sin_port: in_port_t,
104 pub sin_addr: in_addr,
105 pub sin_zero: [u8; 8],
106}
107
108#[repr(C)]
109pub struct sockaddr {
110 pub sa_family: sa_family_t,
111 pub sa_data: [c_char; 14],
112}
113
114#[repr(C)]
116pub struct linux_dirent64 {
117 pub d_ino: ino_t,
118 pub d_off: off_t,
119 pub d_reclen: c_ushort,
120 pub d_type: c_uchar,
121 pub d_name: c_char,
122}
123
124#[repr(C)]
127pub struct Stat {
128 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,
140 pub st_atime_nsec: i64,
141 pub st_mtime: time_t,
142 pub st_mtime_nsec: i64,
143 pub st_ctime: time_t,
144 pub st_ctime_nsec: i64,
145 __unused: [i64; 3],
146}
147
148#[derive(Copy, Clone)]
149#[repr(C, packed)]
150pub struct epoll_event {
151 pub events: u32,
152 pub data: u64,
153}
154
155pub fn getrandom(buf: &mut [u8]) {
158 debug_assert!(
159 buf.len().is_multiple_of(8),
160 "getrandom buffer len must be multiple of 8"
161 );
162 let mut r: u64;
163 let mut i = 0;
164 while i < buf.len() {
165 unsafe {
166 asm!("RDRAND rax", out("rax") r);
167 buf[i..i + 8].copy_from_slice(&r.to_be_bytes());
168 }
169 i += 8;
170 }
171}
172
173pub fn read(fd: c_int, buf: *mut c_void, count: size_t) -> i32 {
177 let mut ret: i32;
178 unsafe {
179 asm!("syscall",
180 inlateout("eax") SYS_READ as i32 => ret,
181 in("edi") fd,
182 in("rsi") buf,
183 in("rdx") count,
184 lateout("rcx") _,
185 lateout("r11") _,
186 options(nostack)
187 );
188 }
189 ret
190}
191
192pub fn write(fd: c_int, buf: *const c_void, count: size_t) -> i32 {
193 let mut ret: i32;
194 unsafe {
195 asm!("syscall",
196 inlateout("eax") SYS_WRITE as i32 => ret,
197 in("edi") fd,
198 in("rsi") buf,
199 in("rdx") count,
200 lateout("rcx") _,
201 lateout("r11") _,
202 options(nostack)
203 );
204 }
205 ret
206}
207
208pub fn mmap(
209 addr: *mut c_void,
210 len: size_t,
211 prot: c_int,
212 flags: c_int,
213 fd: c_int,
214 offset: off_t,
215) -> *mut c_void {
216 let mut ret: isize;
217 unsafe {
218 asm!("syscall",
219 inlateout("rax") SYS_MMAP as isize => ret,
220 in("rdi") addr,
221 in("rsi") len,
222 in("edx") prot,
223 in("r10d") flags,
224 in("r8d") fd,
225 in("r9") offset,
226 lateout("rcx") _,
227 lateout("r11") _,
228 options(nostack)
229 );
230 }
231 if ret < 0 {
232 core::ptr::null_mut()
233 } else {
234 ret as *mut c_void
235 }
236}
237
238pub fn mprotect(addr: *mut c_void, len: size_t, prot: c_int) -> c_int {
239 let mut ret: c_long;
240 unsafe {
241 asm!("syscall",
242 inlateout("rax") SYS_MPROTECT as c_long => ret,
243 in("rdi") addr,
244 in("rsi") len,
245 in("edx") prot,
246 lateout("rcx") _,
247 lateout("r11") _,
248 options(nostack)
249 );
250 }
251 ret as c_int
252}
253
254pub fn access(path: *const c_char, mode: c_int) -> c_int {
255 let mut ret: c_long;
256 unsafe {
257 asm!("syscall",
258 inlateout("rax") SYS_ACCESS as c_long => ret,
259 in("rdi") path,
260 in("esi") mode,
261 lateout("rcx") _,
262 lateout("r11") _,
263 options(nostack)
264 );
265 }
266 if ret < 0 { -1 } else { ret as c_int }
267}
268
269pub fn isatty(fd: c_int) -> bool {
270 let mut ret: c_long;
271 let mut termios = MaybeUninit::<[u8; 64]>::uninit();
272 unsafe {
273 asm!("syscall",
274 inlateout("rax") SYS_IOCTL as c_long => ret,
275 in("edi") fd,
276 in("rsi") TCGETS,
277 in("rdx") termios.as_mut_ptr(),
278 lateout("rcx") _,
279 lateout("r11") _,
280 options(nostack)
281 );
282 }
283 match ret {
284 0 => true,
285 x if x == ENOTTY as c_long => false,
286 _ => false,
287 }
288}
289
290pub fn mkdir(path: *const c_char, mode: u32) -> i32 {
291 let mut ret: i32;
292 unsafe {
293 asm!("syscall",
294 inout("eax") SYS_MKDIR => ret,
295 in("rdi") path,
296 in("esi") mode,
297 lateout("rcx") _,
298 lateout("r11") _,
299 options(nostack),
300 );
301 }
302 ret
303}
304
305pub fn getdents64(fd: c_int, dirp: *mut c_void, count: size_t) -> ssize_t {
306 let mut ret: ssize_t;
307 unsafe {
308 asm!("syscall",
309 inlateout("rax") SYS_GETDENTS64 as ssize_t => ret,
310 in("edi") fd,
311 in("rsi") dirp,
312 in("rdx") count,
313 lateout("rcx") _,
314 lateout("r11") _,
315 options(nostack)
316 );
317 }
318 if ret < 0 { -1 } else { ret }
319}
320
321pub fn open(path: *const c_char, flags: i32, mode: i32) -> Result<i32, &'static str> {
322 let mut result: i32;
323 unsafe {
324 asm!("syscall",
325 inout("eax") SYS_OPEN => result,
326 in("rdi") path,
327 in("esi") flags,
328 in("edx") mode,
329 lateout("rcx") _,
330 lateout("r11") _,
331 options(nostack)
332 );
333 }
334 if result == EACCES {
335 Err("Permission denied")
336 } else if result < 0 {
337 Err("SYS_OPEN error")
338 } else {
339 Ok(result)
340 }
341}
342
343pub fn close(fd: i32) -> i32 {
344 let mut ret: i32;
345 unsafe {
346 asm!("syscall",
347 inout("eax") SYS_CLOSE => ret,
348 in("edi") fd,
349 lateout("rcx") _,
350 lateout("r11") _,
351 options(nostack, nomem),
352 );
353 }
354 ret
355}
356
357pub fn stat(path: *const c_char, sb: &mut MaybeUninit<Stat>) -> Result<(), &'static str> {
359 let fd = open(path, O_RDONLY, 0)?;
360 let mut ret: i32;
361 unsafe {
362 asm!("syscall",
363 inout("eax") SYS_FSTAT => ret,
364 in("edi") fd,
365 in("rsi") sb as *mut MaybeUninit<Stat>,
366 lateout("rcx") _,
367 lateout("r11") _,
368 options(nostack),
369 );
370 }
371 if ret != 0 {
372 Err("fstat failed")
373 } else {
374 let _ = close(fd);
375 Ok(())
376 }
377}
378
379pub fn socket(domain: c_int, ty: c_int, protocol: c_int) -> i32 {
380 let mut ret: i32;
381 unsafe {
382 asm!("syscall",
383 inout("eax") SYS_SOCKET => ret,
384 in("edi") domain,
385 in("esi") ty,
386 in("edx") protocol,
387 lateout("rcx") _,
388 lateout("r11") _,
389 options(nostack),
390 );
391 }
392 ret
393}
394
395pub fn connect(socket: c_int, address: *const sockaddr, len: socklen_t) -> c_int {
396 let mut ret: c_int;
397 unsafe {
398 asm!("syscall",
399 inout("eax") SYS_CONNECT => ret,
400 in("edi") socket,
401 in("rsi") address,
402 in("edx") len,
403 lateout("rcx") _,
404 lateout("r11") _,
405 options(nostack),
406 );
407 }
408 ret
409}
410
411pub fn setsockopt(
412 socket: c_int,
413 level: c_int,
414 name: c_int,
415 value: *const c_void,
416 option_len: socklen_t,
417) -> c_int {
418 let mut ret: c_int;
419 unsafe {
420 asm!("syscall",
421 inout("eax") SYS_SETSOCKOPT => ret,
422 in("edi") socket,
423 in("esi") level,
424 in("edx") name,
425 in("r10") value,
426 in("r8d") option_len,
427 lateout("rcx") _,
428 lateout("r11") _,
429 options(nostack),
430 );
431 }
432 ret
433}
434
435pub fn fcntl(fd: c_int, op: c_int, flags: c_int) -> c_int {
436 let mut ret: c_int;
437 unsafe {
438 asm!("syscall",
439 inout("eax") SYS_FCNTL => ret,
440 in("edi") fd,
441 in("esi") op,
442 in("edx") flags,
443 lateout("rcx") _,
444 lateout("r11") _,
445 options(nostack),
446 );
447 }
448 ret
449}
450
451pub fn epoll_create(size: c_int) -> c_int {
452 let mut ret: c_int;
453 unsafe {
454 asm!("syscall",
455 inout("eax") SYS_EPOLL_CREATE => ret,
456 in("edi") size,
457 lateout("rcx") _,
458 lateout("r11") _,
459 options(nostack),
460 );
461 }
462 ret
463}
464
465pub fn epoll_ctl(epfd: c_int, op: c_int, fd: c_int, event: *mut epoll_event) -> c_int {
466 let mut ret: c_int;
467 unsafe {
468 asm!("syscall",
469 inout("eax") SYS_EPOLL_CTL => ret,
470 in("edi") epfd,
471 in("esi") op,
472 in("edx") fd,
473 in("r10") event,
474 lateout("rcx") _,
475 lateout("r11") _,
476 options(nostack),
477 );
478 }
479 ret
480}
481
482pub fn epoll_wait(
483 epfd: c_int,
484 events: *mut epoll_event,
485 maxevents: c_int,
486 timeout: c_int,
487) -> c_int {
488 let mut ret: c_int;
489 unsafe {
490 asm!("syscall",
491 inout("eax") SYS_EPOLL_WAIT => ret,
492 in("edi") epfd,
493 in("rsi") events,
494 in("edx") maxevents,
495 in("r10d") timeout,
496 lateout("rcx") _,
497 lateout("r11") _,
498 options(nostack),
499 );
500 }
501 ret
502}
503
504pub fn exit(exit_code: i32) -> ! {
505 unsafe {
506 asm!("syscall",
507 in("eax") SYS_EXIT,
508 in("edi") exit_code,
509 options(nostack, nomem, noreturn)
510 )
511 }
512}
513
514