Signals and Exit Codes#

Unix Signals#

Linux signal numbers vary slightly by architecture; the numbers below are for x86_64 Linux. Names are POSIX. The -l flag of kill prints the local mapping.

Number

Name

Default

Meaning

1

SIGHUP

Term

terminal hangup; daemons commonly reload

2

SIGINT

Term

interrupt (Ctrl-C)

3

SIGQUIT

Core

quit + core dump (Ctrl-\)

4

SIGILL

Core

illegal instruction

5

SIGTRAP

Core

trace / breakpoint trap

6

SIGABRT

Core

abort()

7

SIGBUS

Core

bus error (memory access)

8

SIGFPE

Core

floating-point exception

9

SIGKILL

Term

forced termination, cannot be caught

10

SIGUSR1

Term

user-defined 1

11

SIGSEGV

Core

segmentation fault (invalid memory)

12

SIGUSR2

Term

user-defined 2

13

SIGPIPE

Term

write to closed pipe / socket

14

SIGALRM

Term

alarm timer expired

15

SIGTERM

Term

graceful termination request (default for kill)

16

SIGSTKFLT

Term

stack fault (rare)

17

SIGCHLD

Ign

child stopped or terminated

18

SIGCONT

Cont

continue (resume)

19

SIGSTOP

Stop

stop (cannot be caught)

20

SIGTSTP

Stop

terminal stop (Ctrl-Z)

21

SIGTTIN

Stop

background process tried to read tty

22

SIGTTOU

Stop

background process tried to write tty

23

SIGURG

Ign

out-of-band socket data

24

SIGXCPU

Core

CPU time limit exceeded

25

SIGXFSZ

Core

file size limit exceeded

26

SIGVTALRM

Term

virtual alarm

27

SIGPROF

Term

profiling alarm

28

SIGWINCH

Ign

terminal window size changed

29

SIGIO / SIGPOLL

Term

async I/O

30

SIGPWR

Term

power failure

31

SIGSYS

Core

bad system call

Default actions: Term = terminate; Core = terminate + core dump; Stop = pause; Cont = resume; Ign = ignored.

The Two You Can’t Catch#

Two signals the kernel handles itself, with no opportunity for the target process to install a handler. SIGKILL terminates; SIGSTOP suspends. Every other signal can be caught, blocked, or ignored, which is why these two are the always-works escape hatch.

  • SIGKILL (9), forced termination. The kernel kills the process; no chance to clean up.

  • SIGSTOP (19), forced pause. SIGCONT resumes.

Every other signal can be caught, blocked, or ignored.

Real-Time Signals#

Linux also defines real-time signals 32-64 (SIGRTMIN .. SIGRTMAX). These are queued (multiple deliveries are not coalesced the way standard signals are) and used by libpthread internally and by some applications for IPC.

Sending Signals#

The shell-side primitives. kill sends to a PID, pkill / killall send by name, and trap installs a handler in the current shell so a script can clean up before the signal would otherwise terminate it.

$ kill -TERM PID
$ kill -9 PID
$ kill -HUP PID
$ pkill -USR1 myproc
$ killall -SIGTERM myproc

$ trap 'echo got SIGINT; cleanup; exit 130' INT
$ trap 'cleanup' EXIT

Common Daemon Conventions#

What well-behaved daemons do when each signal arrives. SIGHUP for config reload is the most-cited convention; SIGUSR1 / SIGUSR2 are application-defined hooks (log rotation, graceful restart); SIGTERM is the polite shutdown request before SIGKILL.

Signal

Common effect

SIGHUP

reload configuration

SIGUSR1

rotate logs / dump stats

SIGUSR2

graceful binary upgrade (nginx, unicorn)

SIGTERM

graceful shutdown

SIGINT

interrupt (often same as SIGTERM)

SIGQUIT

graceful drain (nginx) or core-dump (most processes)

SIGKILL

last resort

Unix Exit Codes#

A process’s exit status is an 8-bit integer. By convention:

Code

Meaning

0

success

1

general / catch-all error

2

misuse of shell builtins

64

EX_USAGE command-line usage error

65

EX_DATAERR input data error

66

EX_NOINPUT cannot open input

67

EX_NOUSER user does not exist

68

EX_NOHOST host does not exist

69

EX_UNAVAILABLE service unavailable

70

EX_SOFTWARE internal software error

71

EX_OSERR operating-system error

72

EX_OSFILE system file missing

73

EX_CANTCREAT cannot create output

74

EX_IOERR IO error

75

EX_TEMPFAIL temporary failure; retry safe

76

EX_PROTOCOL remote protocol error

77

EX_NOPERM permission denied

78

EX_CONFIG configuration error

126

command found but not executable

127

command not found

128

invalid argument to exit

128 + N

terminated by signal N

Examples:

  • 137, killed by SIGKILL (128 + 9). Often OOM killer or kill -9.

  • 143, terminated by SIGTERM (128 + 15). Typical orderly shutdown.

  • 130, interrupted by SIGINT (128 + 2). User pressed Ctrl-C.

The 64-78 range comes from sysexits.h, BSD convention; not universally used, but worth knowing.

$? and Pipelines#

$? carries the exit status of the last command in the foreground. In a pipeline, $? is the last stage by default; ${PIPESTATUS[@]} exposes every stage; set -o pipefail makes the pipeline exit non-zero if any stage failed.

$ cmd
$ echo "$?"

$ a | b | c
$ echo "${PIPESTATUS[@]}"

$ set -o pipefail

Timeout Conventions#

Exit codes timeout(1) uses to distinguish “the command ran but took too long” from “the command itself failed.” 124 is the common one; 125-127 are the failure modes; 137 is “we had to SIGKILL it” (128+9).

Code

Source

124

timeout, command timed out

125

timeout, internal error

126

timeout, command found but not executable

127

timeout, command not found

137

usually timeout --signal=KILL (128+9)

What to Use in Your Programs#

A short rule for picking exit codes when you write something new. 0 / 1 / 2 cover most cases; reach for sysexits.h numbers only if your program participates in that BSD convention; reserve custom codes for cases where callers genuinely need to branch on the failure type.

  • 0 for success.

  • 1 for general failure.

  • 2 for usage / syntax errors (argparse does this in Python).

  • Numbers from sysexits.h if your program participates in the BSD convention.

  • Custom non-overlapping codes only when callers genuinely need to distinguish.