1 Commits

Author SHA1 Message Date
DTB
1c6e2970f7 retval(1) sans documentation 2024-07-23 17:58:49 -06:00
4 changed files with 45 additions and 165 deletions

View File

@@ -32,7 +32,7 @@ RUSTLIBS = --extern getopt=build/o/libgetopt.rlib \
CFLAGS += -I$(SYSEXITS)
.PHONY: all
all: dj false fop hru intcmp mm npc rpn run scrut str strcmp swab true
all: dj false fop hru intcmp mm npc retval rpn scrut str strcmp swab true
# keep build/include until bindgen(1) has stdin support
# https://github.com/rust-lang/rust-bindgen/issues/2703
@@ -122,16 +122,16 @@ npc: build/bin/npc
build/bin/npc: src/npc.c build
$(CC) $(CFLAGAS) -o $@ src/npc.c
.PHONY: retval
retval: build/bin/retval
build/bin/retval: src/retval.rs build rustlibs
$(RUSTC) $(RUSTFLAGS) $(RUSTLIBS) -o $@ src/retval.rs
.PHONY: rpn
rpn: build/bin/rpn
build/bin/rpn: src/rpn.rs build rustlibs
$(RUSTC) $(RUSTFLAGS) $(RUSTLIBS) -o $@ src/rpn.rs
.PHONY: run
run: build/bin/run
build/bin/run: src/run.rs build
$(RUSTC) $(RUSTFLAGS) $(RUSTLIBS) -o $@ src/run.rs
.PHONY: scrut
scrut: build/bin/scrut
build/bin/scrut: src/scrut.c build

View File

@@ -1,60 +0,0 @@
.\" Copyright (c) 20222024 DTB <trinity@trinity.moe>
.\"
.\" This work is licensed under CC BY-SA 4.0. To see a copy of this license,
.\" visit <http://creativecommons.org/licenses/by-sa/4.0/>.
.\"
.TH SIMEXEC 1 2024-07-24 "Harakit-overgrown X.X.X"
.SH NAME
run \(en execute a program
.\"
.SH SYNOPSIS
run
.B binary argument...
.\"
.SH DESCRIPTION
Execute a binary with arguments.
.\"
.SH CAVEATS
Non-binary programs cannot be executed on their own. The PATH environment
variable is not used and a valid pathname (relative or absolute) must be
specified.
While POSIX.1-2017 doesn't mandate there being an argv[0] per se, a Strictly
Conforming POSIX Application must pass an argv[0]. It has also been said that
those who do not pass an argv[0] are mean and nasty and smell of elderberries.
.\"
.SH DIAGNOSTICS
.BR run (1)
exits with the returned value of
.BR execv (3p),
which will be 255 if an error occurs in execution, such as the binary not being
found.
This is indistinguishable from the executed binary exiting with the same
status.
.BR run (1)
will print a error message and return the proper
.BR sysexits.h (3)
value if invoked in an invalid manner.
.\"
.SH AUTHOR
Written by DTB
.MT trinity@trinity.moe
.ME .
.\"
.SH COPYRIGHT
.\"
Copyright \(co 20222024 DTB. License AGPLv3+: GNU AGPL version 3 or later
<https://gnu.org/licenses/gpl.html>.
.\"
.SH SEE ALSO
.BR execv (3p)
The C89 standard's draft, section 2.1.2.2: "Hosted environment".
POSIX.1-2017 System Interfaces: execv. Particularly under the RATIONALE section
header.

39
src/retval.rs Normal file
View File

@@ -0,0 +1,39 @@
/*
* Copyright (c) 2024 DTB <trinity@trinity.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
use std::{ env::args, process::ExitCode };
extern crate sysexits;
use sysexits::EX_USAGE;
fn usage(s: &str) -> ExitCode {
eprintln!("Usage: {} status", s);
ExitCode::from(EX_USAGE)
}
fn main() -> ExitCode {
let argv = args().collect::<Vec<String>>();
match argv.len() {
2 => match argv[1].parse::<u8>() {
Ok(e) => ExitCode::from(e),
_ => usage(&argv[0])
},
_ => usage(&argv[0])
}
}

View File

@@ -1,99 +0,0 @@
/*
* Copyright (c) 20222024 DTB <trinity@trinity.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
use std::{
env::args,
io::Error,
os::unix::process::CommandExt,
process::{ Command, ExitCode }
};
extern crate getopt;
use getopt::GetOpt;
extern crate strerror;
use strerror::StrError;
extern crate sysexits;
use sysexits::{ EX_UNAVAILABLE, EX_USAGE };
fn error(p: &str, n: &str, e: Error) -> ExitCode {
eprintln!("{}: {}: {}", p, n, e.strerror());
ExitCode::from(EX_UNAVAILABLE as u8)
}
fn usage(s: &str) -> ExitCode {
eprintln!("Usage: {} command [argument...]", s);
ExitCode::from(EX_USAGE as u8)
}
fn main() -> ExitCode {
let argv = args().collect::<Vec<String>>();
let mut optind = 1;
/* arg0 is None if no argv[0] is meant to be given (argc will be 0),
* however I don't know how to do this in Rust, so the option is currently
* meaningless. -z will set this to None. */
let mut arg0: Option<String> = Some(String::default());
let mut dir = String::from("."); // $PWD for command
while let Some(opt) = argv.getopt("C:n:z") {
match opt.opt() {
// Consistent with precedent; git, make, tar, etc.
Ok("C") => dir = opt.arg().unwrap(),
Ok("n") => arg0 = Some(opt.arg().unwrap()),
// Ok("z") => arg0 = None,
_ => { return usage(&argv[0]); }
}
optind = opt.ind();
}
if argv.len() - optind < 1 { return usage(&argv[0]); }
let mut cmd = Command::new(argv[optind].clone());
cmd.current_dir(dir.clone());
match arg0 {
Some(a) if a != String::default() => { cmd.arg0(a); },
_ => () // TODO: argv[0]==NULL support
}
if argv.len() - optind > 1 { // there are arguments
let cmdargs = argv
.iter()
.clone()
.skip(optind + 1)
.collect::<Vec<&String>>();
cmd.args(cmdargs);
}
match cmd.spawn() {
Ok(mut child) => match child.wait() {
Ok(status) => match status.code() {
Some(code) => ExitCode::from(code as u8),
None => {
eprintln!("{}: {}: process terminated by signal",
argv[0], argv[2]);
ExitCode::FAILURE
}
},
Err(e) => error(&argv[0], &argv[optind], e)
},
Err(e) => error(&argv[0], &argv[optind], e)
}
}