1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
//
// Syd: rock-solid application kernel
// src/utils/syd-pds.rs: Run a command with parent death signal set
//
// Copyright (c) 2024, 2025, 2026 Ali Polatel <alip@chesswob.org>
//
// SPDX-License-Identifier: GPL-3.0
use std::{process::ExitCode, str::FromStr};
use nix::{errno::Errno, sys::signal::Signal};
use syd::{compat::set_pdeathsig, confine::run_syd_shell, eprintfln, err::err2exit, printfln};
// Set global allocator to GrapheneOS allocator.
#[cfg(all(
not(target_os = "android"),
not(target_arch = "loongarch64"),
not(target_arch = "riscv64"),
target_page_size_4k,
target_pointer_width = "64"
))]
#[global_allocator]
static GLOBAL: hardened_malloc::HardenedMalloc = hardened_malloc::HardenedMalloc;
syd::main! {
use lexopt::prelude::*;
syd::set_sigpipe_dfl()?;
// Parse CLI options.
//
// Note, option parsing is POSIXly correct:
// POSIX recommends that no more options are parsed after the first
// positional argument. The other arguments are then all treated as
// positional arguments.
// See: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html#tag_12_02
let mut opt_sig = Signal::SIGKILL;
let mut opt_cmd = None;
let mut opt_arg = Vec::new();
let mut parser = lexopt::Parser::from_env();
while let Some(arg) = parser.next()? {
match arg {
Short('h') => {
help()?;
return Ok(ExitCode::SUCCESS);
}
Short('s') => {
let sig = parser.value()?;
opt_sig = match sig.parse::<i32>() {
Ok(value) => match Signal::try_from(value) {
Ok(value) => value,
Err(_) => {
eprintfln!("syd-pds: Invalid signal specified with -s!")?;
return Err(Errno::EINVAL.into());
}
},
Err(_) => {
let mut value = sig.parse::<String>()?.to_ascii_uppercase();
if !value.starts_with("SIG") {
value = format!("SIG{value}");
}
match Signal::from_str(&value) {
Ok(value) => value,
Err(_) => {
eprintfln!("syd-pds: Invalid signal specified with -s!")?;
return Err(Errno::EINVAL.into());
}
}
}
};
}
Value(prog) => {
opt_cmd = Some(prog);
opt_arg.extend(parser.raw_args()?);
}
_ => return Err(arg.unexpected().into()),
}
}
// Set parent death signal to the specified signal or SIGKILL.
set_pdeathsig(Some(opt_sig))?;
// Execute command, Syd shell by default.
Ok(err2exit(run_syd_shell(opt_cmd, opt_arg)))
}
fn help() -> Result<(), Errno> {
printfln!("Usage: syd-pds [-h] [-s signal] {{command [args...]}}")?;
printfln!("Run a command with parent death signal set.")?;
printfln!("Use -s to specify a signal, defaults to SIGKILL.")?;
Ok(())
}