0

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.

  • 1
    please read [mcve](https://stackoverflow.com/help/mcve). – Duck Dodgers Jan 22 '19 at 07:57
  • @JoeyMallone I don't think other parts are very necessary here. The problem can be resolved with my posted code. –  Jan 22 '19 at 08:00
  • @AlanBirtles After I read that, I don't think this question is a duplicate. I don't want the return code. The error message is printed before I get the status. I just want to modify the error message. –  Jan 22 '19 at 08:02
  • redirect stderr to suppress the msg from execvp https://stackoverflow.com/questions/14543443/in-c-how-do-you-redirect-stdin-stdout-stderr-to-files-when-making-an-execvp-or/14543484 – Marc Stroebel Jan 22 '19 at 08:33
  • @MarcStröbel It seems to be talking about using fstream. I am not using that. I am very to to this area. Could you be more specific? –  Jan 22 '19 at 08:44
  • Why would be you expecting this behaviour? It would be very confusing. In the first case, cat is tellinng you there's no file named ff. In the second case, your shell is (or should be) telling you there is no file named catt. Two completely different situations. Why do you want to masquerade the second one as the first? – n. m. could be an AI Jan 22 '19 at 09:02
  • @n.m. I am using the second to show that its status is different from the first. –  Jan 22 '19 at 09:05
  • I meant the third sorry. The error message is different and should remain different. – n. m. could be an AI Jan 22 '19 at 09:16
  • @n.m. I am using the third to show that this "ERROR:" is desired. –  Jan 22 '19 at 09:18
  • If you have nothing better to do with your time, you can try to intercept, parse, and modify the standard error stream of the program you are running. You will probably soon find out this is counterproductive. No existing shell is doung that. But whatever floats your boat. – n. m. could be an AI Jan 22 '19 at 09:33

1 Answers1

0

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';
        }
    }
}
Marc Stroebel
  • 2,295
  • 1
  • 12
  • 21
  • Could you please show me the code how to redirect that using my example? I am really confused with these. –  Jan 22 '19 at 08:56
  • But I don't want that log.txt to be created. Is that ok? Is it possible to save is as a string so that I can print it directly after waitpid? –  Jan 22 '19 at 09:12
  • use /dev/null instead – Marc Stroebel Jan 22 '19 at 09:15
  • Do you mean freopen("/dev/null", "w", stderr)? If so, how do I get its error message? I cannot customize it here sorry. I has to be the same. –  Jan 22 '19 at 09:20
  • @SeakyLuo you can redirect the output using pipes. See edits... https://jineshkj.wordpress.com/2006/12/22/how-to-capture-stdin-stdout-and-stderr-of-child-program/ – Marc Stroebel Jan 22 '19 at 13:31
  • Thank you! You saved my life! –  Jan 22 '19 at 17:39