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 |
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.
SIGCONTresumes.
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 |
128 + N |
terminated by signal N |
Examples:
137, killed by SIGKILL (128 + 9). Often OOM killer orkill -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 |
|
125 |
|
126 |
|
127 |
|
137 |
usually |
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 (
argparsedoes this in Python).Numbers from
sysexits.hif your program participates in the BSD convention.Custom non-overlapping codes only when callers genuinely need to distinguish.