1

When failing to launch an exec command - I can only get a bad return code from the exec - how can I also get the stderr?

#include <stdio.h>
#include <unistd.h>

int main(){
    char* argv[] = {"bla", NULL};
    execvp(argv[0], argv);
    printf("exec failed\n");
    return 0;
}

In this snippet the printf is only reached if the execvp breaks - which in my case it does. I'm interested in getting the output of the shell for trying to run bla:

Command 'bla' not found, did you mean:

  command 'tla' from deb tla (1.3.5+dfsg1-2build1)
  command 'bwa' from deb bwa (0.7.17-4)
  command 'bls' from deb bacula-sd (9.4.2-2ubuntu5)

Try: sudo apt install <deb name>

How can I find it? tried playing with errno but didn't find the data I'm looking for

errno try:

#include <errno.h>
#include <stdio.h>
#include <unistd.h>

int main() {
  char* argv[] = {"bla", NULL};
  execvp(argv[0], argv);
  printf("exec failed\n %d", errno);
  return 0;
}

returns 2 - but no info.

2 is " 2 ENOENT No such file or directory" - but I still want Bash's stderr

CIsForCookies
  • 12,097
  • 11
  • 59
  • 124
  • Did you consider to redirect `stderr` in a pipe? – the busybee Sep 22 '22 at 09:17
  • @thebusybee I have - it seems like the redirection only happens after the process is spawned - so the error of the shell is not captured – CIsForCookies Sep 22 '22 at 09:20
  • 1
    Why `waitpid`? As long as I can see your code is not calling `fork`. – David Ranieri Sep 22 '22 at 09:21
  • @DavidRanieri It is a snippet of a bigger piece where I fork, and the child calls exec. I'll delete the waitpid as indeed it is not relevant for this snippet – CIsForCookies Sep 22 '22 at 09:23
  • 1
    Are you exec'ing a shell or are you exec'ing another executable? – Fe2O3 Sep 22 '22 at 09:28
  • 1
    I think exec doesn't rely on the shell, it asks the OS directly, even if the program was started by the shell. If what you want is the output of Bash, then you need to explicitly involve Bash, like `exec bash bla`. But then, provided that Bash is installed, exec will always work. So maybe you need to fork, the child execs Bash and captures STDERR, the parent waits for the child and somehow gets STDERR. – Fabio says Reinstate Monica Sep 22 '22 at 09:29
  • `execvp` uses the shell's environment PATH, but indeed - you might be the right that I'm not actually invoking the shell itself. If so - then @DavidRanieri's answer is the maximum I can get without actually invoking `execvp("bash", {"bash" "bla", NULL});` – CIsForCookies Sep 22 '22 at 09:33
  • `execvp` invokes the shell under certain circumstances, at least on some systems. As your observation shows, it is invoked in your case. – the busybee Sep 22 '22 at 10:11

2 Answers2

2

You need to #include <errno.h>, you can also use perror() to get more information about the error:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>

int main(void)
{
    char* argv[] = {"bla", NULL};

    execvp(argv[0], argv);
    perror("execvp");
    fprintf(stderr, "errno: %d\n", errno);
    exit(EXIT_FAILURE);
}

Output:

execvp: No such file or directory
errno: 2
David Ranieri
  • 39,972
  • 7
  • 52
  • 94
0

Search with keywords "c exec stderr", you can get many mature solution. Here is the top answer. stackoverflow - R Samuel Klatchko - Redirecting exec output to a buffer or file