From 3e1c12b6a1a29da86c8dd640ec9350a788b2fd72 Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Sat, 27 Feb 2021 22:27:08 +0800 Subject: [PATCH] Add sys_dup && support input/output redirection in user_shell --- os/src/syscall/fs.rs | 15 +++++++ os/src/syscall/mod.rs | 2 + user/src/bin/cmdline_args.rs | 2 +- user/src/bin/user_shell.rs | 81 ++++++++++++++++++++++++++++++------ user/src/lib.rs | 1 + user/src/syscall.rs | 5 +++ 6 files changed, 93 insertions(+), 13 deletions(-) diff --git a/os/src/syscall/fs.rs b/os/src/syscall/fs.rs index 577e4a0a..79eac32a 100644 --- a/os/src/syscall/fs.rs +++ b/os/src/syscall/fs.rs @@ -6,6 +6,7 @@ use crate::mm::{ }; use crate::task::{current_user_token, current_task}; use crate::fs::{make_pipe, OpenFlags, open_file}; +use alloc::sync::Arc; pub fn sys_write(fd: usize, buf: *const u8, len: usize) -> isize { let token = current_user_token(); @@ -93,4 +94,18 @@ pub fn sys_pipe(pipe: *mut usize) -> isize { *translated_refmut(token, pipe) = read_fd; *translated_refmut(token, unsafe { pipe.add(1) }) = write_fd; 0 +} + +pub fn sys_dup(fd: usize) -> isize { + let task = current_task().unwrap(); + let mut inner = task.acquire_inner_lock(); + if fd >= inner.fd_table.len() { + return -1; + } + if inner.fd_table[fd].is_none() { + return -1; + } + let new_fd = inner.alloc_fd(); + inner.fd_table[new_fd] = Some(Arc::clone(inner.fd_table[fd].as_ref().unwrap())); + new_fd as isize } \ No newline at end of file diff --git a/os/src/syscall/mod.rs b/os/src/syscall/mod.rs index 4a3952b4..4683d055 100644 --- a/os/src/syscall/mod.rs +++ b/os/src/syscall/mod.rs @@ -1,3 +1,4 @@ +const SYSCALL_DUP: usize = 24; const SYSCALL_OPEN: usize = 56; const SYSCALL_CLOSE: usize = 57; const SYSCALL_PIPE: usize = 59; @@ -19,6 +20,7 @@ use process::*; pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize { match syscall_id { + SYSCALL_DUP=> sys_dup(args[0]), SYSCALL_OPEN => sys_open(args[0] as *const u8, args[1] as u32), SYSCALL_CLOSE => sys_close(args[0]), SYSCALL_PIPE => sys_pipe(args[0] as *mut usize), diff --git a/user/src/bin/cmdline_args.rs b/user/src/bin/cmdline_args.rs index 18b0112e..b49ec332 100644 --- a/user/src/bin/cmdline_args.rs +++ b/user/src/bin/cmdline_args.rs @@ -10,7 +10,7 @@ extern crate user_lib; pub fn main(argc: usize, argv: &[&str]) -> i32 { println!("argc = {}", argc); for i in 0..argc { - println!("argc[{}] = {}", i, argv[i]); + println!("argv[{}] = {}", i, argv[i]); } 0 } \ No newline at end of file diff --git a/user/src/bin/user_shell.rs b/user/src/bin/user_shell.rs index d1838cae..b2c33f2d 100644 --- a/user/src/bin/user_shell.rs +++ b/user/src/bin/user_shell.rs @@ -13,7 +13,15 @@ const BS: u8 = 0x08u8; use alloc::string::String; use alloc::vec::Vec; -use user_lib::{fork, exec, waitpid}; +use user_lib::{ + fork, + exec, + waitpid, + open, + OpenFlags, + close, + dup, +}; use user_lib::console::getchar; #[no_mangle] @@ -29,18 +37,40 @@ pub fn main() -> i32 { if !line.is_empty() { let args: Vec<_> = line.as_str().split(' ').collect(); let mut args_copy: Vec = args - .iter() - .map(|&arg| { - let mut string = String::new(); - string.push_str(arg); - string - }) - .collect(); + .iter() + .map(|&arg| { + let mut string = String::new(); + string.push_str(arg); + string + }) + .collect(); + args_copy - .iter_mut() - .for_each(|string| { - string.push('\0'); - }); + .iter_mut() + .for_each(|string| { + string.push('\0'); + }); + + // redirect input + let mut input = String::new(); + if let Some((idx, _)) = args_copy + .iter() + .enumerate() + .find(|(_, arg)| arg.as_str() == "<\0") { + input = args_copy[idx + 1].clone(); + args_copy.drain(idx..=idx + 1); + } + + // redirect output + let mut output = String::new(); + if let Some((idx, _)) = args_copy + .iter() + .enumerate() + .find(|(_, arg)| arg.as_str() == ">\0") { + output = args_copy[idx + 1].clone(); + args_copy.drain(idx..=idx + 1); + } + let mut args_addr: Vec<*const u8> = args_copy .iter() .map(|arg| arg.as_ptr()) @@ -48,6 +78,33 @@ pub fn main() -> i32 { args_addr.push(0 as *const u8); let pid = fork(); if pid == 0 { + // input redirection + if !input.is_empty() { + let input_fd = open(input.as_str(), OpenFlags::RDONLY); + if input_fd == -1 { + println!("Error when opening file {}", input); + return -4; + } + let input_fd = input_fd as usize; + close(0); + assert_eq!(dup(input_fd), 0); + close(input_fd); + } + // output redirection + if !output.is_empty() { + let output_fd = open( + output.as_str(), + OpenFlags::CREATE | OpenFlags::WRONLY + ); + if output_fd == -1 { + println!("Error when opening file {}", output); + return -4; + } + let output_fd = output_fd as usize; + close(1); + assert_eq!(dup(output_fd), 1); + close(output_fd); + } // child process if exec(args_copy[0].as_str(), args_addr.as_slice()) == -1 { println!("Error when executing!"); diff --git a/user/src/lib.rs b/user/src/lib.rs index 22ad9d49..0ef03bfb 100644 --- a/user/src/lib.rs +++ b/user/src/lib.rs @@ -69,6 +69,7 @@ bitflags! { } } +pub fn dup(fd: usize) -> isize { sys_dup(fd) } pub fn open(path: &str, flags: OpenFlags) -> isize { sys_open(path, flags.bits) } pub fn close(fd: usize) -> isize { sys_close(fd) } pub fn pipe(pipe_fd: &mut [usize]) -> isize { sys_pipe(pipe_fd) } diff --git a/user/src/syscall.rs b/user/src/syscall.rs index 99e16df9..1cd30f84 100644 --- a/user/src/syscall.rs +++ b/user/src/syscall.rs @@ -1,3 +1,4 @@ +const SYSCALL_DUP: usize = 24; const SYSCALL_OPEN: usize = 56; const SYSCALL_CLOSE: usize = 57; const SYSCALL_PIPE: usize = 59; @@ -24,6 +25,10 @@ fn syscall(id: usize, args: [usize; 3]) -> isize { ret } +pub fn sys_dup(fd: usize) -> isize { + syscall(SYSCALL_DUP, [fd, 0, 0]) +} + pub fn sys_open(path: &str, flags: u32) -> isize { syscall(SYSCALL_OPEN, [path.as_ptr() as usize, flags as usize, 0]) }