Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check whether named pipe/FIFO is open for writing

I've created a named pipe for some other process to write to and want to check that the other process started correctly, but don't know its PID. The context is running a command in screen, making sure the command started correctly. I was hoping this might work:

mkfifo /tmp/foo
echo hello > /tmp/foo &
lsof /tmp/foo

Sadly, lsof does not report echo. inotifywait might be another option, but isn't always installed and I really want to poll just once, rather than block until some event.

Is there any way to check if a named pipe is open for writing? Even open in general?


UPDATE:

Once both ends are connected lsof seems to work. This actually solves my problem, but for the sake of the question I'd be interested to know if it's possible to detect the initial redirection to the named pipe without a reader.

> mkfifo /tmp/foo
> yes > /tmp/foo &
> lsof /tmp/foo
> cat /tmp/foo > /dev/null &
> lsof /tmp/foo
COMMAND   PID     USER   FD   TYPE DEVICE SIZE/OFF     NODE     NAME
yes     16915     user    1w  FIFO   8,18      0t0 16660270 /tmp/foo
cat     16950     user    3r  FIFO   8,18      0t0 16660270 /tmp/foo
like image 532
jozxyqk Avatar asked Feb 06 '17 19:02

jozxyqk


1 Answers

Update 2: After playing with inotify-tools, there doesn't seem to be a way to get a notification that a named pipe has been opened for writing and is blocking. This is probably why lsof doesn't show the pipe until it has a reader and a writer.

Update: After researching named pipes, I don't believe that there is any method that will work with named pipes by themselves. Reasoning:

  • there is no way to limit the number of writers to a named pipe (without resorting to locking)
  • all writers block if there is no reader
  • no writers block if there is a reader (presumably as long as the kernel buffers aren't full)

You could try writing nothing to the pipe with a short timeout. If the timeout expires, then the write blocked indicating that someone has already opened the pipe for writing.

Note: As pointed out in the comments, if a reader exists and presumably is fast enough, our test write will not block and the test essentially fails. Comment out the cat line below to test this.

#!/bin/bash

is_named_pipe_already_opened_for_writing() {
    local named_pipe="$1"
    # Make sure it's a named pipe
    if ! [ -p "$named_pipe" ]; then
        return 1
    fi
    # Try to write zero bytes in the background
    echo -n > "$named_pipe" &
    pid=$!
    # Wait a short amount of time
    sleep 0.1
    # Kill the background process. If kill succeeds, then
    # the write was blocked indicating that someone
    # else is already writing to the named pipe.
    kill $pid 2>/dev/null
}

PIPE=/tmp/foo

# Ignore any bash messages from killing below
trap : TERM

mkfifo $PIPE
# a writer
yes > $PIPE &
# a reader
cat $PIPE >/dev/null &

if is_named_pipe_already_opened_for_writing "$PIPE"; then
    echo "$PIPE is already being written to by another process"
else
    echo "$PIPE is NOT being written to by another process"
fi

jobs -pr | kill 2>/dev/null
rm -f $PIPE
like image 177
Harvey Avatar answered Sep 28 '22 05:09

Harvey