ctrl-c killing my background processes in my shell

5.4k Views Asked by At

I'm trying to write a basic a shell in C. One of things I need to do, is be able to have both background and foreground processes. Control-C must kill the foreground process (if there is one), and must not kill any background processes.

I wrote a signal handler for SIGINT that kills the foreground process. The only problem is, if I have a background process, it kills that too. From what I understand, when Control-C is pressed, SIGINT is passed up a queue to different processes, and if one handles it, then that's where it stops. My shell should be handling it, so it should not be passed to the background process right?

Here is my code:

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);
}

When I run a foreground process:

sleep(100)

I can then hit contorl-c and it will quit. Like it should. However, if I run a background process:

sleep(100) &

I get a new prompt, like I should, but if I hit control-c, nothing should happen. But the background process gets killed.

I would love to know how to stop the background process getting killed. Any ideas? :)

0

There are 0 best solutions below