/* If ACT is not NULL, change the action for SIG to *ACT.
   If OACT is not NULL, put the old action for SIG in *OACT.  */
int __libc_sigaction (int sig, const struct sigaction *act, struct sigaction *oact)
{
    int result;
    struct old_kernel_sigaction kact, koact;

    if (act) {
	kact.k_sa_handler = act->sa_handler;
	kact.sa_mask = act->sa_mask.__val[0];
	kact.sa_flags = act->sa_flags;
# ifdef HAVE_SA_RESTORER
	/* See the comments above for why we test SA_ONSTACK.  */
	if (kact.sa_flags & (SA_RESTORER | SA_ONSTACK)) {
	    kact.sa_restorer = act->sa_restorer;
	} else {
	    kact.sa_restorer = __default_sa_restorer;
	    kact.sa_flags |= SA_RESTORER;
	}
# endif
    }
    result = __syscall_sigaction(sig, act ? __ptrvalue (&kact) : NULL,
	    oact ? __ptrvalue (&koact) : NULL);

    if (oact && result >= 0) {
	oact->sa_handler = koact.k_sa_handler;
	oact->sa_mask.__val[0] = koact.sa_mask;
	oact->sa_flags = koact.sa_flags;
# ifdef HAVE_SA_RESTORER
	oact->sa_restorer = koact.sa_restorer;
# endif
    }
    return result;
}
/* If ACT is not NULL, change the action for SIG to *ACT.
   If OACT is not NULL, put the old action for SIG in *OACT.  */
int __libc_sigaction (int sig, const struct sigaction *act, struct sigaction *oact)
{
    int result;
    struct old_kernel_sigaction kact, koact;

    if (act) {
	kact.k_sa_handler = act->sa_handler;
	kact.sa_mask = act->sa_mask.__val[0];
	kact.sa_flags = act->sa_flags;
# ifdef HAVE_SA_RESTORER
	if (kact.sa_flags & SA_RESTORER) {
	    kact.sa_restorer = act->sa_restorer;
	} else {
	    kact.sa_restorer = choose_restorer (kact.sa_flags);
	    kact.sa_flags |= SA_RESTORER;
	}
# endif
    }
    result = __syscall_sigaction(sig, act ? __ptrvalue (&kact) : NULL,
	    oact ? __ptrvalue (&koact) : NULL);
    if (oact && result >= 0) {
	oact->sa_handler = koact.k_sa_handler;
	oact->sa_mask.__val[0] = koact.sa_mask;
	oact->sa_flags = koact.sa_flags;
# ifdef HAVE_SA_RESTORER
	oact->sa_restorer = koact.sa_restorer;
# endif
    }
    return result;
}
Exemple #3
0
/* If ACT is not NULL, change the action for SIG to *ACT.
   If OACT is not NULL, put the old action for SIG in *OACT.  */
int __libc_sigaction (int sig, const struct sigaction *act, struct sigaction *oact)
{
    int result;
    struct old_kernel_sigaction kact, koact;

#ifdef SIGCANCEL
    if (sig == SIGCANCEL) {
        __set_errno (EINVAL);
        return -1;
    }
#endif
    if (act) {
        kact.k_sa_handler = act->sa_handler;
        kact.sa_mask = act->sa_mask.__val[0];
        kact.sa_flags = act->sa_flags;
# ifdef HAVE_SA_RESTORER
        kact.sa_restorer = act->sa_restorer;
# endif
    }
    result = __syscall_sigaction(sig, act ? __ptrvalue (&kact) : NULL,
                                 oact ? __ptrvalue (&koact) : NULL);

    if (oact && result >= 0) {
        oact->sa_handler = koact.k_sa_handler;
        oact->sa_mask.__val[0] = koact.sa_mask;
        oact->sa_flags = koact.sa_flags;
# ifdef HAVE_SA_RESTORER
        oact->sa_restorer = koact.sa_restorer;
# endif
    }
    return result;
}
Exemple #4
0
/* If ACT is not NULL, change the action for SIG to *ACT.
   If OACT is not NULL, put the old action for SIG in *OACT.  */
int __libc_sigaction (int sig, const struct sigaction *act, struct sigaction *oact)
{
    int result;
    struct kernel_sigaction kact, koact;

#ifdef SIGCANCEL
    if (sig == SIGCANCEL) {
        __set_errno (EINVAL);
        return -1;
    }
#endif
    if (act) {
        kact.k_sa_handler = act->sa_handler;
        memcpy (&kact.sa_mask, &act->sa_mask, sizeof (kact.sa_mask));
        kact.sa_flags = act->sa_flags;
# ifdef HAVE_SA_RESTORER
        kact.sa_restorer = act->sa_restorer;
# endif
    }

    /* XXX The size argument hopefully will have to be changed to the
       real size of the user-level sigset_t.  */
    result = __syscall_rt_sigaction(sig, act ? __ptrvalue (&kact) : NULL,
                                    oact ? __ptrvalue (&koact) : NULL, _NSIG / 8);

    if (oact && result >= 0) {
        oact->sa_handler = koact.k_sa_handler;
        memcpy (&oact->sa_mask, &koact.sa_mask, sizeof (oact->sa_mask));
        oact->sa_flags = koact.sa_flags;
# ifdef HAVE_SA_RESTORER
        oact->sa_restorer = koact.sa_restorer;
# endif
    }
    return result;
}
Exemple #5
0
/*
 * If act is not NULL, change the action for sig to *act.
 * If oact is not NULL, put the old action for sig in *oact.
 */
int __libc_sigaction(int signum, const struct sigaction *act,
		     struct sigaction *oldact)
{
	struct kernel_sigaction kact, koact;
	int result;

	if (act) {
		kact.k_sa_handler = act->sa_handler;
		memcpy(&kact.sa_mask, &act->sa_mask, sizeof (kact.sa_mask));
		kact.sa_flags = act->sa_flags;
		if (kact.sa_flags & SA_RESTORER)
			kact.sa_restorer = act->sa_restorer;
		else
			kact.sa_restorer = __default_rt_sa_restorer;
		kact.sa_flags |= SA_RESTORER;
	}

	result = __syscall_rt_sigaction(signum, act ? __ptrvalue(&kact) : NULL,
					oldact ? __ptrvalue(&koact) : NULL,
					_NSIG / 8);

	if (oldact && result >= 0) {
		oldact->sa_handler = koact.k_sa_handler;
		memcpy(&oldact->sa_mask, &koact.sa_mask,
		       sizeof(oldact->sa_mask));
		oldact->sa_flags = koact.sa_flags;
		oldact->sa_restorer = koact.sa_restorer;
	}

	return result;
}
/* If ACT is not NULL, change the action for SIG to *ACT.
   If OACT is not NULL, put the old action for SIG in *OACT.  */
int
__libc_sigaction (int sig, const struct sigaction *act, struct sigaction *oact)
{
  int result;
  struct kernel_sigaction kact, koact;

  if (act)
    {
      kact.k_sa_handler = act->sa_handler;
      memcpy (&kact.sa_mask, &act->sa_mask, sizeof (sigset_t));
      kact.sa_flags = act->sa_flags | SA_RESTORER;

      kact.sa_restorer = &restore_rt;
    }

  /* XXX The size argument hopefully will have to be changed to the
     real size of the user-level sigset_t.  */
  result = INLINE_SYSCALL (rt_sigaction, 4,
			   sig, act ? __ptrvalue (&kact) : NULL,
			   oact ? __ptrvalue (&koact) : NULL, _NSIG / 8);
  if (oact && result >= 0)
    {
      oact->sa_handler = koact.k_sa_handler;
      memcpy (&oact->sa_mask, &koact.sa_mask, sizeof (sigset_t));
      oact->sa_flags = koact.sa_flags;
      oact->sa_restorer = koact.sa_restorer;
    }
  return result;
}
Exemple #7
0
/* Get information about the file FD in BUF.  */
int
__fxstat (int vers, int fd, struct stat *buf)
{
#if __ASSUME_STAT64_SYSCALL == 0
  struct kernel_stat kbuf;
#endif
  int result;

  if (vers == _STAT_VER_KERNEL)
    return INLINE_SYSCALL (fstat, 2, fd, CHECK_1 ((struct kernel_stat *) buf));

#if __ASSUME_STAT64_SYSCALL > 0
  {
    struct stat64 buf64;

    result = INLINE_SYSCALL (fstat64, 2, fd, __ptrvalue (&buf64));
    if (result == 0)
      result = __xstat32_conv (vers, &buf64, buf);
    return result;
  }
#else

# if defined __NR_stat64
  /* To support 32 bit UIDs, we have to use stat64.  The normal stat call only returns
     16 bit UIDs.  */
  if (! __have_no_stat64)
    {
      struct stat64 buf64;

      result = INLINE_SYSCALL (fstat64, 2, fd, __ptrvalue (&buf64));

      if (result == 0)
	result = __xstat32_conv (vers, &buf64, buf);

      if (result != -1 || errno != ENOSYS)
	return result;

      __have_no_stat64 = 1;
    }
# endif

  result = INLINE_SYSCALL (fstat, 2, fd, __ptrvalue (&kbuf));
  if (result == 0)
    result = __xstat_conv (vers, &kbuf, buf);

  return result;
#endif  /* __ASSUME_STAT64_SYSCALL  */
}
Exemple #8
0
/* Get information about the file NAME relative to FD in ST.  */
int
__fxstatat (int vers, int fd, const char *file, struct stat *st, int flag)
{
      int result;

      if (__builtin_expect (vers == _STAT_VER, 1))
	{
	  struct stat16 buf16;
	  result =
	    INLINE_SYSCALL (fstatat, 4, fd, CHECK_STRING (file),
			    __ptrvalue (&buf16), flag);
	  if (result == 0)
	    stat16_to_stat (&buf16, st);
	}
      else if (__builtin_expect (vers == _STAT_VER_stat, 1))
	{
	  result =
	    INLINE_SYSCALL (fstatat, 4, fd, CHECK_STRING (file),
			    CHECK_1 ((struct stat16 *) st), flag);
	}
      else
	{
	  __set_errno (EINVAL);
	  return -1;
	}
	return result;
}
Exemple #9
0
int
__fxstat64 (int vers, int fd, struct stat64 *buf)
{
  int result;
  struct kernel_stat kbuf;

  result = INLINE_SYSCALL (fstat, 2, fd, __ptrvalue (&kbuf));
  if (result == 0)
    result = __xstat64_conv (vers, &kbuf, buf);

  return result;
}
Exemple #10
0
int
__xstat64 (int vers, const char *name, struct stat64 *buf)
{
  int result;
  struct kernel_stat kbuf;

  result = INLINE_SYSCALL (stat, 2, CHECK_STRING (name), __ptrvalue (&kbuf));
  if (result == 0)
    result = __xstat64_conv (vers, &kbuf, buf);

  return result;
}
/* If ACT is not NULL, change the action for SIG to *ACT.
   If OACT is not NULL, put the old action for SIG in *OACT.  */
int __libc_sigaction (int sig, const struct sigaction *act, struct sigaction *oact)
{
    int result;
    struct kernel_sigaction kact, koact;

    if (act) {
	kact.k_sa_handler = act->sa_handler;
	memcpy (&kact.sa_mask, &act->sa_mask, sizeof (kact.sa_mask));
	kact.sa_flags = act->sa_flags;
# ifdef HAVE_SA_RESTORER
	if (kact.sa_flags & (SA_RESTORER | SA_ONSTACK)) {
	    kact.sa_restorer = act->sa_restorer;
	} else {
	    if (kact.sa_flags & SA_SIGINFO) {
		kact.sa_restorer = __default_rt_sa_restorer;
	    } else {
		kact.sa_restorer = __default_sa_restorer;
		kact.sa_flags |= SA_RESTORER;
	    }
	}
# endif
    }

    /* XXX The size argument hopefully will have to be changed to the
       real size of the user-level sigset_t.  */
    result = __syscall_rt_sigaction(sig, act ? __ptrvalue (&kact) : NULL,
	    oact ? __ptrvalue (&koact) : NULL, _NSIG / 8);

    if (oact && result >= 0) {
	oact->sa_handler = koact.k_sa_handler;
	memcpy (&oact->sa_mask, &koact.sa_mask, sizeof (oact->sa_mask));
	oact->sa_flags = koact.sa_flags;
# ifdef HAVE_SA_RESTORER
	oact->sa_restorer = koact.sa_restorer;
# endif
    }
    return result;
}
int
__new_setrlimit (enum __rlimit_resource resource, const struct rlimit *rlimits)
{
#ifdef __ASSUME_NEW_GETRLIMIT_SYSCALL
  return INLINE_SYSCALL (setrlimit, 2, resource, CHECK_1 (rlimits));
#else
  struct rlimit rlimits_small;

# ifdef __NR_ugetrlimit
  if (__have_no_new_getrlimit == 0)
    {
      /* Check if the new ugetrlimit syscall exists.  We must do this
	 first because older kernels don't reject negative rlimit
	 values in setrlimit.  */
      int result = INLINE_SYSCALL (ugetrlimit, 2, resource, __ptrvalue (&rlimits_small));
      if (result != -1 || errno != ENOSYS)
	/* The syscall exists.  */
	__have_no_new_getrlimit = -1;
      else
	/* The syscall does not exist.  */
	__have_no_new_getrlimit = 1;
    }
  if (__have_no_new_getrlimit < 0)
    return INLINE_SYSCALL (setrlimit, 2, resource, CHECK_1 (rlimits));
# endif

  /* We might have to correct the limits values.  Since the old values
     were signed the new values might be too large.  */
  rlimits_small.rlim_cur = MIN ((unsigned long int) rlimits->rlim_cur,
				RLIM_INFINITY >> 1);
  rlimits_small.rlim_max = MIN ((unsigned long int) rlimits->rlim_max,
				RLIM_INFINITY >> 1);

  /* Use the adjusted values.  */
  return INLINE_SYSCALL (setrlimit, 2, resource, __ptrvalue (&rlimits_small));
#endif
}
Exemple #13
0
/* Get information about the file FD in BUF.  */
int
__fxstat (int vers, int fd, struct stat *buf)
{
    struct kernel_stat kbuf;
    int result;

    if (vers == _STAT_VER_KERNEL)
        return INLINE_SYSCALL (fstat, 2, fd, CHECK_1 ((struct kernel_stat *) buf));

    result = INLINE_SYSCALL (fstat, 2, fd, __ptrvalue (&kbuf));
    if (result == 0)
        result = xstat_conv (vers, &kbuf, buf);

    return result;
}
Exemple #14
0
/* Return any pending signal or wait for one for the given time.  */
int sigqueue (pid_t pid, int sig, const union sigval val)
{
  siginfo_t info;

  /* First, clear the siginfo_t structure, so that we don't pass our
     stack content to other tasks.  */
  memset (&info, 0, sizeof (siginfo_t));
  /* We must pass the information about the data in a siginfo_t value.  */
  info.si_signo = sig;
  info.si_code = SI_QUEUE;
  info.si_pid = getpid ();
  info.si_uid = getuid ();
  info.si_value = val;

  return __libc_rt_sigqueueinfo(pid, sig, __ptrvalue (&info));
}
/* Set the group set for the current user to GROUPS (N of them).  For
   Linux we must convert the array of groups into the format that the
   kernel expects.  */
int
setgroups (size_t n, const gid_t *groups)
{
#if __ASSUME_32BITUIDS > 0
  return INLINE_SETXID_SYSCALL (setgroups32, 2, n, CHECK_N (groups, n));
#else
  if (n > (size_t) __sysconf (_SC_NGROUPS_MAX))
    {
      __set_errno (EINVAL);
      return -1;
    }
  else
    {
      size_t i;
      __kernel_gid_t kernel_groups[n];

# ifdef __NR_setgroups32
      if (__libc_missing_32bit_uids <= 0)
	{
	  int result;
	  int saved_errno = errno;

	  result = INLINE_SETXID_SYSCALL (setgroups32, 2, n,
					  CHECK_N (groups, n));
	  if (result == 0 || errno != ENOSYS)
	    return result;

	  __set_errno (saved_errno);
	  __libc_missing_32bit_uids = 1;
	}
# endif /* __NR_setgroups32 */
      for (i = 0; i < n; i++)
	{
	  kernel_groups[i] = (__ptrvalue (groups))[i];
	  if (groups[i] != (gid_t) ((__kernel_gid_t) groups[i]))
	    {
	      __set_errno (EINVAL);
	      return -1;
	    }
	}

      return INLINE_SETXID_SYSCALL (setgroups, 2, n,
				    CHECK_N (kernel_groups, n));
    }
#endif
}
Exemple #16
0
int
__lxstat64 (int vers, const char *file, struct stat64 *buf)
{
  if (__builtin_expect (vers == _STAT_VER, 1))
    {
      struct stat16 buf16;
      int result = __syscall_lstat (CHECK_STRING (file), __ptrvalue (&buf16));
      if (result == 0)
	stat16_to_stat64 (&buf16, buf);
      return result;
    }
  else
    {
      __set_errno (EINVAL);
      return -1;
    }
}
Exemple #17
0
int
__sysctl (int *name, int nlen, void *oldval, size_t *oldlenp,
	  void *newval, size_t newlen)
{
  /* GKM FIXME: force __sysctl_args decl to have unbounded pointers.  */
  struct __sysctl_args args =
  {
    .name = name,
    .nlen = nlen,
    .oldval = oldval,
    .oldlenp = oldlenp,
    .newval = newval,
    .newlen = newlen
  };
  (void) CHECK_N (name, nlen);
  (void) CHECK_N (oldval, *oldlenp);
  (void) CHECK_N (newval, newlen);

  return INLINE_SYSCALL (_sysctl, 1, __ptrvalue (&args));
}
Exemple #18
0
int
___xstat64 (int vers, const char *name, struct stat64 *buf)
{
  int result;
#if __ASSUME_STAT64_SYSCALL > 0
  result = INLINE_SYSCALL (stat64, 2, CHECK_STRING (name), CHECK_1 (buf));
# if defined _HAVE_STAT64___ST_INO && __ASSUME_ST_INO_64_BIT == 0
  if (__builtin_expect (!result, 1) && buf->__st_ino != (__ino_t) buf->st_ino)
    buf->st_ino = buf->__st_ino;
# endif
  return result;
#else
  struct kernel_stat kbuf;
# if defined __NR_stat64
  if (! __have_no_stat64)
    {
      int saved_errno = errno;
      result = INLINE_SYSCALL (stat64, 2, CHECK_STRING (name), CHECK_1 (buf));

      if (result != -1 || errno != ENOSYS)
	{
#  if defined _HAVE_STAT64___ST_INO && __ASSUME_ST_INO_64_BIT == 0
	  if (!result && buf->__st_ino != (__ino_t) buf->st_ino)
	    buf->st_ino = buf->__st_ino;
#  endif
	  return result;
	}

      __set_errno (saved_errno);
      __have_no_stat64 = 1;
    }
# endif

  result = INLINE_SYSCALL (stat, 2, CHECK_STRING (name), __ptrvalue (&kbuf));
  if (result == 0)
    result = __xstat64_conv (vers, &kbuf, buf);

  return result;
#endif
}
Exemple #19
0
/* Get information about the file NAME in BUF.  */
int
__xstat (int vers, const char *name, struct stat *buf)
{
  if (vers == _STAT_VER_KERNEL)
    return INLINE_SYSCALL (stat, 2, CHECK_STRING (name),
			   CHECK_1 ((struct kernel_stat *) buf));

#ifdef STAT_IS_KERNEL_STAT
  errno = EINVAL;
  return -1;
#else
  struct kernel_stat kbuf;
  int result;

  result = INLINE_SYSCALL (stat, 2, CHECK_STRING (name),
			   __ptrvalue (&kbuf));
  if (result == 0)
    result = __xstat_conv (vers, &kbuf, buf);

  return result;
#endif
}
int
__new_shmctl (int shmid, int cmd, struct shmid_ds *buf)
{
#if __ASSUME_IPC64 > 0
  return INLINE_SYSCALL (ipc, 5, IPCOP_shmctl, shmid, cmd | __IPC_64, 0,
			 CHECK_1 (buf));
#else
  switch (cmd) {
    case SHM_STAT:
    case IPC_STAT:
    case IPC_SET:
#if __WORDSIZE != 32
    case IPC_INFO:
#endif
      break;
    default:
      return INLINE_SYSCALL (ipc, 5, IPCOP_shmctl, shmid, cmd, 0,
			     CHECK_1 (buf));
  }

  {
    int save_errno = errno, result;
    union
      {
	struct __old_shmid_ds ds;
	struct __old_shminfo info;
      } old;

    /* Unfortunately there is no way how to find out for sure whether
       we should use old or new shmctl.  */
    result = INLINE_SYSCALL (ipc, 5, IPCOP_shmctl, shmid, cmd | __IPC_64, 0,
			     CHECK_1 (buf));
    if (result != -1 || errno != EINVAL)
      return result;

    __set_errno(save_errno);
    if (cmd == IPC_SET)
      {
	old.ds.shm_perm.uid = buf->shm_perm.uid;
	old.ds.shm_perm.gid = buf->shm_perm.gid;
	old.ds.shm_perm.mode = buf->shm_perm.mode;
	if (old.ds.shm_perm.uid != buf->shm_perm.uid ||
	    old.ds.shm_perm.gid != buf->shm_perm.gid)
	  {
	    __set_errno (EINVAL);
	    return -1;
	  }
      }
    result = INLINE_SYSCALL (ipc, 5, IPCOP_shmctl, shmid, cmd, 0,
			     __ptrvalue (&old.ds));
    if (result != -1 && (cmd == SHM_STAT || cmd == IPC_STAT))
      {
	memset(buf, 0, sizeof(*buf));
	buf->shm_perm.__key = old.ds.shm_perm.__key;
	buf->shm_perm.uid = old.ds.shm_perm.uid;
	buf->shm_perm.gid = old.ds.shm_perm.gid;
	buf->shm_perm.cuid = old.ds.shm_perm.cuid;
	buf->shm_perm.cgid = old.ds.shm_perm.cgid;
	buf->shm_perm.mode = old.ds.shm_perm.mode;
	buf->shm_perm.__seq = old.ds.shm_perm.__seq;
	buf->shm_atime = old.ds.shm_atime;
	buf->shm_dtime = old.ds.shm_dtime;
	buf->shm_ctime = old.ds.shm_ctime;
	buf->shm_segsz = old.ds.shm_segsz;
	buf->shm_nattch = old.ds.shm_nattch;
	buf->shm_cpid = old.ds.shm_cpid;
	buf->shm_lpid = old.ds.shm_lpid;
      }
#if __WORDSIZE != 32
    else if (result != -1 && cmd == IPC_INFO)
      {
	struct shminfo *i = (struct shminfo *)buf;

	memset(i, 0, sizeof(*i));
	i->shmmax = old.info.shmmax;
	i->shmmin = old.info.shmmin;
	i->shmmni = old.info.shmmni;
	i->shmseg = old.info.shmseg;
	i->shmall = old.info.shmall;
      }
#endif
    return result;
  }
#endif
}
Exemple #21
0
int
__new_shmctl (int shmid, int cmd, struct shmid_ds *buf)
{
#if __ASSUME_32BITUIDS > 0
  return INLINE_SYSCALL (ipc, 5, IPCOP_shmctl,
			 shmid, cmd | __IPC_64, 0, CHECK_1 (buf));
#else
  switch (cmd) {
    case SHM_STAT:
    case IPC_STAT:
    case IPC_SET:
# if __WORDSIZE != 32
    case IPC_INFO:
# endif
      break;
    default:
      return INLINE_SYSCALL (ipc, 5, IPCOP_shmctl,
			     shmid, cmd, 0, CHECK_1 (buf));
  }

  {
    struct __old_shmid_ds old;
    int result;

# ifdef __NR_getuid32
    if (__libc_missing_32bit_uids <= 0)
      {
	if (__libc_missing_32bit_uids < 0)
	  {
	    int save_errno = errno;

	    /* Test presence of new IPC by testing for getuid32 syscall.  */
	    result = INLINE_SYSCALL (getuid32, 0);
	    if (result == -1 && errno == ENOSYS)
	      __libc_missing_32bit_uids = 1;
	    else
	      __libc_missing_32bit_uids = 0;
	    __set_errno(save_errno);
	  }
	if (__libc_missing_32bit_uids <= 0)
	  return INLINE_SYSCALL (ipc, 5, IPCOP_shmctl,
				 shmid, cmd | __IPC_64, 0, CHECK_1 (buf));
      }
# endif

    if (cmd == IPC_SET)
      {
	old.shm_perm.uid = buf->shm_perm.uid;
	old.shm_perm.gid = buf->shm_perm.gid;
	old.shm_perm.mode = buf->shm_perm.mode;
	if (old.shm_perm.uid != buf->shm_perm.uid ||
	    old.shm_perm.gid != buf->shm_perm.gid)
	  {
	    __set_errno (EINVAL);
	    return -1;
	  }
      }
    result = INLINE_SYSCALL (ipc, 5, IPCOP_shmctl,
			     shmid, cmd, 0, __ptrvalue (&old));
    if (result != -1 && (cmd == SHM_STAT || cmd == IPC_STAT))
      {
	memset(buf, 0, sizeof(*buf));
	buf->shm_perm.__key = old.shm_perm.__key;
	buf->shm_perm.uid = old.shm_perm.uid;
	buf->shm_perm.gid = old.shm_perm.gid;
	buf->shm_perm.cuid = old.shm_perm.cuid;
	buf->shm_perm.cgid = old.shm_perm.cgid;
	buf->shm_perm.mode = old.shm_perm.mode;
	buf->shm_perm.__seq = old.shm_perm.__seq;
	buf->shm_atime = old.shm_atime;
	buf->shm_dtime = old.shm_dtime;
	buf->shm_ctime = old.shm_ctime;
	buf->shm_segsz = old.shm_segsz;
	buf->shm_nattch = old.shm_nattch;
	buf->shm_cpid = old.shm_cpid;
	buf->shm_lpid = old.shm_lpid;
      }
# if __WORDSIZE != 32
    else if (result != -1 && cmd == IPC_INFO)
      {
	struct __old_shminfo *oldi = (struct __old_shminfo *)&old;
	struct shminfo *i = (struct shminfo *)buf;

	memset(i, 0, sizeof(*i));
	i->shmmax = oldi->shmmax;
	i->shmmin = oldi->shmmin;
	i->shmmni = oldi->shmmni;
	i->shmseg = oldi->shmseg;
	i->shmall = oldi->shmall;
      }
# endif
    return result;
  }
#endif
}
int
fchownat (int fd, const char *file, uid_t owner, gid_t group, int flag)
{
  if (flag & ~AT_SYMLINK_NOFOLLOW)
    {
      __set_errno (EINVAL);
      return -1;
    }

  char *buf = NULL;

  if (fd != AT_FDCWD && file[0] != '/')
    {
      size_t filelen = strlen (file);
      static const char procfd[] = "/proc/self/fd/%d/%s";
      /* Buffer for the path name we are going to use.  It consists of
	 - the string /proc/self/fd/
	 - the file descriptor number
	 - the file name provided.
	 The final NUL is included in the sizeof.   A bit of overhead
	 due to the format elements compensates for possible negative
	 numbers.  */
      size_t buflen = sizeof (procfd) + sizeof (int) * 3 + filelen;
      buf = alloca (buflen);

      __snprintf (buf, buflen, procfd, fd, file);
      file = buf;
    }

  int result;
  INTERNAL_SYSCALL_DECL (err);

#if __ASSUME_LCHOWN_SYSCALL
  if (flag & AT_SYMLINK_NOFOLLOW)
    result = INTERNAL_SYSCALL (lchown, err, 3, file, owner, group);
  else
    result = INTERNAL_SYSCALL (chown, err, 3, file, owner, group);
#else
  char link[PATH_MAX + 2];
  char path[2 * PATH_MAX + 4];
  int loopct;
  size_t filelen;
  static int libc_old_chown = 0 /* -1=old linux, 1=new linux, 0=unknown */;

  if (libc_old_chown == 1)
    {
      if (flag & AT_SYMLINK_NOFOLLOW)
	result = INTERNAL_SYSCALL (lchown, err, 3, __ptrvalue (file), owner,
				   group);
      else
	result = INTERNAL_SYSCALL (chown, err, 3, __ptrvalue (file), owner,
				   group);
      goto out;
    }

# ifdef __NR_lchown
  if (flag & AT_SYMLINK_NOFOLLOW)
    {
      result = INTERNAL_SYSCALL (lchown, err, 3, __ptrvalue (file), owner,
				 group);
      goto out;
    }

  if (libc_old_chown == 0)
    {
      result = INTERNAL_SYSCALL (chown, err, 3, __ptrvalue (file), owner,
				 group);
      if (__builtin_expect (!INTERNAL_SYSCALL_ERROR_P (result, err), 1))
	return result;
      if (INTERNAL_SYSCALL_ERRNO (result, err) != ENOSYS)
	{
	  libc_old_chown = 1;
	  goto fail;
	}
      libc_old_chown = -1;
    }
# else
  if (flag & AT_SYMLINK_NOFOLLOW)
    {
      result = INTERNAL_SYSCALL (chown, err, 3, __ptrvalue (file), owner,
				 group);
      goto out;
    }
# endif

  result = __readlink (file, link, PATH_MAX + 1);
  if (result == -1)
    {
# ifdef __NR_lchown
      result = INTERNAL_SYSCALL (lchown, err, 3, __ptrvalue (file), owner,
				 group);
# else
      result = INTERNAL_SYSCALL (chown, err, 3, __ptrvalue (file), owner,
				 group);
# endif
      goto out;
    }

  filelen = strlen (file) + 1;
  if (filelen > sizeof (path))
    {
      errno = ENAMETOOLONG;
      return -1;
    }
  memcpy (path, file, filelen);

  /* 'The system has an arbitrary limit...'  In practise, we'll hit
     ENAMETOOLONG before this, usually.  */
  for (loopct = 0; loopct < 128; ++loopct)
    {
      size_t linklen;

      if (result >= PATH_MAX + 1)
	{
	  errno = ENAMETOOLONG;
	  return -1;
	}

      link[result] = 0;  /* Null-terminate string, just-in-case.  */

      linklen = strlen (link) + 1;

      if (link[0] == '/')
	memcpy (path, link, linklen);
      else
	{
	  filelen = strlen (path);

	  while (filelen > 1 && path[filelen - 1] == '/')
	    --filelen;
	  while (filelen > 0 && path[filelen - 1] != '/')
	    --filelen;
	  if (filelen + linklen > sizeof (path))
	    {
	      errno = ENAMETOOLONG;
	      return -1;
	    }
	  memcpy (path + filelen, link, linklen);
	}

      result = __readlink (path, link, PATH_MAX + 1);

      if (result == -1)
	{
# ifdef __NR_lchown
	  result = INTERNAL_SYSCALL (lchown, err, 3, path, owner, group);
# else
	  result = INTERNAL_SYSCALL (chown, err, 3, path, owner, group);
# endif
	  goto out;
	}
    }
  __set_errno (ELOOP);
  return -1;

 out:
#endif

  if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (result, err), 0))
    {
#if !__ASSUME_LCHOWN_SYSCALL
    fail:
#endif
      __atfct_seterrno (INTERNAL_SYSCALL_ERRNO (result, err), fd, buf);
      result = -1;
    }

  return result;
}
Exemple #23
0
int
__new_msgctl (int msqid, int cmd, struct msqid_ds *buf)
{
  /* This is a misnomer -- Alpha had 32-bit uids at the beginning
     of time.  However, msg_qnum and msg_qbytes changed size at
     the same time the size of uid changed elsewhere.  */
#if __ASSUME_32BITUIDS > 0
  return INLINE_SYSCALL (msgctl, 3, msqid, cmd | __IPC_64, CHECK_1 (buf));
#else
  switch (cmd) {
    case MSG_STAT:
    case IPC_STAT:
    case IPC_SET:
      break;
    default:
      return INLINE_SYSCALL (msgctl, 3, msqid, cmd, CHECK_1 (buf));
  }

  {
    int save_errno = errno, result;
    struct __old_msqid_ds old;

    /* Unfortunately there is no way how to find out for sure whether
       we should use old or new msgctl.  */
    result = INLINE_SYSCALL (msgctl, 3, msqid, cmd | __IPC_64, CHECK_1 (buf));
    if (result != -1 || errno != EINVAL)
      return result;

    __set_errno(save_errno);
    if (cmd == IPC_SET)
      {
	old.msg_perm.uid = buf->msg_perm.uid;
	old.msg_perm.gid = buf->msg_perm.gid;
	old.msg_perm.mode = buf->msg_perm.mode;
	old.msg_qbytes = buf->msg_qbytes;
	if (old.msg_perm.uid != buf->msg_perm.uid ||
	    old.msg_perm.gid != buf->msg_perm.gid ||
	    old.msg_qbytes != buf->msg_qbytes)
	  {
	    __set_errno (EINVAL);
	    return -1;
	  }
      }
    result = INLINE_SYSCALL (msgctl, 3, msqid, cmd, __ptrvalue (&old));
    if (result != -1 && cmd != IPC_SET)
      {
	memset(buf, 0, sizeof(*buf));
	buf->msg_perm.__key = old.msg_perm.__key;
	buf->msg_perm.uid = old.msg_perm.uid;
	buf->msg_perm.gid = old.msg_perm.gid;
	buf->msg_perm.cuid = old.msg_perm.cuid;
	buf->msg_perm.cgid = old.msg_perm.cgid;
	buf->msg_perm.mode = old.msg_perm.mode;
	buf->msg_perm.__seq = old.msg_perm.__seq;
	buf->msg_stime = old.msg_stime;
	buf->msg_rtime = old.msg_rtime;
	buf->msg_ctime = old.msg_ctime;
	buf->__msg_cbytes = old.__msg_cbytes;
	buf->msg_qnum = old.msg_qnum;
	buf->msg_qbytes = old.msg_qbytes;
	buf->msg_lspid = old.msg_lspid;
	buf->msg_lrpid = old.msg_lrpid;
      }
    return result;
  }
#endif
}
Exemple #24
0
int
__new_msgctl (int msqid, int cmd, struct msqid_ds *buf)
{
#if __ASSUME_IPC64 > 0
  return INLINE_SYSCALL (ipc, 5, IPCOP_msgctl,
			 msqid, cmd | __IPC_64, 0, CHECK_1 (buf));
#else
  switch (cmd) {
    case MSG_STAT:
    case IPC_STAT:
    case IPC_SET:
      break;
    default:
      return INLINE_SYSCALL (ipc, 5, IPCOP_msgctl,
			     msqid, cmd, 0, CHECK_1 (buf));
  }

  {
    int result;
    struct __old_msqid_ds old;

    /* Unfortunately there is no way how to find out for sure whether
       we should use old or new msgctl.  */
    result = INLINE_SYSCALL (ipc, 5, IPCOP_msgctl,
			     msqid, cmd | __IPC_64, 0, CHECK_1 (buf));
    if (result != -1 || errno != EINVAL)
      return result;

    if (cmd == IPC_SET)
      {
	old.msg_perm.uid = buf->msg_perm.uid;
	old.msg_perm.gid = buf->msg_perm.gid;
	old.msg_perm.mode = buf->msg_perm.mode;
	old.msg_qbytes = buf->msg_qbytes;
	if (old.msg_perm.uid != buf->msg_perm.uid ||
	    old.msg_perm.gid != buf->msg_perm.gid ||
	    old.msg_qbytes != buf->msg_qbytes)
	  {
	    __set_errno (EINVAL);
	    return -1;
	  }
      }
    result = INLINE_SYSCALL (ipc, 5, IPCOP_msgctl,
			     msqid, cmd, 0, __ptrvalue (&old));
    if (result != -1 && cmd != IPC_SET)
      {
	memset(buf, 0, sizeof(*buf));
	buf->msg_perm.__key = old.msg_perm.__key;
	buf->msg_perm.uid = old.msg_perm.uid;
	buf->msg_perm.gid = old.msg_perm.gid;
	buf->msg_perm.cuid = old.msg_perm.cuid;
	buf->msg_perm.cgid = old.msg_perm.cgid;
	buf->msg_perm.mode = old.msg_perm.mode;
	buf->msg_perm.__seq = old.msg_perm.__seq;
	buf->msg_stime = old.msg_stime;
	buf->msg_rtime = old.msg_rtime;
	buf->msg_ctime = old.msg_ctime;
	buf->__msg_cbytes = old.__msg_cbytes;
	buf->msg_qnum = old.msg_qnum;
	buf->msg_qbytes = old.msg_qbytes;
	buf->msg_lspid = old.msg_lspid;
	buf->msg_lrpid = old.msg_lrpid;
      }
    return result;
  }
#endif
}
/* If ACT is not NULL, change the action for SIG to *ACT.
   If OACT is not NULL, put the old action for SIG in *OACT.  */
int
__libc_sigaction (int sig, const struct sigaction *act, struct sigaction *oact)
{
#if __ASSUME_REALTIME_SIGNALS == 0
  struct old_kernel_sigaction k_newact, k_oldact;
#endif
  int result;

#ifdef __NR_rt_sigaction

  /* First try the RT signals.  */
# if __ASSUME_REALTIME_SIGNALS == 0
  if (!__libc_missing_rt_sigs)
# endif
    {
      struct kernel_sigaction kact, koact;
# if __ASSUME_REALTIME_SIGNALS == 0
      int saved_errno = errno;
# endif

      if (act)
	{
	  kact.k_sa_handler = act->sa_handler;
	  kact.sa_flags = act->sa_flags;
	  memcpy (&kact.sa_mask, &act->sa_mask, sizeof (sigset_t));

	  if (GLRO(dl_sysinfo_dso) == NULL)
	    {
	      kact.sa_flags |= SA_RESTORER;

	      kact.sa_restorer = ((act->sa_flags & SA_SIGINFO)
				  ? &restore_rt : &restore);
	    }
	}

      /* XXX The size argument hopefully will have to be changed to the
	 real size of the user-level sigset_t.  */
      result = INLINE_SYSCALL (rt_sigaction, 4,
			       sig, act ? __ptrvalue (&kact) : NULL,
			       oact ? __ptrvalue (&koact) : NULL, _NSIG / 8);

# if __ASSUME_REALTIME_SIGNALS == 0
      if (result >= 0 || errno != ENOSYS)
# endif
	{
	  if (oact && result >= 0)
	    {
	      oact->sa_handler = koact.k_sa_handler;
	      memcpy (&oact->sa_mask, &koact.sa_mask, sizeof (sigset_t));
	      oact->sa_flags = koact.sa_flags;
	      oact->sa_restorer = koact.sa_restorer;
	    }
	  return result;
	}

# if __ASSUME_REALTIME_SIGNALS == 0
      __set_errno (saved_errno);
      __libc_missing_rt_sigs = 1;
# endif
    }
#endif

#if __ASSUME_REALTIME_SIGNALS == 0
  if (act)
    {
      k_newact.k_sa_handler = act->sa_handler;
      k_newact.sa_mask = act->sa_mask.__val[0];
      k_newact.sa_flags = act->sa_flags | SA_RESTORER;

      k_newact.sa_restorer = &restore;
    }

  result = INLINE_SYSCALL (sigaction, 3, sig,
			   act ? __ptrvalue (&k_newact) : 0,
			   oact ? __ptrvalue (&k_oldact) : 0);

  if (result < 0)
    return -1;

  if (oact)
    {
      oact->sa_handler = k_oldact.k_sa_handler;
      oact->sa_mask.__val[0] = k_oldact.sa_mask;
      oact->sa_flags = k_oldact.sa_flags;
      oact->sa_restorer = k_oldact.sa_restorer;
    }

  return 0;
#endif
}
Exemple #26
0
/* Get information about the file NAME in BUF.  */
int
__fxstatat (int vers, int fd, const char *file, struct stat *st, int flag)
{
  int result;
  INTERNAL_SYSCALL_DECL (err);
#ifdef STAT_IS_KERNEL_STAT
# define kst (*st)
#else
  struct kernel_stat kst;
#endif

#ifdef __NR_newfstatat
# ifndef __ASSUME_ATFCTS
  if (__have_atfcts >= 0)
# endif
    {
      result = INTERNAL_SYSCALL (newfstatat, err, 4, fd, file, &kst, flag);
# ifndef __ASSUME_ATFCTS
      if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (result, err), 1)
	  && INTERNAL_SYSCALL_ERRNO (result, err) == ENOSYS)
	__have_atfcts = -1;
      else
# endif
	if (!__builtin_expect (INTERNAL_SYSCALL_ERROR_P (result, err), 1))
	  {
#ifdef STAT_IS_KERNEL_STAT
	    return 0;
#else
	    return __xstat_conv (vers, &kst, st);
#endif
	  }
	else
	  {
	    __set_errno (INTERNAL_SYSCALL_ERRNO (result, err));
	    return -1;
	  }
    }
#endif

  if (flag & ~AT_SYMLINK_NOFOLLOW)
    {
      __set_errno (EINVAL);
      return -1;
    }

  char *buf = NULL;

  if (fd != AT_FDCWD && file[0] != '/')
    {
      size_t filelen = strlen (file);
      if (__builtin_expect (filelen == 0, 0))
	{
	  __set_errno (ENOENT);
	  return -1;
	}

      static const char procfd[] = "/proc/self/fd/%d/%s";
      /* Buffer for the path name we are going to use.  It consists of
	 - the string /proc/self/fd/
	 - the file descriptor number
	 - the file name provided.
	 The final NUL is included in the sizeof.   A bit of overhead
	 due to the format elements compensates for possible negative
	 numbers.  */
      size_t buflen = sizeof (procfd) + sizeof (int) * 3 + filelen;
      buf = alloca (buflen);

      __snprintf (buf, buflen, procfd, fd, file);
      file = buf;
    }

  if (vers == _STAT_VER_KERNEL)
    {
      if (flag & AT_SYMLINK_NOFOLLOW)
	result = INTERNAL_SYSCALL (lstat, err, 2, CHECK_STRING (file),
				   CHECK_1 ((struct kernel_stat *) st));
      else
	result = INTERNAL_SYSCALL (stat, err, 2, CHECK_STRING (file),
				   CHECK_1 ((struct kernel_stat *) st));

      if (__builtin_expect (!INTERNAL_SYSCALL_ERROR_P (result, err), 1))
	return result;
    }
#ifdef STAT_IS_KERNEL_STAT
  else
    {
      __set_errno (EINVAL);
      return -1;
    }
#else
  if (flag & AT_SYMLINK_NOFOLLOW)
    result = INTERNAL_SYSCALL (lstat, err, 2, CHECK_STRING (file),
			       __ptrvalue (&kst));
  else
    result = INTERNAL_SYSCALL (stat, err, 2, CHECK_STRING (file),
			       __ptrvalue (&kst));

  if (__builtin_expect (!INTERNAL_SYSCALL_ERROR_P (result, err), 1))
    return __xstat_conv (vers, &kst, st);
#endif

  __atfct_seterrno (INTERNAL_SYSCALL_ERRNO (result, err), fd, buf);

  return -1;
}
Exemple #27
0
long int
ptrace (enum __ptrace_request request, ...)
{
  long int res, ret;
  va_list ap;
  pid_t pid;
  void *addr, *data;

  va_start (ap, request);
  pid = va_arg (ap, pid_t);
  addr = va_arg (ap, void *);
  data = va_arg (ap, void *);
  va_end (ap);

  if (request > 0 && request < 4)
    data = &ret;

#if __BOUNDED_POINTERS__
  switch (request)
    {
    case PTRACE_PEEKTEXT:
    case PTRACE_PEEKDATA:
    case PTRACE_PEEKUSER:
    case PTRACE_POKETEXT:
    case PTRACE_POKEDATA:
    case PTRACE_POKEUSER:
      (void) CHECK_1 ((int *) addr);
      (void) CHECK_1 ((int *) data);
      break;

    case PTRACE_GETREGS:
    case PTRACE_SETREGS:
#ifdef __i386__
      (void) CHECK_1 ((struct user_regs_struct *) data);
#else
      /* We don't know the size of data, so the best we can do is ensure
	 that `data' is valid for at least one word.  */
      (void) CHECK_1 ((int *) data);
#endif
      break;

    case PTRACE_GETFPREGS:
    case PTRACE_SETFPREGS:
#ifdef __i386__
      (void) CHECK_1 ((struct user_fpregs_struct *) data);
#else
      /* We don't know the size of data, so the best we can do is ensure
	 that `data' is valid for at least one word.  */
      (void) CHECK_1 ((int *) data);
#endif
      break;

    case PTRACE_GETFPXREGS:
    case PTRACE_SETFPXREGS:
#ifdef __i386__
      (void) CHECK_1 ((struct user_fpxregs_struct *) data);
#else
      /* We don't know the size of data, so the best we can do is ensure
	 that `data' is valid for at least one word.  */
      (void) CHECK_1 ((int *) data);
#endif
      break;

    case PTRACE_GETSIGINFO:
    case PTRACE_SETSIGINFO:
      (void) CHECK_1 ((siginfo_t *) data);
      break;

    case PTRACE_GETEVENTMSG:
      (void) CHECK_1 ((unsigned long *) data);
      break;

    case PTRACE_SETOPTIONS:
      (void) CHECK_1 ((long *) data);
      break;

    case PTRACE_TRACEME:
    case PTRACE_CONT:
    case PTRACE_KILL:
    case PTRACE_SINGLESTEP:
    case PTRACE_ATTACH:
    case PTRACE_DETACH:
    case PTRACE_SYSCALL:
      /* Neither `data' nor `addr' needs any checks.  */
      break;
    };
#endif

  res = INLINE_SYSCALL (ptrace, 4, request, pid,
			__ptrvalue (addr), __ptrvalue (data));
  if (res >= 0 && request > 0 && request < 4)
    {
      __set_errno (0);
      return ret;
    }

  return res;
}
int
__fxstatat64 (int vers, int fd, const char *file, struct stat64 *st, int flag)
{
  if (__builtin_expect (vers != _STAT_VER_LINUX, 0))
    {
      __set_errno (EINVAL);
      return -1;
    }

  int result;
  INTERNAL_SYSCALL_DECL (err);

#ifdef __NR_fstatat64
# ifndef __ASSUME_ATFCTS
  if (__have_atfcts >= 0)
# endif
    {
      result = INTERNAL_SYSCALL (fstatat64, err, 4, fd, file, st, flag);
# ifndef __ASSUME_ATFCTS
      if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (result, err), 1)
	  && INTERNAL_SYSCALL_ERRNO (result, err) == ENOSYS)
	__have_atfcts = -1;
      else
# endif
	if (!__builtin_expect (INTERNAL_SYSCALL_ERROR_P (result, err), 1))
	  return 0;
	else
	  {
	    __set_errno (INTERNAL_SYSCALL_ERRNO (result, err));
	    return -1;
	  }
    }
#endif

#ifndef __ASSUME_ATFCTS
  if (flag & ~AT_SYMLINK_NOFOLLOW)
    {
      __set_errno (EINVAL);
      return -1;
    }

  char *buf = NULL;

  if (fd != AT_FDCWD && file[0] != '/')
    {
      size_t filelen = strlen (file);
      static const char procfd[] = "/proc/self/fd/%d/%s";
      /* Buffer for the path name we are going to use.  It consists of
	 - the string /proc/self/fd/
	 - the file descriptor number
	 - the file name provided.
	 The final NUL is included in the sizeof.   A bit of overhead
	 due to the format elements compensates for possible negative
	 numbers.  */
      size_t buflen = sizeof (procfd) + sizeof (int) * 3 + filelen;
      buf = alloca (buflen);

      __snprintf (buf, buflen, procfd, fd, file);
      file = buf;
    }

# if __ASSUME_STAT64_SYSCALL > 0
  if (flag & AT_SYMLINK_NOFOLLOW)
    result = INTERNAL_SYSCALL (lstat64, err, 2, CHECK_STRING (file),
			       CHECK_1 (st));
  else
    result = INTERNAL_SYSCALL (stat64, err, 2, CHECK_STRING (file),
			       CHECK_1 (st));
  if (__builtin_expect (!INTERNAL_SYSCALL_ERROR_P (result, err), 1))
    {
#  if defined _HAVE_STAT64___ST_INO && __ASSUME_ST_INO_64_BIT == 0
      if (st->__st_ino != (__ino_t) st->st_ino)
	st->st_ino = st->__st_ino;
#  endif
      return result;
    }
# else
  struct kernel_stat kst;
#  ifdef __NR_stat64
  if (! __have_no_stat64)
    {
      if (flag & AT_SYMLINK_NOFOLLOW)
	result = INTERNAL_SYSCALL (lstat64, err, 2, CHECK_STRING (file),
				   CHECK_1 (st));
      else
	result = INTERNAL_SYSCALL (stat64, err, 2, CHECK_STRING (file),
				   CHECK_1 (st));

      if (__builtin_expect (!INTERNAL_SYSCALL_ERROR_P (result, err), 1))
	{
#   if defined _HAVE_STAT64___ST_INO && __ASSUME_ST_INO_64_BIT == 0
	  if (st->__st_ino != (__ino_t) st->st_ino)
	    st->st_ino = st->__st_ino;
#   endif
	  return result;
	}
      if (INTERNAL_SYSCALL_ERRNO (result, err) != ENOSYS)
	goto fail;

      __have_no_stat64 = 1;
    }
#  endif

  if (flag & AT_SYMLINK_NOFOLLOW)
    result = INTERNAL_SYSCALL (lstat, err, 2, CHECK_STRING (file),
			       __ptrvalue (&kst));
  else
    result = INTERNAL_SYSCALL (stat, err, 2, CHECK_STRING (file),
			       __ptrvalue (&kst));

  if (__builtin_expect (!INTERNAL_SYSCALL_ERROR_P (result, err), 1))
    return __xstat64_conv (vers, &kst, st);

 fail:
# endif
  __atfct_seterrno (INTERNAL_SYSCALL_ERRNO (result, err), fd, buf);

  return -1;
#endif
}
/* Get information about the file NAME relative to FD in ST.  */
int
__fxstatat (int vers, int fd, const char *file, struct stat *st, int flag)
{
  int result;
  INTERNAL_SYSCALL_DECL (err);
  struct stat64 st64;

#ifdef __NR_fstatat64
# ifndef __ASSUME_ATFCTS
  if (__have_atfcts >= 0)
# endif
    {
      result = INTERNAL_SYSCALL (fstatat64, err, 4, fd, file, &st64, flag);
# ifndef __ASSUME_ATFCTS
      if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (result, err), 1)
	  && INTERNAL_SYSCALL_ERRNO (result, err) == ENOSYS)
	__have_atfcts = -1;
      else
# endif
	if (!__builtin_expect (INTERNAL_SYSCALL_ERROR_P (result, err), 1))
	  return __xstat32_conv (vers, &st64, st);
	else
	  {
	    __set_errno (INTERNAL_SYSCALL_ERRNO (result, err));
	    return -1;
	  }
    }
#endif

#ifndef __ASSUME_ATFCTS
  if (__builtin_expect (flag & ~AT_SYMLINK_NOFOLLOW, 0))
    {
      __set_errno (EINVAL);
      return -1;
    }

  char *buf = NULL;

  if (fd != AT_FDCWD && file[0] != '/')
    {
      size_t filelen = strlen (file);
      static const char procfd[] = "/proc/self/fd/%d/%s";
      /* Buffer for the path name we are going to use.  It consists of
	 - the string /proc/self/fd/
	 - the file descriptor number
	 - the file name provided.
	 The final NUL is included in the sizeof.   A bit of overhead
	 due to the format elements compensates for possible negative
	 numbers.  */
      size_t buflen = sizeof (procfd) + sizeof (int) * 3 + filelen;
      buf = alloca (buflen);

      __snprintf (buf, buflen, procfd, fd, file);
      file = buf;
    }

# if __ASSUME_STAT64_SYSCALL == 0
  struct kernel_stat kst;
# endif
  if (vers == _STAT_VER_KERNEL)
    {
      if (flag & AT_SYMLINK_NOFOLLOW)
	result = INTERNAL_SYSCALL (lstat, err, 2, CHECK_STRING (file),
				   CHECK_1 ((struct kernel_stat *) st));
      else
	result = INTERNAL_SYSCALL (stat, err, 2, CHECK_STRING (file),
				   CHECK_1 ((struct kernel_stat *) st));
      goto out;
    }

# if __ASSUME_STAT64_SYSCALL > 0

  if (flag & AT_SYMLINK_NOFOLLOW)
    result = INTERNAL_SYSCALL (lstat64, err, 2, CHECK_STRING (file),
			       __ptrvalue (&st64));
  else
    result = INTERNAL_SYSCALL (stat64, err, 2, CHECK_STRING (file),
			       __ptrvalue (&st64));
  if (__builtin_expect (!INTERNAL_SYSCALL_ERROR_P (result, err), 1))
    return __xstat32_conv (vers, &st64, st);
# else
#  if defined __NR_stat64
  /* To support 32 bit UIDs, we have to use stat64.  The normal stat
     call only returns 16 bit UIDs.  */
  if (! __have_no_stat64)
    {
      if (flag & AT_SYMLINK_NOFOLLOW)
	result = INTERNAL_SYSCALL (lstat64, err, 2, CHECK_STRING (file),
				   __ptrvalue (&st64));
      else
	result = INTERNAL_SYSCALL (stat64, err, 2, CHECK_STRING (file),
				   __ptrvalue (&st64));

      if (__builtin_expect (!INTERNAL_SYSCALL_ERROR_P (result, err), 1))
	result = __xstat32_conv (vers, &st64, st);

      if (__builtin_expect (!INTERNAL_SYSCALL_ERROR_P (result, err), 1)
	  || INTERNAL_SYSCALL_ERRNO (result, err) != ENOSYS)
	goto out;

      __have_no_stat64 = 1;
    }
#  endif
  if (flag & AT_SYMLINK_NOFOLLOW)
    result = INTERNAL_SYSCALL (lstat, err, 2, CHECK_STRING (file),
			       __ptrvalue (&kst));
  else
    result = INTERNAL_SYSCALL (stat, err, 2, CHECK_STRING (file),
			       __ptrvalue (&kst));
  if (__builtin_expect (!INTERNAL_SYSCALL_ERROR_P (result, err), 1))
    return __xstat_conv (vers, &kst, st);
# endif  /* __ASSUME_STAT64_SYSCALL  */

 out:
  if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (result, err), 0))
    {
      __atfct_seterrno (INTERNAL_SYSCALL_ERRNO (result, err), fd, buf);
      result = -1;
    }

  return result;
#endif
}