I'm currently writing a simple shell in C and i'm facing issues with signals.
For example when I launch my program, I type ping command then CTRL-Z I want that the child process (the ping command) to be paused and then to come back when I use fg.
I think that I need to store as a global variable the child pid of the one that execute the ping command.
I already checked other posts to resolve the problem by my own but I can't get it working.
This is the code to execute a command (multiple commands with |) and where I store the child pid.
int exec_proc(int input, int output, char** command) {
pid_t runner;
runner = fork();
f_pid = runner;
if (runner == 0) {
// Use input for stdin
if (input != 0) {
dup2(input, 0);
close(input);
}
// Use output for stdout
if (output != 1) {
dup2(output, 1);
close(output);
}
// Return command code
execvp(command[0], command);
}
// An error occured
return -1;
This is my handler c file.
pid_t f_pid;
/**
* Handles every handler !
*/
void handlerManager()
{
signal(SIGINT,INTHandler);
signal(SIGTSTP,TSTPHandler);
signal(SIGCONT,CONTHandler);
}
/**
* Handler for CTRL-C
* @param sig
*/
void INTHandler(int sig)
{
printf("\nDo you really want to quit ? [y/n] \n");
int answer = getchar();
if(toupper(answer) == 'Y')
kill(f_pid,SIGINT);
}
/**
* Handler for CTRL-Z (processus sleep)
* @param sig
*/
void TSTPHandler(int sig)
{
printf("\nGoing to sleep! \n");
printf("%d", f_pid);
kill(f_pid,SIGTSTP);
}
/**
* Handler to reset a processus
* @param sig
*/
void CONTHandler(int sig)
{
printf("\nHey i'm awake\n");
kill(f_pid,SIGCONT);
}`
When I print the pid I am getting the right PID.
Finally this where I call my handler Manager.
int main() {
char* line;
char** args[MAX_ARG_SIZE] = {NULL};
int status;
handlerManager();
do {
fflush(stdin);
prompt();
line = readline();
char linecpy[strlen(line)];
strcpy(linecpy, line);
splitBy(line, " ", args);
status = exec(args, linecpy);
switch (status) {
case EMPTY_LINE:
break;
}
} while (status);
return 0;
Thank you in advance and sorry for my english.
The
exec_proc
file should haveas a global variable (reverse the two lines)
The handler C file needs to access the global variable declared in the other file via
extern
This way, both object files share the same variable
f_pid
.edit -----
Try to change the handler TSTP, and add the following ALRM
Add Alarm signal
Works on my Linux box. When a stop occurs
Note that
alarm()
takes seconds,setitimer()
goes down to the microsecond (in theory).Doing proper job-control signal handling lifts your project a bit beyond what I would characterize as a "simple" shell. The GLIBC manual has a whole multi-part section on implementing a job-control shell, and it sounds like much of it would apply to your project.
A key aspect that you seem to be disregarding is managing process groups and which of those has control of the terminal. The way you're doing things now, your shell's child processes will belong to the same process group as the shell itself, and that will present a problem when a signal, such as
SIGSTP
, is sent to the child's whole process group.To avoid such problems, your shell should make new child processes be process-group leaders of their own process groups (via
setpgid()
). When such process groups are meant to initially be in the foreground, your shell should make them terminal's controlling process group (tcsetpgrp()
).There's more to it than that, of course, but that should get you going in the right direction.