Can I create my own output stream other than stdout and stderr?
The UNIX man pages for it unistd.h
states:
The following symbolic constants are defined for file streams:
STDIN_FILENO File number of stdin. It is 0.
STDOUT_FILENO File number of stdout. It is 1.
STDERR_FILENO File number of stderr. It is 2.
grepping all my header files, I believe it is true.
[/usr]grep -r "STDIN_FILENO" include
include/unistd.h:#define STDIN_FILENO 0 /* Standard input. */
[/usr] grep -r "STDOUT_FILENO" include
include/unistd.h:#define STDOUT_FILENO 1 /* Standard output. */
[/usr]grep -r "STDERR_FILENO" include
include/boost/asio/detail/impl/handler_tracking.ipp: ::write(STDERR_FILENO, line, length);
include/unistd.h:#define STDERR_FILENO 2 /* Standard error output. */
Even though they are defined, they never seem to be used by any other std file on my machine. I find this strange. Perhaps 0,1 and 2 are used elsewhere in place of certain macros. Macros simply exist to be referenced as an indication of how streams are configured.?
Anyway, we can capture specific output streams in the shell by doing this:
./program 1> stdout.txt
./program 2> stderr.txt
./program > both.txt 2>&1
I want to create my own output stream and capture it by doing the following:
./program 3> mine.txt
I tried searching for unistd.h
other files included in the list <iostream>
to see how std::cout
and how they work std::cerr
, but as you might imagine, I was lost and confused.
I'm more interested in whether you can do this rather than this is a good idea.
source to share
Open file descriptors are inherited by child processes. The operating system takes care of connecting the process to the three standard threads, but you can do any number open()
and then exec()
(preferably after the previous one fork()
). The child can then scan the list of open file descriptors (s /proc/self/fd/
) or somehow "find out" which ones to use.
Here's a small example written in C.
#include <errno.h> /* errno */
#include <stdio.h> /* atoi, fprintf */
#include <stdlib.h> /* EXIT_SUCCESS, EXIT_FAILURE */
#include <string.h> /* strerror, strlen */
#include <unistd.h> /* write */
static const char *const message = "hello, world\n";
int main(int argc, char * * argv)
{
int fd;
int i;
for (i = 1; i < argc; ++i)
{
fd = atoi(argv[i]);
if (write(fd, message, strlen(message)) < 0)
{
fprintf(stderr, "error: cannot write to fd %d: %s\n",
fd, strerror(errno));
return EXIT_FAILURE;
}
}
return EXIT_SUCCESS;
}
The caller of the program is responsible for opening any file descriptors that the program needs to write and signaling this using command line arguments.
To pass it open file descriptor 3, which is attached to the file redir
, we can use the exec
shell utility to open the file descriptors and execute it.
$ exec 3>redir ./a.out 3
This closes the current shell after the child exits, so you probably want to try it in a subshell:
$ sh -c 'exec 3>redir ./a.out 3'
Or alternatively, don't use exec
but the @ bmargulies redirection syntax mentioned . Here we write to standard error (2) and also to file descriptors 3 and 4, where we redirect 3 to standard output (1) and 4 to a file redir
.
$ ./a.out 2 3 4 3>&1 4>redir hello, world hello, world $ cat redir hello, world
This kind of file descriptor inheritance is heavily used in server processes that allow their (unprivileged) children to have file descriptors to register files, files outside their chroot()
jail, TCP connections, and what not.
Unfortunately, forgetting to close the file descriptor before exec()
executing the child process is a common mistake that can be related to security. There is Valgrind to test this module .
source to share