views:

451

answers:

4

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.

+2  A: 

The 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
Jerry Coffin
arg I want it in C
@user355926: on what platform? The standard doesn't cover this, so you'll need some non-portable code to do it in C.
Jerry Coffin
I need to somehow block the command in C so I can get its stderr
Jerry Coffin: using OpenBSD
+2  A: 

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");
}
Dusty
There are two other similar answers, but for some reason they seem to think you need to fork in order to use dup2.
JeremyP
A: 

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;
}
dreamlax
A: 

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.

Dummy00001