diff --git a/src/kopenafs/Makefile.in b/src/kopenafs/Makefile.in index dceeb16422..25a5f03afd 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 727e05a617..746a4b5549 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 cfa2aa43ef..3bdbc19974 100644 --- a/src/kopenafs/kopenafs.h +++ b/src/kopenafs/kopenafs.h @@ -37,6 +37,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 2220a046eb..0bc3f66a13 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 dc11673bcb..fa3a5fffc0 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; }