Mail Archives: djgpp-workers/1999/06/01/02:28:48
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, ®s);
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, ®s);
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, ®s);
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, ®s);
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 -