[BUILTIN] Use faccessat if available

Eric Blake suggested that we should use faccessat so that ACLs
and other corner cases are handled correctly.  This patch does
exactly that.

Note that faccessat doesn't handle ACLs when euid != uid, as
this case is currently implemented by glibc instead of the kernel,
using code similar to the existing dash test.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
This commit is contained in:
Herbert Xu 2010-04-02 22:02:22 +08:00
parent 02a568bb14
commit 1d68712ba2
3 changed files with 28 additions and 1 deletions

View File

@ -1,3 +1,7 @@
2010-04-02 Herbert Xu <herbert@gondor.apana.org.au>
* Use faccessat if available.
2010-04-02 Herbert Xu <herbert@gondor.apana.org.au>
* Make trap signal name/number errors non-fatal.

View File

@ -46,7 +46,8 @@ dnl Checks for header files.
AC_CHECK_HEADERS(alloca.h)
dnl Checks for library functions.
AC_CHECK_FUNCS(bsearch getpwnam getrlimit imaxdiv isalpha killpg mempcpy \
AC_CHECK_FUNCS(bsearch faccessat getpwnam getrlimit imaxdiv isalpha killpg \
mempcpy \
sigsetmask stpcpy strchrnul strsignal strtod strtoimax \
strtoumax sysconf)

View File

@ -11,6 +11,7 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
@ -147,8 +148,12 @@ static int isoperand(char **);
static int newerf(const char *, const char *);
static int olderf(const char *, const char *);
static int equalf(const char *, const char *);
#ifdef HAVE_FACCESSAT
static int test_file_access(const char *, int);
#else
static int test_st_mode(const struct stat64 *, int);
static int bash_group_member(gid_t);
#endif
static inline intmax_t getn(const char *s)
{
@ -295,6 +300,14 @@ primary(enum token n)
return strlen(*t_wp) != 0;
case FILTT:
return isatty(getn(*t_wp));
#ifdef HAVE_FACCESSAT
case FILRD:
return test_file_access(*t_wp, R_OK);
case FILWR:
return test_file_access(*t_wp, W_OK);
case FILEX:
return test_file_access(*t_wp, X_OK);
#endif
default:
return filstat(*t_wp, n);
}
@ -364,12 +377,14 @@ filstat(char *nm, enum token mode)
return 0;
switch (mode) {
#ifndef HAVE_FACCESSAT
case FILRD:
return test_st_mode(&s, R_OK);
case FILWR:
return test_st_mode(&s, W_OK);
case FILEX:
return test_st_mode(&s, X_OK);
#endif
case FILEXIST:
return 1;
case FILREG:
@ -469,6 +484,12 @@ equalf (const char *f1, const char *f2)
b1.st_ino == b2.st_ino);
}
#ifdef HAVE_FACCESSAT
static int test_file_access(const char *path, int mode)
{
return !faccessat(AT_FDCWD, path, mode, AT_EACCESS);
}
#else /* HAVE_FACCESSAT */
/*
* Similar to what access(2) does, but uses the effective uid and gid.
* Doesn't make the mistake of telling root that any file is executable.
@ -519,3 +540,4 @@ bash_group_member(gid_t gid)
return (0);
}
#endif /* HAVE_FACCESSAT */