5

If I do this:

x | y

is there any way to check, during the runtime of x, to see if it's connected to y? Note that I don't know what y is, and I am not responsible for starting y.

Specifically, I am talking about the Node.js runtime, so perhaps this is a Node.js specific question. But ultimately, I am wondering if it's possible to determine given any runtime. Is it possible and how?

Is it possible to determine if the stdout/stderr are hooked up to the stdin of another process? I guess that's what this question is about.

JdeBP
  • 68,745
  • 2
    If this were Linux, /proc/<pid-x>/fd/1 and /proc/<pid-y>/fd/0 would be links to the same pipe. – muru Jul 31 '17 at 04:30
  • Yeah it has to work on MacOS too, so that exact technique won't work. Also note that I don't know what y is, I am not responsible for starting y. If I were, then I would already have the answer to this yes/no question :) – Alexander Mills Jul 31 '17 at 04:36
  • 1
    You don't need to know what Y is to inspect /proc/*/fd/0 (on Linux, again). For example, I used find and awk for that: https://unix.stackexchange.com/a/156152/70524 – muru Jul 31 '17 at 04:39
  • 1
    lsof should show processes that have the file opened as well – EkriirkE Jul 31 '17 at 05:20
  • @muru ah, I see what you are saying – Alexander Mills Jul 31 '17 at 05:21

4 Answers4

4

To check whether the program's output is going to a pipe, based on https://nodejs.org/api/fs.html#fs_class_fs_stats, you want to call fs.fstat(FileDescriptor) and then call isFIFO() on the returned stat object (FIFO == first-in-first-out == a pipe or a named pipe):

$ </dev/null node -e 'var fs=require("fs");
   fs.fstat(0,function(err,stats){ if(err) throw(err); console.log(stats.isFIFO()); });  ' 
  false
$  : | node -e 'var fs=require("fs");
   fs.fstat(0,function(err,stats){ if(err) throw(err); console.log(stats.isFIFO()); });  ' 
  true

In C, you'd make the fstat syscall and then test the .st_mode field of the returned struct stat using the S_ISFIFO macro.

If you like to waste CPU cycles and want to use an external binary, you can execute test -p /dev/fd/$THE_FD to get the answer (or invoke that in a shell where test will be a builtin, or run stat, or launch something else capable of determining the file type).

Petr Skocik
  • 28,816
1

It is possible, and fairly trivial, for a program to determine whether any given open file descriptor in its process references a pipe or a FIFO. It is a simple exercise in the use of the fstat() library function.

You'll have to work out how to call fstat() in your programming language of choice. In the C or C++ languages a function to do this is quite simple:

#include <sys/types.h>  // no longer required by IEEE 1003.1:2008
#include <sys/stat.h>
#include <unistd.h>

/// \brief Check a file descriptor for being open and denoting a pipe/FIFO
extern inline
bool        /// \returns true if and only if the descriptor is open to a pipe/FIFO
is_fifo (
    int fd  ///< the file descriptor to test
) {
    struct stat s;
    return 0 <= fstat(fd, &s) && S_ISFIFO(s.st_mode);
}

The libsystemd library in systemd has a somewhat more complicated sd_is_fifo() library function.

JdeBP
  • 68,745
1

Testing whether a file descriptor is a pipe is easy and portable. Figuring out what's at the other end of the pipe isn't.

Externally, with recent versions of lsof on Linux:

$ sleep 100 | sleep 200 &
[1] 15314 15315
$ lsof -ad0-1 -E -p 15314
COMMAND   PID     USER   FD   TYPE DEVICE SIZE/OFF     NODE NAME
sleep   15314 stephane    0u   CHR  136,1      0t0        4 /dev/pts/1
sleep   15314 stephane    1w  FIFO   0,10      0t0 17895049 pipe 15315,sleep,0r

Shows that stdout of 15314 is the writing end of a pipe which has the stdin of 15315 at the other end.

0

Using Node.js, in the runtime on a *nix system, this seems to work:

const isTTY = process.stdout.isTTY;

if true, it's not connected to a destination pipe

if undefined, it's connected to a destination pipe

...at least according to my testing so far

  • 1
    Stdout isn't limited to being either a terminal or a pipe. It can also be a regular file (if you're running under a redirection) (or I guess also a socket, character device or a block device, though I haven't tested with the last three types). – Petr Skocik Nov 29 '17 at 20:55
  • yeah my current understanding is this is not as reliable a measure as using fstat, I guess for the reasons you just mentioned – Alexander Mills Nov 29 '17 at 21:00