1mod file_system;
61mod io;
62mod process;
63mod signal;
64
65pub use self::file_system::*;
66pub use self::io::*;
67pub use self::process::*;
68pub use self::signal::*;
69use super::AT_FDCWD;
70use super::CaughtSignals;
71use super::Chdir;
72use super::Clock;
73use super::Close;
74use super::CpuTimes;
75use super::Dir;
76use super::Disposition;
77use super::Dup;
78use super::Errno;
79use super::Exec;
80use super::Exit;
81use super::Fcntl;
82use super::FdFlag;
83use super::Fork;
84use super::Fstat;
85use super::GetCwd;
86use super::GetPid;
87use super::GetPw;
88use super::GetRlimit;
89use super::GetSigaction;
90use super::GetUid;
91use super::Gid;
92use super::IsExecutableFile;
93use super::Isatty;
94use super::OfdAccess;
95use super::Open;
96use super::OpenFlag;
97use super::Pipe;
98use super::Read;
99use super::Result;
100use super::Seek;
101use super::Select;
102use super::SendSignal;
103use super::SetPgid;
104use super::SetRlimit;
105use super::ShellPath;
106use super::Sigaction;
107use super::Sigmask;
108use super::SigmaskOp;
109use super::Signals;
110use super::Stat;
111use super::Sysconf;
112use super::TcGetPgrp;
113use super::TcSetPgrp;
114use super::Times;
115use super::Uid;
116use super::Umask;
117use super::Wait;
118use super::Write;
119use super::resource::INFINITY;
120use super::resource::LimitPair;
121use super::resource::Resource;
122#[cfg(doc)]
123use crate::System;
124use crate::io::Fd;
125use crate::job::Pid;
126use crate::job::ProcessState;
127use crate::path::Path;
128use crate::path::PathBuf;
129use crate::semantics::ExitStatus;
130use crate::str::UnixStr;
131use crate::str::UnixString;
132use crate::system::ChildProcessStarter;
133use enumset::EnumSet;
134use std::borrow::Cow;
135use std::cell::Cell;
136use std::cell::Ref;
137use std::cell::RefCell;
138use std::cell::RefMut;
139use std::collections::BTreeMap;
140use std::collections::HashMap;
141use std::collections::VecDeque;
142use std::convert::Infallible;
143use std::convert::TryInto;
144use std::ffi::CStr;
145use std::ffi::CString;
146use std::ffi::c_int;
147use std::fmt::Debug;
148use std::future::pending;
149use std::future::poll_fn;
150use std::future::ready;
151use std::io::SeekFrom;
152use std::ops::DerefMut as _;
153use std::ops::RangeInclusive;
154use std::pin::Pin;
155use std::rc::Rc;
156use std::task::Context;
157use std::task::Poll;
158use std::task::Waker;
159use std::time::Duration;
160use std::time::Instant;
161
162#[derive(Clone, Debug)]
177pub struct VirtualSystem {
178 pub state: Rc<RefCell<SystemState>>,
180
181 pub process_id: Pid,
183}
184
185impl VirtualSystem {
186 pub fn new() -> VirtualSystem {
199 let mut state = SystemState::default();
200 let mut process = Process::with_parent_and_group(Pid(1), Pid(1));
201
202 let mut set_std_fd = |path, fd| {
203 let file = Rc::new(RefCell::new(Inode::new([])));
204 state.file_system.save(path, Rc::clone(&file)).unwrap();
205 let body = FdBody {
206 open_file_description: Rc::new(RefCell::new(OpenFileDescription {
207 file,
208 offset: 0,
209 is_readable: true,
210 is_writable: true,
211 is_appending: true,
212 })),
213 flags: EnumSet::empty(),
214 };
215 process.set_fd(fd, body).unwrap();
216 };
217 set_std_fd("/dev/stdin", Fd::STDIN);
218 set_std_fd("/dev/stdout", Fd::STDOUT);
219 set_std_fd("/dev/stderr", Fd::STDERR);
220
221 state
222 .file_system
223 .save(
224 "/tmp",
225 Rc::new(RefCell::new(Inode {
226 body: FileBody::Directory {
227 files: Default::default(),
228 },
229 permissions: Mode::ALL_9,
230 })),
231 )
232 .unwrap();
233
234 let process_id = Pid(2);
235 state.processes.insert(process_id, process);
236
237 let state = Rc::new(RefCell::new(state));
238 VirtualSystem { state, process_id }
239 }
240
241 pub fn current_process(&self) -> Ref<'_, Process> {
248 Ref::map(self.state.borrow(), |state| {
249 &state.processes[&self.process_id]
250 })
251 }
252
253 pub fn current_process_mut(&self) -> RefMut<'_, Process> {
260 RefMut::map(self.state.borrow_mut(), |state| {
261 state.processes.get_mut(&self.process_id).unwrap()
262 })
263 }
264
265 pub fn with_open_file_description<F, R>(&self, fd: Fd, f: F) -> Result<R>
269 where
270 F: FnOnce(&OpenFileDescription) -> Result<R>,
271 {
272 let process = self.current_process();
273 let body = process.get_fd(fd).ok_or(Errno::EBADF)?;
274 let ofd = body.open_file_description.borrow();
275 f(&ofd)
276 }
277
278 pub fn with_open_file_description_mut<F, R>(&self, fd: Fd, f: F) -> Result<R>
282 where
283 F: FnOnce(&mut OpenFileDescription) -> Result<R>,
284 {
285 let mut process = self.current_process_mut();
286 let body = process.get_fd_mut(fd).ok_or(Errno::EBADF)?;
287 let mut ofd = body.open_file_description.borrow_mut();
288 f(&mut ofd)
289 }
290
291 fn resolve_relative_path<'a>(&self, path: &'a Path) -> Cow<'a, Path> {
292 if path.is_absolute() {
293 Cow::Borrowed(path)
294 } else {
295 Cow::Owned(self.current_process().cwd.join(path))
296 }
297 }
298
299 fn resolve_existing_file(
300 &self,
301 _dir_fd: Fd,
302 path: &Path,
303 follow_symlinks: bool,
304 ) -> Result<Rc<RefCell<Inode>>> {
305 const _POSIX_SYMLOOP_MAX: i32 = 8;
308
309 let mut path = Cow::Borrowed(path);
310 for _count in 0.._POSIX_SYMLOOP_MAX {
311 let resolved_path = self.resolve_relative_path(&path);
312 let inode = self.state.borrow().file_system.get(&resolved_path)?;
313 if !follow_symlinks {
314 return Ok(inode);
315 }
316
317 let inode_ref = inode.borrow();
318 if let FileBody::Symlink { target } = &inode_ref.body {
319 let mut new_path = resolved_path.into_owned();
320 new_path.pop();
321 new_path.push(target);
322 path = Cow::Owned(new_path);
323 } else {
324 drop(inode_ref);
325 return Ok(inode);
326 }
327 }
328
329 Err(Errno::ELOOP)
330 }
331
332 async fn block_until_running(&self) {
334 let waker = Rc::new(Cell::new(None));
335
336 poll_fn(|cx| {
337 let mut state = self.state.borrow_mut();
338 let Some(process) = state.processes.get_mut(&self.process_id) else {
339 return Poll::Ready(());
340 };
341
342 match process.state {
343 ProcessState::Running => Poll::Ready(()),
344 ProcessState::Halted(result) => {
345 if result.is_stopped() {
346 waker.set(Some(cx.waker().clone()));
347 process.wake_on_resumption(Rc::downgrade(&waker));
348 }
349 Poll::Pending
350 }
351 }
352 })
353 .await
354 }
355}
356
357impl Default for VirtualSystem {
358 fn default() -> Self {
359 VirtualSystem::new()
360 }
361}
362
363impl Fstat for VirtualSystem {
364 fn fstat(&self, fd: Fd) -> Result<Stat> {
365 self.with_open_file_description(fd, |ofd| Ok(ofd.file.borrow().stat()))
366 }
367
368 fn fstatat(&self, dir_fd: Fd, path: &CStr, follow_symlinks: bool) -> Result<Stat> {
369 let path = Path::new(UnixStr::from_bytes(path.to_bytes()));
370 let inode = self.resolve_existing_file(dir_fd, path, follow_symlinks)?;
371 Ok(inode.borrow().stat())
372 }
373}
374
375impl IsExecutableFile for VirtualSystem {
376 fn is_executable_file(&self, path: &CStr) -> bool {
381 let path = Path::new(UnixStr::from_bytes(path.to_bytes()));
382 self.resolve_existing_file(AT_FDCWD, path, true)
383 .is_ok_and(|inode| inode.borrow().permissions.intersects(Mode::ALL_EXEC))
384 }
385}
386
387impl Pipe for VirtualSystem {
388 fn pipe(&self) -> Result<(Fd, Fd)> {
389 let file = Rc::new(RefCell::new(Inode {
390 body: FileBody::Fifo {
391 content: VecDeque::new(),
392 readers: 1,
393 writers: 1,
394 },
395 permissions: Mode::default(),
396 }));
397 let reader = OpenFileDescription {
398 file: Rc::clone(&file),
399 offset: 0,
400 is_readable: true,
401 is_writable: false,
402 is_appending: false,
403 };
404 let writer = OpenFileDescription {
405 file: Rc::clone(&file),
406 offset: 0,
407 is_readable: false,
408 is_writable: true,
409 is_appending: false,
410 };
411
412 let reader = FdBody {
413 open_file_description: Rc::new(RefCell::new(reader)),
414 flags: EnumSet::empty(),
415 };
416 let writer = FdBody {
417 open_file_description: Rc::new(RefCell::new(writer)),
418 flags: EnumSet::empty(),
419 };
420
421 let mut process = self.current_process_mut();
422 let reader = process.open_fd(reader).map_err(|_| Errno::EMFILE)?;
423 let writer = process.open_fd(writer).map_err(|_| {
424 process.close_fd(reader);
425 Errno::EMFILE
426 })?;
427 Ok((reader, writer))
428 }
429}
430
431impl Dup for VirtualSystem {
432 fn dup(&self, from: Fd, to_min: Fd, flags: EnumSet<FdFlag>) -> Result<Fd> {
433 let mut process = self.current_process_mut();
434 let mut body = process.fds.get(&from).ok_or(Errno::EBADF)?.clone();
435 body.flags = flags;
436 process.open_fd_ge(to_min, body).map_err(|_| Errno::EMFILE)
437 }
438
439 fn dup2(&self, from: Fd, to: Fd) -> Result<Fd> {
440 let mut process = self.current_process_mut();
441 let mut body = process.fds.get(&from).ok_or(Errno::EBADF)?.clone();
442 body.flags = EnumSet::empty();
443 process.set_fd(to, body).map_err(|_| Errno::EBADF)?;
444 Ok(to)
445 }
446}
447
448impl Open for VirtualSystem {
449 fn open(
450 &self,
451 path: &CStr,
452 access: OfdAccess,
453 flags: EnumSet<OpenFlag>,
454 mode: Mode,
455 ) -> Result<Fd> {
456 let path = self.resolve_relative_path(Path::new(UnixStr::from_bytes(path.to_bytes())));
457 let umask = self.current_process().umask;
458
459 let mut state = self.state.borrow_mut();
460 let file = match state.file_system.get(&path) {
461 Ok(inode) => {
462 if flags.contains(OpenFlag::Exclusive) {
463 return Err(Errno::EEXIST);
464 }
465 if flags.contains(OpenFlag::Directory)
466 && !matches!(inode.borrow().body, FileBody::Directory { .. })
467 {
468 return Err(Errno::ENOTDIR);
469 }
470 if flags.contains(OpenFlag::Truncate) {
471 if let FileBody::Regular { content, .. } = &mut inode.borrow_mut().body {
472 content.clear();
473 };
474 }
475 inode
476 }
477 Err(Errno::ENOENT) if flags.contains(OpenFlag::Create) => {
478 let mut inode = Inode::new([]);
479 inode.permissions = mode.difference(umask);
480 let inode = Rc::new(RefCell::new(inode));
481 state.file_system.save(&path, Rc::clone(&inode))?;
482 inode
483 }
484 Err(errno) => return Err(errno),
485 };
486
487 let (is_readable, is_writable) = match access {
488 OfdAccess::ReadOnly => (true, false),
489 OfdAccess::WriteOnly => (false, true),
490 OfdAccess::ReadWrite => (true, true),
491 OfdAccess::Exec | OfdAccess::Search => (false, false),
492 };
493
494 if let FileBody::Fifo {
495 readers, writers, ..
496 } = &mut file.borrow_mut().body
497 {
498 if is_readable {
499 *readers += 1;
500 }
501 if is_writable {
502 *writers += 1;
503 }
504 }
505
506 let open_file_description = Rc::new(RefCell::new(OpenFileDescription {
507 file,
508 offset: 0,
509 is_readable,
510 is_writable,
511 is_appending: flags.contains(OpenFlag::Append),
512 }));
513 let body = FdBody {
514 open_file_description,
515 flags: if flags.contains(OpenFlag::CloseOnExec) {
516 EnumSet::only(FdFlag::CloseOnExec)
517 } else {
518 EnumSet::empty()
519 },
520 };
521 let process = state.processes.get_mut(&self.process_id).unwrap();
522 process.open_fd(body).map_err(|_| Errno::EMFILE)
523 }
524
525 fn open_tmpfile(&self, _parent_dir: &Path) -> Result<Fd> {
526 let file = Rc::new(RefCell::new(Inode::new([])));
527 let open_file_description = Rc::new(RefCell::new(OpenFileDescription {
528 file,
529 offset: 0,
530 is_readable: true,
531 is_writable: true,
532 is_appending: false,
533 }));
534 let body = FdBody {
535 open_file_description,
536 flags: EnumSet::empty(),
537 };
538 let mut state = self.state.borrow_mut();
539 let process = state.processes.get_mut(&self.process_id).unwrap();
540 process.open_fd(body).map_err(|_| Errno::EMFILE)
541 }
542
543 fn fdopendir(&self, fd: Fd) -> Result<impl Dir + use<>> {
544 self.with_open_file_description(fd, |ofd| {
545 let inode = ofd.inode();
546 let dir = VirtualDir::try_from(&inode.borrow().body)?;
547 Ok(dir)
548 })
549 }
550
551 fn opendir(&self, path: &CStr) -> Result<impl Dir + use<>> {
552 let fd = self.open(
553 path,
554 OfdAccess::ReadOnly,
555 OpenFlag::Directory.into(),
556 Mode::empty(),
557 )?;
558 self.fdopendir(fd)
559 }
560}
561
562impl Close for VirtualSystem {
563 fn close(&self, fd: Fd) -> Result<()> {
564 self.current_process_mut().close_fd(fd);
565 Ok(())
566 }
567}
568
569impl Fcntl for VirtualSystem {
570 fn ofd_access(&self, fd: Fd) -> Result<OfdAccess> {
571 fn is_directory(file_body: &FileBody) -> bool {
572 matches!(file_body, FileBody::Directory { .. })
573 }
574
575 self.with_open_file_description(fd, |ofd| match (ofd.is_readable, ofd.is_writable) {
576 (true, false) => Ok(OfdAccess::ReadOnly),
577 (false, true) => Ok(OfdAccess::WriteOnly),
578 (true, true) => Ok(OfdAccess::ReadWrite),
579 (false, false) => {
580 if is_directory(&ofd.inode().borrow().body) {
581 Ok(OfdAccess::Search)
582 } else {
583 Ok(OfdAccess::Exec)
584 }
585 }
586 })
587 }
588
589 fn get_and_set_nonblocking(&self, fd: Fd, _nonblocking: bool) -> Result<bool> {
590 self.with_open_file_description(fd, |_ofd| {
591 Ok(false)
593 })
594 }
595
596 fn fcntl_getfd(&self, fd: Fd) -> Result<EnumSet<FdFlag>> {
597 let process = self.current_process();
598 let body = process.get_fd(fd).ok_or(Errno::EBADF)?;
599 Ok(body.flags)
600 }
601
602 fn fcntl_setfd(&self, fd: Fd, flags: EnumSet<FdFlag>) -> Result<()> {
603 let mut process = self.current_process_mut();
604 let body = process.get_fd_mut(fd).ok_or(Errno::EBADF)?;
605 body.flags = flags;
606 Ok(())
607 }
608}
609
610impl Read for VirtualSystem {
611 fn read(&self, fd: Fd, buffer: &mut [u8]) -> Result<usize> {
612 self.with_open_file_description_mut(fd, |ofd| ofd.read(buffer))
613 }
614}
615
616impl Write for VirtualSystem {
617 fn write(&self, fd: Fd, buffer: &[u8]) -> Result<usize> {
618 self.with_open_file_description_mut(fd, |ofd| ofd.write(buffer))
619 }
620}
621
622impl Seek for VirtualSystem {
623 fn lseek(&self, fd: Fd, position: SeekFrom) -> Result<u64> {
624 self.with_open_file_description_mut(fd, |ofd| ofd.seek(position))
625 .and_then(|new_offset| new_offset.try_into().map_err(|_| Errno::EOVERFLOW))
626 }
627}
628
629impl Umask for VirtualSystem {
630 fn umask(&self, new_mask: Mode) -> Mode {
631 std::mem::replace(&mut self.current_process_mut().umask, new_mask)
632 }
633}
634
635impl GetCwd for VirtualSystem {
636 fn getcwd(&self) -> Result<PathBuf> {
637 Ok(self.current_process().cwd.clone())
638 }
639}
640
641impl Chdir for VirtualSystem {
642 fn chdir(&self, path: &CStr) -> Result<()> {
643 let path = Path::new(UnixStr::from_bytes(path.to_bytes()));
644 let inode = self.resolve_existing_file(AT_FDCWD, path, true)?;
645 if matches!(&inode.borrow().body, FileBody::Directory { .. }) {
646 let mut process = self.current_process_mut();
647 let new_path = process.cwd.join(path);
648 process.chdir(new_path);
649 Ok(())
650 } else {
651 Err(Errno::ENOTDIR)
652 }
653 }
654}
655
656impl Clock for VirtualSystem {
657 fn now(&self) -> Instant {
661 self.state
662 .borrow()
663 .now
664 .expect("SystemState::now not assigned")
665 }
666}
667
668impl Times for VirtualSystem {
669 fn times(&self) -> Result<CpuTimes> {
671 Ok(self.state.borrow().times)
672 }
673}
674
675impl Signals for VirtualSystem {
676 const SIGABRT: signal::Number = signal::SIGABRT;
677 const SIGALRM: signal::Number = signal::SIGALRM;
678 const SIGBUS: signal::Number = signal::SIGBUS;
679 const SIGCHLD: signal::Number = signal::SIGCHLD;
680 const SIGCLD: Option<signal::Number> = Some(signal::SIGCLD);
681 const SIGCONT: signal::Number = signal::SIGCONT;
682 const SIGEMT: Option<signal::Number> = Some(signal::SIGEMT);
683 const SIGFPE: signal::Number = signal::SIGFPE;
684 const SIGHUP: signal::Number = signal::SIGHUP;
685 const SIGILL: signal::Number = signal::SIGILL;
686 const SIGINFO: Option<signal::Number> = Some(signal::SIGINFO);
687 const SIGINT: signal::Number = signal::SIGINT;
688 const SIGIO: Option<signal::Number> = Some(signal::SIGIO);
689 const SIGIOT: signal::Number = signal::SIGIOT;
690 const SIGKILL: signal::Number = signal::SIGKILL;
691 const SIGLOST: Option<signal::Number> = Some(signal::SIGLOST);
692 const SIGPIPE: signal::Number = signal::SIGPIPE;
693 const SIGPOLL: Option<signal::Number> = Some(signal::SIGPOLL);
694 const SIGPROF: signal::Number = signal::SIGPROF;
695 const SIGPWR: Option<signal::Number> = Some(signal::SIGPWR);
696 const SIGQUIT: signal::Number = signal::SIGQUIT;
697 const SIGSEGV: signal::Number = signal::SIGSEGV;
698 const SIGSTKFLT: Option<signal::Number> = Some(signal::SIGSTKFLT);
699 const SIGSTOP: signal::Number = signal::SIGSTOP;
700 const SIGSYS: signal::Number = signal::SIGSYS;
701 const SIGTERM: signal::Number = signal::SIGTERM;
702 const SIGTHR: Option<signal::Number> = Some(signal::SIGTHR);
703 const SIGTRAP: signal::Number = signal::SIGTRAP;
704 const SIGTSTP: signal::Number = signal::SIGTSTP;
705 const SIGTTIN: signal::Number = signal::SIGTTIN;
706 const SIGTTOU: signal::Number = signal::SIGTTOU;
707 const SIGURG: signal::Number = signal::SIGURG;
708 const SIGUSR1: signal::Number = signal::SIGUSR1;
709 const SIGUSR2: signal::Number = signal::SIGUSR2;
710 const SIGVTALRM: signal::Number = signal::SIGVTALRM;
711 const SIGWINCH: signal::Number = signal::SIGWINCH;
712 const SIGXCPU: signal::Number = signal::SIGXCPU;
713 const SIGXFSZ: signal::Number = signal::SIGXFSZ;
714
715 fn sigrt_range(&self) -> Option<RangeInclusive<Number>> {
716 Some(signal::SIGRTMIN..=signal::SIGRTMAX)
717 }
718}
719
720impl GetPid for VirtualSystem {
721 fn getsid(&self, pid: Pid) -> Result<Pid> {
723 self.state
724 .borrow()
725 .processes
726 .get(&pid)
727 .map_or(Err(Errno::ESRCH), |_| Ok(Pid(2)))
728 }
729
730 fn getpid(&self) -> Pid {
731 self.process_id
732 }
733
734 fn getppid(&self) -> Pid {
735 self.current_process().ppid
736 }
737
738 fn getpgrp(&self) -> Pid {
739 self.current_process().pgid
740 }
741}
742
743impl SetPgid for VirtualSystem {
744 fn setpgid(&self, mut pid: Pid, mut pgid: Pid) -> Result<()> {
748 if pgid.0 < 0 {
749 return Err(Errno::EINVAL);
750 }
751 if pid.0 == 0 {
752 pid = self.process_id;
753 }
754 if pgid.0 == 0 {
755 pgid = pid;
756 }
757
758 let mut state = self.state.borrow_mut();
759 if pgid != pid && !state.processes.values().any(|p| p.pgid == pgid) {
760 return Err(Errno::EPERM);
761 }
762 let process = state.processes.get_mut(&pid).ok_or(Errno::ESRCH)?;
763 if pid != self.process_id && process.ppid != self.process_id {
764 return Err(Errno::ESRCH);
765 }
766 if process.last_exec.is_some() {
767 return Err(Errno::EACCES);
768 }
769
770 process.pgid = pgid;
771 Ok(())
772 }
774}
775
776impl Sigmask for VirtualSystem {
777 fn sigmask(
778 &self,
779 op: Option<(SigmaskOp, &[signal::Number])>,
780 old_mask: Option<&mut Vec<signal::Number>>,
781 ) -> Result<()> {
782 let mut state = self.state.borrow_mut();
783 let process = state
784 .processes
785 .get_mut(&self.process_id)
786 .expect("current process not found");
787
788 if let Some(old_mask) = old_mask {
789 old_mask.clear();
790 old_mask.extend(process.blocked_signals());
791 }
792
793 if let Some((op, mask)) = op {
794 let result = process.block_signals(op, mask);
795 if result.process_state_changed {
796 let parent_pid = process.ppid;
797 raise_sigchld(&mut state, parent_pid);
798 }
799 }
800
801 Ok(())
802 }
803}
804
805impl GetSigaction for VirtualSystem {
806 fn get_sigaction(&self, signal: signal::Number) -> Result<Disposition> {
807 let process = self.current_process();
808 Ok(process.disposition(signal))
809 }
810}
811
812impl Sigaction for VirtualSystem {
813 fn sigaction(&self, signal: signal::Number, disposition: Disposition) -> Result<Disposition> {
814 let mut process = self.current_process_mut();
815 Ok(process.set_disposition(signal, disposition))
816 }
817}
818
819impl CaughtSignals for VirtualSystem {
820 fn caught_signals(&self) -> Vec<signal::Number> {
821 std::mem::take(&mut self.current_process_mut().caught_signals)
822 }
823}
824
825impl SendSignal for VirtualSystem {
826 fn kill(
839 &self,
840 target: Pid,
841 signal: Option<signal::Number>,
842 ) -> impl Future<Output = Result<()>> + use<> {
843 let result = 'result: {
844 if let Some(signal) = signal {
845 if signal.as_raw() < 0 {
847 break 'result Err(Errno::EINVAL);
848 }
849 }
850
851 match target {
852 Pid::MY_PROCESS_GROUP => {
853 let target_pgid = self.current_process().pgid;
854 send_signal_to_processes(
855 &mut self.state.borrow_mut(),
856 Some(target_pgid),
857 signal,
858 )
859 }
860
861 Pid::ALL => send_signal_to_processes(&mut self.state.borrow_mut(), None, signal),
862
863 Pid(raw_pid) if raw_pid >= 0 => {
864 let mut state = self.state.borrow_mut();
865 match state.processes.get_mut(&target) {
866 Some(process) => {
867 if let Some(signal) = signal {
868 let result = process.raise_signal(signal);
869 if result.process_state_changed {
870 let parent_pid = process.ppid;
871 raise_sigchld(&mut state, parent_pid);
872 }
873 }
874 Ok(())
875 }
876 None => Err(Errno::ESRCH),
877 }
878 }
879
880 Pid(negative_pgid) => {
881 let target_pgid = Pid(-negative_pgid);
882 send_signal_to_processes(
883 &mut self.state.borrow_mut(),
884 Some(target_pgid),
885 signal,
886 )
887 }
888 }
889 };
890
891 let system = self.clone();
892 async move {
893 system.block_until_running().await;
894 result
895 }
896 }
897
898 fn raise(&self, signal: signal::Number) -> impl Future<Output = Result<()>> + use<> {
899 let target = self.process_id;
900 self.kill(target, Some(signal))
901 }
902}
903
904impl Select for VirtualSystem {
905 fn select(
914 &self,
915 readers: &mut Vec<Fd>,
916 writers: &mut Vec<Fd>,
917 timeout: Option<Duration>,
918 signal_mask: Option<&[signal::Number]>,
919 ) -> Result<c_int> {
920 let mut process = self.current_process_mut();
921
922 let fds = readers.iter().chain(writers.iter());
925 if { fds }.any(|fd| !process.fds().contains_key(fd)) {
926 return Err(Errno::EBADF);
927 }
928
929 if let Some(signal_mask) = signal_mask {
930 let save_mask = process
931 .blocked_signals()
932 .iter()
933 .copied()
934 .collect::<Vec<signal::Number>>();
935 let result_1 = process.block_signals(SigmaskOp::Set, signal_mask);
936 let result_2 = process.block_signals(SigmaskOp::Set, &save_mask);
937 assert!(!result_2.delivered);
938 if result_1.caught {
939 return Err(Errno::EINTR);
940 }
941 }
942
943 readers.retain(|fd| {
944 let ofd = process.fds()[fd].open_file_description.borrow();
946 !ofd.is_readable() || ofd.is_ready_for_reading()
947 });
948 writers.retain(|fd| {
949 let ofd = process.fds()[fd].open_file_description.borrow();
950 !ofd.is_writable() || ofd.is_ready_for_writing()
951 });
952
953 drop(process);
954
955 let count = (readers.len() + writers.len()).try_into().unwrap();
956 if count == 0 {
957 if let Some(duration) = timeout {
958 if !duration.is_zero() {
959 let mut state = self.state.borrow_mut();
960 let now = state.now.as_mut();
961 let now = now.expect("now time unspecified; cannot add timeout duration");
962 *now += duration;
963 }
964 }
965 }
966 Ok(count)
967 }
968}
969
970impl Isatty for VirtualSystem {
971 fn isatty(&self, fd: Fd) -> bool {
972 self.with_open_file_description(fd, |ofd| {
973 Ok(matches!(&ofd.file.borrow().body, FileBody::Terminal { .. }))
974 })
975 .unwrap_or(false)
976 }
977}
978
979impl TcGetPgrp for VirtualSystem {
980 fn tcgetpgrp(&self, fd: Fd) -> Result<Pid> {
985 self.with_open_file_description(fd, |_| Ok(()))?;
987
988 self.state.borrow().foreground.ok_or(Errno::ENOTTY)
989 }
990}
991
992impl TcSetPgrp for VirtualSystem {
993 fn tcsetpgrp(&self, fd: Fd, pgid: Pid) -> impl Future<Output = Result<()>> + use<> {
998 fn inner(system: &VirtualSystem, fd: Fd, pgid: Pid) -> Result<()> {
999 system.with_open_file_description(fd, |_| Ok(()))?;
1001
1002 let mut state = system.state.borrow_mut();
1004 if !state.processes.values().any(|p| p.pgid == pgid) {
1005 return Err(Errno::EPERM);
1006 }
1007
1008 state.foreground = Some(pgid);
1012 Ok(())
1013 }
1014
1015 ready(inner(self, fd, pgid))
1016 }
1017}
1018
1019impl Fork for VirtualSystem {
1020 fn new_child_process(&self) -> Result<ChildProcessStarter<Self>> {
1033 let mut state = self.state.borrow_mut();
1034 let executor = state.executor.clone().ok_or(Errno::ENOSYS)?;
1035 let process_id = state
1036 .processes
1037 .keys()
1038 .max()
1039 .map_or(Pid(2), |pid| Pid(pid.0 + 1));
1040 let parent_process = &state.processes[&self.process_id];
1041 let child_process = Process::fork_from(self.process_id, parent_process);
1042 state.processes.insert(process_id, child_process);
1043 drop(state);
1044
1045 let state = Rc::clone(&self.state);
1046 Ok(Box::new(move |parent_env, task| {
1047 let system = VirtualSystem { state, process_id };
1048 let mut child_env = parent_env.clone_with_system(system.clone());
1049
1050 {
1051 let mut process = system.current_process_mut();
1052 process.selector = Rc::downgrade(&child_env.system.0);
1053 }
1054
1055 let run_task_and_set_exit_status = Box::pin(async move {
1056 let runner = ProcessRunner {
1057 task: task(&mut child_env),
1058 system,
1059 waker: Rc::new(Cell::new(None)),
1060 };
1061 runner.await;
1062 });
1063
1064 executor
1065 .spawn(run_task_and_set_exit_status)
1066 .expect("the executor failed to start the child process task");
1067
1068 process_id
1069 }))
1070 }
1071}
1072
1073impl Wait for VirtualSystem {
1074 fn wait(&self, target: Pid) -> Result<Option<(Pid, ProcessState)>> {
1078 let parent_pid = self.process_id;
1079 let mut state = self.state.borrow_mut();
1080 if let Some((pid, process)) = state.child_to_wait_for(parent_pid, target) {
1081 if process.state_has_changed() {
1082 Ok(Some((pid, process.take_state())))
1083 } else if process.state().is_alive() {
1084 Ok(None)
1085 } else {
1086 Err(Errno::ECHILD)
1087 }
1088 } else {
1089 Err(Errno::ECHILD)
1090 }
1091 }
1092}
1093
1094impl Exec for VirtualSystem {
1095 fn execve(
1101 &self,
1102 path: &CStr,
1103 args: &[CString],
1104 envs: &[CString],
1105 ) -> impl Future<Output = Result<Infallible>> + use<> {
1106 let os_path = UnixStr::from_bytes(path.to_bytes());
1107 let mut state = self.state.borrow_mut();
1108 let fs = &state.file_system;
1109 let file = match fs.get(os_path) {
1110 Ok(file) => file,
1111 Err(e) => return ready(Err(e)),
1112 };
1113 let is_executable = matches!(
1115 &file.borrow().body,
1116 FileBody::Regular {
1117 is_native_executable: true,
1118 ..
1119 }
1120 );
1121 if is_executable {
1122 let process = state.processes.get_mut(&self.process_id).unwrap();
1124 let path = path.to_owned();
1125 let args = args.to_owned();
1126 let envs = envs.to_owned();
1127 process.last_exec = Some((path, args, envs));
1128
1129 ready(Err(Errno::ENOSYS))
1133 } else {
1134 ready(Err(Errno::ENOEXEC))
1135 }
1136 }
1137}
1138
1139impl Exit for VirtualSystem {
1140 fn exit(&self, exit_status: ExitStatus) -> impl Future<Output = Infallible> + use<> {
1141 let mut myself = self.current_process_mut();
1142 let parent_pid = myself.ppid;
1143 let exited = myself.set_state(ProcessState::exited(exit_status));
1144 drop(myself);
1145 if exited {
1146 raise_sigchld(&mut self.state.borrow_mut(), parent_pid);
1147 }
1148
1149 pending()
1150 }
1151}
1152
1153impl GetUid for VirtualSystem {
1154 fn getuid(&self) -> Uid {
1155 self.current_process().uid()
1156 }
1157
1158 fn geteuid(&self) -> Uid {
1159 self.current_process().euid()
1160 }
1161
1162 fn getgid(&self) -> Gid {
1163 self.current_process().gid()
1164 }
1165
1166 fn getegid(&self) -> Gid {
1167 self.current_process().egid()
1168 }
1169}
1170
1171impl GetPw for VirtualSystem {
1172 fn getpwnam_dir(&self, name: &CStr) -> Result<Option<PathBuf>> {
1173 let state = self.state.borrow();
1174 let name = match name.to_str() {
1175 Ok(name) => name,
1176 Err(_utf8_error) => return Ok(None),
1177 };
1178 Ok(state.home_dirs.get(name).cloned())
1179 }
1180}
1181
1182impl Sysconf for VirtualSystem {
1183 fn confstr_path(&self) -> Result<UnixString> {
1188 let path = self.state.borrow().path.clone();
1189 if path.is_empty() {
1190 Err(Errno::ENOSYS)
1191 } else {
1192 Ok(path)
1193 }
1194 }
1195}
1196
1197impl ShellPath for VirtualSystem {
1198 fn shell_path(&self) -> CString {
1202 c"/bin/sh".to_owned()
1203 }
1204}
1205
1206impl GetRlimit for VirtualSystem {
1207 fn getrlimit(&self, resource: Resource) -> Result<LimitPair> {
1208 Ok(self
1209 .current_process()
1210 .resource_limits
1211 .get(&resource)
1212 .copied()
1213 .unwrap_or(LimitPair {
1214 soft: INFINITY,
1215 hard: INFINITY,
1216 }))
1217 }
1218}
1219
1220impl SetRlimit for VirtualSystem {
1221 fn setrlimit(&self, resource: Resource, limits: LimitPair) -> Result<()> {
1222 if limits.soft_exceeds_hard() {
1223 return Err(Errno::EINVAL);
1224 }
1225
1226 let mut process = self.current_process_mut();
1227 use std::collections::hash_map::Entry::{Occupied, Vacant};
1228 match process.resource_limits.entry(resource) {
1229 Occupied(occupied) => {
1230 let occupied = occupied.into_mut();
1231 if limits.hard > occupied.hard {
1232 return Err(Errno::EPERM);
1233 }
1234 *occupied = limits;
1235 }
1236 Vacant(vacant) => {
1237 vacant.insert(limits);
1238 }
1239 }
1240 Ok(())
1241 }
1242}
1243
1244fn send_signal_to_processes(
1245 state: &mut SystemState,
1246 target_pgid: Option<Pid>,
1247 signal: Option<signal::Number>,
1248) -> Result<()> {
1249 let mut results = Vec::new();
1250
1251 if let Some(signal) = signal {
1252 for (&_pid, process) in &mut state.processes {
1253 if target_pgid.is_none_or(|target_pgid| process.pgid == target_pgid) {
1254 let result = process.raise_signal(signal);
1255 results.push((result, process.ppid));
1256 }
1257 }
1258 }
1259
1260 if results.is_empty() {
1261 Err(Errno::ESRCH)
1262 } else {
1263 for (result, ppid) in results {
1264 if result.process_state_changed {
1265 raise_sigchld(state, ppid);
1266 }
1267 }
1268 Ok(())
1269 }
1270}
1271
1272fn raise_sigchld(state: &mut SystemState, target_pid: Pid) {
1273 if let Some(target) = state.processes.get_mut(&target_pid) {
1274 let result = target.raise_signal(signal::SIGCHLD);
1275 assert!(!result.process_state_changed);
1276 }
1277}
1278
1279#[derive(Clone, Debug, Default)]
1281pub struct SystemState {
1282 pub now: Option<Instant>,
1284
1285 pub times: CpuTimes,
1287
1288 pub executor: Option<Rc<dyn Executor>>,
1293
1294 pub processes: BTreeMap<Pid, Process>,
1296
1297 pub foreground: Option<Pid>,
1303
1304 pub file_system: FileSystem,
1306
1307 pub home_dirs: HashMap<String, PathBuf>,
1312
1313 pub path: UnixString,
1315}
1316
1317impl SystemState {
1318 pub fn select_all(this: &RefCell<Self>) {
1326 let mut selectors = Vec::new();
1327 for process in this.borrow().processes.values() {
1328 if let Some(selector) = process.selector.upgrade() {
1329 selectors.push(selector);
1330 }
1331 }
1332 for selector in selectors {
1335 selector.borrow_mut().select(false).ok();
1337 }
1338 }
1339
1340 fn child_to_wait_for(&mut self, parent_pid: Pid, target: Pid) -> Option<(Pid, &mut Process)> {
1344 match target.0 {
1345 0 => todo!("wait target {}", target),
1346 -1 => {
1347 let mut result = None;
1349 for (pid, process) in &mut self.processes {
1350 if process.ppid == parent_pid {
1351 let changed = process.state_has_changed();
1352 result = Some((*pid, process));
1353 if changed {
1354 break;
1355 }
1356 }
1357 }
1358 result
1359 }
1360 raw if raw >= 0 => {
1361 let process = self.processes.get_mut(&target)?;
1362 if process.ppid == parent_pid {
1363 Some((target, process))
1364 } else {
1365 None
1366 }
1367 }
1368 _target => todo!("wait target {}", target),
1369 }
1370 }
1371}
1372
1373pub trait Executor: Debug {
1381 fn spawn(
1386 &self,
1387 task: Pin<Box<dyn Future<Output = ()>>>,
1388 ) -> std::result::Result<(), Box<dyn std::error::Error>>;
1389}
1390
1391struct ProcessRunner<'a> {
1397 task: Pin<Box<dyn Future<Output = Infallible> + 'a>>,
1398 system: VirtualSystem,
1399
1400 waker: Rc<Cell<Option<Waker>>>,
1402}
1403
1404impl Future for ProcessRunner<'_> {
1405 type Output = ();
1406
1407 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
1408 let this = self.deref_mut();
1409
1410 let process_state = this.system.current_process().state;
1411 if process_state == ProcessState::Running {
1412 let poll = this.task.as_mut().poll(cx);
1414 match poll {
1415 Poll::Pending => (),
1417 }
1418 }
1419
1420 let mut process = this.system.current_process_mut();
1421 match process.state {
1422 ProcessState::Running => Poll::Pending,
1423 ProcessState::Halted(result) => {
1424 if result.is_stopped() {
1425 this.waker.set(Some(cx.waker().clone()));
1426 process.wake_on_resumption(Rc::downgrade(&this.waker));
1427 Poll::Pending
1428 } else {
1429 Poll::Ready(())
1430 }
1431 }
1432 }
1433 }
1434}
1435
1436#[cfg(test)]
1437mod tests {
1438 use super::*;
1439 use crate::Env;
1440 use crate::job::ProcessResult;
1441 use crate::system::FileType;
1442 use assert_matches::assert_matches;
1443 use futures_executor::LocalPool;
1444 use futures_util::FutureExt as _;
1445 use std::future::pending;
1446
1447 impl Executor for futures_executor::LocalSpawner {
1448 fn spawn(
1449 &self,
1450 task: Pin<Box<dyn Future<Output = ()>>>,
1451 ) -> std::result::Result<(), Box<dyn std::error::Error>> {
1452 use futures_util::task::LocalSpawnExt;
1453 self.spawn_local(task)
1454 .map_err(|e| Box::new(e) as Box<dyn std::error::Error>)
1455 }
1456 }
1457
1458 #[test]
1459 fn fstatat_non_existent_file() {
1460 let system = VirtualSystem::new();
1461 assert_matches!(
1462 system.fstatat(Fd(0), c"/no/such/file", true),
1463 Err(Errno::ENOENT)
1464 );
1465 }
1466
1467 #[test]
1468 fn fstatat_regular_file() {
1469 let system = VirtualSystem::new();
1470 let path = "/some/file";
1471 let content = Rc::new(RefCell::new(Inode::new([1, 2, 3, 42, 100])));
1472 let mut state = system.state.borrow_mut();
1473 state.file_system.save(path, content).unwrap();
1474 drop(state);
1475
1476 let stat = system.fstatat(Fd(0), c"/some/file", true).unwrap();
1477 assert_eq!(stat.mode, Mode::default());
1478 assert_eq!(stat.r#type, FileType::Regular);
1479 assert_eq!(stat.size, 5);
1480 }
1482
1483 #[test]
1484 fn fstatat_directory() {
1485 let system = VirtualSystem::new();
1486 let path = "/some/file";
1487 let content = Rc::new(RefCell::new(Inode::new([])));
1488 let mut state = system.state.borrow_mut();
1489 state.file_system.save(path, content).unwrap();
1490 drop(state);
1491
1492 let stat = system.fstatat(Fd(0), c"/some/", true).unwrap();
1493 assert_eq!(stat.mode, Mode::from_bits_retain(0o755));
1494 assert_eq!(stat.r#type, FileType::Directory);
1495 }
1497
1498 #[test]
1499 fn fstatat_fifo() {
1500 let system = VirtualSystem::new();
1501 let path = "/some/fifo";
1502 let content = Rc::new(RefCell::new(Inode {
1503 body: FileBody::Fifo {
1504 content: [17; 42].into(),
1505 readers: 0,
1506 writers: 0,
1507 },
1508 permissions: Mode::default(),
1509 }));
1510 let mut state = system.state.borrow_mut();
1511 state.file_system.save(path, content).unwrap();
1512 drop(state);
1513
1514 let stat = system.fstatat(Fd(0), c"/some/fifo", true).unwrap();
1515 assert_eq!(stat.mode, Mode::default());
1516 assert_eq!(stat.r#type, FileType::Fifo);
1517 assert_eq!(stat.size, 42);
1518 }
1519
1520 fn system_with_symlink() -> VirtualSystem {
1521 let system = VirtualSystem::new();
1522 let mut state = system.state.borrow_mut();
1523 state
1524 .file_system
1525 .save("/some/file", Rc::new(RefCell::new(Inode::new([]))))
1526 .unwrap();
1527 state
1528 .file_system
1529 .save(
1530 "/link",
1531 Rc::new(RefCell::new(Inode {
1532 body: FileBody::Symlink {
1533 target: "some/file".into(),
1534 },
1535 permissions: Mode::default(),
1536 })),
1537 )
1538 .unwrap();
1539 drop(state);
1540 system
1541 }
1542
1543 #[test]
1544 fn fstatat_symlink_to_regular_file() {
1545 let system = system_with_symlink();
1546 let stat = system.fstatat(Fd(0), c"/link", true).unwrap();
1547 assert_eq!(stat.r#type, FileType::Regular);
1548 }
1549
1550 #[test]
1551 fn fstatat_symlink_no_follow() {
1552 let system = system_with_symlink();
1553 let stat = system.fstatat(Fd(0), c"/link", false).unwrap();
1554 assert_eq!(stat.r#type, FileType::Symlink);
1555 }
1556
1557 #[test]
1558 fn is_executable_file_non_existing_file() {
1559 let system = VirtualSystem::new();
1560 assert!(!system.is_executable_file(c"/no/such/file"));
1561 }
1562
1563 #[test]
1564 fn is_executable_file_existing_but_non_executable_file() {
1565 let system = VirtualSystem::new();
1566 let path = "/some/file";
1567 let content = Rc::new(RefCell::new(Inode::default()));
1568 let mut state = system.state.borrow_mut();
1569 state.file_system.save(path, content).unwrap();
1570 drop(state);
1571 assert!(!system.is_executable_file(c"/some/file"));
1572 }
1573
1574 #[test]
1575 fn is_executable_file_with_executable_file() {
1576 let system = VirtualSystem::new();
1577 let path = "/some/file";
1578 let mut content = Inode::default();
1579 content.permissions.set(Mode::USER_EXEC, true);
1580 let content = Rc::new(RefCell::new(content));
1581 let mut state = system.state.borrow_mut();
1582 state.file_system.save(path, content).unwrap();
1583 drop(state);
1584 assert!(system.is_executable_file(c"/some/file"));
1585 }
1586
1587 #[test]
1588 fn pipe_read_write() {
1589 let system = VirtualSystem::new();
1590 let (reader, writer) = system.pipe().unwrap();
1591 let result = system.write(writer, &[5, 42, 29]);
1592 assert_eq!(result, Ok(3));
1593
1594 let mut buffer = [1; 4];
1595 let result = system.read(reader, &mut buffer);
1596 assert_eq!(result, Ok(3));
1597 assert_eq!(buffer, [5, 42, 29, 1]);
1598
1599 let result = system.close(writer);
1600 assert_eq!(result, Ok(()));
1601
1602 let result = system.read(reader, &mut buffer);
1603 assert_eq!(result, Ok(0));
1604 }
1605
1606 #[test]
1607 fn dup_shares_open_file_description() {
1608 let system = VirtualSystem::new();
1609 let result = system.dup(Fd::STDOUT, Fd::STDERR, EnumSet::empty());
1610 assert_eq!(result, Ok(Fd(3)));
1611
1612 let process = system.current_process();
1613 let fd1 = process.fds.get(&Fd(1)).unwrap();
1614 let fd3 = process.fds.get(&Fd(3)).unwrap();
1615 assert_eq!(fd1, fd3);
1616 }
1617
1618 #[test]
1619 fn dup_can_set_cloexec() {
1620 let system = VirtualSystem::new();
1621 let result = system.dup(Fd::STDOUT, Fd::STDERR, FdFlag::CloseOnExec.into());
1622 assert_eq!(result, Ok(Fd(3)));
1623
1624 let process = system.current_process();
1625 let fd3 = process.fds.get(&Fd(3)).unwrap();
1626 assert_eq!(fd3.flags, EnumSet::only(FdFlag::CloseOnExec));
1627 }
1628
1629 #[test]
1630 fn dup2_shares_open_file_description() {
1631 let system = VirtualSystem::new();
1632 let result = system.dup2(Fd::STDOUT, Fd(5));
1633 assert_eq!(result, Ok(Fd(5)));
1634
1635 let process = system.current_process();
1636 let fd1 = process.fds.get(&Fd(1)).unwrap();
1637 let fd5 = process.fds.get(&Fd(5)).unwrap();
1638 assert_eq!(fd1, fd5);
1639 }
1640
1641 #[test]
1642 fn dup2_clears_cloexec() {
1643 let system = VirtualSystem::new();
1644 let mut process = system.current_process_mut();
1645 process.fds.get_mut(&Fd::STDOUT).unwrap().flags = FdFlag::CloseOnExec.into();
1646 drop(process);
1647
1648 let result = system.dup2(Fd::STDOUT, Fd(6));
1649 assert_eq!(result, Ok(Fd(6)));
1650
1651 let process = system.current_process();
1652 let fd6 = process.fds.get(&Fd(6)).unwrap();
1653 assert_eq!(fd6.flags, EnumSet::empty());
1654 }
1655
1656 #[test]
1657 fn open_non_existing_file_no_creation() {
1658 let system = VirtualSystem::new();
1659 let result = system.open(
1660 c"/no/such/file",
1661 OfdAccess::ReadOnly,
1662 EnumSet::empty(),
1663 Mode::empty(),
1664 );
1665 assert_eq!(result, Err(Errno::ENOENT));
1666 }
1667
1668 #[test]
1669 fn open_creating_non_existing_file() {
1670 let system = VirtualSystem::new();
1671 let result = system.open(
1672 c"new_file",
1673 OfdAccess::WriteOnly,
1674 OpenFlag::Create.into(),
1675 Mode::empty(),
1676 );
1677 assert_eq!(result, Ok(Fd(3)));
1678
1679 system.write(Fd(3), &[42, 123]).unwrap();
1680 let file = system.state.borrow().file_system.get("new_file").unwrap();
1681 let file = file.borrow();
1682 assert_eq!(file.permissions, Mode::empty());
1683 assert_matches!(&file.body, FileBody::Regular { content, .. } => {
1684 assert_eq!(content[..], [42, 123]);
1685 });
1686 }
1687
1688 #[test]
1689 fn open_creating_non_existing_file_umask() {
1690 let system = VirtualSystem::new();
1691 system.umask(Mode::from_bits_retain(0o125));
1692 system
1693 .open(
1694 c"file",
1695 OfdAccess::WriteOnly,
1696 OpenFlag::Create.into(),
1697 Mode::ALL_9,
1698 )
1699 .unwrap();
1700
1701 let file = system.state.borrow().file_system.get("file").unwrap();
1702 let file = file.borrow();
1703 assert_eq!(file.permissions, Mode::from_bits_retain(0o652));
1704 }
1705
1706 #[test]
1707 fn open_existing_file() {
1708 let system = VirtualSystem::new();
1709 let fd = system
1710 .open(
1711 c"file",
1712 OfdAccess::WriteOnly,
1713 OpenFlag::Create.into(),
1714 Mode::empty(),
1715 )
1716 .unwrap();
1717 system.write(fd, &[75, 96, 133]).unwrap();
1718
1719 let result = system.open(
1720 c"file",
1721 OfdAccess::ReadOnly,
1722 EnumSet::empty(),
1723 Mode::empty(),
1724 );
1725 assert_eq!(result, Ok(Fd(4)));
1726
1727 let mut buffer = [0; 5];
1728 let count = system.read(Fd(4), &mut buffer).unwrap();
1729 assert_eq!(count, 3);
1730 assert_eq!(buffer, [75, 96, 133, 0, 0]);
1731 let count = system.read(Fd(4), &mut buffer).unwrap();
1732 assert_eq!(count, 0);
1733 }
1734
1735 #[test]
1736 fn open_existing_file_excl() {
1737 let system = VirtualSystem::new();
1738 let first = system.open(
1739 c"my_file",
1740 OfdAccess::WriteOnly,
1741 OpenFlag::Create | OpenFlag::Exclusive,
1742 Mode::empty(),
1743 );
1744 assert_eq!(first, Ok(Fd(3)));
1745
1746 let second = system.open(
1747 c"my_file",
1748 OfdAccess::WriteOnly,
1749 OpenFlag::Create | OpenFlag::Exclusive,
1750 Mode::empty(),
1751 );
1752 assert_eq!(second, Err(Errno::EEXIST));
1753 }
1754
1755 #[test]
1756 fn open_truncating() {
1757 let system = VirtualSystem::new();
1758 let fd = system
1759 .open(
1760 c"file",
1761 OfdAccess::WriteOnly,
1762 OpenFlag::Create.into(),
1763 Mode::ALL_9,
1764 )
1765 .unwrap();
1766 system.write(fd, &[1, 2, 3]).unwrap();
1767
1768 let result = system.open(
1769 c"file",
1770 OfdAccess::WriteOnly,
1771 OpenFlag::Truncate.into(),
1772 Mode::empty(),
1773 );
1774 assert_eq!(result, Ok(Fd(4)));
1775
1776 let reader = system
1777 .open(
1778 c"file",
1779 OfdAccess::ReadOnly,
1780 EnumSet::empty(),
1781 Mode::empty(),
1782 )
1783 .unwrap();
1784 let count = system.read(reader, &mut [0; 1]).unwrap();
1785 assert_eq!(count, 0);
1786 }
1787
1788 #[test]
1789 fn open_appending() {
1790 let system = VirtualSystem::new();
1791 let fd = system
1792 .open(
1793 c"file",
1794 OfdAccess::WriteOnly,
1795 OpenFlag::Create.into(),
1796 Mode::ALL_9,
1797 )
1798 .unwrap();
1799 system.write(fd, &[1, 2, 3]).unwrap();
1800
1801 let result = system.open(
1802 c"file",
1803 OfdAccess::WriteOnly,
1804 OpenFlag::Append.into(),
1805 Mode::empty(),
1806 );
1807 assert_eq!(result, Ok(Fd(4)));
1808 system.write(Fd(4), &[4, 5, 6]).unwrap();
1809
1810 let reader = system
1811 .open(
1812 c"file",
1813 OfdAccess::ReadOnly,
1814 EnumSet::empty(),
1815 Mode::empty(),
1816 )
1817 .unwrap();
1818 let mut buffer = [0; 7];
1819 let count = system.read(reader, &mut buffer).unwrap();
1820 assert_eq!(count, 6);
1821 assert_eq!(buffer, [1, 2, 3, 4, 5, 6, 0]);
1822 }
1823
1824 #[test]
1825 fn open_directory() {
1826 let system = VirtualSystem::new();
1827
1828 let _ = system.open(
1830 c"/dir/file",
1831 OfdAccess::WriteOnly,
1832 OpenFlag::Create.into(),
1833 Mode::empty(),
1834 );
1835
1836 let result = system.open(
1837 c"/dir",
1838 OfdAccess::ReadOnly,
1839 OpenFlag::Directory.into(),
1840 Mode::empty(),
1841 );
1842 assert_eq!(result, Ok(Fd(4)));
1843 }
1844
1845 #[test]
1846 fn open_non_directory_path_prefix() {
1847 let system = VirtualSystem::new();
1848
1849 let _ = system.open(
1851 c"/file",
1852 OfdAccess::WriteOnly,
1853 OpenFlag::Create.into(),
1854 Mode::empty(),
1855 );
1856
1857 let result = system.open(
1858 c"/file/file",
1859 OfdAccess::WriteOnly,
1860 OpenFlag::Create.into(),
1861 Mode::empty(),
1862 );
1863 assert_eq!(result, Err(Errno::ENOTDIR));
1864 }
1865
1866 #[test]
1867 fn open_non_directory_file() {
1868 let system = VirtualSystem::new();
1869
1870 let _ = system.open(
1872 c"/file",
1873 OfdAccess::WriteOnly,
1874 OpenFlag::Create.into(),
1875 Mode::empty(),
1876 );
1877
1878 let result = system.open(
1879 c"/file",
1880 OfdAccess::ReadOnly,
1881 OpenFlag::Directory.into(),
1882 Mode::empty(),
1883 );
1884 assert_eq!(result, Err(Errno::ENOTDIR));
1885 }
1886
1887 #[test]
1888 fn open_default_working_directory() {
1889 let system = VirtualSystem::new();
1891
1892 let writer = system.open(
1893 c"/dir/file",
1894 OfdAccess::WriteOnly,
1895 OpenFlag::Create.into(),
1896 Mode::ALL_9,
1897 );
1898 system.write(writer.unwrap(), &[1, 2, 3, 42]).unwrap();
1899
1900 let reader = system.open(
1901 c"./dir/file",
1902 OfdAccess::ReadOnly,
1903 EnumSet::empty(),
1904 Mode::empty(),
1905 );
1906 let mut buffer = [0; 10];
1907 let count = system.read(reader.unwrap(), &mut buffer).unwrap();
1908 assert_eq!(count, 4);
1909 assert_eq!(buffer[0..4], [1, 2, 3, 42]);
1910 }
1911
1912 #[test]
1913 fn open_tmpfile() {
1914 let system = VirtualSystem::new();
1915 let fd = system.open_tmpfile(Path::new("")).unwrap();
1916 system.write(fd, &[42, 17, 75]).unwrap();
1917 system.lseek(fd, SeekFrom::Start(0)).unwrap();
1918 let mut buffer = [0; 4];
1919 let count = system.read(fd, &mut buffer).unwrap();
1920 assert_eq!(count, 3);
1921 assert_eq!(buffer[..3], [42, 17, 75]);
1922 }
1923
1924 #[test]
1925 fn close() {
1926 let system = VirtualSystem::new();
1927
1928 let result = system.close(Fd::STDERR);
1929 assert_eq!(result, Ok(()));
1930 assert_eq!(system.current_process().fds.get(&Fd::STDERR), None);
1931
1932 let result = system.close(Fd::STDERR);
1933 assert_eq!(result, Ok(()));
1934 }
1935
1936 #[test]
1937 fn fcntl_getfd_and_setfd() {
1938 let system = VirtualSystem::new();
1939
1940 let flags = system.fcntl_getfd(Fd::STDIN).unwrap();
1941 assert_eq!(flags, EnumSet::empty());
1942
1943 system
1944 .fcntl_setfd(Fd::STDIN, FdFlag::CloseOnExec.into())
1945 .unwrap();
1946
1947 let flags = system.fcntl_getfd(Fd::STDIN).unwrap();
1948 assert_eq!(flags, EnumSet::only(FdFlag::CloseOnExec));
1949
1950 let flags = system.fcntl_getfd(Fd::STDOUT).unwrap();
1951 assert_eq!(flags, EnumSet::empty());
1952
1953 system.fcntl_setfd(Fd::STDIN, EnumSet::empty()).unwrap();
1954
1955 let flags = system.fcntl_getfd(Fd::STDIN).unwrap();
1956 assert_eq!(flags, EnumSet::empty());
1957 }
1958
1959 #[test]
1960 fn opendir_default_working_directory() {
1961 let system = VirtualSystem::new();
1963
1964 let _ = system.open(
1965 c"/dir/file",
1966 OfdAccess::WriteOnly,
1967 OpenFlag::Create.into(),
1968 Mode::ALL_9,
1969 );
1970
1971 let mut dir = system.opendir(c"./dir").unwrap();
1972 let mut files = Vec::new();
1973 while let Some(entry) = dir.next().unwrap() {
1974 files.push(entry.name.to_unix_string());
1975 }
1976 files.sort_unstable();
1977 assert_eq!(
1978 files[..],
1979 [
1980 UnixString::from("."),
1981 UnixString::from(".."),
1982 UnixString::from("file")
1983 ]
1984 );
1985 }
1986
1987 #[test]
1990 fn kill_process() {
1991 let system = VirtualSystem::new();
1992 system
1993 .kill(system.process_id, None)
1994 .now_or_never()
1995 .unwrap()
1996 .unwrap();
1997 assert_eq!(system.current_process().state(), ProcessState::Running);
1998
1999 let result = system.kill(system.process_id, Some(SIGINT)).now_or_never();
2000 assert_eq!(result, None);
2002 assert_eq!(
2003 system.current_process().state(),
2004 ProcessState::Halted(ProcessResult::Signaled {
2005 signal: SIGINT,
2006 core_dump: false
2007 })
2008 );
2009
2010 let system = VirtualSystem::new();
2011 let state = system.state.borrow();
2012 let max_pid = *state.processes.keys().max().unwrap();
2013 drop(state);
2014 let e = system
2015 .kill(Pid(max_pid.0 + 1), Some(SIGINT))
2016 .now_or_never()
2017 .unwrap()
2018 .unwrap_err();
2019 assert_eq!(e, Errno::ESRCH);
2020 }
2021
2022 #[test]
2023 fn kill_all_processes() {
2024 let system = VirtualSystem::new();
2025 let pgid = system.current_process().pgid;
2026 let mut state = system.state.borrow_mut();
2027 state.processes.insert(
2028 Pid(10),
2029 Process::with_parent_and_group(system.process_id, pgid),
2030 );
2031 state.processes.insert(
2032 Pid(11),
2033 Process::with_parent_and_group(system.process_id, pgid),
2034 );
2035 state
2036 .processes
2037 .insert(Pid(21), Process::with_parent_and_group(Pid(10), Pid(21)));
2038 drop(state);
2039
2040 let result = system.kill(Pid::ALL, Some(SIGTERM)).now_or_never();
2041 assert_eq!(result, None);
2043 let state = system.state.borrow();
2044 for process in state.processes.values() {
2045 assert_eq!(
2046 process.state,
2047 ProcessState::Halted(ProcessResult::Signaled {
2048 signal: SIGTERM,
2049 core_dump: false
2050 })
2051 );
2052 }
2053 }
2054
2055 #[test]
2056 fn kill_processes_in_same_group() {
2057 let system = VirtualSystem::new();
2058 let pgid = system.current_process().pgid;
2059 let mut state = system.state.borrow_mut();
2060 state.processes.insert(
2061 Pid(10),
2062 Process::with_parent_and_group(system.process_id, pgid),
2063 );
2064 state.processes.insert(
2065 Pid(11),
2066 Process::with_parent_and_group(system.process_id, pgid),
2067 );
2068 state
2069 .processes
2070 .insert(Pid(21), Process::with_parent_and_group(Pid(10), Pid(21)));
2071 drop(state);
2072
2073 let result = system
2074 .kill(Pid::MY_PROCESS_GROUP, Some(SIGQUIT))
2075 .now_or_never();
2076 assert_eq!(result, None);
2078 let state = system.state.borrow();
2079 assert_eq!(
2080 state.processes[&system.process_id].state,
2081 ProcessState::Halted(ProcessResult::Signaled {
2082 signal: SIGQUIT,
2083 core_dump: true
2084 })
2085 );
2086 assert_eq!(
2087 state.processes[&Pid(10)].state,
2088 ProcessState::Halted(ProcessResult::Signaled {
2089 signal: SIGQUIT,
2090 core_dump: true
2091 })
2092 );
2093 assert_eq!(
2094 state.processes[&Pid(11)].state,
2095 ProcessState::Halted(ProcessResult::Signaled {
2096 signal: SIGQUIT,
2097 core_dump: true
2098 })
2099 );
2100 assert_eq!(state.processes[&Pid(21)].state, ProcessState::Running);
2101 }
2102
2103 #[test]
2104 fn kill_process_group() {
2105 let system = VirtualSystem::new();
2106 let pgid = system.current_process().pgid;
2107 let mut state = system.state.borrow_mut();
2108 state.processes.insert(
2109 Pid(10),
2110 Process::with_parent_and_group(system.process_id, pgid),
2111 );
2112 state.processes.insert(
2113 Pid(11),
2114 Process::with_parent_and_group(system.process_id, Pid(21)),
2115 );
2116 state
2117 .processes
2118 .insert(Pid(21), Process::with_parent_and_group(Pid(10), Pid(21)));
2119 drop(state);
2120
2121 system
2122 .kill(Pid(-21), Some(SIGHUP))
2123 .now_or_never()
2124 .unwrap()
2125 .unwrap();
2126 let state = system.state.borrow();
2127 assert_eq!(
2128 state.processes[&system.process_id].state,
2129 ProcessState::Running
2130 );
2131 assert_eq!(state.processes[&Pid(10)].state, ProcessState::Running);
2132 assert_eq!(
2133 state.processes[&Pid(11)].state,
2134 ProcessState::Halted(ProcessResult::Signaled {
2135 signal: SIGHUP,
2136 core_dump: false
2137 })
2138 );
2139 assert_eq!(
2140 state.processes[&Pid(21)].state,
2141 ProcessState::Halted(ProcessResult::Signaled {
2142 signal: SIGHUP,
2143 core_dump: false
2144 })
2145 );
2146 }
2147
2148 #[test]
2149 fn kill_returns_success_even_if_process_state_did_not_change() {
2150 let system = VirtualSystem::new();
2151 let pgid = system.current_process().pgid;
2152 let mut state = system.state.borrow_mut();
2153 state.processes.insert(
2154 Pid(10),
2155 Process::with_parent_and_group(system.process_id, pgid),
2156 );
2157 drop(state);
2158
2159 system
2160 .kill(-pgid, Some(SIGCONT))
2161 .now_or_never()
2162 .unwrap()
2163 .unwrap();
2164 let state = system.state.borrow();
2165 assert_eq!(state.processes[&Pid(10)].state, ProcessState::Running);
2166 }
2167
2168 #[test]
2169 fn select_regular_file_is_always_ready() {
2170 let system = VirtualSystem::new();
2171 let mut readers = vec![Fd::STDIN];
2172 let mut writers = vec![Fd::STDOUT, Fd::STDERR];
2173
2174 let result = system.select(&mut readers, &mut writers, None, None);
2175 assert_eq!(result, Ok(3));
2176 assert_eq!(readers, [Fd::STDIN]);
2177 assert_eq!(writers, [Fd::STDOUT, Fd::STDERR]);
2178 }
2179
2180 #[test]
2181 fn select_pipe_reader_is_ready_if_writer_is_closed() {
2182 let system = VirtualSystem::new();
2183 let (reader, writer) = system.pipe().unwrap();
2184 system.close(writer).unwrap();
2185 let mut readers = vec![reader];
2186 let mut writers = vec![];
2187
2188 let result = system.select(&mut readers, &mut writers, None, None);
2189 assert_eq!(result, Ok(1));
2190 assert_eq!(readers, [reader]);
2191 assert_eq!(writers, []);
2192 }
2193
2194 #[test]
2195 fn select_pipe_reader_is_ready_if_something_has_been_written() {
2196 let system = VirtualSystem::new();
2197 let (reader, writer) = system.pipe().unwrap();
2198 system.write(writer, &[0]).unwrap();
2199 let mut readers = vec![reader];
2200 let mut writers = vec![];
2201
2202 let result = system.select(&mut readers, &mut writers, None, None);
2203 assert_eq!(result, Ok(1));
2204 assert_eq!(readers, [reader]);
2205 assert_eq!(writers, []);
2206 }
2207
2208 #[test]
2209 fn select_pipe_reader_is_not_ready_if_writer_has_written_nothing() {
2210 let system = VirtualSystem::new();
2211 let (reader, _writer) = system.pipe().unwrap();
2212 let mut readers = vec![reader];
2213 let mut writers = vec![];
2214
2215 let result = system.select(&mut readers, &mut writers, None, None);
2216 assert_eq!(result, Ok(0));
2217 assert_eq!(readers, []);
2218 assert_eq!(writers, []);
2219 }
2220
2221 #[test]
2222 fn select_pipe_writer_is_ready_if_pipe_is_not_full() {
2223 let system = VirtualSystem::new();
2224 let (_reader, writer) = system.pipe().unwrap();
2225 let mut readers = vec![];
2226 let mut writers = vec![writer];
2227
2228 let result = system.select(&mut readers, &mut writers, None, None);
2229 assert_eq!(result, Ok(1));
2230 assert_eq!(readers, []);
2231 assert_eq!(writers, [writer]);
2232 }
2233
2234 #[test]
2235 fn select_on_unreadable_fd() {
2236 let system = VirtualSystem::new();
2237 let (_reader, writer) = system.pipe().unwrap();
2238 let mut fds = vec![writer];
2239 let result = system.select(&mut fds, &mut vec![], None, None);
2240 assert_eq!(result, Ok(1));
2241 assert_eq!(fds, [writer]);
2242 }
2243
2244 #[test]
2245 fn select_on_unwritable_fd() {
2246 let system = VirtualSystem::new();
2247 let (reader, _writer) = system.pipe().unwrap();
2248 let mut fds = vec![reader];
2249 let result = system.select(&mut vec![], &mut fds, None, None);
2250 assert_eq!(result, Ok(1));
2251 assert_eq!(fds, [reader]);
2252 }
2253
2254 #[test]
2255 fn select_on_closed_fd() {
2256 let system = VirtualSystem::new();
2257 let result = system.select(&mut vec![Fd(17)], &mut vec![], None, None);
2258 assert_eq!(result, Err(Errno::EBADF));
2259
2260 let result = system.select(&mut vec![], &mut vec![Fd(17)], None, None);
2261 assert_eq!(result, Err(Errno::EBADF));
2262 }
2263
2264 fn system_for_catching_sigchld() -> VirtualSystem {
2265 let system = VirtualSystem::new();
2266 system
2267 .sigmask(Some((SigmaskOp::Add, &[SIGCHLD])), None)
2268 .unwrap();
2269 system.sigaction(SIGCHLD, Disposition::Catch).unwrap();
2270 system
2271 }
2272
2273 #[test]
2274 fn select_on_non_pending_signal() {
2275 let system = system_for_catching_sigchld();
2276 let result = system.select(&mut vec![], &mut vec![], None, Some(&[]));
2277 assert_eq!(result, Ok(0));
2278 assert_eq!(system.caught_signals(), []);
2279 }
2280
2281 #[test]
2282 fn select_on_pending_signal() {
2283 let system = system_for_catching_sigchld();
2284 let _ = system.current_process_mut().raise_signal(SIGCHLD);
2285 let result = system.select(&mut vec![], &mut vec![], None, Some(&[]));
2286 assert_eq!(result, Err(Errno::EINTR));
2287 assert_eq!(system.caught_signals(), [SIGCHLD]);
2288 }
2289
2290 #[test]
2291 fn select_timeout() {
2292 let system = VirtualSystem::new();
2293 let now = Instant::now();
2294 system.state.borrow_mut().now = Some(now);
2295
2296 let (reader, _writer) = system.pipe().unwrap();
2297 let mut readers = vec![reader];
2298 let mut writers = vec![];
2299 let timeout = Duration::new(42, 195);
2300
2301 let result = system.select(&mut readers, &mut writers, Some(timeout), None);
2302 assert_eq!(result, Ok(0));
2303 assert_eq!(readers, []);
2304 assert_eq!(writers, []);
2305 assert_eq!(
2306 system.state.borrow().now,
2307 Some(now + Duration::new(42, 195))
2308 );
2309 }
2310
2311 fn virtual_system_with_executor() -> (VirtualSystem, LocalPool) {
2312 let system = VirtualSystem::new();
2313 let executor = LocalPool::new();
2314 system.state.borrow_mut().executor = Some(Rc::new(executor.spawner()));
2315 (system, executor)
2316 }
2317
2318 #[test]
2319 fn setpgid_creating_new_group_from_parent() {
2320 let (system, _executor) = virtual_system_with_executor();
2321 let state = Rc::clone(&system.state);
2322 let mut env = Env::with_system(system);
2323 let child = env.system.new_child_process().unwrap();
2324 let pid = child(&mut env, Box::new(|_env| Box::pin(pending())));
2325
2326 let result = env.system.setpgid(pid, pid);
2327 assert_eq!(result, Ok(()));
2328
2329 let pgid = state.borrow().processes[&pid].pgid();
2330 assert_eq!(pgid, pid);
2331 }
2332
2333 #[test]
2334 fn setpgid_creating_new_group_from_child() {
2335 let (system, mut executor) = virtual_system_with_executor();
2336 let state = Rc::clone(&system.state);
2337 let mut env = Env::with_system(system);
2338 let child = env.system.new_child_process().unwrap();
2339 let pid = child(
2340 &mut env,
2341 Box::new(|child_env| {
2342 Box::pin(async move {
2343 let result = child_env.system.setpgid(Pid(0), Pid(0));
2344 assert_eq!(result, Ok(()));
2345 child_env.system.exit(child_env.exit_status).await
2346 })
2347 }),
2348 );
2349 executor.run_until_stalled();
2350
2351 let pgid = state.borrow().processes[&pid].pgid();
2352 assert_eq!(pgid, pid);
2353 }
2354
2355 #[test]
2356 fn setpgid_extending_existing_group_from_parent() {
2357 let (system, _executor) = virtual_system_with_executor();
2358 let state = Rc::clone(&system.state);
2359 let mut env = Env::with_system(system);
2360 let child_1 = env.system.new_child_process().unwrap();
2361 let pid_1 = child_1(&mut env, Box::new(|_env| Box::pin(pending())));
2362 env.system.setpgid(pid_1, pid_1).unwrap();
2363 let child_2 = env.system.new_child_process().unwrap();
2364 let pid_2 = child_2(&mut env, Box::new(|_env| Box::pin(pending())));
2365
2366 let result = env.system.setpgid(pid_2, pid_1);
2367 assert_eq!(result, Ok(()));
2368
2369 let pgid = state.borrow().processes[&pid_2].pgid();
2370 assert_eq!(pgid, pid_1);
2371 }
2372
2373 #[test]
2374 fn setpgid_with_nonexisting_pid() {
2375 let (system, _executor) = virtual_system_with_executor();
2376 let state = Rc::clone(&system.state);
2377 let mut env = Env::with_system(system);
2378 let child = env.system.new_child_process().unwrap();
2379 let pid = child(&mut env, Box::new(|_env| Box::pin(pending())));
2380
2381 let dummy_pid = Pid(123);
2382 let result = env.system.setpgid(dummy_pid, dummy_pid);
2383 assert_eq!(result, Err(Errno::ESRCH));
2384
2385 let pgid = state.borrow().processes[&pid].pgid();
2386 assert_eq!(pgid, Pid(1));
2387 }
2388
2389 #[test]
2390 fn setpgid_with_unrelated_pid() {
2391 let (system, mut executor) = virtual_system_with_executor();
2392 let parent_pid = system.process_id;
2393 let state = Rc::clone(&system.state);
2394 let mut env = Env::with_system(system);
2395 let child = env.system.new_child_process().unwrap();
2396 let _pid = child(
2397 &mut env,
2398 Box::new(move |child_env| {
2399 Box::pin(async move {
2400 let result = child_env.system.setpgid(parent_pid, Pid(0));
2401 assert_eq!(result, Err(Errno::ESRCH));
2402 child_env.system.exit(child_env.exit_status).await
2403 })
2404 }),
2405 );
2406 executor.run_until_stalled();
2407
2408 let pgid = state.borrow().processes[&parent_pid].pgid();
2409 assert_eq!(pgid, Pid(1));
2410 }
2411
2412 #[test]
2413 fn setpgid_with_execed_child() {
2414 let (system, mut executor) = virtual_system_with_executor();
2415 let path = "/some/file";
2416 let mut content = Inode::default();
2417 content.body = FileBody::Regular {
2418 content: vec![],
2419 is_native_executable: true,
2420 };
2421 content.permissions.set(Mode::USER_EXEC, true);
2422 let content = Rc::new(RefCell::new(content));
2423 let state = Rc::clone(&system.state);
2424 state.borrow_mut().file_system.save(path, content).unwrap();
2425 let mut env = Env::with_system(system);
2426 let child = env.system.new_child_process().unwrap();
2427 let pid = child(
2428 &mut env,
2429 Box::new(move |child_env| {
2430 Box::pin(async move {
2431 let path = CString::new(path).unwrap();
2432 child_env.system.execve(&path, &[], &[]).await.ok();
2433 child_env.system.exit(child_env.exit_status).await
2434 })
2435 }),
2436 );
2437 executor.run_until_stalled();
2438
2439 let result = env.system.setpgid(pid, pid);
2440 assert_eq!(result, Err(Errno::EACCES));
2441
2442 let pgid = state.borrow().processes[&pid].pgid();
2443 assert_eq!(pgid, Pid(1));
2444 }
2445
2446 #[test]
2447 fn setpgid_with_nonexisting_pgid() {
2448 let (system, mut executor) = virtual_system_with_executor();
2449 let state = Rc::clone(&system.state);
2450 let mut env = Env::with_system(system);
2451 let child_1 = env.system.new_child_process().unwrap();
2452 let pid_1 = child_1(&mut env, Box::new(|_env| Box::pin(pending())));
2453 let child_2 = env.system.new_child_process().unwrap();
2455 let pid_2 = child_2(&mut env, Box::new(|_env| Box::pin(pending())));
2456 executor.run_until_stalled();
2457
2458 let result = env.system.setpgid(pid_2, pid_1);
2459 assert_eq!(result, Err(Errno::EPERM));
2460
2461 let pgid = state.borrow().processes[&pid_2].pgid();
2462 assert_eq!(pgid, Pid(1));
2463 }
2464
2465 #[test]
2466 fn tcsetpgrp_success() {
2467 let system = VirtualSystem::new();
2468 let pid = Pid(10);
2469 let ppid = system.process_id;
2470 let pgid = Pid(9);
2471 system
2472 .state
2473 .borrow_mut()
2474 .processes
2475 .insert(pid, Process::with_parent_and_group(ppid, pgid));
2476
2477 system
2478 .tcsetpgrp(Fd::STDIN, pgid)
2479 .now_or_never()
2480 .unwrap()
2481 .unwrap();
2482
2483 let foreground = system.state.borrow().foreground;
2484 assert_eq!(foreground, Some(pgid));
2485 }
2486
2487 #[test]
2488 fn tcsetpgrp_with_invalid_fd() {
2489 let system = VirtualSystem::new();
2490 let result = system.tcsetpgrp(Fd(100), Pid(2)).now_or_never().unwrap();
2491 assert_eq!(result, Err(Errno::EBADF));
2492 }
2493
2494 #[test]
2495 fn tcsetpgrp_with_nonexisting_pgrp() {
2496 let system = VirtualSystem::new();
2497 let result = system
2498 .tcsetpgrp(Fd::STDIN, Pid(100))
2499 .now_or_never()
2500 .unwrap();
2501 assert_eq!(result, Err(Errno::EPERM));
2502 }
2503
2504 #[test]
2505 fn new_child_process_without_executor() {
2506 let system = VirtualSystem::new();
2507 let result = system.new_child_process();
2508 match result {
2509 Ok(_) => panic!("unexpected Ok value"),
2510 Err(e) => assert_eq!(e, Errno::ENOSYS),
2511 }
2512 }
2513
2514 #[test]
2515 fn new_child_process_with_executor() {
2516 let (system, _executor) = virtual_system_with_executor();
2517
2518 let result = system.new_child_process();
2519
2520 let state = system.state.borrow();
2521 assert_eq!(state.processes.len(), 2);
2522 drop(state);
2523
2524 let mut env = Env::with_system(system);
2525 let child_process = result.unwrap();
2526 let pid = child_process(
2527 &mut env,
2528 Box::new(|env| Box::pin(async move { env.system.exit(env.exit_status).await })),
2529 );
2530 assert_eq!(pid, Pid(3));
2531 }
2532
2533 #[test]
2534 fn wait_for_running_child() {
2535 let (system, _executor) = virtual_system_with_executor();
2536
2537 let child_process = system.new_child_process();
2538
2539 let mut env = Env::with_system(system);
2540 let child_process = child_process.unwrap();
2541 let pid = child_process(
2542 &mut env,
2543 Box::new(|_env| {
2544 Box::pin(async {
2545 unreachable!("child process does not progress unless executor is used")
2546 })
2547 }),
2548 );
2549
2550 let result = env.system.wait(pid);
2551 assert_eq!(result, Ok(None))
2552 }
2553
2554 #[test]
2555 fn wait_for_exited_child() {
2556 let (system, mut executor) = virtual_system_with_executor();
2557
2558 let child_process = system.new_child_process();
2559
2560 let mut env = Env::with_system(system);
2561 let child_process = child_process.unwrap();
2562 let pid = child_process(
2563 &mut env,
2564 Box::new(|env| Box::pin(async move { env.system.exit(ExitStatus(5)).await })),
2565 );
2566 executor.run_until_stalled();
2567
2568 let result = env.system.wait(pid);
2569 assert_eq!(result, Ok(Some((pid, ProcessState::exited(5)))));
2570 }
2571
2572 #[test]
2573 fn wait_for_signaled_child() {
2574 let (system, mut executor) = virtual_system_with_executor();
2575
2576 let child_process = system.new_child_process();
2577
2578 let mut env = Env::with_system(system);
2579 let child_process = child_process.unwrap();
2580 let pid = child_process(
2581 &mut env,
2582 Box::new(|env| {
2583 Box::pin(async move {
2584 let pid = env.system.getpid();
2585 let result = env.system.kill(pid, Some(SIGKILL)).await;
2586 unreachable!("kill returned {result:?}");
2587 })
2588 }),
2589 );
2590 executor.run_until_stalled();
2591
2592 let result = env.system.wait(pid);
2593 assert_eq!(
2594 result,
2595 Ok(Some((
2596 pid,
2597 ProcessState::Halted(ProcessResult::Signaled {
2598 signal: SIGKILL,
2599 core_dump: false
2600 })
2601 )))
2602 );
2603 }
2604
2605 #[test]
2606 fn wait_for_stopped_child() {
2607 let (system, mut executor) = virtual_system_with_executor();
2608
2609 let child_process = system.new_child_process();
2610
2611 let mut env = Env::with_system(system);
2612 let child_process = child_process.unwrap();
2613 let pid = child_process(
2614 &mut env,
2615 Box::new(|env| {
2616 Box::pin(async move {
2617 let pid = env.system.getpid();
2618 let result = env.system.kill(pid, Some(SIGSTOP)).await;
2619 unreachable!("kill returned {result:?}");
2620 })
2621 }),
2622 );
2623 executor.run_until_stalled();
2624
2625 let result = env.system.wait(pid);
2626 assert_eq!(result, Ok(Some((pid, ProcessState::stopped(SIGSTOP)))));
2627 }
2628
2629 #[test]
2630 fn wait_for_resumed_child() {
2631 let (system, mut executor) = virtual_system_with_executor();
2632
2633 let child_process = system.new_child_process();
2634
2635 let mut env = Env::with_system(system);
2636 let child_process = child_process.unwrap();
2637 let pid = child_process(
2638 &mut env,
2639 Box::new(|env| {
2640 Box::pin(async move {
2641 let pid = env.system.getpid();
2642 let result = env.system.kill(pid, Some(SIGSTOP)).await;
2643 assert_eq!(result, Ok(()));
2644 env.system.exit(ExitStatus(123)).await
2645 })
2646 }),
2647 );
2648 executor.run_until_stalled();
2649
2650 env.system
2651 .kill(pid, Some(SIGCONT))
2652 .now_or_never()
2653 .unwrap()
2654 .unwrap();
2655
2656 let result = env.system.wait(pid);
2657 assert_eq!(result, Ok(Some((pid, ProcessState::Running))));
2658
2659 executor.run_until_stalled();
2660
2661 let result = env.system.wait(pid);
2662 assert_eq!(result, Ok(Some((pid, ProcessState::exited(123)))));
2663 }
2664
2665 #[test]
2666 fn wait_without_child() {
2667 let system = VirtualSystem::new();
2668 let result = system.wait(Pid::ALL);
2669 assert_eq!(result, Err(Errno::ECHILD));
2670 let result = system.wait(system.process_id);
2674 assert_eq!(result, Err(Errno::ECHILD));
2675 let result = system.wait(Pid(1234));
2676 assert_eq!(result, Err(Errno::ECHILD));
2677 }
2681
2682 #[test]
2683 fn exiting_child_sends_sigchld_to_parent() {
2684 let (system, mut executor) = virtual_system_with_executor();
2685 system.sigaction(SIGCHLD, Disposition::Catch).unwrap();
2686
2687 let child_process = system.new_child_process().unwrap();
2688
2689 let mut env = Env::with_system(system);
2690 let _pid = child_process(
2691 &mut env,
2692 Box::new(|env| Box::pin(async { env.system.exit(ExitStatus(0)).await })),
2693 );
2694 executor.run_until_stalled();
2695
2696 assert_eq!(env.system.caught_signals(), [SIGCHLD]);
2697 }
2698
2699 #[test]
2700 fn execve_returns_enosys_for_executable_file() {
2701 let system = VirtualSystem::new();
2702 let path = "/some/file";
2703 let mut content = Inode::default();
2704 content.body = FileBody::Regular {
2705 content: vec![],
2706 is_native_executable: true,
2707 };
2708 content.permissions.set(Mode::USER_EXEC, true);
2709 let content = Rc::new(RefCell::new(content));
2710 let mut state = system.state.borrow_mut();
2711 state.file_system.save(path, content).unwrap();
2712 drop(state);
2713 let path = CString::new(path).unwrap();
2714 let result = system.execve(&path, &[], &[]).now_or_never().unwrap();
2715 assert_eq!(result, Err(Errno::ENOSYS));
2716 }
2717
2718 #[test]
2719 fn execve_saves_arguments() {
2720 let system = VirtualSystem::new();
2721 let path = "/some/file";
2722 let mut content = Inode::default();
2723 content.body = FileBody::Regular {
2724 content: vec![],
2725 is_native_executable: true,
2726 };
2727 content.permissions.set(Mode::USER_EXEC, true);
2728 let content = Rc::new(RefCell::new(content));
2729 let mut state = system.state.borrow_mut();
2730 state.file_system.save(path, content).unwrap();
2731 drop(state);
2732 let path = CString::new(path).unwrap();
2733 let args = [c"file".to_owned(), c"bar".to_owned()];
2734 let envs = [c"foo=FOO".to_owned(), c"baz".to_owned()];
2735 system.execve(&path, &args, &envs).now_or_never();
2736
2737 let process = system.current_process();
2738 let arguments = process.last_exec.as_ref().unwrap();
2739 assert_eq!(arguments.0, path);
2740 assert_eq!(arguments.1, args);
2741 assert_eq!(arguments.2, envs);
2742 }
2743
2744 #[test]
2745 fn execve_returns_enoexec_for_non_executable_file() {
2746 let system = VirtualSystem::new();
2747 let path = "/some/file";
2748 let mut content = Inode::default();
2749 content.permissions.set(Mode::USER_EXEC, true);
2750 let content = Rc::new(RefCell::new(content));
2751 let mut state = system.state.borrow_mut();
2752 state.file_system.save(path, content).unwrap();
2753 drop(state);
2754 let path = CString::new(path).unwrap();
2755 let result = system.execve(&path, &[], &[]).now_or_never().unwrap();
2756 assert_eq!(result, Err(Errno::ENOEXEC));
2757 }
2758
2759 #[test]
2760 fn execve_returns_enoent_on_file_not_found() {
2761 let system = VirtualSystem::new();
2762 let result = system
2763 .execve(c"/no/such/file", &[], &[])
2764 .now_or_never()
2765 .unwrap();
2766 assert_eq!(result, Err(Errno::ENOENT));
2767 }
2768
2769 #[test]
2770 fn exit_sets_current_process_state_to_exited() {
2771 let system = VirtualSystem::new();
2772 system.exit(ExitStatus(42)).now_or_never();
2773
2774 assert!(system.current_process().state_has_changed());
2775 assert_eq!(
2776 system.current_process().state(),
2777 ProcessState::exited(ExitStatus(42))
2778 );
2779 }
2780
2781 #[test]
2782 fn exit_sends_sigchld_to_parent() {
2783 let (system, mut executor) = virtual_system_with_executor();
2784 system.sigaction(SIGCHLD, Disposition::Catch).unwrap();
2785
2786 let child_process = system.new_child_process().unwrap();
2787
2788 let mut env = Env::with_system(system);
2789 let _pid = child_process(
2790 &mut env,
2791 Box::new(|env| Box::pin(async { env.system.exit(ExitStatus(123)).await })),
2792 );
2793 executor.run_until_stalled();
2794
2795 assert_eq!(env.system.caught_signals(), [SIGCHLD]);
2796 }
2797
2798 #[test]
2799 fn chdir_changes_directory() {
2800 let system = VirtualSystem::new();
2801
2802 let _ = system.open(
2804 c"/dir/file",
2805 OfdAccess::WriteOnly,
2806 OpenFlag::Create.into(),
2807 Mode::empty(),
2808 );
2809
2810 let result = system.chdir(c"/dir");
2811 assert_eq!(result, Ok(()));
2812 assert_eq!(system.current_process().cwd, Path::new("/dir"));
2813 }
2814
2815 #[test]
2816 fn chdir_fails_with_non_existing_directory() {
2817 let system = VirtualSystem::new();
2818
2819 let result = system.chdir(c"/no/such/dir");
2820 assert_eq!(result, Err(Errno::ENOENT));
2821 }
2822
2823 #[test]
2824 fn chdir_fails_with_non_directory_file() {
2825 let system = VirtualSystem::new();
2826
2827 let _ = system.open(
2829 c"/dir/file",
2830 OfdAccess::WriteOnly,
2831 OpenFlag::Create.into(),
2832 Mode::empty(),
2833 );
2834
2835 let result = system.chdir(c"/dir/file");
2836 assert_eq!(result, Err(Errno::ENOTDIR));
2837 }
2838
2839 #[test]
2840 fn getrlimit_for_unset_resource_returns_infinity() {
2841 let system = VirtualSystem::new();
2842 let result = system.getrlimit(Resource::CPU).unwrap();
2843 assert_eq!(
2844 result,
2845 LimitPair {
2846 soft: INFINITY,
2847 hard: INFINITY,
2848 },
2849 );
2850 }
2851
2852 #[test]
2853 fn setrlimit_and_getrlimit_with_finite_limits() {
2854 let system = VirtualSystem::new();
2855 system
2856 .setrlimit(
2857 Resource::CORE,
2858 LimitPair {
2859 soft: 4096,
2860 hard: 8192,
2861 },
2862 )
2863 .unwrap();
2864 system
2865 .setrlimit(Resource::CPU, LimitPair { soft: 10, hard: 30 })
2866 .unwrap();
2867
2868 let result = system.getrlimit(Resource::CORE).unwrap();
2869 assert_eq!(
2870 result,
2871 LimitPair {
2872 soft: 4096,
2873 hard: 8192,
2874 },
2875 );
2876 let result = system.getrlimit(Resource::CPU).unwrap();
2877 assert_eq!(result, LimitPair { soft: 10, hard: 30 },);
2878 }
2879
2880 #[test]
2881 fn setrlimit_rejects_soft_limit_higher_than_hard_limit() {
2882 let system = VirtualSystem::new();
2883 let result = system.setrlimit(Resource::CPU, LimitPair { soft: 2, hard: 1 });
2884 assert_eq!(result, Err(Errno::EINVAL));
2885
2886 let result = system.getrlimit(Resource::CPU).unwrap();
2888 assert_eq!(
2889 result,
2890 LimitPair {
2891 soft: INFINITY,
2892 hard: INFINITY,
2893 },
2894 );
2895 }
2896
2897 #[test]
2898 fn setrlimit_refuses_raising_hard_limit() {
2899 let system = VirtualSystem::new();
2900 system
2901 .setrlimit(Resource::CPU, LimitPair { soft: 1, hard: 1 })
2902 .unwrap();
2903 let result = system.setrlimit(Resource::CPU, LimitPair { soft: 1, hard: 2 });
2904 assert_eq!(result, Err(Errno::EPERM));
2905
2906 let result = system.getrlimit(Resource::CPU).unwrap();
2908 assert_eq!(result, LimitPair { soft: 1, hard: 1 });
2909 }
2910}