From 515aa3671bc7ffda880fcee4ac8ddc6eea04cd16 Mon Sep 17 00:00:00 2001
From: Jeremy Soller <jackpot51@gmail.com>
Date: Tue, 27 Dec 2016 11:18:41 -0700
Subject: [PATCH] Implement dup2. Add debugging lines.

---
 context/context.rs  | 19 +++++++++++++++++++
 syscall/fs.rs       | 37 +++++++++++++++++++++++++++++++++++++
 syscall/mod.rs      | 15 ++++++++++++---
 syscall/process.rs  |  5 +++++
 syscall/validate.rs |  9 +++++++--
 5 files changed, 80 insertions(+), 5 deletions(-)

diff --git a/context/context.rs b/context/context.rs
index a7d41d48..607653c8 100644
--- a/context/context.rs
+++ b/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<FileHandle> {
+        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<File> {
diff --git a/syscall/fs.rs b/syscall/fs.rs
index 6f6a6984..bd02c52a 100644
--- a/syscall/fs.rs
+++ b/syscall/fs.rs
@@ -89,6 +89,8 @@ pub fn open(path: &[u8], flags: usize) -> Result<FileHandle> {
         (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<FileHandle> {
     }).ok_or(Error::new(EMFILE))
 }
 
+/// Duplicate file descriptor, replacing another
+pub fn dup2(fd: FileHandle, new_fd: FileHandle, buf: &[u8]) -> Result<FileHandle> {
+    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<usize> {
     let file = {
diff --git a/syscall/mod.rs b/syscall/mod.rs
index 69e53ecd..d3030071 100644
--- a/syscall/mod.rs
+++ b/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/syscall/process.rs b/syscall/process.rs
index cde11bee..8ffadf58 100644
--- a/syscall/process.rs
+++ b/syscall/process.rs
@@ -26,6 +26,9 @@ pub fn brk(address: usize) -> Result<usize> {
     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<usize> {
             panic!("user heap not initialized");
         }
 
+        //println!("Brk resize {:X}", address);
         Ok(address)
     } else {
+        //println!("Brk no mem");
         Err(Error::new(ENOMEM))
     }
 }
diff --git a/syscall/validate.rs b/syscall/validate.rs
index 361f58d9..0f5b03be 100644
--- a/syscall/validate.rs
+++ b/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));
         }
     }
-- 
GitLab