Search code examples
cterminalposix

Make pipe fd return true for is_atty() in child process


I'm creating some pipes and handing it over to fork()/exec()'d child process as stdout and stderr FDs. But the child program doesn't output ANSI colours.

For e.g., the gcc command can output diagnostics with colours. But when I create it as a child of my program and hand over the piped FDs it doesn't send generate colours.

With a bit of snooping around, I found it tests isatty(STDERR_FILENO) and doesn't send ANSI colour codes when it returns false. Is there a way I can make my pipes be treated as TTYs in child process?

P.S. Also, please not I'm aware of unbuffer shell command which was recommended for similar question. I am looking for C/POSIX API solution that's portable across unices. Not just Linux.


Solution

  • There are two answers to your question, the direct answer and the answer to your XY problem. First, the latter. Generally, programs that can output color/formatting suitable for a terminal, or plain text, choose their default based on isatty, but let you pass an explicit option to enable or disable it. For GCC, this is -fdiagnostics-color=always. This is almost surely what you should be using.

    But to answer your original question, the way to do this is not to use a pipe but instead a pseudo-tty (pty). The POSIX interfaces to do this are posix_openpt, grantpt, unlockpt, and ptsname (to get the name of the device to open). But there's a much nicer non-standardized interface, openpty, that does it all for you in one call, and an accompanying forkpty that automatically forks and connects the child's stdin/out/err up to it. I would use one of these if available (they're available on glibc and musl on Linux systems, and on most/all BSD systems).