Re: tail(1) with multiple FIFOs

2022-06-09 Thread Claudio Jeker
On Thu, Jun 09, 2022 at 02:34:27PM +0200, Martijn van Duren wrote:
> The "problem" is that a FIFO without data hangs on open(2), until data
> is available, the same goes for the initial read of the file.
> 
> We could work around this by adding the O_NONBLOCK flag to a separate
> open(2) call, but I know that this flag is frowned upon. Since gnu tail
> shows the same behaviour I'm not sure if it's worth doing.
> 
> Since I'm not claiming to know all the edge-cases of O_NONBLOCK you
> could carry this diff locally at your own risk. Or maybe if other
> developers feel strong about this and are braver than me when it comes
> to O_NONBLOCK it might go somewhere.

But this does not really work the way people would expect. This will just
jump over FIFOs that have no writer. It will not start to report messages
from those FIFOs when a writer connects later on.

A proper fix would need some probably kqueue magic to get an event when a
FIFO becomes readable.

Since tail -f on fifos is a very uncommon operation I see no need to write
a lot of code to support this questionable mode of operation.

-- 
:wq Claudio
 
> martijn@
> 
> On Wed, 2022-06-08 at 22:09 -0400, Philippe Meunier wrote:
> > Hi,
> > 
> > Try:
> > 
> > $ mkfifo fifo1 fifo2
> > $ tail -f fifo1 fifo2
> > 
> > Then in another terminal:
> > 
> > $ while true; do /bin/echo  > fifo1; done
> > 
> > and... nothing happens.  I would have expected tail(1) to start showing the
> > content of fifo1 as soon as content became available but no, it just keeps
> > waiting.
> > 
> > Then in another terminal:
> > 
> > $ while true; do /bin/echo  > fifo2; done
> > 
> > and then tail(1) starts showing output as expected, alternating between
> > fifo1 and fifo2.
> > 
> > The interesting part is that, once tail(1) has started producing output,
> > you can interrupt and restart one or both of the "" and / or ""
> > loops and tail(1) always does what you'd expect.  It seems that it's only
> > at the very start that tail(1) doesn't produce any output until content is
> > available in both fifos.
> > 
> > I tried various things like -n 0 and -c 0 but to no avail.
> > 
> > Another interesting thing to try:
> > - start the "" loop
> > - interrupt the "" loop
> > - start the "" loop
> > and tail(1) starts displaying output.
> > 
> > But if you try:
> > - start the "" loop
> > - interrupt the "" loop
> > - start the "" loop
> > then tail(1) still doesn't show any output, until you start the "" loop
> > for a second time!
> > 
> > So at the very start, not only does tail(1) seem to expect content in both
> > fifos before it start showing output, but it also seems to expect the
> > content to appear in the specific order indicated on the tail(1) command
> > line.
> > 
> > I assume this is a bug in tail(1)?
> > 
> > Cheers,
> > 
> > Philippe
> > 
> > 
> Index: tail.c
> ===
> RCS file: /cvs/src/usr.bin/tail/tail.c,v
> retrieving revision 1.22
> diff -u -p -r1.22 tail.c
> --- tail.c4 Jan 2019 15:04:28 -   1.22
> +++ tail.c9 Jun 2022 12:33:24 -
> @@ -37,6 +37,7 @@
>  
>  #include 
>  #include 
> +#include 
>  #include 
>  #include 
>  #include 
> @@ -56,7 +57,7 @@ main(int argc, char *argv[])
>   off_t off = 0;
>   enum STYLE style;
>   int ch;
> - int i;
> + int i, fd;
>   char *p;
>  
>   if (pledge("stdio rpath", NULL) == -1)
> @@ -154,8 +155,12 @@ main(int argc, char *argv[])
>   if (argc) {
>   for (i = 0; *argv; i++) {
>   tf[i].fname = *argv++;
> - if ((tf[i].fp = fopen(tf[i].fname, "r")) == NULL ||
> - fstat(fileno(tf[i].fp), &(tf[i].sb))) {
> + /*
> +  * Use O_NONBLOCK to avoid hanging on FIFO.
> +  */
> + fd = open(tf[i].fname, O_RDONLY | O_NONBLOCK);
> + if (fd == -1 || (tf[i].fp = fdopen(fd, "r")) == NULL ||
> + fstat(fd, &(tf[i].sb))) {
>   ierr(tf[i].fname);
>   i--;
>   continue;
> 



Re: tail(1) with multiple FIFOs

2022-06-09 Thread Martijn van Duren
The "problem" is that a FIFO without data hangs on open(2), until data
is available, the same goes for the initial read of the file.

We could work around this by adding the O_NONBLOCK flag to a separate
open(2) call, but I know that this flag is frowned upon. Since gnu tail
shows the same behaviour I'm not sure if it's worth doing.

Since I'm not claiming to know all the edge-cases of O_NONBLOCK you
could carry this diff locally at your own risk. Or maybe if other
developers feel strong about this and are braver than me when it comes
to O_NONBLOCK it might go somewhere.

martijn@

On Wed, 2022-06-08 at 22:09 -0400, Philippe Meunier wrote:
> Hi,
> 
> Try:
> 
> $ mkfifo fifo1 fifo2
> $ tail -f fifo1 fifo2
> 
> Then in another terminal:
> 
> $ while true; do /bin/echo  > fifo1; done
> 
> and... nothing happens.  I would have expected tail(1) to start showing the
> content of fifo1 as soon as content became available but no, it just keeps
> waiting.
> 
> Then in another terminal:
> 
> $ while true; do /bin/echo  > fifo2; done
> 
> and then tail(1) starts showing output as expected, alternating between
> fifo1 and fifo2.
> 
> The interesting part is that, once tail(1) has started producing output,
> you can interrupt and restart one or both of the "" and / or ""
> loops and tail(1) always does what you'd expect.  It seems that it's only
> at the very start that tail(1) doesn't produce any output until content is
> available in both fifos.
> 
> I tried various things like -n 0 and -c 0 but to no avail.
> 
> Another interesting thing to try:
> - start the "" loop
> - interrupt the "" loop
> - start the "" loop
> and tail(1) starts displaying output.
> 
> But if you try:
> - start the "" loop
> - interrupt the "" loop
> - start the "" loop
> then tail(1) still doesn't show any output, until you start the "" loop
> for a second time!
> 
> So at the very start, not only does tail(1) seem to expect content in both
> fifos before it start showing output, but it also seems to expect the
> content to appear in the specific order indicated on the tail(1) command
> line.
> 
> I assume this is a bug in tail(1)?
> 
> Cheers,
> 
> Philippe
> 
> 
Index: tail.c
===
RCS file: /cvs/src/usr.bin/tail/tail.c,v
retrieving revision 1.22
diff -u -p -r1.22 tail.c
--- tail.c  4 Jan 2019 15:04:28 -   1.22
+++ tail.c  9 Jun 2022 12:33:24 -
@@ -37,6 +37,7 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -56,7 +57,7 @@ main(int argc, char *argv[])
off_t off = 0;
enum STYLE style;
int ch;
-   int i;
+   int i, fd;
char *p;
 
if (pledge("stdio rpath", NULL) == -1)
@@ -154,8 +155,12 @@ main(int argc, char *argv[])
if (argc) {
for (i = 0; *argv; i++) {
tf[i].fname = *argv++;
-   if ((tf[i].fp = fopen(tf[i].fname, "r")) == NULL ||
-   fstat(fileno(tf[i].fp), &(tf[i].sb))) {
+   /*
+* Use O_NONBLOCK to avoid hanging on FIFO.
+*/
+   fd = open(tf[i].fname, O_RDONLY | O_NONBLOCK);
+   if (fd == -1 || (tf[i].fp = fdopen(fd, "r")) == NULL ||
+   fstat(fd, &(tf[i].sb))) {
ierr(tf[i].fname);
i--;
continue;