Why child process returns exit status = 32512 in unix?

32,023

execvp takes a path to an executable, and arguments with which to launch that executable. It doesn't take bourne shell commands.

ls | wc is a bourne shell command (among others), and it can't be broken down into the path to an executable and some arguments due to the use of a pipe. This means it can't be executed using execvp.

To execute a bourne shell command using execvp, one has to execute sh and pass -c and the command for arguments.

So you want to execute ls | wc using execvp.

char *const argv[] = {
    "sh",
    "-c", "ls | wc",  // Command to execute.
    NULL
};

execvp(argv[0], argv)

You apparently tried

char *const argv[] = {
    "sh",
    "-c", "ls",  // Command to execute.
    "|",         // Stored in called sh's $0.
    "wc",        // Stored in called sh's $1.
    NULL
};

That would be the same as bourne shell command sh -c ls '|' wc.

And both are very different than shell command sh -c ls | wc. That would be

char *const argv[] = {
    "sh",
    "-c", "sh -c ls | wc",  // Command to execute.
    NULL
};

You seem to think | and wc are passed to the sh, but that's not the case at all. | is a special character which results in a pipe, not an argument.


As for the exit code,

Bits 15-8 = Exit code.
Bit     7 = 1 if a core dump was produced.
Bits  6-0 = Signal number that killed the process.

32512 = 0x7F00

So it didn't die from a signal, a core dump wasn't produced, and it exited with code 127 (0x7F).

What 127 means is unclear, which is why it should accompanied by an error message. You tried to execute program ls | wc, but there is no such program.

Share:
32,023
Mihran Hovsepyan
Author by

Mihran Hovsepyan

Software Engineer at OneMarketData

Updated on April 30, 2020

Comments

  • Mihran Hovsepyan
    Mihran Hovsepyan about 4 years

    In my program I'm executing given command and getting result (log, and exit status). Also my program have to support shell specific commands (i.e. commands which contains shell specific characters ~(tild),|(pipe),*). But when I try to run sh -c ls | wc in my home directory via my program it failed and its exit status was 32512, also in stderr stream "sh: ls | wc: command not found" was printed.

    But the interesting thing is that the command sh -c ls | wc works correct if I run it in shell.

    What is the problem? Or more preferable how can I run shell specific commands via my program (i.ec which command with which parameters should I run)?

    The code part bellow is in child part after fork(). It executs the command.

    tokenized_command is std::vector<std::string> where in my case "sh", "-c", "ls", "|", "wc" are stored, also I have tried to store there "sh", "-c", "\"ls | wc\"" but result is same. command is char * where full command line is stored.

            boost::shared_array<const char *> bargv(new const char *[tokenized_command.size() + 1]);
            const char **argv = bargv.get();
            for(int i = 0; i < tokenized_command.size(); ++i)
            {
                argv[i] = tokenized_command[i].c_str();
                printf("argv[%d]: %s\n", i, argv[i]); //trace
            }
            argv[tokenized_command.size()] = NULL;
    
            if(execvp(argv[0], (char * const *)argv) == -1)
            {
                fprintf(stderr, "Failed to execute command %s: %s", command, strerror(errno));
                _exit(EXIT_FAILURE);
            }
    

    P.S.

    I know that using system(command) instead execvp can solve my problem. But system() waits until command is finished, and this is not good enough for my program. And also I'm sure that in implementation of system() one of exec-family functions is used, so the problem can be solved via exec as well, but I don't know how.

  • Jonathan
    Jonathan about 13 years
    Actually, it was probably spawning a separate shell to run ls and also spawning a wc to receive its output.
  • pajton
    pajton about 13 years
    Yes, I know, I just didn't underlined it.
  • Mihran Hovsepyan
    Mihran Hovsepyan about 13 years
    No I'm getting error message. Sorry that I havn't put it here. sh: ls | wc: command not found this is the message/
  • ikegami
    ikegami about 13 years
    @Mihran Hovsepyan, you are trying to execute the file named "ls | wc" rather than the bourne shell command "ls | wc". If you want to execute a bourne shell command, you need to launch a bourne shell and pass it the command. sh -c 'ls | wc'.
  • Mihran Hovsepyan
    Mihran Hovsepyan about 13 years
    I don't wan't lunch shell. I wan't run shell specific commands from my program.
  • ikegami
    ikegami about 13 years
    @Mihran Hovsepyan. It's not clear what you mean by that. If you mean you want to avoid running a shell, then you simply can't execute ls | wc. If you mean you want to make the shell configurable, I don't really see the point, but nothing's stopping you.
  • ikegami
    ikegami about 13 years
    @Mihran Hovsepyan. If you wanted to avoid running a shell, you'll need to launch two processes (ls in one, wc in other), creating a pipe between them in the process. You'll also have to manage the termination of two processes instead of one. It might even be easier to implement the functionality you want from ls and wc yourself.
  • Mihran Hovsepyan
    Mihran Hovsepyan about 13 years
    I want avoid running a shell. Now re: first comment ls | wc wouldn't work, because ls doesn't take as argument | and wc. But I think that sh takes as arguments -c and 'ls | wc'. re: second comment I want my program can run everything which is possible in shell ls | wc is just example.
  • ikegami
    ikegami about 13 years
    Yes @Mihran Hovsepyan, sh -c 'ls | wc', runs the bourne shell (sh) and passes arguments -c and a shell command (ls | wc).
  • Mihran Hovsepyan
    Mihran Hovsepyan about 13 years
    Yes @ikegami. I'm talking about same. Then why this doesn't work?
  • ikegami
    ikegami about 13 years
    @Mihran Hovsepyan, I've updated to my post. It should now answer all your questions.
  • Mark Nunberg
    Mark Nunberg about 10 years
    You have "NULL" instead of NULL. Just sayin'