Reputation: 77
I want to the following in my implementation of shell.
When shell is launched, the prompt is printed. When I click CTRL+C it should ignore the signal and print the prompt on new line. No enter key should pressed.
When I launch an external program like top, I should be able to kill it with CTRL+C and get back to my shell.
Finally, when I launch a program like 'python', I want to be able to click CTRL+C and only receive KeyboardInterrupt and >> printed on new line as in real shell. Currently, I get this:
Shell> python
Type "help", "copyright", "credits" or "license" for more information.
>>>
Shell>
KeyboardInterrupt
>>>
Shell>
KeyboardInterrupt
>>>
Shell>
KeyboardInterrupt
>>>
Where you can see that Shell> is printed in the middle of CTRL+C interrupt. A relevant excerpt of code is:
void signal_handler(int dummy) {
#ifdef DEBUG
printf("CTRL-C is disabled.\n");
#endif
printf("\n");
}
int main(int argc, char **argv) {
char *command;
char **args;
int status;
/* Register a signal handler for Ctrl-C */
sigset(SIGINT, signal_handler);
while (1) {
printf("Shell> ");
command = read_command();
args = tokenize_command(command);
status = execute(args);
#ifdef DEBUG
printf("The newest status code was: %d\n", status);
#endif
free(command);
free(args);
}
}
Upvotes: 0
Views: 2235
Reputation: 18420
You will have to create a new process group for your executed command and make it the foreground process group.
i.e. between fork()
and execve()
in the child process:
setpgid(0, 0);
tcsetpgrp(fileno(stdin), getpgrp());
When the child terminates and waitpid()
in your shell returns, you have to reset the foreground process group:
tcsetpgrp(fileno(stdin), getpgrp()); // Called in the shell main process
Explanation: The processes in the foreground process group may read from the terminal and receive the signals from keyboard-input (Ctrl-C, Ctrl-Z, etc.). When a new command is executed by your shell, it is still in the same process group as the shell, which is also the foreground process group. So you have to create a new process group for your executed command (setpgid) and make it the foreground process group (tcsetpgrp).
Upvotes: 3