Search code examples
c++fork

how to make child process when it finishes to return immediately to run parent process ( when we do fork )?


i wrote a function that simulate cp function (copy in bash ) , basically this function takes a file as an input and copies it to a dest file :

cp sourceFile destFile .

the cp function can run in fore ground or in back ground if there was a '&' at the end of the line (cp sourceFile destFile & )

in order to support this i used fork , and the son basically copies the file , and he father if the command was fore ground waits for the child , else if the command is back ground we don't wait ( we add it to certain list )

my problem is when the command runs in fore ground after the son finishes the code exit the cp function then returns , but when it exits the cp function it prints something , and i don't want this to happen :(

( example at the end )

my function :

void CopyCommand::execute() {
    char *buff = new char[1024]();
    int fdRead = open(args[1], O_RDONLY);
    if (fdRead == -1) {
        perror("smash error: open failed");
        return;
    }

    int fdWrite = open(args[2], O_WRONLY | O_TRUNC);
    if (fdWrite ==-1) {              
        fdWrite = open(args[2], O_WRONLY | O_CREAT, 0666);
        if (fdWrite == -1) {
            perror("smash error: open failed");
            return;
        }
    }

    PID = fork();
    if (PID == 0) {
        setpgrp();
        int count = read(fdRead, buff, 1);  /// read from the file fd1 into fd2
        while (count != -1) {
            if (!count) {
                break;
            }
            if (write(fdWrite, buff, 1) == -1) {
                perror("smash error: write failed");
                return;  // not sure if we should return
            }
            count = read(fdRead, buff, 1);
            if (count == -1) {
                perror("smash error: read failed");
                return;
            }
        }
        return ;
    }  if (PID > 0) { // if i am the father then i will :
        if (isBackground) {
            // if cp command is running in the background then add it to the jobs list
            SmallShell::getInstance().SmallShellGetJobs()->removeFinishedJobs();
            SmallShell::getInstance().Jobs_List.addJob(SmallShell::getInstance().currentCommand, false);
            cout << "smash: " << args[1] << " was copied to " << args[2] << endl;
            return;
        } else {
            int status;
            waitpid(PID, &status, WUNTRACED);
            cout << "smash: " << args[1] << " was copied to " << args[2] << endl;
            return;
        }
    } else {
        perror("smash error: fork failed");
    }
}

what happens : for example the input is :

 cp test_src_1.txt test_newdest_1.txt

the output would be :

outside of cp function :(
smash: test_src_1.txt was copied to test_newdest_1.txt

Solution

  • fork doesn't work the way you think it does. The child process exists until it's terminated, and inherits things like the parent's call stack; when you return in the child process, you're just going to the calling function.

    You need to use exit or something in the same family. For example:

    if (PID == 0) {
            setpgrp();
            int count = read(fdRead, buff, 1);  /// read from the file fd1 into fd2
            while (count != -1) {
                if (!count) {
                    break;
                }
                if (write(fdWrite, buff, 1) == -1) {
                    perror("smash error: write failed");
                    exit(0);  // not sure if we should return
                }
                count = read(fdRead, buff, 1);
                if (count == -1) {
                    perror("smash error: read failed");
                    exit(1);
                }
            }
            exit(1) ;
        }