Search code examples
cbackgroundforkparent-child

Print exit status of background child process but return parent command line access


In C, I would like to print the exit status of a child process when it finishes executing. I know how to do this in a foreground process (just use waitpid) but in a background process I want the command line access to be instantly given to the user when the child is forked.

In other words I can't wait around in the case of the parent and instead I have to return to the top and let the while loop execute again.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <dirent.h>
#include <limits.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>

#define MAX_JOBS 100 //max jobs that can go on at once

pid_t jobs[MAX_JOBS];
int job_count = 0;
int last_exit_status = 0;
char* last_termination = 0;

void addJob(pid_t pid) {// Function to add a job to the list
    if (job_count < MAX_JOBS) {
        jobs[job_count] = pid;
        job_count++;
    }
}

//main func
int main() {
    int x = 0;
    char *token;
    char *argv[1024]; // Array to store command and arguments
    char *argvSec[1024];
    int i = 0;
    while(x == 0) {
        int pid = getpid();
        char* command = prompt();   //get user input
        if (command != NULL) {
            int childExitMethod;
            pid_t spwanPID = fork();

            switch (spwanPID){
            case -1:
                last_exit_status = 1;
            case 0:
                execvp(argv[0], argv);
                last_exit_status = 1;
                exit(1);
            default:
                if (isForeGround){
                    waitpid(spwanPID, &childExitMethod, 0); // Wait for the child only if foreground
                    if (WIFEXITED(childExitMethod) && !WEXITSTATUS(childExitMethod)) {
                        last_exit_status = 0;
                    } else {
                        printf("bash: %s: command not found\n", command);
                        last_exit_status = 1;
                    }
                } else if (isBackground){

                }
            }
        }
    }
    return 0;
}

Solution

  • The problem I was expeirencing was because waitpid(spwanPID, &childExitMethod, 0); blocks and waits for the child to finish running, because of this I couldnt give the user command line access instantly after the fork. I was able to solve this by using waitpid(-1, &currentStatus, WNOHANG); where WHOHANG stops waitpid from blocking. And I can check the child termination by doing so before the prompt function. Heres an example.

    void check_background() {
        if (backgroundChildrenRunning > 0) {        //this function is to print the background process termination signal
            int currentStatus;
            int completedChild = waitpid(-1, &currentStatus, WNOHANG);      //use WHOHANG so it does not block
    
            if (completedChild > 0) {
                if (WIFEXITED(currentStatus)) {
                    printf("Background process with ID %d has been completed. Exit value: %d.\n", completedChild, WEXITSTATUS(currentStatus));
                    last_termination = WEXITSTATUS(currentStatus);
                }
                else {
                    if (completedChild == backgroundPid) {
                        printf("Background process with ID %d has been completed. Terminated by signal: %d.\n", completedChild, WTERMSIG(currentStatus));
                        last_termination = WTERMSIG(currentStatus);
                    }
                }
                backgroundPid = 0;
                backgroundChildrenRunning -= 1;
            }
        }
    }
    
    
    int main() {
        int x = 0;
        char *token;
        char *argv[1024]; 
        char *argvSec[1024];
    
        while(x == 0) {
            check_background();     //check background here
            int pid = getpid();
            char* command = prompt(pid);   //get user input
            if (command != NULL) {
                int childExitMethod;
                pid_t spwanPID = fork();
    
                switch (spwanPID){
                case -1:
                    last_exit_status = 1;
                case 0:
                    execvp(argv[0], argv);
                    last_exit_status = 1;
                    exit(1);
                
                default:
                    if (hasSymbolEnd == 0){
                        waitpid(spwanPID, &childExitMethod, 0); // Wait for the child only if background
                        if (WIFEXITED(childExitMethod) && !WEXITSTATUS(childExitMethod)) {
                            last_exit_status = 0;
                        } 
                    } else {
                        printf("background pid is %d\n", spwanPID);      //print the child pid as requeste
                        backgroundChildrenRunning += 1;
                    }
                }
            }
        }
        return 0;
    }