Blame sysdeps/mach/hurd/fcntl.c

Packit 6c4009
/* Copyright (C) 1992-2018 Free Software Foundation, Inc.
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; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <fcntl.h>
Packit 6c4009
#include <hurd.h>
Packit 6c4009
#include <hurd/fd.h>
Packit 6c4009
#include <stdarg.h>
Packit 6c4009
#include <sys/file.h>		/* XXX for LOCK_* */
Packit 6c4009
Packit 6c4009
/* Perform file control operations on FD.  */
Packit 6c4009
int
Packit 6c4009
__libc_fcntl (int fd, int cmd, ...)
Packit 6c4009
{
Packit 6c4009
  va_list ap;
Packit 6c4009
  struct hurd_fd *d;
Packit 6c4009
  int result;
Packit 6c4009
Packit 6c4009
  d = _hurd_fd_get (fd);
Packit 6c4009
Packit 6c4009
  if (d == NULL)
Packit 6c4009
    return __hurd_fail (EBADF);
Packit 6c4009
Packit 6c4009
  va_start (ap, cmd);
Packit 6c4009
Packit 6c4009
  switch (cmd)
Packit 6c4009
    {
Packit 6c4009
      error_t err;
Packit 6c4009
Packit 6c4009
    default:			/* Bad command.  */
Packit 6c4009
      errno = EINVAL;
Packit 6c4009
      result = -1;
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
      /* First the descriptor-based commands, which do no RPCs.  */
Packit 6c4009
Packit 6c4009
    case F_DUPFD:		/* Duplicate the file descriptor.  */
Packit 6c4009
    case F_DUPFD_CLOEXEC:
Packit 6c4009
      {
Packit 6c4009
	struct hurd_fd *new;
Packit 6c4009
	io_t port, ctty;
Packit 6c4009
	struct hurd_userlink ulink, ctty_ulink;
Packit 6c4009
	int flags;
Packit 6c4009
Packit 6c4009
	HURD_CRITICAL_BEGIN;
Packit 6c4009
Packit 6c4009
	/* Extract the ports and flags from the file descriptor.  */
Packit 6c4009
	__spin_lock (&d->port.lock);
Packit 6c4009
	flags = d->flags;
Packit 6c4009
	ctty = _hurd_port_get (&d->ctty, &ctty_ulink);
Packit 6c4009
	port = _hurd_port_locked_get (&d->port, &ulink); /* Unlocks D.  */
Packit 6c4009
Packit 6c4009
	if (cmd == F_DUPFD_CLOEXEC)
Packit 6c4009
	  flags |= FD_CLOEXEC;
Packit 6c4009
	else
Packit 6c4009
	  /* Duplication clears the FD_CLOEXEC flag.  */
Packit 6c4009
	  flags &= ~FD_CLOEXEC;
Packit 6c4009
Packit 6c4009
	/* Get a new file descriptor.  The third argument to __fcntl is the
Packit 6c4009
	   minimum file descriptor number for it.  */
Packit 6c4009
	new = _hurd_alloc_fd (&result, va_arg (ap, int));
Packit 6c4009
	if (new == NULL)
Packit 6c4009
	  /* _hurd_alloc_fd has set errno.  */
Packit 6c4009
	  result = -1;
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.  */
Packit 6c4009
	    if (ctty != MACH_PORT_NULL)
Packit 6c4009
	      _hurd_port_set (&new->ctty, ctty);
Packit 6c4009
	    new->flags = flags;
Packit 6c4009
	    _hurd_port_locked_set (&new->port, port); /* Unlocks NEW.  */
Packit 6c4009
	  }
Packit 6c4009
Packit 6c4009
	HURD_CRITICAL_END;
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
	break;
Packit 6c4009
      }
Packit 6c4009
Packit 6c4009
      /* Set RESULT by evaluating EXPR with the descriptor locked.
Packit 6c4009
	 Check for an empty descriptor and return EBADF.  */
Packit 6c4009
#define LOCKED(expr)							      \
Packit 6c4009
      HURD_CRITICAL_BEGIN;						      \
Packit 6c4009
      __spin_lock (&d->port.lock);					      \
Packit 6c4009
      if (d->port.port == MACH_PORT_NULL)				      \
Packit 6c4009
	result = __hurd_fail (EBADF);					      \
Packit 6c4009
      else								      \
Packit 6c4009
	result = (expr);						      \
Packit 6c4009
      __spin_unlock (&d->port.lock);					      \
Packit 6c4009
      HURD_CRITICAL_END;
Packit 6c4009
Packit 6c4009
    case F_GETFD:		/* Get descriptor flags.  */
Packit 6c4009
      LOCKED (d->flags);
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case F_SETFD:		/* Set descriptor flags.  */
Packit 6c4009
      LOCKED ((d->flags = va_arg (ap, int), 0));
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
Packit 6c4009
      /* Now the real io operations, done by RPCs to io servers.  */
Packit 6c4009
Packit 6c4009
    case F_GETLK:
Packit 6c4009
    case F_SETLK:
Packit 6c4009
    case F_SETLKW:
Packit 6c4009
      {
Packit 6c4009
	/* XXX
Packit 6c4009
	   We need new RPCs to support POSIX.1 fcntl file locking!!
Packit 6c4009
	   For the time being we support the whole-file case only,
Packit 6c4009
	   with all kinds of WRONG WRONG WRONG semantics,
Packit 6c4009
	   by using flock.  This is definitely the Wrong Thing,
Packit 6c4009
	   but it might be better than nothing (?).  */
Packit 6c4009
	struct flock *fl = va_arg (ap, struct flock *);
Packit 6c4009
	va_end (ap);
Packit 6c4009
	switch (cmd)
Packit 6c4009
	  {
Packit 6c4009
	  case F_GETLK:
Packit 6c4009
	    errno = ENOSYS;
Packit 6c4009
	    return -1;
Packit 6c4009
	  case F_SETLK:
Packit 6c4009
	    cmd = LOCK_NB;
Packit 6c4009
	    break;
Packit 6c4009
	  default:
Packit 6c4009
	    cmd = 0;
Packit 6c4009
	    break;
Packit 6c4009
	  }
Packit 6c4009
	switch (fl->l_type)
Packit 6c4009
	  {
Packit 6c4009
	  case F_RDLCK: cmd |= LOCK_SH; break;
Packit 6c4009
	  case F_WRLCK: cmd |= LOCK_EX; break;
Packit 6c4009
	  case F_UNLCK: cmd |= LOCK_UN; break;
Packit 6c4009
	  default:
Packit 6c4009
	    errno = EINVAL;
Packit 6c4009
	    return -1;
Packit 6c4009
	  }
Packit 6c4009
	switch (fl->l_whence)
Packit 6c4009
	  {
Packit 6c4009
	  case SEEK_SET:
Packit 6c4009
	    if (fl->l_start == 0 && fl->l_len == 0) /* Whole file request.  */
Packit 6c4009
	      break;
Packit 6c4009
	    /* It seems to be common for applications to lock the first
Packit 6c4009
	       byte of the file when they are really doing whole-file locking.
Packit 6c4009
	       So, since it's so wrong already, might as well do that too.  */
Packit 6c4009
	    if (fl->l_start == 0 && fl->l_len == 1)
Packit 6c4009
	      break;
Packit 6c4009
	    /* FALLTHROUGH */
Packit 6c4009
	  case SEEK_CUR:
Packit 6c4009
	  case SEEK_END:
Packit 6c4009
	    errno = ENOTSUP;
Packit 6c4009
	    return -1;
Packit 6c4009
	  default:
Packit 6c4009
	    errno = EINVAL;
Packit 6c4009
	    return -1;
Packit 6c4009
	  }
Packit 6c4009
Packit 6c4009
	return __flock (fd, cmd);
Packit 6c4009
      }
Packit 6c4009
Packit 6c4009
    case F_GETFL:		/* Get per-open flags.  */
Packit 6c4009
      if (err = HURD_FD_PORT_USE (d, __io_get_openmodes (port, &result)))
Packit 6c4009
	result = __hurd_dfail (fd, err);
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case F_SETFL:		/* Set per-open flags.  */
Packit 6c4009
      err = HURD_FD_PORT_USE (d, __io_set_all_openmodes (port,
Packit 6c4009
							 va_arg (ap, int)));
Packit 6c4009
      result = err ? __hurd_dfail (fd, err) : 0;
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case F_GETOWN:		/* Get owner.  */
Packit 6c4009
      if (err = HURD_FD_PORT_USE (d, __io_get_owner (port, &result)))
Packit 6c4009
	result = __hurd_dfail (fd, err);
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case F_SETOWN:		/* Set owner.  */
Packit 6c4009
      err = HURD_FD_PORT_USE (d, __io_mod_owner (port, va_arg (ap, pid_t)));
Packit 6c4009
      result = err ? __hurd_dfail (fd, err) : 0;
Packit 6c4009
      break;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  va_end (ap);
Packit 6c4009
Packit 6c4009
  return result;
Packit 6c4009
}
Packit 6c4009
libc_hidden_def (__libc_fcntl)
Packit 6c4009
weak_alias (__libc_fcntl, __fcntl)
Packit 6c4009
libc_hidden_weak (__fcntl)
Packit 6c4009
weak_alias (__libc_fcntl, fcntl)
Packit 6c4009
Packit 6c4009
strong_alias (__libc_fcntl, __libc_fcntl64)
Packit 6c4009
libc_hidden_def (__libc_fcntl64)
Packit 6c4009
weak_alias (__libc_fcntl64, __fcntl64)
Packit 6c4009
libc_hidden_weak (__fcntl64)