mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-26 06:50:07 +00:00
06ab719d30
This patch fixes the OFD ("file private") locks for architectures that support non-LFS flock definition (__USE_FILE_OFFSET64 not defined). The issue in this case is both F_OFD_{GETLK,SETLK,SETLKW} and F_{SET,GET}L{W}K64 expects a flock64 argument and when using old F_OFD_* flags with a non LFS flock argument the kernel might interpret the underlying data wrongly. Kernel idea originally was to avoid using such flags in non-LFS syscall, but since GLIBC uses fcntl with LFS semantic as default it is possible to provide the functionality and avoid the bogus struct kernel passing by adjusting the struct manually for the required flags. The idea follows other LFS interfaces that provide two symbols: 1. A new LFS fcntl64 is added on default ABI with the usual macros to select it for FILE_OFFSET_BITS=64. 2. The Linux non-LFS fcntl use a stack allocated struct flock64 for F_OFD_{GETLK,SETLK,SETLKW} copy the results on the user provided struct. 3. Keep a compat symbol with old broken semantic for architectures that do not define __OFF_T_MATCHES_OFF64_T. So for architectures which defines __USE_FILE_OFFSET64, fcntl64 will aliased to fcntl and no adjustment would be required. So to actually use F_OFD_* with LFS support the source must be built with LFS support (_FILE_OFFSET_BITS=64). Also F_OFD_SETLKW command is handled a cancellation point, as for F_SETLKW{64}. Checked on x86_64-linux-gnu and i686-linux-gnu. [BZ #20251] * NEWS: Mention fcntl64 addition. * csu/check_fds.c: Replace __fcntl_nocancel by __fcntl64_nocancel. * login/utmp_file.c: Likewise. * sysdeps/posix/fdopendir.c: Likewise. * sysdeps/posix/opendir.c: Likewise. * sysdeps/unix/pt-fcntl.c: Likewise. * include/fcntl.h (__libc_fcntl64, __fcntl64, __fcntl64_nocancel_adjusted): New prototype. (__fcntl_nocancel_adjusted): Remove prototype. * io/Makefile (routines): Add fcntl64. (CFLAGS-fcntl64.c): New rule. * io/Versions [GLIBC_2.28] (fcntl64): New symbol. [GLIBC_PRIVATE] (__libc_fcntl): Rename to __libc_fcntl64. * io/fcntl.h (fcntl64): Add prototype and redirect if __USE_FILE_OFFSET64 is defined. * io/fcntl64.c: New file. * manual/llio.text: Add a note for which commands fcntl acts a cancellation point. * nptl/Makefile (CFLAGS-fcntl64.c): New rule. * sysdeps/mach/hurd/fcntl.c: Alias fcntl to fcntl64 symbols. * sysdeps/mach/hurd/i386/libc.abilist [GLIBC_2.28] (fcntl, fcntl64): New symbols. * sysdeps/unix/sysv/linux/fcntl.c (__libc_fcntl): Fix F_GETLK64, F_OFD_GETLK, F_SETLK64, F_SETLKW64, F_OFD_SETLK, and F_OFD_SETLKW for non-LFS case. * sysdeps/unix/sysv/linux/fcntl64.c: New file. * sysdeps/unix/sysv/linux/fcntl_nocancel.c (__fcntl_nocancel): Rename to __fcntl64_nocancel. (__fcntl_nocancel_adjusted): Rename to __fcntl64_nocancel_adjusted. * sysdeps/unix/sysv/linux/not-cancel.h (__fcntl_nocancel): Rename to __fcntl64_nocancel. * sysdeps/unix/sysv/linux/tst-ofdlocks.c: New file. * sysdeps/unix/sysv/linux/tst-ofdlocks-compat.c: Likewise. * sysdeps/unix/sysv/linux/Makefile (tests): Add tst-ofdlocks. (tests-internal): Add tst-ofdlocks-compat. * sysdeps/unix/sysv/linux/aarch64/libc.abilist [GLIBC_2.28] (fcntl64): New symbol. * sysdeps/unix/sysv/linux/alpha/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/ia64/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist: Likewise. * sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/x86_64/64/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/arm/libc.abilist [GLIBC_2.28] (fcntl, fcntl64): Likewise. * sysdeps/unix/sysv/linux/hppa/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/i386/libc.abilis: Likewise. * sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/microblaze/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/nios2/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/sh/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist: Likewise.
218 lines
5.8 KiB
C
218 lines
5.8 KiB
C
/* Copyright (C) 1992-2018 Free Software Foundation, Inc.
|
|
This file is part of the GNU C Library.
|
|
|
|
The GNU C Library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
The GNU C Library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with the GNU C Library; if not, see
|
|
<http://www.gnu.org/licenses/>. */
|
|
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <hurd.h>
|
|
#include <hurd/fd.h>
|
|
#include <stdarg.h>
|
|
#include <sys/file.h> /* XXX for LOCK_* */
|
|
|
|
/* Perform file control operations on FD. */
|
|
int
|
|
__libc_fcntl (int fd, int cmd, ...)
|
|
{
|
|
va_list ap;
|
|
struct hurd_fd *d;
|
|
int result;
|
|
|
|
d = _hurd_fd_get (fd);
|
|
|
|
if (d == NULL)
|
|
return __hurd_fail (EBADF);
|
|
|
|
va_start (ap, cmd);
|
|
|
|
switch (cmd)
|
|
{
|
|
error_t err;
|
|
|
|
default: /* Bad command. */
|
|
errno = EINVAL;
|
|
result = -1;
|
|
break;
|
|
|
|
/* First the descriptor-based commands, which do no RPCs. */
|
|
|
|
case F_DUPFD: /* Duplicate the file descriptor. */
|
|
case F_DUPFD_CLOEXEC:
|
|
{
|
|
struct hurd_fd *new;
|
|
io_t port, ctty;
|
|
struct hurd_userlink ulink, ctty_ulink;
|
|
int flags;
|
|
|
|
HURD_CRITICAL_BEGIN;
|
|
|
|
/* Extract the ports and flags from the file descriptor. */
|
|
__spin_lock (&d->port.lock);
|
|
flags = d->flags;
|
|
ctty = _hurd_port_get (&d->ctty, &ctty_ulink);
|
|
port = _hurd_port_locked_get (&d->port, &ulink); /* Unlocks D. */
|
|
|
|
if (cmd == F_DUPFD_CLOEXEC)
|
|
flags |= FD_CLOEXEC;
|
|
else
|
|
/* Duplication clears the FD_CLOEXEC flag. */
|
|
flags &= ~FD_CLOEXEC;
|
|
|
|
/* Get a new file descriptor. The third argument to __fcntl is the
|
|
minimum file descriptor number for it. */
|
|
new = _hurd_alloc_fd (&result, va_arg (ap, int));
|
|
if (new == NULL)
|
|
/* _hurd_alloc_fd has set errno. */
|
|
result = -1;
|
|
else
|
|
{
|
|
/* Give the ports each a user ref for the new descriptor. */
|
|
__mach_port_mod_refs (__mach_task_self (), port,
|
|
MACH_PORT_RIGHT_SEND, 1);
|
|
if (ctty != MACH_PORT_NULL)
|
|
__mach_port_mod_refs (__mach_task_self (), ctty,
|
|
MACH_PORT_RIGHT_SEND, 1);
|
|
|
|
/* Install the ports and flags in the new descriptor. */
|
|
if (ctty != MACH_PORT_NULL)
|
|
_hurd_port_set (&new->ctty, ctty);
|
|
new->flags = flags;
|
|
_hurd_port_locked_set (&new->port, port); /* Unlocks NEW. */
|
|
}
|
|
|
|
HURD_CRITICAL_END;
|
|
|
|
_hurd_port_free (&d->port, &ulink, port);
|
|
if (ctty != MACH_PORT_NULL)
|
|
_hurd_port_free (&d->ctty, &ctty_ulink, port);
|
|
|
|
break;
|
|
}
|
|
|
|
/* Set RESULT by evaluating EXPR with the descriptor locked.
|
|
Check for an empty descriptor and return EBADF. */
|
|
#define LOCKED(expr) \
|
|
HURD_CRITICAL_BEGIN; \
|
|
__spin_lock (&d->port.lock); \
|
|
if (d->port.port == MACH_PORT_NULL) \
|
|
result = __hurd_fail (EBADF); \
|
|
else \
|
|
result = (expr); \
|
|
__spin_unlock (&d->port.lock); \
|
|
HURD_CRITICAL_END;
|
|
|
|
case F_GETFD: /* Get descriptor flags. */
|
|
LOCKED (d->flags);
|
|
break;
|
|
|
|
case F_SETFD: /* Set descriptor flags. */
|
|
LOCKED ((d->flags = va_arg (ap, int), 0));
|
|
break;
|
|
|
|
|
|
/* Now the real io operations, done by RPCs to io servers. */
|
|
|
|
case F_GETLK:
|
|
case F_SETLK:
|
|
case F_SETLKW:
|
|
{
|
|
/* XXX
|
|
We need new RPCs to support POSIX.1 fcntl file locking!!
|
|
For the time being we support the whole-file case only,
|
|
with all kinds of WRONG WRONG WRONG semantics,
|
|
by using flock. This is definitely the Wrong Thing,
|
|
but it might be better than nothing (?). */
|
|
struct flock *fl = va_arg (ap, struct flock *);
|
|
va_end (ap);
|
|
switch (cmd)
|
|
{
|
|
case F_GETLK:
|
|
errno = ENOSYS;
|
|
return -1;
|
|
case F_SETLK:
|
|
cmd = LOCK_NB;
|
|
break;
|
|
default:
|
|
cmd = 0;
|
|
break;
|
|
}
|
|
switch (fl->l_type)
|
|
{
|
|
case F_RDLCK: cmd |= LOCK_SH; break;
|
|
case F_WRLCK: cmd |= LOCK_EX; break;
|
|
case F_UNLCK: cmd |= LOCK_UN; break;
|
|
default:
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
switch (fl->l_whence)
|
|
{
|
|
case SEEK_SET:
|
|
if (fl->l_start == 0 && fl->l_len == 0) /* Whole file request. */
|
|
break;
|
|
/* It seems to be common for applications to lock the first
|
|
byte of the file when they are really doing whole-file locking.
|
|
So, since it's so wrong already, might as well do that too. */
|
|
if (fl->l_start == 0 && fl->l_len == 1)
|
|
break;
|
|
/* FALLTHROUGH */
|
|
case SEEK_CUR:
|
|
case SEEK_END:
|
|
errno = ENOTSUP;
|
|
return -1;
|
|
default:
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
|
|
return __flock (fd, cmd);
|
|
}
|
|
|
|
case F_GETFL: /* Get per-open flags. */
|
|
if (err = HURD_FD_PORT_USE (d, __io_get_openmodes (port, &result)))
|
|
result = __hurd_dfail (fd, err);
|
|
break;
|
|
|
|
case F_SETFL: /* Set per-open flags. */
|
|
err = HURD_FD_PORT_USE (d, __io_set_all_openmodes (port,
|
|
va_arg (ap, int)));
|
|
result = err ? __hurd_dfail (fd, err) : 0;
|
|
break;
|
|
|
|
case F_GETOWN: /* Get owner. */
|
|
if (err = HURD_FD_PORT_USE (d, __io_get_owner (port, &result)))
|
|
result = __hurd_dfail (fd, err);
|
|
break;
|
|
|
|
case F_SETOWN: /* Set owner. */
|
|
err = HURD_FD_PORT_USE (d, __io_mod_owner (port, va_arg (ap, pid_t)));
|
|
result = err ? __hurd_dfail (fd, err) : 0;
|
|
break;
|
|
}
|
|
|
|
va_end (ap);
|
|
|
|
return result;
|
|
}
|
|
libc_hidden_def (__libc_fcntl)
|
|
weak_alias (__libc_fcntl, __fcntl)
|
|
libc_hidden_weak (__fcntl)
|
|
weak_alias (__libc_fcntl, fcntl)
|
|
|
|
strong_alias (__libc_fcntl, __libc_fcntl64)
|
|
libc_hidden_def (__libc_fcntl64)
|
|
weak_alias (__libc_fcntl64, __fcntl64)
|
|
libc_hidden_weak (__fcntl64)
|