Back to index

glibc  2.9
dup2.c
Go to the documentation of this file.
00001 /* Copyright (C) 1991, 92, 93, 94, 95, 97, 2002 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003 
00004    The GNU C Library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Lesser General Public
00006    License as published by the Free Software Foundation; either
00007    version 2.1 of the License, or (at your option) any later version.
00008 
00009    The GNU C Library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Lesser General Public License for more details.
00013 
00014    You should have received a copy of the GNU Lesser General Public
00015    License along with the GNU C Library; if not, write to the Free
00016    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00017    02111-1307 USA.  */
00018 
00019 #include <errno.h>
00020 #include <fcntl.h>
00021 #include <unistd.h>
00022 #include <hurd.h>
00023 #include <hurd/fd.h>
00024 
00025 /* Duplicate FD to FD2, closing the old FD2 and making FD2 be
00026    open on the same file as FD is.  Return FD2 or -1.  */
00027 int
00028 __dup2 (fd, fd2)
00029      int fd;
00030      int fd2;
00031 {
00032   struct hurd_fd *d;
00033 
00034   /* Extract the ports and flags from FD.  */
00035   d = _hurd_fd_get (fd);
00036   if (d == NULL)
00037     {
00038       errno = EBADF;
00039       return -1;
00040     }
00041 
00042   HURD_CRITICAL_BEGIN;
00043 
00044   __spin_lock (&d->port.lock);
00045   if (d->port.port == MACH_PORT_NULL)
00046     {
00047       __spin_unlock (&d->port.lock);
00048       errno = EBADF;
00049       fd2 = -1;
00050     }
00051   else if (fd2 == fd)
00052     /* FD is valid and FD2 is already the same; just return it.  */
00053     __spin_unlock (&d->port.lock);
00054   else
00055     {
00056       struct hurd_userlink ulink, ctty_ulink;
00057       int flags = d->flags;
00058       io_t ctty = _hurd_port_get (&d->ctty, &ctty_ulink);
00059       io_t port = _hurd_port_locked_get (&d->port, &ulink); /* Unlocks D.  */
00060 
00061       if (fd2 < 0)
00062        {
00063          errno = EBADF;
00064          fd2 = -1;
00065        }
00066       else
00067        {
00068          /* Get a hold of the destination descriptor.  */
00069          struct hurd_fd *d2;
00070 
00071          if (fd2 >= _hurd_dtablesize)
00072            {
00073              /* The table is not large enough to hold the destination
00074                descriptor.  Enlarge it as necessary to allocate this
00075                descriptor.  */
00076              __mutex_unlock (&_hurd_dtable_lock);
00077              /* We still hold FD1's lock, but this is safe because
00078                _hurd_alloc_fd will only examine the cells starting
00079                at FD2.  */
00080              d2 = _hurd_alloc_fd (NULL, fd2);
00081              if (d2)
00082               __spin_unlock (&d2->port.lock);
00083              __mutex_lock (&_hurd_dtable_lock);
00084            }
00085          else
00086            {
00087              d2 = _hurd_dtable[fd2];
00088              if (d2 == NULL)
00089               {
00090                 /* Must allocate a new one.  We don't initialize the port
00091                    cells with this call so that if it fails (out of
00092                    memory), we will not have already added user
00093                    references for the ports, which we would then have to
00094                    deallocate.  */
00095                 d2 = _hurd_dtable[fd2] = _hurd_new_fd (MACH_PORT_NULL,
00096                                                   MACH_PORT_NULL);
00097               }
00098            }
00099 
00100          if (d2 == NULL)
00101            {
00102              fd2 = -1;
00103              if (errno == EINVAL)
00104               errno = EBADF;       /* POSIX.1-1990 6.2.1.2 ll 54-55.  */
00105            }
00106          else
00107            {
00108              /* Give the ports each a user ref for the new descriptor.  */
00109              __mach_port_mod_refs (__mach_task_self (), port,
00110                                 MACH_PORT_RIGHT_SEND, 1);
00111              if (ctty != MACH_PORT_NULL)
00112               __mach_port_mod_refs (__mach_task_self (), ctty,
00113                                   MACH_PORT_RIGHT_SEND, 1);
00114 
00115              /* Install the ports and flags in the new descriptor slot.  */
00116              __spin_lock (&d2->port.lock);
00117              d2->flags = flags & ~FD_CLOEXEC; /* Dup clears FD_CLOEXEC. */
00118              _hurd_port_set (&d2->ctty, ctty);
00119              _hurd_port_locked_set (&d2->port, port); /* Unlocks D2.  */
00120            }
00121        }
00122       __mutex_unlock (&_hurd_dtable_lock);
00123 
00124       _hurd_port_free (&d->port, &ulink, port);
00125       if (ctty != MACH_PORT_NULL)
00126        _hurd_port_free (&d->ctty, &ctty_ulink, port);
00127     }
00128 
00129   HURD_CRITICAL_END;
00130 
00131   return fd2;
00132 }
00133 libc_hidden_def (__dup2)
00134 weak_alias (__dup2, dup2)