Send EOF to named pipe - cleaning up / drying up fifo

10,960

Solution 1

EOF is not a character nor an "event" and could not be sent through the pipe, or "fed" to its writing end, as some stubborn urban legend suggests.

The only way to generate an EOF on the reading end of a pipe/fifo (ie cause a read(2) on it to return 0) is to close all open handles to its writing end.

This will happen automatically if all the processes that had opened a named pipe in write mode and all the children that have inherited the file descriptors through fork() are terminated [1].

It's not possible for a read(2) on a named pipe to return 0 it that pipe was opened in read/write mode, eg. with

exec 7<>/path/to/fifo

because in that case there is a single file descriptor / handle for both ends of the pipe and closing the write end will also close the read end making impossible for a read(2) to return 0 (pipes do not support any kind of half-close as sockets do with shutdown(2)).

[1] And all processes that have received the file descriptor via SCM_RIGHTS ancillary message on a unix socket.


Notice that tail -f by definition won't terminate upon EOF, whether the file it's reading from is regular or special. One way to kill all processes that are holding a open handle to a file descriptor is with fuser(1):

tail -f /path/to/fifo
...
> /path/to/fifo  # let any blocking open(2) through
fuser -TERM -k /path/to/fifo

Beware that this will also kill processes that have (inadvertently) inherited an open handle to /path/to/fifo from their parents.

Solution 2

You cannot “send EOF”. There is simply no “EOF character” that would go through the pipe.

Typically, linux programs read from a file descriptor using read(2) in blocking mode, filling a buffer with the received data, and returning the amount of characters read. When read returns 0, i.e., 0 bytes have been read, most programs interpret this as end-of-file.

A program may flush its side of the pipe before the buffer is full, using fsync(2). In that case, the reader's read would return immediately, even if the buffer is empty, returning 0 as the amount of readbytes.

You can observe this by running cat, typing some characters (not return) and hit Ctrl-D (which causes a flush by the terminal). At that moment, cat will print the typed characters. Hit Ctrl-D again, and cat's read will return 0 bytes, making cat assume to have reached end of file. Since line-buffering is used, cat also prints its input when you hit Return.

Share:
10,960

Related videos on Youtube

Alexander Mills
Author by

Alexander Mills

Updated on September 18, 2022

Comments

  • Alexander Mills
    Alexander Mills over 1 year

    If I have some random processes reading from a named pipe:

    tail -f MYNAMEDPIPED 
    cat MYNAMEDPIPE | someOtherProc
    

    Elsewhere, I have a handle on MYNAMEDPIPED by name. is there a safe and clean way to stop the tail process by deleting MYNAMEDPIPED or perhaps somehow "drying it up"?

    In other words

    MYNAMEDPIPED.noMoreDataIsComingThroughSoPleaseStopTailingThis()
    

    :)

    From one of the comments, it says to send EOF to MYNAMEDPIPE. But I cannot figure out how to do this.

    This shows the difficulty I am facing:

    http://comp.os.linux.questions.narkive.com/2AW9g5yn/sending-an-eof-to-a-named-pipe

    • Admin
      Admin almost 7 years
      Feed EOF into the input side of the pipe, tail will see it and close its end. This should normally happen automagically when whatever had been writing to the pipe was done. Remember to clean up after yourself and rm what you had mkfifoed earlier.
    • Admin
      Admin almost 7 years
      thanks, can you show an actual example of sending EOF to a named pipe?
    • Admin
      Admin almost 7 years
      The whole purpose of tail -f is that it ignores any suggestion that it has reached the end of the file (or pipe); it will wait forever for someone to reopen the file and start writing to it again. Compare with something like cat MYNAMEDPIPE, which will block until something writes to it, but will indeed exit once the writer closes its end and all remaining data has been read.
    • Admin
      Admin almost 7 years
      maybe cat <<EOF > MYNAMEDPIPED ?
    • Admin
      Admin almost 7 years
      need help please with sending EOF to named pipe.
    • Admin
      Admin almost 7 years
      The only reasonable way to terminate tail -f is to send a signal to it, e.g. with kill.
    • Admin
      Admin almost 7 years
      yeah, I guess I will have to write the pid of the tail command to a file
  • mosvy
    mosvy over 5 years
    what this answer describes in the last paragraph only happens with ttys, not with pipes; a fsync() on the write end of the pipe will not cause a read() on the reading end to return 0, even if the pipe's buffer was empty.