www.delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/2000/11/19/02:39:06

Message-Id: <5.0.1.4.0.20001119021029.0235ee50@pop5.banet.net>
X-Sender: usbanet DOT farley3 AT pop5 DOT banet DOT net
X-Mailer: QUALCOMM Windows Eudora Version 5.0.1
Date: Sun, 19 Nov 2000 02:39:39 -0500
To: djgpp-workers AT delorie DOT com
From: "Peter J. Farley III" <pjfarley AT banet DOT net>
Subject: Trial version of locking fcntl
Cc: "Mark E." <snowball3 AT bigfoot DOT com>
Mime-Version: 1.0
Reply-To: djgpp-workers AT delorie DOT com

--=====================_55779254==_
Content-Type: text/plain; charset="us-ascii"; format=flowed

OK, I have gotten Mark's locking version of fcntl into what looks to me 
like working order.  I have attached a diff to the current v2.03 fcntl, 
a complete version and a small test program.

Please test it on your systems.  The test program just prints the 
return code from various calls to fcntl, it's not a very complete test 
yet but it is a small beginning.  I will try to make up a more complete 
test program and post it later.  As Mark did, I mainly used it to step 
through the code with gdb to find problems.

I have built libc with this version and then built a recent bleedperl 
release (perl AT 7707) with the new libc.  Perl seems to like it; perl 
uses the locking functions of fcntl to simulate flock and passes both 
basic perl flock tests and tests using the emulated flock in the 
Storable module tests.  There was one locking-related patch needed to 
Storable.pm, and I have submitted that to the p5p list.

The F_GETLK function is not yet working properly, but I hope to have 
that fixed soon.

For those interested, the main change I made to Mark's version was the 
assignment to lock_req in the F_SETLK... section.  Mark had coded this:

       va_start (ap, cmd);
       lock_req = va_arg(lock_req, struct flock *);
       va_end (ap);

What was needed was this:

       va_start (ap, cmd);
       lock_req = va_arg(ap, struct flock *);
       va_end (ap);

Notice the difference in the argument to va_arg.

I also allowed F_RDLCK requests to proceed under the following 
conditions:

        lock_req->l_whence = SEEK_SET
        lock_req->l_start == 0
        lock_req->l_len == 0

Under these conditions, F_RDLCK is equivalent to a file-level lock, so 
I saw no harm in allowing it.

Comments, errata, etc. welcome.

Enjoy.

--=====================_55779254==_
Content-Type: text/plain; charset="us-ascii"
Content-Disposition: attachment; filename="fcntl.dif"

--- libc/posix/fcntl/fcntl.c0	Thu Jun  3 13:27:38 1999
+++ libc/posix/fcntl/fcntl.c	Fri Nov 17 20:08:00 2000
@@ -1,3 +1,4 @@
+/* Copyright (C) 2000 DJ Delorie, see COPYING.DJ for details */
 /* Copyright (C) 1999 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 */
@@ -7,28 +8,101 @@
 #include <stdarg.h>
 #include <unistd.h>
 #include <fcntl.h>
+#include <io.h>
 #include <sys/fsext.h>
+#include <sys/movedata.h>
+#include <sys/farptr.h>
+#include <libc/dosio.h>
+#include <libc/getdinfo.h>
 
-static int
-is_used_fd(int fd)
+
+#include <go32.h>
+
+
+static unsigned long _get_sft_entry_ptr(int fd)
 {
   __dpmi_regs regs;
+  unsigned char index;
+  unsigned long es, di;
 
-  regs.x.ax = 0x4400;
+
+  /* Get the JFT entry address for this handle.  */
+  regs.x.ax = 0x1220;
   regs.x.bx = fd;
-  __dpmi_int(0x21, &regs);
+  __dpmi_int(0x2f, &regs);
+
+
+  if (regs.x.flags & 1)
+  {
+    errno = ENOSYS;
+    return 0;
+  }
+
+
+  /* Get the SFT entry number for this handle.  */
+  es = regs.x.es;
+  di = regs.x.di;
+  index = _farpeekb(_dos_ds, es * 16 + di);
+
+
+  /* Now get the address of the entry.  */
+  regs.x.ax = 0x1216;
+  regs.x.bx = index;
+  __dpmi_int (0x2f, &regs);
   if (regs.x.flags & 1)
+  {
+    errno = ENOSYS;
     return 0;
+  }
+
+
+  es = regs.x.es;
+  di = regs.x.di;
+
+
+  return es * 16 + di;
+}
+
+
+static int
+inherit_bit_test (int fd, short dev_info)
+{
+  __dpmi_regs regs;
+  short new_dev_info;
 
-  return 1;
+
+  dev_info |= _DEV_NO_INHERIT;
+  regs.x.ax = 0x4401;
+  regs.x.bx = fd;
+  regs.x.dx = dev_info;
+  __dpmi_int(0x21, &regs);
+  
+  new_dev_info = _get_dev_info(fd);
+  
+  /* If the dev info words are equal, then the documented
+     interface can't be used to set the inheritance bit.  */
+  return (new_dev_info == dev_info) ? 1 : 0;
 }
 
+
 int
 fcntl(int fd, int cmd, ...)
 {
   int tofd, open_max;
   va_list ap;
-  __FSEXT_Function *func = __FSEXT_get_function(fd);
+  __FSEXT_Function *func;
+  short dev_info = _get_dev_info(fd);
+  static int inherit_bit_visible = -1;
+  int errno_save;
+
+  /* Verify the descriptor is valid by retrieving
+     the handle's device info word.  */
+  if (dev_info == -1)
+    return dev_info;
+
+
+  /* Allow a fd to override with a FSEXT.  */
+  func = __FSEXT_get_function(fd);
   if (func)
   {
     int rv;
@@ -36,62 +110,272 @@
       return rv;
   }
 
+
+  errno_save = errno;
+
   switch (cmd)
   {
-  case F_DUPFD:
-    va_start(ap, cmd);
-    tofd = va_arg(ap, int);
-    va_end(ap);
-
-    open_max = getdtablesize();
-    if (tofd < 0 || tofd >= open_max)
+    case F_DUPFD:
     {
-      errno = EINVAL;
-      return -1;
+      va_start(ap, cmd);
+      tofd = va_arg(ap, int);
+      va_end(ap);
+
+
+      open_max = getdtablesize();
+      while (tofd < open_max)
+      {
+        /* If unable to get the device info for the handle,
+           then the handle is not active and it can be used.  */
+        if (_get_dev_info(tofd) == -1)
+          break;
+        tofd++;
+      }
+
+
+      if (tofd >= open_max)
+      {
+        errno = EMFILE;
+        return -1;
+      }
+
+
+      errno = errno_save;
+      return dup2(fd, tofd);
     }
-    while (tofd < open_max)
+
+
+    case F_GETFD:
     {
-      if (! is_used_fd(tofd))
-	break;
-      tofd++;
+       unsigned long entry_ptr;
+
+
+      /* DOS only passes the first 20 handles to child programs.  In
+         addition, handles 19 and 18 will be closed by the stub of the
+         child program (if it is a DJGPP program).  */
+
+
+      if (fd >= 18)
+        return FD_CLOEXEC;
+
+
+      /* Determine if the documented interface will allow twiddling with
+         the inherit bit. If not, fallback to the undocumented one.  */
+      if (inherit_bit_visible == -1)
+        inherit_bit_visible = inherit_bit_test (fd, dev_info);
+
+      if (!inherit_bit_visible)
+      {
+        entry_ptr = _get_sft_entry_ptr(fd);
+        if (entry_ptr == 0)
+        {
+          /* The fd has already been validated, so reaching here means
+             something is wrong with _get_sft_entry_ptr. */
+          return -1;
+        }
+        /* Offset 5 in the SFT contains the device info word.  */
+        dev_info = _farpeekw(_dos_ds, entry_ptr + 5);
+      }
+      return (dev_info & _DEV_NO_INHERIT) ? FD_CLOEXEC : 0;
     }
 
-    if (tofd >= open_max)
+
+    case F_SETFD:
     {
-      errno = EMFILE;
-      return -1;
+      unsigned int flag;
+      unsigned long entry_ptr = 0; /* shut up -Wall */
+      __dpmi_regs regs;
+
+
+      va_start (ap, cmd);
+      flag = va_arg(ap, int);
+      va_end(ap);
+
+
+      /* DOS only passes the first 20 handles to child programs.  In
+         addition, handles 19 and 18 will be closed by the stub of the
+         child program (if it is a DJGPP program).  */
+      if (fd >= 18)
+      {
+        if (flag & FD_CLOEXEC)
+          return 0;
+        else
+        {
+          errno = ENOSYS;
+          return -1;
+        }
+      }
+
+
+      /* Determine if the documented interface will allow twiddling with
+         the inherit bit. If not, fallback to the undocumented one.  */
+      if (inherit_bit_visible == -1)
+        inherit_bit_visible = inherit_bit_test(fd, dev_info);
+
+      if (!inherit_bit_visible)
+      {
+        entry_ptr = _get_sft_entry_ptr(fd);
+        if (entry_ptr == 0)
+        {
+          /* The fd has already been validated, so reaching here means
+             something is wrong with _get_sft_entry_ptr. */
+          return -1;
+        }
+
+
+        dev_info = _farpeekw(_dos_ds, entry_ptr + 5);
+      }
+
+
+      if (flag & FD_CLOEXEC)
+        dev_info |= _DEV_NO_INHERIT;
+      else
+        dev_info &= ~(_DEV_NO_INHERIT);
+
+
+      if (inherit_bit_visible)
+      {
+        regs.x.ax = 0x4401;
+        regs.x.bx = fd;
+        regs.x.dx = dev_info;
+        __dpmi_int(0x21, &regs);
+      }
+      else
+        _farpokew(_dos_ds, entry_ptr + 5, dev_info);
+
+
+      return 0;
     }
 
-    return dup2(fd, tofd);
-    
-  case F_GETFD:
-    /* DOS only passes the first 20 handles to child programs.  In
-       addition, handles 19 and 18 will be closed by the stub of the
-       child program (if it is a DJGPP program).
 
-       FIXME: we should look at the no-inherit bit stashed in the SFT
-       entry pointed to by the handle, since some of the first 18
-       handles could have been opened with a no-inherit bit.  */
-    return fd >= 18 ? FD_CLOEXEC : 0;
-  case F_SETFD:
-    if ((fd < 18) ^ ((cmd & FD_CLOEXEC) != 0))
+    case F_GETFL:
+    {
       return 0;
-    else
+    }
+
+
+    case F_SETFL:
+    {
+      unsigned char new_mode_bits;
+
+
+      va_start (ap, cmd);
+      new_mode_bits = va_arg(ap,int);
+      va_end(ap);
+
+
+      /* Allow removal of O_NONBLOCK, since DJGPP doesn't support it
+         anyway.  */
+      return (new_mode_bits == 0) ? 0 : -1;
+    }
+
+
+    case F_GETLK:
+    case F_SETLK:
+    case F_SETLKW:
+    {
+      struct flock *lock_req = NULL; /* shut up -Wall */
+      int ret = -1;
+      off_t pos, cur_pos, lock_pos;
+      off_t len;
+
+
+      cur_pos = lseek(fd, 0, SEEK_CUR);
+      va_start (ap, cmd);
+      lock_req = va_arg(ap, struct flock *);
+      va_end (ap);
+      lock_pos = lseek (fd, lock_req->l_start, lock_req->l_whence);
+      len = lock_req->l_len;
+
+
+      /* If l_len is zero, then the lock is to be set from l_start
+         until the end-of-file. */
+      if (len == 0)
       {
-	errno = ENOSYS;
-	return -1;
+        len = filelength(fd) - cur_pos;
+        /* This should probably be an error.  */
+        if (len <= 0)
+          len = 1;
       }
-  case F_GETFL:
-    return 0;	/* FIXME: should use the data in the SFT */
-  case F_SETFL:
-    errno = ENOSYS;
-    return -1;
-  case F_GETLK:
-  case F_SETLK:
-  case F_SETLKW:
-    errno = ENOSYS;
-    return -1;
+
+
+      lseek (fd, cur_pos, SEEK_SET);
+
+
+      /* If l_len is positive, the area to lock is from l_start
+         to l_start + l_len - 1. If l_len is negative, the area to lock is
+         from l_start + len to l_start - 1.  */
+      if (len > 0)
+      {
+        pos = lock_pos;
+      }
+      else
+      {
+        pos = lock_pos + len;
+        len = -lock_req->l_len;
+      }
+
+
+      /* DOS/Windows only support read locks on a per-file basis,
+         so any attempted use of a read lock is an error,
+         UNLESS all of these conditions are true, which makes the
+         request into a per-file lock equivalent to F_WRLCK:
+
+             lock_req->l_whence = SEEK_SET
+             lock_req->l_start == 0
+             lock_req->l_len == 0
+      */
+      if ((lock_req->l_type == F_RDLCK)   &&
+          (lock_req->l_whence != SEEK_SET ||
+      	   lock_req->l_start  != 0        ||
+      	   lock_req->l_len    != 0))
+      {
+        errno = ENOSYS;
+        return -1;
+      }
+
+      if (lock_req->l_type == F_UNLCK)
+      {
+        ret = _dos_unlock(fd, pos, len);
+      }
+      else if ((lock_req->l_type == F_WRLCK) || (lock_req->l_type == F_RDLCK))
+      {
+        ret = _dos_lock(fd, pos, len);
+        if (cmd == F_GETLK)
+        {
+          if (ret == 0)
+          {
+            _dos_unlock(fd, pos, len);
+            /* If no lock is found that would prevent a lock from
+               being created, the lock type is set to F_UNLCK.  */
+            lock_req->l_type = F_UNLCK;
+          }
+          else
+          {
+            /* If a lock is found then l_whence, l_start, and l_len
+               should point to the area covered by the lock. But the
+               file locking interface doesn't report where the
+               existing lock is, so nothing more can be done.  */
+            ;
+          }
+        }
+
+
+        /* If F_SETLKW is set, wait for the lock to be released.  */
+        if (cmd == F_SETLKW && ret < 0)
+          while ((ret = _dos_lock(fd, pos, len)) < 0)
+            __dpmi_yield();
+      }
+      if (ret < 0)
+        errno = ENOSYS;
+
+
+      return ret;
+    }
   }
+
+
+  /* In case fcntl is called with an unrecognized command.  */
   errno = ENOSYS;
   return -1;
 }

--=====================_55779254==_
Content-Type: text/plain; charset="us-ascii"
Content-Disposition: attachment; filename="fcntl.c"

/* Copyright (C) 2000 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 1999 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>
#include <dpmi.h>
#include <errno.h>
#include <stdarg.h>
#include <unistd.h>
#include <fcntl.h>
#include <io.h>
#include <sys/fsext.h>
#include <sys/movedata.h>
#include <sys/farptr.h>
#include <libc/dosio.h>
#include <libc/getdinfo.h>


#include <go32.h>


static unsigned long _get_sft_entry_ptr(int fd)
{
  __dpmi_regs regs;
  unsigned char index;
  unsigned long es, di;


  /* Get the JFT entry address for this handle.  */
  regs.x.ax = 0x1220;
  regs.x.bx = fd;
  __dpmi_int(0x2f, &regs);


  if (regs.x.flags & 1)
  {
    errno = ENOSYS;
    return 0;
  }


  /* Get the SFT entry number for this handle.  */
  es = regs.x.es;
  di = regs.x.di;
  index = _farpeekb(_dos_ds, es * 16 + di);


  /* Now get the address of the entry.  */
  regs.x.ax = 0x1216;
  regs.x.bx = index;
  __dpmi_int (0x2f, &regs);
  if (regs.x.flags & 1)
  {
    errno = ENOSYS;
    return 0;
  }


  es = regs.x.es;
  di = regs.x.di;


  return es * 16 + di;
}


static int
inherit_bit_test (int fd, short dev_info)
{
  __dpmi_regs regs;
  short new_dev_info;


  dev_info |= _DEV_NO_INHERIT;
  regs.x.ax = 0x4401;
  regs.x.bx = fd;
  regs.x.dx = dev_info;
  __dpmi_int(0x21, &regs);
  
  new_dev_info = _get_dev_info(fd);
  
  /* If the dev info words are equal, then the documented
     interface can't be used to set the inheritance bit.  */
  return (new_dev_info == dev_info) ? 1 : 0;
}


int
fcntl(int fd, int cmd, ...)
{
  int tofd, open_max;
  va_list ap;
  __FSEXT_Function *func;
  short dev_info = _get_dev_info(fd);
  static int inherit_bit_visible = -1;
  int errno_save;

  /* Verify the descriptor is valid by retrieving
     the handle's device info word.  */
  if (dev_info == -1)
    return dev_info;


  /* Allow a fd to override with a FSEXT.  */
  func = __FSEXT_get_function(fd);
  if (func)
  {
    int rv;
    if (func(__FSEXT_fcntl, &rv, &fd))
      return rv;
  }


  errno_save = errno;

  switch (cmd)
  {
    case F_DUPFD:
    {
      va_start(ap, cmd);
      tofd = va_arg(ap, int);
      va_end(ap);


      open_max = getdtablesize();
      while (tofd < open_max)
      {
        /* If unable to get the device info for the handle,
           then the handle is not active and it can be used.  */
        if (_get_dev_info(tofd) == -1)
          break;
        tofd++;
      }


      if (tofd >= open_max)
      {
        errno = EMFILE;
        return -1;
      }


      errno = errno_save;
      return dup2(fd, tofd);
    }


    case F_GETFD:
    {
       unsigned long entry_ptr;


      /* DOS only passes the first 20 handles to child programs.  In
         addition, handles 19 and 18 will be closed by the stub of the
         child program (if it is a DJGPP program).  */


      if (fd >= 18)
        return FD_CLOEXEC;


      /* Determine if the documented interface will allow twiddling with
         the inherit bit. If not, fallback to the undocumented one.  */
      if (inherit_bit_visible == -1)
        inherit_bit_visible = inherit_bit_test (fd, dev_info);

      if (!inherit_bit_visible)
      {
        entry_ptr = _get_sft_entry_ptr(fd);
        if (entry_ptr == 0)
        {
          /* The fd has already been validated, so reaching here means
             something is wrong with _get_sft_entry_ptr. */
          return -1;
        }
        /* Offset 5 in the SFT contains the device info word.  */
        dev_info = _farpeekw(_dos_ds, entry_ptr + 5);
      }
      return (dev_info & _DEV_NO_INHERIT) ? FD_CLOEXEC : 0;
    }


    case F_SETFD:
    {
      unsigned int flag;
      unsigned long entry_ptr = 0; /* shut up -Wall */
      __dpmi_regs regs;


      va_start (ap, cmd);
      flag = va_arg(ap, int);
      va_end(ap);


      /* DOS only passes the first 20 handles to child programs.  In
         addition, handles 19 and 18 will be closed by the stub of the
         child program (if it is a DJGPP program).  */
      if (fd >= 18)
      {
        if (flag & FD_CLOEXEC)
          return 0;
        else
        {
          errno = ENOSYS;
          return -1;
        }
      }


      /* Determine if the documented interface will allow twiddling with
         the inherit bit. If not, fallback to the undocumented one.  */
      if (inherit_bit_visible == -1)
        inherit_bit_visible = inherit_bit_test(fd, dev_info);

      if (!inherit_bit_visible)
      {
        entry_ptr = _get_sft_entry_ptr(fd);
        if (entry_ptr == 0)
        {
          /* The fd has already been validated, so reaching here means
             something is wrong with _get_sft_entry_ptr. */
          return -1;
        }


        dev_info = _farpeekw(_dos_ds, entry_ptr + 5);
      }


      if (flag & FD_CLOEXEC)
        dev_info |= _DEV_NO_INHERIT;
      else
        dev_info &= ~(_DEV_NO_INHERIT);


      if (inherit_bit_visible)
      {
        regs.x.ax = 0x4401;
        regs.x.bx = fd;
        regs.x.dx = dev_info;
        __dpmi_int(0x21, &regs);
      }
      else
        _farpokew(_dos_ds, entry_ptr + 5, dev_info);


      return 0;
    }


    case F_GETFL:
    {
      return 0;
    }


    case F_SETFL:
    {
      unsigned char new_mode_bits;


      va_start (ap, cmd);
      new_mode_bits = va_arg(ap,int);
      va_end(ap);


      /* Allow removal of O_NONBLOCK, since DJGPP doesn't support it
         anyway.  */
      return (new_mode_bits == 0) ? 0 : -1;
    }


    case F_GETLK:
    case F_SETLK:
    case F_SETLKW:
    {
      struct flock *lock_req = NULL; /* shut up -Wall */
      int ret = -1;
      off_t pos, cur_pos, lock_pos;
      off_t len;


      cur_pos = lseek(fd, 0, SEEK_CUR);
      va_start (ap, cmd);
      lock_req = va_arg(ap, struct flock *);
      va_end (ap);
      lock_pos = lseek (fd, lock_req->l_start, lock_req->l_whence);
      len = lock_req->l_len;


      /* If l_len is zero, then the lock is to be set from l_start
         until the end-of-file. */
      if (len == 0)
      {
        len = filelength(fd) - cur_pos;
        /* This should probably be an error.  */
        if (len <= 0)
          len = 1;
      }


      lseek (fd, cur_pos, SEEK_SET);


      /* If l_len is positive, the area to lock is from l_start
         to l_start + l_len - 1. If l_len is negative, the area to lock is
         from l_start + len to l_start - 1.  */
      if (len > 0)
      {
        pos = lock_pos;
      }
      else
      {
        pos = lock_pos + len;
        len = -lock_req->l_len;
      }


      /* DOS/Windows only support read locks on a per-file basis,
         so any attempted use of a read lock is an error,
         UNLESS all of these conditions are true, which makes the
         request into a per-file lock equivalent to F_WRLCK:

             lock_req->l_whence = SEEK_SET
             lock_req->l_start == 0
             lock_req->l_len == 0
      */
      if ((lock_req->l_type == F_RDLCK)   &&
          (lock_req->l_whence != SEEK_SET ||
      	   lock_req->l_start  != 0        ||
      	   lock_req->l_len    != 0))
      {
        errno = ENOSYS;
        return -1;
      }

      if (lock_req->l_type == F_UNLCK)
      {
        ret = _dos_unlock(fd, pos, len);
      }
      else if ((lock_req->l_type == F_WRLCK) || (lock_req->l_type == F_RDLCK))
      {
        ret = _dos_lock(fd, pos, len);
        if (cmd == F_GETLK)
        {
          if (ret == 0)
          {
            _dos_unlock(fd, pos, len);
            /* If no lock is found that would prevent a lock from
               being created, the lock type is set to F_UNLCK.  */
            lock_req->l_type = F_UNLCK;
          }
          else
          {
            /* If a lock is found then l_whence, l_start, and l_len
               should point to the area covered by the lock. But the
               file locking interface doesn't report where the
               existing lock is, so nothing more can be done.  */
            ;
          }
        }


        /* If F_SETLKW is set, wait for the lock to be released.  */
        if (cmd == F_SETLKW && ret < 0)
          while ((ret = _dos_lock(fd, pos, len)) < 0)
            __dpmi_yield();
      }
      if (ret < 0)
        errno = ENOSYS;


      return ret;
    }
  }


  /* In case fcntl is called with an unrecognized command.  */
  errno = ENOSYS;
  return -1;
}

--=====================_55779254==_
Content-Type: text/plain; charset="us-ascii"
Content-Disposition: attachment; filename="tfcntl.c"

#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main() {
#if defined(F_SETLK) && defined(F_SETLKW)
     struct flock flock;
     int retval, fd;
     fd = open("tfcntl.c", O_RDONLY);
     flock.l_type = F_RDLCK;
     flock.l_whence = SEEK_SET;
     flock.l_start = flock.l_len = 0;

     retval = fcntl(fd, F_SETLK, &flock);
     printf("F_SETLK/F_RDLCK:retval=%d\n", retval);
     if (retval < 0) exit(2);

     retval = fcntl(fd, F_GETLK, &flock);
     printf("F_GETLK:retval=%d\n", retval);

     flock.l_type = F_UNLCK;
     retval = fcntl(fd, F_SETLK, &flock);
     printf("F_SETLK/F_UNLCK:retval=%d\n", retval);
     if (retval < 0) exit(3);

     retval = fcntl(fd, F_GETFD);
     printf("F_GETFD:retval=%04x\n", retval);

     retval = fcntl(fd, F_SETFL, O_BINARY);
     printf("F_SETFL:retval=%04x\n", retval);

     retval = fcntl(fd, F_GETFL);
     printf("F_GETFL:retval=%04x\n", retval);

     close(fd);
     if (retval < 0) exit(4);
     exit(0);
#else
     exit(99);
#endif
}

--=====================_55779254==_
Content-Type: text/plain; charset="us-ascii"; format=flowed

---------------------------------------------------------
Peter J. Farley III (pjfarley AT dorsai DOT org OR
                      pjfarley AT banet DOT net)
--=====================_55779254==_--

- Raw text -


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