Back to index

glibc  2.9
fcntl.c
Go to the documentation of this file.
00001 /* Copyright (C) 1992-1997,1999,2000,2002,2007 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 <hurd.h>
00022 #include <hurd/fd.h>
00023 #include <stdarg.h>
00024 #include <sys/file.h>              /* XXX for LOCK_* */
00025 
00026 /* Perform file control operations on FD.  */
00027 int
00028 __libc_fcntl (int fd, int cmd, ...)
00029 {
00030   va_list ap;
00031   struct hurd_fd *d;
00032   int result;
00033 
00034   d = _hurd_fd_get (fd);
00035 
00036   if (d == NULL)
00037     return __hurd_fail (EBADF);
00038 
00039   va_start (ap, cmd);
00040 
00041   switch (cmd)
00042     {
00043       error_t err;
00044 
00045     default:                /* Bad command.  */
00046       errno = EINVAL;
00047       result = -1;
00048       break;
00049 
00050       /* First the descriptor-based commands, which do no RPCs.  */
00051 
00052     case F_DUPFD:           /* Duplicate the file descriptor.  */
00053     case F_DUPFD_CLOEXEC:
00054       {
00055        struct hurd_fd *new;
00056        io_t port, ctty;
00057        struct hurd_userlink ulink, ctty_ulink;
00058        int flags;
00059 
00060        HURD_CRITICAL_BEGIN;
00061 
00062        /* Extract the ports and flags from the file descriptor.  */
00063        __spin_lock (&d->port.lock);
00064        flags = d->flags;
00065        ctty = _hurd_port_get (&d->ctty, &ctty_ulink);
00066        port = _hurd_port_locked_get (&d->port, &ulink); /* Unlocks D.  */
00067 
00068        if (cmd == F_DUPFD_CLOEXEC)
00069          flags |= FD_CLOEXEC;
00070        else
00071          /* Duplication clears the FD_CLOEXEC flag.  */
00072          flags &= ~FD_CLOEXEC;
00073 
00074        /* Get a new file descriptor.  The third argument to __fcntl is the
00075           minimum file descriptor number for it.  */
00076        new = _hurd_alloc_fd (&result, va_arg (ap, int));
00077        if (new == NULL)
00078          /* _hurd_alloc_fd has set errno.  */
00079          result = -1;
00080        else
00081          {
00082            /* Give the ports each a user ref for the new descriptor.  */
00083            __mach_port_mod_refs (__mach_task_self (), port,
00084                               MACH_PORT_RIGHT_SEND, 1);
00085            if (ctty != MACH_PORT_NULL)
00086              __mach_port_mod_refs (__mach_task_self (), ctty,
00087                                 MACH_PORT_RIGHT_SEND, 1);
00088 
00089            /* Install the ports and flags in the new descriptor.  */
00090            if (ctty != MACH_PORT_NULL)
00091              _hurd_port_set (&new->ctty, ctty);
00092            new->flags = flags;
00093            _hurd_port_locked_set (&new->port, port); /* Unlocks NEW.  */
00094          }
00095 
00096        HURD_CRITICAL_END;
00097 
00098        _hurd_port_free (&d->port, &ulink, port);
00099        if (ctty != MACH_PORT_NULL)
00100          _hurd_port_free (&d->ctty, &ctty_ulink, port);
00101 
00102        break;
00103       }
00104 
00105       /* Set RESULT by evaluating EXPR with the descriptor locked.
00106         Check for an empty descriptor and return EBADF.  */
00107 #define LOCKED(expr)                                                 \
00108       HURD_CRITICAL_BEGIN;                                           \
00109       __spin_lock (&d->port.lock);                                   \
00110       if (d->port.port == MACH_PORT_NULL)                            \
00111        result = __hurd_fail (EBADF);                                        \
00112       else                                                           \
00113        result = (expr);                                              \
00114       __spin_unlock (&d->port.lock);                                        \
00115       HURD_CRITICAL_END;
00116 
00117     case F_GETFD:           /* Get descriptor flags.  */
00118       LOCKED (d->flags);
00119       break;
00120 
00121     case F_SETFD:           /* Set descriptor flags.  */
00122       LOCKED ((d->flags = va_arg (ap, int), 0));
00123       break;
00124 
00125 
00126       /* Now the real io operations, done by RPCs to io servers.  */
00127 
00128     case F_GETLK:
00129     case F_SETLK:
00130     case F_SETLKW:
00131       {
00132        /* XXX
00133           We need new RPCs to support POSIX.1 fcntl file locking!!
00134           For the time being we support the whole-file case only,
00135           with all kinds of WRONG WRONG WRONG semantics,
00136           by using flock.  This is definitely the Wrong Thing,
00137           but it might be better than nothing (?).  */
00138        struct flock *fl = va_arg (ap, struct flock *);
00139        va_end (ap);
00140        switch (cmd)
00141          {
00142          case F_GETLK:
00143            errno = ENOSYS;
00144            return -1;
00145          case F_SETLK:
00146            cmd = LOCK_NB;
00147            break;
00148          default:
00149            cmd = 0;
00150            break;
00151          }
00152        switch (fl->l_type)
00153          {
00154          case F_RDLCK: cmd |= LOCK_SH; break;
00155          case F_WRLCK: cmd |= LOCK_EX; break;
00156          case F_UNLCK: cmd |= LOCK_UN; break;
00157          default:
00158            errno = EINVAL;
00159            return -1;
00160          }
00161        switch (fl->l_whence)
00162          {
00163          case SEEK_SET:
00164            if (fl->l_start == 0 && fl->l_len == 0) /* Whole file request.  */
00165              break;
00166            /* It seems to be common for applications to lock the first
00167               byte of the file when they are really doing whole-file locking.
00168               So, since it's so wrong already, might as well do that too.  */
00169            if (fl->l_start == 0 && fl->l_len == 1)
00170              break;
00171            /* FALLTHROUGH */
00172          case SEEK_CUR:
00173          case SEEK_END:
00174            errno = ENOTSUP;
00175            return -1;
00176          default:
00177            errno = EINVAL;
00178            return -1;
00179          }
00180 
00181        return __flock (fd, cmd);
00182       }
00183 
00184     case F_GETFL:           /* Get per-open flags.  */
00185       if (err = HURD_FD_PORT_USE (d, __io_get_openmodes (port, &result)))
00186        result = __hurd_dfail (fd, err);
00187       break;
00188 
00189     case F_SETFL:           /* Set per-open flags.  */
00190       err = HURD_FD_PORT_USE (d, __io_set_all_openmodes (port,
00191                                                   va_arg (ap, int)));
00192       result = err ? __hurd_dfail (fd, err) : 0;
00193       break;
00194 
00195     case F_GETOWN:          /* Get owner.  */
00196       if (err = HURD_FD_PORT_USE (d, __io_get_owner (port, &result)))
00197        result = __hurd_dfail (fd, err);
00198       break;
00199 
00200     case F_SETOWN:          /* Set owner.  */
00201       err = HURD_FD_PORT_USE (d, __io_mod_owner (port, va_arg (ap, pid_t)));
00202       result = err ? __hurd_dfail (fd, err) : 0;
00203       break;
00204     }
00205 
00206   va_end (ap);
00207 
00208   return result;
00209 }
00210 libc_hidden_def (__libc_fcntl)
00211 weak_alias (__libc_fcntl, __fcntl)
00212 libc_hidden_weak (__fcntl)
00213 weak_alias (__libc_fcntl, fcntl)