delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/1999/06/01/02:28:48

Date: Tue, 1 Jun 1999 09:26:23 +0300 (IDT)
From: Eli Zaretskii <eliz AT is DOT elta DOT co DOT il>
X-Sender: eliz AT is
To: "Mark E." <snowball3 AT bigfoot DOT com>
cc: djgpp-workers AT delorie DOT com
Subject: Re: enhancements to fcntl.c
In-Reply-To: <199905311824.SAA72470@out2.ibm.net>
Message-ID: <Pine.SUN.3.91.990601092558.19912F-100000@is>
MIME-Version: 1.0
Reply-To: djgpp-workers AT delorie DOT com
X-Mailing-List: djgpp-workers AT delorie DOT com
X-Unsubscribes-To: listserv AT delorie DOT com

I wrote two short test programs and played with them a bit.  The
programs are attached below, for those who are interested.  They were
run on DOS 5.0, Windows 95 v4.00.950r7 and NT v4.00SP3.

Conclusions:

  1. Using the O_NOINHERIT bit only matters for the first 20 handles;
     handles beyond the first 20 are *never* inherited.

  2. Actually, we cannot inherit more than 18 handles, since the stub
     of the child (if the child was compiled with v2.02 and later)
     will forcibly close handles 19 and 18: one handle to allow the
     stub to open the executable and read the COFF info, and another
     one for the DPMI host, in case it needs it to open a swap file
     (on DOS).

  3. Therefore, if the application calls `fcntl' with F_SETFD for
     handles beyond 17, the only thing we can do is to fail the call,
     unless they want it non-inheritable, in which case we should
     return a success.  Reopening the file, as I suggested earlier in
     this thread, won't work (of course), since you don't have the
     file's name to reopen it...

     Conversely, a call with F_SETFD for handles below 18 should
     always fail if the caller requests to make it non-inheritable,
     unless the no-inherit bit is already set in the SFT.

  4. 214400 doesn't bring the inherit bit on plain DOS as well, so the
     only way to go is via the SFT; let's hope some future version of
     Windows won't break this...  Handles 18 and above should always
     return as close-on-exec, since we cannot inherit them.

Oh, and btw, I think that "regs.x.es * 16" is unsafe, since the SFT
may reside in high memory (if they have DOS=HIGH in CONFIG.SYS), and
then this expression might overflow.

--------------------------------------------------------------------
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <dpmi.h>
#include <go32.h>
#include <sys/movedata.h>
#include <sys/farptr.h>
#include <libc/dosio.h>
#include <errno.h>
#include <io.h>
#include <dos.h>
#include <process.h>

static int
get_sft_entry (int fd, unsigned char sft_entry[])
{
  __dpmi_regs regs;
  unsigned char index;
  unsigned long es, di;

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

  if (regs.x.flags & 1)
    {
      printf ("GetJFT: error code %d\n", regs.h.al);
      return -1;
    }
  else
    {
      /* Get the SFT entry number for this handle.  */
      es = regs.x.es;
      di = regs.x.di;
      index = _farpeekb (_dos_ds, es * 16 + di);
      regs.x.ax = 0x1216;
      regs.x.bx = index;
      __dpmi_int (0x2f, &regs);
      if (regs.x.flags & 1)
	{
	  printf ("GetSFT: error 0x%x\n", regs.x.ax);
	  return -1;
	}
      else
	{
	  es = regs.x.es;
	  di = regs.x.di;
	  dosmemget (es * 16 + di, 7, sft_entry);
	  return 0;
	}
    }
}

static int
dev_word (int fd)
{
  __dpmi_regs regs;

  regs.x.ax = 0x4400;
  regs.x.bx = fd;
  regs.x.dx = 0;
  __dpmi_int(0x21, &regs);
  if (regs.x.flags & 1)
    {
      printf ("IOCTL func 0: error code 0x%x\n", regs.x.ax);
      return -1;
    }
  else
    return regs.x.dx;
}

int _open (const char *filename, int oflag)
{
  __dpmi_regs r;
  int use_lfn = _USE_LFN;

  if (filename == 0)
  {
    errno = EINVAL;
    return -1;
  }

  _put_path(filename);
  if(use_lfn)
    r.x.ax = 0x716c;
  else
    r.x.ax = 0x6c00;
  r.x.bx = oflag & 0xffff;
  r.x.dx = 0x11;			/* Open or create */
  r.x.si = __tb & 15;
  r.x.cx = 0;
  r.x.ds = __tb >> 4;
  __dpmi_int(0x21, &r);
  if(r.x.flags & 1)
  {
    errno = __doserr_to_errno(r.x.ax);
    return -1;
  }
  __file_handle_set(r.x.ax, O_BINARY);
  return r.x.ax;
}

int main (int argc, char *argv[])
{
  int fd = open (argv[0], O_RDONLY | O_BINARY | O_NOINHERIT);
  int fd1;
  int status;

  /* Try dup() first.  */
  while ((fd1 = dup (fd)) != -1)
    {
      unsigned char sft_entry[7];
      int dev_info;

      if (get_sft_entry (fd1, sft_entry) != -1
	  && (dev_info = dev_word (fd1)) != -1)
	printf ("%d:  SFT: 0x%x   IOCTL: 0x%x\n", fd1,
		*(unsigned short *)&sft_entry[5], dev_info & 0xffff);
      else
	printf ("%d:  Failure!\n", fd1);
    }

  close (21);

  if ((status = spawnl (P_WAIT, "tfd.exe", "tfd.exe", NULL)) != 0)
    fprintf (stderr, "Spawn: %d\n", status);

  for (fd1 = 254; fd1 > fd; fd1--)
    close (fd1);

  /* Now try the same with open().  */
  while ((fd1 = open (argv[0], O_RDONLY | O_BINARY | O_NOINHERIT)) != -1)
    {
      unsigned char sft_entry[7];
      int dev_info;

      if (get_sft_entry (fd1, sft_entry) != -1
	  && (dev_info = dev_word (fd1)) != -1)
	printf ("%d:  SFT: 0x%x   IOCTL: 0x%x\n", fd1,
		*(unsigned short *)&sft_entry[5], dev_info & 0xffff);
      else
	printf ("%d:  Failure!\n", fd1);
    }

  close (21);

  if ((status = spawnl (P_WAIT, "tfd.exe", "tfd.exe", NULL)) != 0)
    fprintf (stderr, "Spawn: %d\n", status);
  return 0;
}

---------------- tfd.c -------------------------------------------
#include <dpmi.h>
#include <stdio.h>

static int
dev_word (int fd)
{
  __dpmi_regs regs;

  regs.x.ax = 0x4400;
  regs.x.bx = fd;
  regs.x.dx = 0;
  __dpmi_int(0x21, &regs);
  if (regs.x.flags & 1)
    {
      return -1;
    }
  else
    return regs.x.dx;
}


int main (void)
{
  int i;

  for (i = 0; i < 255; i++)
    {
      int dev_info = dev_word (i);

      if (dev_info != -1)
	printf ("%d: inherited, info word: 0x%x\n", i, dev_info & 0xffff);
    }

  return 0;
}

- Raw text -


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