Я пытаюсь написать базовую оболочку на C. Одна из вещей, которые мне нужно сделать, - иметь возможность иметь как фоновые, так и передние процессы. Control-C должен убить процесс переднего плана (если он есть) и не должен убивать какие-либо фоновые процессы.
Я написал обработчик сигнала для SIGINT, который убивает процесс переднего плана. Единственная проблема в том, что если у меня есть фоновый процесс, он тоже убивает его. Насколько я понимаю, при нажатии Control-C SIGINT передается по очереди в разные процессы, и если один обрабатывает его, то на этом он останавливается. Моя оболочка должна обрабатывать его, поэтому его нельзя передавать фоновому процессу, верно?
Вот мой код:
pid_t foreground_pid;
int main(int argc, char *argv[]) {
signal(SIGINT, INThandler);
char *buf;
while(1) {
fgets(buf, 128, stdin);
*/ error checking */
*/ split buf into null terminated char* array (arg_array)
and count the number of args (num_args) */
handlerCommand(buf, arg_array, num_args);
zombieTerminator();
}
void handleCommand(char *command, char **args, int num) {
pid_t pid;
if ((pid = fork()) < 0)
printf("error\n");
else if (pid == 0) { // Child
if (!strcmp(args[num-1], "&")) {
/* redirect stdin to /dev/null */
}
execvp(args[0], args);
printf("error\n");
exit(127);
}
// parent - either wait (foreground) or continue (background)
if (!strcmp(args[num-1], "&")) {
printf(" [%ld] : %s\n", (long)pid, command);
} else {
foreground_pid = pid;
if ((pid = waitpid(pid, &status, 0)) < 0)
fprintf(stderr, "waitpid error\n");
}
return;
}
/** Terminates any zombie processes that finished in the background */
void zombieTerminator(void) {
int status;
pid_t pid;
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
if (pid != foreground_pid) {
printf(" [%ld] exited with status: %d\n", (long)pid,
WEXITSTATUS(status));
}
}
}
/** Handles the control-c signal from the keyboard */
void INThandler(int sig) {
if (foreground_pid) {
kill(foreground_pid, SIGKILL);
foreground_pid = 0;
} else {
printf("\n%s\? ", cwd);
}
fflush(stdout);
}
Когда я запускаю процесс переднего плана:
sleep(100)
Затем я могу нажать contorl-c, и он выйдет. Как и должно. Однако, если я запускаю фоновый процесс:
sleep(100) &
Я получаю новое приглашение, как и должно быть, но если я нажму Control-C, ничего не должно произойти. Но фоновый процесс убивается.
Я хотел бы знать, как остановить фоновый процесс, убиваемый. Есть идеи? :)