diff --git a/kernel/arch/hosted/src/lib.rs b/kernel/arch/hosted/src/lib.rs index 0a333a5f..a9a40551 100644 --- a/kernel/arch/hosted/src/lib.rs +++ b/kernel/arch/hosted/src/lib.rs @@ -17,7 +17,10 @@ use libk_mm_interface::{ process::ProcessAddressSpaceManager, table::{MapAttributes, TableAllocator}, }; -use yggdrasil_abi::{error::Error, process::Signal}; +use yggdrasil_abi::{ + error::Error, + process::{ProcessGroupId, Signal}, +}; pub struct ArchitectureImpl; @@ -171,6 +174,6 @@ impl TaskContext } #[no_mangle] -extern "Rust" fn __signal_process_group(_group_id: u32, _signal: Signal) { +extern "Rust" fn __signal_process_group(_group_id: ProcessGroupId, _signal: Signal) { unimplemented!() } diff --git a/kernel/lib/vfs/src/pty.rs b/kernel/lib/vfs/src/pty.rs index 597360a5..60e828ad 100644 --- a/kernel/lib/vfs/src/pty.rs +++ b/kernel/lib/vfs/src/pty.rs @@ -19,7 +19,7 @@ use yggdrasil_abi::{ DeviceRequest, TerminalInputOptions, TerminalLineOptions, TerminalOptions, TerminalOutputOptions, TerminalSize, }, - process::{ProcessId, Signal}, + process::{ProcessGroupId, Signal}, }; const CAPACITY: usize = 8192; @@ -38,7 +38,7 @@ struct PtyMasterToSlaveHalf { // Actual data to be read by the slave buffer: IrqSafeSpinlock, ready_ring: LossyRingQueue, - signal_pgroup: IrqSafeRwLock>, + signal_pgroup: IrqSafeRwLock>, } /// Pseudo-terminal shared device diff --git a/kernel/libk/libk-thread/src/binary/mod.rs b/kernel/libk/libk-thread/src/binary/mod.rs index 8a2fae24..1e9f5a31 100644 --- a/kernel/libk/libk-thread/src/binary/mod.rs +++ b/kernel/libk/libk-thread/src/binary/mod.rs @@ -18,7 +18,7 @@ use yggdrasil_abi::{ io::SeekFrom, pass::{Place, Placer}, path::Path, - process::ProgramArgumentInner, + process::{ProcessGroupId, ProgramArgumentInner}, }; use crate::{ @@ -170,6 +170,7 @@ fn setup_context( fn setup_binary( name: S, + group_id: ProcessGroupId, parent: Option>>, space: ProcessAddressSpace, image: ProcessImage, @@ -182,8 +183,14 @@ where IO: ProcessIo, { let context = setup_context(&space, &image, args, envs)?; - let (process, main) = - ProcessImpl::new_with_main(name, parent, Arc::new(space), context, Some(image)); + let (process, main) = ProcessImpl::new_with_main( + name, + group_id, + parent, + Arc::new(space), + context, + Some(image), + ); Ok((process, main)) } @@ -237,6 +244,7 @@ fn xxx_load_program>( /// Loads a program from given `path` pub fn load( source: &mut PS, + group_id: ProcessGroupId, parent: Option>>, path: P, args: &[&str], @@ -254,7 +262,7 @@ where let space = ProcessAddressSpace::new()?; let (image, args, envs) = xxx_load_program(&space, source, path, args, envs)?; - setup_binary(path.display(), parent, space, image, &args, &envs) + setup_binary(path.display(), group_id, parent, space, image, &args, &envs) } pub fn load_into( diff --git a/kernel/libk/libk-thread/src/lib.rs b/kernel/libk/libk-thread/src/lib.rs index fe3c5503..43a4debb 100644 --- a/kernel/libk/libk-thread/src/lib.rs +++ b/kernel/libk/libk-thread/src/lib.rs @@ -16,10 +16,10 @@ use kernel_arch::{Architecture, ArchitectureImpl, KernelTableManagerImpl}; use libk_mm::phys::GlobalPhysicalAllocator; pub(crate) mod api { - use yggdrasil_abi::process::{ProcessId, Signal}; + use yggdrasil_abi::process::{ProcessGroupId, Signal}; extern "Rust" { - pub fn __signal_process_group(group_id: ProcessId, signal: Signal); + pub fn __signal_process_group(group_id: ProcessGroupId, signal: Signal); } } @@ -41,7 +41,7 @@ pub type TaskContextImpl = use sched::CpuQueue; pub use types::{AtomicThreadState, ThreadAffinity, ThreadId, ThreadState}; -use yggdrasil_abi::process::{ProcessId, Signal}; +use yggdrasil_abi::process::{ProcessGroupId, Signal}; /// Returns local CPU index #[inline] @@ -53,6 +53,6 @@ pub fn cpu_count() -> usize { ArchitectureImpl::cpu_count() } -pub fn signal_process_group(group_id: ProcessId, signal: Signal) { +pub fn signal_process_group(group_id: ProcessGroupId, signal: Signal) { unsafe { __signal_process_group(group_id, signal) } } diff --git a/kernel/libk/libk-thread/src/process.rs b/kernel/libk/libk-thread/src/process.rs index 4b041253..15c75192 100644 --- a/kernel/libk/libk-thread/src/process.rs +++ b/kernel/libk/libk-thread/src/process.rs @@ -1,4 +1,7 @@ -use core::marker::PhantomData; +use core::{ + marker::PhantomData, + sync::atomic::{AtomicU32, Ordering}, +}; use abi_lib::SyscallRegister; use alloc::{ @@ -19,7 +22,7 @@ use libk_util::{ }; use yggdrasil_abi::{ error::Error, - process::{ExitCode, ProcessId, Signal, ThreadSpawnOptions}, + process::{ExitCode, ProcessGroupId, ProcessId, Signal, ThreadSpawnOptions}, }; use crate::{ @@ -69,7 +72,7 @@ pub struct ProcessImage { pub struct ProcessInner { session_id: ProcessId, - group_id: ProcessId, + group_id: ProcessGroupId, session_terminal: Option>, threads: Vec>, @@ -140,6 +143,7 @@ impl, IO: ProcessIo> ProcessImpl { /// Creates a new process with given main thread pub fn new_with_main>( name: S, + group_id: ProcessGroupId, parent: Option>, space: Arc, context: TaskContextImpl, @@ -153,7 +157,7 @@ impl, IO: ProcessIo> ProcessImpl { id, parent, - inner: IrqSafeRwLock::new(ProcessInner::new(id, Some(space.clone()), image)), + inner: IrqSafeRwLock::new(ProcessInner::new(id, group_id, Some(space.clone()), image)), exit: OneTimeEvent::new(), io: IrqSafeSpinlock::new(IO::new()), @@ -170,6 +174,13 @@ impl, IO: ProcessIo> ProcessImpl { (process, thread) } + pub fn create_group() -> ProcessGroupId { + static ID: AtomicU32 = AtomicU32::new(1); + let id = ID.fetch_add(1, Ordering::AcqRel); + + unsafe { ProcessGroupId::from_raw(id) } + } + /// Spawns a new child thread within the process pub fn spawn_thread(self: &Arc, options: &ThreadSpawnOptions) -> Result { log::debug!( @@ -216,6 +227,7 @@ impl, IO: ProcessIo> ProcessImpl { let (new_process, new_main) = Self::new_with_main( self.name(), + self.group_id(), Some(Arc::downgrade(self)), Arc::new(new_space), new_context, @@ -282,7 +294,7 @@ impl, IO: ProcessIo> ProcessImpl { } /// Returns the process group ID of the process - pub fn group_id(&self) -> ProcessId { + pub fn group_id(&self) -> ProcessGroupId { self.inner.read().group_id } @@ -292,7 +304,7 @@ impl, IO: ProcessIo> ProcessImpl { } /// Changes the process's group ID - pub fn set_group_id(&self, id: ProcessId) { + pub fn set_group_id(&self, id: ProcessGroupId) { self.inner.write().group_id = id; } @@ -359,7 +371,7 @@ impl, IO: ProcessIo> ProcessImpl { } /// Raises a signal for the specified process group - pub fn signal_group(group_id: ProcessId, signal: Signal) { + pub fn signal_group(group_id: ProcessGroupId, signal: Signal) { PM::for_each(|_, proc| { let inner = proc.inner.read(); if !proc.has_exited() && inner.group_id == group_id { @@ -397,12 +409,13 @@ impl, IO: ProcessIo> ProcessImpl { impl ProcessInner { pub fn new( id: ProcessId, + group_id: ProcessGroupId, space: Option>, image: Option, ) -> Self { Self { session_id: id, - group_id: id, + group_id, session_terminal: None, threads: Vec::new(), diff --git a/kernel/src/device/tty.rs b/kernel/src/device/tty.rs index c213adc3..3fe70b21 100644 --- a/kernel/src/device/tty.rs +++ b/kernel/src/device/tty.rs @@ -8,7 +8,7 @@ use core::{ use abi::{ error::Error, io::{TerminalInputOptions, TerminalLineOptions, TerminalOptions, TerminalOutputOptions}, - process::{ProcessId, Signal}, + process::{ProcessGroupId, Signal}, }; use device_api::serial::SerialDevice; use futures_util::Future; @@ -83,7 +83,7 @@ impl TerminalRing { struct TtyContextInner { config: TerminalOptions, - process_group: Option, + process_group: Option, } /// Represents the context of a terminal device @@ -99,7 +99,7 @@ pub trait TtyDevice: SerialDevice { fn context(&self) -> &TtyContext; /// Sets the process group to which signals from this terminal should be delivered - fn set_signal_group(&self, id: ProcessId) { + fn set_signal_group(&self, id: ProcessGroupId) { self.context().inner.lock().process_group.replace(id); } diff --git a/kernel/src/init.rs b/kernel/src/init.rs index 22190535..6630ecec 100644 --- a/kernel/src/init.rs +++ b/kernel/src/init.rs @@ -11,7 +11,7 @@ use vfs::{impls::FnSymlink, IoContext, NodeRef}; use crate::{ fs::{FileBlockAllocator, INITRD_DATA}, proc::{self, random}, - task::process::ProcessManagerImpl, + task::process::{ProcessImpl, ProcessManagerImpl}, }; fn setup_root() -> Result { @@ -67,8 +67,9 @@ pub fn kinit() -> Result<(), Error> { let mut ioctx = IoContext::new(root); { + let group_id = ProcessImpl::create_group(); let (user_init, user_init_main) = - proc::load_binary(&mut ioctx, None, "/init", &["/init", "xxx"], &[])?; + proc::load_binary(&mut ioctx, group_id, None, "/init", &["/init", "xxx"], &[])?; let mut io = user_init.io.lock(); io.set_ioctx(ioctx); diff --git a/kernel/src/proc/mod.rs b/kernel/src/proc/mod.rs index daf65ad4..27934eee 100644 --- a/kernel/src/proc/mod.rs +++ b/kernel/src/proc/mod.rs @@ -1,6 +1,6 @@ //! Internal management for processes -use abi::{error::Error, path::Path}; +use abi::{error::Error, path::Path, process::ProcessGroupId}; use alloc::sync::{Arc, Weak}; use libk_thread::thread::Thread; use vfs::IoContext; @@ -14,10 +14,11 @@ pub mod random; #[inline] pub fn load_binary>( ioctx: &mut IoContext, + group_id: ProcessGroupId, parent: Option>, path: P, args: &[&str], envs: &[&str], ) -> Result<(Arc, Arc), Error> { - libk_thread::binary::load(ioctx, parent, path, args, envs) + libk_thread::binary::load(ioctx, group_id, parent, path, args, envs) } diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index e1ecdbd0..273d59d2 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -54,7 +54,7 @@ mod impls { }; use abi::{ io::ChannelPublisherId, - process::{ExecveOptions, ProcessId, SpawnOption}, + process::{ExecveOptions, ProcessGroupId, ProcessId, SpawnOption}, }; use alloc::{boxed::Box, sync::Arc}; use libk::{block, runtime}; @@ -81,7 +81,7 @@ mod impls { debug::LogLevel, fs, proc::{self, random}, - task::process::ProcessManagerImpl, + task::process::{ProcessImpl, ProcessManagerImpl}, }; use super::{run_with_io, run_with_io_at}; @@ -175,6 +175,18 @@ mod impls { } // Process/thread management + pub(crate) fn create_process_group() -> ProcessGroupId { + let id = ProcessImpl::create_group(); + log::info!("CREATED PROCESS GROUP {}", id); + id + } + + pub(crate) fn get_process_group_id() -> ProcessGroupId { + let thread = Thread::current(); + let process = thread.process::(); + process.group_id() + } + pub(crate) fn exit_process(code: ExitCode) -> ! { let thread = Thread::current(); thread.exit_process::(code) @@ -188,6 +200,7 @@ mod impls { // Setup a new process from the file let (child_process, child_main) = proc::load_binary( io.ioctx_mut(), + process.group_id(), Some(Arc::downgrade(&process)), options.program, options.arguments, @@ -213,7 +226,7 @@ mod impls { } &SpawnOption::SetProcessGroup(pgroup) => { let pgroup = if pgroup.into_raw() == 0 { - child_process.id() + todo!() } else { pgroup }; @@ -261,11 +274,10 @@ mod impls { process.id() } - pub(crate) fn nanosleep(duration: &Duration) { + pub(crate) fn nanosleep(duration: &Duration) -> Result<(), Error> { block! { runtime::sleep(*duration).await } - .unwrap(); } pub(crate) fn set_signal_entry(ip: usize, sp: usize) { @@ -311,8 +323,10 @@ mod impls { }); } + let group_id = ProcessImpl::create_group(); + process.set_session_id(process.id()); - process.set_group_id(process.id()); + process.set_group_id(group_id); Ok(()) } diff --git a/kernel/src/task/process.rs b/kernel/src/task/process.rs index d069fe5b..9459380a 100644 --- a/kernel/src/task/process.rs +++ b/kernel/src/task/process.rs @@ -1,6 +1,6 @@ //! Process data structures -use abi::process::{ProcessId, Signal}; +use abi::process::{ProcessGroupId, ProcessId, Signal}; use alloc::{collections::BTreeMap, sync::Arc}; use libk_thread::process::{Process, ProcessManager}; use libk_util::sync::spin_rwlock::IrqSafeRwLock; @@ -40,6 +40,6 @@ impl ProcessManager for ProcessManagerImpl { } #[no_mangle] -fn __signal_process_group(group_id: ProcessId, signal: Signal) { +fn __signal_process_group(group_id: ProcessGroupId, signal: Signal) { ProcessImpl::signal_group(group_id, signal) } diff --git a/lib/abi/def/yggdrasil.abi b/lib/abi/def/yggdrasil.abi index dcd49aba..478f2d82 100644 --- a/lib/abi/def/yggdrasil.abi +++ b/lib/abi/def/yggdrasil.abi @@ -52,12 +52,15 @@ syscall map_memory(hint: Option, len: usize, source: &MappingSourc syscall unmap_memory(address: usize, len: usize) -> Result<()>; // Process/thread management +syscall create_process_group() -> ProcessGroupId; +syscall get_process_group_id() -> ProcessGroupId; + syscall exit_process(code: ExitCode) -> !; syscall spawn_process(options: &SpawnOptions<'_>) -> Result; syscall wait_process(pid: ProcessId, status: &mut ExitCode) -> Result<()>; syscall get_pid() -> ProcessId; -syscall nanosleep(dur: &Duration); +syscall nanosleep(dur: &Duration) -> Result<()>; syscall exit_signal(frame: &SignalEntryData) -> !; syscall set_signal_entry(ip: usize, sp: usize); diff --git a/lib/abi/src/io/device.rs b/lib/abi/src/io/device.rs index 20932515..0a647619 100644 --- a/lib/abi/src/io/device.rs +++ b/lib/abi/src/io/device.rs @@ -1,6 +1,6 @@ use core::mem::MaybeUninit; -use crate::generated::ProcessId; +use crate::generated::ProcessGroupId; use super::terminal; @@ -19,7 +19,7 @@ pub enum DeviceRequest { /// Return the terminal's size GetTerminalSize(MaybeUninit), /// Sets a foreground process group ID for the terminal - SetTerminalGroup(ProcessId), + SetTerminalGroup(ProcessGroupId), /// "Acquires" ownership of the device, preventing others from accessing it AcquireDevice, /// "Releases" ownership of the device diff --git a/lib/abi/src/process/mod.rs b/lib/abi/src/process/mod.rs index a6adcc0c..a4623eec 100644 --- a/lib/abi/src/process/mod.rs +++ b/lib/abi/src/process/mod.rs @@ -10,7 +10,8 @@ use crate::{ mod exit; pub use crate::generated::{ - ExecveOptions, ProcessId, Signal, SignalEntryData, SpawnOptions, ThreadId, ThreadSpawnOptions, + ExecveOptions, ProcessGroupId, ProcessId, Signal, SignalEntryData, SpawnOptions, ThreadId, + ThreadSpawnOptions, }; pub use exit::ExitCode; @@ -25,7 +26,7 @@ pub enum SpawnOption { child: RawFd, }, /// The new process should be placed in the specified group - SetProcessGroup(ProcessId), + SetProcessGroup(ProcessGroupId), /// Gain terminal control for the given FD GainTerminal(RawFd), } @@ -70,3 +71,9 @@ impl fmt::Display for ProcessId { write!(f, "", self.0) } } + +impl fmt::Display for ProcessGroupId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "", self.0) + } +} diff --git a/lib/runtime/src/process.rs b/lib/runtime/src/process.rs index 267c532e..e9996838 100644 --- a/lib/runtime/src/process.rs +++ b/lib/runtime/src/process.rs @@ -1,6 +1,7 @@ //! Process management data types pub use abi::process::{ - ExecveOptions, ExitCode, MutexOperation, ProcessId, ProcessInfoElement, ProgramArgumentInner, - Signal, SignalEntryData, SpawnOption, SpawnOptions, ThreadId, ThreadSpawnOptions, + ExecveOptions, ExitCode, MutexOperation, ProcessGroupId, ProcessId, ProcessInfoElement, + ProgramArgumentInner, Signal, SignalEntryData, SpawnOption, SpawnOptions, ThreadId, + ThreadSpawnOptions, }; diff --git a/lib/runtime/src/sys/mod.rs b/lib/runtime/src/sys/mod.rs index b3fe65eb..8efd3952 100644 --- a/lib/runtime/src/sys/mod.rs +++ b/lib/runtime/src/sys/mod.rs @@ -18,7 +18,9 @@ mod generated { }, mem::MappingSource, net::SocketType, - process::{ExecveOptions, ProcessId, Signal, SignalEntryData, SpawnOptions}, + process::{ + ExecveOptions, ProcessGroupId, ProcessId, Signal, SignalEntryData, SpawnOptions, + }, SyscallFunction, }; diff --git a/userspace/shell/src/main.rs b/userspace/shell/src/main.rs index 7fa69bff..e1f89109 100644 --- a/userspace/shell/src/main.rs +++ b/userspace/shell/src/main.rs @@ -1,4 +1,4 @@ -#![cfg_attr(not(unix), feature(yggdrasil_os))] +#![cfg_attr(not(unix), feature(yggdrasil_os, rustc_private))] use std::{ collections::HashMap, @@ -7,7 +7,7 @@ use std::{ io::{self, stdin, stdout, BufRead, BufReader, Stdin, Write}, os::fd::{FromRawFd, IntoRawFd, OwnedFd}, path::Path, - process::{ExitCode, Stdio}, + process::{Child, ExitCode, Stdio}, }; use clap::Parser; @@ -36,6 +36,22 @@ pub enum Outcome { ExitShell(ExitCode), } +pub struct PipelineElement<'a> { + pub command: &'a str, + pub args: &'a [String], + pub input: Stdio, + pub output: Stdio, +} + +pub struct Pipeline<'a> { + pub elements: Vec>, + pub env: &'a HashMap, +} + +pub struct SpawnedPipeline { + pub children: Vec, +} + pub enum Input { Interactive(Stdin), File(BufReader), @@ -95,7 +111,6 @@ pub fn exec( let mut inputs = vec![]; let mut outputs = vec![]; - let mut children = vec![]; let mut pipe_fds = vec![]; inputs.push(Stdio::inherit()); @@ -118,31 +133,39 @@ pub fn exec( assert_eq!(inputs.len(), outputs.len()); assert_eq!(inputs.len(), pipeline.len()); + let mut elements = vec![]; let ios = inputs.drain(..).zip(outputs.drain(..)); + for (command, (input, output)) in pipeline.iter().zip(ios) { let (cmd, args) = command.words.split_first().unwrap(); - let child = sys::exec_binary(interactive, cmd, args, env, input, output)?; + let element = PipelineElement { + command: cmd, + args, + input, + output, + }; - children.push(child); + elements.push(element); } + let pipeline = Pipeline { elements, env }; + let pipeline = sys::spawn_pipeline(interactive, pipeline)?; + drop(pipe_fds); - for mut child in children.drain(..) { - let status = child.wait()?; + let status = sys::wait_for_pipeline(interactive, pipeline)?; - if !status.success() { - return Ok(Outcome::from(status)); - } - } - - Ok(Outcome::ok()) + Ok(status) } fn run(mut input: Input, vars: &mut HashMap) -> io::Result { let mut line = String::new(); + if input.is_interactive() { + sys::init_signal_handler(); + } + let code = loop { line.clear(); @@ -171,8 +194,7 @@ fn run(mut input: Input, vars: &mut HashMap) -> io::Result code % 256, Err(e) => { - // TODO stringify the command back - eprintln!(": {}", e); + eprintln!("{}: {}", line, e); 127 } }; diff --git a/userspace/shell/src/sys/yggdrasil.rs b/userspace/shell/src/sys/yggdrasil.rs index 263bad7f..fc339a80 100644 --- a/userspace/shell/src/sys/yggdrasil.rs +++ b/userspace/shell/src/sys/yggdrasil.rs @@ -1,41 +1,76 @@ -use std::os::yggdrasil::io::pipe; +use std::os::yggdrasil::{ + io::{ + device::{DeviceRequest, FdDeviceRequest}, + pipe, + }, + process::{self, CommandExt, ExitStatusExt, ProcessGroupId}, + signal::{set_signal_handler, Signal, SignalHandler}, +}; use std::{ - collections::HashMap, - io, + io::{self, stdin}, os::fd::OwnedFd, - process::{Child, Command, ExitStatus, Stdio}, + process::{Command, ExitStatus}, }; -use crate::Outcome; +use crate::{Outcome, Pipeline, SpawnedPipeline}; pub struct Pipe { pub read: OwnedFd, pub write: OwnedFd, } -pub fn exec_binary( +fn set_terminal_group(group_id: ProcessGroupId) -> Result<(), io::Error> { + unsafe { stdin().device_request(&mut DeviceRequest::SetTerminalGroup(group_id)) } +} + +pub fn spawn_pipeline( interactive: bool, - binary: &str, - args: &[String], - env: &HashMap, - input: Stdio, - output: Stdio, -) -> Result { - use std::os::yggdrasil::process::CommandExt; - let mut command = Command::new(binary); - let mut command = command - .args(args) - .envs(env.iter()) - .stdin(input) - .stdout(output); + pipeline: Pipeline<'_>, +) -> Result { + let group_id = process::create_process_group(); if interactive { - unsafe { - command = command.process_group_raw(0); + set_terminal_group(group_id)?; + } + + let mut children = vec![]; + for element in pipeline.elements { + let mut command = Command::new(element.command); + command + .args(element.args) + .envs(pipeline.env.iter()) + .stdin(element.input) + .stdout(element.output) + .process_group(group_id); + + children.push(command.spawn()?); + } + + Ok(SpawnedPipeline { children }) +} + +pub fn wait_for_pipeline( + interactive: bool, + mut pipeline: SpawnedPipeline, +) -> Result { + let self_group_id = process::group_id(); + + for mut child in pipeline.children.drain(..) { + let status = child.wait()?; + + if !status.success() { + if interactive { + set_terminal_group(self_group_id).ok(); + } + return Ok(Outcome::from(status)); } } - command.spawn() + if interactive { + set_terminal_group(self_group_id).ok(); + } + + Ok(Outcome::ok()) } pub fn create_pipe() -> Result { @@ -43,10 +78,16 @@ pub fn create_pipe() -> Result { Ok(Pipe { read, write }) } +fn signal_handler(_sig: Signal) { + println!(); +} + +pub fn init_signal_handler() { + set_signal_handler(Signal::Interrupted, SignalHandler::Function(signal_handler)); +} + impl From for Outcome { fn from(value: ExitStatus) -> Self { - use std::os::yggdrasil::process::ExitStatusExt; - if let Some(code) = value.code() { Self::Exited(code) } else if let Some(sig) = value.signal() { diff --git a/userspace/sysutils/src/cat.rs b/userspace/sysutils/src/cat.rs index 7b4870a1..3e367e6d 100644 --- a/userspace/sysutils/src/cat.rs +++ b/userspace/sysutils/src/cat.rs @@ -1,14 +1,14 @@ use std::{ env, - fs::File, - io::{self, stdout, BufReader, Read, Stdout, Write}, - path::Path, + io::{self, stdout, Read, Stdout, Write}, process::ExitCode, }; -fn cat_file>(stdout: &mut Stdout, path: P) -> io::Result<()> { +use sysutils::Input; + +fn cat_file(stdout: &mut Stdout, path: &str) -> io::Result<()> { let mut buf = [0; 4096]; - let mut reader = BufReader::new(File::open(path)?); + let mut reader = Input::open_str(path)?; loop { let count = reader.read(&mut buf)?; @@ -25,11 +25,20 @@ fn main() -> ExitCode { let mut stdout = stdout(); let mut exit = ExitCode::SUCCESS; - for arg in env::args().skip(1) { - if let Err(error) = cat_file(&mut stdout, &arg) { - eprintln!("{}: {}", arg, error); + let args = env::args().skip(1); + + if args.len() == 0 { + if let Err(error) = cat_file(&mut stdout, "-") { + eprintln!("{}: {}", "", error); exit = ExitCode::FAILURE; } + } else { + for arg in env::args().skip(1) { + if let Err(error) = cat_file(&mut stdout, &arg) { + eprintln!("{}: {}", arg, error); + exit = ExitCode::FAILURE; + } + } } exit diff --git a/userspace/sysutils/src/login.rs b/userspace/sysutils/src/login.rs index d5d97da6..c22f4c30 100644 --- a/userspace/sysutils/src/login.rs +++ b/userspace/sysutils/src/login.rs @@ -70,9 +70,9 @@ fn main() -> ExitCode { // "Attach" the terminal unsafe { - let pid = std::os::yggdrasil::process::id_ext(); + let group_id = std::os::yggdrasil::process::group_id(); stdin() - .device_request(&mut DeviceRequest::SetTerminalGroup(pid)) + .device_request(&mut DeviceRequest::SetTerminalGroup(group_id)) .expect("Could not attach the terminal"); } diff --git a/userspace/term/src/main.rs b/userspace/term/src/main.rs index e9444b89..0ed7939e 100644 --- a/userspace/term/src/main.rs +++ b/userspace/term/src/main.rs @@ -6,6 +6,7 @@ use std::{ os::{ fd::{AsRawFd, FromRawFd, RawFd}, yggdrasil::{ + self, io::{ device::{DeviceRequest, FdDeviceRequest}, poll::PollChannel, @@ -262,13 +263,14 @@ impl<'a> Terminal<'a> { poll.add(pty_master_fd)?; let pty_slave_fd = pty_slave.as_raw_fd(); + let group_id = yggdrasil::process::create_process_group(); let shell = unsafe { Command::new("/bin/sh") .arg("-l") .stdin(Stdio::from_raw_fd(pty_slave_fd)) .stdout(Stdio::from_raw_fd(pty_slave_fd)) .stderr(Stdio::from_raw_fd(pty_slave_fd)) - .process_group_raw(0) + .process_group(group_id) .gain_terminal(0) .spawn()? };