Blame sysdeps/mach/hurd/dup3.c

Packit 6c4009
/* Duplicate a file descriptor to a given number, with flags.  Hurd version.
Packit 6c4009
   Copyright (C) 1991-2018 Free Software Foundation, Inc.
Packit 6c4009
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; see the file COPYING.LIB.  If
Packit 6c4009
   not, see <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <fcntl.h>
Packit 6c4009
#include <unistd.h>
Packit 6c4009
#include <hurd.h>
Packit 6c4009
#include <hurd/fd.h>
Packit 6c4009
Packit 6c4009
/* Duplicate FD to FD2, closing the old FD2 and making FD2 be
Packit 6c4009
   open on the same file as FD is, and setting FD2's flags according to FLAGS.
Packit 6c4009
   Return FD2 or -1.  */
Packit 6c4009
int
Packit 6c4009
__dup3 (int fd, int fd2, int flags)
Packit 6c4009
{
Packit 6c4009
  struct hurd_fd *d;
Packit 6c4009
Packit 6c4009
  /* Both passing flags different from O_CLOEXEC and FD2 being the same as FD
Packit 6c4009
     are invalid.  */
Packit 6c4009
  if ((flags & ~O_CLOEXEC
Packit 6c4009
       || fd2 == fd)
Packit 6c4009
      /* ... with the exception in case that dup2 behavior is requested: if FD
Packit 6c4009
	 is valid and FD2 is already the same then just return it.  */
Packit 6c4009
      && ! (flags == -1
Packit 6c4009
	    && fd2 == fd))
Packit 6c4009
    return __hurd_fail (EINVAL);
Packit 6c4009
Packit 6c4009
  /* Extract the ports and flags from FD.  */
Packit 6c4009
  d = _hurd_fd_get (fd);
Packit 6c4009
  if (d == NULL)
Packit 6c4009
    return __hurd_fail (EBADF);
Packit 6c4009
Packit 6c4009
  HURD_CRITICAL_BEGIN;
Packit 6c4009
Packit 6c4009
  __spin_lock (&d->port.lock);
Packit 6c4009
  if (d->port.port == MACH_PORT_NULL)
Packit 6c4009
    {
Packit 6c4009
      __spin_unlock (&d->port.lock);
Packit 6c4009
      fd2 = __hurd_fail (EBADF);
Packit 6c4009
    }
Packit 6c4009
  else if (fd2 == fd)
Packit 6c4009
    __spin_unlock (&d->port.lock);
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      struct hurd_userlink ulink, ctty_ulink;
Packit 6c4009
      int d_flags = d->flags;
Packit 6c4009
      io_t ctty = _hurd_port_get (&d->ctty, &ctty_ulink);
Packit 6c4009
      io_t port = _hurd_port_locked_get (&d->port, &ulink); /* Unlocks D.  */
Packit 6c4009
Packit 6c4009
      if (fd2 < 0)
Packit 6c4009
	fd2 = __hurd_fail (EBADF);
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  /* Get a hold of the destination descriptor.  */
Packit 6c4009
	  struct hurd_fd *d2;
Packit 6c4009
Packit 6c4009
	  __mutex_lock (&_hurd_dtable_lock);
Packit 6c4009
Packit 6c4009
	  if (fd2 >= _hurd_dtablesize)
Packit 6c4009
	    {
Packit 6c4009
	      /* The table is not large enough to hold the destination
Packit 6c4009
		 descriptor.  Enlarge it as necessary to allocate this
Packit 6c4009
		 descriptor.  */
Packit 6c4009
	      __mutex_unlock (&_hurd_dtable_lock);
Packit 6c4009
	      d2 = _hurd_alloc_fd (NULL, fd2);
Packit 6c4009
	      if (d2)
Packit 6c4009
		__spin_unlock (&d2->port.lock);
Packit 6c4009
	      __mutex_lock (&_hurd_dtable_lock);
Packit 6c4009
	    }
Packit 6c4009
	  else
Packit 6c4009
	    {
Packit 6c4009
	      d2 = _hurd_dtable[fd2];
Packit 6c4009
	      if (d2 == NULL)
Packit 6c4009
		{
Packit 6c4009
		  /* Must allocate a new one.  We don't initialize the port
Packit 6c4009
		     cells with this call so that if it fails (out of
Packit 6c4009
		     memory), we will not have already added user
Packit 6c4009
		     references for the ports, which we would then have to
Packit 6c4009
		     deallocate.  */
Packit 6c4009
		  d2 = _hurd_dtable[fd2] = _hurd_new_fd (MACH_PORT_NULL,
Packit 6c4009
							 MACH_PORT_NULL);
Packit 6c4009
		}
Packit 6c4009
	    }
Packit 6c4009
	  __mutex_unlock (&_hurd_dtable_lock);
Packit 6c4009
Packit 6c4009
	  if (d2 == NULL)
Packit 6c4009
	    {
Packit 6c4009
	      fd2 = -1;
Packit 6c4009
	      if (errno == EINVAL)
Packit 6c4009
		errno = EBADF;	/* POSIX.1-1990 6.2.1.2 ll 54-55.  */
Packit 6c4009
	    }
Packit 6c4009
	  else
Packit 6c4009
	    {
Packit 6c4009
	      /* Give the ports each a user ref for the new descriptor.  */
Packit 6c4009
	      __mach_port_mod_refs (__mach_task_self (), port,
Packit 6c4009
				    MACH_PORT_RIGHT_SEND, 1);
Packit 6c4009
	      if (ctty != MACH_PORT_NULL)
Packit 6c4009
		__mach_port_mod_refs (__mach_task_self (), ctty,
Packit 6c4009
				      MACH_PORT_RIGHT_SEND, 1);
Packit 6c4009
Packit 6c4009
	      /* Install the ports and flags in the new descriptor slot.  */
Packit 6c4009
	      __spin_lock (&d2->port.lock);
Packit 6c4009
	      if (flags & O_CLOEXEC)
Packit 6c4009
		d2->flags = d_flags | FD_CLOEXEC;
Packit 6c4009
	      else
Packit 6c4009
		/* dup clears FD_CLOEXEC.  */
Packit 6c4009
		d2->flags = d_flags & ~FD_CLOEXEC;
Packit 6c4009
	      _hurd_port_set (&d2->ctty, ctty);
Packit 6c4009
	      _hurd_port_locked_set (&d2->port, port); /* Unlocks D2.  */
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      _hurd_port_free (&d->port, &ulink, port);
Packit 6c4009
      if (ctty != MACH_PORT_NULL)
Packit 6c4009
	_hurd_port_free (&d->ctty, &ctty_ulink, port);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  HURD_CRITICAL_END;
Packit 6c4009
Packit 6c4009
  return fd2;
Packit 6c4009
}
Packit 6c4009
libc_hidden_def (__dup3)
Packit 6c4009
weak_alias (__dup3, dup3)