1 //! unistd implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/unistd.h.html 2 3 use core::{convert::TryFrom, mem, ptr, slice}; 4 5 use crate::{ 6 c_str::CStr, 7 header::{ 8 errno, fcntl, limits, stdlib::getenv, sys_ioctl, sys_time, sys_utsname, termios, 9 time::timespec, 10 }, 11 platform::{self, types::*, Pal, Sys}, 12 }; 13 use alloc::collections::LinkedList; 14 15 pub use self::{brk::*, getopt::*, pathconf::*, sysconf::*}; 16 17 mod brk; 18 mod getopt; 19 mod pathconf; 20 mod sysconf; 21 22 pub const F_OK: c_int = 0; 23 pub const R_OK: c_int = 4; 24 pub const W_OK: c_int = 2; 25 pub const X_OK: c_int = 1; 26 27 pub const SEEK_SET: c_int = 0; 28 pub const SEEK_CUR: c_int = 1; 29 pub const SEEK_END: c_int = 2; 30 31 pub const F_ULOCK: c_int = 0; 32 pub const F_LOCK: c_int = 1; 33 pub const F_TLOCK: c_int = 2; 34 pub const F_TEST: c_int = 3; 35 36 pub const STDIN_FILENO: c_int = 0; 37 pub const STDOUT_FILENO: c_int = 1; 38 pub const STDERR_FILENO: c_int = 2; 39 40 #[thread_local] 41 pub static mut fork_hooks_static: Option<[LinkedList<extern "C" fn()>; 3]> = None; 42 43 unsafe fn init_fork_hooks<'a>() -> &'a mut [LinkedList<extern "C" fn()>; 3] { 44 // Transmute the lifetime so we can return here. Should be safe as 45 // long as one does not access the original fork_hooks. 46 mem::transmute( 47 fork_hooks_static 48 .get_or_insert_with(|| [LinkedList::new(), LinkedList::new(), LinkedList::new()]), 49 ) 50 } 51 52 #[no_mangle] 53 pub extern "C" fn _exit(status: c_int) { 54 Sys::exit(status) 55 } 56 57 #[no_mangle] 58 pub unsafe extern "C" fn access(path: *const c_char, mode: c_int) -> c_int { 59 let path = CStr::from_ptr(path); 60 Sys::access(path, mode) 61 } 62 63 #[no_mangle] 64 pub extern "C" fn alarm(seconds: c_uint) -> c_uint { 65 let mut timer = sys_time::itimerval { 66 it_value: sys_time::timeval { 67 tv_sec: seconds as time_t, 68 tv_usec: 0, 69 }, 70 ..Default::default() 71 }; 72 let errno_backup = unsafe { platform::errno }; 73 let secs = if sys_time::setitimer(sys_time::ITIMER_REAL, &timer, &mut timer) < 0 { 74 0 75 } else { 76 timer.it_value.tv_sec as c_uint + if timer.it_value.tv_usec > 0 { 1 } else { 0 } 77 }; 78 unsafe { 79 platform::errno = errno_backup; 80 } 81 82 secs 83 } 84 85 #[no_mangle] 86 pub unsafe extern "C" fn chdir(path: *const c_char) -> c_int { 87 let path = CStr::from_ptr(path); 88 Sys::chdir(path) 89 } 90 91 // #[no_mangle] 92 pub extern "C" fn chroot(path: *const c_char) -> c_int { 93 unimplemented!(); 94 } 95 96 #[no_mangle] 97 pub unsafe extern "C" fn chown(path: *const c_char, owner: uid_t, group: gid_t) -> c_int { 98 let path = CStr::from_ptr(path); 99 Sys::chown(path, owner, group) 100 } 101 102 #[no_mangle] 103 pub extern "C" fn close(fildes: c_int) -> c_int { 104 Sys::close(fildes) 105 } 106 107 // #[no_mangle] 108 pub extern "C" fn confstr(name: c_int, buf: *mut c_char, len: size_t) -> size_t { 109 unimplemented!(); 110 } 111 112 // #[no_mangle] 113 pub extern "C" fn crypt(key: *const c_char, salt: *const c_char) -> *mut c_char { 114 unimplemented!(); 115 } 116 117 #[no_mangle] 118 pub extern "C" fn dup(fildes: c_int) -> c_int { 119 Sys::dup(fildes) 120 } 121 122 #[no_mangle] 123 pub extern "C" fn dup2(fildes: c_int, fildes2: c_int) -> c_int { 124 Sys::dup2(fildes, fildes2) 125 } 126 127 // #[no_mangle] 128 pub extern "C" fn encrypt(block: [c_char; 64], edflag: c_int) { 129 unimplemented!(); 130 } 131 132 // #[no_mangle] 133 // pub extern "C" fn execl(path: *const c_char, args: *const *mut c_char) -> c_int { 134 // unimplemented!(); 135 // } 136 137 // #[no_mangle] 138 // pub extern "C" fn execle( 139 // path: *const c_char, 140 // args: *const *mut c_char, 141 // envp: *const *mut c_char, 142 // ) -> c_int { 143 // unimplemented!(); 144 // } 145 146 // #[no_mangle] 147 // pub extern "C" fn execlp(file: *const c_char, args: *const *mut c_char) -> c_int { 148 // unimplemented!(); 149 // } 150 151 #[no_mangle] 152 pub unsafe extern "C" fn execv(path: *const c_char, argv: *const *mut c_char) -> c_int { 153 execve(path, argv, platform::environ) 154 } 155 156 #[no_mangle] 157 pub unsafe extern "C" fn execve( 158 path: *const c_char, 159 argv: *const *mut c_char, 160 envp: *const *mut c_char, 161 ) -> c_int { 162 let path = CStr::from_ptr(path); 163 Sys::execve(path, argv, envp) 164 } 165 166 #[cfg(target_os = "linux")] 167 const PATH_SEPARATOR: u8 = b':'; 168 169 #[cfg(target_os = "redox")] 170 const PATH_SEPARATOR: u8 = b';'; 171 172 #[no_mangle] 173 pub unsafe extern "C" fn execvp(file: *const c_char, argv: *const *mut c_char) -> c_int { 174 let file = CStr::from_ptr(file); 175 176 if file.to_bytes().contains(&b'/') 177 || (cfg!(target_os = "redox") && file.to_bytes().contains(&b':')) 178 { 179 execv(file.as_ptr(), argv) 180 } else { 181 let mut error = errno::ENOENT; 182 183 let path_env = getenv(c_str!("PATH\0").as_ptr()); 184 if !path_env.is_null() { 185 let path_env = CStr::from_ptr(path_env); 186 for path in path_env.to_bytes().split(|&b| b == PATH_SEPARATOR) { 187 let mut program = path.to_vec(); 188 program.push(b'/'); 189 program.extend_from_slice(file.to_bytes()); 190 program.push(b'\0'); 191 192 let program_c = CStr::from_bytes_with_nul(&program).unwrap(); 193 execv(program_c.as_ptr(), argv); 194 195 match platform::errno { 196 errno::ENOENT => (), 197 other => error = other, 198 } 199 } 200 } 201 202 platform::errno = error; 203 -1 204 } 205 } 206 207 #[no_mangle] 208 pub extern "C" fn fchown(fildes: c_int, owner: uid_t, group: gid_t) -> c_int { 209 Sys::fchown(fildes, owner, group) 210 } 211 212 #[no_mangle] 213 pub extern "C" fn fchdir(fildes: c_int) -> c_int { 214 Sys::fchdir(fildes) 215 } 216 217 // #[no_mangle] 218 pub extern "C" fn fdatasync(fildes: c_int) -> c_int { 219 unimplemented!(); 220 } 221 222 #[no_mangle] 223 pub extern "C" fn fork() -> pid_t { 224 let fork_hooks = unsafe { init_fork_hooks() }; 225 for prepare in &fork_hooks[0] { 226 prepare(); 227 } 228 let pid = Sys::fork(); 229 if pid == 0 { 230 for child in &fork_hooks[2] { 231 child(); 232 } 233 } else if pid != -1 { 234 for parent in &fork_hooks[1] { 235 parent(); 236 } 237 } 238 pid 239 } 240 241 #[no_mangle] 242 pub extern "C" fn fsync(fildes: c_int) -> c_int { 243 Sys::fsync(fildes) 244 } 245 246 #[no_mangle] 247 pub extern "C" fn ftruncate(fildes: c_int, length: off_t) -> c_int { 248 Sys::ftruncate(fildes, length) 249 } 250 251 #[no_mangle] 252 pub extern "C" fn getcwd(mut buf: *mut c_char, mut size: size_t) -> *mut c_char { 253 let alloc = buf.is_null(); 254 let mut stack_buf = [0; limits::PATH_MAX]; 255 if alloc { 256 buf = stack_buf.as_mut_ptr(); 257 size = stack_buf.len(); 258 } 259 260 let ret = Sys::getcwd(buf, size); 261 if ret.is_null() { 262 return ptr::null_mut(); 263 } 264 265 if alloc { 266 let len = stack_buf 267 .iter() 268 .position(|b| *b == 0) 269 .expect("no nul-byte in getcwd string") 270 + 1; 271 let heap_buf = unsafe { platform::alloc(len) as *mut c_char }; 272 for i in 0..len { 273 unsafe { 274 *heap_buf.add(i) = stack_buf[i]; 275 } 276 } 277 heap_buf 278 } else { 279 ret 280 } 281 } 282 283 // #[no_mangle] 284 pub extern "C" fn getdtablesize() -> c_int { 285 unimplemented!(); 286 } 287 288 #[no_mangle] 289 pub extern "C" fn getegid() -> gid_t { 290 Sys::getegid() 291 } 292 293 #[no_mangle] 294 pub extern "C" fn geteuid() -> uid_t { 295 Sys::geteuid() 296 } 297 298 #[no_mangle] 299 pub extern "C" fn getgid() -> gid_t { 300 Sys::getgid() 301 } 302 303 // #[no_mangle] 304 pub extern "C" fn getgroups(gidsetsize: c_int, grouplist: *mut gid_t) -> c_int { 305 unimplemented!(); 306 } 307 308 // #[no_mangle] 309 pub extern "C" fn gethostid() -> c_long { 310 unimplemented!(); 311 } 312 313 #[no_mangle] 314 pub unsafe extern "C" fn gethostname(mut name: *mut c_char, mut len: size_t) -> c_int { 315 let mut uts = mem::MaybeUninit::<sys_utsname::utsname>::uninit(); 316 let err = Sys::uname(uts.as_mut_ptr()); 317 if err < 0 { 318 mem::forget(uts); 319 return err; 320 } 321 for c in uts.assume_init().nodename.iter() { 322 if len == 0 { 323 break; 324 } 325 len -= 1; 326 327 *name = *c; 328 329 if *name == 0 { 330 // We do want to copy the zero also, so we check this after the copying. 331 break; 332 } 333 334 name = name.offset(1); 335 } 336 0 337 } 338 339 #[no_mangle] 340 pub unsafe extern "C" fn getlogin() -> *mut c_char { 341 static mut LOGIN: [c_char; 256] = [0; 256]; 342 if getlogin_r(LOGIN.as_mut_ptr(), LOGIN.len()) == 0 { 343 LOGIN.as_mut_ptr() 344 } else { 345 ptr::null_mut() 346 } 347 } 348 349 #[no_mangle] 350 pub extern "C" fn getlogin_r(name: *mut c_char, namesize: size_t) -> c_int { 351 //TODO: Determine correct getlogin result on Redox 352 unsafe { platform::errno = errno::ENOENT }; 353 -1 354 } 355 356 #[no_mangle] 357 pub extern "C" fn getpagesize() -> c_int { 358 match c_int::try_from(sysconf(_SC_PAGESIZE)) { 359 Ok(page_size) => page_size, 360 Err(_) => { 361 /* Behavior not specified by POSIX for this case. The -1 362 * value mimics sysconf()'s behavior, though. 363 * 364 * As specified for the limits.h header, the minimum 365 * acceptable value for {PAGESIZE} is 1. The -1 value thus 366 * cannot be mistaken for an acceptable value. 367 * 368 * POSIX does not specify any possible errors for this 369 * function, hence no errno setting. */ 370 -1 371 } 372 } 373 } 374 375 // #[no_mangle] 376 pub extern "C" fn getpass(prompt: *const c_char) -> *mut c_char { 377 unimplemented!(); 378 } 379 380 #[no_mangle] 381 pub extern "C" fn getpgid(pid: pid_t) -> pid_t { 382 Sys::getpgid(pid) 383 } 384 385 #[no_mangle] 386 pub extern "C" fn getpgrp() -> pid_t { 387 Sys::getpgid(Sys::getpid()) 388 } 389 390 #[no_mangle] 391 pub extern "C" fn getpid() -> pid_t { 392 Sys::getpid() 393 } 394 395 #[no_mangle] 396 pub extern "C" fn getppid() -> pid_t { 397 Sys::getppid() 398 } 399 400 // #[no_mangle] 401 pub extern "C" fn getsid(pid: pid_t) -> pid_t { 402 unimplemented!(); 403 } 404 405 #[no_mangle] 406 pub extern "C" fn getuid() -> uid_t { 407 Sys::getuid() 408 } 409 410 #[no_mangle] 411 pub extern "C" fn getwd(path_name: *mut c_char) -> *mut c_char { 412 getcwd(path_name, limits::PATH_MAX) 413 } 414 415 #[no_mangle] 416 pub extern "C" fn isatty(fd: c_int) -> c_int { 417 let mut t = termios::termios::default(); 418 if unsafe { termios::tcgetattr(fd, &mut t as *mut termios::termios) == 0 } { 419 1 420 } else { 421 0 422 } 423 } 424 425 // #[no_mangle] 426 pub extern "C" fn lchown(path: *const c_char, owner: uid_t, group: gid_t) -> c_int { 427 unimplemented!(); 428 } 429 430 #[no_mangle] 431 pub unsafe extern "C" fn link(path1: *const c_char, path2: *const c_char) -> c_int { 432 let path1 = CStr::from_ptr(path1); 433 let path2 = CStr::from_ptr(path2); 434 Sys::link(path1, path2) 435 } 436 437 // #[no_mangle] 438 pub extern "C" fn lockf(fildes: c_int, function: c_int, size: off_t) -> c_int { 439 unimplemented!(); 440 } 441 442 #[no_mangle] 443 pub extern "C" fn lseek(fildes: c_int, offset: off_t, whence: c_int) -> off_t { 444 Sys::lseek(fildes, offset, whence) 445 } 446 447 // #[no_mangle] 448 pub extern "C" fn nice(incr: c_int) -> c_int { 449 unimplemented!(); 450 } 451 452 // #[no_mangle] 453 pub extern "C" fn pause() -> c_int { 454 unimplemented!(); 455 } 456 457 #[no_mangle] 458 pub unsafe extern "C" fn pipe(fildes: *mut c_int) -> c_int { 459 pipe2(fildes, 0) 460 } 461 462 #[no_mangle] 463 pub unsafe extern "C" fn pipe2(fildes: *mut c_int, flags: c_int) -> c_int { 464 Sys::pipe2(slice::from_raw_parts_mut(fildes, 2), flags) 465 } 466 467 #[no_mangle] 468 pub extern "C" fn pread(fildes: c_int, buf: *mut c_void, nbyte: size_t, offset: off_t) -> ssize_t { 469 //TODO: better pread using system calls 470 471 let previous = lseek(fildes, offset, SEEK_SET); 472 if previous == -1 { 473 return -1; 474 } 475 476 let res = read(fildes, buf, nbyte); 477 if res < 0 { 478 return res; 479 } 480 481 if lseek(fildes, previous, SEEK_SET) == -1 { 482 return -1; 483 } 484 485 res 486 } 487 488 #[no_mangle] 489 pub extern "C" fn pthread_atfork( 490 prepare: Option<extern "C" fn()>, 491 parent: Option<extern "C" fn()>, 492 child: Option<extern "C" fn()>, 493 ) -> c_int { 494 let fork_hooks = unsafe { init_fork_hooks() }; 495 if let Some(prepare) = prepare { 496 fork_hooks[0].push_back(prepare); 497 } 498 if let Some(parent) = parent { 499 fork_hooks[1].push_back(parent); 500 } 501 if let Some(child) = child { 502 fork_hooks[2].push_back(child); 503 } 504 0 505 } 506 507 #[no_mangle] 508 pub extern "C" fn pwrite( 509 fildes: c_int, 510 buf: *const c_void, 511 nbyte: size_t, 512 offset: off_t, 513 ) -> ssize_t { 514 //TODO: better pwrite using system calls 515 516 let previous = lseek(fildes, offset, SEEK_SET); 517 if previous == -1 { 518 return -1; 519 } 520 521 let res = write(fildes, buf, nbyte); 522 if res < 0 { 523 return res; 524 } 525 526 if lseek(fildes, previous, SEEK_SET) == -1 { 527 return -1; 528 } 529 530 res 531 } 532 533 #[no_mangle] 534 pub extern "C" fn read(fildes: c_int, buf: *const c_void, nbyte: size_t) -> ssize_t { 535 let buf = unsafe { slice::from_raw_parts_mut(buf as *mut u8, nbyte as usize) }; 536 trace_expr!( 537 Sys::read(fildes, buf), 538 "read({}, {:p}, {})", 539 fildes, 540 buf, 541 nbyte 542 ) 543 } 544 545 #[no_mangle] 546 pub unsafe extern "C" fn readlink( 547 path: *const c_char, 548 buf: *mut c_char, 549 bufsize: size_t, 550 ) -> ssize_t { 551 let path = CStr::from_ptr(path); 552 let buf = slice::from_raw_parts_mut(buf as *mut u8, bufsize as usize); 553 Sys::readlink(path, buf) 554 } 555 556 #[no_mangle] 557 pub unsafe extern "C" fn rmdir(path: *const c_char) -> c_int { 558 let path = CStr::from_ptr(path); 559 Sys::rmdir(path) 560 } 561 562 #[no_mangle] 563 pub extern "C" fn setgid(gid: gid_t) -> c_int { 564 Sys::setregid(gid, gid) 565 } 566 567 #[no_mangle] 568 pub extern "C" fn setpgid(pid: pid_t, pgid: pid_t) -> c_int { 569 Sys::setpgid(pid, pgid) 570 } 571 572 #[no_mangle] 573 pub extern "C" fn setpgrp() -> pid_t { 574 setpgid(0, 0) 575 } 576 577 #[no_mangle] 578 pub extern "C" fn setregid(rgid: gid_t, egid: gid_t) -> c_int { 579 Sys::setregid(rgid, egid) 580 } 581 582 #[no_mangle] 583 pub extern "C" fn setreuid(ruid: uid_t, euid: uid_t) -> c_int { 584 Sys::setreuid(ruid, euid) 585 } 586 587 // #[no_mangle] 588 pub extern "C" fn setsid() -> pid_t { 589 unimplemented!(); 590 } 591 592 #[no_mangle] 593 pub extern "C" fn setuid(uid: uid_t) -> c_int { 594 Sys::setreuid(uid, uid) 595 } 596 597 #[no_mangle] 598 pub extern "C" fn sleep(seconds: c_uint) -> c_uint { 599 let rqtp = timespec { 600 tv_sec: seconds as i64, 601 tv_nsec: 0, 602 }; 603 let rmtp = ptr::null_mut(); 604 Sys::nanosleep(&rqtp, rmtp); 605 0 606 } 607 608 #[no_mangle] 609 pub extern "C" fn swab(src: *const c_void, dest: *mut c_void, nbytes: ssize_t) { 610 if nbytes <= 0 { 611 return; 612 } 613 let number_of_swaps = nbytes / 2; 614 let mut offset = 0; 615 for i in 0..number_of_swaps { 616 unsafe { 617 src.offset(offset).copy_to(dest.offset(offset + 1), 1); 618 src.offset(offset + 1).copy_to(dest.offset(offset), 1); 619 } 620 offset += 2; 621 } 622 } 623 624 #[no_mangle] 625 pub unsafe extern "C" fn symlink(path1: *const c_char, path2: *const c_char) -> c_int { 626 let path1 = CStr::from_ptr(path1); 627 let path2 = CStr::from_ptr(path2); 628 Sys::symlink(path1, path2) 629 } 630 631 // #[no_mangle] 632 pub extern "C" fn sync() { 633 unimplemented!(); 634 } 635 636 #[no_mangle] 637 pub extern "C" fn tcgetpgrp(fd: c_int) -> pid_t { 638 let mut pgrp = 0; 639 if unsafe { sys_ioctl::ioctl(fd, sys_ioctl::TIOCGPGRP, &mut pgrp as *mut pid_t as _) } < 0 { 640 return -1; 641 } 642 pgrp 643 } 644 645 #[no_mangle] 646 pub extern "C" fn tcsetpgrp(fd: c_int, pgrp: pid_t) -> c_int { 647 if unsafe { sys_ioctl::ioctl(fd, sys_ioctl::TIOCSPGRP, &pgrp as *const pid_t as _) } < 0 { 648 return -1; 649 } 650 pgrp 651 } 652 653 #[no_mangle] 654 pub extern "C" fn truncate(path: *const c_char, length: off_t) -> c_int { 655 let file = unsafe { CStr::from_ptr(path) }; 656 let fd = Sys::open(file, fcntl::O_WRONLY, 0); 657 if fd < 0 { 658 return -1; 659 } 660 661 let res = ftruncate(fd, length); 662 663 Sys::close(fd); 664 665 res 666 } 667 668 #[no_mangle] 669 pub unsafe extern "C" fn ttyname(fildes: c_int) -> *mut c_char { 670 static mut TTYNAME: [c_char; 4096] = [0; 4096]; 671 if ttyname_r(fildes, TTYNAME.as_mut_ptr(), TTYNAME.len()) == 0 { 672 TTYNAME.as_mut_ptr() 673 } else { 674 ptr::null_mut() 675 } 676 } 677 678 #[no_mangle] 679 pub extern "C" fn ttyname_r(fildes: c_int, name: *mut c_char, namesize: size_t) -> c_int { 680 let name = unsafe { slice::from_raw_parts_mut(name as *mut u8, namesize) }; 681 if name.is_empty() { 682 return errno::ERANGE; 683 } 684 685 let len = Sys::fpath(fildes, &mut name[..namesize - 1]); 686 if len < 0 { 687 return unsafe { -platform::errno }; 688 } 689 name[len as usize] = 0; 690 691 0 692 } 693 694 #[no_mangle] 695 pub extern "C" fn ualarm(usecs: useconds_t, interval: useconds_t) -> useconds_t { 696 let mut timer = sys_time::itimerval { 697 it_value: sys_time::timeval { 698 tv_sec: 0, 699 tv_usec: usecs as suseconds_t, 700 }, 701 it_interval: sys_time::timeval { 702 tv_sec: 0, 703 tv_usec: interval as suseconds_t, 704 }, 705 }; 706 let errno_backup = unsafe { platform::errno }; 707 let ret = if sys_time::setitimer(sys_time::ITIMER_REAL, &timer, &mut timer) < 0 { 708 0 709 } else { 710 timer.it_value.tv_sec as useconds_t * 1_000_000 + timer.it_value.tv_usec as useconds_t 711 }; 712 unsafe { 713 platform::errno = errno_backup; 714 } 715 716 ret 717 } 718 719 #[no_mangle] 720 pub unsafe extern "C" fn unlink(path: *const c_char) -> c_int { 721 let path = CStr::from_ptr(path); 722 Sys::unlink(path) 723 } 724 725 #[no_mangle] 726 pub extern "C" fn usleep(useconds: useconds_t) -> c_int { 727 let rqtp = timespec { 728 tv_sec: (useconds / 1_000_000) as i64, 729 tv_nsec: ((useconds % 1_000_000) * 1000) as i64, 730 }; 731 let rmtp = ptr::null_mut(); 732 Sys::nanosleep(&rqtp, rmtp) 733 } 734 735 // #[no_mangle] 736 pub extern "C" fn vfork() -> pid_t { 737 unimplemented!(); 738 } 739 740 #[no_mangle] 741 pub extern "C" fn write(fildes: c_int, buf: *const c_void, nbyte: size_t) -> ssize_t { 742 let buf = unsafe { slice::from_raw_parts(buf as *const u8, nbyte as usize) }; 743 Sys::write(fildes, buf) 744 } 745