Like I said, popen_result is valid because popen() created a shell successfully.
That the shell failed to do anything useful with the command is a separate problem.
This is getting increasingly ugly
Code:
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/select.h>
int main(int argc, char *argv[])
{
FILE *popen_result;
char *cmd = argc > 1 ? argv[1] : "Oops";
char buff[512] = { 0 };
int p[2];
int temperr = dup(2); // copy where stderr is at the moment
pipe(p); // create a pipe
fcntl(p[0],F_SETFL,O_NONBLOCK);
dup2(p[1],2); // make stderr use one end of the pipe
popen_result = popen(cmd, "r");
// check if an error message line was printed by the sub-shell
struct timeval tmo = { .tv_sec = 0, .tv_usec = 1000 };
fd_set rdset;
FD_ZERO(&rdset);
FD_SET(p[0],&rdset);
if ( select(p[0]+1,&rdset,NULL,NULL,&tmo) > 0 ) {
char emsg[500];
ssize_t n = read(p[0],emsg,sizeof(emsg)-1);
if ( n > 0 ) {
emsg[n] = '\0';
printf("StdErrMsgFromPopen=>>>%s<<<\n",emsg);
}
}
close(p[0]);
close(p[1]); // All done with the pipe
stderr = fdopen(temperr,"w"); // get back stderr
if(!popen_result){
printf("Error!!!\n");
return 0;
}
printf("Reading %p...\n",(void*)popen_result);
if ( feof(popen_result) ) {
printf("Already at EOF!\n");
}
if ( ferror(popen_result) ) {
printf("Already at error!\n");
}
while(fgets(buff, sizeof(buff), popen_result)!=NULL){
printf(">>> %s", buff);
}
if ( feof(popen_result) ) {
printf("Got EOF!\n");
}
if ( ferror(popen_result) ) {
printf("Got error!\n");
}
printf("Closing...\n");
pclose(popen_result);
}
$ gcc -Wall foo.c
$ ./a.out
StdErrMsgFromPopen=>>>sh: 1: Oops: not found
<<<
Reading 0x21db010...
Got EOF!
Closing...
$ ./a.out 'Err'
StdErrMsgFromPopen=>>>sh: 1: Err: not found
<<<
Reading 0x20c9010...
Got EOF!
Closing...
$ ./a.out 'ls *.c'
Reading 0x1d02010...
>>> bar.c
>>> foo.c
>>> locale_wide_char.c
>>> main.c
Got EOF!
Closing...