^C doesn’t kill processes, SIGINT does
On the LUV mailing list recently, the perils of tty handling when booting with “init=/bin/bash” came up, and somebody asked why running ‘ping’ (without remembering to run stty or openvt first) will result in you having to reboot.
i.e. “why doesn’t ^C work in emergency mode”?
I wrote a fairly detailed, but comprehensible to a novice, answer and a friend suggested i should have written it as a blog post – which was the point of me setting up a blog in the first place.
So here’s a slightly edited version of it:
> Couldn’t you just open another console, run “top” and find the PID for
> ping and kill it? Or ps aux |grep ping and kill it? Is a reboot the
> only way to kill a ping where ^C is not available?
there’s nothing special about ^C except that by long convention it is mapped to the interrupt signal aka intr aka SIGINT. So, ^C itself doesn’t kill a program, the fact that it generates an interrupt signal does.
If you’ve rebooted for emergency maintenance (e.g. “init=/bin/bash” on the LILO or GRUB command line) then all you get is ONE instance of /bin/bash. Nothing else is running and nothing else has been run (because you’ve overriden the usual init with /bin/bash). No setup has been done on the terminal, and no other virtual terminals have been opened. The emergency environment is minimal (and deliberately so – you asked for it, you got it). It’s up to you to do whatever is needed to set up the environment so that you can do the required maintenance/repair work.
So if you run ping *before* remembering to set up the terminal (‘stty sane’) then ^C doesn’t work because ^C doesn’t generate SIGINT so there’s no way of telling ping to quit, and if you haven’t opened another virtual terminal with openvt (aka “open” – it got renamed some time ago) then there is no other shell available to run top or ps or kill.
BTW, it’s not just ping. You’ll see the same problem in the same environment with ANY program that runs continuously until it gets a signal to terminate it. ping’s just the most obvious and common example.
Most programs, especially simple programs like ping, don’t have a ^C handler. They don’t need one. They have a signal handler which, amongst other things, handles SIGINT however it’s generated – it can be generated by pressing ^C in a normal tty environment, or by sending the program a SIGINT (e.g. “kill -2”).
That, BTW, is a core difference between a SIGTERM (just plain ‘kill’ or ‘kill -15’) and SIGKILL (‘kill -9’).
SIGTERM is usually handled by the program by setting up a signal handler for it, and it voluntarily terminates when it receives the signal (usually cleaning up, closing files, etc before it does so). If the program hasn’t set up a handler for SIGTERM then the default action is to just terminate. A program can set up a handler which does nothing on SIGTERM, which effectively just ignores the signal.
SIGKILL is handled by the kernel and it just kills the process immediately – it can not be blocked or intercepted by the program.
(By common convention, SIGHUP or ‘kill -1’ tells a long running daemon process to just reload it’s config files. It’s also generated when the tty that the program is running on is terminated – e.g. you log out or the modem hangs up or the ssh session dies, hence the name “HUP” aka “HANGUP”. That’s why you need to use something like nohup or screen if you want a program to continue running after you log out)
In a way, ‘kill’ is a bit of a misnomer. It’s actually a generic tool for sending signals to running processes, but the default action for most of those signals is to terminate the program. Here’s a list of the signals which can be sent.
$ kill -l 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM 16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP 21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ 26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR 31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3 38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8 43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13 48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7 58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2 63) SIGRTMAX-1 64) SIGRTMAX
See the man pages for init(8), kill(1), and especially signal(7) for more info on this topic.