123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305 | /* kill -- send a signal to a process Copyright (C) 2002-2025 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. *//* Written by Paul Eggert. */#include <config.h>#include <stdio.h>#include <getopt.h>#include <sys/types.h>#include <signal.h>#include"system.h"#include"c-ctype.h"#include"sig2str.h"#include"operand2sig.h"#include"quote.h"/* The official name of this program (e.g., no 'g' prefix). */#define PROGRAM_NAME"kill"#define AUTHORS proper_name ("Paul Eggert")static char const short_options[] ="0::1::2::3::4::5::6::7::8::9::""A::B::C::D::E::F::G::H::I::J::K::M::""N::O::P::Q::R::S::T::U::V::W::X::Y::Z::""Lln:s:t";static struct option const long_options[] ={{"list", no_argument,nullptr,'l'},{"signal", required_argument,nullptr,'s'},{"table", no_argument,nullptr,'t'},{GETOPT_HELP_OPTION_DECL},{GETOPT_VERSION_OPTION_DECL},{nullptr,0,nullptr,0}};voidusage(int status){if(status != EXIT_SUCCESS)emit_try_help();else{printf(_("\Usage: %s [-s SIGNAL | -SIGNAL] PID...\n\ or: %s -l [SIGNAL]...\n\ or: %s -t [SIGNAL]...\n\"), program_name, program_name, program_name);fputs(_("\Send signals to processes, or list signals.\n\"), stdout);emit_mandatory_arg_note();fputs(_("\ -s, --signal=SIGNAL, -SIGNAL\n\ specify the name or number of the signal to be sent\n\ -l, --list list signal names, or convert signal names to/from numbers\n\ -t, --table print a table of signal information\n\"), stdout);fputs(HELP_OPTION_DESCRIPTION, stdout);fputs(VERSION_OPTION_DESCRIPTION, stdout);fputs(_("\n\SIGNAL may be a signal name like 'HUP', or a signal number like '1',\n\or the exit status of a process terminated by a signal.\n\PID is an integer; if negative it identifies a process group.\n\"), stdout);printf(USAGE_BUILTIN_WARNING, PROGRAM_NAME);emit_ancillary_info(PROGRAM_NAME);}exit(status);}/* Print a row of 'kill -t' output. NUM_WIDTH is the maximum signal number width, and SIGNUM is the signal number to print. The maximum name width is NAME_WIDTH, and SIGNAME is the name to print. */static voidprint_table_row(int num_width,int signum,int name_width,char const*signame){char const*description =strsignal(signum);printf("%*d %-*s %s\n", num_width, signum, name_width, signame, description ? description :"?");}/* Print a list of signal names. If TABLE, print a table. Print the names specified by ARGV if nonzero; otherwise, print all known names. Return a suitable exit status. */static intlist_signals(bool table,char*const*argv){int signum;int status = EXIT_SUCCESS;char signame[SIG2STR_MAX];if(table){int name_width =0;/* Compute the maximum width of a signal number. */int num_width =1;for(signum =1; signum <= SIGNUM_BOUND /10; signum *=10) num_width++;/* Compute the maximum width of a signal name. */for(signum =0; signum <= SIGNUM_BOUND; signum++)if(sig2str(signum, signame) ==0){ idx_t len =strlen(signame);if(name_width < len) name_width = len;}if(argv)for(; *argv; argv++){ signum =operand2sig(*argv);if(signum <0) status = EXIT_FAILURE;else{if(sig2str(signum, signame) !=0)snprintf(signame,sizeof signame,"SIG%d", signum);print_table_row(num_width, signum, name_width, signame);}}elsefor(signum =0; signum <= SIGNUM_BOUND; signum++)if(sig2str(signum, signame) ==0)print_table_row(num_width, signum, name_width, signame);}else{if(argv)for(; *argv; argv++){ signum =operand2sig(*argv);if(signum <0) status = EXIT_FAILURE;else if(c_isdigit(**argv)){if(sig2str(signum, signame) ==0)puts(signame);elseprintf("%d\n", signum);}elseprintf("%d\n", signum);}elsefor(signum =0; signum <= SIGNUM_BOUND; signum++)if(sig2str(signum, signame) ==0)puts(signame);}return status;}/* Send signal SIGNUM to all the processes or process groups specified by ARGV. Return a suitable exit status. */static intsend_signals(int signum,char*const*argv){int status = EXIT_SUCCESS;char const*arg = *argv;do{char*endp;intmax_t n = (errno =0,strtoimax(arg, &endp,10)); pid_t pid;if(errno == ERANGE ||ckd_add(&pid, n,0)|| arg == endp || *endp){error(0,0,_("%s: invalid process id"),quote(arg)); status = EXIT_FAILURE;}else if(kill(pid, signum) !=0){if(errno == EINVAL)error(0, errno,"%d", signum);elseerror(0, errno,"%s",quote(arg)); status = EXIT_FAILURE;}}while((arg = *++argv));return status;}intmain(int argc,char**argv){int optc;bool list =false;bool table =false;int signum = -1;initialize_main(&argc, &argv);set_program_name(argv[0]);setlocale(LC_ALL,"");bindtextdomain(PACKAGE, LOCALEDIR);textdomain(PACKAGE);atexit(close_stdout);while((optc =getopt_long(argc, argv, short_options, long_options,nullptr))!= -1)switch(optc){case'0':case'1':case'2':case'3':case'4':case'5':case'6':case'7':case'8':case'9':if(optind !=2){/* This option is actually a process-id. */ optind--;goto no_more_options;} FALLTHROUGH;case'A':case'B':case'C':case'D':case'E':case'F':case'G':case'H':case'I':case'J':case'K':/*case 'L':*/case'M':case'N':case'O':case'P':case'Q':case'R':case'S':case'T':case'U':case'V':case'W':case'X':case'Y':case'Z':if(! optarg) optarg = argv[optind -1] +strlen(argv[optind -1]);if(optarg != argv[optind -1] +2){error(0,0,_("invalid option -- %c"), optc);usage(EXIT_FAILURE);} optarg--; FALLTHROUGH;case'n':/* -n is not documented, but is for Bash compatibility. */case's':if(0<= signum){error(0,0,_("%s: multiple signals specified"),quote(optarg));usage(EXIT_FAILURE);} signum =operand2sig(optarg);if(signum <0)usage(EXIT_FAILURE);break;case'L':/* -L is not documented, but is for procps compatibility. */case't': table =true; FALLTHROUGH;case'l':if(list){error(0,0,_("multiple -l or -t options specified"));usage(EXIT_FAILURE);} list =true;break; case_GETOPT_HELP_CHAR;case_GETOPT_VERSION_CHAR(PROGRAM_NAME, AUTHORS);default:usage(EXIT_FAILURE);} no_more_options:if(signum <0) signum = SIGTERM;else if(list){error(0,0,_("cannot combine signal with -l or -t"));usage(EXIT_FAILURE);}if( ! list && argc <= optind){error(0,0,_("no process ID specified"));usage(EXIT_FAILURE);}return(list ?list_signals(table, optind < argc ? argv + optind :nullptr):send_signals(signum, argv + optind));}
|