0

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
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)).

  • 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. – Alexander Mills Jun 5 at 0:20
  • can you explain how this works a little bit more? Why file descriptor 1? – Alexander Mills Jun 5 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). – mosvy Jun 5 at 0:24
  • Right but why does it have to be 1 instead of 0? (stdout instead of stdin) – Alexander Mills Jun 5 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>&-. – mosvy Jun 5 at 0:40
-3

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.

  • 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. – muru Jun 5 at 4:29
  • 1
    @muru I guess he stole this code from a friend – mosvy Jun 5 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 – muru Jun 5 at 22:34
  • 1
    I stand corrected. – mosvy Jun 5 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. – Jeff Schaller Jun 5 at 23:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.