Skip to content

Commit ba7a0c8

Browse files
authored
Merge pull request #387 from grisenti/sh
implement sh
2 parents 0c321b0 + 92b36f6 commit ba7a0c8

File tree

276 files changed

+22899
-230
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

276 files changed

+22899
-230
lines changed

Cargo.lock

Lines changed: 397 additions & 230 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ members = [
2020
"process",
2121
"sccs",
2222
"screen",
23+
"sh",
2324
"sys",
2425
"text",
2526
"tree",

sh/Cargo.toml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[package]
2+
name = "posixutils-sh"
3+
version = "0.1.7"
4+
edition = "2021"
5+
6+
[dependencies]
7+
plib = { path = "../plib" }
8+
gettext-rs.workspace = true
9+
nix = { version = "0.29", features = ["process", "fs", "resource", "signal", "user", "term"] }
10+
atty = "0.2"
11+
12+
[[bin]]
13+
name = "sh"
14+
path = "src/main.rs"

sh/src/builtin/alias.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//
2+
// Copyright (c) 2024 Hemi Labs, Inc.
3+
//
4+
// This file is part of the posixutils-rs project covered under
5+
// the MIT License. For the full license text, please see the LICENSE
6+
// file in the root directory of this project.
7+
// SPDX-License-Identifier: MIT
8+
//
9+
10+
use crate::builtin::{BuiltinResult, BuiltinUtility};
11+
use crate::shell::opened_files::OpenedFiles;
12+
use crate::shell::Shell;
13+
14+
pub struct AliasBuiltin;
15+
16+
impl BuiltinUtility for AliasBuiltin {
17+
fn exec(
18+
&self,
19+
args: &[String],
20+
shell: &mut Shell,
21+
opened_files: &mut OpenedFiles,
22+
) -> BuiltinResult {
23+
if args.is_empty() {
24+
for (alias, command) in &shell.alias_table {
25+
opened_files.write_out(format!("alias {}='{}'", alias, command));
26+
}
27+
return Ok(0);
28+
}
29+
30+
for arg in args {
31+
if let Some(eq_pos) = arg.find('=') {
32+
let (alias, command) = arg.split_at(eq_pos);
33+
let command = &command[1..];
34+
shell
35+
.alias_table
36+
.insert(alias.to_string(), command.to_string());
37+
} else if let Some(command) = shell.alias_table.get(arg) {
38+
opened_files.write_out(format!("alias {}='{}'", arg, command));
39+
} else {
40+
return Err(format!("alias: {}: not found", arg).into());
41+
}
42+
}
43+
Ok(0)
44+
}
45+
}

sh/src/builtin/bg.rs

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
//
2+
// Copyright (c) 2024 Hemi Labs, Inc.
3+
//
4+
// This file is part of the posixutils-rs project covered under
5+
// the MIT License. For the full license text, please see the LICENSE
6+
// file in the root directory of this project.
7+
// SPDX-License-Identifier: MIT
8+
//
9+
10+
use crate::builtin::{skip_option_terminator, BuiltinResult, BuiltinUtility};
11+
use crate::jobs::{parse_job_id, Job, JobState};
12+
use crate::shell::opened_files::OpenedFiles;
13+
use crate::shell::Shell;
14+
use nix::sys::signal::kill;
15+
16+
fn run_background_job(
17+
arg: &str,
18+
job: &mut Job,
19+
opened_files: &mut OpenedFiles,
20+
) -> Result<(), String> {
21+
if job.state != JobState::Stopped {
22+
return Err(format!(
23+
"bg: job {arg} is already running in the background"
24+
));
25+
}
26+
kill(job.pid, nix::sys::signal::SIGCONT)
27+
.map_err(|err| format!("bg: failed to resume job {arg} ({err})"))?;
28+
opened_files.write_out(format!("[{}] {}\n", job.number, job.command));
29+
job.state = JobState::Running;
30+
Ok(())
31+
}
32+
pub struct Bg;
33+
34+
impl BuiltinUtility for Bg {
35+
fn exec(
36+
&self,
37+
args: &[String],
38+
shell: &mut Shell,
39+
opened_files: &mut OpenedFiles,
40+
) -> BuiltinResult {
41+
if !shell.set_options.monitor {
42+
return Err("bg: cannot use bg when job control is disabled".into());
43+
}
44+
if !shell.is_interactive {
45+
return Err("bg: cannot use bg in a non-interactive shell".into());
46+
}
47+
if shell.is_subshell {
48+
return Err("bg: cannot use bg in a subshell environment".into());
49+
}
50+
51+
let mut status = 0;
52+
let args = skip_option_terminator(args);
53+
if args.is_empty() {
54+
if let Some(job) = shell.background_jobs.current_mut() {
55+
if let Err(err) = run_background_job("current", job, opened_files) {
56+
opened_files.write_err(err);
57+
status = 1;
58+
}
59+
} else {
60+
opened_files.write_err("bg: no background jobs");
61+
status = 1;
62+
}
63+
} else {
64+
for arg in args {
65+
match parse_job_id(arg) {
66+
Ok(job_id) => {
67+
if let Some(job) = shell.background_jobs.get_job_mut(job_id) {
68+
if let Err(err) = run_background_job(arg, job, opened_files) {
69+
opened_files.write_err(err);
70+
status = 1;
71+
}
72+
} else {
73+
opened_files.write_err(format!("bg: '{arg}' no such job"));
74+
status = 1;
75+
}
76+
}
77+
Err(_) => {
78+
opened_files.write_err(format!("bg: '{arg}' no such job"));
79+
status = 1
80+
}
81+
}
82+
}
83+
}
84+
85+
Ok(status)
86+
}
87+
}

0 commit comments

Comments
 (0)