delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/2003/03/10/18:23:30

Date: Mon, 10 Mar 2003 23:26:16 +0000
From: "Richard Dawe" <rich AT phekda DOT freeserve DOT co DOT uk>
Sender: rich AT phekda DOT freeserve DOT co DOT uk
To: djgpp-workers AT delorie DOT com
X-Mailer: Emacs 21.3.50 (via feedmail 8.3.emacs20_6 I) and Blat ver 1.8.6
Subject: POSIX: fchdir [PATCH]
Message-Id: <E18sWby-0000tq-00@phekda.freeserve.co.uk>
Reply-To: djgpp-workers AT delorie DOT com

Hello.

Please find below a patch to add fchdir to DJGPP. Also included is
a test program for select.

OK to commit? (Ha-ha, I should be so lucky on the first try. ;) )

Bye, Rich =]

Index: include/unistd.h
===================================================================
RCS file: /cvs/djgpp/djgpp/include/unistd.h,v
retrieving revision 1.16
diff -p -c -3 -r1.16 unistd.h
*** include/unistd.h	4 Feb 2003 20:24:30 -0000	1.16
--- include/unistd.h	10 Mar 2003 23:18:54 -0000
*************** int		execlp(const char *_file, const cha
*** 115,120 ****
--- 115,121 ----
  int		execv(const char *_path, char *const _argv[]);
  int		execve(const char *_path, char *const _argv[], char *const _envp[]);
  int		execvp(const char *_file, char *const _argv[]);
+ int		fchdir(int _fd);
  pid_t		fork(void);
  long		fpathconf(int _fildes, int _name);
  char *		getcwd(char *_buf, size_t _size);
Index: include/libc/fd_props.h
===================================================================
RCS file: /cvs/djgpp/djgpp/include/libc/fd_props.h,v
retrieving revision 1.8
diff -p -c -3 -r1.8 fd_props.h
*** include/libc/fd_props.h	4 Feb 2003 20:24:58 -0000	1.8
--- include/libc/fd_props.h	10 Mar 2003 23:19:00 -0000
*************** extern "C" {
*** 36,41 ****
--- 36,44 ----
  /* Set when the descriptor is opened for append only. */
  #define FILE_DESC_APPEND            0x10
  
+ /* Set when the descriptor is used for directory emulation. */
+ #define FILE_DESC_DIRECTORY         0x20
+ 
  typedef struct fd_properties fd_properties;
  
  struct fd_properties
Index: src/libc/dos/io/fd_props.txh
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/dos/io/fd_props.txh,v
retrieving revision 1.5
diff -p -c -3 -r1.5 fd_props.txh
*** src/libc/dos/io/fd_props.txh	1 Mar 2003 11:12:37 -0000	1.5
--- src/libc/dos/io/fd_props.txh	10 Mar 2003 23:19:00 -0000
*************** This is an internal function that stores
*** 19,24 ****
--- 19,29 ----
  @var{fd} in a @code{fd_properties} struct.  It is called by @code{open} and
  its helper functions.
  
+ The file name stored in @code{fd_properties} is the result
+ of the @code{_truename} function (@pxref{_truename}) on @var{filename}.
+ The @var{open_flags} are scanned and the temporary and append flags
+ are stored in the @code{flags} field in @code{fd_properties}.
+ 
  @example
  struct fd_properties
  @{
*************** The file descriptor is used in emulating
*** 50,55 ****
--- 55,63 ----
  
  @item FILE_DESC_APPEND
  The file pointer will be set to the end of file before each write.
+ 
+ @item FILE_DESC_DIRECTORY
+ The file descriptor is for a directory.
  
  @end table
  
Index: src/libc/posix/fcntl/open.c
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/posix/fcntl/open.c,v
retrieving revision 1.11
diff -p -c -3 -r1.11 open.c
*** src/libc/posix/fcntl/open.c	25 Sep 2001 00:52:30 -0000	1.11
--- src/libc/posix/fcntl/open.c	10 Mar 2003 23:19:10 -0000
***************
*** 1,3 ****
--- 1,4 ----
+ /* Copyright (C) 2003 DJ Delorie, see COPYING.DJ for details */
  /* Copyright (C) 2001 DJ Delorie, see COPYING.DJ for details */
  /* Copyright (C) 2000 DJ Delorie, see COPYING.DJ for details */
  /* Copyright (C) 1999 DJ Delorie, see COPYING.DJ for details */
***************
*** 17,32 ****
--- 18,116 ----
  #include <unistd.h>
  #include <sys/stat.h>
  #include <io.h>
+ #include <sys/fsext.h>
  
  #include <libc/dosio.h>
  #include <libc/fd_props.h>
  
+ 
  /* Extra share flags that can be indicated by the user */
  int __djgpp_share_flags;
  
+ /* Move a file descriptor FD such that it is at least MIN_FD.
+    If the file descriptor is changed (meaning it was origially
+    *below* MIN_FD), the old one will be closed.
+    If the operation failed (no more handles available?), -1 will
+    be returned, in which case the original descriptor is still
+    valid.
+ 
+    This jewel is due to Morten Welinder <terra AT diku DOT dk>.  */
+ static int
+ move_fd (int fd, int min_fd)
+ {
+   int new_fd, tmp_fd;
+ 
+   if (fd == -1 || fd >= min_fd)
+     return fd;
+ 
+   tmp_fd = dup (fd);
+   if (tmp_fd == -1)
+     return tmp_fd;
+ 
+   new_fd = move_fd (tmp_fd, min_fd);
+   if (new_fd != -1)
+     close (fd);		/* success--get rid of the original descriptor */
+   else
+     close (tmp_fd);	/* failure--get rid of the temporary descriptor */
+   return new_fd;
+ }
+ 
+ static int
+ opendir_as_fd (const char *filename, const int oflag)
+ {
+   int fd, old_fd, flags, ret;
+ 
+   /* Check the flags. */
+   if ((oflag & (O_RDONLY|O_WRONLY|O_RDWR)) != O_RDONLY)
+   {
+     /* Only read-only access is allowed. */
+     errno = EISDIR;
+     return -1;
+   }
+ 
+   /*
+    * Allocate a file descriptor that:
+    *
+    * - is dup'd off nul, so that bogus operations at least go somewhere
+    *   sensible;
+    * - is in binary mode;
+    * - is non-inheritable;
+    * - is marked as a directory.
+    *
+    * __FSEXT_alloc_fd() conveniently handles the first two. File handles
+    * greater than 19 are not inherited, due to a misfeature
+    * of the DOS exec call.
+    */
+   old_fd = __FSEXT_alloc_fd(NULL);
+   if (old_fd < 0)
+     return -1; /* Pass through errno. */
+ 
+   fd = move_fd(old_fd, 20);
+   if (fd < 0)
+   {
+     close(old_fd);
+     errno = EMFILE;
+     return -1;
+   }
+ 
+   __set_fd_properties(fd, filename, 0);
+   __set_fd_flags(fd, FILE_DESC_DIRECTORY);
+ 
+   flags = fcntl(fd, F_GETFD);
+   if (flags < 0)
+     return -1; /* Pass through errno. */
+   flags |= FD_CLOEXEC;
+   ret = fcntl(fd, F_SETFD, flags);
+   if (ret < 0)
+     return -1; /* Pass through errno. */
+ 
+   return fd;
+ }
+ 
  int
  open(const char* filename, int oflag, ...)
  {
+   const int original_oflag = oflag;
    int fd, dmode, bintext, dont_have_share;
    char real_name[FILENAME_MAX + 1];
    int should_create = (oflag & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL);
*************** open(const char* filename, int oflag, ..
*** 137,142 ****
--- 221,232 ----
  	fd = _creat(real_name, dmode);
      }
    }
+ 
+   /* Is the target a directory? If so, generate a file descriptor
+    * for the directory. Skip the rest of `open', because it does not
+    * apply to directories. */
+   if ((fd == -1) && (access(real_name, D_OK) == 0))
+     return opendir_as_fd(real_name, original_oflag);
  
    if (fd == -1)
      return fd;	/* errno already set by _open or _creat */
Index: src/libc/posix/fcntl/open.txh
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/posix/fcntl/open.txh,v
retrieving revision 1.8
diff -p -c -3 -r1.8 open.txh
*** src/libc/posix/fcntl/open.txh	29 Jan 2003 12:51:40 -0000	1.8
--- src/libc/posix/fcntl/open.txh	10 Mar 2003 23:19:11 -0000
*************** You can specify the share flags (a DOS s
*** 111,116 ****
--- 111,123 ----
  And you can indicate default values for the share flags in
  @code{__djgpp_share_flags}. @xref{__djgpp_share_flags}.
  
+ You can open directories using @code{open}, but there is limited
+ support for POSIX file operations on directories.  The principal reason
+ for allowing @code{open} to open directories is to support changing
+ directories using @code{fchdir} (@pxref{fchdir}).  If you wish to read
+ the contents of a directory, use the @code{opendir} (@pxref{opendir})
+ and @code{readdir} (@pxref{readdir}) functions instead.
+ 
  @subheading Return Value
  
  If successful, the file descriptor is returned.  On error, a negative
Index: src/libc/posix/fcntl/fcntl.c
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/posix/fcntl/fcntl.c,v
retrieving revision 1.8
diff -p -c -3 -r1.8 fcntl.c
*** src/libc/posix/fcntl/fcntl.c	11 Jun 2002 08:26:44 -0000	1.8
--- src/libc/posix/fcntl/fcntl.c	10 Mar 2003 23:19:17 -0000
***************
*** 1,3 ****
--- 1,4 ----
+ /* Copyright (C) 2003 DJ Delorie, see COPYING.DJ for details */
  /* Copyright (C) 2002 DJ Delorie, see COPYING.DJ for details */
  /* Copyright (C) 2001 DJ Delorie, see COPYING.DJ for details */
  /* Copyright (C) 1999 DJ Delorie, see COPYING.DJ for details */
*************** _fcntl_lk64(int fd, int cmd, struct floc
*** 110,116 ****
    offset_t pos, cur_pos, lock_pos, len;
    long long int flen;
  
!   /* First check if SHARE is loaded */
    ret = _get_SHARE_status();
  
    if (!ret) /* Then SHARE is NOT loaded, just return success */
--- 111,124 ----
    offset_t pos, cur_pos, lock_pos, len;
    long long int flen;
  
!   /* Is this a directory? If so, fail. */
!   if (__get_fd_flags(fd) & FILE_DESC_DIRECTORY)
!   {
!     errno = EINVAL;
!     return -1;
!   }
! 
!   /* Check if SHARE is loaded */
    ret = _get_SHARE_status();
  
    if (!ret) /* Then SHARE is NOT loaded, just return success */
Index: src/libc/posix/fcntl/fcntl.txh
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/posix/fcntl/fcntl.txh,v
retrieving revision 1.10
diff -p -c -3 -r1.10 fcntl.txh
*** src/libc/posix/fcntl/fcntl.txh	29 Jan 2003 12:51:40 -0000	1.10
--- src/libc/posix/fcntl/fcntl.txh	10 Mar 2003 23:19:19 -0000
*************** obtained, -1 is returned and @code{errno
*** 100,105 ****
--- 100,107 ----
  will be one of @code{EINVAL}, @code{EBADF}, @code{EACCES} or
  @code{ENOLCK}).
  
+ Locking of directories is not supported.
+ 
  @item F_SETLK
  Set or clear a file segment lock according to the structure pointed to
  by the third argument.  The lock is set when @code{l_type} is
*************** if it were @code{F_WRLCK} for a write lo
*** 114,119 ****
--- 116,123 ----
  This is because DOS/Win9x only supports one kind of lock, and it is the
  exclusive kind.
  
+ Locking of directories is not supported.
+ 
  @item F_SETLKW
  Same as @code{F_SETLK}, but if the lock is blocked, the call will wait
  (using @code{__dpmi_yield}, see @pxref{__dpmi_yield}) until it is
*************** unblocked and the lock can be applied.  
*** 121,126 ****
--- 125,132 ----
  exit} if the program making the call is the program which already owns
  the lock.
  
+ Locking of directories is not supported.
+ 
  @item F_GETLK64
  @item F_SETLK64
  @item F_SETLKW64
*************** gigabytes minus 1.  True 64-bit file loc
*** 134,139 ****
--- 140,147 ----
  The @code{struct flock64} members @var{l_start} and @var{l_len} are
  declared to be of type @code{offset_t}, which is in turn typedef'ed to
  be a @code{long long}.
+ 
+ Locking of directories is not supported.
  @end table
  
  This function can be hooked by the @dfn{Filesystem extensions}, see
Index: src/libc/compat/unistd/lockf.txh
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/compat/unistd/lockf.txh,v
retrieving revision 1.3
diff -p -c -3 -r1.3 lockf.txh
*** src/libc/compat/unistd/lockf.txh	29 Jan 2003 12:44:35 -0000	1.3
--- src/libc/compat/unistd/lockf.txh	10 Mar 2003 23:19:24 -0000
*************** section is already locked.
*** 74,79 ****
--- 74,80 ----
  
  @item EINVAL
  Parameter @var{function} is not one of the implemented functions.
+ Or: An attempt was made to lock a directory, which is not supported.
  @end table
  
  All lock requests in this implementation are coded as exclusive locks
Index: src/libc/compat/unistd/llockf.txh
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/compat/unistd/llockf.txh,v
retrieving revision 1.3
diff -p -c -3 -r1.3 llockf.txh
*** src/libc/compat/unistd/llockf.txh	29 Jan 2003 12:44:35 -0000	1.3
--- src/libc/compat/unistd/llockf.txh	10 Mar 2003 23:19:24 -0000
*************** section is already locked.
*** 85,90 ****
--- 85,91 ----
  
  @item EINVAL
  Parameter @var{function} is not one of the implemented functions.
+ Or: An attempt was made to lock a directory, which is not supported.
  @end table
  
  All lock requests in this implementation are coded as exclusive locks
Index: src/libc/posix/unistd/read.c
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/posix/unistd/read.c,v
retrieving revision 1.4
diff -p -c -3 -r1.4 read.c
*** src/libc/posix/unistd/read.c	21 Dec 2002 22:38:18 -0000	1.4
--- src/libc/posix/unistd/read.c	10 Mar 2003 23:19:31 -0000
***************
*** 1,3 ****
--- 1,4 ----
+ /* Copyright (C) 2003 DJ Delorie, see COPYING.DJ for details */
  /* Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details */
  /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
  #include <libc/stubs.h>
***************
*** 5,13 ****
--- 6,16 ----
  #include <fcntl.h>
  #include <unistd.h>
  #include <io.h>
+ #include <errno.h>
  
  #include <libc/dosio.h>
  #include <libc/ttyprvt.h>
+ #include <libc/fd_props.h>
  
  ssize_t
  read(int handle, void* buffer, size_t count)
*************** read(int handle, void* buffer, size_t co
*** 21,26 ****
--- 24,37 ----
        if (__libc_read_termios_hook(handle, buffer, count, &rv) != 0)
          return rv;
      }
+ 
+   /* Directory? If so, fail, which indicates that the caller should use
+    * readdir() instead. */
+   if (__get_fd_flags(handle) & FILE_DESC_DIRECTORY)
+   {
+     errno = EISDIR;
+     return -1;
+   }
  
    ngot = _read(handle, buffer, count);
    if(ngot <= 0)
Index: src/libc/posix/unistd/read.txh
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/posix/unistd/read.txh,v
retrieving revision 1.3
diff -p -c -3 -r1.3 read.txh
*** src/libc/posix/unistd/read.txh	29 Jan 2003 12:51:41 -0000	1.3
--- src/libc/posix/unistd/read.txh	10 Mar 2003 23:19:31 -0000
*************** This function reads at most @var{length}
*** 15,20 ****
--- 15,23 ----
  and text files, it may read less than the requested number of bytes. 
  At end-of-file, @code{read} will read exactly zero bytes.
  
+ Directories cannot be read using @code{read} --- use @code{readdir}
+ instead.
+ 
  @subheading Return Value
  
  The number of bytes read, zero meaning end-of-file, or -1 for an error. 
Index: src/libc/posix/unistd/write.c
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/posix/unistd/write.c,v
retrieving revision 1.10
diff -p -c -3 -r1.10 write.c
*** src/libc/posix/unistd/write.c	29 Jan 2003 01:29:42 -0000	1.10
--- src/libc/posix/unistd/write.c	10 Mar 2003 23:19:38 -0000
*************** write(int handle, const void* buffer, si
*** 40,45 ****
--- 40,52 ----
    if (count == 0)
      return 0; /* POSIX.1 requires this */
  
+   /* Directory? If so, fail. */
+   if (__get_fd_flags(handle) & FILE_DESC_DIRECTORY)
+   {
+     errno = EBADF;
+     return -1;
+   }
+ 
    if ( __has_fd_properties(handle)
    && ( __fd_properties[handle]->flags & FILE_DESC_APPEND ) )
    {
Index: src/libc/compat/unistd/llseek.c
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/compat/unistd/llseek.c,v
retrieving revision 1.6
diff -p -c -3 -r1.6 llseek.c
*** src/libc/compat/unistd/llseek.c	14 Jun 2002 14:39:55 -0000	1.6
--- src/libc/compat/unistd/llseek.c	10 Mar 2003 23:19:38 -0000
***************
*** 1,3 ****
--- 1,4 ----
+ /* Copyright (C) 2003 DJ Delorie, see COPYING.DJ for details */
  /* Copyright (C) 2002 DJ Delorie, see COPYING.DJ for details */
  /* Copyright (C) 2001 DJ Delorie, see COPYING.DJ for details */
  /*
*************** llseek( int handle, offset_t offset, int
*** 38,43 ****
--- 39,48 ----
    }
  
    has_props = __has_fd_properties(handle);
+ 
+   /* Directory? If so, we're done. */
+   if (has_props && (__fd_properties[handle]->flags & FILE_DESC_DIRECTORY))
+     return 0;
  
    /* POSIX doesn't allow seek on a pipe.  */
    if (has_props && (__fd_properties[handle]->flags & FILE_DESC_PIPE))
Index: src/libc/compat/unistd/ftruncat.c
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/compat/unistd/ftruncat.c,v
retrieving revision 1.3
diff -p -c -3 -r1.3 ftruncat.c
*** src/libc/compat/unistd/ftruncat.c	4 Aug 1999 19:58:23 -0000	1.3
--- src/libc/compat/unistd/ftruncat.c	10 Mar 2003 23:19:43 -0000
***************
*** 1,15 ****
  /* Copyright (C) 1999 DJ Delorie, see COPYING.DJ for details */
  /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
  #include <libc/stubs.h>
  #include <unistd.h>
  #include <io.h>
  
  int
  ftruncate(int fd, off_t where)
  {
!   off_t here = lseek(fd, 0, SEEK_CUR);
    int retval = 0;
  
    if (here == -1)
      return -1;
    if (lseek(fd, where, SEEK_SET) == -1)
--- 1,26 ----
+ /* Copyright (C) 2003 DJ Delorie, see COPYING.DJ for details */
  /* Copyright (C) 1999 DJ Delorie, see COPYING.DJ for details */
  /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
  #include <libc/stubs.h>
  #include <unistd.h>
  #include <io.h>
+ #include <errno.h>
+ #include <libc/fd_props.h>
  
  int
  ftruncate(int fd, off_t where)
  {
!   off_t here;
    int retval = 0;
  
+   /* Directory? If so, fail. */
+   if (__get_fd_flags(fd) & FILE_DESC_DIRECTORY)
+   {
+     errno = EINVAL;
+     return -1;
+   }
+ 
+   here = lseek(fd, 0, SEEK_CUR);
    if (here == -1)
      return -1;
    if (lseek(fd, where, SEEK_SET) == -1)
Index: src/libc/compat/unistd/ftruncat.txh
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/compat/unistd/ftruncat.txh,v
retrieving revision 1.5
diff -p -c -3 -r1.5 ftruncat.txh
*** src/libc/compat/unistd/ftruncat.txh	29 Jan 2003 12:44:35 -0000	1.5
--- src/libc/compat/unistd/ftruncat.txh	10 Mar 2003 23:19:43 -0000
*************** like @code{fwrite} and @code{fprintf}, s
*** 19,24 ****
--- 19,26 ----
  @code{FILE} object, you need to call @code{fflush} before calling this
  function.
  
+ @code{ftruncate} does not support directories.
+ 
  @subheading Return Value
  
  Zero for success, nonzero for failure.
Index: src/libc/posix/sys/stat/fstat.c
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/posix/sys/stat/fstat.c,v
retrieving revision 1.10
diff -p -c -3 -r1.10 fstat.c
*** src/libc/posix/sys/stat/fstat.c	14 Dec 2002 12:41:15 -0000	1.10
--- src/libc/posix/sys/stat/fstat.c	10 Mar 2003 23:19:52 -0000
***************
*** 1,3 ****
--- 1,4 ----
+ /* Copyright (C) 2003 DJ Delorie, see COPYING.DJ for details */
  /* Copyright (C) 2002 DJ Delorie, see COPYING.DJ for details */
  /* Copyright (C) 2001 DJ Delorie, see COPYING.DJ for details */
  /* Copyright (C) 2000 DJ Delorie, see COPYING.DJ for details */
*************** fstat(int handle, struct stat *statbuf)
*** 907,912 ****
--- 908,923 ----
    if (func && __FSEXT_func_wrapper(func, __FSEXT_fstat, &rv, handle, statbuf))
      {
         return rv;
+     }
+ 
+   /* See if this is a file descriptor for a directory. If so, just
+    * use a normal stat call. */
+   if (__get_fd_flags(handle) & FILE_DESC_DIRECTORY)
+     {
+       const char *filename = __get_fd_name(handle);
+ 
+       if (filename)
+ 	return stat(filename, statbuf);
      }
  
    if (fstat_assist(handle, statbuf) == -1)
Index: src/libc/compat/time/select.c
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/compat/time/select.c,v
retrieving revision 1.6
diff -p -c -3 -r1.6 select.c
*** src/libc/compat/time/select.c	14 Jun 2002 14:24:23 -0000	1.6
--- src/libc/compat/time/select.c	10 Mar 2003 23:19:53 -0000
***************
*** 1,3 ****
--- 1,4 ----
+ /* Copyright (C) 2003 DJ Delorie, see COPYING.DJ for details */
  /* Copyright (C) 2002 DJ Delorie, see COPYING.DJ for details */
  /* Copyright (C) 2001 DJ Delorie, see COPYING.DJ for details */
  /* Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details */
***************
*** 27,32 ****
--- 28,35 ----
  #include <libc/ttyprvt.h>
  #include <sys/fsext.h>
  #include <libc/fsexthlp.h>
+ #include <io.h>
+ #include <libc/fd_props.h>
  
  inline static int
  fp_output_ready(FILE *fp)
*************** fp_input_ready (FILE *fp)
*** 67,75 ****
  inline static int
  fd_output_ready(int fd)
  {
- 
    __dpmi_regs regs;
  
    regs.x.ax = 0x4407;
    regs.x.bx = fd;
    __dpmi_int (0x21, &regs);
--- 70,81 ----
  inline static int
  fd_output_ready(int fd)
  {
    __dpmi_regs regs;
  
+   /* If it's a directory, always return 0. We can't write to directories. */
+   if (__get_fd_flags(fd) & FILE_DESC_DIRECTORY)
+     return 0;
+ 
    regs.x.ax = 0x4407;
    regs.x.bx = fd;
    __dpmi_int (0x21, &regs);
*************** fd_output_ready(int fd)
*** 85,108 ****
  inline static int
  fd_input_ready(int fd)
  {
- 
    __dpmi_regs regs;
  
    /* If it's a disk file, always return 1, since DOS returns ``not ready''
       for files at EOF, but we won't block in that case.  */
!   regs.x.ax = 0x4400;
!   regs.x.bx = fd;
!   __dpmi_int (0x21, &regs);
!   if (regs.x.flags & 1)
!   {
!     errno = __doserr_to_errno (regs.x.ax);
      return -1;
!   }
!   if ((regs.x.dx & 0x80) == 0)	/* if not a character device */
      return 1;
    /* If it's a STDIN device, and termios buffers some characters, say
       it's ready for input.  */
!   else if ((regs.x.dx & _DEV_STDIN) == 1
  	   && __libc_read_termios_hook && __libc_termios_exist_queue ())
      return 1;
  
--- 91,116 ----
  inline static int
  fd_input_ready(int fd)
  {
    __dpmi_regs regs;
+   short dev_info;
+ 
+   /* If it's a directory, always return 1. That way the caller
+      will hit the EISDIR error as quickly as possible. */
+   if (__get_fd_flags(fd) & FILE_DESC_DIRECTORY)
+     return 1;
  
    /* If it's a disk file, always return 1, since DOS returns ``not ready''
       for files at EOF, but we won't block in that case.  */
!   dev_info = _get_dev_info(fd);
!   if (dev_info == -1)
      return -1;
! 
!   if ((dev_info & _DEV_CDEV) == 0)	/* if not a character device */
      return 1;
+ 
    /* If it's a STDIN device, and termios buffers some characters, say
       it's ready for input.  */
!   else if ((dev_info & _DEV_STDIN) == _DEV_STDIN
  	   && __libc_read_termios_hook && __libc_termios_exist_queue ())
      return 1;
  
Index: src/libc/compat/unistd/fsync.c
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/compat/unistd/fsync.c,v
retrieving revision 1.1
diff -p -c -3 -r1.1 fsync.c
*** src/libc/compat/unistd/fsync.c	12 Nov 1995 23:27:56 -0000	1.1
--- src/libc/compat/unistd/fsync.c	10 Mar 2003 23:19:58 -0000
***************
*** 1,14 ****
--- 1,24 ----
+ /* Copyright (C) 2003 DJ Delorie, see COPYING.DJ for details */
  /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
  #include <libc/stubs.h>
  #include <unistd.h>
  #include <dpmi.h>
  #include <errno.h>
  #include <libc/dosio.h>
+ #include <libc/fd_props.h>
  
  int
  fsync(int _fd)
  {
    int oerrno = errno;
+ 
+   /* Directory? If so, fail. */
+   if (__get_fd_flags(_fd) & FILE_DESC_DIRECTORY)
+   {
+     errno = EINVAL;
+     return -1;
+   }
+ 
    __dpmi_regs r;
    r.h.ah = 0x68;
    r.x.bx = _fd;
Index: src/libc/compat/unistd/fsync.txh
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/compat/unistd/fsync.txh,v
retrieving revision 1.3
diff -p -c -3 -r1.3 fsync.txh
*** src/libc/compat/unistd/fsync.txh	29 Jan 2003 12:44:35 -0000	1.3
--- src/libc/compat/unistd/fsync.txh	10 Mar 2003 23:19:58 -0000
*************** Forces all information about the file wi
*** 14,19 ****
--- 14,21 ----
  synchronized with the disk image.  Works by calling DOS function 0x68.
  @emph{Warning}: External disk caches are not flushed by this function.
  
+ @code{ftruncate} does not support directories.
+ 
  @subheading Return Value
  
  Zero on success, nonzero on failure. 
Index: src/libc/posix/unistd/makefile
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/posix/unistd/makefile,v
retrieving revision 1.5
diff -p -c -3 -r1.5 makefile
*** src/libc/posix/unistd/makefile	14 Jun 2001 02:56:32 -0000	1.5
--- src/libc/posix/unistd/makefile	10 Mar 2003 23:20:03 -0000
***************
*** 1,3 ****
--- 1,4 ----
+ # Copyright (C) 2003 DJ Delorie, see COPYING.DJ for details
  # Copyright (C) 2001 DJ Delorie, see COPYING.DJ for details
  # Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details
  # Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details
*************** SRC += execv.c
*** 20,25 ****
--- 21,27 ----
  SRC += execve.c
  SRC += execvp.c
  SRC += execvpe.c
+ SRC += fchdir.c
  SRC += fork.c
  SRC += fpathcon.c
  SRC += getcwd.c
Index: src/docs/kb/wc204.txi
===================================================================
RCS file: /cvs/djgpp/djgpp/src/docs/kb/wc204.txi,v
retrieving revision 1.147
diff -p -c -3 -r1.147 wc204.txi
*** src/docs/kb/wc204.txi	8 Mar 2003 01:19:20 -0000	1.147
--- src/docs/kb/wc204.txi	10 Mar 2003 23:20:08 -0000
***************
*** 1,4 ****
- 
  @node Changes in 2.04, , Changes in 2.03, What Changed
  @section Changes in 2.04
  
--- 1,3 ----
*************** The function @code{fchmod} was added.
*** 911,913 ****
--- 910,927 ----
  @findex _tolower
  @findex _toupper
  The functions @code{_tolower} and @code{_toupper} were added.
+ 
+ @findex fchdir
+ @findex open AT r{, and directories}
+ @findex read AT r{, and directories}
+ @findex write AT r{, and directories}
+ @findex lseek AT r{, and directories}
+ @findex ftruncate AT r{, and directories}
+ @findex fstat AT r{, and directories}
+ @findex select AT r{, and directories}
+ @findex fsync AT r{, and directories}
+ @cindex Opening directories with @code{open}
+ The function @code{fchdir} was added.  This required modifications
+ to the POSIX functions @code{open}, @code{read}, @code{write},
+ @code{lseek}, @code{ftruncate}, @code{fstat}, @code{select}
+ and @code{fsync}, to make them aware of file descriptors for directories.
Index: tests/libc/posix/unistd/makefile
===================================================================
RCS file: /cvs/djgpp/djgpp/tests/libc/posix/unistd/makefile,v
retrieving revision 1.4
diff -p -c -3 -r1.4 makefile
*** tests/libc/posix/unistd/makefile	1 Mar 2003 13:17:36 -0000	1.4
--- tests/libc/posix/unistd/makefile	10 Mar 2003 23:20:13 -0000
*************** SRC += getpid.c
*** 8,13 ****
--- 8,15 ----
  SRC += sleep.c
  SRC += tread.c
  SRC += write.c
+ SRC += t-fchdir.c
  SRC += t-isatty.c
+ SRC += t-select.c
  
  include $(TOP)/../makefile.inc
*** /dev/null	Mon Mar 10 23:24:51 2003
--- src/libc/posix/unistd/fchdir.c	Sat Mar  8 13:06:04 2003
***************
*** 0 ****
--- 1,26 ----
+ /* Copyright (C) 2003 DJ Delorie, see COPYING.DJ for details */
+ #include <libc/stubs.h>
+ #include <string.h>
+ #include <errno.h>
+ #include <unistd.h>
+ #include <io.h>
+ #include <libc/fd_props.h>
+ 
+ int
+ fchdir (int fd)
+ {
+   const char *filename = __get_fd_name(fd);
+   const int   flags    = __get_fd_flags(fd);
+ 
+   /* Check that it's a valid file descriptor. */
+   if (_get_dev_info(fd) == -1)
+     return(-1);
+ 
+   /* Is it actually a directory? */
+   if (((flags & FILE_DESC_DIRECTORY) == 0) || (filename == NULL)) {
+     errno = ENOTDIR;
+     return(-1);
+   }
+ 
+   return(chdir(filename));
+ }
*** /dev/null	Mon Mar 10 23:24:51 2003
--- src/libc/posix/unistd/fchdir.txh	Sun Mar  9 15:59:58 2003
***************
*** 0 ****
--- 1,28 ----
+ @node fchdir, file system
+ @findex fchdir
+ @subheading Syntax
+ 
+ @example
+ #include <unistd.h>
+ 
+ int fchdir(int fd);
+ @end example
+ 
+ @subheading Description
+ 
+ This function changes the current directory to the directory
+ described by the file descriptor @var{fd}.
+ 
+ @subheading Return Value
+ 
+ Zero on success, else nonzero and @var{errno} set if error.
+ 
+ @subheading Portability
+ 
+ @portability !ansi, posix
+ 
+ @subheading Example
+ 
+ @example
+ TODO
+ @end example
*** /dev/null	Mon Mar 10 23:24:51 2003
--- tests/libc/posix/unistd/t-fchdir.c	Mon Mar 10 22:56:16 2003
***************
*** 0 ****
--- 1,359 ----
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include <errno.h>
+ #include <unistd.h>
+ #include <fcntl.h>
+ #include <sys/stat.h>
+ #include <io.h>
+ #include <sys/ioctl.h>
+ #include <time.h>
+ #include <limits.h>
+ #include <libc/fd_props.h>
+ 
+ #define TEST_DIR "t-fchdir.dir"
+ 
+ int
+ main (int argc, char *argv[])
+ {
+   off_t offset;
+   char buf[1024];
+   char cwd[PATH_MAX];
+   fd_set read_fds, write_fds, except_fds;
+   short dev_info;
+   struct stat stat_buf, fstat_buf;
+   int fd, ret;
+   char *p;
+ 
+   if (   (access(TEST_DIR, D_OK) != 0)
+       && (mkdir(TEST_DIR, S_IRUSR|S_IWUSR) < 0))
+     {
+       perror(argv[0]);
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   /* Try opening the directory for writes. */
+   fd = open(TEST_DIR, O_RDWR);
+   if ((fd >= 0) || ((fd < 0) && (errno != EISDIR)))
+     {
+       if (fd >= 0)
+ 	puts("Unexpectedly able to open() '" TEST_DIR "' for read-write!");
+       else
+ 	perror(argv[0]);
+ 
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   fd = open(TEST_DIR, O_WRONLY);
+   if ((fd >= 0) || ((fd < 0) && (errno != EISDIR)))
+     {
+       if (fd >= 0)
+ 	puts("Unexpectedly able to open() '" TEST_DIR "' for write-only!");
+       else
+ 	perror(argv[0]);
+ 
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   /* Try opening the file for reads. */
+   fd = open(TEST_DIR, O_RDONLY);
+   if (fd < 0)
+     {
+       puts("Unable to open() '" TEST_DIR "'!");
+       perror(argv[0]);
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   /* Try read, write. */
+   memset(buf, 'X', sizeof(buf));
+ 
+   ret = read(fd, buf, sizeof(buf));
+   if ((ret >= 0) || ((ret < 0) && (errno != EISDIR)))
+     {
+       if (ret >= 0)
+ 	puts("Unexpectedly able to read() from '" TEST_DIR "'!");
+       else
+ 	perror(argv[0]);
+ 
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   ret = write(fd, buf, sizeof(buf));
+   if ((ret >= 0) || ((ret < 0) && (errno != EBADF)))
+     {
+       if (ret >= 0)
+ 	puts("Unexpectedly able to write() to '" TEST_DIR "'!");
+       else
+ 	perror(argv[0]);
+ 
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   /* Try lseek. */
+   offset = lseek(fd, 42L, SEEK_SET);
+   if (offset != 0)
+     {
+       if (offset != -1)
+ 	printf("Unexpected result from lseek() on '%s': %ld\n",
+ 	       TEST_DIR, (long) offset);
+       else
+ 	perror(argv[0]);
+ 
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   /* Try ftruncate. */
+   ret = ftruncate(fd, 20L);
+   if ((ret != -1) || ((ret == -1) && (errno != EINVAL)))
+     {
+       if (ret != -1)
+ 	puts("Unexpectedly able to ftruncate() '" TEST_DIR "'!");
+       else
+ 	perror(argv[0]);
+ 
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   /* Try fchmod. Make the directory read-only. */
+   ret = fchmod(fd, S_IRUSR);
+   if (ret < 0)
+     {
+       perror(argv[0]);
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   /* Try fchown. */
+   ret = fchown(fd, getuid() * 2, getgid() * 2);
+   if (ret < 0)
+     {
+       perror(argv[0]);
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   /* Try ioctl. Check that we get the same device info as _get_dev_info. */
+   dev_info = _get_dev_info(fd);
+   if (dev_info == -1)
+     {
+       puts("Unable to get device information for '" TEST_DIR "'!");
+       perror(argv[0]);
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   ret = ioctl(fd, DOS_GETDEVDATA);
+   if ((ret == -1) || ((ret & 0xffff) != (dev_info & 0xffff)))
+     {
+       if (ret != dev_info)
+ 	{
+ 	  puts("Different device information from ioctl() for '"
+ 	       TEST_DIR "'!");
+ 	  printf("_get_dev_info() vs. ioctl(): %d vs. %d\n",
+ 		 dev_info, ret);
+ 	}
+       else
+ 	{
+ 	  perror(argv[0]);
+ 	}
+ 
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   /* Try fcntl. Check that the close-on-exec flag is set. */
+   ret = fcntl(fd, F_GETFD);
+   if ((ret < 0) || ((ret & FD_CLOEXEC) == 0))
+     {
+       if (ret >= 0)
+ 	puts("FD_CLOEXEC was not set for '" TEST_DIR "'!");
+       else
+ 	perror(argv[0]);
+ 
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   /* Try lockf. */
+   ret = lockf(fd, F_TLOCK, 1024);
+   if ((ret >= 0) || ((ret < 0) && (errno != EINVAL)))
+     {
+       if (ret >= 0)
+ 	puts("Unexpectedly able to lockf() '" TEST_DIR "'!");
+       else
+ 	perror(argv[0]);
+ 
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   /* Try fstat. Compare the result with that of stat. */
+   ret = fstat(fd, &fstat_buf);
+   if (ret < 0)
+     {
+       puts("fstat() failed!");
+       perror(argv[0]);
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   ret = stat(TEST_DIR, &stat_buf);
+   if (ret < 0)
+     {
+       puts("stat() failed!");
+       perror(argv[0]);
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   if (memcmp(&stat_buf, &fstat_buf, sizeof(stat_buf)) != 0)
+     {
+       puts("fstat() and stat() returned different results!");
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   if (!S_ISDIR(stat_buf.st_mode))
+     {
+       puts("fstat() doesn't think '" TEST_DIR "' is a directory!");
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   /* Copied & modified from src/libc/posix/sys/stat/stat.c. */
+   printf("%s: %d %6u %o %d %d %ld %lu %s", __get_fd_name(fd),
+ 	 stat_buf.st_dev,
+ 	 (unsigned)stat_buf.st_ino,
+ 	 stat_buf.st_mode,
+ 	 stat_buf.st_nlink,
+ 	 stat_buf.st_uid,
+ 	 (long)stat_buf.st_size,
+ 	 (unsigned long)stat_buf.st_mtime,
+ 	 ctime(&stat_buf.st_mtime));
+ 
+   printf("\t\t\tBlock size: %d\n",
+ 	 stat_buf.st_blksize);
+ 
+   _djstat_describe_lossage(stderr);
+ 
+   /* Try select. */
+   FD_ZERO(&read_fds);
+   FD_ZERO(&write_fds);
+   FD_ZERO(&except_fds);
+ 
+   FD_SET(fd, &read_fds);
+   FD_SET(fd, &write_fds);
+   FD_SET(fd, &except_fds);
+ 
+   ret = select(fd + 1, &read_fds, &write_fds, &except_fds, NULL);
+   if (ret < 0)
+     {
+       puts("select() failed!");
+       perror(argv[0]);
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   if (ret != 1)
+     {
+       puts("select() did not return the expected number!");
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   if (!FD_ISSET(fd, &read_fds))
+     {
+       puts("Directory '" TEST_DIR "' should be ready for reading!");
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   if (FD_ISSET(fd, &write_fds))
+     {
+       puts("Directory '" TEST_DIR "' should not be ready for writing!");
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   if (FD_ISSET(fd, &except_fds))
+     {
+       puts("Directory '" TEST_DIR "' should not have an error!");
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   /* Try fsync. */
+   ret = fsync(fd);
+   if ((ret >= 0) || ((ret < 0) && (errno != EINVAL)))
+     {
+       if (ret >= 0)
+ 	puts("Unexpectedly able to fsync() to '" TEST_DIR "'!");
+       else
+ 	perror(argv[0]);
+ 
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   /* Try fchdir. */
+   ret = fchdir(fd);
+   if (ret < 0)
+     {
+       perror(argv[0]);
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   /* Where are we? */
+   if (getcwd(cwd, sizeof(cwd)) == NULL)
+     {
+       perror(argv[0]);
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   p = basename(cwd);
+   if (p == NULL)
+     {
+       printf("basename() failed on '%s'\n", cwd);
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   if (strcasecmp(p, TEST_DIR) != 0)
+     {
+       printf("Now in '%s'; expected to be in '%s'\n", p, TEST_DIR);
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   /* Change back. */
+   ret = chdir("..");
+   if (ret < 0)
+     {
+       perror(argv[0]);
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   /* Done. */
+   ret = close(fd);
+   if (ret < 0)
+     {
+       puts("Unable to close '" TEST_DIR "'!");
+       perror(argv[0]);
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   puts("PASS");
+   return(EXIT_SUCCESS);
+ }
*** /dev/null	Mon Mar 10 23:24:51 2003
--- tests/libc/posix/unistd/t-select.c	Mon Mar 10 21:58:22 2003
***************
*** 0 ****
--- 1,187 ----
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include <unistd.h>
+ #include <time.h>
+ #include <errno.h>
+ #include <fcntl.h>
+ #include <sys/stat.h>
+ 
+ #define TEST_FILE "t-select.tst"
+ 
+ int
+ main (int argc, char *argv[])
+ {
+   fd_set read_fds;
+   fd_set write_fds;
+   fd_set except_fds;
+   struct timeval tv;
+   int fd, ret;
+ 
+   /* Create the test file, if necessary. */
+   if (access(TEST_FILE, D_OK) == 0)
+     {
+       puts("Directory in way - please remove '" TEST_FILE "'!");
+       puts("FAIL");
+       return(EXIT_SUCCESS);
+     }
+ 
+   if (access(TEST_FILE, F_OK) != 0)
+     {
+       fd = open(TEST_FILE, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
+       if (fd < 0)
+ 	puts("Unable to create '" TEST_FILE "'!");
+     }
+   else
+     {
+       fd = open(TEST_FILE, O_RDWR);
+       if (fd < 0)
+ 	puts("Unable to open '" TEST_FILE "'!");
+     }
+ 
+   if (fd < 0)
+     {
+       perror(argv[0]);
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   /* Check the file is ready for read & write and that there aren't
+    * any errors. */
+   FD_ZERO(&read_fds);
+   FD_ZERO(&write_fds);
+   FD_ZERO(&except_fds);
+ 
+   FD_SET(fd, &read_fds);
+   FD_SET(fd, &write_fds);
+   FD_SET(fd, &except_fds);
+ 
+   ret = select(fd + 1, &read_fds, &write_fds, &except_fds, NULL);
+   if (ret < 0)
+     {
+       perror(argv[0]);
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   if (ret != 2)
+     {
+       puts("select() did not return the expected number!");
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   if (!FD_ISSET(fd, &read_fds))
+     {
+       puts("File '" TEST_FILE "' should be ready for reading!");
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   if (!FD_ISSET(fd, &write_fds))
+     {
+       puts("File '" TEST_FILE "' should be ready for writing!");
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   if (FD_ISSET(fd, &except_fds))
+     {
+       puts("File '" TEST_FILE "' should not have an error!");
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   /* Try a time-out. */
+   FD_ZERO(&except_fds);
+ 
+   FD_SET(fd, &except_fds);
+ 
+   tv.tv_sec  = 5;
+   tv.tv_usec = 0;
+   printf("Trying a time-out: %ld seconds\n", (long) tv.tv_sec);
+ 
+   ret = select(fd + 1, NULL, NULL, &except_fds, &tv);
+   if (ret < 0)
+     {
+       perror(argv[0]);
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   if (FD_ISSET(fd, &except_fds))
+     {
+       puts("File '" TEST_FILE "' should not have an error!");
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   /* Done with the file now. */
+   close(fd);
+   fd = -1;
+ 
+   /* Try select on stdin. */
+   FD_ZERO(&read_fds);
+ 
+   FD_SET(fileno(stdin), &read_fds);
+ 
+   tv.tv_sec  = 5;
+   tv.tv_usec = 0;
+   printf("Please press a key in the next %ld seconds\n", (long) tv.tv_sec);
+ 
+   ret = select(fileno(stdin) + 1, &read_fds, NULL, NULL, &tv);
+   if (ret <= 0)
+     {
+       if (ret == 0)
+ 	puts("No key pressed");
+       else
+ 	perror(argv[0]);
+ 
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   if (!FD_ISSET(fileno(stdin), &read_fds))
+     {
+       puts("stdin should be ready for reading!");
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   /* Try select on stdout. */
+   FD_ZERO(&write_fds);
+ 
+   FD_SET(fileno(stdout), &write_fds);
+ 
+   ret = select(fileno(stdout) + 1, NULL, &write_fds, NULL, NULL);
+   if (ret != 1)
+     {
+     }
+ 
+   if (!FD_ISSET(fileno(stdout), &write_fds))
+     {
+       puts("stdout should be ready for writing!");
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   /* Try select on stderr. */
+   FD_ZERO(&write_fds);
+ 
+   FD_SET(fileno(stderr), &write_fds);
+ 
+   ret = select(fileno(stderr) + 1, NULL, &write_fds, NULL, NULL);
+   if (ret != 1)
+     {
+     }
+ 
+   if (!FD_ISSET(fileno(stderr), &write_fds))
+     {
+       puts("stderr should be ready for writing!");
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   puts("PASS");
+   return(EXIT_SUCCESS);
+ }

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019