shell: set tty control for spawned processes

This commit is contained in:
Mark Poliakov 2023-11-14 17:31:30 +02:00
parent 7e42999539
commit 5447306fa6
8 changed files with 159 additions and 8 deletions

View File

@ -7,7 +7,7 @@ members = [
] ]
[patch.'https://git.alnyan.me/yggdrasil/yggdrasil-abi.git'] [patch.'https://git.alnyan.me/yggdrasil/yggdrasil-abi.git']
yggdrasil-abi = { path = "abi" } yggdrasil-abi = { path = "../abi" }
[patch.'https://git.alnyan.me/yggdrasil/yggdrasil-rt.git'] [patch.'https://git.alnyan.me/yggdrasil/yggdrasil-rt.git']
yggdrasil-rt = { path = "rt" } yggdrasil-rt = { path = "rt" }

1
abi
View File

@ -1 +0,0 @@
../abi

View File

@ -53,6 +53,7 @@ pack_initrd() {
cp ${build_dir}/mount ${root_dir}/sbin/ cp ${build_dir}/mount ${root_dir}/sbin/
cp ${build_dir}/login ${root_dir}/sbin/ cp ${build_dir}/login ${root_dir}/sbin/
cp ${build_dir}/ls ${root_dir}/bin/ cp ${build_dir}/ls ${root_dir}/bin/
cp ${build_dir}/hexd ${root_dir}/bin/
cp -r ${workspace_dir}/etc ${root_dir}/ cp -r ${workspace_dir}/etc ${root_dir}/

View File

@ -1,3 +1,4 @@
#![feature(yggdrasil_os)]
use std::{ use std::{
collections::HashMap, collections::HashMap,
env, env,
@ -22,7 +23,7 @@ pub struct Args {
#[arg(short)] #[arg(short)]
login: bool, login: bool,
script: Option<String>, script: Option<String>,
args: Vec<String> args: Vec<String>,
} }
pub enum Outcome { pub enum Outcome {
@ -93,8 +94,28 @@ impl From<ExitStatus> for Outcome {
} }
} }
#[cfg(target_os = "yggdrasil")]
fn exec_binary(
interactive: bool,
binary: &str,
args: &[String],
env: &HashMap<String, String>,
) -> Result<ExitStatus, io::Error> {
use std::os::yggdrasil::process::CommandExt;
let mut command = Command::new(binary);
let mut command = command.args(args).envs(env.iter());
if interactive {
unsafe {
command = command.process_group(0).gain_terminal(0);
}
}
command.status()
}
// TODO this has one flaw: it needs to somehow fork() (?) to set the created process' process group // TODO this has one flaw: it needs to somehow fork() (?) to set the created process' process group
pub fn exec(cmd: &[String], env: &mut HashMap<String, String>) -> Result<Outcome, Error> { pub fn exec(interactive: bool, cmd: &[String], env: &mut HashMap<String, String>) -> Result<Outcome, Error> {
let Some((cmd, args)) = cmd.split_first() else { let Some((cmd, args)) = cmd.split_first() else {
return Ok(Outcome::ok()); return Ok(Outcome::ok());
}; };
@ -102,8 +123,7 @@ pub fn exec(cmd: &[String], env: &mut HashMap<String, String>) -> Result<Outcome
if let Some(builtin) = builtins::get_builtin(cmd) { if let Some(builtin) = builtins::get_builtin(cmd) {
builtin(args, env) builtin(args, env)
} else { } else {
let status = Command::new(&cmd).args(args).envs(env.iter()).status()?; let status = exec_binary(interactive, cmd, args, env)?;
Ok(Outcome::from(status)) Ok(Outcome::from(status))
} }
} }
@ -123,7 +143,7 @@ fn run(mut input: Input, vars: &mut HashMap<String, String>) -> io::Result<ExitC
let line = line.trim(); let line = line.trim();
let cmd = parser::parse_line(vars, line).unwrap(); let cmd = parser::parse_line(vars, line).unwrap();
match exec(&cmd, vars) { match exec(input.is_interactive(), &cmd, vars) {
Ok(status) => { Ok(status) => {
if input.is_interactive() { if input.is_interactive() {
match status { match status {

View File

@ -14,6 +14,7 @@ yggdrasil-rt = { git = "https://git.alnyan.me/yggdrasil/yggdrasil-rt.git" }
[lib] [lib]
path = "src/lib.rs" path = "src/lib.rs"
# /sbin
[[bin]] [[bin]]
name = "mount" name = "mount"
path = "src/mount.rs" path = "src/mount.rs"
@ -22,6 +23,11 @@ path = "src/mount.rs"
name = "login" name = "login"
path = "src/login.rs" path = "src/login.rs"
# /bin
[[bin]] [[bin]]
name = "ls" name = "ls"
path = "src/ls.rs" path = "src/ls.rs"
[[bin]]
name = "hexd"
path = "src/hexd.rs"

73
sysutils/src/hexd.rs Normal file
View File

@ -0,0 +1,73 @@
use std::{env, io::{self, Read}, process::ExitCode};
use sysutils::{ToExitCode, Input};
const WINDOW_SIZE: usize = 16;
fn do_line(offset: usize, line: &[u8]) {
print!("{:08x} |", offset);
for i in 0..WINDOW_SIZE {
if i % 2 == 0 {
print!(" ");
}
if i < line.len() {
print!("{:02X}", line[i]);
} else {
print!(" ");
}
}
print!(" | ");
for &ch in line {
let ch = if ch.is_ascii_control() { b'.' } else { ch };
print!("{}", ch as char);
}
println!();
}
fn do_file(path: &str) -> io::Result<()> {
let mut input = Input::open_str(path)?;
let mut buf = [0; WINDOW_SIZE];
let mut offset = 0;
loop {
let len = input.read(&mut buf)?;
if len == 0 {
break;
}
do_line(offset, &buf[..len]);
offset += len;
}
Ok(())
}
pub fn main() -> ExitCode {
let args = env::args().collect::<Vec<_>>();
let result = if args.len() < 2 {
do_file("-").to_exit_code()
} else if args.len() == 2 {
do_file(&args[1]).to_exit_code()
} else {
let mut result = 0;
for arg in args[1..].iter() {
println!("{}:", arg);
if do_file(arg).to_exit_code() != 0 {
result = 1;
}
}
result
};
if result == 0 {
ExitCode::SUCCESS
} else {
ExitCode::FAILURE
}
}

View File

@ -1 +1,53 @@
pub mod display; use std::{io::{self, Read}, fs::File};
// TODO replace this
pub trait ToExitCode {
fn to_exit_code(&self) -> i32;
}
impl<T> ToExitCode for io::Result<T> {
fn to_exit_code(&self) -> i32 {
match self {
Ok(_) => 0,
_ => 1
}
}
}
pub enum Input {
Stdin(io::Stdin),
File(io::BufReader<File>)
}
impl Input {
pub fn open_str(arg: &str) -> io::Result<Self> {
if arg == "-" {
Ok(Self::Stdin(io::stdin()))
} else {
let file = File::open(arg)?;
let reader = io::BufReader::new(file);
Ok(Self::File(reader))
}
}
}
impl From<io::Stdin> for Input {
fn from(value: io::Stdin) -> Self {
Self::Stdin(value)
}
}
impl From<File> for Input {
fn from(value: File) -> Self {
Self::File(io::BufReader::new(value))
}
}
impl Read for Input {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
match self {
Self::Stdin(value) => value.read(buf),
Self::File(value) => value.read(buf)
}
}
}