yash_builtin/kill.rs
1// This file is part of yash, an extended POSIX shell.
2// Copyright (C) 2024 WATANABE Yuki
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <https://www.gnu.org/licenses/>.
16
17//! Kill built-in
18//!
19//! This module implements the [`kill` built-in], which sends a signal to processes.
20//!
21//! [`kill` built-in]: https://magicant.github.io/yash-rs/builtins/kill.html
22
23use crate::common::report::report_error;
24use yash_env::Env;
25use yash_env::semantics::Field;
26use yash_env::signal::RawNumber;
27use yash_env::system::{Fcntl, Isatty, SendSignal, Signals, Write};
28
29/// Parsed command line arguments
30///
31/// # Design notes
32///
33/// `Command::Print::signals` contains raw operands received as command-line
34/// arguments. Since determining whether a number represents a signal number or
35/// an exit status falls within the semantics of [`mod@print`], these operands
36/// remain unconverted to specific signals by the time arguments are parsed as
37/// `Command::Print`. In contrast, `Command::Send` requires signal name
38/// validation during command-line option parsing, so even when signals are
39/// specified by name, `Command::Send::signal` already contains a signal
40/// converted to its numerical value.
41#[derive(Clone, Debug, Eq, PartialEq)]
42#[non_exhaustive]
43pub enum Command {
44 /// Sends a signal to processes
45 Send {
46 /// Signal to send
47 ///
48 /// This signal number may represent an invalid signal if it was
49 /// specified by number on the command line.
50 signal: RawNumber,
51 /// Parameter that specified the signal, if any
52 signal_origin: Option<Field>,
53 /// Target processes
54 targets: Vec<Field>,
55 },
56
57 /// Lists signal names or descriptions
58 Print {
59 /// Signals to list
60 ///
61 /// Field values can be:
62 ///
63 /// - Signal names, e.g., `HUP`, `TERM`;
64 /// - Signal numbers, e.g., `1`, `15`; or
65 /// - Exit statuses representing signals, e.g., `386` for `SIGINT`.
66 ///
67 /// If empty, all signals are listed.
68 signals: Vec<Field>,
69 /// Whether to print descriptions
70 verbose: bool,
71 },
72}
73
74pub mod print;
75pub mod send;
76pub mod syntax;
77
78impl Command {
79 /// Executes the built-in.
80 pub async fn execute<S>(&self, env: &mut Env<S>) -> crate::Result
81 where
82 S: Fcntl + Isatty + SendSignal + Signals + Write,
83 {
84 match self {
85 Self::Send {
86 signal,
87 signal_origin,
88 targets,
89 } => send::execute(env, *signal, signal_origin.as_ref(), targets).await,
90
91 Self::Print { signals, verbose } => print::execute(env, signals, *verbose).await,
92 }
93 }
94}
95
96/// Entry point of the kill built-in
97pub async fn main<S>(env: &mut Env<S>, args: Vec<Field>) -> crate::Result
98where
99 S: Fcntl + Isatty + SendSignal + Signals + Write,
100{
101 match syntax::parse(env, args) {
102 Ok(command) => command.execute(env).await,
103 Err(error) => report_error(env, &error).await,
104 }
105}