linuxutils_system/
setpgid.rs1use linuxutils_common::man::ManContent;
2
3pub const MAN: ManContent = ManContent::empty();
4
5use clap::Parser;
6use rustix::{
7 process::{getpid, setpgid as do_setpgid},
8 termios::tcsetpgrp,
9};
10use std::{ffi::CString, process::ExitCode};
11
12#[derive(Parser)]
13#[command(
14 name = "setpgid",
15 version,
16 about = "Run a program in a new process group"
17)]
18pub struct Args {
19 #[arg(short = 'f', long = "foreground")]
21 foreground: bool,
22
23 #[arg(
25 trailing_var_arg = true,
26 allow_hyphen_values = true,
27 required = true
28 )]
29 pub command: Vec<String>,
30}
31
32pub fn run(args: Args) -> ExitCode {
33 let pid = getpid();
34
35 if let Err(e) = do_setpgid(Some(pid), Some(pid)) {
36 eprintln!("setpgid: setpgid: {e}");
37 return ExitCode::FAILURE;
38 }
39
40 if args.foreground {
41 let stderr = std::io::stderr();
42 if let Err(e) = tcsetpgrp(&stderr, pid) {
43 eprintln!("setpgid: tcsetpgrp: {e}");
44 return ExitCode::FAILURE;
45 }
46 }
47
48 let program = &args.command[0];
49 let arguments = &args.command[1..];
50 exec_program(program, arguments)
51}
52
53fn exec_program(program: &str, arguments: &[String]) -> ExitCode {
54 let c_program = match CString::new(program.as_bytes()) {
55 Ok(s) => s,
56 Err(e) => {
57 eprintln!("setpgid: {e}");
58 return ExitCode::FAILURE;
59 }
60 };
61
62 let mut c_args: Vec<CString> = vec![c_program.clone()];
63 for arg in arguments {
64 match CString::new(arg.as_bytes()) {
65 Ok(s) => c_args.push(s),
66 Err(e) => {
67 eprintln!("setpgid: {e}");
68 return ExitCode::FAILURE;
69 }
70 }
71 }
72
73 let c_ptrs: Vec<*const libc::c_char> = c_args
74 .iter()
75 .map(|s| s.as_ptr())
76 .chain(std::iter::once(std::ptr::null()))
77 .collect();
78
79 unsafe {
80 libc::execvp(c_program.as_ptr(), c_ptrs.as_ptr());
81 }
82
83 eprintln!(
85 "setpgid: exec {program}: {}",
86 std::io::Error::last_os_error()
87 );
88 ExitCode::from(127)
89}