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