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, ×)) 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