/* block.c

   Test to see whether HAVE_UNBLOCKED_WRITES should be set to 0 or 1
   on this system.  This tests whether a write to a pseudo terminal
   will block even if O_NDELAY has been set.

   This code is not particularly portable.

   Copyright (c) 1992 Ian Lance Taylor.  */

#include <stdio.h>
#include <signal.h>
#include <errno.h>

extern int errno;

/* On some systems you will have to replace <fcntl.h> with
   <sys/file.h>.  */
#include <fcntl.h>

/* Get definitions for both O_NONBLOCK and O_NDELAY.  */

#ifndef O_NDELAY
#ifdef FNDELAY
#define O_NDELAY FNDELAY
#else /* ! defined (FNDELAY) */
#define O_NDELAY 0
#endif /* ! defined (FNDELAY) */
#endif /* ! defined (O_NDELAY) */

#ifndef O_NONBLOCK
#ifdef FNBLOCK
#define O_NONBLOCK FNBLOCK
#else /* ! defined (FNBLOCK) */
#define O_NONBLOCK 0
#endif /* ! defined (FNBLOCK) */
#endif /* ! defined (O_NONBLOCK) */

#if O_NDELAY == 0 && O_NONBLOCK == 0
 #error No way to do nonblocking I/O
#endif

/* Get definitions for both EAGAIN and EWOULDBLOCK.  */

#ifndef EAGAIN
#ifndef EWOULDBLOCK
#define EAGAIN (-1)
#define EWOULDBLOCK (-1)
#else /* defined (EWOULDBLOCK) */
#define EAGAIN EWOULDBLOCK
#endif /* defined (EWOULDBLOCK) */
#else /* defined (EAGAIN) */
#ifndef EWOULDBLOCK
#define EWOULDBLOCK EAGAIN
#endif /* ! defined (EWOULDBLOCK) */
#endif /* defined (EAGAIN) */
static char abbig[100];

static void
usalarm (isig)
     int isig;
{
  printf ("#define HAVE_UNBLOCKED_WRITES 0\n");
  exit (0);
}

int
main (argc, argv)
     int argc;
     char **argv;
{
  char *zpty;
  char abpty1[sizeof "/dev/ptyp0"];
  char *zptyname;
  int omaster, oslave;
  int cwrote;

  omaster = -1;
  oslave = -1;
  zptyname = abpty1;

  for (zpty = "pqrs"; *zpty != '\0'; ++zpty)
    {
      int ipty;

      for (ipty = 0; ipty < 16; ipty++)
	{
	  int om, os;
  
	  sprintf (zptyname, "/dev/pty%c%c", *zpty,
		   "0123456789abcdef"[ipty]);
	  om = open (zptyname, O_RDWR);
	  if (om < 0)
	    continue;
	  zptyname[5] = 't';
	  os = open (zptyname, O_RDWR);
	  if (os < 0)
	    {
	      (void) close (om);
	      continue;
	    }

	  omaster = om;
	  oslave = os;
	  break;
	}
    }

  if (omaster == -1)
    {
      fprintf (stderr, "No pseudo-terminals available\n");
      exit (1);
    }

  if (fcntl (oslave, F_SETFL, O_NDELAY | O_NONBLOCK) < 0)
    {
      /* If it didn't like O_NDELAY | O_NONBLOCK, maybe it will like
	 just plain O_NONBLOCK.  */
      if (fcntl (oslave, F_SETFL, O_NONBLOCK) < 0)
	{
	  perror ("fcntl");
	  exit (1);
	}
    }

  signal (SIGALRM, usalarm);
  alarm (60);

  printf ("Checking for unblocked writes; this will take a minute.\n");

  while (1)
    {
      cwrote = write (oslave, abbig, sizeof abbig);
      if (cwrote < 0)
	{
	  if (errno == EAGAIN || errno == EWOULDBLOCK)
	    {
	      printf ("#define HAVE_UNBLOCKED_WRITES 1\n");
	      exit (0);
	    }
	  perror ("write");
	  exit (1);
	}
    }
}
