From 5f2c6bd341674618d14658d0f642465b0f0259b9 Mon Sep 17 00:00:00 2001 From: Russ Allbery Date: Wed, 26 May 2010 23:23:10 -0500 Subject: [PATCH] Add k_haspag to libkopenafs Add the k_haspag function to libkopenafs, which returns true if the current process is in a PAG and false otherwise. The implementation currently duplicates code from the ktc_curpag function since the latter calls the regular pioctl() interface and hence introduces an Rx dependency that we're avoiding for libkopenafs. This should be refactored to avoid the code duplication at some point, but that will require building a utility library that can be reasonably linked into libkopenafs and is therefore deferred for future work. Change-Id: Ib97322ef24dc3a4e48cb45090c516c95b71e9fc7 Reviewed-on: http://gerrit.openafs.org/2041 Reviewed-by: Derrick Brashear Tested-by: Derrick Brashear --- src/kopenafs/Makefile.in | 2 +- src/kopenafs/kopenafs.c | 111 +++++++++++++++++++++++++++++++++++++++++-- src/kopenafs/kopenafs.h | 6 +++ src/kopenafs/libkopenafs.map | 1 + src/kopenafs/test-setpag.c | 7 +++ 5 files changed, 123 insertions(+), 4 deletions(-) diff --git a/src/kopenafs/Makefile.in b/src/kopenafs/Makefile.in index dceeb16..25a5f03 100644 --- a/src/kopenafs/Makefile.in +++ b/src/kopenafs/Makefile.in @@ -17,7 +17,7 @@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ # API version. When something changes, increment as appropriate. # Ignore at your own risk. MAJOR = 1 -MINOR = 0 +MINOR = 1 CC = ${MT_CC} INCLUDES = -I. -I${srcdir} -I../sys diff --git a/src/kopenafs/kopenafs.c b/src/kopenafs/kopenafs.c index 727e05a..746a4b5 100644 --- a/src/kopenafs/kopenafs.c +++ b/src/kopenafs/kopenafs.c @@ -12,14 +12,23 @@ * included in the libsys code. */ -#include -#include #include -#include +#include #include +#include +#ifdef AFS_AIX51_ENV +# include +# ifdef HAVE_SYS_PAG_H +# include +# endif +#endif +#include +#include +#include #include #include +#include #include static volatile sig_atomic_t syscall_okay = 1; @@ -87,3 +96,99 @@ k_unlog(void) iob.out_size = 0; return lpioctl(NULL, VIOCUNLOG, &iob, 0); } + + +/* + * If we don't have the VIOC_GETPAG pioctl, we try to determine whether we're + * in a PAG by using either a special OS call (AIX 5.2 and later) or by + * walking the group list, which works differently for current versions of + * Linux. + * + * These OS differences are encapsulated in the following OS-specific haspag + * helper functions. + * + * This is largely copied from auth/ktc.c and should be merged with that + * version, but that version calls through the pioctl() interface right now + * and therefore pulls in Rx for NFS translator support. This avoids an Rx + * dependency in the standalone libkopenafs interface. + */ +#if defined(AFS_AIX52_ENV) +static int +os_haspag(void) +{ + return (getpagvalue("afs") < 0) ? 0 : 1; +} +#elif defined(AFS_AIX51_ENV) +static int +os_haspag(void) +{ + return 0; +} +#else +static int +os_haspag(void) +{ + int ngroups; + gid_t *groups; + afs_uint32 g0, g1; + afs_uint32 h, l, pag; +# ifdef AFS_LINUX26_ENV + int i; +# endif + + ngroups = getgroups(0, NULL); + groups = malloc(sizeof(*groups) * ngroups); + if (groups == NULL) + return 0; + ngroups = getgroups(ngroups, groups); + + /* Check for AFS_LINUX26_ONEGROUP_ENV PAGs. */ +# ifdef AFS_LINUX26_ENV + for (i = 0; i < ngroups; i++) + if (((groups[i] >> 24) & 0xff) == 'A') { + free(groups); + return 1; + } +# endif + + /* Check for the PAG group pair. */ + if (ngroups < 2) { + free(groups); + return 0; + } + g0 = groups[0] & 0xffff; + g1 = groups[1] & 0xffff; + free(groups); + g0 -= 0x3f00; + g1 -= 0x3f00; + if (g0 < 0xc000 && g1 < 0xc000) { + l = ((g0 & 0x3fff) << 14) | (g1 & 0x3fff); + h = (g0 >> 14); + h = (g1 >> 14) + h + h + h; + pag = ((h << 28) | l); + if (((pag >> 24) & 0xff) == 'A') + return 1; + else + return 0; + } + return 0; +} +#endif /* !AFS_AIX51_ENV */ + +int +k_haspag(void) +{ + int code; + struct ViceIoctl iob; + afs_uint32 pag; + + iob.in = NULL; + iob.in_size = 0; + iob.out = (caddr_t) &pag; + iob.out_size = sizeof(afs_uint32); + code = lpioctl(NULL, VIOC_GETPAG, &iob, 0); + if (code == 0) + return pag != (afs_uint32) -1; + else + return os_haspag(); +} diff --git a/src/kopenafs/kopenafs.h b/src/kopenafs/kopenafs.h index cfa2aa4..3bdbc19 100644 --- a/src/kopenafs/kopenafs.h +++ b/src/kopenafs/kopenafs.h @@ -38,6 +38,12 @@ int k_hasafs(void); int k_setpag(void); /* + * Returns true if the current process is in a PAG and false if it is not or + * if an error was encountered in determining whether it is in a PAG. + */ +int k_haspag(void); + +/* * Remove the tokens in the current PAG. Returns 0 on success, non-zero on * system call failure. */ diff --git a/src/kopenafs/libkopenafs.map b/src/kopenafs/libkopenafs.map index 2220a04..0bc3f66 100644 --- a/src/kopenafs/libkopenafs.map +++ b/src/kopenafs/libkopenafs.map @@ -6,6 +6,7 @@ KOPENAFS_1.0 { global: k_hasafs; k_setpag; + k_haspag; k_unlog; k_pioctl; local: diff --git a/src/kopenafs/test-setpag.c b/src/kopenafs/test-setpag.c index dc11673..fa3a5ff 100644 --- a/src/kopenafs/test-setpag.c +++ b/src/kopenafs/test-setpag.c @@ -13,6 +13,9 @@ #include #include +#include + +#include int main(int argc, char *argv[]) @@ -20,9 +23,12 @@ main(int argc, char *argv[]) int status; if (k_hasafs()) { + printf("%s in a PAG\n", k_haspag() ? "Currently" : "Not currently"); printf("Running k_setpag\n"); status = k_setpag(); printf("Status: %d, errno: %d\n", status, errno); + if (!k_haspag()) + printf("Error: not in a PAG after k_setpag()\n"); if (argc > 1) { argv++; execvp(argv[0], argv); @@ -30,4 +36,5 @@ main(int argc, char *argv[]) } else { printf("AFS apparently not running\n"); } + return 0; } -- 1.9.4