Add k_haspag to libkopenafs
authorRuss Allbery <rra@stanford.edu>
Thu, 27 May 2010 04:23:10 +0000 (23:23 -0500)
committerDerrick Brashear <shadow@dementia.org>
Fri, 28 May 2010 02:52:07 +0000 (19:52 -0700)
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 <shadow@dementia.org>
Tested-by: Derrick Brashear <shadow@dementia.org>

src/kopenafs/Makefile.in
src/kopenafs/kopenafs.c
src/kopenafs/kopenafs.h
src/kopenafs/libkopenafs.map
src/kopenafs/test-setpag.c

index dceeb16..25a5f03 100644 (file)
@@ -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
index 727e05a..746a4b5 100644 (file)
  * included in the libsys code.
  */
 
-#include <sys/param.h>
-#include <netinet/in.h>
 #include <errno.h>
-#include <stdlib.h>
+#include <netinet/in.h>
 #include <signal.h>
+#include <stdlib.h>
+#ifdef AFS_AIX51_ENV
+# include <sys/cred.h>
+# ifdef HAVE_SYS_PAG_H
+#  include <sys/pag.h>
+# endif
+#endif
+#include <sys/param.h>
+#include <sys/types.h>
+#include <unistd.h>
 
 #include <afsconfig.h>
 #include <afs/afssyscalls.h>
+#include <afs/param.h>
 #include <kopenafs.h>
 
 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();
+}
index cfa2aa4..3bdbc19 100644 (file)
@@ -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.
  */
index 2220a04..0bc3f66 100644 (file)
@@ -6,6 +6,7 @@ KOPENAFS_1.0 {
     global:
         k_hasafs;
         k_setpag;
+        k_haspag;
         k_unlog;
         k_pioctl;
     local:
index dc11673..fa3a5ff 100644 (file)
@@ -13,6 +13,9 @@
 
 #include <errno.h>
 #include <stdio.h>
+#include <unistd.h>
+
+#include <kopenafs.h>
 
 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;
 }