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