Which signal does ctrl-x send when used in a terminal?
To get all the terminal control character assignments:
stty -a
What is the behavior of each ctrl + key and its signals?
The description of Linux terminal input handling is found in man tcsetattr
, which is the function you would use to configure the mapping for cooked input. (Look for the c_cc
array for the list of special characters.) The Linux terminal is based on the Posix standard but it has a number of extensions. (The list of special characters is in §11.1.9 of Posix, but you should also read the preceding sections for a complete understanding of the terminal programming model.)
There are three signals which the terminal driver will send in response to control characters:
SIGINT
(VINTR
, default Ctrl-C)SIGQUIT
(VQUIT
, default Ctrl-\)SIGTSTP
(VSUSP
, default Ctrl-Z)
If you set the terminal to raw mode (with the same function) then you will have to issue the signals yourself (if you want to) and you can use whatever mechanism you choose to decide what triggers each signal.
The readline
library (used by many shells) puts the terminal into raw mode while it is reading, then does its own character mapping [Note 2]. However, when bash
hands the terminal over to a command application, the terminal is restored to default mode [Note 1], so the mapping is controlled by the terminal driver as explained in the tcsetattr
documention.
If you want to use readline
, you will need to consult its documentation.
Most applications using ncurses
also start by putting the terminal into raw mode.
Notes
This is actually a bit imprecise, since commands can modify the terminal mode. (See
man stty
, for example.) If some command changes a control character, that becomes part of the mode which will be passed to the next command.readline
doesn't turn offVINTR
handling, soSIGINT
can be sent even ifreadline
is being used; this will obey the current terminal setting. But it does turn off the other control characters.
In detail, what happens when you press Ctrl-C in a terminal?
tl;dr the kernel does it.
Each pty (pseudo tty) has two ends, a master and a slave. In the xterm example, xterm would be holding onto the master file descriptor. Any key presses are written directly into the master fd. The slave fd (pts, or pty slave) is owned by a session and passed to whatever the foreground process group is.
Whenever an ASCII ETX character (^C) is written to the master, the kernel translates that into sending SIGINT to the foreground process group with the corresponding controlling terminal. This is actually a pty setting. You can run stty -a
and see that the default is intr = ^C;
, meaning ^C
or ETX is the "SIGINT" character. This can be changed to a different character or disabled entirely.
A more complex example would be how Ctrl-C works through an interactive SSH session. Interactive SSH sessions allocate a pty on the server side. The client side pty is set to raw mode, meaning that the client side kernel will not translate ETX into SIGINT. Instead, the client side kernel passes the ETX along to the slave. In this case, the ssh client process takes that ETX and passes it along to the server sshd process. If the server sshd pty is not in raw mode, then the server's kernel will translate that ETX into a SIGINT to its foreground process group. This is how Ctrl-C sends SIGINT to the process running on the server instead of killing your client side SSH and leaving you hanging.
Forcing a terminal not to print Ctrl hotkeys when signals are caught
When you type a key on a terminal, two things happen
- the character is echoed (displayed) on this terminal
- the character is sent (over the line) to the attached program
Both these actions can be controlled via termios/tcsetattr(): a different character(s) can be sent or echoed, some can be suppressed, etc. (some/most of these actions take place in the terminal-driver , but this is not relevant here)
Demonstration: using tcsetattr()
to control the echoing of the terminal:
#include <stdio.h>
#include <stdlib.h>
#define _SVID_SOURCE 1
#include <termios.h>
#include <unistd.h>
#include <signal.h>
struct termios termios_save;
void reset_the_terminal(void)
{
tcsetattr(0, 0, &termios_save );
}
sig_atomic_t the_flag = 0;
void handle_the_stuff(int num)
{
char buff[4];
buff[0] = '[';
buff[2] = '0' + num%10;
num /= 10;
buff[1] = '0' + num%10;
buff[3] = ']';
write(0, buff, sizeof buff);
the_flag = 1;
}
int main (void)
{
int rc;
int ch;
struct termios termios_new;
rc = tcgetattr(0, &termios_save );
if (rc) {perror("tcgetattr"); exit(1); }
rc = atexit(reset_the_terminal);
if (rc) {perror("atexit"); exit(1); }
termios_new = termios_save;
termios_new.c_lflag &= ~ECHOCTL;
rc = tcsetattr(0, 0, &termios_new );
if (rc) {perror("tcsetattr"); exit(1); }
signal(SIGINT, handle_the_stuff);
printf("(pseudoshell)Start typing:\n" );
while(1) {
ch = getc(stdin);
if (the_flag) {
printf("Saw the signal, last character was %02x\n", (unsigned) ch);
break;
}
}
exit (0);
}
What keyboard signal apart from Ctrl-C can I catch?
You can use ctrl+Z
,
SIGTSTP
Value = 20
For more details refer this link.
What happens in BASH when you do Ctrl-C (hint, it's not simply sending a SIGINT)
Okay mystery solved! Thanks to the helpful folks over at the Indian Linux Users Group.
The answer here is two-fold -
Firstly, apt-get
invokes another program called http
for downloading data.
[~] ➔ file /usr/lib/apt/methods/http
/usr/lib/apt/methods/http: ELF 32-bit LSB executable, Intel 80386, version 1
(SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.15,
stripped
Note that that's an executable, not even a script, probably to support downloading files during system installation when none of perl/python/ruby etc. are yet available.
Secondly, when you press Ctrl-C after running apt-get
, the SIGINT gets sent to http
, and not to apt-get
. When http
receives the SIGINT, it saves the download state before shutting down.
Here's the updated script that works perfectly -
#!/bin/sh
for i in `seq 1 100` ; do
sudo apt-get install foo -y &
sleep 10
sudo kill -2 `ps -ae | grep " http" | awk '{print $1}'`
done
Related Topics
Google-Chrome Failed to Move to New Namespace
Add User to Group But Not Reflected When Run "Id"
How to Make Sure the Numpy Blas Libraries Are Available as Dynamically-Loadable Libraries
Is It Possible That Linux File Descriptor 0 1 2 Not for Stdin, Stdout and Stderr
How to Get Started Developing on *Nix
Spidev Linux Driver on Intel Atom Board
Tilde Expansion in Environment Variable
Linux Kernel System Call Returns -1 Instead of {-1, -256}
The Irq in Kernel Function Asm_Do_Irq() Is Different from the One I Request in Module
Moving Multiple Files Having Spaces in Name (Linux)
Differencebetween './Example.Sh' and 'Sh Example.Sh'
How to Look Up a Variable by Name with #!/Bin/Sh (Posix Sh)
How to Run Dos2Unix on an Entire Directory
How to See Top Processes Sorted by Actual Memory Usage
How to Calculate an Md5 Checksum of a Directory
How to List All Users in a Linux Group
Recursively List All Files in a Directory Including Files in Symlink Directories