I'm writing a c++ program that executes and outputs (in real-time) a shell script, makefile or just another program. However I would like to have my program return differently when there are errors or no error.
#include "execxi.h"
using namespace std;
int execXI::run(string command)
{
FILE *in;
char buff[512];
// is this the check for command execution exited with not 0?
if(!(in = popen(command.c_str(), "r"))){
// I want to return the exit code and error message too if any
return 1;
}
// this part echoes the output of the command that's executed
while(fgets(buff, sizeof(buff), in)!=NULL){
cout << buff;
}
pclose(in);
return 0;
}
is what I have so far.
Let's say this script ran make
to build a program and it gave an error like so
on_target_webkit_version out/Release/obj/gen/webkit_version.h
Traceback (most recent call last):
File "../build/webkit_version.py", line 107, in <module>
sys.exit(main())
File "../build/webkit_version.py", line 103, in main
return EmitVersionHeader(*sys.argv[1:])
File "../build/webkit_version.py", line 86, in EmitVersionHeader
webkit_revision = GetWebKitRevision(webkit_dir, version_file)
File "../build/webkit_version.py", line 60, in GetWebKitRevision
version_info = lastchange.FetchVersionInfo(
AttributeError: 'module' object has no attribute 'FetchVersionInfo'
make: *** [out/Release/obj/gen/webkit_version.h] Error 1
Considering that make
exited with code not 0
, let's say 1
, and it output in stderr
is it not possible for me to capture these exit codes and error message in the end?
How can I capture the exit code and stderr
after outputting the results of the program, and return the exit code
/ stderr
in the function?
If you are interested in the error code, this is a more portable way of getting it rather than dividing by 256:
printf("Exit code: %i\n", WEXITSTATUS(pclose(fp)));
However, popen
is one way, so you are either creating further workarounds by the usual redirection style in shell, or you follow this untested code to do it right:
#include <unistd.h>
#include <stdio.h>
/* since pipes are unidirectional, we need two pipes.
one for data to flow from parent's stdout to child's
stdin and the other for child's stdout to flow to
parent's stdin */
#define NUM_PIPES 2
#define PARENT_WRITE_PIPE 0
#define PARENT_READ_PIPE 1
int pipes[NUM_PIPES][2];
/* always in a pipe[], pipe[0] is for read and
pipe[1] is for write */
#define READ_FD 0
#define WRITE_FD 1
#define PARENT_READ_FD ( pipes[PARENT_READ_PIPE][READ_FD] )
#define PARENT_WRITE_FD ( pipes[PARENT_WRITE_PIPE][WRITE_FD] )
#define CHILD_READ_FD ( pipes[PARENT_WRITE_PIPE][READ_FD] )
#define CHILD_WRITE_FD ( pipes[PARENT_READ_PIPE][WRITE_FD] )
void
main()
{
int outfd[2];
int infd[2];
// pipes for parent to write and read
pipe(pipes[PARENT_READ_PIPE]);
pipe(pipes[PARENT_WRITE_PIPE]);
if(!fork()) {
char *argv[]={ "/usr/bin/bc", "-q", 0};
dup2(CHILD_READ_FD, STDIN_FILENO);
dup2(CHILD_WRITE_FD, STDOUT_FILENO);
/* Close fds not required by child. Also, we don't
want the exec'ed program to know these existed */
close(CHILD_READ_FD);
close(CHILD_WRITE_FD);
close(PARENT_READ_FD);
close(PARENT_WRITE_FD);
execv(argv[0], argv);
} else {
char buffer[100];
int count;
/* close fds not required by parent */
close(CHILD_READ_FD);
close(CHILD_WRITE_FD);
// Write to child’s stdin
write(PARENT_WRITE_FD, "2^32\n", 5);
// Read from child’s stdout
count = read(PARENT_READ_FD, buffer, sizeof(buffer)-1);
if (count >= 0) {
buffer[count] = 0;
printf("%s", buffer);
} else {
printf("IO Error\n");
}
}
}
The code is from here:
http://jineshkj.wordpress.com/2006/12/22/how-to-capture-stdin-stdout-and-stderr-of-child-program/
The returnvalue of the child process is in the top 16 8 bits. You have
to divide the returned value of pclose by 256, then you get the
searched return value of the child process.
Gotten from http://bytes.com/topic/c/answers/131694-pclose-returning-termination-status-command
My answer would be pclose(in)/256
is exit code.
I still don't know how to capture stderr or sdtout differently but until there's an answer for that I will accept this as my answer.
Thanks for the reply about exit code Logan.
I believe a round-trip to get stderr would be to redirect it to a temporary file:
FILE* f = popen("cmd 2>/tmp/tmpfile.txt", "r");