Blame sysdeps/unix/sysv/linux/prlimit.c

Packit 6c4009
/* Copyright (C) 2010-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 <sys/resource.h>
Packit 6c4009
#include <sys/syscall.h>
Packit 6c4009
Packit 6c4009
Packit 6c4009
int
Packit 6c4009
prlimit (__pid_t pid, enum __rlimit_resource resource,
Packit 6c4009
	 const struct rlimit *new_rlimit, struct rlimit *old_rlimit)
Packit 6c4009
{
Packit 6c4009
  struct rlimit64 new_rlimit64_mem;
Packit 6c4009
  struct rlimit64 *new_rlimit64 = NULL;
Packit 6c4009
  struct rlimit64 old_rlimit64_mem;
Packit 6c4009
  struct rlimit64 *old_rlimit64 = (old_rlimit != NULL
Packit 6c4009
				   ? &old_rlimit64_mem : NULL);
Packit 6c4009
Packit 6c4009
  if (new_rlimit != NULL)
Packit 6c4009
    {
Packit 6c4009
      if (new_rlimit->rlim_cur == RLIM_INFINITY)
Packit 6c4009
	new_rlimit64_mem.rlim_cur = RLIM64_INFINITY;
Packit 6c4009
      else
Packit 6c4009
	new_rlimit64_mem.rlim_cur = new_rlimit->rlim_cur;
Packit 6c4009
      if (new_rlimit->rlim_max == RLIM_INFINITY)
Packit 6c4009
	new_rlimit64_mem.rlim_max = RLIM64_INFINITY;
Packit 6c4009
      else
Packit 6c4009
	new_rlimit64_mem.rlim_max = new_rlimit->rlim_max;
Packit 6c4009
      new_rlimit64 = &new_rlimit64_mem;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  int res = INLINE_SYSCALL (prlimit64, 4, pid, resource, new_rlimit64,
Packit 6c4009
			    old_rlimit64);
Packit 6c4009
Packit 6c4009
  if (res == 0 && old_rlimit != NULL)
Packit 6c4009
    {
Packit 6c4009
      /* The prlimit64 syscall is ill-designed for 32-bit machines.
Packit 6c4009
	 We have to provide a 32-bit variant since otherwise the LFS
Packit 6c4009
	 system would not work.  The infinity value can be translated,
Packit 6c4009
	 but otherwise what shall we do if the syscall succeeds but the
Packit 6c4009
	 old values do not fit into a rlimit structure?  We cannot return
Packit 6c4009
	 an error because the operation itself worked.  Best is perhaps
Packit 6c4009
	 to return RLIM_INFINITY.  */
Packit 6c4009
      old_rlimit->rlim_cur = old_rlimit64_mem.rlim_cur;
Packit 6c4009
      if (old_rlimit->rlim_cur != old_rlimit64_mem.rlim_cur)
Packit 6c4009
	{
Packit 6c4009
	  if ((new_rlimit == NULL)
Packit 6c4009
	      && (old_rlimit64_mem.rlim_cur != RLIM64_INFINITY))
Packit 6c4009
	    return INLINE_SYSCALL_ERROR_RETURN_VALUE (EOVERFLOW);
Packit 6c4009
	  old_rlimit->rlim_cur = RLIM_INFINITY;
Packit 6c4009
	}
Packit 6c4009
      old_rlimit->rlim_max = old_rlimit64_mem.rlim_max;
Packit 6c4009
      if (old_rlimit->rlim_max != old_rlimit64_mem.rlim_max)
Packit 6c4009
	{
Packit 6c4009
	  if ((new_rlimit == NULL)
Packit 6c4009
	      && (old_rlimit64_mem.rlim_max != RLIM64_INFINITY))
Packit 6c4009
	    return INLINE_SYSCALL_ERROR_RETURN_VALUE (EOVERFLOW);
Packit 6c4009
	  old_rlimit->rlim_max = RLIM_INFINITY;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return res;
Packit 6c4009
}