├── .gitignore ├── src ├── built_in_command │ ├── mod.rs │ ├── exit.rs │ └── cd.rs ├── parser │ ├── mod.rs │ ├── redirect.rs │ └── parser.rs ├── lib.rs ├── process │ ├── mod.rs │ ├── signal.rs │ ├── process.rs │ ├── redirect.rs │ ├── pipe.rs │ └── fork.rs └── main.rs ├── README.md ├── Cargo.toml └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /src/built_in_command/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod cd; 2 | pub mod exit; -------------------------------------------------------------------------------- /src/parser/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod parser; 2 | pub mod redirect; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # g_shell 2 | 自作のShellです 3 | 多段パイプ リダクレイク 対応済み 4 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod built_in_command; 2 | pub mod parser; 3 | pub mod process; -------------------------------------------------------------------------------- /src/process/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod process; 2 | pub mod fork; 3 | pub mod signal; 4 | pub mod pipe; 5 | pub mod redirect; -------------------------------------------------------------------------------- /src/built_in_command/exit.rs: -------------------------------------------------------------------------------- 1 | use std::process::exit; 2 | 3 | use super::super::parser::parser::CommandParse; 4 | 5 | pub fn run_exit(command: &CommandParse) -> Result<(), String> { 6 | if command.get_index() == 1 { 7 | exit(1); 8 | } else { 9 | return Err(format!("exit has no subcommands, options and path")); 10 | } 11 | } -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "g_shell" 3 | version = "0.1.0" 4 | authors = ["garebare "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | nix = "0.19.0" 11 | whoami = "0.9.0" 12 | dirs = "3.0" 13 | chan = "0.1.23" -------------------------------------------------------------------------------- /src/parser/redirect.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone)] 2 | pub struct Redirect { 3 | path: String, 4 | is_over:bool 5 | } 6 | 7 | impl Redirect { 8 | pub fn new(path:&str, is_over:bool) -> Self { 9 | Self { 10 | path:path.to_string(), 11 | is_over, 12 | } 13 | } 14 | 15 | pub fn get_redirect_path(&self) -> &str { 16 | &self.path 17 | } 18 | 19 | pub fn get_is_over(&self) -> bool { 20 | self.is_over 21 | } 22 | } -------------------------------------------------------------------------------- /src/process/signal.rs: -------------------------------------------------------------------------------- 1 | use nix::sys::signal; 2 | use nix::sys::signal::SaFlags; 3 | use nix::sys::signal::{sigaction, SigAction, SigHandler, SigSet}; 4 | 5 | use super::process; 6 | 7 | extern "C" fn handle_signal(_signam: i32) { 8 | println!(); 9 | } 10 | 11 | impl process::Process { 12 | pub(crate) fn signal_action(&self) { 13 | let sa = SigAction::new( 14 | SigHandler::Handler(handle_signal), 15 | SaFlags::SA_RESETHAND, 16 | SigSet::empty(), 17 | ); 18 | unsafe { sigaction(signal::SIGINT, &sa) }.unwrap(); 19 | } 20 | } -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::io::{stdin, stdout, Write}; 3 | 4 | use whoami; 5 | 6 | use g_shell::parser; 7 | use g_shell::process; 8 | 9 | fn main() { 10 | sh_loop(); 11 | } 12 | 13 | fn sh_loop() { 14 | loop { 15 | print!( 16 | "{}@{}:{} > ", 17 | whoami::username(), 18 | whoami::hostname(), 19 | env::current_dir().unwrap().display() 20 | ); 21 | stdout().flush().unwrap(); 22 | 23 | //コマンドラインを取得 24 | let mut line = String::new(); 25 | stdin().read_line(&mut line).expect("Faild to read line"); 26 | line.remove(line.len() - 1); 27 | 28 | //コマンドの解析 29 | let mut command = parser::parser::CommandParse::new(); 30 | command.run(line); 31 | 32 | //コマンドの実行とプロセスの生成 33 | let mut process = process::process::Process::new(&command); 34 | match process.argvs_execute(){ 35 | Ok(_) => {} 36 | Err(e) => { 37 | eprintln!("{}", e); 38 | } 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /src/built_in_command/cd.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | 3 | use dirs; 4 | 5 | use super::super::parser::parser::CommandParse; 6 | 7 | pub fn run_cd(commands: &CommandParse) -> Result<(), String> { 8 | let is_path = set_current(&commands.get_path()); 9 | let is_subcommand = set_current(&commands.get_sub_command()); 10 | let is_path_empty = commands.get_path().trim().is_empty(); 11 | let is_subcommand_empty = commands.get_sub_command().trim().is_empty(); 12 | 13 | if is_path_empty && is_subcommand_empty { 14 | env::set_current_dir(dirs::home_dir().unwrap()).unwrap(); 15 | return Ok(()); 16 | } 17 | 18 | if !(is_path || is_subcommand) { 19 | if !is_path_empty { 20 | return Err(format!("cd : {} No such file or directory", &commands.get_path())); 21 | } else if !is_subcommand_empty { 22 | return Err(format!( 23 | "cd : {} No such file or directory", 24 | &commands.get_sub_command() 25 | )); 26 | } 27 | } 28 | return Ok(()); 29 | } 30 | 31 | fn set_current(path: &str) -> bool { 32 | env::set_current_dir(path).is_ok() 33 | } 34 | -------------------------------------------------------------------------------- /src/process/process.rs: -------------------------------------------------------------------------------- 1 | use super::super::parser; 2 | 3 | pub struct Process { 4 | run_command: parser::parser::CommandParse, 5 | pub pipes: Vec<(i32, i32)>, 6 | pub process: Vec, 7 | } 8 | 9 | impl Process { 10 | pub fn new(command: &parser::parser::CommandParse) -> Self { 11 | Self { 12 | run_command: command.clone(), 13 | pipes: Vec::new(), 14 | process: Vec::new(), 15 | } 16 | } 17 | 18 | pub fn get_run_command(&self) -> &parser::parser::CommandParse { 19 | &self.run_command 20 | } 21 | 22 | pub fn push_pipe(&mut self, pipe: (i32, i32)) { 23 | self.pipes.push(pipe); 24 | } 25 | 26 | pub fn len_pipes(&self) -> usize { 27 | self.pipes.len() - 1 28 | } 29 | 30 | pub fn get_pipe(&self, index: usize) -> Option<&(i32, i32)> { 31 | self.pipes.get(index) 32 | } 33 | 34 | pub fn is_empty_pipes(&self) -> bool { 35 | self.pipes.is_empty() 36 | } 37 | 38 | pub fn pop_pipes(&mut self) { 39 | if self.len_pipes() == 0 { 40 | return; 41 | } 42 | self.pipes.pop(); 43 | } 44 | 45 | pub fn deque_pipe(&mut self) { 46 | if self.len_pipes() == 0 { 47 | return; 48 | } 49 | self.pipes.remove(0); 50 | } 51 | 52 | pub fn push_process(&mut self, pid: nix::unistd::Pid) { 53 | self.process.push(pid); 54 | } 55 | 56 | pub fn get_process(&self) -> &Vec { 57 | &self.process 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/process/redirect.rs: -------------------------------------------------------------------------------- 1 | use super::process::Process; 2 | use nix::fcntl::{open, OFlag}; 3 | use nix::sys::stat::Mode; 4 | use nix::unistd::*; 5 | 6 | impl Process { 7 | pub(crate) fn redirect(&self, path: &str) -> Result<(), String> { 8 | let mode = Mode::S_IRWXU; 9 | let flag = OFlag::O_CREAT | OFlag::O_WRONLY | OFlag::O_TRUNC; 10 | match self.open_file(path, flag, mode) { 11 | Ok(_) => { 12 | return Ok(()); 13 | } 14 | Err(e) => { 15 | return Err(e); 16 | } 17 | } 18 | } 19 | 20 | pub(crate) fn over_redirect(&self, path: &str) -> Result<(), String> { 21 | let mode = Mode::S_IRWXU; 22 | let flag = OFlag::O_CREAT | OFlag::O_WRONLY | OFlag::O_APPEND; 23 | match self.open_file(path, flag, mode) { 24 | Ok(_) => { 25 | return Ok(()); 26 | } 27 | Err(e) => { 28 | return Err(e); 29 | } 30 | } 31 | } 32 | 33 | fn open_file(&self, path: &str, flag: OFlag, mode: Mode) -> Result<(), String> { 34 | match open(path, flag, mode) { 35 | Ok(file) => match dup2(file, 1) { 36 | Ok(_) => match close(file) { 37 | Ok(_) => {} 38 | Err(_) => { 39 | return Err(format!("file clse error")); 40 | } 41 | }, 42 | Err(_) => { 43 | return Err(format!("file dup2 error")); 44 | } 45 | }, 46 | Err(_) => { 47 | return Err(format!("file open error")); 48 | } 49 | } 50 | return Ok(()); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/parser/parser.rs: -------------------------------------------------------------------------------- 1 | use super::redirect::Redirect; 2 | 3 | #[derive(Debug, Clone)] 4 | pub struct CommandParse { 5 | command: String, 6 | sub_command: String, 7 | option: Vec, 8 | path: String, 9 | index: usize, 10 | pipe: Option>, 11 | redirect: Option, 12 | } 13 | 14 | impl CommandParse { 15 | pub fn new() -> Self { 16 | Self { 17 | command: String::new(), 18 | sub_command: String::new(), 19 | option: Vec::new(), 20 | path: String::new(), 21 | index: 0, 22 | pipe: None, 23 | redirect: None, 24 | } 25 | } 26 | 27 | pub fn run(&mut self, line: String) { 28 | let mut line_split: Vec<&str> = line.split(" ").collect(); 29 | self.judge_loop(&mut line_split); 30 | } 31 | 32 | fn judge_loop(&mut self, mut line_split: &mut Vec<&str>) { 33 | self.index += 1; 34 | let line_index = line_split.len(); 35 | self.command = line_split[0].to_string(); 36 | loop { 37 | if line_index <= self.index { 38 | break; 39 | } 40 | self.judge(&mut line_split); 41 | self.index += 1; 42 | } 43 | } 44 | 45 | fn judge(&mut self, args: &mut Vec<&str>) { 46 | let arg = args[self.index]; 47 | 48 | if arg.chars().nth(0).unwrap() == '>' { 49 | self.index += 1; 50 | let arg = args[self.index]; 51 | if arg.len() == 2 && arg.chars().nth(1).unwrap() == '>' { 52 | self.redirect = Some(Redirect::new(arg, true)); 53 | return; 54 | } 55 | self.redirect = Some(Redirect::new(arg, false)); 56 | return; 57 | } 58 | 59 | if arg.chars().nth(0).unwrap() == '-' { 60 | self.option.push(arg.to_string()); 61 | return; 62 | } 63 | 64 | if arg.contains("/") || arg.contains(".") { 65 | self.path = arg.to_string(); 66 | return; 67 | } 68 | 69 | if arg == "|" { 70 | let mut command = CommandParse::new(); 71 | let mut args_split: Vec<&str> = Vec::new(); 72 | for index in self.index + 1..args.len() { 73 | let split = args[index]; 74 | args_split.push(split); 75 | } 76 | command.judge_loop(&mut args_split); 77 | self.pipe = Some(Box::new(command)); 78 | self.index += args.len() - self.index; 79 | return; 80 | } 81 | 82 | self.sub_command = arg.to_string(); 83 | } 84 | 85 | pub fn get_command(&self) -> &str { 86 | &self.command 87 | } 88 | 89 | pub fn get_sub_command(&self) -> &str { 90 | &self.sub_command 91 | } 92 | 93 | pub fn get_path(&self) -> &str { 94 | &self.path 95 | } 96 | 97 | pub fn get_index(&self) -> usize { 98 | self.index 99 | } 100 | 101 | pub fn get_options(&self) -> &Vec { 102 | &self.option 103 | } 104 | 105 | pub fn get_pipe(&self) -> &Option> { 106 | &self.pipe 107 | } 108 | 109 | pub fn get_redirect(&self) -> &Option { 110 | &self.redirect 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/process/pipe.rs: -------------------------------------------------------------------------------- 1 | use nix::unistd::*; 2 | 3 | use super::process::Process; 4 | 5 | impl Process { 6 | pub(crate) fn pipe_first_connect(&self) -> Result<(), String> { 7 | match self.get_pipe(self.len_pipes()) { 8 | Some(pipes) => { 9 | match dup2(pipes.1, 1) { 10 | Ok(_) => {} 11 | Err(_) => { 12 | return Err(format!("pipe first dup2 error")); 13 | } 14 | } 15 | 16 | match self.close_pipe(pipes) { 17 | Ok(_) => {} 18 | Err(_) => { 19 | return Err(format!("pipe first close error")); 20 | } 21 | } 22 | } 23 | None => { 24 | return Err(format!("pipe first missing")); 25 | } 26 | } 27 | 28 | return Ok(()); 29 | } 30 | 31 | pub(crate) fn pipe_end_connect(&self) -> Result<(), String> { 32 | match self.get_pipe(self.len_pipes()) { 33 | Some(pipes) => { 34 | match dup2(pipes.0, 0) { 35 | Ok(_) => {} 36 | Err(_) => { 37 | return Err(format!("pipe close dup2 error")); 38 | } 39 | } 40 | 41 | match self.close_pipe(pipes) { 42 | Ok(_) => {} 43 | Err(_) => { 44 | return Err(format!("pipe end close error")); 45 | } 46 | } 47 | } 48 | 49 | None => { 50 | return Err(format!("pipe end missing")); 51 | } 52 | } 53 | 54 | return Ok(()); 55 | } 56 | 57 | pub(crate) fn pipe_route_connect(&self) -> Result<(), String> { 58 | match self.get_pipe(self.len_pipes() - 1) { 59 | Some(pipes) => { 60 | match dup2(pipes.0, 0) { 61 | Ok(_) => {} 62 | 63 | Err(_) => { 64 | return Err(format!("pipe route dup2 error")); 65 | } 66 | } 67 | 68 | match self.close_pipe(pipes) { 69 | Ok(_) => {} 70 | Err(_) => { 71 | return Err(format!("pipe route close error")); 72 | } 73 | } 74 | } 75 | 76 | None => { 77 | return Err(format!("pipe route missinag")); 78 | } 79 | } 80 | 81 | match self.get_pipe(self.len_pipes()) { 82 | Some(pipes) => { 83 | match dup2(pipes.1, 1) { 84 | Ok(_) => {} 85 | Err(_) => { 86 | return Err(format!("pipe route dup2 error")); 87 | } 88 | } 89 | match self.close_pipe(pipes) { 90 | Ok(_) => {} 91 | Err(_) => { 92 | return Err(format!("pipe route close error")); 93 | } 94 | } 95 | } 96 | None => { 97 | return Err(format!("pipe route missinag")); 98 | } 99 | } 100 | 101 | return Ok(()); 102 | } 103 | 104 | pub(crate) fn pearent_connect_end(&mut self) -> Result<(), String> { 105 | match self.get_pipe(0) { 106 | Some(pipes) => match self.close_pipe(pipes) { 107 | Ok(_) => {} 108 | Err(_) => { 109 | return Err(format!("pearent end close error")); 110 | } 111 | }, 112 | None => { 113 | return Err(format!("pipe missing")); 114 | } 115 | } 116 | 117 | self.deque_pipe(); 118 | return Ok(()); 119 | } 120 | 121 | pub(crate) fn close_pipe(&self, pipe: &(i32, i32)) -> Result<(), String> { 122 | match close(pipe.0) { 123 | Ok(_) => {} 124 | Err(_) => { 125 | return Err(format!("pipe close error")); 126 | } 127 | } 128 | match close(pipe.1) { 129 | Ok(_) => {} 130 | Err(_) => { 131 | return Err(format!("pipe clsoe error")); 132 | } 133 | } 134 | return Ok(()); 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /src/process/fork.rs: -------------------------------------------------------------------------------- 1 | use std::ffi::{CStr, CString}; 2 | use std::process::exit; 3 | 4 | use nix::sys::wait::{waitpid, WaitPidFlag, WaitStatus}; 5 | use nix::unistd::*; 6 | 7 | use super::super::built_in_command; 8 | use super::super::parser; 9 | use super::process::Process; 10 | 11 | impl Process { 12 | pub fn argvs_execute(&mut self) -> Result<(), String> { 13 | self.signal_action(); 14 | let command = self.get_run_command(); 15 | let commands = self.get_run_command().get_command(); 16 | 17 | if commands == "" { 18 | return Ok(()); 19 | } 20 | 21 | if commands == "cd" { 22 | match built_in_command::cd::run_cd(command) { 23 | Ok(_) => {} 24 | Err(e) => { 25 | return Err(e); 26 | } 27 | } 28 | } else if commands == "exit" { 29 | match built_in_command::exit::run_exit(command) { 30 | Ok(_) => {} 31 | Err(e) => { 32 | return Err(e); 33 | } 34 | } 35 | } else { 36 | let command = self.get_run_command().clone(); 37 | match self.sh_launch(&command) { 38 | Ok(_) => { 39 | for pid in self.get_process() { 40 | match self.wait_process(*pid) { 41 | Ok(_) => {} 42 | Err(e) => { 43 | return Err(e); 44 | } 45 | } 46 | } 47 | } 48 | Err(e) => { 49 | return Err(e); 50 | } 51 | } 52 | } 53 | return Ok(()); 54 | } 55 | 56 | fn sh_launch(&mut self, command: &parser::parser::CommandParse) -> Result<(), String> { 57 | let is_empty = !self.is_empty_pipes(); 58 | match command.get_pipe() { 59 | Some(_) => match pipe() { 60 | Ok(pipe) => { 61 | self.push_pipe(pipe); 62 | } 63 | Err(_) => { 64 | return Err(format!("Pipe error")); 65 | } 66 | }, 67 | None => {} 68 | } 69 | //プロセスの生成 70 | match unsafe { fork() } { 71 | //親プロセス 72 | Ok(ForkResult::Parent { child, .. }) => { 73 | self.push_process(child); 74 | if is_empty { 75 | match self.pearent_connect_end() { 76 | Ok(_) => {} 77 | Err(e) => { 78 | return Err(e); 79 | } 80 | } 81 | } 82 | match command.get_pipe() { 83 | Some(pipe) => match self.sh_launch(&pipe) { 84 | Ok(()) => {} 85 | Err(e) => { 86 | return Err(e); 87 | } 88 | }, 89 | None => {} 90 | } 91 | } 92 | //子プロセス 93 | Ok(ForkResult::Child) => unsafe { 94 | if command.get_pipe().is_some() && self.len_pipes() == 0 { 95 | match self.pipe_first_connect() { 96 | Ok(_) => {} 97 | Err(e) => { 98 | println!("{}", e); 99 | exit(-1); 100 | } 101 | } 102 | } else if !self.is_empty_pipes() && !command.get_pipe().is_some() { 103 | match self.pipe_end_connect() { 104 | Ok(_) => {} 105 | Err(e) => { 106 | println!("{}", e); 107 | exit(-1); 108 | } 109 | } 110 | } else if !self.is_empty_pipes() && command.get_pipe().is_some() { 111 | match self.pipe_route_connect() { 112 | Ok(_) => {} 113 | Err(e) => { 114 | println!("{}", e); 115 | exit(-1); 116 | } 117 | } 118 | } 119 | 120 | match command.get_redirect() { 121 | Some(redirect) => { 122 | let path = redirect.get_redirect_path(); 123 | if redirect.get_is_over() { 124 | match self.redirect(path) { 125 | Ok(_) => {} 126 | Err(e) => { 127 | return Err(e); 128 | } 129 | } 130 | } else { 131 | match self.over_redirect(path) { 132 | Ok(_) => {} 133 | Err(e) => { 134 | return Err(e); 135 | } 136 | } 137 | } 138 | } 139 | None => {} 140 | } 141 | 142 | let cstring = CString::new(command.get_command()).expect("CString::new failed"); 143 | let cstr = CStr::from_bytes_with_nul_unchecked(cstring.to_bytes_with_nul()); 144 | let mut argv: Vec = Vec::new(); 145 | self.push_argv(&mut argv); 146 | let result = execvp(cstr, &argv); 147 | match result { 148 | Ok(_) => { 149 | exit(0); 150 | } 151 | 152 | Err(_) => { 153 | println!("{}: command not found", command.get_command()); 154 | exit(-1); 155 | } 156 | } 157 | }, 158 | 159 | Err(_) => { 160 | return Err(format!("Fork Failed")); 161 | } 162 | } 163 | return Ok(()); 164 | } 165 | 166 | fn push_argv(&self, argvs: &mut Vec) { 167 | let command = self.get_run_command(); 168 | argvs.push(CString::new(command.get_command()).expect("CString::new failed")); 169 | if command.get_sub_command() != "" { 170 | argvs.push(CString::new(command.get_sub_command()).expect("CString::new failed")); 171 | } else if command.get_path() != "" { 172 | argvs.push(CString::new(command.get_path()).expect("CString::new failed")); 173 | } 174 | for option in command.get_options() { 175 | argvs.push(CString::new(option.to_string()).expect("CString::new failed")); 176 | } 177 | } 178 | 179 | fn wait_process(&self, child: Pid) -> Result<(), String> { 180 | match waitpid(child, Some(WaitPidFlag::WCONTINUED)) { 181 | Ok(status) => match status { 182 | WaitStatus::Exited(_, _) => {} 183 | 184 | WaitStatus::Stopped(_, _) => {} 185 | _ => { 186 | return Err(format!("Waiprocess EOF")); 187 | } 188 | }, 189 | Err(_) => {} 190 | } 191 | return Ok(()); 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "arrayref" 5 | version = "0.3.6" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" 8 | 9 | [[package]] 10 | name = "arrayvec" 11 | version = "0.5.2" 12 | source = "registry+https://github.com/rust-lang/crates.io-index" 13 | checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" 14 | 15 | [[package]] 16 | name = "autocfg" 17 | version = "1.0.1" 18 | source = "registry+https://github.com/rust-lang/crates.io-index" 19 | checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" 20 | 21 | [[package]] 22 | name = "base64" 23 | version = "0.12.3" 24 | source = "registry+https://github.com/rust-lang/crates.io-index" 25 | checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" 26 | 27 | [[package]] 28 | name = "bitflags" 29 | version = "1.2.1" 30 | source = "registry+https://github.com/rust-lang/crates.io-index" 31 | checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" 32 | 33 | [[package]] 34 | name = "blake2b_simd" 35 | version = "0.5.11" 36 | source = "registry+https://github.com/rust-lang/crates.io-index" 37 | checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587" 38 | dependencies = [ 39 | "arrayref", 40 | "arrayvec", 41 | "constant_time_eq", 42 | ] 43 | 44 | [[package]] 45 | name = "cc" 46 | version = "1.0.63" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "ad9c6140b5a2c7db40ea56eb1821245e5362b44385c05b76288b1a599934ac87" 49 | 50 | [[package]] 51 | name = "cfg-if" 52 | version = "0.1.10" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 55 | 56 | [[package]] 57 | name = "chan" 58 | version = "0.1.23" 59 | source = "registry+https://github.com/rust-lang/crates.io-index" 60 | checksum = "d14956a3dae065ffaa0d92ece848ab4ced88d32361e7fdfbfd653a5c454a1ed8" 61 | dependencies = [ 62 | "rand 0.3.23", 63 | ] 64 | 65 | [[package]] 66 | name = "constant_time_eq" 67 | version = "0.1.5" 68 | source = "registry+https://github.com/rust-lang/crates.io-index" 69 | checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" 70 | 71 | [[package]] 72 | name = "crossbeam-utils" 73 | version = "0.7.2" 74 | source = "registry+https://github.com/rust-lang/crates.io-index" 75 | checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" 76 | dependencies = [ 77 | "autocfg", 78 | "cfg-if", 79 | "lazy_static", 80 | ] 81 | 82 | [[package]] 83 | name = "dirs" 84 | version = "3.0.1" 85 | source = "registry+https://github.com/rust-lang/crates.io-index" 86 | checksum = "142995ed02755914747cc6ca76fc7e4583cd18578746716d0508ea6ed558b9ff" 87 | dependencies = [ 88 | "dirs-sys", 89 | ] 90 | 91 | [[package]] 92 | name = "dirs-sys" 93 | version = "0.3.5" 94 | source = "registry+https://github.com/rust-lang/crates.io-index" 95 | checksum = "8e93d7f5705de3e49895a2b5e0b8855a1c27f080192ae9c32a6432d50741a57a" 96 | dependencies = [ 97 | "libc", 98 | "redox_users", 99 | "winapi", 100 | ] 101 | 102 | [[package]] 103 | name = "fuchsia-cprng" 104 | version = "0.1.1" 105 | source = "registry+https://github.com/rust-lang/crates.io-index" 106 | checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" 107 | 108 | [[package]] 109 | name = "g_shell" 110 | version = "0.1.0" 111 | dependencies = [ 112 | "chan", 113 | "dirs", 114 | "nix", 115 | "whoami", 116 | ] 117 | 118 | [[package]] 119 | name = "getrandom" 120 | version = "0.1.15" 121 | source = "registry+https://github.com/rust-lang/crates.io-index" 122 | checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6" 123 | dependencies = [ 124 | "cfg-if", 125 | "libc", 126 | "wasi", 127 | ] 128 | 129 | [[package]] 130 | name = "lazy_static" 131 | version = "1.4.0" 132 | source = "registry+https://github.com/rust-lang/crates.io-index" 133 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 134 | 135 | [[package]] 136 | name = "libc" 137 | version = "0.2.80" 138 | source = "registry+https://github.com/rust-lang/crates.io-index" 139 | checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614" 140 | 141 | [[package]] 142 | name = "nix" 143 | version = "0.19.0" 144 | source = "registry+https://github.com/rust-lang/crates.io-index" 145 | checksum = "85db2feff6bf70ebc3a4793191517d5f0331100a2f10f9bf93b5e5214f32b7b7" 146 | dependencies = [ 147 | "bitflags", 148 | "cc", 149 | "cfg-if", 150 | "libc", 151 | ] 152 | 153 | [[package]] 154 | name = "rand" 155 | version = "0.3.23" 156 | source = "registry+https://github.com/rust-lang/crates.io-index" 157 | checksum = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" 158 | dependencies = [ 159 | "libc", 160 | "rand 0.4.6", 161 | ] 162 | 163 | [[package]] 164 | name = "rand" 165 | version = "0.4.6" 166 | source = "registry+https://github.com/rust-lang/crates.io-index" 167 | checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" 168 | dependencies = [ 169 | "fuchsia-cprng", 170 | "libc", 171 | "rand_core 0.3.1", 172 | "rdrand", 173 | "winapi", 174 | ] 175 | 176 | [[package]] 177 | name = "rand_core" 178 | version = "0.3.1" 179 | source = "registry+https://github.com/rust-lang/crates.io-index" 180 | checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" 181 | dependencies = [ 182 | "rand_core 0.4.2", 183 | ] 184 | 185 | [[package]] 186 | name = "rand_core" 187 | version = "0.4.2" 188 | source = "registry+https://github.com/rust-lang/crates.io-index" 189 | checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" 190 | 191 | [[package]] 192 | name = "rdrand" 193 | version = "0.4.0" 194 | source = "registry+https://github.com/rust-lang/crates.io-index" 195 | checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" 196 | dependencies = [ 197 | "rand_core 0.3.1", 198 | ] 199 | 200 | [[package]] 201 | name = "redox_syscall" 202 | version = "0.1.57" 203 | source = "registry+https://github.com/rust-lang/crates.io-index" 204 | checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" 205 | 206 | [[package]] 207 | name = "redox_users" 208 | version = "0.3.5" 209 | source = "registry+https://github.com/rust-lang/crates.io-index" 210 | checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" 211 | dependencies = [ 212 | "getrandom", 213 | "redox_syscall", 214 | "rust-argon2", 215 | ] 216 | 217 | [[package]] 218 | name = "rust-argon2" 219 | version = "0.8.2" 220 | source = "registry+https://github.com/rust-lang/crates.io-index" 221 | checksum = "9dab61250775933275e84053ac235621dfb739556d5c54a2f2e9313b7cf43a19" 222 | dependencies = [ 223 | "base64", 224 | "blake2b_simd", 225 | "constant_time_eq", 226 | "crossbeam-utils", 227 | ] 228 | 229 | [[package]] 230 | name = "wasi" 231 | version = "0.9.0+wasi-snapshot-preview1" 232 | source = "registry+https://github.com/rust-lang/crates.io-index" 233 | checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" 234 | 235 | [[package]] 236 | name = "whoami" 237 | version = "0.9.0" 238 | source = "registry+https://github.com/rust-lang/crates.io-index" 239 | checksum = "7884773ab69074615cb8f8425d0e53f11710786158704fca70f53e71b0e05504" 240 | 241 | [[package]] 242 | name = "winapi" 243 | version = "0.3.9" 244 | source = "registry+https://github.com/rust-lang/crates.io-index" 245 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 246 | dependencies = [ 247 | "winapi-i686-pc-windows-gnu", 248 | "winapi-x86_64-pc-windows-gnu", 249 | ] 250 | 251 | [[package]] 252 | name = "winapi-i686-pc-windows-gnu" 253 | version = "0.4.0" 254 | source = "registry+https://github.com/rust-lang/crates.io-index" 255 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 256 | 257 | [[package]] 258 | name = "winapi-x86_64-pc-windows-gnu" 259 | version = "0.4.0" 260 | source = "registry+https://github.com/rust-lang/crates.io-index" 261 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 262 | --------------------------------------------------------------------------------