Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add process struct #19

Merged
merged 11 commits into from
Feb 10, 2020
42 changes: 30 additions & 12 deletions src/kernel/fs.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use alloc::format;
use alloc::string::String;
use alloc::vec::Vec;
use bit_field::BitField;
use crate::kernel;
use alloc::vec::Vec;
use alloc::string::String;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FileType {
Expand All @@ -28,6 +29,17 @@ pub fn filename(pathname: &str) -> &str {
&pathname[i..n]
}

// Transform "foo.txt" into "/path/to/foo.txt"
pub fn realpath(pathname: &str) -> String {
if pathname.starts_with("/") {
pathname.into()
} else {
let dirname = kernel::process::dir();
let sep = if dirname.ends_with("/") { "" } else { "/" };
format!("{}{}{}", dirname, sep, pathname)
}
}

#[derive(Clone)]
pub struct File {
name: String,
Expand All @@ -38,8 +50,9 @@ pub struct File {

impl File {
pub fn create(pathname: &str) -> Option<Self> {
let dirname = dirname(pathname);
let filename = filename(pathname);
let pathname = realpath(pathname);
let dirname = dirname(&pathname);
let filename = filename(&pathname);
if let Some(dir) = Dir::open(dirname) {
if let Some(dir_entry) = dir.create_file(filename) {
return Some(dir_entry.to_file());
Expand All @@ -49,8 +62,9 @@ impl File {
}

pub fn open(pathname: &str) -> Option<Self> {
let dirname = dirname(pathname);
let filename = filename(pathname);
let pathname = realpath(pathname);
let dirname = dirname(&pathname);
let filename = filename(&pathname);
if let Some(dir) = Dir::open(dirname) {
if let Some(dir_entry) = dir.find(filename) {
if dir_entry.is_file() {
Expand Down Expand Up @@ -145,8 +159,9 @@ impl File {
}

pub fn delete(pathname: &str) -> Result<(), ()> {
let dirname = dirname(pathname);
let filename = filename(pathname);
let pathname = realpath(pathname);
let dirname = dirname(&pathname);
let filename = filename(&pathname);
if let Some(mut dir) = Dir::open(dirname) {
dir.delete_entry(filename)
} else {
Expand Down Expand Up @@ -347,8 +362,9 @@ impl Dir {
}

pub fn create(pathname: &str) -> Option<Self> {
let dirname = dirname(pathname);
let filename = filename(pathname);
let pathname = realpath(pathname);
let dirname = dirname(&pathname);
let filename = filename(&pathname);
if let Some(dir) = Dir::open(dirname) {
if let Some(dir_entry) = dir.create_dir(filename) {
return Some(dir_entry.to_dir())
Expand All @@ -358,6 +374,7 @@ impl Dir {
}

pub fn open(pathname: &str) -> Option<Self> {
let pathname = realpath(pathname);
let mut dir = Dir::root();
if pathname == "/" {
return Some(dir);
Expand Down Expand Up @@ -500,8 +517,9 @@ impl Dir {
}

pub fn delete(pathname: &str) -> Result<(), ()> {
let dirname = dirname(pathname);
let filename = filename(pathname);
let pathname = realpath(pathname);
let dirname = dirname(&pathname);
let filename = filename(&pathname);
if let Some(mut dir) = Dir::open(dirname) {
dir.delete_entry(filename)
} else {
Expand Down
1 change: 1 addition & 0 deletions src/kernel/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ pub mod keyboard;
pub mod mem;
pub mod pci;
pub mod pic;
pub mod process;
pub mod random;
pub mod rtl8139;
pub mod serial;
Expand Down
58 changes: 58 additions & 0 deletions src/kernel/process.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
use alloc::collections::btree_map::BTreeMap;
use alloc::string::{String, ToString};
use core::sync::atomic::{AtomicUsize, Ordering};
use lazy_static::lazy_static;
use spin::Mutex;

lazy_static! {
pub static ref PIDS: AtomicUsize = AtomicUsize::new(0);
pub static ref PROCESS: Mutex<Process> = Mutex::new(Process::new("/", "admin")); // TODO
}

pub struct Process {
id: usize,
env: BTreeMap<String, String>,
dir: String,
user: String, // TODO: Use uid
}

impl Process {
pub fn new(dir: &str, user: &str) -> Self {
let id = PIDS.fetch_add(1, Ordering::SeqCst);
let env = BTreeMap::new();
let dir = dir.to_string();
let user = user.to_string();
Self { id, env, dir, user }
}
}

pub fn id() -> usize {
PROCESS.lock().id
}

pub fn env(key: &str) -> Option<String> {
match PROCESS.lock().env.get(key.into()) {
Some(val) => Some(val.clone()),
None => None,
}
}

pub fn dir() -> String {
PROCESS.lock().dir.clone()
}

pub fn user() -> String {
PROCESS.lock().user.clone()
}

pub fn set_env(key: &str, val: &str) {
PROCESS.lock().env.insert(key.into(), val.into());
}

pub fn set_dir(dir: &str) {
PROCESS.lock().dir = dir.into();
}

pub fn set_user(user: &str) {
PROCESS.lock().user = user.into();
}
11 changes: 6 additions & 5 deletions src/user/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ use crate::{print, kernel, user};
use alloc::vec::Vec;

pub fn main(args: &[&str]) -> user::shell::ExitCode {
if args.len() != 2 {
return user::shell::ExitCode::CommandError;
}

let mut pathname = args[1];
let current_dir = kernel::process::dir();
let mut pathname = if args.len() == 2 && args[1].len() > 0 {
args[1]
} else {
&current_dir
};

// The commands `list /usr/alice/` and `list /usr/alice` are equivalent,
// but `list /` should not be modified.
Expand Down
6 changes: 6 additions & 0 deletions src/user/login.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::{print, kernel, user};
use alloc::collections::btree_map::BTreeMap;
use alloc::format;
use alloc::vec::Vec;
use alloc::string::String;
use core::convert::TryInto;
Expand Down Expand Up @@ -51,6 +52,11 @@ pub fn login() -> user::shell::ExitCode {
}
}

let home = format!("/usr/{}", username);
kernel::process::set_user(&username);
kernel::process::set_env("HOME", &home);
kernel::process::set_dir(&home);

// TODO: load shell
user::shell::ExitCode::CommandSuccessful
}
Expand Down
80 changes: 50 additions & 30 deletions src/user/shell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,36 +175,38 @@ impl Shell {
}

pub fn load_history(&mut self) {
let username = "admin"; // TODO: The login command should write the username somewhere
let pathname = format!("/usr/{}/.shell_history", username);
if let Some(home) = kernel::process::env("HOME") {
let pathname = format!("{}/.shell_history", home);

if let Some(file) = kernel::fs::File::open(&pathname) {
let contents = file.read_to_string();
for line in contents.split('\n') {
let cmd = line.trim();
if cmd.len() > 0 {
self.history.push(cmd.into());
if let Some(file) = kernel::fs::File::open(&pathname) {
let contents = file.read_to_string();
for line in contents.split('\n') {
let cmd = line.trim();
if cmd.len() > 0 {
self.history.push(cmd.into());
}
}
}
self.history_index = self.history.len();
}
self.history_index = self.history.len();
}

pub fn save_history(&mut self) {
let username = "admin"; // TODO: The login command should write the username somewhere
let pathname = format!("/usr/{}/.shell_history", username);
if let Some(home) = kernel::process::env("HOME") {
let pathname = format!("{}/.shell_history", home);

let mut contents = String::new();
for cmd in &self.history {
contents.push_str(&format!("{}\n", cmd));
}
let mut contents = String::new();
for cmd in &self.history {
contents.push_str(&format!("{}\n", cmd));
}

let mut file = match kernel::fs::File::open(&pathname) {
Some(file) => file,
None => kernel::fs::File::create(&pathname).unwrap(),
};
let mut file = match kernel::fs::File::open(&pathname) {
Some(file) => file,
None => kernel::fs::File::create(&pathname).unwrap(),
};

file.write(&contents.as_bytes()).unwrap();
file.write(&contents.as_bytes()).unwrap();
}
}

pub fn print_autocomplete(&mut self) {
Expand All @@ -224,19 +226,15 @@ impl Shell {
}
} else {
// Autocomplete path
let dirname = kernel::fs::dirname(args[i]);
let filename = kernel::fs::filename(args[i]);
let pathname = kernel::fs::realpath(args[i]);
let dirname = kernel::fs::dirname(&pathname);
let filename = kernel::fs::filename(&pathname);
self.autocomplete = vec![args[i].into()];
if let Some(dir) = kernel::fs::Dir::open(dirname) {
let sep = if dirname.ends_with("/") { "" } else { "/" };
for entry in dir.read() {
if entry.name().starts_with(filename) {
let mut path = String::new();
path.push_str(dirname);
if path != "/" {
path.push('/');
}
path.push_str(&entry.name());
self.autocomplete.push(path);
self.autocomplete.push(format!("{}{}{}", dirname, sep, entry.name()));
}
}
}
Expand Down Expand Up @@ -316,7 +314,7 @@ impl Shell {
"d" | "del" | "delete" => user::delete::main(&args),
"e" | "edit" => user::editor::main(&args),
"f" | "find" => ExitCode::CommandUnknown,
"g" | "go" => ExitCode::CommandUnknown,
"g" | "go" | "goto" => self.change_dir(&args),
"h" | "help" => user::help::main(&args),
"i" => ExitCode::CommandUnknown,
"j" | "jump" => ExitCode::CommandUnknown,
Expand Down Expand Up @@ -359,6 +357,28 @@ impl Shell {
fn print_prompt(&self) {
print!("\n{}", self.prompt);
}

fn change_dir(&self, args: &[&str]) -> ExitCode {
match args.len() {
1 => {
print!("{}\n", kernel::process::dir());
ExitCode::CommandSuccessful
},
2 => {
let pathname = kernel::fs::realpath(args[1]);
if kernel::fs::Dir::open(&pathname).is_some() {
kernel::process::set_dir(&pathname);
ExitCode::CommandSuccessful
} else {
print!("File not found '{}'\n", pathname);
ExitCode::CommandError
}
},
_ => {
ExitCode::CommandError
}
}
}
}

pub fn main(args: &[&str]) -> ExitCode {
Expand Down