Want to win a PS4? Go Premium and enter to win our High-Tech Treats giveaway. Enter to Win

x
?
Solved

redirecting stderr in c

Posted on 1998-07-30
8
Medium Priority
?
1,346 Views
Last Modified: 2013-12-26
I want to execute a program which outputs to stderr, in a section of c code.  I could use popen() to monitor output, but this only pipes stdout back to the calling program.  I need to read from stderr to recieve update information until the program has finished executing.

How do I do this?
0
Comment
Question by:zed1
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
8 Comments
 

Author Comment

by:zed1
ID: 1295239
Adjusted points to 200
0
 
LVL 3

Expert Comment

by:braveheart
ID: 1295240
/*
 * Command program to echo supplied arguments to standard error
 */
#include <stdio.h>
#include <stdlib.h>

main(int argc, char **argv)
{
    /* Skip program name */
    argc--;argv++;

    /* Print remaining arguments, separated by spaces, terminated by newline */
    while (argc--)
        fprintf(stderr,"%s%c", *argv++, argc ? '\n' : ' ' );
}
0
 

Author Comment

by:zed1
ID: 1295241
Hmmm...  Perhaps you only read the first sentence of my question.  Sorry for not explaining it well enough.

I want to execute a program using a shell command in c.  The program that I want to execute outputs to stderr.  Using the popen() function, only stdout gets piped back to my program, NOT stderr which is what I need.

If the program outputted to stdout I could simply use the following code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

      main()
            {
                    char *cmd = "<command>";
                     char buf[BUFSIZ];
                     FILE *ptr;

                    if ((ptr = popen(cmd, "r")) != NULL)
                          while (fgets(buf, BUFSIZ, ptr) != NULL)
                                
                          //each line from stdout gets
                          //put into the buf variable
                return 0;
            }

However, this code wont work for me.

0
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 
LVL 3

Expert Comment

by:braveheart
ID: 1295242
How are you piping the stderr output of your program into your other program?  Are you using "|&" instead of "|" ?
0
 
LVL 84

Expert Comment

by:ozo
ID: 1295243
char *cmd = "command 2>&1";
0
 
LVL 1

Expert Comment

by:grisu072798
ID: 1295244
I have not tried this, but let me make a suggestion:
(1) The external program could close or redirect it's standard output and instead write it's stderr to that file descriptor. This could be done by exchanging the file descriptors _iobuf[1]
and _iobuf[2].
(2) If you don't have the source for the external program, you could write a wrapper around it which does the above thing. If you then execute the 'external' prg by calling vfork() (or was it clone(), anyway, so that the new program overlays the old one and inherits all its file descriptors) these settings should remain.
0
 
LVL 3

Accepted Solution

by:
dhm earned 800 total points
ID: 1295245
This is a little tedious to set up, but it's not that hard.  What you have to do is explicitly do all the magic that popen() normally does for you.  Here's code that you can use to do it.  The super_popen() function is what you want; I've added a main() that shows you how to use it, and a sample subprogram that echos back whatever the main program sends to it on its on stdin, and then prints messages on both stdout and stderr.  I've tested this on Solaris-2.5.1, but it should work on any recent unix.

d.

---------------------------------------------------
Main Program:
/*
 * Sample program to demonstrate super_popen
 *
 * by dave madden <dhm@webvision.com>
 */
#include <stdio.h>
#include <errno.h>
#include <sys/select.h>

int
super_popen( FILE **SI_SO_SE, const char *cmd )
{
      int             si[2] = { -1, -1 };
      int             so[2] = { -1, -1 };
      int             se[2] = { -1, -1 };
      pid_t       pid;
      int             e;
      int             fd;

      /*
       * Create 3 pipes to talk to subprocess on stdin/stdout/stderr
       */
      if (pipe( si ) != 0 || pipe( so ) != 0 || pipe( se ) != 0) goto SHUTDOWN;

      if ((pid = fork( )) == -1) goto SHUTDOWN;

      if (pid) {                              /* in parent */
            close( si[0] );
            close( so[1] );
            close( se[1] );
            SI_SO_SE[0] = fdopen( si[1], "w" );
            SI_SO_SE[1] = fdopen( so[0], "r" );
            SI_SO_SE[2] = fdopen( se[0], "r" );
            
            return 0;                        /* OK! */
      }

      /*
       * This is the child process...we have to fiddle around with the
       * pipe descriptors and then exec the program.
       */

      /*
       * Make sure none of our stdin/stdout/stderr descriptors are
       * on FDs 0, 1, or 2 (if they are, it'll screw things up when
       * we do the dup2()'s)
       */
      if (si[0] < 2 || so[1] < 2 || se[1] < 2) {
            int       free_index = 0;
            int       free_fds[3];
            printf( "have to (Edited by Computer101) with FDs in child\n" );
            for (fd = 3; fd < FD_SETSIZE; fd++) {
                  if (fd != si[0] && fd != si[1] && fd != se[1]) {
                        free_fds[free_index++] = fd;
                        if (free_index == 3) break;
                  }
            }
            if (dup2( si[0], free_fds[0] ) == -1 ||
                  dup2( so[1], free_fds[1] ) == -1 ||
                  dup2( se[1], free_fds[2] ) == -1) exit( errno );
            si[0] = free_fds[0];
            so[1] = free_fds[1];
            se[1] = free_fds[2];
      }
            
      /* close all other descriptors...don't want child to have copies */
      for (fd = 0; fd < FD_SETSIZE; fd++)
            if (fd != si[0] && fd != so[1] && fd != se[1]) close( fd );
      
      dup2( si[0], 0 );                  /* attach pipes to FD 0, 1, and 2 */
      dup2( so[1], 1 );
      dup2( se[1], 2 );

      close( si[0] );
      close( so[1] );
      close( se[1] );

/*      write( 1, "Hello\n", 6 );
      write( 2, "World\n", 6 );
      exit( 0 );*/

      exit( execl( "/usr/bin/sh", "sh", "-c", cmd, 0 ) );

  SHUTDOWN:      /* something went wrong...close the pipes & etc */
      e = errno;
      close( si[0] ); close( si[1] );
      close( so[0] ); close( so[1] );
      close( se[0] ); close( se[1] );
      errno = e;
      return -1;
}

int
main( int argc, char **argv )
{
      FILE      *child_io[3];

      if (argc != 2) {
            printf( "usage: %s <name-of-program-to-run>\n", argv[0] );
            exit( 1 );
      }

      if (super_popen( child_io, argv[1] ) == 0) {
            char       buf[256];
            
            fprintf( child_io[0], "Message to child\n" );
            fflush( child_io[0] );

            while (fgets( buf, sizeof(buf), child_io[1] ) != 0) {
                  printf( "Child STDOUT: \"%.*s\"\n", strlen(buf) - 1, buf );
            }

            while (fgets( buf, sizeof(buf), child_io[2] ) != 0) {
                  printf( "Child STDERR: \"%.*s\"\n", strlen(buf) - 1, buf );
            }
      } else {
            printf("couldn't run %s: %d (%s)\n", argv[1], errno, strerror(errno));
      }

      exit( 0 );
}
---------------------------------------------------------
Sample subprogram:

#include <stdio.h>

int
main( int argc, char **argv )
{
      char       buf[128];

      fgets( buf, sizeof(buf), stdin );
      printf( "Child received \"%s\" on stdin\n", buf );
      fprintf( stdout, "This is a message on stdout\n" );
      fprintf( stderr, "This is a message on stderr\n" );
      return 0;
}

0
 

Author Comment

by:zed1
ID: 1295246
Thanx dhm, your solution seems to be working fine.  At first I had a little trouble recieving output from stderr and stdout simultaneously, but all I had to do was alter the while loops in the main.
0

Featured Post

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

In this article, I'll describe -- and show pictures of -- some of the significant additions that have been made available to programmers in the MFC Feature Pack for Visual C++ 2008.  These same feature are in the MFC libraries that come with Visual …
Introduction: Dynamic window placements and drawing on a form, simple usage of windows registry as a storage place for information. Continuing from the first article about sudoku.  There we have designed the application and put a lot of user int…
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
Have you created a query with information for a calendar? ... and then, abra-cadabra, the calendar is done?! I am going to show you how to make that happen. Visualize your data!  ... really see it To use the code to create a calendar from a q…

604 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question