diff --git a/kernel/context/context.rs b/kernel/context/context.rs index a7d41d4..607653c 100644 --- a/kernel/context/context.rs +++ b/kernel/context/context.rs @@ -220,6 +220,25 @@ impl Context { } } + /// Insert a file with a specific handle number. This is used by dup2 + /// Return the file descriptor number or None if the slot was not empty, or i was invalid + pub fn insert_file(&self, i: FileHandle, file: File) -> Option { + let mut files = self.files.lock(); + if i.into() < super::CONTEXT_MAX_FILES { + while i.into() >= files.len() { + files.push(None); + } + if files[i.into()].is_none() { + files[i.into()] = Some(file); + Some(i) + } else { + None + } + } else { + None + } + } + /// Remove a file // TODO: adjust files vector to smaller size if possible pub fn remove_file(&self, i: FileHandle) -> Option { diff --git a/kernel/syscall/fs.rs b/kernel/syscall/fs.rs index 6f6a698..bd02c52 100644 --- a/kernel/syscall/fs.rs +++ b/kernel/syscall/fs.rs @@ -89,6 +89,8 @@ pub fn open(path: &[u8], flags: usize) -> Result { (context.canonicalize(path), context.euid, context.egid, context.ens) }; + //println!("open {}", unsafe { ::core::str::from_utf8_unchecked(&path_canon) }); + let mut parts = path_canon.splitn(2, |&b| b == b':'); let scheme_name_opt = parts.next(); let reference_opt = parts.next(); @@ -261,6 +263,41 @@ pub fn dup(fd: FileHandle, buf: &[u8]) -> Result { }).ok_or(Error::new(EMFILE)) } +/// Duplicate file descriptor, replacing another +pub fn dup2(fd: FileHandle, new_fd: FileHandle, buf: &[u8]) -> Result { + if fd == new_fd { + Ok(new_fd) + } else { + let _ = close(new_fd)?; + + let file = { + let contexts = context::contexts(); + let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; + let context = context_lock.read(); + let file = context.get_file(fd).ok_or(Error::new(EBADF))?; + file + }; + + let new_id = { + let scheme = { + let schemes = scheme::schemes(); + let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?; + scheme.clone() + }; + scheme.dup(file.number, buf)? + }; + + let contexts = context::contexts(); + let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; + let context = context_lock.read(); + context.insert_file(new_fd, ::context::file::File { + scheme: file.scheme, + number: new_id, + event: None, + }).ok_or(Error::new(EBADF)) + } +} + /// Register events for file pub fn fevent(fd: FileHandle, flags: usize) -> Result { let file = { diff --git a/kernel/syscall/mod.rs b/kernel/syscall/mod.rs index 69e53ec..d303007 100644 --- a/kernel/syscall/mod.rs +++ b/kernel/syscall/mod.rs @@ -53,6 +53,7 @@ pub extern fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize _ => match a { SYS_CLOSE => close(fd), SYS_DUP => dup(fd, validate_slice(c as *const u8, d)?).map(FileHandle::into), + SYS_DUP2 => dup2(fd, FileHandle::from(c), validate_slice(d as *const u8, e)?).map(FileHandle::into), SYS_FEVENT => fevent(fd, c), SYS_FUNMAP => funmap(b), _ => file_op(a, fd, c, d) @@ -103,10 +104,18 @@ pub extern fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize } let result = inner(a, b, c, d, e, f, stack); -/* + + /* if let Err(ref err) = result { - println!("{}, {}, {}, {}: {}", a, b, c, d, err); + let contexts = ::context::contexts(); + if let Some(context_lock) = contexts.current() { + let context = context_lock.read(); + print!("{}: {}: ", unsafe { ::core::str::from_utf8_unchecked(&context.name.lock()) }, context.id.into()); + } + + println!("{:X}, {:X}, {:X}, {:X}: {}", a, b, c, d, err); } -*/ + */ + Error::mux(result) } diff --git a/kernel/syscall/process.rs b/kernel/syscall/process.rs index cde11be..8ffadf5 100644 --- a/kernel/syscall/process.rs +++ b/kernel/syscall/process.rs @@ -26,6 +26,9 @@ pub fn brk(address: usize) -> Result { let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; let context = context_lock.read(); + //println!("{}: {}: BRK {:X}", unsafe { ::core::str::from_utf8_unchecked(&context.name.lock()) }, + // context.id.into(), address); + let current = if let Some(ref heap_shared) = context.heap { heap_shared.with(|heap| { heap.start_address().get() + heap.size() @@ -47,8 +50,10 @@ pub fn brk(address: usize) -> Result { panic!("user heap not initialized"); } + //println!("Brk resize {:X}", address); Ok(address) } else { + //println!("Brk no mem"); Err(Error::new(ENOMEM)) } } diff --git a/kernel/syscall/validate.rs b/kernel/syscall/validate.rs index 361f58d..0f5b03b 100644 --- a/kernel/syscall/validate.rs +++ b/kernel/syscall/validate.rs @@ -9,8 +9,13 @@ fn validate(address: usize, size: usize, flags: entry::EntryFlags) -> Result<()> let start_page = Page::containing_address(VirtualAddress::new(address)); let end_page = Page::containing_address(VirtualAddress::new(address + size - 1)); for page in Page::range_inclusive(start_page, end_page) { - let page_flags = active_table.translate_page_flags(page).ok_or(Error::new(EFAULT))?; - if ! page_flags.contains(flags) { + if let Some(page_flags) = active_table.translate_page_flags(page) { + if ! page_flags.contains(flags) { + //println!("{:X}: Not {:?}", page.start_address().get(), flags); + return Err(Error::new(EFAULT)); + } + } else { + //println!("{:X}: Not found", page.start_address().get()); return Err(Error::new(EFAULT)); } } diff --git a/syscall b/syscall index 9b0c363..e79e54d 160000 --- a/syscall +++ b/syscall @@ -1 +1 @@ -Subproject commit 9b0c363b2711c64ad5be298bdf39c65b2a5d5e2f +Subproject commit e79e54d2f5ad6492b4452f74e60c54325997823f