Search code examples
c++forkstderrerrnoexecvp

c++ evecvp error handling for invalid command


I am trying to implement a simple shell. Everything else works fine except for the error handling.

When I try to do execute an invalid command like "cat ff", in which "ff" does not exist, I got this:

Terminal Output

The expected behavior should be like the third one "catt f". It must start with "ERROR:" and then the error message, which means it should be "ERROR:cat: ff: No such file or directory"

How should I modify my code to achieve that? Thanks in advance!

#include <fcntl.h>
#include <iostream>
#include <unistd.h>
#include <cstring>
#include <errno.h>
#include <sys/wait.h>

using namespace std;

int main(){
    int pid;
    int status;
    char *cmd[] = {"cat", "ff", NULL};
    if ((pid = fork()) == 0){
        if (execvp(cmd[0], cmd) == -1){
            cout << "ERROR:" << strerror(errno) << '\n';
        }
    }else if (pid == -1){
        cout << "ERROR:" << strerror(errno) << '\n';
    }else{
        waitpid(pid, &status, 0);
        cout << "Status: " << status << '\n';
    }
}

The status here isn't very much necessary here. It is just my attempt to figure out whether it comes before that error message. I am super new to this and I am very confused and lost. Please forgive me if I did anything unnecessarily.


Solution

  • the second line cat: ff: No suche file... is an error output to stderr pipe written by cat command. If you want to suppress this you need to redirect stderr pipe. The execution of your shell command "cat" was successful, so it's handled through your last else condition. You need to check there for e.g. status 256 "no such file" and then print the error yourself.

    #include <fcntl.h>
    #include <iostream>
    #include <unistd.h>
    #include <cstring>
    #include <errno.h>
    #include <sys/wait.h>
    #include <cstdio>
    
    using namespace std;
    
    int main(int argc, char** argv){
        int pid;
        int status;
        char *cmd[] = {"cat", "ff", NULL};
        int pipes[2];
        pipe(pipes);
        if ((pid = fork()) == 0){
            dup2(pipes[1], STDERR_FILENO);
            if (execvp(cmd[0], cmd) == -1){
                cout << "ERROR:" << strerror(errno) << '\n';
            }
        }else if (pid == -1){
            cout << "ERROR:" << strerror(errno) << '\n';
        }else{
            waitpid(pid, &status, 0);
            if(256 == status) {
                cout << "ERROR: ";
                char buffer[100];
                int count = read(pipes[0], buffer, sizeof(buffer)-1);
                if (count >= 0) {
                    buffer[count] = 0;
                    cout << buffer;
                    cout << endl;
                } else {
                    cout << "IO Error" << endl;
                }
            } else {
                cout << "Status: " << status << '\n';
            }
        }
    }