Steve Williams
2002-Mar-01 15:45 UTC
[Samba] PATCH - smbd/trans2.c to support writing to Unix named pipes(FIFO)
Hi, We have a simple "Remote Procedure Call" mechanism that we are using to communicate between Windows computers and our Unix Samba server. The Windows application is proprietary software (Progress - not ours) and we have to work within the constraints of it. We have a Unix named pipe sitting in a Samba shared directory. We have a small C program that runs as a Unix daemon, listening for input from the pipe file and performing tasks based on what is written to the pipe file by the Windows client. ( Unix system: mknod some_fifo p ) The windows clients just see a "file" in a share on the Unix box, open it, write to it, close it, and magic, we have a very simple RPC style API that works with almost every windows application (including VBScript in MS Word!). This has been working for years using Windows 9X clients, talking to Samba 2.0.x, right up to 2.2.3a. I have avoided NT clients to date, but unfortunately, I finally must get this working on NT. NT seems to do something different that breaks this very simple interface. ( Tested with NT4 as well as NT5/Win2K.. no XP yet!) Poking into the level 10 logfiles, the problem is in: [2002/02/28 19:27:11, 3] smbd/trans2.c:call_trans2qfilepathinfo(1560) call_trans2qfilepathinfo: TRANSACT2_QFILEINFO: level 258 [2002/02/28 19:27:11, 3] lib/system.c:sys_lseek(146) sys_lseek with fd: 18, offset: 0, whence: 0 (the sys_lseek above line is something I added in....) [2002/02/28 19:27:11, 3] smbd/error.c:error_packet(91) error string = Illegal seek [2002/02/28 19:27:11, 3] smbd/error.c:error_packet(103) error packet at smbd/trans2.c(1604) cmd=50 (SMBtrans2) NT_STATUS_ACCESS_DENIED [2002/02/28 19:27:11, 5] lib/util.c:show_msg(275) The problem is that system is trying to do an lseek on a pipefile, which, rightly so returns an error. I have no idea why Windows 9X clients don't do this! The code in question is in (samba 2.2.3a) smbd/trans2.c:1603 ---------------------------------------------------------------------- call_trans2qfilepathinfo: ---------------------------------------------------------------------- /* * Original code - this is an open file. */ CHECK_FSP(fsp,conn); fname = fsp->fsp_name; if (vfs_fstat(fsp,fsp->fd,&sbuf) != 0) { DEBUG(3,("fstat of fnum %d failed (%s)\n",fsp->fnum, strerror(errno))); return(UNIXERROR(ERRDOS,ERRbadfid)); } if((pos = fsp->conn->vfs_ops.lseek(fsp,fsp->fd,0,SEEK_CUR)) == -1) return(UNIXERROR(ERRDOS,ERRnoaccess)); delete_pending = fsp->delete_on_close; ---------------------------------------------------------------------- The problem is the line that does the vfs_ops.lseek. The FD is actually a pipe which causes an error. I have no idea what what a "TRANSACT2_QFILEINFO: level=258" call is supposed to do, but based the fact that it is returning the current offset in the file, I am offering the following code as a potential enhancement. I have tested this code, and it completely resolves my problem. I have not done any other regression testing, as I figure knowlegeable eyes should have a look at it first & tell me that I am crazy! I'll attach the code snippet as a diff, but here it is inline in the email. ---------------------------------------------------------------------- /* * Original code - this is an open file. */ CHECK_FSP(fsp,conn); fname = fsp->fsp_name; if (vfs_fstat(fsp,fsp->fd,&sbuf) != 0) { DEBUG(3,("fstat of fnum %d failed (%s)\n",fsp->fnum, strerror(errno))); return(UNIXERROR(ERRDOS,ERRbadfid)); } /* If it is a FIFO, it should be safe to assume * that the current position is always "0" in the * file... by the very nature of a FIFO... * * Steve Williams (steve@ware-solutions.com) * Fri Mar 1 15:51:33 MST 2002 */ if(S_ISFIFO(sbuf.st_mode)){ DEBUG(3,("Is a FIFO, assuming 0 for lseek")); pos=0; } else if((pos = fsp->conn->vfs_ops.lseek(fsp,fsp->fd,0,SEEK_CUR)) == -1) return(UNIXERROR(ERRDOS,ERRnoaccess)); delete_pending = fsp->delete_on_close; ---------------------------------------------------------------------- I have used different applications to test my fix, but the simplified one that I wrote is (compiled with gcc under cygwin on Win2K): ---------------------------------------------------------------------- main(int argc, char *argv[]) { int fd; int pos; if (argc != 2) { printf("Missing file specification\n"); exit(1); } if ( (fd=open(argv[1],2)) < 0 ){ perror("open"); printf("unable to open file: %s\n", argv[0]); exit(1); } printf("Got fd: %d\n", fd); if ( (pos=lseek(fd,0,0)) == -1) { perror("seek"); printf("Could not seek\n"); exit(1); } printf("Got pos=%d\n", pos); if(write(fd,"ls\n",3) != 3){ perror("write"); printf("could not write\n"); exit(1); } printf("Wrote pipefile fine\n"); close(fd); exit(0); } ---------------------------------------------------------------------- Running un-patched Samba 2.2.3a $ ./a.exe /cygdrive/p/faxdir/FAXFIFO Got fd: 3 Got pos=0 write: No space left on device could not write Running patched Samba 2.2.3a $ ./a.exe /cygdrive/q/faxdir/FAXFIFO Got fd: 3 Got pos=0 Wrote pipefile fine and the logfile from my daemon on the unix system... Date 3/1/2002 Time 15:06:15 - Complete string is *ls* Token at 0 is *ls* So, the patched one seems to work fine. As an aside, it's pretty amazing that the lseek itself isn't causing a problem (maybe it's cached or something!), but the call that is causing the problem is the WRITE statement??? I checked the samba logfiles & it is indeed the write that is causing the seek to happen?? Oh well... What do people think of this patch/issue? Hopefully I've been clear enough describing this problem. Thanks, -- Steve Williams, Calgary, Alberta, Canada Ware Solutions steve@ware-solutions.com "A man doesn't begin to attain wisdom until he recognizes that he is no longer indispensable." - Admiral Richard E. Byrd ( 1888-1957 )
Jeremy Allison
2002-Mar-01 18:53 UTC
[Samba] PATCH - smbd/trans2.c to support writing to Unix named pipes(FIFO)
On Fri, Mar 01, 2002 at 04:07:38PM -0700, Steve Williams wrote:> > We have a Unix named pipe sitting in a Samba shared directory. We have a > small C program that runs as a Unix daemon, listening for input from the > pipe file and performing tasks based on what is written to the pipe file by > the Windows client. ( Unix system: mknod some_fifo p ) > > The windows clients just see a "file" in a share on the Unix box, open it, > write to it, close it, and magic, we have a very simple RPC style API that > works with almost every windows application (including VBScript in MS > Word!). > > This has been working for years using Windows 9X clients, talking to Samba > 2.0.x, right up to 2.2.3a. I have avoided NT clients to date, but > error string = Illegal.....> The problem is the line that does the vfs_ops.lseek. The FD is actually a > pipe which causes an error. > > I have no idea what what a "TRANSACT2_QFILEINFO: level=258" call is > supposed to do, but based the fact that it is returning the current offset > in the file, I am offering the following code as a potential enhancement.I've actually fixed this differently - I modified the lseek inside the VFS to silently allow ESPIPE errors to return 0. This should fix all uses of the vfs lseek as seen by the client. This also allowed me to tidy up some code in smbd/fileio.c. As Windows clients are never aware of pipes in the filesystem this should be completely safe. Comments anyone ? Jeremy.