Skip to main content

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}