From nobody@FreeBSD.org  Mon Apr 19 13:29:32 2004
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125])
	by hub.freebsd.org (Postfix) with ESMTP id 9D51D16A4CE
	for <freebsd-gnats-submit@FreeBSD.org>; Mon, 19 Apr 2004 13:29:32 -0700 (PDT)
Received: from www.freebsd.org (www.freebsd.org [216.136.204.117])
	by mx1.FreeBSD.org (Postfix) with ESMTP id 5DE5E43D55
	for <freebsd-gnats-submit@FreeBSD.org>; Mon, 19 Apr 2004 13:29:32 -0700 (PDT)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (localhost [127.0.0.1])
	by www.freebsd.org (8.12.10/8.12.10) with ESMTP id i3JKTW72000682
	for <freebsd-gnats-submit@FreeBSD.org>; Mon, 19 Apr 2004 13:29:32 -0700 (PDT)
	(envelope-from nobody@www.freebsd.org)
Received: (from nobody@localhost)
	by www.freebsd.org (8.12.10/8.12.10/Submit) id i3JKTWGJ000679;
	Mon, 19 Apr 2004 13:29:32 -0700 (PDT)
	(envelope-from nobody)
Message-Id: <200404192029.i3JKTWGJ000679@www.freebsd.org>
Date: Mon, 19 Apr 2004 13:29:32 -0700 (PDT)
From: Guido Laubner <Guido.Laubner@gmx.de>
To: freebsd-gnats-submit@FreeBSD.org
Subject: Incorrect fifo semantics
X-Send-Pr-Version: www-2.3

>Number:         65786
>Category:       kern
>Synopsis:       [vfs] Incorrect fifo semantics
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    rwatson
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Mon Apr 19 13:30:21 PDT 2004
>Closed-Date:    Sat Sep 17 19:27:10 GMT 2005
>Last-Modified:  Sat Sep 17 19:27:10 GMT 2005
>Originator:     Guido Laubner
>Release:        5.2.1
>Organization:
>Environment:
FreeBSD doomsday.die-insel.germany.net 5.2.1-RELEASE FreeBSD 5.2.1-RELEASE #0: Mon Feb 23 20:45:55 GMT 2004     root@wv1u.btc.adaptec.com:/usr/obj/usr/src/sys/GENERIC  i386
      
>Description:
I found a strange behaviour of dd. Digging into it I believe it's a
problem of the fifo created by mkfifo(2).
It looks like the fifo allows (and reports correct return codes) for
lseek(2), but when reading form the fifo after the lseek advancing the "read cursor", reading starts from position 0.
Comparing this with a pipe, the pipe behaves correctly :
It allows for lseek and reading starts at the position given in the lseek(2) syscall.
Assuming the pipe is correct, the fifo is not implemented correctly in that is does not position the read "cursor" for the next read properly.
If my assumption is wrong (so the pipe semantics would not hold for
a fifo) the lseek syscall to a fifo should return an error.
>How-To-Repeat:
I've put a shell script and a c-programm together.
The shell script shows the difference in pipe and fifo.
Just run the script and then do more /tmp/c1 ; more /tmp/c2
The output should be identical, but isn't. It shows the pipe working
correctly (/tmp/c2 = "c"), while the fifo did not advance the read pointer (/tmp/c1 = "a" ).
==========================SNIP for SHELL SCRIPT=========================
#!/bin/sh
mkfifo /tmp/fifo
dd if=/tmp/fifo of=/tmp/c1 bs=1 count=1 iseek=2 &
echo abc  >/tmp/fifo
echo abc | dd of=/tmp/c2 bs=1 count=1 iseek=2 
exit
================= SNIP END OF SCRIPT ===================================


The c-program shows, that a fifo does accept the "lseek" system call and
returns correct return code to the lseek, but does not advance the input
pointer for the next read.
to compile : gcc -o main fifo_test.c
to run : mkfifo /tmp/fifo ; ./main & echo abc > /tmp/fifo
which prints : r=2 z=1 c=a  (r=return from lseek, z=return from read
                             c=characer read from fifo)
It should not print "c=a", since the lseek advances the input pointer.

================= SNIP for fifo_test.c =================================
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
main()
{
int o, r, z;
char *c;
   c=(char*)calloc( 2, 1 );
   o=open( "/tmp/fifo", O_RDONLY );
   r=lseek( o, 2, SEEK_SET );
   z=read( o, c, 1 );
   fprintf( stdout, "r=%d z=%d c=%s\n", r, z, c );
}
================= SNIP End of fifo_test.c ==============================
>Fix:
Not known.
>Release-Note:
>Audit-Trail:

From: Bruce Evans <bde@zeta.org.au>
To: Guido Laubner <Guido.Laubner@gmx.de>
Cc: freebsd-gnats-submit@freebsd.org, freebsd-bugs@freebsd.org
Subject: Re: kern/65786: Incorrect fifo semantics
Date: Tue, 20 Apr 2004 16:26:47 +1000 (EST)

 On Mon, 19 Apr 2004, Guido Laubner wrote:
 
 > >Description:
 > I found a strange behaviour of dd. Digging into it I believe it's a
 > problem of the fifo created by mkfifo(2).
 > It looks like the fifo allows (and reports correct return codes) for
 > lseek(2), but when reading form the fifo after the lseek advancing the "read cursor", reading starts from position 0.
 > Comparing this with a pipe, the pipe behaves correctly :
 > It allows for lseek and reading starts at the position given in the lseek(2) syscall.
 > Assuming the pipe is correct, the fifo is not implemented correctly in that is does not position the read "cursor" for the next read properly.
 > If my assumption is wrong (so the pipe semantics would not hold for
 > a fifo) the lseek syscall to a fifo should return an error.
 
 lseek() on fifos shall return an error.  From POSIX.1-2001-draft7:
 
 % 23980            The lseek( ) function shall fail if:
 % ...
 % 23986            [ESPIPE]             The fildes argument is associated with a pipe, FIFO, or socket.
 
 This was fixed in 1996 in rev.1.52 of vfs_syscalls.c and associated changes,
 but was broken in 2003 in rev.1.319 of vfs_syscalls.c and associated changes.
 
 % Index: vfs_syscalls.c
 % ===================================================================
 % RCS file: /home/ncvs/src/sys/kern/vfs_syscalls.c,v
 % retrieving revision 1.318
 % retrieving revision 1.319
 % diff -u -2 -r1.318 -r1.319
 % --- vfs_syscalls.c	11 Jun 2003 00:56:59 -0000	1.318
 % +++ vfs_syscalls.c	18 Jun 2003 19:53:59 -0000	1.319
 % ...
 % @@ -1342,5 +1342,5 @@
 %  	if ((error = fget(td, uap->fd, &fp)) != 0)
 %  		return (error);
 % -	if (fp->f_type != DTYPE_VNODE) {
 % +	if (!(fp->f_ops->fo_flags & DFLAG_SEEKABLE)) {
 %  		fdrop(fp, td);
 %  		return (ESPIPE);
 
 The bug in rev.1.319 is that fifos use the same f_ops as regular files,
 so they cannot be distinguished from regular files using f_ops.
 
 Rev.1.52 worked by putting their classification in f_type and using it
 here and in a couple of other places.
 
 Fifos are still classified by f_type, but the correct fix is not as
 simple as changing the above to:
 
 	if (!(fp->f_ops->fo_flags & DFLAG_SEEKABLE) ||
 	    fp->f_type != DTYPE_VNODE) {
 		...
 
 since several places would need to be changed similarly and then the
 changes in rev.1.352 would increase the number of special cases a
 lot instead of reducing it a little.
 
 lseek() is also broken for device files (seeking on ttys and /dev/null
 bogusly succeeds), but this is an old bug.  Some devices are seekable,
 so lseek() must work for them, but there is no way for indivual devices
 to indicate if they support seeking so lseek() must works for all
 devices.
 
 Breaking lseek() of course confuses any program that expects lseek()
 to actually work if it returns successfully, and are used on files
 where it is broken.  Such program/usage combinations are apparently
 surprisingly rare.  The problem only showed up here in a fifo test
 program.  dd knows not to trust lseek() on devices only.
 
 Bruce
State-Changed-From-To: open->patched 
State-Changed-By: rwatson 
State-Changed-When: Tue Sep 13 11:24:53 GMT 2005 
State-Changed-Why:  
I independently bumped into this bug while investigating a race condition 
in fifos, and drew the same conclusion as Bruce: POSIX specifies that 
ESPIPE should be returned on lseek() attempts.  This has been patched as 
fifofs_vnops.c:1.119 in 7.x-CURRENT, and will be merged to other branches 
after additional testing time has passed.  The commit information: 

revision 1.119 
date: 2005/09/12 12:15:12;  author: rwatson;  state: Exp;  lines: +1 -1 
Remove DFLAG_SEEKABLE from fifo file descriptors: fifos are not seekable 
according to POSIX, not to mention the fact that it doesn't make sense 
(and hence isn't really implemented).  This causes the fifo_misc 
regression test to succeed. 

I'm leaving this PR in the patched state until the fix is merged to 
appropriate branches. 


http://www.freebsd.org/cgi/query-pr.cgi?pr=65786 
Responsible-Changed-From-To: freebsd-bugs->rwatson 
Responsible-Changed-By: rwatson 
Responsible-Changed-When: Tue Sep 13 11:27:03 GMT 2005 
Responsible-Changed-Why:  
Take ownership of this PR so I can use it to remind me to MFC to 
appropriate branches. 


http://www.freebsd.org/cgi/query-pr.cgi?pr=65786 
State-Changed-From-To: patched->closed 
State-Changed-By: rwatson 
State-Changed-When: Sat Sep 17 19:22:22 GMT 2005 
State-Changed-Why:  
This fix has been merged to RELENG_6 as fifo_vnops.c:1.113.2.6.  I do 
not currently plan to merge a fix to RELENG_5, as in RELENG_5 fifos 
do not have their own descriptor types, relying instead on vnode file 
descriptors and customized vnode operations.  This fix will first 
appear in FreeBSD 6.0. 


http://www.freebsd.org/cgi/query-pr.cgi?pr=65786 
>Unformatted:
