From 519893d31f0118cbc57e26ddf87255f00bfc366c Mon Sep 17 00:00:00 2001 From: Tim Ledbetter Date: Thu, 15 Jun 2023 18:25:05 +0100 Subject: [PATCH] pkill: Add `-n` option to kill the newest matching process only --- Base/usr/share/man/man1/pkill.md | 3 ++- Userland/Utilities/pkill.cpp | 21 +++++++++++++++------ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/Base/usr/share/man/man1/pkill.md b/Base/usr/share/man/man1/pkill.md index dc40e5847c6..7f3e2fa0f61 100644 --- a/Base/usr/share/man/man1/pkill.md +++ b/Base/usr/share/man/man1/pkill.md @@ -5,7 +5,7 @@ pkill - Signal processes based on name ## Synopsis ```sh -$ pkill [--count] [--ignore-case] [--echo] [--signal signame] [--uid uid-list] [--exact] +$ pkill [--count] [--ignore-case] [--echo] [--newest] [--signal signame] [--uid uid-list] [--exact] ``` ## Options @@ -13,6 +13,7 @@ $ pkill [--count] [--ignore-case] [--echo] [--signal signame] [--uid uid-list] [ * `-c`, `--count`: Display the number of matching processes * `-i`, `--ignore-case`: Make matches case-insensitive * `-e`, `--echo`: Display what is killed +* `-n`, `--newest`: Kill the most recently created process only * `-s signame`, `--signal signame`: Signal to send. The signal name or number may be used * `-U uid-list`, `--uid uid-list`: Select only processes whose UID is in the given comma-separated list. Login name or numerical user ID may be used * `-x`, `--exact`: Select only processes whose names match the given pattern exactly diff --git a/Userland/Utilities/pkill.cpp b/Userland/Utilities/pkill.cpp index 6b95dedabfd..926857ad75b 100644 --- a/Userland/Utilities/pkill.cpp +++ b/Userland/Utilities/pkill.cpp @@ -6,6 +6,7 @@ */ #include +#include #include #include #include @@ -29,6 +30,7 @@ ErrorOr serenity_main(Main::Arguments args) bool case_insensitive = false; bool echo = false; bool exact_match = false; + bool newest_only = false; StringView pattern; HashTable uids_to_filter_by; int signal = SIGTERM; @@ -37,6 +39,7 @@ ErrorOr serenity_main(Main::Arguments args) args_parser.add_option(display_number_of_matches, "Display the number of matching processes", "count", 'c'); args_parser.add_option(case_insensitive, "Make matches case-insensitive", "ignore-case", 'i'); args_parser.add_option(echo, "Display what is killed", "echo", 'e'); + args_parser.add_option(newest_only, "Kill the most recently created process only", "newest", 'n'); args_parser.add_option(Core::ArgsParser::Option { .argument_mode = Core::ArgsParser::OptionArgumentMode::Required, .help_string = "Signal number to send. A signal name or number may be used", @@ -115,12 +118,18 @@ ErrorOr serenity_main(Main::Arguments args) } } - for (auto& process : matched_processes) { - auto result = Core::System::kill(process.pid, signal); - if (result.is_error()) - warnln("Killing pid {} failed. {}", process.pid, result.release_error()); - else if (echo) - outln("{} killed (pid {})", process.name, process.pid); + if (!matched_processes.is_empty()) { + quick_sort(matched_processes, [](auto const& a, auto const& b) { return a.creation_time < b.creation_time; }); + if (newest_only) + matched_processes = { matched_processes.last() }; + + for (auto& process : matched_processes) { + auto result = Core::System::kill(process.pid, signal); + if (result.is_error()) + warnln("Killing pid {} failed. {}", process.pid, result.release_error()); + else if (echo) + outln("{} killed (pid {})", process.name, process.pid); + } } if (display_number_of_matches)