3

I'm writing a utility for running programs, and I need to capture unbuffered stdout and stderr from the programs. I need to:

  • Capture stdout and stderr to separate files.
  • Output needs to not be buffered (or be line buffered).
  • Without modifying the source of the program being run.

The problem is, when piping output to a file, the stdout stream becomes block buffered rather than line buffered. If the program crashes, the output never gets flushed, and is blank. So I need to capture stdout without buffering (or with line buffering).

I think this can be done with pty's but I'm having difficulty finding any examples that do exactly what I want (most ignore stderr). In fact, I'm not sure I've found any pty examples in C at all; most use a higher-level interface like Python's pty and subprocess modules.

Can anyone help (with code snippets or links)? Any help would be appreciated.

EDIT: I think I've solved it. The following two links were pretty helpful.

My code is available as a repository:

3
  • 1
    You should look at whether you should close slavefd after dup2-ing it to stdin/stdout/stderr...you probably should but do not seem to do so. Also consider whether the parent should exit with the status of the child - worrying about what to do with signals. At the moment, the calling code can only find out by looking at data. Also, you should ensure that the child returns a non-zero status when it fails to execv() - at the moment, it returns 0. Commented Oct 11, 2009 at 23:09
  • Thanks. I added the catch for execv errors. For dup2, it looks like the close call is already included (see linux.die.net/man/3/dup2). Commented Oct 26, 2009 at 23:27
  • dup2() closes the target file descriptor if it is open; however, you need to close the source file descriptor, usually, after the dup2() completes. That is, if the pty is opened on file descriptor 8, then dup2'd to 1, you want to close 8 now that you have the copy as 1. Otherwise, when you exec(), the child will have descriptors 0, 1, 2 and 8 open -- plus any other strays. Commented Oct 27, 2009 at 1:16

1 Answer 1

1

see man 7 pty


In particular:

Unix 98 pseudo-terminals

An unused Unix 98 pseudo-terminal master is opened by calling posix_openpt(3). (This function opens the master clone device, /dev/ptmx; see pts(4).) After performing any program-specific initializations, changing the ownership and permissions of the slave device using grantpt(3), and unlocking the slave using unlockpt(3)), the corresponding slave device can be opened by passing the name returned by ptsname(3) in a call to open(2).

And now that you know the names of the library functions such a code will need to call, you can do two useful things:

  • Look up their man pages
  • Google for example code. Since you know what keywords to use with the search engine I suspect you will have much more luck hunting down examples.
Sign up to request clarification or add additional context in comments.

2 Comments

Note that the posix_openpt() and related functions are a relatively recent addition to POSIX and are not widely available. Specifically, not available on MacOS X (10.5, anyway). OTOH, they do seem to be available on Solaris 10. For Linux, they may well simplify life a lot.
Good point. The BSD style pty, while disrespected in the linux docs as non-standard, might actually be the de facto standard. And it's fine with me! I went with the vanilla linux approach because his question was tagged "linux".

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.