Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Changelog

## Unreleased
- Add pipe device file (#822)
- Fix potential deadlocks (#824)
- Reuse deleted dir entries (#820)
- Improve editor search (#817)
Expand Down
5 changes: 4 additions & 1 deletion doc/lisp.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ MOROS Lisp is a Lisp-1 dialect inspired by Scheme, Clojure, and Ruby!
- `string->binary` and `binary->string` (aliased to `str->bin` and `bin->str`)
- `number->binary` and `binary->number` (aliased to `num->bin` and `bin->num`)
- `regex/find`
- `shell` (aliased to `sh`)
- `shell` (aliased to `sh`) and `shell->binary` (aliased to `sh->bin`)
- `date`, `sleep`
- Arithmetic operations: `+`, `-`, `*`, `/`, `^`, `rem` (aliased to `%`), `trunc`
- Trigonometric functions: `acos`, `asin`, `atan`, `cos`, `sin`, `tan`
Expand All @@ -74,6 +74,7 @@ MOROS Lisp is a Lisp-1 dialect inspired by Scheme, Clojure, and Ruby!
- `not`, `and`, `or`
- `set`, `let`
- `string/join` (aliased to `str/join`), `lines`, `words`, `chars`
- `shell->string` (aliased to `sh->str`)
- `regex/match?`

### File Library
Expand Down Expand Up @@ -177,6 +178,8 @@ Would produce the following output:
## Changelog

### Unreleased
- Add `shell->binary` function (aliased to `sh->bin`)
- Add `shell->string` function (aliased to `sh->str`)
- Add dict support to `head`, `tail`, `length`, `empty?`, and `map`
- Add `push!` as the mutating counterpart of `push` for lists
- Add `put!` as the mutating counterpart of `put` for dicts
Expand Down
6 changes: 6 additions & 0 deletions dsk/lib/lisp/core.lsp
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,14 @@
(get ls
(if (= (length ls) 0) 0 (- (length ls) 1))))

(def (shell->string cmd)
"Returns the output of the command"
(string/trim (binary->string (shell->binary cmd))))

# Short aliases

(var sh->str shell->string)
(var sh->bin shell->binary)
(var sh shell)
(var $ shell)
(var % rem)
Expand Down
1 change: 1 addition & 0 deletions src/api/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ fn device_type(name: &str) -> Result<DeviceType, ()> {
"vga-palette" => Ok(DeviceType::VgaPalette),
"speaker" => Ok(DeviceType::Speaker),
"ata" => Ok(DeviceType::Drive),
"pipe" => Ok(DeviceType::Pipe),
_ => Err(()),
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/sys/fs/block_device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ impl BlockDeviceIO for MemBlockDevice {
}

pub fn mount_mem() {
let mem = sys::mem::memory_free() / 2;
let mem = sys::mem::memory_free() / 3;
let len = mem / super::BLOCK_SIZE; // TODO: take a size argument
let dev = MemBlockDevice::new(len);
*BLOCK_DEVICE.lock() = Some(BlockDevice::Mem(dev));
Expand Down
10 changes: 10 additions & 0 deletions src/sys/fs/device.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use super::block::LinkedBlock;
use super::dir::Dir;
use super::file::File;
use super::pipe::Pipe;
use super::{dirname, filename, realpath, FileIO, IO};

use crate::sys::ata::Drive;
Expand Down Expand Up @@ -43,6 +44,7 @@ pub enum DeviceType {
NetIp = 16,
NetMac = 17,
NetUsage = 18,
Pipe = 19,
}

impl TryFrom<&[u8]> for DeviceType {
Expand All @@ -69,6 +71,7 @@ impl TryFrom<&[u8]> for DeviceType {
16 => Ok(DeviceType::NetIp),
17 => Ok(DeviceType::NetMac),
18 => Ok(DeviceType::NetUsage),
19 => Ok(DeviceType::Pipe),
_ => Err(()),
}
}
Expand All @@ -94,6 +97,7 @@ impl DeviceType {
DeviceType::NetIp => NetIp::size(),
DeviceType::NetMac => NetMac::size(),
DeviceType::NetUsage => NetUsage::size(),
DeviceType::Pipe => Pipe::size(),
_ => 1,
};
let mut res = vec![0; len];
Expand Down Expand Up @@ -123,6 +127,7 @@ pub enum Device {
NetIp(NetIp),
NetMac(NetMac),
NetUsage(NetUsage),
Pipe(Pipe),
}

impl TryFrom<&[u8]> for Device {
Expand All @@ -148,6 +153,7 @@ impl TryFrom<&[u8]> for Device {
DeviceType::NetIp => Ok(Device::NetIp(NetIp::new())),
DeviceType::NetMac => Ok(Device::NetMac(NetMac::new())),
DeviceType::NetUsage => Ok(Device::NetUsage(NetUsage::new())),
DeviceType::Pipe => Ok(Device::Pipe(Pipe::new())),
DeviceType::Drive if buf.len() > 2 => {
let bus = buf[1];
let dsk = buf[2];
Expand Down Expand Up @@ -216,6 +222,7 @@ impl FileIO for Device {
Device::NetIp(io) => io.read(buf),
Device::NetMac(io) => io.read(buf),
Device::NetUsage(io) => io.read(buf),
Device::Pipe(io) => io.read(buf),
}
}

Expand All @@ -240,6 +247,7 @@ impl FileIO for Device {
Device::NetIp(io) => io.write(buf),
Device::NetMac(io) => io.write(buf),
Device::NetUsage(io) => io.write(buf),
Device::Pipe(io) => io.write(buf),
}
}

Expand All @@ -264,6 +272,7 @@ impl FileIO for Device {
Device::NetIp(io) => io.close(),
Device::NetMac(io) => io.close(),
Device::NetUsage(io) => io.close(),
Device::Pipe(io) => io.close(),
}
}

Expand All @@ -288,6 +297,7 @@ impl FileIO for Device {
Device::NetIp(io) => io.poll(event),
Device::NetMac(io) => io.poll(event),
Device::NetUsage(io) => io.poll(event),
Device::Pipe(io) => io.poll(event),
}
}
}
1 change: 1 addition & 0 deletions src/sys/fs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ mod device;
mod dir;
mod dir_entry;
mod file;
mod pipe;
mod read_dir;
mod super_block;

Expand Down
55 changes: 55 additions & 0 deletions src/sys/fs/pipe.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
use super::{FileIO, IO};

use alloc::sync::Arc;
//use alloc::rc::Rc;
use alloc::vec::Vec;
//use core::borrow::BorrowMut;
//use core::cell::RefCell;
use core::cmp;
use spin::Mutex;

#[derive(Debug, Clone)]
pub struct Pipe {
//buf: Rc<RefCell<Vec<u8>>>,
buf: Arc<Mutex<Vec<u8>>>,
}

impl Pipe {
pub fn new() -> Self {
Self {
//buf: Rc::new(RefCell::new(Vec::with_capacity(super::BLOCK_SIZE)))
buf: Arc::new(Mutex::new(Vec::with_capacity(super::BLOCK_SIZE)))
}
}

pub fn size() -> usize {
super::BLOCK_SIZE
}
}

impl FileIO for Pipe {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, ()> {
let mut pipe = self.buf.lock();
let n = cmp::min(buf.len(), pipe.len());
buf[..n].clone_from_slice(&pipe[..n]);
pipe.drain(..n);
Ok(n)
}

fn write(&mut self, buf: &[u8]) -> Result<usize, ()> {
let mut pipe = self.buf.lock();
pipe.extend_from_slice(buf);
Ok(buf.len())
}

fn close(&mut self) {
}

fn poll(&mut self, event: IO) -> bool {
let pipe = self.buf.lock();
match event {
IO::Read => !pipe.is_empty(),
IO::Write => true,
}
}
}
2 changes: 1 addition & 1 deletion src/sys/net/nic/e1000.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use crate::sys;
use crate::sys::mem::PhysBuf;
use crate::sys::net::{EthernetDeviceIO, Config, Stats};
use spin::Mutex;

use alloc::slice;
use alloc::sync::Arc;
Expand All @@ -10,6 +9,7 @@ use bit_field::BitField;
use core::ptr;
use core::sync::atomic::{AtomicUsize, Ordering};
use smoltcp::wire::EthernetAddress;
use spin::Mutex;
use x86_64::instructions::port::Port;
use x86_64::PhysAddr;

Expand Down
20 changes: 11 additions & 9 deletions src/usr/draw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::api::clock;
use crate::sys::console;
use crate::usr::shell;

use alloc::string::ToString;
use alloc::string::{String, ToString};
use alloc::format;
use alloc::vec::Vec;
use bit_field::BitField;
Expand Down Expand Up @@ -131,18 +131,20 @@ pub fn main(args: &[&str]) -> Result<(), ExitCode> {
if refresh {
start = clock::epoch_time();
let out = if let Some(cmd) = command {
let tmp = "/tmp/draw.tmp";
let cmd = format!("{} => {}", cmd, tmp);
if shell::exec(&cmd).is_err() {
if let Ok(buf) = shell::exec_to_bytes(&cmd) {
if let Ok(txt) = String::from_utf8(buf) {
txt.trim().to_string()
} else {
config.text_mode();
return Err(ExitCode::Failure);
}
} else {
config.text_mode();
return Err(ExitCode::Failure);
}
let res = fs::read_to_string(tmp).unwrap();
let _ = fs::delete(tmp);
res.trim().to_string()
} else {
if let Some(text) = text {
text.to_string()
if let Some(txt) = text {
txt.to_string()
} else {
help();
return Err(ExitCode::UsageError);
Expand Down
1 change: 1 addition & 0 deletions src/usr/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ pub fn copy_files(verbose: bool) {
create_dev("/dev/net/mac", "net-mac", verbose);
create_dev("/dev/net/usage", "net-usage", verbose);
create_dev("/dev/null", "null", verbose);
create_dev("/dev/pipe", "pipe", verbose);
create_dev("/dev/random", "random", verbose);
create_dev("/dev/speaker", "speaker", verbose);
create_dev("/dev/vga/buffer", "vga-buffer", verbose);
Expand Down
4 changes: 4 additions & 0 deletions src/usr/lisp/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ pub fn default_env() -> Rc<RefCell<Env>> {
"shell".to_string(),
Exp::Primitive(primitive::lisp_shell),
);
data.insert(
"shell->binary".to_string(),
Exp::Primitive(primitive::lisp_shell_binary),
);
data.insert(
"string".to_string(),
Exp::Primitive(primitive::lisp_string),
Expand Down
9 changes: 9 additions & 0 deletions src/usr/lisp/primitive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,15 @@ pub fn lisp_shell(args: &[Exp]) -> Result<Exp, Err> {
}
}

pub fn lisp_shell_binary(args: &[Exp]) -> Result<Exp, Err> {
ensure_length_gt!(args, 0);
let cmd = strings(args)?.join(" ");
let buf = shell::exec_to_bytes(&cmd).or(could_not!("execute command"))?;
Ok(Exp::List(
buf.iter().map(|b| Exp::Num(Number::from(*b))).collect()
))
}

pub fn lisp_string(args: &[Exp]) -> Result<Exp, Err> {
let args: Vec<String> = args.iter().map(|arg| match arg {
Exp::Str(s) => format!("{}", s),
Expand Down
43 changes: 41 additions & 2 deletions src/usr/shell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use crate::{api, sys, usr};
use alloc::collections::btree_map::BTreeMap;
use alloc::format;
use alloc::string::{String, ToString};
use alloc::vec;
use alloc::vec::Vec;
use core::sync::atomic::{fence, Ordering};

Expand Down Expand Up @@ -261,19 +262,30 @@ fn tilde_expansion(arg: &str) -> String {
fn variables_expansion(cmd: &str, config: &mut Config) -> String {
let mut cmd = cmd.to_string();

// Special cases for none alphanum (\w) variables
// Special cases for non alphanum (\w) variables
cmd = cmd.replace("$?", "$status");
cmd = cmd.replace("$*", "$1 $2 $3 $4 $5 $6 $7 $8 $9");

// Replace alphanum `$key` with its value in the environment
// or an empty string.
// or an empty string
let re = Regex::new("\\$\\w+");
while let Some((a, b)) = re.find(&cmd) {
let key: String = cmd.chars().skip(a + 1).take(b - a - 1).collect();
let val = config.env.get(&key).map_or("", String::as_str);
cmd = cmd.replace(&format!("${}", key), val);
}

// Replace `$(command)` with its captured output
let re = Regex::new("\\$(.*?)");
while let Some((a, b)) = re.find(&cmd) {
let sub: String = cmd.drain(a..b).skip(2).take(b - a - 3).collect();
if let Ok(buf) = exec_to_bytes(&sub) {
if let Ok(txt) = String::from_utf8(buf) {
cmd.insert_str(a, txt.trim());
}
}
}

cmd
}

Expand Down Expand Up @@ -661,6 +673,33 @@ pub fn exec(cmd: &str) -> Result<(), ExitCode> {
exec_with_config(cmd, &mut config)
}

pub fn exec_to_bytes(cmd: &str) -> Result<Vec<u8>, ExitCode> {
let pipe = "/dev/pipe";
let stdout = 1;
if let Some(info) = syscall::info(pipe) {
if info.is_device() {
if let Some(handle) = api::fs::open_device(pipe) {
syscall::dup(handle, stdout).ok();
exec(cmd)?;
api::fs::reopen("/dev/console", stdout, false).ok();
let n = info.size() as usize;
let mut buf = vec![0; n];
let mut res = Vec::new();
while let Some(bytes) = syscall::read(handle, &mut buf) {
if bytes == 0 {
break;
}
res.extend_from_slice(&buf[..bytes]);
}
syscall::close(handle);
return Ok(res);
}
}
}
error!("Could not open pipe");
Err(ExitCode::Failure)
}

pub fn main(args: &[&str]) -> Result<(), ExitCode> {
let mut config = Config::new();

Expand Down
Loading