2

I've written a daemon that during development had its debugging information going to stderr (before it was fully 'daemonized'). Now the code is more mature, so the stderr has been redirected to /dev/null with an freopen(2) call. For the purposes of debugging, I'd really like to be able to connect to the server daemon, send a command and have it magically start sending the stderr stream over the socket.

Is there a way (in a forked process) to do a 'dup(2)' like operation on stderr of the parent process to the child's socket file descriptor? A Linux only solution is acceptable.

There are great swaths of code that print to stderr, that - for verification purposes - I would rather simply not touch.

If dup2 could do what I'm asking, this would work: Redirect STDOUT and STDERR to socket in C?

Community
  • 1
  • 1
Jamie
  • 7,075
  • 12
  • 56
  • 86
  • Have you considered sending it to a FIFO and netcating it out? – Eugen Rieck Jan 05 '12 at 02:09
  • I'm confused by the _child_ and _parent_ discussion in the question; does the server `fork(2)` a child for every client? do you want to get the _parent's_ debugging information from one of these spawned children? – sarnold Jan 05 '12 at 02:10
  • @sarnold Yes & Yes. I would like to get the parent's debugging information on *one* of the spawned children. – Jamie Jan 05 '12 at 02:32

3 Answers3

2

Once the parent process has forked, the child is unable to forcibly change the status of anything in the parent process. It can conceivable communicate with the parent and request it to change where it writes its standard error output, but the child cannot force the parent to do it. Further, if the parent closed the socket to the client after forking (which it normally would), then it cannot communicate easily with the client.

There are ways to migrate a (socket) file descriptor between processes, but I'm tolerably certain that is a cooperative process too. If you want to go down that route, then this page has a description of what to do and links to the client-end and server-end programs to do the work. (You need an AF_UNIX socket connection and use the sendmsg() in the child daemon and recvmsg() in the parent daemon. With that setup, the child daemon could arrange to pass the client's socket connection to the parent daemon, and the parent daemon would then dup2() the file descriptor received to 2 (standard error), and would then close the original descriptor received. Thereafter, standard error output would go to the client.

This requires care in the setup, and (as already stated) cooperation between the child and the parent daemon processes. I've not actually done this directly myself, so I'm not sure of the pitfalls in the process. I do know it is actually fairly widely usable, at least on Unix-like systems.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
1

What's wrong with a dup2?

In the parent, socket and connect in the parent and pass the number in argv. Pass the file descriptor of the write side of the pipe to the child in argv. Then close(2), and dup2(numberFromArgv, 2)?

Or, just pass the port number of the error server to the child (or hardwire it), and let it call socket, connect, and dup2.

Come to think of it, I bet that the main problem here is the 'f' part of it. After you call freopen, the descriptor number is probably no longer '2'. Call fileno to obtain the number, and then use dup2 to move the socket to that number.

bmargulies
  • 97,814
  • 39
  • 186
  • 310
  • I tried that (I think, the brevity of your answer is confusing). In a child invoking `dup2(sockfd, STDERR_FILENO);` doesn't give the desired results. This was tried on code that didn't `freopen("/dev/null", "w", stderr);` in the parent process. However, if I do a `dup2(STDOUT_FILENO,STDERR_FILENO);` in the parent I see all the debugging information on stdout which led me to think that a forked process couldn't operate on the parent's file descriptors. – Jamie Jan 05 '12 at 02:39
  • I like the "error server" idea here, but that does potentially expose the error messages to other clients as well. – sarnold Jan 05 '12 at 03:20
1

Once a process has fork(2)ed, the child and parent processes do not share file descriptor tables, so operations in one do not influence the other. The Linux-specific clone(2) system call allows processes to share the file descriptor table using CLONE_FILES and filesystem information (filesystem root, current working directory, umask) can be shared with CLONE_NS. Using clone(2) might be too large a re-write for your purposes -- and because it is out of the ordinary, working with it might be annoying.

Another approach, one bmargulies suggests, is to create an "error server" portion of the parent process that tells clients which port to connect(2) to to read error information. If you stick with TCP, it'll work over networks but be open to all without some authentication and authorization code. If you use unix(7) sockets, you can use SCM_CREDENTIALS messages to check the user, group, and pid of the connecting process.

You could also create a new pipe(7) using the pipe(2) system call for every child, before fork(2), and just waste the filedescriptors if the child doesn't want the debugging information.

If you use a unix(7) socket to provide parent to child communication, you could use the SCM_RIGHTS message to send a filedescriptor from one process to another -- you could either have the parent send a pipe(7) or socket(7) to the child for reading or have the child send the parent a pipe(7) or socket(7) for writing.

Community
  • 1
  • 1
sarnold
  • 102,305
  • 22
  • 181
  • 238