/* close1.c (emx+gcc) */

/* Test fix to close_handle() in emx.dll (revision index 36).  Up to
   revision index 35, close_handle() leaves a dangling reference in
   files[handle]. */

/* Syntax for annotations: handle(files_index:ref_count). */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>


static void xclose (int fd)
{
  int ht;

  if (close (fd) != 0)
    {
      perror ("close()");
      exit (2);
    }
  if (ioctl (fd, FGETHTYPE, &ht) == 0)
    {
      fprintf (stderr, "Handle not closed\n");
      exit (2);
    }
  if (errno != EBADF)
    {
      fprintf (stderr, "Wrong errno (%d)\n", errno);
      exit (2);
    }
}


static void xhtype (int fd, int x)
{
  int ht;

  if (ioctl (fd, FGETHTYPE, &ht) != 0)
    {
      perror ("ioctl()");
      exit (2);
    }
  if (ht != x)
    {
      fprintf (stderr, "Handle type is %d, not %d\n", ht, x);
      exit (2);
    }
}


static void xsocktest (int fd)
{
  int n;

  if (ioctl (fd, SIOCATMARK, &n) != 0)
    {
      perror ("ioctl()");
      exit (2);
    }
}


static int xsocket (void)
{
  int fd;

  fd = socket (AF_INET, SOCK_STREAM, 0);
  if (fd == -1)
    {
      perror ("socket()");
      exit (2);
    }
  xhtype (fd, HT_SOCKET);
  xsocktest (fd);
  return fd;
}


static int xnull (void)
{
  int fd;

  fd = open ("nul", O_RDONLY);
  if (fd == -1)
    {
      perror ("open()");
      exit (2);
    }
  xhtype (fd, HT_DEV_NUL);
  return fd;
}


static int xdup (int fd)
{
  int fd2;

  fd2 = dup (fd);
  if (fd2 == -1)
    {
      perror ("dup()");
      exit (2);
    }
  return fd2;
}
      

int main (void)
{
  int fd0, fd1, fd2, fd3, fd4, fd5;

  /* First find the first slot which is used for both normal handles
     and for socket handles. */

  xsocket ();                   /* Initialize TCP/IP */
  fd0 = xnull ();               /* -> 6(4:1) */
  xclose (fd0);                 /* 6(4:1) -> 6(4:0) */

  do
    {
      fd1 = xsocket ();         /* -> 5(4:1), -> 6(5:1) */
    } while (fd1 != fd0);
  xclose (fd1);                 /* 6(5:1) -> 6(5:0) */

  /* Create 3 handles referring to the same socket. */

  fd2 = xsocket ();             /* 6(5:0) -> 6(5:1) */
  fd3 = xdup (fd2);             /* -> 7(5:2) */
  fd4 = xdup (fd2);             /* -> 8(5:3) */

  /* Close one of the 3 handles, to be reused later.  Due to the bug,
     this leaves the closed handle pointing to files[5]. */

  xclose (fd2);                 /* 6(5:3) -> 6(5:2) */

  /* This will decrement the reference count of files[5] through
     handle 6 as __open() calls close_handle() for the new handle! */

  fd5 = xnull ();               /* 6(5:2) -> 6(5:1) -> 6(6:1) */

  /* Closing fd3 will erroneously close the socket which is still
     referenced by fd4! */

  xsocktest (fd4);
  xclose (fd3);                 /* 7(5:1) -> 7(5:0) */
  xsocktest (fd4);              /* BOMB */

  xclose (fd4);

  return 0;
}
