The shell command $ avrdude -c usbtiny
outputs text to stderr. I cannot read it with commmands such as head-less-more cos it is not stdout. I want the text to stdout or to a file. How can I do it in C? I have tried to solve the problem by my last question but still unsolved.
views:
451answers:
4The normal way would be something like:
avrdude -c usbtiny 2>&1
This directs what would normally go to stderr to go to stdout instead. If you'd prefer to direct it to a file, you could do something like:
avrdude -c usbtiny 2> outputfile.txt
I've not tried something like this in OpenBSD, but in at least a few *nix-like systems, you can do this using dup2
.
#include <unistd.h>
#include <stdio.h>
int main(void) {
fprintf(stderr, "This goes to stderr\n");
dup2(1, 2); //redirects stderr to stdout below this line.
fprintf(stderr, "This goes to stdout\n");
}
The following uses the POSIX function to duplicate the standard output file number into the standard error file number. Duplicating stderr to stdout is given in the POSIX page for dup2
as an example usage of the function.
#include <unistd.h>
#include <stdio.h>
int main (void)
{
pid_t child = fork();
if (child == 0)
{
dup2(STDOUT_FILENO, STDERR_FILENO);
execlp("avrdude", "-c", "usbtiny", NULL);
}
else if (child > 0)
{
waitpid(child);
puts("Done!");
}
else
{
puts("Error in forking :(");
}
return 0;
}
I need to somehow block the command in C so I can get its stderr
Start by reading man fork
, man exec
on how to start a child process. Look into man 7 signal
, man sigaction
and man wait
for how to reap the child.
Finally, the man dup2
.
Untested code to exemplify:
int pip_stderr[2];
int r;
int pid;
r = pipe(pip_stderr);
assert( r != -1 );
int pid = fork();
assert( pid != -1 );
if (pid == 0) { /* child */
/* child doesn't need to read from stderr */
r = close(pip_stderr[0]); assert( r != -1 );
/* make fd 2 to be the writing end of the pipe */
r = dup2(pip_stderr[1], 2); assert( r != -1 );
/* close the now redundant writing end of the pipe */
r = close(pip_stderr[1]); assert( r != -1 );
/* fire! */
exec( /* whatever */ );
assert( !"exec failed!" );
} else { /* parent */
/* must: close writing end of the pipe */
r = close( pip_stderr[1] ); assert( r != -1 );
/* here read from the pip_stderr[0] */
r = waitpid(pid,0,0); assert( r == pid );
}
Using dup2() we replace stderr (which is fd 2) of the child with a writing end of a pipe. pipe() is called before fork(). After fork we also have to close all hanging ends of the pipe so that the reading in parent process would actually receive EOF.
Probably there is a simpler solution using stdio, but I'm not aware of it. Since popen() runs the command via shell, probably one can tell it to redirect stderr to stdout (and send stdout to /dev/null). Never tried that.
One can also use mktemp() (man 3 mktemp
) to create a temp file name, compose command for system() to redirect stderr of the command to the temp file and after system() returns read the temp file.