[GNU Manual] [POSIX requirement] [Linux man] [FreeBSD man]
Summary
kill - terminate or signal processes
Lines of code: 315
Principal syscall: kill()
Support syscalls: None
Options: 10 (5 short, 5 long)
Descended from kill introduced in Version 3 UNIX (1972)
Added to Shellutils in December 2001 [First version]
Number of revisions: 63 [Code Evolution]
list_signals()
- outputs a list of available signalsprint_table_row()
- wrapper forprintf()
for table output formatsend_signals()
- sends a signal to one or more processes
error()
- Outputs error message to standard error with possible process terminationoperand2sig()
- Converts operand (number/name) to a number and fills in the namequote()
- Converts input argument to a printable stringsig2str()
- Converts input signal number to a name to store in the input buffer
Setup
At global scope, kill.c initializes the parsing options for getopt. These include:
- Short: -L, -l, -n, -s, -t
- Long: --list, --signal, --table, --help, --version
It also traps all digits and capitals as short options with no arguments. The numbers are used to detect pids and the capitals force invalid argument handling during parse
main() initializes the following:
list
- Flag used to trigger a signal listoptc
- The current command line option lettersignum
- The signal number (some vary by archiecture)signame
- Holds the signal name for displaytable
- Flag used to trigger tabular output
Parsing
Parsing for kill has two stages of decisions as it sweeps through the arguments:
Decision one: Are we sending a signal or listing signals?
This decision is controlled by the list
flag, which defaults to false (sending signals). These options trigger listing signals: -t, -L, -l, --list, --table
Decision two (if sending): Which signal? Which process?
For the minimum successful command, the user provides a valid pid. User specified signals are resolved in signum
.
Decision two (if listing): Are we printing the signals in list form or table form?
The table
flag controls this decision. Default is false, which means a simple list. The following options trigger table listing: -t, --table.
Parsing failures
These failure cases are explicitly checked:
- No pid specified
- Including both -l and -t, or each one multiple times
- Multiple signals specified
- Specifing a signal while also listing signals
- Using unknown options
All parsing failures result in a short error message followed by the usage instructions.
Extra comments
Digits are checked first because they represent pids. The pid is the only non-option argument expected and POSIX requires that the first non-option argument ends the option checking.
Execution
Successful execution kicks off on one of two paths: In send_signals()
, or in list_signals()
. We'll look at the end goal and failure cases of each.
Sending signals
We need to prepare the arguments and variables for the kill()
syscall. The two arguments are the pid and the signal. The signal number was already obtained during parsing, which may be the default SIGTERM. Parsing left the optind
index sitting on the pid, which may have multiple pids after, requiring us to increment the pointer and call kill()
repeatedly until all pids are eaten.
Failure cases:
- The pid is invalid
kill()
returned a non-zero result
All failures at this stage output an error message to STDERR and return without displaying usage help
Listing signals
The listing output collects character strings and integers for display. At a minimum we need the signal name for list printing, but we may need the pid for table printing. These values were determined in parsing. Both end in a call to either puts()
for the list, or printf()
for the table. libc handles the eventual write()
internally to take advantage of streams and buffering.
Failure case:
- The pid is not a number