4

In our C++ project under MacOS X, we are using stdio for interaction with clients. Yet, the dylib we are using is also using stdio to print "open log files". This breaks down all communication between our clients and the application. I looked at the examples of redirecting stdio to a file or temporarily disabling stdio. Yet, we could not succeed in it.

So, how can we disable or redirect stdio temporarily while interacting with the dylib.

barbarossa
  • 45
  • 4

2 Answers2

3

OSX is a POSIX systems, and like all POSIX systems standard output is file descriptor STDOUT_FILENO (which is a macro defined as 1).

What you can do is duplicate STDOUT_FILENO to another file descriptor, open a temporary file and duplicating (using dup2) the temporary file as STDOUT_FILENO. Then whenever there is output to standard out (using plain write, C printf or C++ std::cout) it will be put in the temporary file.

When done with the temporary "redirection" you simply duplicate the saved standard output (from the first dup call) back into STDOUT_FILENO. and close and remove the temporary file.

Something like the following:

int saved_stdout = dup(STDOUT_FILENO);

int temp_file = open("/tmp/temp_stdout", O_WRONLY, 0600);
dup2(temp_file, STDOUT_FILENO);  // Replace standard out

// Code here to write to standard output
// It should all end up in the file /tmp/temp_stdout

dup2(saved_stdout, STDOUT_FILENO);  // Restore old standard out
close(temp_file)
unlink("/tmp/temp_stdout");  // Remove file
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • Thank you Joachim, we tried your suggestion. Unfortunately it still prints out "open log files" to the stdio. – barbarossa May 23 '16 at 09:45
3
void RedirectStandardStreamsToDEVNULL(int *_piOriginalSTDIN_FILENO, int *_piOriginalSTDOUT_FILENO, int *_piOriginalSTDERR_FILENO)
{
        //flushing pending things before redirection.
        //fflush(stdin);
        fflush(stdout);
        fflush(stderr);

        *_piOriginalSTDIN_FILENO = dup(STDIN_FILENO);
        *_piOriginalSTDOUT_FILENO = dup(STDOUT_FILENO);
        *_piOriginalSTDERR_FILENO = dup(STDERR_FILENO);

        int devnull = open("/dev/null", O_RDWR);
        dup2(devnull, STDIN_FILENO);
        dup2(devnull, STDOUT_FILENO);
        dup2(devnull, STDERR_FILENO);
        close(devnull);
}
void RestoreStandardStreams(int *_piOriginalSTDIN_FILENO, int *_piOriginalSTDOUT_FILENO, int *_piOriginalSTDERR_FILENO)
{
        //flushing pending things before restoring.
        //fflush(stdin);
        fflush(stdout);
        fflush(stderr);

        dup2(*_piOriginalSTDIN_FILENO, STDIN_FILENO);
        dup2(*_piOriginalSTDOUT_FILENO, STDOUT_FILENO);
        dup2(*_piOriginalSTDERR_FILENO, STDERR_FILENO);
}

void myfunction()
{
    int iOriginalSTDIN_FILENO = -1;
    int iOriginalSTDOUT_FILENO = -1;
    int iOriginalSTDERR_FILENO = -1;
    RedirectStandardStreamsToDEVNULL(&iOriginalSTDIN_FILENO, &iOriginalSTDOUT_FILENO, &iOriginalSTDERR_FILENO);

//all of your code which prints to stdout or stderr will be directed to /dev/null

    RestoreStandardStreams(&iOriginalSTDIN_FILENO, &iOriginalSTDOUT_FILENO, &iOriginalSTDERR_FILENO);

}

Important point is to identify the functions which are called inside dylib from your code. Now, surround such functions with Redirect and Restore functions described above.

sameerkn
  • 2,209
  • 1
  • 12
  • 13
  • Thank you sameerkn, we tried the solution. We noticed that the first time we run the code, the "open log files" text disappears from the console. But the next times, it remains and crashes communication with client app. I think your approach handles all three cases of stdio usage; so I expected that it would work. – barbarossa May 24 '16 at 04:52
  • In addition, if I write `close(STDOUT_FILENO);` or `fclose(stdout);` the log text never gets printed. Is there a way to restore stdout afterwards? – barbarossa May 24 '16 at 05:00
  • `dup2` itself does closing of the STDOUT_FILENO inside `Redirect` function. Are you properly nesting all the call to dylib under `Redirect` and `Restore` functions? – sameerkn May 24 '16 at 05:49
  • Here is the way I call the function: ` int iOriginalSTDIN_FILENO = -1; int iOriginalSTDOUT_FILENO = -1; int iOriginalSTDERR_FILENO = -1; RedirectStandardStreamsToDEVNULL(&iOriginalSTDIN_FILENO, &iOriginalSTDOUT_FILENO, &iOriginalSTDERR_FILENO); std::string a = listCardTypeAndSlots(); RestoreStandardStreams(&iOriginalSTDIN_FILENO, &iOriginalSTDOUT_FILENO, &iOriginalSTDERR_FILENO); std::cout << a << std::endl;` – barbarossa May 24 '16 at 06:14
  • One more point. If I pause between restore and std::cout for 5 seconds, the log gets printed 5 seconds later. So, the log gets written to the console when I write something very simple to the std::cout. – barbarossa May 24 '16 at 06:33
  • Dear sameerkn, we solved the issue. We used `std::cout.flush();` right before calling restore. It works like a charm. Thank you for your support. – barbarossa May 24 '16 at 07:25
  • Is `"open log file"` a string which gets printed to console? or what is it? – sameerkn May 24 '16 at 07:25
  • Hi sameerkn, how would we do it in windows? – barbarossa May 24 '16 at 09:48
  • These might help: http://stackoverflow.com/questions/1692987/redirect-stdout-to-an-edit-control-win32 [_dup, _dup2 in Win32](https://msdn.microsoft.com/en-us/library/8syseb29.aspx) – sameerkn May 24 '16 at 10:45