/* dup.c */

/* Test dup(), dup2(), and fcntl (F_DUPFD, ...). */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>

#define INVALID 55555
#define CLOSED  12
#define OTHER   13


int main (void)
{
  int fd;

  printf ("Expected output: 123456 -- done.\n");
  printf ("Actual output:   ");
  fflush (stdout);

  close (CLOSED);

  errno = 0;
  if (dup2 (1, INVALID) != -1)
    fprintf (stderr, "dup2 (1, INVALID) does not fail\n");
  else if (errno != EBADF)
    fprintf (stderr, "dup2 (1, INVALID) sets errno incorrectly: %s\n",
             strerror (errno));

  errno = 0;
  if (fcntl (1, F_DUPFD, INVALID) != -1)
    fprintf (stderr, "fcntl (1, F_DUPFD, INVALID) does not fail\n");
  else if (errno != EINVAL)
    fprintf (stderr,
             "fcntl (1, F_DUPFD, INVALID) sets errno incorrectly: %s\n",
             strerror (errno));

  fd = fcntl (1, F_DUPFD, OTHER);
  if (fd < 0)
    fprintf (stderr, "fcntl (1, F_DUPFD, OTHER) fails: %s\n",
             strerror (errno));
  else
    {
      write (fd, "1", 1);
      if (fd != OTHER)
        fprintf (stderr, "fcntl (1, F_DUPFD, OTHER) does not work\n");
      if (close (fd) != 0)
        fprintf (stderr, "close (%d) fails: %s\n", fd, strerror (errno));
    }

  fd = fcntl (1, F_DUPFD, 0);
  if (fd < 0)
    fprintf (stderr, "fcntl (1, F_DUPFD, 0) fails: %s\n", strerror (errno));
  else
    {
      write (fd, "2", 1);
      if (fd <= 2)
        fprintf (stderr, "fcntl (1, F_DUPFD, 0) does not work\n");
      if (close (fd) != 0)
        fprintf (stderr, "close (%d) fails: %s\n", fd, strerror (errno));
    }

  fd = dup2 (1, OTHER);
  if (fd < 0)
    fprintf (stderr, "dup2 (1, OTHER) fails: %s\n", strerror (errno));
  else
    {
      write (fd, "3", 1);
      if (fd != OTHER)
        fprintf (stderr, "dup2 (1, OTHER) does not work\n");
    }

  fd = dup2 (1, OTHER);
  if (fd < 0)
    fprintf (stderr, "dup2 (1, OTHER) fails: %s\n", strerror (errno));
  else
    {
      write (fd, "4", 1);
      if (fd != OTHER)
        fprintf (stderr, "dup2 (1, OTHER) does not work\n");
      if (close (fd) != 0)
        fprintf (stderr, "close (%d) fails: %s\n", fd, strerror (errno));
    }

  fd = dup (1);
  if (fd < 0)
    fprintf (stderr, "dup (1) fails: %s\n", strerror (errno));
  else
    {
      write (fd, "5", 1);
      if (fd <= 2)
        fprintf (stderr, "dup (1) does not work\n");
      if (close (fd) != 0)
        fprintf (stderr, "close (%d) fails: %s\n", fd, strerror (errno));
    }

  fd = dup2 (1, 1);
  if (fd < 0)
    fprintf (stderr, "dup2 (1, 1) fails: %s\n", strerror (errno));
  else
    {
      if (fd != 1)
        fprintf (stderr, "dup2 (1, 1) does not work\n");
    }

  write (1, "6", 1);

  fd = dup (INVALID);
  if (fd >= 0)
    fprintf (stderr, "dup (INVALID) does not fail\n");
  else if (errno != EBADF)
    fprintf (stderr, "dup (INVALID) sets errno incorrectly: %s\n",
             strerror (errno));

  fd = dup2 (INVALID, 3);
  if (fd >= 0)
    fprintf (stderr, "dup2 (INVALID, 3) does not fail\n");
  else if (errno != EBADF)
    fprintf (stderr, "dup2 (INVALID, 3) sets errno incorrectly: %s\n",
             strerror (errno));

  fd = dup2 (INVALID, INVALID);
  if (fd >= 0)
    fprintf (stderr, "dup2 (INVALID, INVALID) does not fail\n");
  else if (errno != EBADF)
    fprintf (stderr, "dup2 (INVALID, INVALID) sets errno incorrectly: %s\n",
             strerror (errno));

  fd = dup (CLOSED);
  if (fd >= 0)
    fprintf (stderr, "dup (CLOSED) does not fail\n");
  else if (errno != EBADF)
    fprintf (stderr, "dup (CLOSED) sets errno incorrectly: %s\n",
             strerror (errno));

  fd = dup2 (CLOSED, 3);
  if (fd >= 0)
    fprintf (stderr, "dup2 (CLOSED, 3) does not fail\n");
  else if (errno != EBADF)
    fprintf (stderr, "dup2 (CLOSED, 3) sets errno incorrectly: %s\n",
             strerror (errno));

  fd = dup2 (CLOSED, CLOSED);
  if (fd >= 0)
    fprintf (stderr, "dup2 (CLOSED, CLOSED) does not fail\n");
  else if (errno != EBADF)
    fprintf (stderr, "dup2 (CLOSED, CLOSED) sets errno incorrectly: %s\n",
             strerror (errno));

  printf (" -- done.\n");
  return 0;
}
