xref: /relibc/src/platform/redox/mod.rs (revision 65bd3ed1e301a3691b81ada5c5b06dd6d68483c1)
1 use core::{mem, ptr, result::Result as CoreResult, slice, str};
2 use syscall::{
3     self,
4     data::{Map, Stat as redox_stat, StatVfs as redox_statvfs, TimeSpec as redox_timespec},
5     PtraceEvent, Result,
6 };
7 
8 use crate::{
9     c_str::{CStr, CString},
10     fs::File,
11     header::{
12         dirent::dirent,
13         errno::{EINVAL, EIO, ENOMEM, EPERM, ERANGE},
14         fcntl,
15         sys_mman::{MAP_ANONYMOUS, PROT_READ, PROT_WRITE},
16         sys_random,
17         sys_resource::{rlimit, RLIM_INFINITY},
18         sys_stat::stat,
19         sys_statvfs::statvfs,
20         sys_time::{timeval, timezone},
21         sys_utsname::{utsname, UTSLENGTH},
22         sys_wait,
23         time::timespec,
24         unistd::{F_OK, R_OK, W_OK, X_OK},
25     },
26     io::{self, prelude::*, BufReader, SeekFrom},
27 };
28 
29 use super::{errno, types::*, Pal, Read};
30 
31 static mut BRK_CUR: *mut c_void = ptr::null_mut();
32 static mut BRK_END: *mut c_void = ptr::null_mut();
33 
34 mod epoll;
35 mod extra;
36 mod ptrace;
37 mod signal;
38 mod socket;
39 
40 macro_rules! path_from_c_str {
41     ($c_str:expr) => {{
42         match $c_str.to_str() {
43             Ok(ok) => ok,
44             Err(err) => {
45                 unsafe {
46                     errno = EINVAL;
47                 }
48                 return -1;
49             }
50         }
51     }};
52 }
53 
54 pub fn e(sys: Result<usize>) -> usize {
55     match sys {
56         Ok(ok) => ok,
57         Err(err) => {
58             unsafe {
59                 errno = err.errno as c_int;
60             }
61             !0
62         }
63     }
64 }
65 
66 pub struct Sys;
67 
68 impl Pal for Sys {
69     fn access(path: &CStr, mode: c_int) -> c_int {
70         let fd = match File::open(path, fcntl::O_PATH | fcntl::O_CLOEXEC) {
71             Ok(fd) => fd,
72             Err(_) => return -1,
73         };
74 
75         if mode == F_OK {
76             return 0;
77         }
78 
79         let mut stat = syscall::Stat::default();
80 
81         if e(syscall::fstat(*fd as usize, &mut stat)) == !0 {
82             return -1;
83         }
84 
85         let uid = e(syscall::getuid());
86         if uid == !0 {
87             return -1;
88         }
89         let gid = e(syscall::getgid());
90         if gid == !0 {
91             return -1;
92         }
93 
94         let perms = if stat.st_uid as usize == uid {
95             stat.st_mode >> (3 * 2 & 0o7)
96         } else if stat.st_gid as usize == gid {
97             stat.st_mode >> (3 * 1 & 0o7)
98         } else {
99             stat.st_mode & 0o7
100         };
101         if (mode & R_OK == R_OK && perms & 0o4 != 0o4)
102             || (mode & W_OK == W_OK && perms & 0o2 != 0o2)
103             || (mode & X_OK == X_OK && perms & 0o1 != 0o1)
104         {
105             unsafe {
106                 errno = EINVAL;
107             }
108             return -1;
109         }
110 
111         0
112     }
113 
114     fn brk(addr: *mut c_void) -> *mut c_void {
115         unsafe {
116             // On first invocation, allocate a buffer for brk
117             if BRK_CUR.is_null() {
118                 // 4 megabytes of RAM ought to be enough for anybody
119                 const BRK_MAX_SIZE: usize = 4 * 1024 * 1024;
120 
121                 let allocated = Self::mmap(
122                     ptr::null_mut(),
123                     BRK_MAX_SIZE,
124                     PROT_READ | PROT_WRITE,
125                     MAP_ANONYMOUS,
126                     0,
127                     0,
128                 );
129                 if allocated == !0 as *mut c_void
130                 /* MAP_FAILED */
131                 {
132                     return !0 as *mut c_void;
133                 }
134 
135                 BRK_CUR = allocated;
136                 BRK_END = (allocated as *mut u8).add(BRK_MAX_SIZE) as *mut c_void;
137             }
138 
139             if addr.is_null() {
140                 // Lookup what previous brk() invocations have set the address to
141                 BRK_CUR
142             } else if BRK_CUR <= addr && addr < BRK_END {
143                 // It's inside buffer, return
144                 BRK_CUR = addr;
145                 addr
146             } else {
147                 // It was outside of valid range
148                 errno = ENOMEM;
149                 ptr::null_mut()
150             }
151         }
152     }
153 
154     fn chdir(path: &CStr) -> c_int {
155         let path = path_from_c_str!(path);
156         e(syscall::chdir(path)) as c_int
157     }
158 
159     fn chmod(path: &CStr, mode: mode_t) -> c_int {
160         match File::open(path, fcntl::O_PATH | fcntl::O_CLOEXEC) {
161             Ok(file) => Self::fchmod(*file, mode),
162             Err(_) => -1,
163         }
164     }
165 
166     fn chown(path: &CStr, owner: uid_t, group: gid_t) -> c_int {
167         match File::open(path, fcntl::O_PATH | fcntl::O_CLOEXEC) {
168             Ok(file) => Self::fchown(*file, owner, group),
169             Err(_) => -1,
170         }
171     }
172 
173     fn clock_gettime(clk_id: clockid_t, tp: *mut timespec) -> c_int {
174         let mut redox_tp = unsafe { redox_timespec::from(&*tp) };
175         match e(syscall::clock_gettime(clk_id as usize, &mut redox_tp)) as c_int {
176             -1 => -1,
177             _ => {
178                 unsafe {
179                     (*tp).tv_sec = redox_tp.tv_sec;
180                     (*tp).tv_nsec = redox_tp.tv_nsec as i64;
181                 };
182                 0
183             }
184         }
185     }
186 
187     fn close(fd: c_int) -> c_int {
188         e(syscall::close(fd as usize)) as c_int
189     }
190 
191     fn dup(fd: c_int) -> c_int {
192         e(syscall::dup(fd as usize, &[])) as c_int
193     }
194 
195     fn dup2(fd1: c_int, fd2: c_int) -> c_int {
196         e(syscall::dup2(fd1 as usize, fd2 as usize, &[])) as c_int
197     }
198 
199     fn exit(status: c_int) -> ! {
200         let _ = syscall::exit(status as usize);
201         loop {}
202     }
203 
204     unsafe fn execve(
205         path: &CStr,
206         mut argv: *const *mut c_char,
207         mut envp: *const *mut c_char,
208     ) -> c_int {
209         let mut file = match File::open(path, fcntl::O_RDONLY | fcntl::O_CLOEXEC) {
210             Ok(file) => file,
211             Err(_) => return -1,
212         };
213         let fd = *file as usize;
214 
215         // Count arguments
216         let mut len = 0;
217         while !(*argv.offset(len)).is_null() {
218             len += 1;
219         }
220 
221         let mut args: Vec<[usize; 2]> = Vec::with_capacity(len as usize);
222 
223         // Read shebang (for example #!/bin/sh)
224         let interpreter = {
225             let mut reader = BufReader::new(&mut file);
226 
227             let mut shebang = [0; 2];
228             let mut read = 0;
229 
230             while read < 2 {
231                 match reader.read(&mut shebang) {
232                     Ok(0) => break,
233                     Ok(i) => read += i,
234                     Err(_) => return -1,
235                 }
236             }
237 
238             if &shebang == b"#!" {
239                 // So, this file is interpreted.
240                 // That means the actual file descriptor passed to `fexec` won't be this file.
241                 // So we need to check ourselves that this file is actually be executable.
242 
243                 let mut stat = redox_stat::default();
244                 if e(syscall::fstat(fd, &mut stat)) == !0 {
245                     return -1;
246                 }
247                 let uid = e(syscall::getuid());
248                 if uid == !0 {
249                     return -1;
250                 }
251                 let gid = e(syscall::getuid());
252                 if gid == !0 {
253                     return -1;
254                 }
255 
256                 let mode = if uid == stat.st_uid as usize {
257                     (stat.st_mode >> 3 * 2) & 0o7
258                 } else if gid == stat.st_gid as usize {
259                     (stat.st_mode >> 3 * 1) & 0o7
260                 } else {
261                     stat.st_mode & 0o7
262                 };
263 
264                 if mode & 0o1 == 0o0 {
265                     errno = EPERM;
266                     return -1;
267                 }
268 
269                 // Then, read the actual interpreter:
270                 let mut interpreter = Vec::new();
271                 match reader.read_until(b'\n', &mut interpreter) {
272                     Err(_) => return -1,
273                     Ok(_) => {
274                         if interpreter.ends_with(&[b'\n']) {
275                             interpreter.pop().unwrap();
276                         }
277                         // TODO: Returning the interpreter here is actually a
278                         // hack. Preferrably we should reassign `file =`
279                         // directly from here. Just wait until NLL comes
280                         // around...
281                         Some(interpreter)
282                     }
283                 }
284             } else {
285                 None
286             }
287         };
288         let mut _interpreter_path = None;
289         if let Some(interpreter) = interpreter {
290             let cstring = match CString::new(interpreter) {
291                 Ok(cstring) => cstring,
292                 Err(_) => return -1,
293             };
294             file = match File::open(&cstring, fcntl::O_RDONLY | fcntl::O_CLOEXEC) {
295                 Ok(file) => file,
296                 Err(_) => return -1,
297             };
298 
299             // Make sure path is kept alive long enough, and push it to the arguments
300             _interpreter_path = Some(cstring);
301             let path_ref = _interpreter_path.as_ref().unwrap();
302             args.push([path_ref.as_ptr() as usize, path_ref.to_bytes().len()]);
303         } else {
304             if file.seek(SeekFrom::Start(0)).is_err() {
305                 return -1;
306             }
307         }
308 
309         // Arguments
310         while !(*argv).is_null() {
311             let arg = *argv;
312 
313             let mut len = 0;
314             while *arg.offset(len) != 0 {
315                 len += 1;
316             }
317             args.push([arg as usize, len as usize]);
318             argv = argv.offset(1);
319         }
320 
321         // Environment variables
322         let mut len = 0;
323         while !(*envp.offset(len)).is_null() {
324             len += 1;
325         }
326 
327         let mut envs: Vec<[usize; 2]> = Vec::with_capacity(len as usize);
328         while !(*envp).is_null() {
329             let env = *envp;
330 
331             let mut len = 0;
332             while *env.offset(len) != 0 {
333                 len += 1;
334             }
335             envs.push([env as usize, len as usize]);
336             envp = envp.offset(1);
337         }
338 
339         e(syscall::fexec(*file as usize, &args, &envs)) as c_int
340     }
341 
342     fn fchdir(fd: c_int) -> c_int {
343         let mut buf = [0; 4096];
344         let res = e(syscall::fpath(fd as usize, &mut buf));
345         if res == !0 {
346             !0
347         } else {
348             match str::from_utf8(&buf[..res]) {
349                 Ok(path) => e(syscall::chdir(&path)) as c_int,
350                 Err(_) => {
351                     unsafe { errno = EINVAL };
352                     return -1;
353                 }
354             }
355         }
356     }
357 
358     fn fchmod(fd: c_int, mode: mode_t) -> c_int {
359         e(syscall::fchmod(fd as usize, mode as u16)) as c_int
360     }
361 
362     fn fchown(fd: c_int, owner: uid_t, group: gid_t) -> c_int {
363         e(syscall::fchown(fd as usize, owner as u32, group as u32)) as c_int
364     }
365 
366     fn fcntl(fd: c_int, cmd: c_int, args: c_int) -> c_int {
367         e(syscall::fcntl(fd as usize, cmd as usize, args as usize)) as c_int
368     }
369 
370     fn flock(_fd: c_int, _operation: c_int) -> c_int {
371         // TODO: Redox does not have file locking yet
372         0
373     }
374 
375     fn fork() -> pid_t {
376         e(unsafe { syscall::clone(syscall::CloneFlags::empty()) }) as pid_t
377     }
378 
379     fn fstat(fildes: c_int, buf: *mut stat) -> c_int {
380         let mut redox_buf: redox_stat = redox_stat::default();
381         match e(syscall::fstat(fildes as usize, &mut redox_buf)) {
382             0 => {
383                 if let Some(buf) = unsafe { buf.as_mut() } {
384                     buf.st_dev = redox_buf.st_dev as dev_t;
385                     buf.st_ino = redox_buf.st_ino as ino_t;
386                     buf.st_nlink = redox_buf.st_nlink as nlink_t;
387                     buf.st_mode = redox_buf.st_mode as mode_t;
388                     buf.st_uid = redox_buf.st_uid as uid_t;
389                     buf.st_gid = redox_buf.st_gid as gid_t;
390                     // TODO st_rdev
391                     buf.st_rdev = 0;
392                     buf.st_size = redox_buf.st_size as off_t;
393                     buf.st_blksize = redox_buf.st_blksize as blksize_t;
394                     buf.st_atim = timespec {
395                         tv_sec: redox_buf.st_atime as time_t,
396                         tv_nsec: redox_buf.st_atime_nsec as c_long,
397                     };
398                     buf.st_mtim = timespec {
399                         tv_sec: redox_buf.st_mtime as time_t,
400                         tv_nsec: redox_buf.st_mtime_nsec as c_long,
401                     };
402                     buf.st_ctim = timespec {
403                         tv_sec: redox_buf.st_ctime as time_t,
404                         tv_nsec: redox_buf.st_ctime_nsec as c_long,
405                     };
406                 }
407                 0
408             }
409             _ => -1,
410         }
411     }
412 
413     fn fstatvfs(fildes: c_int, buf: *mut statvfs) -> c_int {
414         let mut kbuf: redox_statvfs = redox_statvfs::default();
415         match e(syscall::fstatvfs(fildes as usize, &mut kbuf)) {
416             0 => {
417                 unsafe {
418                     if !buf.is_null() {
419                         (*buf).f_bsize = kbuf.f_bsize as c_ulong;
420                         (*buf).f_frsize = kbuf.f_bsize as c_ulong;
421                         (*buf).f_blocks = kbuf.f_blocks;
422                         (*buf).f_bfree = kbuf.f_bfree;
423                         (*buf).f_bavail = kbuf.f_bavail;
424                         //TODO
425                         (*buf).f_files = 0;
426                         (*buf).f_ffree = 0;
427                         (*buf).f_favail = 0;
428                         (*buf).f_fsid = 0;
429                         (*buf).f_flag = 0;
430                         (*buf).f_namemax = 0;
431                     }
432                 }
433                 0
434             }
435             _ => -1,
436         }
437     }
438 
439     fn fsync(fd: c_int) -> c_int {
440         e(syscall::fsync(fd as usize)) as c_int
441     }
442 
443     fn ftruncate(fd: c_int, len: off_t) -> c_int {
444         e(syscall::ftruncate(fd as usize, len as usize)) as c_int
445     }
446 
447     fn futex(addr: *mut c_int, op: c_int, val: c_int) -> c_int {
448         match unsafe {
449             syscall::futex(
450                 addr as *mut i32,
451                 op as usize,
452                 val as i32,
453                 0,
454                 ptr::null_mut(),
455             )
456         } {
457             Ok(success) => success as c_int,
458             Err(err) => -(err.errno as c_int),
459         }
460     }
461 
462     fn futimens(fd: c_int, times: *const timespec) -> c_int {
463         let times = [unsafe { redox_timespec::from(&*times) }, unsafe {
464             redox_timespec::from(&*times.offset(1))
465         }];
466         e(syscall::futimens(fd as usize, &times)) as c_int
467     }
468 
469     fn utimens(path: &CStr, times: *const timespec) -> c_int {
470         match File::open(path, fcntl::O_PATH | fcntl::O_CLOEXEC) {
471             Ok(file) => Self::futimens(*file, times),
472             Err(_) => -1,
473         }
474     }
475 
476     fn getcwd(buf: *mut c_char, size: size_t) -> *mut c_char {
477         let buf_slice = unsafe { slice::from_raw_parts_mut(buf as *mut u8, size as usize) };
478         if !buf_slice.is_empty() {
479             let nonnull_size = buf_slice.len() - 1;
480             let read = e(syscall::getcwd(&mut buf_slice[..nonnull_size]));
481             if read == !0 {
482                 ptr::null_mut()
483             } else if read == nonnull_size {
484                 unsafe {
485                     errno = ERANGE;
486                 }
487                 ptr::null_mut()
488             } else {
489                 for b in &mut buf_slice[read..] {
490                     *b = 0;
491                 }
492                 buf
493             }
494         } else {
495             unsafe {
496                 errno = EINVAL;
497             }
498             ptr::null_mut()
499         }
500     }
501 
502     fn getdents(fd: c_int, mut dirents: *mut dirent, max_bytes: usize) -> c_int {
503         //TODO: rewrite this code. Originally the *dirents = dirent { ... } stuff below caused
504         // massive issues. This has been hacked around, but it still isn't perfect
505 
506         // Get initial reading position
507         let mut read = match syscall::lseek(fd as usize, 0, syscall::SEEK_CUR) {
508             Ok(pos) => pos as isize,
509             Err(err) => return -err.errno,
510         };
511 
512         let mut written = 0;
513         let mut buf = [0; 1024];
514 
515         let mut name = [0; 256];
516         let mut i = 0;
517 
518         let mut flush = |written: &mut usize, i: &mut usize, name: &mut [c_char; 256]| {
519             if *i < name.len() {
520                 // Set NUL byte
521                 name[*i] = 0;
522             }
523             // Get size: full size - unused bytes
524             if *written + mem::size_of::<dirent>() > max_bytes {
525                 // Seek back to after last read entry and return
526                 match syscall::lseek(fd as usize, read, syscall::SEEK_SET) {
527                     Ok(_) => return Some(*written as c_int),
528                     Err(err) => return Some(-err.errno),
529                 }
530             }
531             let size = mem::size_of::<dirent>() - name.len().saturating_sub(*i + 1);
532             unsafe {
533                 //This is the offending code mentioned above
534                 *dirents = dirent {
535                     d_ino: 0,
536                     d_off: read as off_t,
537                     d_reclen: size as c_ushort,
538                     d_type: 0,
539                     d_name: *name,
540                 };
541                 dirents = (dirents as *mut u8).offset(size as isize) as *mut dirent;
542             }
543             read += *i as isize + /* newline */ 1;
544             *written += size;
545             *i = 0;
546             None
547         };
548 
549         loop {
550             // Read a chunk from the directory
551             let len = match syscall::read(fd as usize, &mut buf) {
552                 Ok(0) => {
553                     if i > 0 {
554                         if let Some(value) = flush(&mut written, &mut i, &mut name) {
555                             return value;
556                         }
557                     }
558                     return written as c_int;
559                 }
560                 Ok(n) => n,
561                 Err(err) => return -err.errno,
562             };
563 
564             // Handle everything
565             let mut start = 0;
566             while start < len {
567                 let buf = &buf[start..len];
568 
569                 // Copy everything up until a newline
570                 let newline = buf.iter().position(|&c| c == b'\n');
571                 let pre_len = newline.unwrap_or(buf.len());
572                 let post_len = newline.map(|i| i + 1).unwrap_or(buf.len());
573                 if i < pre_len {
574                     // Reserve space for NUL byte
575                     let name_len = name.len() - 1;
576                     let name = &mut name[i..name_len];
577                     let copy = pre_len.min(name.len());
578                     let buf = unsafe { slice::from_raw_parts(buf.as_ptr() as *const c_char, copy) };
579                     name[..copy].copy_from_slice(buf);
580                 }
581 
582                 i += pre_len;
583                 start += post_len;
584 
585                 // Write the directory entry
586                 if newline.is_some() {
587                     if let Some(value) = flush(&mut written, &mut i, &mut name) {
588                         return value;
589                     }
590                 }
591             }
592         }
593     }
594 
595     fn getegid() -> gid_t {
596         e(syscall::getegid()) as gid_t
597     }
598 
599     fn geteuid() -> uid_t {
600         e(syscall::geteuid()) as uid_t
601     }
602 
603     fn getgid() -> gid_t {
604         e(syscall::getgid()) as gid_t
605     }
606 
607     fn getpagesize() -> usize {
608         4096
609     }
610 
611     fn getpgid(pid: pid_t) -> pid_t {
612         e(syscall::getpgid(pid as usize)) as pid_t
613     }
614 
615     fn getpid() -> pid_t {
616         e(syscall::getpid()) as pid_t
617     }
618 
619     fn getppid() -> pid_t {
620         e(syscall::getppid()) as pid_t
621     }
622 
623     fn getrandom(buf: &mut [u8], flags: c_uint) -> ssize_t {
624         //TODO: make this a system call?
625 
626         let path = if flags & sys_random::GRND_RANDOM != 0 {
627             //TODO: /dev/random equivalent
628             "rand:"
629         } else {
630             "rand:"
631         };
632 
633         let mut open_flags = syscall::O_RDONLY | syscall::O_CLOEXEC;
634         if flags & sys_random::GRND_NONBLOCK != 0 {
635             open_flags |= syscall::O_NONBLOCK;
636         }
637 
638         let fd = e(syscall::open(path, open_flags));
639         if fd == !0 {
640             return -1;
641         }
642 
643         let res = e(syscall::read(fd, buf)) as ssize_t;
644 
645         let _ = syscall::close(fd);
646 
647         res
648     }
649 
650     unsafe fn getrlimit(resource: c_int, rlim: *mut rlimit) -> c_int {
651         //TODO
652         if !rlim.is_null() {
653             (*rlim).rlim_cur = RLIM_INFINITY;
654             (*rlim).rlim_max = RLIM_INFINITY;
655         }
656         0
657     }
658 
659     fn gettid() -> pid_t {
660         //TODO
661         Self::getpid()
662     }
663 
664     fn gettimeofday(tp: *mut timeval, tzp: *mut timezone) -> c_int {
665         let mut redox_tp = redox_timespec::default();
666         let err = e(syscall::clock_gettime(
667             syscall::CLOCK_REALTIME,
668             &mut redox_tp,
669         )) as c_int;
670         if err < 0 {
671             return err;
672         }
673         unsafe {
674             (*tp).tv_sec = redox_tp.tv_sec as time_t;
675             (*tp).tv_usec = (redox_tp.tv_nsec / 1000) as suseconds_t;
676 
677             if !tzp.is_null() {
678                 (*tzp).tz_minuteswest = 0;
679                 (*tzp).tz_dsttime = 0;
680             }
681         }
682         0
683     }
684 
685     fn getuid() -> uid_t {
686         e(syscall::getuid()) as pid_t
687     }
688 
689     fn link(path1: &CStr, path2: &CStr) -> c_int {
690         e(unsafe { syscall::link(path1.as_ptr() as *const u8, path2.as_ptr() as *const u8) })
691             as c_int
692     }
693 
694     fn lseek(fd: c_int, offset: off_t, whence: c_int) -> off_t {
695         e(syscall::lseek(
696             fd as usize,
697             offset as isize,
698             whence as usize,
699         )) as off_t
700     }
701 
702     fn mkdir(path: &CStr, mode: mode_t) -> c_int {
703         match File::create(
704             path,
705             fcntl::O_DIRECTORY | fcntl::O_EXCL | fcntl::O_CLOEXEC,
706             0o777,
707         ) {
708             Ok(_fd) => 0,
709             Err(_) => -1,
710         }
711     }
712 
713     fn mkfifo(path: &CStr, mode: mode_t) -> c_int {
714         match File::create(
715             path,
716             fcntl::O_CREAT | fcntl::O_CLOEXEC,
717             syscall::MODE_FIFO as mode_t | (mode & 0o777),
718         ) {
719             Ok(fd) => 0,
720             Err(_) => -1,
721         }
722     }
723 
724     unsafe fn mmap(
725         addr: *mut c_void,
726         len: usize,
727         prot: c_int,
728         flags: c_int,
729         fildes: c_int,
730         off: off_t,
731     ) -> *mut c_void {
732         let map = Map {
733             offset: off as usize,
734             size: len,
735             flags: syscall::MapFlags::from_bits_truncate(
736                 ((prot as usize) << 16) | ((flags as usize) & 0xFFFF),
737             ),
738             address: addr as usize,
739         };
740 
741         if flags & MAP_ANONYMOUS == MAP_ANONYMOUS {
742             e(syscall::fmap(!0, &map)) as *mut c_void
743         } else {
744             e(syscall::fmap(fildes as usize, &map)) as *mut c_void
745         }
746     }
747 
748     unsafe fn mprotect(addr: *mut c_void, len: usize, prot: c_int) -> c_int {
749         e(syscall::mprotect(
750             addr as usize,
751             len,
752             syscall::MapFlags::from_bits((prot as usize) << 16)
753                 .expect("mprotect: invalid bit pattern"),
754         )) as c_int
755     }
756 
757     unsafe fn msync(addr: *mut c_void, len: usize, flags: c_int) -> c_int {
758         eprintln!("msync {:p} {:x} {:x}", addr, len, flags);
759         e(Err(syscall::Error::new(syscall::ENOSYS))) as c_int
760         /* TODO
761         e(syscall::msync(
762             addr as usize,
763             len,
764             flags
765         )) as c_int
766         */
767     }
768 
769     unsafe fn munmap(addr: *mut c_void, len: usize) -> c_int {
770         if e(syscall::funmap(addr as usize, len)) == !0 {
771             return !0;
772         }
773         0
774     }
775 
776     fn nanosleep(rqtp: *const timespec, rmtp: *mut timespec) -> c_int {
777         let redox_rqtp = unsafe { redox_timespec::from(&*rqtp) };
778         let mut redox_rmtp: redox_timespec;
779         if rmtp.is_null() {
780             redox_rmtp = redox_timespec::default();
781         } else {
782             redox_rmtp = unsafe { redox_timespec::from(&*rmtp) };
783         }
784         match e(syscall::nanosleep(&redox_rqtp, &mut redox_rmtp)) as c_int {
785             -1 => -1,
786             _ => {
787                 unsafe {
788                     if !rmtp.is_null() {
789                         (*rmtp).tv_sec = redox_rmtp.tv_sec;
790                         (*rmtp).tv_nsec = redox_rmtp.tv_nsec as i64;
791                     }
792                 }
793                 0
794             }
795         }
796     }
797 
798     fn open(path: &CStr, oflag: c_int, mode: mode_t) -> c_int {
799         let path = path_from_c_str!(path);
800         e(syscall::open(
801             path,
802             ((oflag as usize) & 0xFFFF_0000) | ((mode as usize) & 0xFFFF),
803         )) as c_int
804     }
805 
806     fn pipe2(fds: &mut [c_int], flags: c_int) -> c_int {
807         let mut usize_fds: [usize; 2] = [0; 2];
808         let res = e(syscall::pipe2(&mut usize_fds, flags as usize));
809         fds[0] = usize_fds[0] as c_int;
810         fds[1] = usize_fds[1] as c_int;
811         res as c_int
812     }
813 
814     #[cfg(target_arch = "aarch64")]
815     unsafe fn pte_clone(stack: *mut usize) -> pid_t {
816         //TODO: aarch64
817         unimplemented!("pte_clone not implemented on aarch64");
818     }
819 
820     #[cfg(target_arch = "x86_64")]
821     unsafe fn pte_clone(stack: *mut usize) -> pid_t {
822         let flags = syscall::CLONE_VM
823             | syscall::CLONE_FS
824             | syscall::CLONE_FILES
825             | syscall::CLONE_SIGHAND
826             | syscall::CLONE_STACK;
827         let pid;
828         llvm_asm!("
829             # Call clone syscall
830             syscall
831 
832             # Check if child or parent
833             test rax, rax
834             jnz .parent
835 
836             # Load registers
837             pop rax
838             pop rdi
839             pop rsi
840             pop rdx
841             pop rcx
842             pop r8
843             pop r9
844 
845             # Call entry point
846             call rax
847 
848             # Exit
849             mov rax, 1
850             xor rdi, rdi
851             syscall
852 
853             # Invalid instruction on failure to exit
854             ud2
855 
856             # Return PID if parent
857             .parent:
858             "
859             : "={rax}"(pid)
860             : "{rax}"(syscall::SYS_CLONE), "{rdi}"(flags), "{rsi}"(stack)
861             : "memory", "rbx", "rcx", "rdx", "rsi", "rdi", "r8",
862               "r9", "r10", "r11", "r12", "r13", "r14", "r15"
863             : "intel", "volatile"
864         );
865         e(syscall::Error::demux(pid)) as pid_t
866     }
867 
868     fn read(fd: c_int, buf: &mut [u8]) -> ssize_t {
869         e(syscall::read(fd as usize, buf)) as ssize_t
870     }
871 
872     fn fpath(fildes: c_int, out: &mut [u8]) -> ssize_t {
873         e(syscall::fpath(fildes as usize, out)) as ssize_t
874     }
875 
876     fn readlink(pathname: &CStr, out: &mut [u8]) -> ssize_t {
877         let file = match File::open(
878             pathname,
879             fcntl::O_PATH | fcntl::O_SYMLINK | fcntl::O_CLOEXEC,
880         ) {
881             Ok(ok) => ok,
882             Err(_) => return -1,
883         };
884 
885         if out.is_empty() {
886             return 0;
887         }
888 
889         let len = out.len();
890         let read = e(syscall::fpath(*file as usize, &mut out[..len - 1]));
891         if (read as c_int) < 0 {
892             return -1;
893         }
894         out[read as usize] = 0;
895 
896         0
897     }
898 
899     fn rename(oldpath: &CStr, newpath: &CStr) -> c_int {
900         let newpath = path_from_c_str!(newpath);
901         match File::open(oldpath, fcntl::O_PATH | fcntl::O_CLOEXEC) {
902             Ok(file) => e(syscall::frename(*file as usize, newpath)) as c_int,
903             Err(_) => -1,
904         }
905     }
906 
907     fn rmdir(path: &CStr) -> c_int {
908         let path = path_from_c_str!(path);
909         e(syscall::rmdir(path)) as c_int
910     }
911 
912     fn sched_yield() -> c_int {
913         e(syscall::sched_yield()) as c_int
914     }
915 
916     fn setpgid(pid: pid_t, pgid: pid_t) -> c_int {
917         e(syscall::setpgid(pid as usize, pgid as usize)) as c_int
918     }
919 
920     fn setregid(rgid: gid_t, egid: gid_t) -> c_int {
921         e(syscall::setregid(rgid as usize, egid as usize)) as c_int
922     }
923 
924     fn setreuid(ruid: uid_t, euid: uid_t) -> c_int {
925         e(syscall::setreuid(ruid as usize, euid as usize)) as c_int
926     }
927 
928     fn symlink(path1: &CStr, path2: &CStr) -> c_int {
929         let mut file = match File::create(
930             path2,
931             fcntl::O_WRONLY | fcntl::O_SYMLINK | fcntl::O_CLOEXEC,
932             0o777,
933         ) {
934             Ok(ok) => ok,
935             Err(_) => return -1,
936         };
937 
938         if file.write(path1.to_bytes()).is_err() {
939             return -1;
940         }
941 
942         0
943     }
944 
945     fn umask(mask: mode_t) -> mode_t {
946         e(syscall::umask(mask as usize)) as mode_t
947     }
948 
949     fn uname(utsname: *mut utsname) -> c_int {
950         fn gethostname(name: &mut [u8]) -> io::Result<()> {
951             if name.is_empty() {
952                 return Ok(());
953             }
954 
955             let mut file = File::open(
956                 &CString::new("/etc/hostname").unwrap(),
957                 fcntl::O_RDONLY | fcntl::O_CLOEXEC,
958             )?;
959 
960             let mut read = 0;
961             let name_len = name.len();
962             loop {
963                 match file.read(&mut name[read..name_len - 1])? {
964                     0 => break,
965                     n => read += n,
966                 }
967             }
968             name[read] = 0;
969             Ok(())
970         }
971 
972         fn inner(utsname: *mut utsname) -> CoreResult<(), i32> {
973             match gethostname(unsafe {
974                 slice::from_raw_parts_mut(
975                     (*utsname).nodename.as_mut_ptr() as *mut u8,
976                     (*utsname).nodename.len(),
977                 )
978             }) {
979                 Ok(_) => (),
980                 Err(_) => return Err(EIO),
981             }
982 
983             let file_path = c_str!("sys:uname");
984             let mut file = match File::open(file_path, fcntl::O_RDONLY | fcntl::O_CLOEXEC) {
985                 Ok(ok) => ok,
986                 Err(_) => return Err(EIO),
987             };
988             let mut lines = BufReader::new(&mut file).lines();
989 
990             let mut read_line = |dst: &mut [c_char]| {
991                 let line = match lines.next() {
992                     Some(Ok(l)) => match CString::new(l) {
993                         Ok(l) => l,
994                         Err(_) => return Err(EIO),
995                     },
996                     None | Some(Err(_)) => return Err(EIO),
997                 };
998 
999                 let line_slice: &[c_char] = unsafe { mem::transmute(line.as_bytes_with_nul()) };
1000 
1001                 if line_slice.len() <= UTSLENGTH {
1002                     dst[..line_slice.len()].copy_from_slice(line_slice);
1003                     Ok(())
1004                 } else {
1005                     Err(EIO)
1006                 }
1007             };
1008 
1009             unsafe {
1010                 read_line(&mut (*utsname).sysname)?;
1011                 read_line(&mut (*utsname).release)?;
1012                 read_line(&mut (*utsname).machine)?;
1013 
1014                 // Version is not provided
1015                 ptr::write_bytes((*utsname).version.as_mut_ptr(), 0, UTSLENGTH);
1016 
1017                 // Redox doesn't provide domainname in sys:uname
1018                 //read_line(&mut (*utsname).domainname)?;
1019                 ptr::write_bytes((*utsname).domainname.as_mut_ptr(), 0, UTSLENGTH);
1020             }
1021 
1022             Ok(())
1023         }
1024 
1025         match inner(utsname) {
1026             Ok(()) => 0,
1027             Err(err) => unsafe {
1028                 errno = err;
1029                 -1
1030             },
1031         }
1032     }
1033 
1034     fn unlink(path: &CStr) -> c_int {
1035         let path = path_from_c_str!(path);
1036         e(syscall::unlink(path)) as c_int
1037     }
1038 
1039     fn waitpid(mut pid: pid_t, stat_loc: *mut c_int, options: c_int) -> pid_t {
1040         if pid == !0 {
1041             pid = 0;
1042         }
1043         let mut res = None;
1044         let mut status = 0;
1045 
1046         let inner = |status: &mut usize, flags| {
1047             syscall::waitpid(
1048                 pid as usize,
1049                 status,
1050                 syscall::WaitFlags::from_bits(flags as usize)
1051                     .expect("waitpid: invalid bit pattern"),
1052             )
1053         };
1054 
1055         // First, allow ptrace to handle waitpid
1056         // TODO: Handle special PIDs here (such as -1)
1057         let state = ptrace::init_state();
1058         let mut sessions = state.sessions.lock();
1059         if let Ok(session) = ptrace::get_session(&mut sessions, pid) {
1060             if options & sys_wait::WNOHANG != sys_wait::WNOHANG {
1061                 let mut _event = PtraceEvent::default();
1062                 let _ = (&mut &session.tracer).read(&mut _event);
1063 
1064                 res = Some(e(inner(
1065                     &mut status,
1066                     options | sys_wait::WNOHANG | sys_wait::WUNTRACED,
1067                 )));
1068                 if res == Some(0) {
1069                     // WNOHANG, just pretend ptrace SIGSTOP:ped this
1070                     status = (syscall::SIGSTOP << 8) | 0x7f;
1071                     assert!(syscall::wifstopped(status));
1072                     assert_eq!(syscall::wstopsig(status), syscall::SIGSTOP);
1073                     res = Some(pid as usize);
1074                 }
1075             }
1076         }
1077 
1078         // If ptrace didn't impact this waitpid, proceed *almost* as
1079         // normal: We still need to add WUNTRACED, but we only return
1080         // it if (and only if) a ptrace traceme was activated during
1081         // the wait.
1082         let res = res.unwrap_or_else(|| loop {
1083             let res = e(inner(&mut status, options | sys_wait::WUNTRACED));
1084 
1085             // TODO: Also handle special PIDs here
1086             if !syscall::wifstopped(res) || ptrace::is_traceme(pid) {
1087                 break res;
1088             }
1089         });
1090 
1091         // If stat_loc is non-null, set that and the return
1092         unsafe {
1093             if !stat_loc.is_null() {
1094                 *stat_loc = status as c_int;
1095             }
1096         }
1097         res as pid_t
1098     }
1099 
1100     fn write(fd: c_int, buf: &[u8]) -> ssize_t {
1101         e(syscall::write(fd as usize, buf)) as ssize_t
1102     }
1103 
1104     fn verify() -> bool {
1105         // GETPID on Redox is 20, which is WRITEV on Linux
1106         e(unsafe { syscall::syscall5(syscall::number::SYS_GETPID, !0, !0, !0, !0, !0) }) != !0
1107     }
1108 }
1109