bhavs
bhavs

Reputation: 2291

redirect stderr to a buffer in c

I have looked at the previous questions that have been asked. And I have come up with this code to obtain the current value of stderr, re-direct that to a buf and reassign stderr. This is code.

The redirect of the stderr to the buff is not happening. I can see this on the screen when I try to execute the code :

     ls: cannot access system: No such file or directory
     hellow world
     error from buffer

The source code looks like this :

#include<stdio.h>
static int fd;
static fpos_t pos;
char *buf;

void closeerr()
{
    fflush(stderr);
    fgetpos(stderr, &pos);
    fd = dup(fileno(stderr));
    buf =(char *)calloc(sizeof(char *),1024);
    stderr = fmemopen(buf, sizeof(buf), "w");
}

void reverterr()
{
    fflush(stderr);
    dup2(fd, fileno(stderr));
    close(fd);
    clearerr(stderr);
    fsetpos(stderr, &pos);
}

void main()
{
    closeerr();
    printf("hellow world");
    system(" ls -l system"); // this is where I see the error msg
    printf("error from buffer %s",buf);
    reverterr();
}

This code re-directs stdout(the logic would be the same to re-direct stderr) to a temp file ( Approach 1 as suggested below though I have not forked and created a child process to write into the file )

void switchStdout(const char *newStream)
{
  fflush(stdout);
  fgetpos(stdout, &pos);
  fd = dup(fileno(stdout));
  freopen(newStream, "w", stdout);

}

void revertStdout()
 {
  fflush(stdout);
  dup2(fd, fileno(stdout));
  close(fd);
  clearerr(stdout);
  fsetpos(stdout, &pos);
 }

void main(){
  switchStdout("/tmp/err.txt");
  printf("Hello world");
  revertStdout();
}

Upvotes: 0

Views: 1174

Answers (1)

fuz
fuz

Reputation: 92994

The fmemopen() function does not actually open a file descriptor, thus fileno() on a FILE obtained from fmemopen() returns an undefined value. fmemopen() is implemented by writing directly to the buffer without ever sending the data through the operating system. It is not possible to preserve the file opened with fmemopen() through a fork().

Another problem is that you never allocate memory for your buffer, read about the fmemopen() API and how to use it to understand the problem.

Here are two approaches that work:

  • open a temporary file, then fork(). In the forked process, dupe its file descriptor over file descriptor 2 (STDERR_FILENO) and then execute your command. In the parent, wait() for the child, then read what it wrote to the temporary file. Note that you need to do an lseek() before reading as the child will change the file pointer.
  • open a fifo with pipe(), then fork(). In the child, dupe the writing end over file descriptor 2, close the reading end and then execute your command. In the parent, close the writing end and read what the child wrote from the reading end while its running. Don't forget to wait() for the child afterwards.

Upvotes: 1

Related Questions