11
Cargo.lock
generated
11
Cargo.lock
generated
@@ -1331,6 +1331,7 @@ dependencies = [
|
||||
"uu_nologin",
|
||||
"uu_renice",
|
||||
"uu_rev",
|
||||
"uu_setpgid",
|
||||
"uu_setsid",
|
||||
"uu_uuidgen",
|
||||
"uucore",
|
||||
@@ -1500,6 +1501,16 @@ dependencies = [
|
||||
"uucore",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uu_setpgid"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"libc",
|
||||
"nix",
|
||||
"uucore",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uu_setsid"
|
||||
version = "0.0.1"
|
||||
|
||||
@@ -42,6 +42,7 @@ feat_common_core = [
|
||||
"nologin",
|
||||
"renice",
|
||||
"rev",
|
||||
"setpgid",
|
||||
"setsid",
|
||||
"uuidgen",
|
||||
]
|
||||
@@ -106,6 +107,7 @@ mountpoint = { optional = true, version = "0.0.1", package = "uu_mountpoint", pa
|
||||
nologin = { optional = true, version = "0.0.1", package = "uu_nologin", path = "src/uu/nologin" }
|
||||
renice = { optional = true, version = "0.0.1", package = "uu_renice", path = "src/uu/renice" }
|
||||
rev = { optional = true, version = "0.0.1", package = "uu_rev", path = "src/uu/rev" }
|
||||
setpgid = { optional = true, version = "0.0.1", package = "uu_setpgid", path = "src/uu/setpgid" }
|
||||
setsid = { optional = true, version = "0.0.1", package = "uu_setsid", path ="src/uu/setsid" }
|
||||
uuidgen = { optional = true, version = "0.0.1", package = "uu_uuidgen", path ="src/uu/uuidgen" }
|
||||
|
||||
|
||||
17
src/uu/setpgid/Cargo.toml
Normal file
17
src/uu/setpgid/Cargo.toml
Normal file
@@ -0,0 +1,17 @@
|
||||
[package]
|
||||
name = "uu_setpgid"
|
||||
version = "0.0.1"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
path = "src/setpgid.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "setpgid"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
uucore = { workspace = true }
|
||||
clap = { workspace = true }
|
||||
libc = { workspace = true }
|
||||
nix = { workspace = true, features = ["process"] }
|
||||
7
src/uu/setpgid/setpgid.md
Normal file
7
src/uu/setpgid/setpgid.md
Normal file
@@ -0,0 +1,7 @@
|
||||
# setpgid
|
||||
|
||||
```
|
||||
setpgid [options] <program> [<argument>...]
|
||||
```
|
||||
|
||||
Run a program in a new process group
|
||||
1
src/uu/setpgid/src/main.rs
Normal file
1
src/uu/setpgid/src/main.rs
Normal file
@@ -0,0 +1 @@
|
||||
uucore::bin!(uu_setpgid);
|
||||
99
src/uu/setpgid/src/setpgid.rs
Normal file
99
src/uu/setpgid/src/setpgid.rs
Normal file
@@ -0,0 +1,99 @@
|
||||
// This file is part of the uutils util-linux package.
|
||||
//
|
||||
// For the full copyright and license information, please view the LICENSE
|
||||
// file that was distributed with this source code.
|
||||
|
||||
use clap::{crate_version, Arg, ArgAction, Command as ClapCommand};
|
||||
use uucore::{
|
||||
error::{UResult, USimpleError},
|
||||
format_usage, help_about, help_usage,
|
||||
};
|
||||
|
||||
const ABOUT: &str = help_about!("setpgid.md");
|
||||
const USAGE: &str = help_usage!("setpgid.md");
|
||||
|
||||
#[cfg(target_family = "unix")]
|
||||
#[uucore::main]
|
||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||
use std::ffi::CString;
|
||||
use std::fs::File;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
|
||||
let matches = uu_app().try_get_matches_from(args)?;
|
||||
|
||||
let remaining_args: Vec<String> = matches
|
||||
.get_many::<String>("args")
|
||||
.unwrap()
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
if unsafe { libc::setpgid(0, 0) } != 0 {
|
||||
return Err(USimpleError::new(
|
||||
1,
|
||||
format!(
|
||||
"failed to create new process group: {}",
|
||||
std::io::Error::last_os_error()
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
if matches.get_flag("foreground") {
|
||||
if let Ok(tty_file) = File::open("/dev/tty") {
|
||||
unsafe {
|
||||
libc::tcsetpgrp(tty_file.as_raw_fd(), libc::getpgrp());
|
||||
}
|
||||
}
|
||||
// According to strace open("/dev/tty") failure is ignored.
|
||||
}
|
||||
|
||||
let program = &remaining_args[0];
|
||||
let program_args = &remaining_args[1..];
|
||||
|
||||
// Command line arguments can't contain NUL bytes, so unwrap() is safe here.
|
||||
let program_cstr = CString::new(program.as_str()).unwrap();
|
||||
let mut argv = vec![program_cstr.clone()];
|
||||
for arg in program_args {
|
||||
argv.push(CString::new(arg.as_str()).unwrap());
|
||||
}
|
||||
|
||||
let Err(e) = nix::unistd::execvp(&program_cstr, &argv);
|
||||
Err(USimpleError::new(
|
||||
1,
|
||||
format!("failed to execute '{}': {}", program, e),
|
||||
))
|
||||
}
|
||||
|
||||
#[cfg(not(target_family = "unix"))]
|
||||
#[uucore::main]
|
||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||
let _matches: clap::ArgMatches = uu_app().try_get_matches_from(args)?;
|
||||
|
||||
Err(USimpleError::new(
|
||||
1,
|
||||
"`setpgid` is unavailable on non-UNIX-like platforms.",
|
||||
))
|
||||
}
|
||||
|
||||
pub fn uu_app() -> ClapCommand {
|
||||
ClapCommand::new(uucore::util_name())
|
||||
.version(crate_version!())
|
||||
.about(ABOUT)
|
||||
.override_usage(format_usage(USAGE))
|
||||
.infer_long_args(true)
|
||||
.arg(
|
||||
Arg::new("foreground")
|
||||
.short('f')
|
||||
.long("foreground")
|
||||
.help("Make a foreground process group")
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("args")
|
||||
.hide_short_help(true)
|
||||
.hide_long_help(true)
|
||||
.required(true)
|
||||
.action(ArgAction::Append)
|
||||
.num_args(1..)
|
||||
.trailing_var_arg(true),
|
||||
)
|
||||
}
|
||||
37
tests/by-util/test_setpgid.rs
Normal file
37
tests/by-util/test_setpgid.rs
Normal file
@@ -0,0 +1,37 @@
|
||||
// This file is part of the uutils util-linux package.
|
||||
//
|
||||
// For the full copyright and license information, please view the LICENSE
|
||||
// file that was distributed with this source code.
|
||||
|
||||
use regex::Regex;
|
||||
use uutests::new_ucmd;
|
||||
|
||||
#[test]
|
||||
#[cfg(target_family = "unix")]
|
||||
fn test_nonexistent_program() {
|
||||
new_ucmd!()
|
||||
.arg("does_not_exist")
|
||||
.fails()
|
||||
.stderr_contains("failed to execute");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_os = "linux")]
|
||||
fn test_pgid_changed() {
|
||||
let our_pgid = unsafe { libc::getpgid(0) };
|
||||
// Gets pgid of the 'cut' process from /proc
|
||||
new_ucmd!()
|
||||
.args(&["cut", "-d", " ", "-f", "5", "/proc/self/stat"])
|
||||
.succeeds()
|
||||
.stdout_does_not_match(&Regex::new(&format!("^{}$", our_pgid)).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_family = "unix")]
|
||||
fn test_flag_after_command() {
|
||||
new_ucmd!()
|
||||
.arg("echo")
|
||||
.arg("-f")
|
||||
.succeeds()
|
||||
.stdout_is("-f\n");
|
||||
}
|
||||
@@ -55,6 +55,10 @@ mod test_renice;
|
||||
#[path = "by-util/test_rev.rs"]
|
||||
mod test_rev;
|
||||
|
||||
#[cfg(feature = "setpgid")]
|
||||
#[path = "by-util/test_setpgid.rs"]
|
||||
mod test_setpgid;
|
||||
|
||||
#[cfg(feature = "setsid")]
|
||||
#[path = "by-util/test_setsid.rs"]
|
||||
mod test_setsid;
|
||||
|
||||
Reference in New Issue
Block a user