2

Right now, I have this crappy check to see if a named pipe is being read from:

is_named_pipe_being_read() {

    local named_pipe="$1" 
    echo "unlocked" > "$named_pipe" & 
    pid="$!"
    # Wait a short amount of time
    sleep 0.25
    # Kill the background process. If kill succeeds, then
    # the write was blocked 
    ( kill -PIPE "$pid" ) &> /dev/null
}

if the kill works (exits with 0) then it means that nobody was reading from the pipe.

But instead of having a 0.25 second delay and starting up an unnecessary process, I am looking for a way to check the named pipe to see if it's opened for reading? Is there some way to determine if something is reading from it?

Note: I can't read from the pipe in this call, I can only write to it (because with named pipes the order at which readers are attached does not seem to be respected - or perhaps it's the most recent reader that gets the data, not the oldest reader).

2 Answers 2

5
if /bin/echo unlocked 1<>fifo >fifo; then
    there are readers
else
    no there ain\'t
fi

is_named_pipe_being_read(){ /bin/echo unlocked 1<>"$1" >"$1"; }

The /bin/echo will be killed by a SIGPIPE and return a non-zero status if there are no readers.

You cannot use the built-in echo (even in a subshell) because the SIGPIPE will be either caught or kill the whole shell.

Just like the version from the OP, this is destructive. If you have GNU dd, you can just try opening the file with O_NONBLOCK, as from C:

is_named_pipe_being_read(){ dd oflag=nonblock conv=notrunc,nocreat count=0 of="$1" 2>/dev/null; }

Bu this is not much better; if there are other writers to the pipe, the automatic close of the fifo at the command exit will cause all the readers to get an EOF.

Note: using named pipes is more of a matter of masochism or standard pedantry [1]. The BSD sockets api as implemented by the unix domain sockets is incomparably better (that's why it rules the world ;-)), and there are programs like the newer versions of netcat which make it kind of usable from the shell too.

[1] which is defeated in examples like the above or this by the fact that opening a fifo in rw mode is "undefined" according to the standard, though implemented the same in most systems since 30 years ago or so)).

12
  • yes I agree, named pipes are probably the most overrated thing I can think of - I always have problems when I try to use them. with unix domain sockets, I would need multiple servers listening from the same socket - which isn't possible. But multiple "servers" can cat the same fifo, so that works out better. Commented Jun 5, 2019 at 0:20
  • can you explain how this works a little bit more? Why file descriptor 1? Commented Jun 5, 2019 at 0:22
  • 1
    Because the <> redirection will use the stdin (0) by default (except in ksh93, as explained in the linked answer from Stéphane Chazelas). Commented Jun 5, 2019 at 0:24
  • Right but why does it have to be 1 instead of 0? (stdout instead of stdin) Commented Jun 5, 2019 at 0:26
  • 1
    Instead of exploiting the fact that dup2 is closing the oldfd, you can use another fd and close it explicitly with the same effect: /bin/echo 7<>fifo >fifo 7>&-. Commented Jun 5, 2019 at 0:40
0

I stole this C program from https://stackoverflow.com/a/20694422/5047085:

#include<stdio.h>
#include<unistd.h>
#include<errno.h>
#include<fcntl.h>
#include<stdlib.h>
#include <sys/stat.h>

#define SERVFIFO "/Users/alex/.locking/ql/locks/a/fifo.lock"
#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)

void syserr(const char *str){
    perror(str);
    exit(1);
}

int main(int argc, char** argv){

    umask(0);

    // try to open for write with no readers

    int fdw = open(SERVFIFO, O_WRONLY | O_NONBLOCK);

    if (fdw == -1){
      syserr("non-blocking open for write with no readers failed");
    }

    // create a reader - the process itself - non-blocking

    int fdr = open(SERVFIFO, O_RDONLY | O_NONBLOCK);
    if (fdr == -1){
      syserr("non-blocking open for read no writers failed");
    }

    // try again to open for write but this time with a reader
    fdw = open(SERVFIFO, O_WRONLY | O_NONBLOCK);

    if (fdw == -1){
      syserr("non-blocking open with readers failed");
    }


    printf("non-blocking open for write succeeded\n");

    close(fdw);
    close(fdr);

}

if it exits with 0, that means someone is reading from the named pipe already? And if it exits with 1, it means nobody is reading from it.

This could be wrong, but basic testing says it works. The fifo path is hardcoded in the program above.

7
  • If you obtained this code from someone else, state the source. Otherwise this is plagiarism, and stating that you stole it doesn't help any. Commented Jun 5, 2019 at 4:29
  • 2
    @muru I guess he stole this code from a friend Commented Jun 5, 2019 at 18:05
  • @mosvy I doubt it. Google the messages in the code and you get what's either the source or a copy of it: codeday.me/jp/qa/20190404/549503.html Commented Jun 5, 2019 at 22:34
  • 1
    I stand corrected. Commented Jun 5, 2019 at 22:35
  • 1
    @MrCholo I'm not sure why you're suggesting an edit as to where Alexander Mills got their code from, but I would suggest a comment on the Answer, allowing the OP to make the attribution they believe is correct. Commented Jun 5, 2019 at 23:03

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.