char/avril
(wip) why'd you have to go and make things so complicaaaaated?
git clone https://git.t4t.associates/char/avril
f4a0f5b
main
1//! macOS specifics of the Unix backend. 2 3use std:: io; 4use std:: os:: fd::{ AsRawFd , FromRawFd , OwnedFd , RawFd }; 5use std:: path:: Path ; 6 7fn close_on_exec ( pair : ( OwnedFd , OwnedFd )) -> io:: Result <( OwnedFd , OwnedFd )> { 8// Not atomic, but this backend's own children close foreign descriptors. 9for fdin [ & pair. 0 , & pair. 1 ] { 10if unsafe { libc:: fcntl ( fd. as_raw_fd (), libc:: F_SETFD , libc:: FD_CLOEXEC ) } <0 { 11return Err ( io:: Error :: last_os_error ()); 12} 13} 14Ok ( pair) 15} 16 17pub ( super ) fn pipe () -> io:: Result <( OwnedFd , OwnedFd )> { 18let mut fds =[ 0 ; 2 ]; 19if unsafe { libc:: pipe ( fds. as_mut_ptr ()) } <0 { 20return Err ( io:: Error :: last_os_error ()); 21} 22close_on_exec ( unsafe { ( OwnedFd :: from_raw_fd ( fds[ 0 ]), OwnedFd :: from_raw_fd ( fds[ 1 ])) }) 23} 24 25/// Returns the master and slave of a new terminal. 26pub ( super ) fn pty () -> io:: Result <( OwnedFd , OwnedFd )> { 27let mut master = -1 ; 28let mut slave = -1 ; 29if unsafe { 30 libc:: openpty ( 31& mut master, 32& mut slave, 33 std:: ptr:: null_mut (), 34 std:: ptr:: null_mut (), 35 std:: ptr:: null_mut (), 36) 37} <0 38{ 39return Err ( io:: Error :: last_os_error ()); 40} 41close_on_exec ( unsafe { ( OwnedFd :: from_raw_fd ( master), OwnedFd :: from_raw_fd ( slave)) }) 42} 43 44/// The authorized executable. macOS has no `fexecve`, so it executes the 45/// authorized path. 46pub struct Executable ; 47impl Executable { 48pub fn open ( target : & Path ) -> io:: Result <( Self , std:: fs:: Metadata )> { 49Ok (( Self , std:: fs:: metadata ( target) ?)) 50} 51pub ( super ) fn reserve ( & self , _minimum : RawFd ) -> io:: Result < Self > { 52Ok ( Self ) 53} 54/// Runs after fork; returns only on failure. argv[0] is the authorized 55/// path. 56pub ( super ) fn execute ( 57& self , 58argv : * const * const libc:: c_char , 59env : * const * const libc:: c_char , 60) -> io:: Error { 61unsafe { 62 libc:: execve ( * argv, argv, env); 63} 64 io:: Error :: last_os_error () 65} 66} 67 68/// macOS has no parent-death signal: an abruptly killed owner orphans its 69/// children, and only orderly exits clean up. 70pub ( super ) struct Owner ; 71impl Owner { 72pub fn new () ->Self { 73Self 74} 75pub fn bind ( & self ) -> io:: Result <()> { 76Ok (()) 77} 78} 79 80pub ( super ) struct Descriptors ( Vec < libc:: proc_fdinfo >); 81impl Descriptors { 82/// Sizes the descriptor listing before fork, so the child need not 83/// allocate. 84pub fn new () -> io:: Result < Self > { 85let size =unsafe { 86 libc:: proc_pidinfo ( 87 libc:: getpid (), 88 libc:: PROC_PIDLISTFDS , 890 , 90 std:: ptr:: null_mut (), 910 , 92) 93}; 94if size <=0 { 95return Err ( io:: Error :: last_os_error ()); 96} 97// Headroom for descriptors other threads open before fork. 98let count = sizeas usize / std:: mem:: size_of ::< libc:: proc_fdinfo >() * 2 +64 ; 99Ok ( Self ( Vec :: with_capacity ( count))) 100} 101/// Marks every descriptor from 3 up CLOEXEC; spawn re-arms the declared 102/// ones. macOS has neither close_range nor procfs, but lists a process's 103/// descriptors directly, including any above a lowered RLIMIT_NOFILE. 104pub fn restrict ( & mut self ) -> io:: Result <()> { 105let capacity = 106( self . 0 . capacity () * std:: mem:: size_of ::< libc:: proc_fdinfo >()) as libc:: c_int ; 107let size =unsafe { 108 libc:: proc_pidinfo ( 109 libc:: getpid (), 110 libc:: PROC_PIDLISTFDS , 1110 , 112self . 0 . as_mut_ptr (). cast (), 113 capacity, 114) 115}; 116if size <=0 { 117return Err ( io:: Error :: last_os_error ()); 118} 119// A full buffer may have been truncated; fail closed. 120if size >= capacity{ 121return Err ( io:: Error :: from_raw_os_error ( libc:: EMFILE )); 122} 123unsafe { 124self . 0 125. set_len ( sizeas usize / std:: mem:: size_of ::< libc:: proc_fdinfo >()); 126} 127for entryin & self . 0 { 128let fd = entry. proc_fd ; 129if fd <3 { 130continue ; 131} 132let flags =unsafe { libc:: fcntl ( fd, libc:: F_GETFD ) }; 133if flags <0 ||unsafe { libc:: fcntl ( fd, libc:: F_SETFD , flags | libc:: FD_CLOEXEC ) } <0 134{ 135return Err ( io:: Error :: last_os_error ()); 136} 137} 138Ok (()) 139} 140}