Decoded: kill (coreutils)

[Back to Project Main Page]

Note: This page explores the design of command-line utilities. It is not a user guide.
[GNU Manual] [POSIX requirement] [Linux man] [FreeBSD man]

Logical flow of kill command (coreutils)

Summary

kill - terminate or signal processes

[Source] [Code Walkthrough]

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]

Helpers:
  • list_signals() - outputs a list of available signals
  • print_table_row() - wrapper for printf() for table output format
  • send_signals() - sends a signal to one or more processes
External non-standard helpers:
  • error() - Outputs error message to standard error with possible process termination
  • operand2sig() - Converts operand (number/name) to a number and fills in the name
  • quote() - Converts input argument to a printable string
  • sig2str() - 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 list
  • optc - The current command line option letter
  • signum - The signal number (some vary by archiecture)
  • signame - Holds the signal name for display
  • table - 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

[Back to Project Main Page]