libafs: Initialize _settok_tokenCell primary flag
[openafs.git] / src / afs / afs_pioctl.c
index 3601aad..a8d8169 100644 (file)
 #ifdef AFS_OBSD_ENV
 #include "h/syscallargs.h"
 #endif
-#ifdef AFS_FBSD50_ENV
+#ifdef AFS_FBSD_ENV
 #include "h/sysproto.h"
 #endif
+#ifdef AFS_NBSD40_ENV
+#include <sys/ioctl.h>
+#include <sys/ioccom.h>
+#endif
 #include "afsincludes.h"       /* Afs-based standard headers */
 #include "afs/afs_stats.h"     /* afs statistics */
 #include "afs/vice.h"
 #include "afs/afs_bypasscache.h"
 #include "rx/rx_globals.h"
+#include "token.h"
 
 struct VenusFid afs_rootFid;
 afs_int32 afs_waitForever = 0;
 short afs_waitForeverCount = 0;
 afs_int32 afs_showflags = GAGUSER | GAGCONSOLE;        /* show all messages */
 
-#ifdef AFS_DISCON_ENV
 afs_int32 afs_is_disconnected;
 afs_int32 afs_is_discon_rw;
 /* On reconnection, turn this knob on until it finishes,
  * then turn it off.
  */
 afs_int32 afs_in_sync = 0;
-#endif
+
+struct afs_pdata {
+    char *ptr;
+    size_t remaining;
+};
+
+/*
+ * A set of handy little functions for encoding and decoding
+ * pioctls without losing your marbles, or memory integrity
+ */
+
+static_inline int
+afs_pd_alloc(struct afs_pdata *apd, size_t size)
+{
+
+    if (size > AFS_LRALLOCSIZ)
+       apd->ptr = osi_Alloc(size + 1);
+    else
+       apd->ptr = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
+
+    if (apd->ptr == NULL)
+       return ENOMEM;
+
+    apd->remaining = size;
+
+    return 0;
+}
+
+static_inline void
+afs_pd_free(struct afs_pdata *apd)
+{
+    if (apd->ptr == NULL)
+       return;
+
+    if (apd->remaining > AFS_LRALLOCSIZ)
+       osi_Free(apd->ptr, apd->remaining + 1);
+    else
+       osi_FreeLargeSpace(apd->ptr);
+
+    apd->ptr = NULL;
+    apd->remaining = 0;
+}
+
+static_inline char *
+afs_pd_where(struct afs_pdata *apd)
+{
+    return apd ? apd->ptr : NULL;
+}
+
+static_inline size_t
+afs_pd_remaining(struct afs_pdata *apd)
+{
+    return apd ? apd->remaining : 0;
+}
+
+static_inline int
+afs_pd_skip(struct afs_pdata *apd, size_t skip)
+{
+    if (apd == NULL || apd->remaining < skip)
+       return EINVAL;
+    apd->remaining -= skip;
+    apd->ptr += skip;
+
+    return 0;
+}
+
+static_inline int
+afs_pd_getBytes(struct afs_pdata *apd, void *dest, size_t bytes)
+{
+    if (apd == NULL || apd->remaining < bytes)
+       return EINVAL;
+    apd->remaining -= bytes;
+    memcpy(dest, apd->ptr, bytes);
+    apd->ptr += bytes;
+    return 0;
+}
+
+static_inline int
+afs_pd_getInt(struct afs_pdata *apd, afs_int32 *val)
+{
+    return afs_pd_getBytes(apd, val, sizeof(*val));
+}
+
+static_inline int
+afs_pd_getUint(struct afs_pdata *apd, afs_uint32 *val)
+{
+    return afs_pd_getBytes(apd, val, sizeof(*val));
+}
+
+static_inline void *
+afs_pd_inline(struct afs_pdata *apd, size_t bytes)
+{
+    void *ret;
+
+    if (apd == NULL || apd->remaining < bytes)
+       return NULL;
+
+    ret = apd->ptr;
+
+    apd->remaining -= bytes;
+    apd->ptr += bytes;
+
+    return ret;
+}
+
+static_inline void
+afs_pd_xdrStart(struct afs_pdata *apd, XDR *xdrs, enum xdr_op op) {
+    xdrmem_create(xdrs, apd->ptr, apd->remaining, op);
+}
+
+static_inline void
+afs_pd_xdrEnd(struct afs_pdata *apd, XDR *xdrs) {
+    size_t pos;
+
+    pos = xdr_getpos(xdrs);
+    apd->ptr += pos;
+    apd->remaining -= pos;
+    xdr_destroy(xdrs);
+}
+
+
+
+static_inline int
+afs_pd_getString(struct afs_pdata *apd, char *str, size_t maxLen)
+{
+    size_t len;
+
+    if (apd == NULL || apd->remaining <= 0)
+       return EINVAL;
+    len = strlen(apd->ptr) + 1;
+    if (len > maxLen)
+       return E2BIG;
+    memcpy(str, apd->ptr, len);
+    apd->ptr += len;
+    apd->remaining -= len;
+    return 0;
+}
+
+static_inline int
+afs_pd_getStringPtr(struct afs_pdata *apd, char **str)
+{
+    size_t len;
+
+    if (apd == NULL || apd->remaining <= 0)
+       return EINVAL;
+    len = strlen(apd->ptr) + 1;
+    *str = apd->ptr;
+    apd->ptr += len;
+    apd->remaining -= len;
+    return 0;
+}
+
+static_inline int
+afs_pd_putBytes(struct afs_pdata *apd, const void *bytes, size_t len)
+{
+    if (apd == NULL || apd->remaining < len)
+       return E2BIG;
+    memcpy(apd->ptr, bytes, len);
+    apd->ptr += len;
+    apd->remaining -= len;
+    return 0;
+}
+
+static_inline int
+afs_pd_putInt(struct afs_pdata *apd, afs_int32 val)
+{
+    return afs_pd_putBytes(apd, &val, sizeof(val));
+}
+
+static_inline int
+afs_pd_putString(struct afs_pdata *apd, char *str) {
+
+    /* Add 1 so we copy the NULL too */
+    return afs_pd_putBytes(apd, str, strlen(str) +1);
+}
 
 /*!
  * \defgroup pioctl Path IOCTL functions
  *
  * DECL_PIOCTL is a macro defined to contain the following parameters for functions:
  *
- * \param[in] avc      the AFS vcache structure in use by pioctl
- * \param[in] afun     not in use
- * \param[in] areq     the AFS vrequest structure
- * \param[in] ain      as defined by the function
- * \param[in] aout     as defined by the function
- * \param[in] ainSize  size of ain
- * \param[in] aoutSize size of aout
- * \param[in] acred    UNIX credentials structure underlying the operation
+ * \param[in] avc
+ *     the AFS vcache structure in use by pioctl
+ * \param[in] afun
+ *     not in use
+ * \param[in] areq
+ *     the AFS vrequest structure
+ * \param[in] ain
+ *     an afs_pdata block describing the data received from the caller
+ * \param[in] aout
+ *     an afs_pdata block describing a pre-allocated block for output
+ * \param[in] acred
+ *     UNIX credentials structure underlying the operation
  */
 
-#define DECL_PIOCTL(x) static int x(struct vcache *avc, int afun, struct vrequest *areq, \
-       char *ain, char *aout, afs_int32 ainSize, afs_int32 *aoutSize, \
-       afs_ucred_t **acred)
+#define DECL_PIOCTL(x) \
+       static int x(struct vcache *avc, int afun, struct vrequest *areq, \
+                    struct afs_pdata *ain, struct afs_pdata *aout, \
+                    afs_ucred_t **acred)
 
 /* Prototypes for pioctl routines */
 DECL_PIOCTL(PGetFID);
@@ -69,11 +252,13 @@ DECL_PIOCTL(PGetFileCell);
 DECL_PIOCTL(PGetWSCell);
 DECL_PIOCTL(PGetUserCell);
 DECL_PIOCTL(PSetTokens);
+DECL_PIOCTL(PSetTokens2);
 DECL_PIOCTL(PGetVolumeStatus);
 DECL_PIOCTL(PSetVolumeStatus);
 DECL_PIOCTL(PFlush);
 DECL_PIOCTL(PNewStatMount);
 DECL_PIOCTL(PGetTokens);
+DECL_PIOCTL(PGetTokens2);
 DECL_PIOCTL(PUnlog);
 DECL_PIOCTL(PMariner);
 DECL_PIOCTL(PCheckServers);
@@ -89,7 +274,6 @@ DECL_PIOCTL(PNewAlias);
 DECL_PIOCTL(PListCells);
 DECL_PIOCTL(PListAliases);
 DECL_PIOCTL(PRemoveMount);
-DECL_PIOCTL(PVenusLogging);
 DECL_PIOCTL(PGetCellStatus);
 DECL_PIOCTL(PSetCellStatus);
 DECL_PIOCTL(PFlushVolumeData);
@@ -116,11 +300,10 @@ DECL_PIOCTL(PCallBackAddr);
 DECL_PIOCTL(PDiscon);
 DECL_PIOCTL(PNFSNukeCreds);
 DECL_PIOCTL(PNewUuid);
-DECL_PIOCTL(PPrecache); 
+DECL_PIOCTL(PPrecache);
 DECL_PIOCTL(PGetPAG);
-#if defined(AFS_CACHE_BYPASS)
+#if defined(AFS_CACHE_BYPASS) && defined(AFS_LINUX24_ENV)
 DECL_PIOCTL(PSetCachingThreshold);
-DECL_PIOCTL(PSetCachingBlkSize);
 #endif
 
 /*
@@ -137,104 +320,104 @@ static int HandleClientContext(struct afs_ioctl *ablob, int *com,
                               afs_ucred_t **acred,
                               afs_ucred_t *credp);
 #endif
-int HandleIoctl(register struct vcache *avc, register afs_int32 acom,
+int HandleIoctl(struct vcache *avc, afs_int32 acom,
                struct afs_ioctl *adata);
 int afs_HandlePioctl(struct vnode *avp, afs_int32 acom,
-                    register struct afs_ioctl *ablob, int afollow,
+                    struct afs_ioctl *ablob, int afollow,
                     afs_ucred_t **acred);
 static int Prefetch(uparmtype apath, struct afs_ioctl *adata, int afollow,
                    afs_ucred_t *acred);
 
 typedef int (*pioctlFunction) (struct vcache *, int, struct vrequest *,
-                              char *, char *, afs_int32, afs_int32 *,
+                              struct afs_pdata *, struct afs_pdata *,
                               afs_ucred_t **);
 
 static pioctlFunction VpioctlSw[] = {
     PBogus,                    /* 0 */
-       PSetAcl,                /* 1 */
-       PGetAcl,                /* 2 */
-       PSetTokens,             /* 3 */
-       PGetVolumeStatus,       /* 4 */
-       PSetVolumeStatus,       /* 5 */
-       PFlush,                 /* 6 */
-       PBogus,                 /* 7 */
-       PGetTokens,             /* 8 */
-       PUnlog,                 /* 9 */
-       PCheckServers,          /* 10 */
-       PCheckVolNames,         /* 11 */
-       PCheckAuth,             /* 12 */
-       PBogus,                 /* 13 -- used to be quick check time */
-       PFindVolume,            /* 14 */
-       PBogus,                 /* 15 -- prefetch is now special-cased; see pioctl code! */
-       PBogus,                 /* 16 -- used to be testing code */
-       PNoop,                  /* 17 -- used to be enable group */
-       PNoop,                  /* 18 -- used to be disable group */
-       PBogus,                 /* 19 -- used to be list group */
-       PViceAccess,            /* 20 */
-       PUnlog,                 /* 21 -- unlog *is* unpag in this system */
-       PGetFID,                /* 22 -- get file ID */
-       PBogus,                 /* 23 -- used to be waitforever */
-       PSetCacheSize,          /* 24 */
-       PRemoveCallBack,        /* 25 -- flush only the callback */
-       PNewCell,               /* 26 */
-       PListCells,             /* 27 */
-       PRemoveMount,           /* 28 -- delete mount point */
-       PNewStatMount,          /* 29 -- new style mount point stat */
-       PGetFileCell,           /* 30 -- get cell name for input file */
-       PGetWSCell,             /* 31 -- get cell name for workstation */
-       PMariner,               /* 32 - set/get mariner host */
-       PGetUserCell,           /* 33 -- get cell name for user */
-       PVenusLogging,          /* 34 -- Enable/Disable logging */
-       PGetCellStatus,         /* 35 */
-       PSetCellStatus,         /* 36 */
-       PFlushVolumeData,       /* 37 -- flush all data from a volume */
-       PSetSysName,            /* 38 - Set system name */
-       PExportAfs,             /* 39 - Export Afs to remote nfs clients */
-       PGetCacheSize,          /* 40 - get cache size and usage */
-       PGetVnodeXStatus,       /* 41 - get vcache's special status */
-       PSetSPrefs33,           /* 42 - Set CM Server preferences... */
-       PGetSPrefs,             /* 43 - Get CM Server preferences... */
-       PGag,                   /* 44 - turn off/on all CM messages */
-       PTwiddleRx,             /* 45 - adjust some RX params       */
-       PSetSPrefs,             /* 46 - Set CM Server preferences... */
-       PStoreBehind,           /* 47 - set degree of store behind to be done */
-       PGCPAGs,                /* 48 - disable automatic pag gc-ing */
-       PGetInitParams,         /* 49 - get initial cm params */
-       PGetCPrefs,             /* 50 - get client interface addresses */
-       PSetCPrefs,             /* 51 - set client interface addresses */
-       PFlushMount,            /* 52 - flush mount symlink data */
-       PRxStatProc,            /* 53 - control process RX statistics */
-       PRxStatPeer,            /* 54 - control peer RX statistics */
-       PGetRxkcrypt,           /* 55 -- Get rxkad encryption flag */
-       PSetRxkcrypt,           /* 56 -- Set rxkad encryption flag */
-       PBogus,                 /* 57 -- arla: set file prio */
-       PBogus,                 /* 58 -- arla: fallback getfh */
-       PBogus,                 /* 59 -- arla: fallback fhopen */
-       PBogus,                 /* 60 -- arla: controls xfsdebug */
-       PBogus,                 /* 61 -- arla: controls arla debug */
-       PBogus,                 /* 62 -- arla: debug interface */
-       PBogus,                 /* 63 -- arla: print xfs status */
-       PBogus,                 /* 64 -- arla: force cache check */
-       PBogus,                 /* 65 -- arla: break callback */
-       PPrefetchFromTape,      /* 66 -- MR-AFS: prefetch file from tape */
-       PFsCmd,                 /* 67 -- RXOSD: generic commnd interface */
-       PBogus,                 /* 68 -- arla: fetch stats */
-       PGetVnodeXStatus2,      /* 69 - get caller access and some vcache status */
+    PSetAcl,                   /* 1 */
+    PGetAcl,                   /* 2 */
+    PSetTokens,                        /* 3 */
+    PGetVolumeStatus,          /* 4 */
+    PSetVolumeStatus,          /* 5 */
+    PFlush,                    /* 6 */
+    PBogus,                    /* 7 */
+    PGetTokens,                        /* 8 */
+    PUnlog,                    /* 9 */
+    PCheckServers,             /* 10 */
+    PCheckVolNames,            /* 11 */
+    PCheckAuth,                        /* 12 */
+    PBogus,                    /* 13 -- used to be quick check time */
+    PFindVolume,               /* 14 */
+    PBogus,                    /* 15 -- prefetch is now special-cased; see pioctl code! */
+    PBogus,                    /* 16 -- used to be testing code */
+    PNoop,                     /* 17 -- used to be enable group */
+    PNoop,                     /* 18 -- used to be disable group */
+    PBogus,                    /* 19 -- used to be list group */
+    PViceAccess,               /* 20 */
+    PUnlog,                    /* 21 -- unlog *is* unpag in this system */
+    PGetFID,                   /* 22 -- get file ID */
+    PBogus,                    /* 23 -- used to be waitforever */
+    PSetCacheSize,             /* 24 */
+    PRemoveCallBack,           /* 25 -- flush only the callback */
+    PNewCell,                  /* 26 */
+    PListCells,                        /* 27 */
+    PRemoveMount,              /* 28 -- delete mount point */
+    PNewStatMount,             /* 29 -- new style mount point stat */
+    PGetFileCell,              /* 30 -- get cell name for input file */
+    PGetWSCell,                        /* 31 -- get cell name for workstation */
+    PMariner,                  /* 32 - set/get mariner host */
+    PGetUserCell,              /* 33 -- get cell name for user */
+    PBogus,                    /* 34 -- Enable/Disable logging */
+    PGetCellStatus,            /* 35 */
+    PSetCellStatus,            /* 36 */
+    PFlushVolumeData,          /* 37 -- flush all data from a volume */
+    PSetSysName,               /* 38 - Set system name */
+    PExportAfs,                        /* 39 - Export Afs to remote nfs clients */
+    PGetCacheSize,             /* 40 - get cache size and usage */
+    PGetVnodeXStatus,          /* 41 - get vcache's special status */
+    PSetSPrefs33,              /* 42 - Set CM Server preferences... */
+    PGetSPrefs,                        /* 43 - Get CM Server preferences... */
+    PGag,                      /* 44 - turn off/on all CM messages */
+    PTwiddleRx,                        /* 45 - adjust some RX params       */
+    PSetSPrefs,                        /* 46 - Set CM Server preferences... */
+    PStoreBehind,              /* 47 - set degree of store behind to be done */
+    PGCPAGs,                   /* 48 - disable automatic pag gc-ing */
+    PGetInitParams,            /* 49 - get initial cm params */
+    PGetCPrefs,                        /* 50 - get client interface addresses */
+    PSetCPrefs,                        /* 51 - set client interface addresses */
+    PFlushMount,               /* 52 - flush mount symlink data */
+    PRxStatProc,               /* 53 - control process RX statistics */
+    PRxStatPeer,               /* 54 - control peer RX statistics */
+    PGetRxkcrypt,              /* 55 -- Get rxkad encryption flag */
+    PSetRxkcrypt,              /* 56 -- Set rxkad encryption flag */
+    PBogus,                    /* 57 -- arla: set file prio */
+    PBogus,                    /* 58 -- arla: fallback getfh */
+    PBogus,                    /* 59 -- arla: fallback fhopen */
+    PBogus,                    /* 60 -- arla: controls xfsdebug */
+    PBogus,                    /* 61 -- arla: controls arla debug */
+    PBogus,                    /* 62 -- arla: debug interface */
+    PBogus,                    /* 63 -- arla: print xfs status */
+    PBogus,                    /* 64 -- arla: force cache check */
+    PBogus,                    /* 65 -- arla: break callback */
+    PPrefetchFromTape,         /* 66 -- MR-AFS: prefetch file from tape */
+    PFsCmd,                    /* 67 -- RXOSD: generic commnd interface */
+    PBogus,                    /* 68 -- arla: fetch stats */
+    PGetVnodeXStatus2,         /* 69 - get caller access and some vcache status */
 };
 
 static pioctlFunction CpioctlSw[] = {
-    PBogus,                    /* 0 */
-       PNewAlias,              /* 1 -- create new cell alias */
-       PListAliases,           /* 2 -- list cell aliases */
-       PCallBackAddr,          /* 3 -- request addr for callback rxcon */
-       PBogus,                 /* 4 */
-       PDiscon,                /* 5 -- get/set discon mode */
-        PBogus,                 /* 6 */
-        PBogus,                 /* 7 */
-        PBogus,                 /* 8 */
-        PNewUuid,               /* 9 */
-    PBogus,                     /* 0 */
     PBogus,                     /* 0 */
+    PNewAlias,                  /* 1 -- create new cell alias */
+    PListAliases,               /* 2 -- list cell aliases */
+    PCallBackAddr,              /* 3 -- request addr for callback rxcon */
+    PBogus,                     /* 4 */
+    PDiscon,                    /* 5 -- get/set discon mode */
+    PBogus,                     /* 6 */
+    PGetTokens2,                /* 7 */
+    PSetTokens2,                /* 8 */
+    PNewUuid,                   /* 9 */
+    PBogus,                     /* 10 */
+    PBogus,                     /* 11 */
     PPrecache,                  /* 12 */
     PGetPAG,                    /* 13 */
 };
@@ -242,7 +425,7 @@ static pioctlFunction CpioctlSw[] = {
 static pioctlFunction OpioctlSw[]  = {
     PBogus,                    /* 0 */
     PNFSNukeCreds,             /* 1 -- nuke all creds for NFS client */
-#if defined(AFS_CACHE_BYPASS)
+#if defined(AFS_CACHE_BYPASS) && defined(AFS_LINUX24_ENV)
     PSetCachingThreshold        /* 2 -- get/set cache-bypass size threshold */
 #else
     PNoop                       /* 2 -- get/set cache-bypass size threshold */
@@ -253,10 +436,10 @@ static pioctlFunction OpioctlSw[]  = {
 int afs_nobody = NFS_NOBODY;
 
 int
-HandleIoctl(register struct vcache *avc, register afs_int32 acom,
+HandleIoctl(struct vcache *avc, afs_int32 acom,
            struct afs_ioctl *adata)
 {
-    register afs_int32 code;
+    afs_int32 code;
 
     code = 0;
     AFS_STATCNT(HandleIoctl);
@@ -274,8 +457,8 @@ HandleIoctl(register struct vcache *avc, register afs_int32 acom,
 
     case 3:{
            /* return the name of the cell this file is open on */
-           register struct cell *tcell;
-           register afs_int32 i;
+           struct cell *tcell;
+           afs_int32 i;
 
            tcell = afs_GetCell(avc->f.fid.Cell, READ_LOCK);
            if (tcell) {
@@ -315,7 +498,7 @@ HandleIoctl(register struct vcache *avc, register afs_int32 acom,
     return code;               /* so far, none implemented */
 }
 
-#ifdef AFS_AIX_ENV
+#ifdef AFS_AIX_ENV
 /* For aix we don't temporarily bypass ioctl(2) but rather do our
  * thing directly in the vnode layer call, VNOP_IOCTL; thus afs_ioctl
  * is now called from afs_gn_ioctl.
@@ -339,15 +522,111 @@ afs_ioctl(struct vcache *tvc, int cmd, int arg)
        return (ENOTTY);
     }
 }
-#endif /* AFS_AIX_ENV */
+# if defined(AFS_AIX32_ENV)
+#  if defined(AFS_AIX51_ENV)
+#   ifdef __64BIT__
+int
+kioctl(int fdes, int com, caddr_t arg, caddr_t ext, caddr_t arg2,
+          caddr_t arg3)
+#   else /* __64BIT__ */
+int
+kioctl32(int fdes, int com, caddr_t arg, caddr_t ext, caddr_t arg2,
+            caddr_t arg3)
+#   endif /* __64BIT__ */
+#  else
+int
+kioctl(int fdes, int com, caddr_t arg, caddr_t ext)
+#  endif /* AFS_AIX51_ENV */
+{
+    struct a {
+       int fd, com;
+       caddr_t arg, ext;
+#  ifdef AFS_AIX51_ENV
+       caddr_t arg2, arg3;
+#  endif
+    } u_uap, *uap = &u_uap;
+    struct file *fd;
+    struct vcache *tvc;
+    int ioctlDone = 0, code = 0;
 
-#if defined(AFS_SGI_ENV)
+    AFS_STATCNT(afs_xioctl);
+    uap->fd = fdes;
+    uap->com = com;
+    uap->arg = arg;
+#  ifdef AFS_AIX51_ENV
+    uap->arg2 = arg2;
+    uap->arg3 = arg3;
+#  endif
+    if (setuerror(getf(uap->fd, &fd))) {
+       return -1;
+    }
+    if (fd->f_type == DTYPE_VNODE) {
+       /* good, this is a vnode; next see if it is an AFS vnode */
+       tvc = VTOAFS(fd->f_vnode);      /* valid, given a vnode */
+       if (tvc && IsAfsVnode(AFSTOV(tvc))) {
+           /* This is an AFS vnode */
+           if (((uap->com >> 8) & 0xff) == 'V') {
+               struct afs_ioctl *datap;
+               AFS_GLOCK();
+               datap =
+                   (struct afs_ioctl *)osi_AllocSmallSpace(AFS_SMALLOCSIZ);
+               code=copyin_afs_ioctl((char *)uap->arg, datap);
+               if (code) {
+                   osi_FreeSmallSpace(datap);
+                   AFS_GUNLOCK();
+#  if defined(AFS_AIX41_ENV)
+                   ufdrele(uap->fd);
+#  endif
+                   return (setuerror(code), code);
+               }
+               code = HandleIoctl(tvc, uap->com, datap);
+               osi_FreeSmallSpace(datap);
+               AFS_GUNLOCK();
+               ioctlDone = 1;
+#  if defined(AFS_AIX41_ENV)
+               ufdrele(uap->fd);
+#  endif
+            }
+       }
+    }
+    if (!ioctlDone) {
+#  if defined(AFS_AIX41_ENV)
+       ufdrele(uap->fd);
+#   if defined(AFS_AIX51_ENV)
+#    ifdef __64BIT__
+       code = okioctl(fdes, com, arg, ext, arg2, arg3);
+#    else /* __64BIT__ */
+       code = okioctl32(fdes, com, arg, ext, arg2, arg3);
+#    endif /* __64BIT__ */
+#   else /* !AFS_AIX51_ENV */
+       code = okioctl(fdes, com, arg, ext);
+#   endif /* AFS_AIX51_ENV */
+       return code;
+#  elif defined(AFS_AIX32_ENV)
+       okioctl(fdes, com, arg, ext);
+#  endif
+    }
+#  if defined(KERNEL_HAVE_UERROR)
+    if (!getuerror())
+       setuerror(code);
+#   if !defined(AFS_AIX41_ENV)
+    return (getuerror()? -1 : u.u_ioctlrv);
+#   else
+    return getuerror()? -1 : 0;
+#   endif
+#  endif
+    return 0;
+}
+# endif
+
+#elif defined(AFS_SGI_ENV)
+# if defined(AFS_SGI65_ENV)
 afs_ioctl(OSI_VN_DECL(tvc), int cmd, void *arg, int flag, cred_t * cr,
-         rval_t * rvalp
-#ifdef AFS_SGI65_ENV
-         , struct vopbd * vbds
-#endif
-    )
+         rval_t * rvalp, struct vopbd * vbds)
+# else
+afs_ioctl(OSI_VN_DECL(tvc), int cmd, void *arg, int flag, cred_t * cr,
+         rval_t * rvalp, struct vopbd * vbds)
+# endif
 {
     struct afs_ioctl data;
     int error = 0;
@@ -373,271 +652,284 @@ afs_ioctl(OSI_VN_DECL(tvc), int cmd, void *arg, int flag, cred_t * cr,
        return (ENOTTY);
     }
 }
-#endif /* AFS_SGI_ENV */
-
-/* unlike most calls here, this one uses u.u_error to return error conditions,
-   since this is really an intercepted chapter 2 call, rather than a vnode
-   interface call.
-   */
-/* AFS_HPUX102 and up uses VNODE ioctl instead */
-#if !defined(AFS_HPUX102_ENV) && !defined(AFS_DARWIN80_ENV)
-# if !defined(AFS_SGI_ENV)
-#  ifdef       AFS_AIX32_ENV
-#   ifdef AFS_AIX51_ENV
-#    ifdef __64BIT__
+#elif defined(AFS_SUN5_ENV)
+struct afs_ioctl_sys {
+    int fd;
+    int com;
+    int arg;
+};
+
 int
-kioctl(int fdes, int com, caddr_t arg, caddr_t ext, caddr_t arg2, 
-          caddr_t arg3)
-#    else /* __64BIT__ */
+afs_xioctl(struct afs_ioctl_sys *uap, rval_t *rvp)
+{
+    struct file *fd;
+    struct vcache *tvc;
+    int ioctlDone = 0, code = 0;
+
+    AFS_STATCNT(afs_xioctl);
+# if defined(AFS_SUN57_ENV)
+    fd = getf(uap->fd);
+    if (!fd)
+       return (EBADF);
+# elif defined(AFS_SUN54_ENV)
+    fd = GETF(uap->fd);
+    if (!fd)
+       return (EBADF);
+# else
+    if (code = getf(uap->fd, &fd)) {
+       return (code);
+    }
+# endif
+    if (fd->f_vnode->v_type == VREG || fd->f_vnode->v_type == VDIR) {
+       tvc = VTOAFS(fd->f_vnode);      /* valid, given a vnode */
+       if (tvc && IsAfsVnode(AFSTOV(tvc))) {
+           /* This is an AFS vnode */
+           if (((uap->com >> 8) & 0xff) == 'V') {
+               struct afs_ioctl *datap;
+               AFS_GLOCK();
+               datap =
+                   (struct afs_ioctl *)osi_AllocSmallSpace(AFS_SMALLOCSIZ);
+               code=copyin_afs_ioctl((char *)uap->arg, datap);
+               if (code) {
+                   osi_FreeSmallSpace(datap);
+                   AFS_GUNLOCK();
+# if defined(AFS_SUN54_ENV)
+                   releasef(uap->fd);
+# else
+                   releasef(fd);
+# endif
+                   return (EFAULT);
+               }
+               code = HandleIoctl(tvc, uap->com, datap);
+               osi_FreeSmallSpace(datap);
+               AFS_GUNLOCK();
+               ioctlDone = 1;
+           }
+       }
+    }
+# if defined(AFS_SUN57_ENV)
+    releasef(uap->fd);
+# elif defined(AFS_SUN54_ENV)
+    RELEASEF(uap->fd);
+# else
+    releasef(fd);
+# endif
+    if (!ioctlDone)
+       code = ioctl(uap, rvp);
+
+    return (code);
+}
+#elif defined(AFS_LINUX22_ENV)
+struct afs_ioctl_sys {
+    unsigned int com;
+    unsigned long arg;
+};
 int
-kioctl32(int fdes, int com, caddr_t arg, caddr_t ext, caddr_t arg2, 
-            caddr_t arg3)
-#    endif /* __64BIT__ */
-#   else
+afs_xioctl(struct inode *ip, struct file *fp, unsigned int com,
+          unsigned long arg)
+{
+    struct afs_ioctl_sys ua, *uap = &ua;
+    struct vcache *tvc;
+    int ioctlDone = 0, code = 0;
+
+    AFS_STATCNT(afs_xioctl);
+    ua.com = com;
+    ua.arg = arg;
+
+    tvc = VTOAFS(ip);
+    if (tvc && IsAfsVnode(AFSTOV(tvc))) {
+       /* This is an AFS vnode */
+       if (((uap->com >> 8) & 0xff) == 'V') {
+           struct afs_ioctl *datap;
+           AFS_GLOCK();
+           datap = osi_AllocSmallSpace(AFS_SMALLOCSIZ);
+           code = copyin_afs_ioctl((char *)uap->arg, datap);
+           if (code) {
+               osi_FreeSmallSpace(datap);
+               AFS_GUNLOCK();
+               return -code;
+           }
+           code = HandleIoctl(tvc, uap->com, datap);
+           osi_FreeSmallSpace(datap);
+           AFS_GUNLOCK();
+           ioctlDone = 1;
+       }
+       else
+           code = EINVAL;
+    }
+    return -code;
+}
+#elif defined(AFS_DARWIN_ENV) && !defined(AFS_DARWIN80_ENV)
+struct ioctl_args {
+    int fd;
+    u_long com;
+    caddr_t arg;
+};
+
 int
-kioctl(int fdes, int com, caddr_t arg, caddr_t ext)
-#   endif
+afs_xioctl(afs_proc_t *p, struct ioctl_args *uap, register_t *retval)
 {
-    struct a {
-       int fd, com;
-       caddr_t arg, ext;
-#   ifdef AFS_AIX51_ENV
-       caddr_t arg2, arg3;
-#   endif
-    } u_uap, *uap = &u_uap;
-#  else
-#   if defined(AFS_SUN5_ENV)
+    struct file *fd;
+    struct vcache *tvc;
+    int ioctlDone = 0, code = 0;
 
-struct afs_ioctl_sys {
+    AFS_STATCNT(afs_xioctl);
+    if ((code = fdgetf(p, uap->fd, &fd)))
+       return code;
+    if (fd->f_type == DTYPE_VNODE) {
+       tvc = VTOAFS((struct vnode *)fd->f_data);       /* valid, given a vnode */
+       if (tvc && IsAfsVnode(AFSTOV(tvc))) {
+           /* This is an AFS vnode */
+           if (((uap->com >> 8) & 0xff) == 'V') {
+               struct afs_ioctl *datap;
+               AFS_GLOCK();
+               datap = osi_AllocSmallSpace(AFS_SMALLOCSIZ);
+               code = copyin_afs_ioctl((char *)uap->arg, datap);
+               if (code) {
+                   osi_FreeSmallSpace(datap);
+                   AFS_GUNLOCK();
+                   return code;
+               }
+               code = HandleIoctl(tvc, uap->com, datap);
+               osi_FreeSmallSpace(datap);
+               AFS_GUNLOCK();
+               ioctlDone = 1;
+           }
+       }
+    }
+
+    if (!ioctlDone)
+       return ioctl(p, uap, retval);
+
+    return (code);
+}
+#elif defined(AFS_XBSD_ENV)
+# if defined(AFS_FBSD_ENV)
+#  define arg data
+int
+afs_xioctl(struct thread *td, struct ioctl_args *uap,
+          register_t *retval)
+{
+    afs_proc_t *p = td->td_proc;
+# else
+struct ioctl_args {
     int fd;
-    int com;
-    int arg;
+    u_long com;
+    caddr_t arg;
 };
 
-int 
-afs_xioctl(struct afs_ioctl_sys *uap, rval_t *rvp)
-{
-#   elif defined(AFS_FBSD50_ENV)
-#    define arg data
-int
-afs_xioctl(struct thread *td, register struct ioctl_args *uap, 
-          register_t *retval)
-{
-    afs_proc_t *p = td->td_proc;
-#   elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
-struct ioctl_args {
-    int fd;
-    u_long com;
-    caddr_t arg;
-};
+int
+afs_xioctl(afs_proc_t *p, struct ioctl_args *uap, register_t *retval)
+{
+# endif
+    struct filedesc *fdp;
+    struct vcache *tvc;
+    int ioctlDone = 0, code = 0;
+    struct file *fd;
+
+    AFS_STATCNT(afs_xioctl);
+#   if defined(AFS_NBSD40_ENV)
+     fdp = p->l_proc->p_fd;
+#   else
+    fdp = p->p_fd;
+#endif
+    if ((u_int) uap->fd >= fdp->fd_nfiles
+       || (fd = fdp->fd_ofiles[uap->fd]) == NULL)
+       return EBADF;
+    if ((fd->f_flag & (FREAD | FWRITE)) == 0)
+       return EBADF;
+    /* first determine whether this is any sort of vnode */
+    if (fd->f_type == DTYPE_VNODE) {
+       /* good, this is a vnode; next see if it is an AFS vnode */
+# if defined(AFS_OBSD_ENV)
+       tvc =
+           IsAfsVnode((struct vnode *)fd->
+                      f_data) ? VTOAFS((struct vnode *)fd->f_data) : NULL;
+# else
+       tvc = VTOAFS((struct vnode *)fd->f_data);       /* valid, given a vnode */
+# endif
+       if (tvc && IsAfsVnode(AFSTOV(tvc))) {
+           /* This is an AFS vnode */
+           if (((uap->com >> 8) & 0xff) == 'V') {
+               struct afs_ioctl *datap;
+               AFS_GLOCK();
+               datap = osi_AllocSmallSpace(AFS_SMALLOCSIZ);
+               code = copyin_afs_ioctl((char *)uap->arg, datap);
+               if (code) {
+                   osi_FreeSmallSpace(datap);
+                   AFS_GUNLOCK();
+                   return code;
+               }
+               code = HandleIoctl(tvc, uap->com, datap);
+               osi_FreeSmallSpace(datap);
+               AFS_GUNLOCK();
+               ioctlDone = 1;
+           }
+       }
+    }
+
+    if (!ioctlDone) {
+# if defined(AFS_FBSD_ENV)
+       return ioctl(td, uap);
+# elif defined(AFS_OBSD_ENV)
+       code = sys_ioctl(p, uap, retval);
+# elif defined(AFS_NBSD_ENV)
+           struct lwp *l = osi_curproc();
+           code = sys_ioctl(l, uap, retval);
+# endif
+    }
 
-int
-afs_xioctl(afs_proc_t *p, register struct ioctl_args *uap, register_t *retval)
-{
-#   elif defined(AFS_LINUX22_ENV)
-struct afs_ioctl_sys {
-    unsigned int com;
-    unsigned long arg;
-};
-int
-afs_xioctl(struct inode *ip, struct file *fp, unsigned int com,
-          unsigned long arg)
-{
-    struct afs_ioctl_sys ua, *uap = &ua;
-#   else
+    return (code);
+}
+#elif defined(UKERNEL)
 int
 afs_xioctl(void)
 {
-    register struct a {
+    struct a {
        int fd;
        int com;
        caddr_t arg;
-    } *uap = (struct a *)u.u_ap;
-#   endif /* AFS_SUN5_ENV */
-#  endif
-#  if defined(AFS_AIX32_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_DARWIN_ENV)
+    } *uap = (struct a *)get_user_struct()->u_ap;
     struct file *fd;
-#  elif !defined(AFS_LINUX22_ENV)
-    register struct file *fd;
-#  endif
-#  if defined(AFS_XBSD_ENV)
-    register struct filedesc *fdp;
-#  endif
-    register struct vcache *tvc;
-    register int ioctlDone = 0, code = 0;
+    struct vcache *tvc;
+    int ioctlDone = 0, code = 0;
 
     AFS_STATCNT(afs_xioctl);
-#  if defined(AFS_DARWIN_ENV)
-    if ((code = fdgetf(p, uap->fd, &fd)))
-       return code;
-#  elif defined(AFS_XBSD_ENV)
-    fdp = p->p_fd;
-    if ((u_int) uap->fd >= fdp->fd_nfiles
-       || (fd = fdp->fd_ofiles[uap->fd]) == NULL)
-       return EBADF;
-    if ((fd->f_flag & (FREAD | FWRITE)) == 0)
-       return EBADF;
-#  elif defined(AFS_LINUX22_ENV)
-    ua.com = com;
-    ua.arg = arg;
-#  elif defined(AFS_AIX32_ENV)
-    uap->fd = fdes;
-    uap->com = com;
-    uap->arg = arg;
-#   ifdef AFS_AIX51_ENV
-    uap->arg2 = arg2;
-    uap->arg3 = arg3;
-#   endif
-    if (setuerror(getf(uap->fd, &fd))) {
-       return -1;
-    }
-#  elif defined(AFS_SUN5_ENV)
-#   if defined(AFS_SUN57_ENV)
-    fd = getf(uap->fd);
-    if (!fd)
-       return (EBADF);
-#   elif defined(AFS_SUN54_ENV)
-    fd = GETF(uap->fd);
-    if (!fd)
-       return (EBADF);
-#   else
-    if (code = getf(uap->fd, &fd)) {
-       return (code);
-    }
-#   endif      /* AFS_SUN57_ENV */
-#  else
+
     fd = getf(uap->fd);
     if (!fd)
        return (EBADF);
-#  endif
     /* first determine whether this is any sort of vnode */
-#  if defined(AFS_LINUX22_ENV)
-    tvc = VTOAFS(ip);
-    {
-#  else
-#   ifdef AFS_SUN5_ENV
-    if (fd->f_vnode->v_type == VREG || fd->f_vnode->v_type == VDIR) {
-#   else
     if (fd->f_type == DTYPE_VNODE) {
-#   endif
        /* good, this is a vnode; next see if it is an AFS vnode */
-#   if defined(AFS_AIX32_ENV) || defined(AFS_SUN5_ENV)
-       tvc = VTOAFS(fd->f_vnode);      /* valid, given a vnode */
-#   elif defined(AFS_OBSD_ENV)
-       tvc =
-           IsAfsVnode((struct vnode *)fd->
-                      f_data) ? VTOAFS((struct vnode *)fd->f_data) : NULL;
-#   else
        tvc = VTOAFS((struct vnode *)fd->f_data);       /* valid, given a vnode */
-#   endif
-#  endif /* AFS_LINUX22_ENV */
        if (tvc && IsAfsVnode(AFSTOV(tvc))) {
            /* This is an AFS vnode */
            if (((uap->com >> 8) & 0xff) == 'V') {
-               register struct afs_ioctl *datap;
+               struct afs_ioctl *datap;
                AFS_GLOCK();
-               datap =
-                   (struct afs_ioctl *)osi_AllocSmallSpace(AFS_SMALLOCSIZ);
+               datap = osi_AllocSmallSpace(AFS_SMALLOCSIZ);
                code=copyin_afs_ioctl((char *)uap->arg, datap);
                if (code) {
                    osi_FreeSmallSpace(datap);
                    AFS_GUNLOCK();
-#  if defined(AFS_AIX41_ENV)
-                   ufdrele(uap->fd);
-#  elif defined(AFS_SUN54_ENV)
-                   releasef(uap->fd);
-#  elif defined(AFS_SUN5_ENV)
-                   releasef(fd);
-#  endif
 
-#  if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
-                   return code;
-#  elif defined(AFS_SUN5_ENV)
-                   return (EFAULT);
-#  elif defined(AFS_LINUX22_ENV)
-                   return -code;
-#  else
                    return (setuerror(code), code);
-#  endif
                }
                code = HandleIoctl(tvc, uap->com, datap);
                osi_FreeSmallSpace(datap);
                AFS_GUNLOCK();
                ioctlDone = 1;
-#  if defined(AFS_AIX41_ENV)
-               ufdrele(uap->fd);
-#  endif
            }
-#  if defined(AFS_LINUX22_ENV)
-           else
-               code = EINVAL;
-#  endif
        }
     }
 
     if (!ioctlDone) {
-#  if defined(AFS_AIX41_ENV)
-       ufdrele(uap->fd);
-#   ifdef AFS_AIX51_ENV
-#    ifdef __64BIT__
-       code = okioctl(fdes, com, arg, ext, arg2, arg3);
-#    else /* __64BIT__ */
-       code = okioctl32(fdes, com, arg, ext, arg2, arg3);
-#    endif /* __64BIT__ */
-#   else /* !AFS_AIX51_ENV */
-       code = okioctl(fdes, com, arg, ext);
-#   endif /* AFS_AIX51_ENV */
-       return code;
-#  elif defined(AFS_AIX32_ENV)
-       okioctl(fdes, com, arg, ext);
-#  elif defined(AFS_SUN5_ENV)
-#   if defined(AFS_SUN57_ENV)
-       releasef(uap->fd);
-#   elif defined(AFS_SUN54_ENV)
-       RELEASEF(uap->fd);
-#   else
-       releasef(fd);
-#   endif
-       code = ioctl(uap, rvp);
-#  elif defined(AFS_FBSD50_ENV)
-       return ioctl(td, uap);
-#  elif defined(AFS_FBSD_ENV)
-       return ioctl(p, uap);
-#  elif defined(AFS_OBSD_ENV)
-       code = sys_ioctl(p, uap, retval);
-#  elif defined(AFS_DARWIN_ENV)
-       return ioctl(p, uap, retval);
-#  elif !defined(AFS_LINUX22_ENV)
        ioctl();
-#  endif
     }
-#  ifdef       AFS_SUN5_ENV
-    if (ioctlDone)
-#   ifdef      AFS_SUN54_ENV
-       releasef(uap->fd);
-#   else
-       releasef(fd);
-#   endif
-    return (code);
-#  elif defined(AFS_LINUX22_ENV)
-    return -code;
-#  elif defined(KERNEL_HAVE_UERROR)
-    if (!getuerror())
-       setuerror(code);
-#   if defined(AFS_AIX32_ENV) && !defined(AFS_AIX41_ENV)
-    return (getuerror()? -1 : u.u_ioctlrv);
-#   else
-    return getuerror()? -1 : 0;
-#   endif
-#  endif
 
-#  if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
-    return (code);
-#  else
     return 0;
-#  endif
 }
-# endif /* AFS_SGI_ENV */
 #endif /* AFS_HPUX102_ENV */
 
 #if defined(AFS_SGI_ENV)
@@ -665,7 +957,7 @@ afs_pioctl(struct pioctlargs *uap, rval_t * rvp)
 # endif
 }
 
-#elif defined(AFS_FBSD50_ENV)
+#elif defined(AFS_FBSD_ENV)
 int
 afs_pioctl(struct thread *td, void *args, int *retval)
 {
@@ -693,14 +985,18 @@ afs_pioctl(afs_proc_t *p, void *args, int *retval)
     } *uap = (struct a *)args;
 
     AFS_STATCNT(afs_pioctl);
-# ifdef AFS_DARWIN80_ENV
+# if defined(AFS_DARWIN80_ENV) || defined(AFS_NBSD40_ENV)
     return (afs_syscall_pioctl
            (uap->path, uap->cmd, uap->cmarg, uap->follow,
             kauth_cred_get()));
 # else
     return (afs_syscall_pioctl
            (uap->path, uap->cmd, uap->cmarg, uap->follow,
+#  if defined(AFS_FBSD_ENV)
+            td->td_ucred));
+#  else
             p->p_cred->pc_ucred));
+#  endif
 # endif
 }
 
@@ -715,14 +1011,14 @@ afs_pioctl(afs_proc_t *p, void *args, int *retval)
 
 int
 #ifdef AFS_SUN5_ENV
-afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow, 
+afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow,
                   rval_t *vvp, afs_ucred_t *credp)
 #else
 #ifdef AFS_DARWIN100_ENV
 afs_syscall64_pioctl(user_addr_t path, unsigned int com, user_addr_t cmarg,
                   int follow, afs_ucred_t *credp)
 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
-afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow, 
+afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow,
                   afs_ucred_t *credp)
 #else
 afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow)
@@ -736,7 +1032,7 @@ afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow)
 #if defined(AFS_NEED_CLIENTCONTEXT) || defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
     afs_ucred_t *foreigncreds = NULL;
 #endif
-    register afs_int32 code = 0;
+    afs_int32 code = 0;
     struct vnode *vp = NULL;
 #ifdef AFS_AIX41_ENV
     struct ucred *credp = crref();     /* don't free until done! */
@@ -836,6 +1132,10 @@ afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow)
            vp = (struct vnode *)dp->d_inode;
 #else
        code = gop_lookupname_user(path, AFS_UIOUSER, follow, &vp);
+#if defined(AFS_FBSD80_ENV) /* XXX check on 7x */
+       if (vp != NULL)
+               VN_HOLD(vp);
+#endif /* AFS_FBSD80_ENV */
 #endif /* AFS_LINUX22_ENV */
 #endif /* AFS_AIX41_ENV */
        AFS_GLOCK();
@@ -854,13 +1154,13 @@ afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow)
        struct vnode *realvp;
        if
 #ifdef AFS_SUN511_ENV
-          (VOP_REALVP(vp, &realvp, NULL) == 0) 
+          (VOP_REALVP(vp, &realvp, NULL) == 0)
 #else
-         (VOP_REALVP(vp, &realvp) == 0) 
+         (VOP_REALVP(vp, &realvp) == 0)
 #endif
 {
            struct vnode *oldvp = vp;
-           
+
            VN_HOLD(realvp);
            vp = realvp;
            AFS_RELE(oldvp);
@@ -899,6 +1199,9 @@ afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow)
        }
 #elif defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
        code = afs_HandlePioctl(vp, com, &data, follow, &credp);
+#elif defined(UKERNEL)
+       code = afs_HandlePioctl(vp, com, &data, follow,
+                               &(get_user_struct()->u_cred));
 #else
        code = afs_HandlePioctl(vp, com, &data, follow, &u.u_cred);
 #endif
@@ -933,6 +1236,10 @@ afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow)
 #ifdef AFS_LINUX22_ENV
        dput(dp);
 #else
+#if defined(AFS_FBSD80_ENV)
+    if (VOP_ISLOCKED(vp))
+       VOP_UNLOCK(vp, 0);
+#endif /* AFS_FBSD80_ENV */
        AFS_RELE(vp);           /* put vnode back */
 #endif
     }
@@ -962,32 +1269,37 @@ afs_syscall_pioctl(char * path, unsigned int com, caddr_t cmarg,
 
 int
 afs_HandlePioctl(struct vnode *avp, afs_int32 acom,
-                register struct afs_ioctl *ablob, int afollow,
+                struct afs_ioctl *ablob, int afollow,
                 afs_ucred_t **acred)
 {
     struct vcache *avc;
     struct vrequest treq;
-    register afs_int32 code;
-    register afs_int32 function, device;
-    afs_int32 inSize, outSize, outSizeMax;
-    char *inData, *outData;
+    afs_int32 code;
+    afs_int32 function, device;
+    struct afs_pdata input, output;
+    struct afs_pdata copyInput, copyOutput;
+    size_t outSize;
     pioctlFunction *pioctlSw;
     int pioctlSwSize;
     struct afs_fakestat_state fakestate;
 
+    memset(&input, 0, sizeof(input));
+    memset(&output, 0, sizeof(output));
+
     avc = avp ? VTOAFS(avp) : NULL;
     afs_Trace3(afs_iclSetp, CM_TRACE_PIOCTL, ICL_TYPE_INT32, acom & 0xff,
               ICL_TYPE_POINTER, avc, ICL_TYPE_INT32, afollow);
     AFS_STATCNT(HandlePioctl);
-    if ((code = afs_InitReq(&treq, *acred)))
+
+    code = afs_InitReq(&treq, *acred);
+    if (code)
        return code;
+
     afs_InitFakeStat(&fakestate);
     if (avc) {
        code = afs_EvalFakeStat(&avc, &fakestate, &treq);
-       if (code) {
-           afs_PutFakeStat(&fakestate);
-           return code;
-       }
+       if (code)
+           goto out;
     }
     device = (acom & 0xff00) >> 8;
     switch (device) {
@@ -1004,79 +1316,63 @@ afs_HandlePioctl(struct vnode *avp, afs_int32 acom,
        pioctlSwSize = sizeof(OpioctlSw);
        break;
     default:
-       afs_PutFakeStat(&fakestate);
-       return EINVAL;
+       code = EINVAL;
+       goto out;
     }
     function = acom & 0xff;
     if (function >= (pioctlSwSize / sizeof(char *))) {
-       afs_PutFakeStat(&fakestate);
-       return EINVAL;          /* out of range */
+       code = EINVAL;
+       goto out;
     }
-    inSize = ablob->in_size;
 
     /* Do all range checking before continuing */
-    if (inSize > MAXPIOCTLTOKENLEN || inSize < 0 || ablob->out_size < 0)
-       return E2BIG;
-
-    /* Note that we use osi_Alloc for large allocs and osi_AllocLargeSpace for small ones */
-    if (inSize > AFS_LRALLOCSIZ) {
-       inData = osi_Alloc(inSize + 1);
-    } else {
-       inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
+    if (ablob->in_size > MAXPIOCTLTOKENLEN ||
+        ablob->in_size < 0 || ablob->out_size < 0) {
+       code = EINVAL;
+       goto out;
     }
-    if (!inData)
-       return ENOMEM;
-    if (inSize > 0) {
-       AFS_COPYIN(ablob->in, inData, inSize, code);
-       inData[inSize] = '\0';
-    } else
-       code = 0;
-    if (code) {
-       if (inSize > AFS_LRALLOCSIZ) {
-           osi_Free(inData, inSize + 1);
-       } else {
-           osi_FreeLargeSpace(inData);
-       }
-       afs_PutFakeStat(&fakestate);
-       return code;
+
+    code = afs_pd_alloc(&input, ablob->in_size);
+    if (code)
+       goto out;
+
+    if (ablob->in_size > 0) {
+       AFS_COPYIN(ablob->in, input.ptr, ablob->in_size, code);
+       input.ptr[input.remaining] = '\0';
     }
-    if (function == 8 && device == 'V') {      /* PGetTokens */
-       outSizeMax = MAXPIOCTLTOKENLEN;
-       outData = osi_Alloc(outSizeMax);
+    if (code)
+       goto out;
+
+    if ((function == 8 && device == 'V') ||
+       (function == 7 && device == 'C')) {     /* PGetTokens */
+       code = afs_pd_alloc(&output, MAXPIOCTLTOKENLEN);
     } else {
-       outSizeMax = AFS_LRALLOCSIZ;
-       outData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
-    }
-    if (!outData) {
-       if (inSize > AFS_LRALLOCSIZ) {
-           osi_Free(inData, inSize + 1);
-       } else {
-           osi_FreeLargeSpace(inData);
-       }
-       afs_PutFakeStat(&fakestate);
-       return ENOMEM;
+       code = afs_pd_alloc(&output, AFS_LRALLOCSIZ);
     }
-    outSize = 0;
+    if (code)
+       goto out;
+
+    copyInput = input;
+    copyOutput = output;
+
     code =
-       (*pioctlSw[function]) (avc, function, &treq, inData, outData, inSize,
-                              &outSize, acred);
-    if (inSize > AFS_LRALLOCSIZ) {
-       osi_Free(inData, inSize + 1);
-    } else {
-       osi_FreeLargeSpace(inData);
-    }
+       (*pioctlSw[function]) (avc, function, &treq, &copyInput,
+                              &copyOutput, acred);
+
+    outSize = copyOutput.ptr - output.ptr;
+
     if (code == 0 && ablob->out_size > 0) {
        if (outSize > ablob->out_size) {
            code = E2BIG;       /* data wont fit in user buffer */
        } else if (outSize) {
-           AFS_COPYOUT(outData, ablob->out, outSize, code);
+           AFS_COPYOUT(output.ptr, ablob->out, outSize, code);
        }
     }
-    if (outSizeMax > AFS_LRALLOCSIZ) {
-       osi_Free(outData, outSizeMax);
-    } else {
-       osi_FreeLargeSpace(outData);
-    }
+
+out:
+    afs_pd_free(&input);
+    afs_pd_free(&output);
+
     afs_PutFakeStat(&fakestate);
     return afs_CheckCode(code, &treq, 41);
 }
@@ -1098,8 +1394,8 @@ DECL_PIOCTL(PGetFID)
     AFS_STATCNT(PGetFID);
     if (!avc)
        return EINVAL;
-    memcpy(aout, (char *)&avc->f.fid, sizeof(struct VenusFid));
-    *aoutSize = sizeof(struct VenusFid);
+    if (afs_pd_putBytes(aout, &avc->f.fid, sizeof(struct VenusFid)) != 0)
+       return EINVAL;
     return 0;
 }
 
@@ -1115,14 +1411,15 @@ DECL_PIOCTL(PGetFID)
  *
  * \post Changed ACL, via direct writing to the wire
  */
-int dummy_PSetAcl(char *ain, char *aout)
+int
+dummy_PSetAcl(char *ain, char *aout)
 {
     return 0;
 }
 
 DECL_PIOCTL(PSetAcl)
 {
-    register afs_int32 code;
+    afs_int32 code;
     struct afs_conn *tconn;
     struct AFSOpaque acl;
     struct AFSVolSync tsync;
@@ -1132,10 +1429,13 @@ DECL_PIOCTL(PSetAcl)
     AFS_STATCNT(PSetAcl);
     if (!avc)
        return EINVAL;
-    if ((acl.AFSOpaque_len = strlen(ain) + 1) > 1024 /* AFSOPAQUEMAX */)
+
+    if (afs_pd_getStringPtr(ain, &acl.AFSOpaque_val) != 0)
+       return EINVAL;
+    acl.AFSOpaque_len = strlen(acl.AFSOpaque_val) + 1;
+    if (acl.AFSOpaque_len > 1024)
        return EINVAL;
 
-    acl.AFSOpaque_val = ain;
     do {
        tconn = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
        if (tconn) {
@@ -1175,40 +1475,45 @@ int afs_defaultAsynchrony = 0;
  * \param[in] ain      sbstruct (store behind structure) input
  * \param[out] aout    resulting sbstruct
  *
- * \retval EPERM       Error if the user doesn't have super-user credentials
- * \retval EACCES      Error if there isn't enough access to not check the mode bits
+ * \retval EPERM
+ *     Error if the user doesn't have super-user credentials
+ * \retval EACCES
+ *     Error if there isn't enough access to not check the mode bits
  *
- * \post sets asynchrony based on a file, from a struct sbstruct "I THINK"
+ * \post
+ *     Changes either the default asynchrony (the amount of data that
+ *     can remain to be written when the cache manager returns control
+ *     to the user), or the asyncrony for the specified file.
  */
 DECL_PIOCTL(PStoreBehind)
 {
-    afs_int32 code = 0;
-    struct sbstruct *sbr;
+    struct sbstruct sbr;
 
-    sbr = (struct sbstruct *)ain;
-    if (sbr->sb_default != -1) {
+    if (afs_pd_getBytes(ain, &sbr, sizeof(struct sbstruct)) != 0)
+       return EINVAL;
+
+    if (sbr.sb_default != -1) {
        if (afs_osi_suser(*acred))
-           afs_defaultAsynchrony = sbr->sb_default;
+           afs_defaultAsynchrony = sbr.sb_default;
        else
-           code = EPERM;
+           return EPERM;
     }
 
-    if (avc && (sbr->sb_thisfile != -1)) {
+    if (avc && (sbr.sb_thisfile != -1)) {
        if (afs_AccessOK
            (avc, PRSFS_WRITE | PRSFS_ADMINISTER, areq, DONT_CHECK_MODE_BITS))
-           avc->asynchrony = sbr->sb_thisfile;
+           avc->asynchrony = sbr.sb_thisfile;
        else
-           code = EACCES;
+           return EACCES;
     }
 
-    *aoutSize = sizeof(struct sbstruct);
-    sbr = (struct sbstruct *)aout;
-    sbr->sb_default = afs_defaultAsynchrony;
+    memset(&sbr, 0, sizeof(sbr));
+    sbr.sb_default = afs_defaultAsynchrony;
     if (avc) {
-       sbr->sb_thisfile = avc->asynchrony;
+       sbr.sb_thisfile = avc->asynchrony;
     }
 
-    return code;
+    return afs_pd_putBytes(aout, &sbr, sizeof(sbr));
 }
 
 /*!
@@ -1246,7 +1551,10 @@ DECL_PIOCTL(PGCPAGs)
  *
  * \post Obtain the ACL, based on file ID
  *
- * \notes there is a hack to tell which type of ACL is being returned, checks the top 2-bytes to judge what type of ACL it is, only for dfs xlat or ACLs
+ * \notes
+ *     There is a hack to tell which type of ACL is being returned, checks
+ *     the top 2-bytes of the input size to judge what type of ACL it is,
+ *     only for dfs xlator ACLs
  */
 DECL_PIOCTL(PGetAcl)
 {
@@ -1274,13 +1582,13 @@ DECL_PIOCTL(PGetAcl)
         */
        if (Fid.Vnode & 0xc0000000)
            return ERANGE;
-       Fid.Vnode |= (ainSize << 30);
+       Fid.Vnode |= (ain->remaining << 30);
     }
-    acl.AFSOpaque_val = aout;
+    acl.AFSOpaque_val = aout->ptr;
     do {
        tconn = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
        if (tconn) {
-           *aout = 0;
+           acl.AFSOpaque_val[0] = '\0';
            XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_FETCHACL);
            RX_AFS_GUNLOCK();
            code = RXAFS_FetchACL(tconn->id, &Fid, &acl, &OutStatus, &tsync);
@@ -1293,17 +1601,27 @@ DECL_PIOCTL(PGetAcl)
              SHARED_LOCK, NULL));
 
     if (code == 0) {
-       *aoutSize = (acl.AFSOpaque_len == 0 ? 1 : acl.AFSOpaque_len);
+       if (acl.AFSOpaque_len == 0)
+           afs_pd_skip(aout, 1); /* leave the NULL */
+       else
+           afs_pd_skip(aout, acl.AFSOpaque_len); /* Length of the ACL */
     }
     return code;
 }
 
 /*!
- * PNoop returns success.  Used for functions which are not implemented or are no longer in use.
+ * PNoop returns success.  Used for functions which are not implemented
+ * or are no longer in use.
  *
  * \ingroup pioctl
  *
- * \notes Functions involved in this: 17 (VIOCENGROUP) -- used to be enable group; 18 (VIOCDISGROUP) -- used to be disable group; 2 (?) -- get/set cache-bypass size threshold
+ * \retval Always returns success
+ *
+ * \notes
+ *     Functions involved in this:
+ *     17 (VIOCENGROUP) -- used to be enable group;
+ *     18 (VIOCDISGROUP) -- used to be disable group;
+ *     2 (?) -- get/set cache-bypass size threshold
  */
 DECL_PIOCTL(PNoop)
 {
@@ -1312,13 +1630,35 @@ DECL_PIOCTL(PNoop)
 }
 
 /*!
- * PBogus returns fail.  Used for functions which are not implemented or are no longer in use.
+ * PBogus returns fail.  Used for functions which are not implemented or
+ * are no longer in use.
  *
  * \ingroup pioctl
  *
- * \retval EINVAL      Error if some of the standard args aren't set
- *
- * \notes Functions involved in this: 0 (?); 4 (?); 6 (?); 7 (VIOCSTAT); 8 (?); 13 (VIOCGETTIME) -- used to be quick check time; 15 (VIOCPREFETCH) -- prefetch is now special-cased; see pioctl code!; 16 (VIOCNOP) -- used to be testing code; 19 (VIOCLISTGROUPS) -- used to be list group; 23 (VIOCWAITFOREVER) -- used to be waitforever; 57 (VIOC_FPRIOSTATUS) -- arla: set file prio; 58 (VIOC_FHGET) -- arla: fallback getfh; 59 (VIOC_FHOPEN) -- arla: fallback fhopen; 60 (VIOC_XFSDEBUG) -- arla: controls xfsdebug; 61 (VIOC_ARLADEBUG) -- arla: controls arla debug; 62 (VIOC_AVIATOR) -- arla: debug interface; 63 (VIOC_XFSDEBUG_PRINT) -- arla: print xfs status; 64 (VIOC_CALCULATE_CACHE) -- arla: force cache check; 65 (VIOC_BREAKCELLBACK) -- arla: break callback; 68 (?) -- arla: fetch stats;
+ * \retval EINVAL      Always returns this value
+ *
+ * \notes
+ *     Functions involved in this:
+ *     0 (?);
+ *     4 (?);
+ *     6 (?);
+ *     7 (VIOCSTAT);
+ *     8 (?);
+ *     13 (VIOCGETTIME) -- used to be quick check time;
+ *     15 (VIOCPREFETCH) -- prefetch is now special-cased; see pioctl code!;
+ *     16 (VIOCNOP) -- used to be testing code;
+ *     19 (VIOCLISTGROUPS) -- used to be list group;
+ *     23 (VIOCWAITFOREVER) -- used to be waitforever;
+ *     57 (VIOC_FPRIOSTATUS) -- arla: set file prio;
+ *     58 (VIOC_FHGET) -- arla: fallback getfh;
+ *     59 (VIOC_FHOPEN) -- arla: fallback fhopen;
+ *     60 (VIOC_XFSDEBUG) -- arla: controls xfsdebug;
+ *     61 (VIOC_ARLADEBUG) -- arla: controls arla debug;
+ *     62 (VIOC_AVIATOR) -- arla: debug interface;
+ *     63 (VIOC_XFSDEBUG_PRINT) -- arla: print xfs status;
+ *     64 (VIOC_CALCULATE_CACHE) -- arla: force cache check;
+ *     65 (VIOC_BREAKCELLBACK) -- arla: break callback;
+ *     68 (?) -- arla: fetch stats;
  */
 DECL_PIOCTL(PBogus)
 {
@@ -1341,7 +1681,7 @@ DECL_PIOCTL(PBogus)
  */
 DECL_PIOCTL(PGetFileCell)
 {
-    register struct cell *tcell;
+    struct cell *tcell;
 
     AFS_STATCNT(PGetFileCell);
     if (!avc)
@@ -1349,9 +1689,11 @@ DECL_PIOCTL(PGetFileCell)
     tcell = afs_GetCell(avc->f.fid.Cell, READ_LOCK);
     if (!tcell)
        return ESRCH;
-    strcpy(aout, tcell->cellName);
+
+    if (afs_pd_putString(aout, tcell->cellName) != 0)
+       return EINVAL;
+
     afs_PutCell(tcell, READ_LOCK);
-    *aoutSize = strlen(aout) + 1;
     return 0;
 }
 
@@ -1363,8 +1705,10 @@ DECL_PIOCTL(PGetFileCell)
  * \param[in] ain      not in use
  * \param[out] aout    cell name
  *
- * \retval EIO         Error if the afs daemon hasn't started yet
- * \retval ESRCH       Error if the machine isn't part of a cell, for whatever reason
+ * \retval EIO
+ *     Error if the afs daemon hasn't started yet
+ * \retval ESRCH
+ *     Error if the machine isn't part of a cell, for whatever reason
  *
  * \post Get the primary cell that the machine is a part of.
  */
@@ -1379,8 +1723,9 @@ DECL_PIOCTL(PGetWSCell)
     tcell = afs_GetPrimaryCell(READ_LOCK);
     if (!tcell)                        /* no primary cell? */
        return ESRCH;
-    strcpy(aout, tcell->cellName);
-    *aoutSize = strlen(aout) + 1;
+
+    if (afs_pd_putString(aout, tcell->cellName) != 0)
+       return EINVAL;
     afs_PutCell(tcell, READ_LOCK);
     return 0;
 }
@@ -1393,15 +1738,16 @@ DECL_PIOCTL(PGetWSCell)
  * \param[in] ain      not in use (user id found via areq)
  * \param[out] aout    cell name
  *
- * \retval ESRCH       Error if the user id doesn't have a primary cell specified
+ * \retval ESRCH
+ *     Error if the user id doesn't have a primary cell specified
  *
  * \post Get the primary cell for a certain user, based on the user's uid
  */
 DECL_PIOCTL(PGetUserCell)
 {
-    register afs_int32 i;
-    register struct unixuser *tu;
-    register struct cell *tcell;
+    afs_int32 i;
+    struct unixuser *tu;
+    struct cell *tcell;
 
     AFS_STATCNT(PGetUserCell);
     if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
@@ -1423,18 +1769,61 @@ DECL_PIOCTL(PGetUserCell)
        if (!tcell)
            return ESRCH;
        else {
-           strcpy(aout, tcell->cellName);
+           if (afs_pd_putString(aout, tcell->cellName) != 0)
+               return E2BIG;
            afs_PutCell(tcell, READ_LOCK);
-           *aoutSize = strlen(aout) + 1;       /* 1 for the null */
        }
     } else {
        ReleaseWriteLock(&afs_xuser);
-       *aout = 0;
-       *aoutSize = 1;
     }
     return 0;
 }
 
+/* Work out which cell we're changing tokens for */
+static_inline int
+_settok_tokenCell(char *cellName, int *cellNum, int *primary) {
+    int t1;
+    struct cell *cell;
+
+    if (primary) {
+       *primary = 0;
+    }
+
+    if (cellName && strlen(cellName) > 0) {
+       cell = afs_GetCellByName(cellName, READ_LOCK);
+    } else {
+       cell = afs_GetPrimaryCell(READ_LOCK);
+       if (primary)
+           *primary = 1;
+    }
+    if (!cell) {
+       t1 = afs_initState;
+       if (t1 < 101)
+           return EIO;
+       else
+           return ESRCH;
+    }
+    *cellNum = cell->cellNum;
+    afs_PutCell(cell, READ_LOCK);
+
+    return 0;
+}
+
+
+static_inline int
+_settok_setParentPag(afs_ucred_t **cred) {
+    afs_uint32 pag;
+#if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
+    char procname[256];
+    osi_procname(procname, 256);
+    afs_warnuser("Process %d (%s) tried to change pags in PSetTokens\n",
+                MyPidxx2Pid(MyPidxx), procname);
+    return setpag(osi_curproc(), cred, -1, &pag, 1);
+#else
+    return setpag(cred, -1, &pag, 1);
+#endif
+}
+
 /*!
  * VIOCSETTOK (3) - Set authentication tokens
  *
@@ -1443,20 +1832,27 @@ DECL_PIOCTL(PGetUserCell)
  * \param[in] ain      the krb tickets from which to set the afs tokens
  * \param[out] aout    not in use
  *
- * \retval EINVAL      Error if the ticket is either too long or too short
- * \retval EIO         Error if the AFS initState is below 101
- * \retval ESRCH       Error if the cell for which the Token is being set can't be found
+ * \retval EINVAL
+ *     Error if the ticket is either too long or too short
+ * \retval EIO
+ *     Error if the AFS initState is below 101
+ * \retval ESRCH
+ *     Error if the cell for which the Token is being set can't be found
  *
- * \post Set the Tokens for a specific cell name, unless there is none set, then default to primary
+ * \post
+ *     Set the Tokens for a specific cell name, unless there is none set,
+ *     then default to primary
  *
  */
 DECL_PIOCTL(PSetTokens)
 {
-    afs_int32 i;
-    register struct unixuser *tu;
+    afs_int32 cellNum;
+    afs_int32 size;
+    afs_int32 code;
+    struct unixuser *tu;
     struct ClearToken clear;
-    register struct cell *tcell;
     char *stp;
+    char *cellName;
     int stLen;
     struct vrequest treq;
     afs_int32 flag, set_parent_pag = 0;
@@ -1465,77 +1861,66 @@ DECL_PIOCTL(PSetTokens)
     if (!afs_resourceinit_flag) {
        return EIO;
     }
-    memcpy((char *)&i, ain, sizeof(afs_int32));
-    ain += sizeof(afs_int32);
-    stp = ain;                 /* remember where the ticket is */
-    if (i < 0 || i > MAXKTCTICKETLEN)
+
+    if (afs_pd_getInt(ain, &stLen) != 0)
+       return EINVAL;
+
+    stp = afs_pd_where(ain);   /* remember where the ticket is */
+    if (stLen < 0 || stLen > MAXKTCTICKETLEN)
        return EINVAL;          /* malloc may fail */
-    stLen = i;
-    ain += i;                  /* skip over ticket */
-    memcpy((char *)&i, ain, sizeof(afs_int32));
-    ain += sizeof(afs_int32);
-    if (i != sizeof(struct ClearToken)) {
+    if (afs_pd_skip(ain, stLen) != 0)
        return EINVAL;
-    }
-    memcpy((char *)&clear, ain, sizeof(struct ClearToken));
+
+    if (afs_pd_getInt(ain, &size) != 0)
+       return EINVAL;
+    if (size != sizeof(struct ClearToken))
+       return EINVAL;
+
+    if (afs_pd_getBytes(ain, &clear, sizeof(struct ClearToken)) !=0)
+       return EINVAL;
+
     if (clear.AuthHandle == -1)
        clear.AuthHandle = 999; /* more rxvab compat stuff */
-    ain += sizeof(struct ClearToken);
-    if (ainSize != 2 * sizeof(afs_int32) + stLen + sizeof(struct ClearToken)) {
-       /* still stuff left?  we've got primary flag and cell name.  Set these */
-       memcpy((char *)&flag, ain, sizeof(afs_int32));  /* primary id flag */
-       ain += sizeof(afs_int32);       /* skip id field */
-       /* rest is cell name, look it up */
-       /* some versions of gcc appear to need != 0 in order to get this right */
+
+    if (afs_pd_remaining(ain) != 0) {
+       /* still stuff left?  we've got primary flag and cell name.
+        * Set these */
+
+       if (afs_pd_getInt(ain, &flag) != 0)
+           return EINVAL;
+
+       /* some versions of gcc appear to need != 0 in order to get this
+        * right */
        if ((flag & 0x8000) != 0) {     /* XXX Use Constant XXX */
            flag &= ~0x8000;
            set_parent_pag = 1;
        }
-       tcell = afs_GetCellByName(ain, READ_LOCK);
-       if (!tcell)
-           goto nocell;
+
+       if (afs_pd_getStringPtr(ain, &cellName) != 0)
+           return EINVAL;
+
+       code = _settok_tokenCell(cellName, &cellNum, NULL);
+       if (code)
+           return code;
     } else {
        /* default to primary cell, primary id */
-       flag = 1;               /* primary id */
-       tcell = afs_GetPrimaryCell(READ_LOCK);
-       if (!tcell)
-           goto nocell;
+       code = _settok_tokenCell(NULL, &cellNum, &flag);
+       if (code)
+           return code;
     }
-    i = tcell->cellNum;
-    afs_PutCell(tcell, READ_LOCK);
+
     if (set_parent_pag) {
-       afs_uint32 pag;
-#if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
-# if defined(AFS_DARWIN_ENV)
-       afs_proc_t *p = current_proc(); /* XXX */
-# else
-       afs_proc_t *p = curproc;        /* XXX */
-# endif
-# ifndef AFS_DARWIN80_ENV
-       uprintf("Process %d (%s) tried to change pags in PSetTokens\n",
-               p->p_pid, p->p_comm);
-# endif
-       if (!setpag(p, acred, -1, &pag, 1)) {
-#else
-       if (!setpag(acred, -1, &pag, 1)) {
-#endif
+       if (_settok_setParentPag(acred) == 0) {
            afs_InitReq(&treq, *acred);
            areq = &treq;
        }
     }
+
     /* now we just set the tokens */
-    tu = afs_GetUser(areq->uid, i, WRITE_LOCK);        /* i has the cell # */
-    tu->vid = clear.ViceId;
-    if (tu->stp != NULL) {
-       afs_osi_Free(tu->stp, tu->stLen);
-    }
-    tu->stp = (char *)afs_osi_Alloc(stLen);
-    if (tu->stp == NULL) {
-       return ENOMEM;
-    }
-    tu->stLen = stLen;
-    memcpy(tu->stp, stp, stLen);
-    tu->ct = clear;
+    tu = afs_GetUser(areq->uid, cellNum, WRITE_LOCK);
+    /* Set tokens destroys any that are already there */
+    afs_FreeTokens(&tu->tokens);
+    afs_AddRxkadToken(&tu->tokens, stp, stLen, &clear);
 #ifndef AFS_NOSTATS
     afs_stats_cmfullperf.authent.TicketUpdates++;
     afs_ComputePAGStats();
@@ -1545,19 +1930,10 @@ DECL_PIOCTL(PSetTokens)
     afs_SetPrimary(tu, flag);
     tu->tokenTime = osi_Time();
     afs_ResetUserConns(tu);
+    afs_NotifyUser(tu, UTokensObtained);
     afs_PutUser(tu, WRITE_LOCK);
 
     return 0;
-
-  nocell:
-    {
-       int t1;
-       t1 = afs_initState;
-       if (t1 < 101)
-           return EIO;
-       else
-           return ESRCH;
-    }
 }
 
 /*!
@@ -1570,28 +1946,29 @@ DECL_PIOCTL(PSetTokens)
  *
  * \retval EINVAL      Error if some of the standard args aren't set
  *
- * \post The status of a volume (based on the FID of the volume), or an offline message /motd
+ * \post
+ *     The status of a volume (based on the FID of the volume), or an
+ *     offline message /motd
  */
 DECL_PIOCTL(PGetVolumeStatus)
 {
     char volName[32];
     char *offLineMsg = afs_osi_Alloc(256);
     char *motd = afs_osi_Alloc(256);
-    register struct afs_conn *tc;
-    register afs_int32 code = 0;
+    struct afs_conn *tc;
+    afs_int32 code = 0;
     struct AFSFetchVolumeStatus volstat;
-    register char *cp;
-    char *Name, *OfflineMsg, *MOTD;
+    char *Name;
     XSTATS_DECLS;
 
+    osi_Assert(offLineMsg != NULL);
+    osi_Assert(motd != NULL);
     AFS_STATCNT(PGetVolumeStatus);
     if (!avc) {
        code = EINVAL;
        goto out;
     }
     Name = volName;
-    OfflineMsg = offLineMsg;
-    MOTD = motd;
     do {
        tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
        if (tc) {
@@ -1599,7 +1976,7 @@ DECL_PIOCTL(PGetVolumeStatus)
            RX_AFS_GUNLOCK();
            code =
                RXAFS_GetVolumeStatus(tc->id, avc->f.fid.Fid.Volume, &volstat,
-                                     &Name, &OfflineMsg, &MOTD);
+                                     &Name, &offLineMsg, &motd);
            RX_AFS_GLOCK();
            XSTATS_END_TIME;
        } else
@@ -1611,16 +1988,14 @@ DECL_PIOCTL(PGetVolumeStatus)
     if (code)
        goto out;
     /* Copy all this junk into msg->im_data, keeping track of the lengths. */
-    cp = aout;
-    memcpy(cp, (char *)&volstat, sizeof(VolumeStatus));
-    cp += sizeof(VolumeStatus);
-    strcpy(cp, volName);
-    cp += strlen(volName) + 1;
-    strcpy(cp, offLineMsg);
-    cp += strlen(offLineMsg) + 1;
-    strcpy(cp, motd);
-    cp += strlen(motd) + 1;
-    *aoutSize = (cp - aout);
+    if (afs_pd_putBytes(aout, &volstat, sizeof(VolumeStatus)) != 0)
+       return E2BIG;
+    if (afs_pd_putString(aout, volName) != 0)
+       return E2BIG;
+    if (afs_pd_putString(aout, offLineMsg) != 0)
+       return E2BIG;
+    if (afs_pd_putString(aout, motd) != 0)
+       return E2BIG;
   out:
     afs_osi_Free(offLineMsg, 256);
     afs_osi_Free(motd, 256);
@@ -1632,68 +2007,72 @@ DECL_PIOCTL(PGetVolumeStatus)
  *
  * \ingroup pioctl
  *
- * \param[in] ain      values to set the status at, offline message, message of the day, volume name, minimum quota, maximum quota
- * \param[out] aout    status of a volume, offlines messages, minimum quota, maximumm quota
- *
- * \retval EINVAL      Error if some of the standard args aren't set
- * \retval EROFS       Error if the volume is read only, or a backup volume
- * \retval ENODEV      Error if the volume can't be accessed
- * \retval E2BIG       Error if the volume name, offline message, and motd are too big
- *
- * \post Set the status of a volume, including any offline messages, a minimum quota, and a maximum quota
+ * \param[in] ain
+ *     values to set the status at, offline message, message of the day,
+ *     volume name, minimum quota, maximum quota
+ * \param[out] aout
+ *     status of a volume, offlines messages, minimum quota, maximumm quota
+ *
+ * \retval EINVAL
+ *     Error if some of the standard args aren't set
+ * \retval EROFS
+ *     Error if the volume is read only, or a backup volume
+ * \retval ENODEV
+ *     Error if the volume can't be accessed
+ * \retval E2BIG
+ *     Error if the volume name, offline message, and motd are too big
+ *
+ * \post
+ *     Set the status of a volume, including any offline messages,
+ *     a minimum quota, and a maximum quota
  */
 DECL_PIOCTL(PSetVolumeStatus)
 {
-    char volName[32];
-    char *offLineMsg = afs_osi_Alloc(256);
-    char *motd = afs_osi_Alloc(256);
-    register struct afs_conn *tc;
-    register afs_int32 code = 0;
+    char *volName;
+    char *offLineMsg;
+    char *motd;
+    struct afs_conn *tc;
+    afs_int32 code = 0;
     struct AFSFetchVolumeStatus volstat;
     struct AFSStoreVolumeStatus storeStat;
-    register struct volume *tvp;
-    register char *cp;
+    struct volume *tvp;
     XSTATS_DECLS;
 
     AFS_STATCNT(PSetVolumeStatus);
-    if (!avc) {
-       code = EINVAL;
-       goto out;
-    }
+    if (!avc)
+       return EINVAL;
 
     tvp = afs_GetVolume(&avc->f.fid, areq, READ_LOCK);
     if (tvp) {
        if (tvp->states & (VRO | VBackup)) {
            afs_PutVolume(tvp, READ_LOCK);
-           code = EROFS;
-           goto out;
+           return EROFS;
        }
        afs_PutVolume(tvp, READ_LOCK);
-    } else {
-       code = ENODEV;
-       goto out;
-    }
-    /* Copy the junk out, using cp as a roving pointer. */
-    cp = ain;
-    memcpy((char *)&volstat, cp, sizeof(AFSFetchVolumeStatus));
-    cp += sizeof(AFSFetchVolumeStatus);
-    if (strlen(cp) >= sizeof(volName)) {
-       code = E2BIG;
-       goto out;
-    }
-    strcpy(volName, cp);
-    cp += strlen(volName) + 1;
-    if (strlen(cp) >= sizeof(offLineMsg)) {
-       code = E2BIG;
-       goto out;
-    }
-    strcpy(offLineMsg, cp);
-    cp += strlen(offLineMsg) + 1;
-    if (strlen(cp) >= sizeof(motd)) {
-       code = E2BIG;
-       goto out;
-    }
-    strcpy(motd, cp);
+    } else
+       return ENODEV;
+
+
+    if (afs_pd_getBytes(ain, &volstat, sizeof(AFSFetchVolumeStatus)) != 0)
+       return EINVAL;
+
+    if (afs_pd_getStringPtr(ain, &volName) != 0)
+       return EINVAL;
+    if (strlen(volName) > 32)
+        return E2BIG;
+
+    if (afs_pd_getStringPtr(ain, &offLineMsg) != 0)
+       return EINVAL;
+    if (strlen(offLineMsg) > 256)
+       return E2BIG;
+
+    if (afs_pd_getStringPtr(ain, &motd) != 0)
+       return EINVAL;
+    if (strlen(motd) > 256)
+       return E2BIG;
+
+    /* Done reading ... */
+
     storeStat.Mask = 0;
     if (volstat.MinQuota != -1) {
        storeStat.MinQuota = volstat.MinQuota;
@@ -1720,22 +2099,20 @@ DECL_PIOCTL(PSetVolumeStatus)
              SHARED_LOCK, NULL));
 
     if (code)
-       goto out;
+       return code;
     /* we are sending parms back to make compat. with prev system.  should
-     * change interface later to not ask for current status, just set new status */
-    cp = aout;
-    memcpy(cp, (char *)&volstat, sizeof(VolumeStatus));
-    cp += sizeof(VolumeStatus);
-    strcpy(cp, volName);
-    cp += strlen(volName) + 1;
-    strcpy(cp, offLineMsg);
-    cp += strlen(offLineMsg) + 1;
-    strcpy(cp, motd);
-    cp += strlen(motd) + 1;
-    *aoutSize = cp - aout;
-  out:
-    afs_osi_Free(offLineMsg, 256);
-    afs_osi_Free(motd, 256);
+     * change interface later to not ask for current status, just set new
+     * status */
+
+    if (afs_pd_putBytes(aout, &volstat, sizeof(VolumeStatus)) != 0)
+       return EINVAL;
+    if (afs_pd_putString(aout, volName) != 0)
+       return EINVAL;
+    if (afs_pd_putString(aout, offLineMsg) != 0)
+       return EINVAL;
+    if (afs_pd_putString(aout, motd) != 0)
+       return EINVAL;
+
     return code;
 }
 
@@ -1773,8 +2150,11 @@ DECL_PIOCTL(PFlush)
  *
  * \ingroup pioctl
  *
- * \param[in] ain      the last component in a path, related to mountpoint that we're looking for information about
- * \param[out] aout    volume, cell, link data 
+ * \param[in] ain
+ *     the last component in a path, related to mountpoint that we're
+ *     looking for information about
+ * \param[out] aout
+ *     volume, cell, link data
  *
  * \retval EINVAL      Error if some of the standard args aren't set
  * \retval ENOTDIR     Error if the 'mount point' argument isn't a directory
@@ -1784,17 +2164,22 @@ DECL_PIOCTL(PFlush)
  */
 DECL_PIOCTL(PNewStatMount)
 {
-    register afs_int32 code;
-    register struct vcache *tvc;
-    register struct dcache *tdc;
+    afs_int32 code;
+    struct vcache *tvc;
+    struct dcache *tdc;
     struct VenusFid tfid;
     char *bufp;
+    char *name;
     struct sysname_info sysState;
     afs_size_t offset, len;
 
     AFS_STATCNT(PNewStatMount);
     if (!avc)
        return EINVAL;
+
+    if (afs_pd_getStringPtr(ain, &name) != 0)
+       return EINVAL;
+
     code = afs_VerifyVCache(avc, areq);
     if (code)
        return code;
@@ -1804,7 +2189,7 @@ DECL_PIOCTL(PNewStatMount)
     tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
     if (!tdc)
        return ENOENT;
-    Check_AtSys(avc, ain, &sysState, areq);
+    Check_AtSys(avc, name, &sysState, areq);
     ObtainReadLock(&tdc->lock);
     do {
        code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
@@ -1839,8 +2224,8 @@ DECL_PIOCTL(PNewStatMount)
                code = EINVAL;
            else {
                /* we have the data */
-               strcpy(aout, tvc->linkData);
-               *aoutSize = strlen(tvc->linkData) + 1;
+               if (afs_pd_putString(aout, tvc->linkData) != 0)
+                   code = EINVAL;
            }
        } else
            code = EIO;
@@ -1854,30 +2239,66 @@ DECL_PIOCTL(PNewStatMount)
 }
 
 /*!
+ * A helper function to get the n'th cell which a particular user has tokens
+ * for. This is racy. If new tokens are added whilst we're iterating, then
+ * we may return some cells twice. If tokens expire mid run, then we'll
+ * miss some cells from our output. So, could be better, but that would
+ * require an interface change.
+ */
+
+static struct unixuser *
+getNthCell(afs_int32 uid, afs_int32 iterator) {
+    int i;
+    struct unixuser *tu = NULL;
+
+    i = UHash(uid);
+    ObtainReadLock(&afs_xuser);
+    for (tu = afs_users[i]; tu; tu = tu->next) {
+       if (tu->uid == uid && (tu->states & UHasTokens)) {
+           if (iterator-- == 0)
+           break;      /* are we done yet? */
+       }
+    }
+    if (tu) {
+       tu->refCount++;
+    }
+    ReleaseReadLock(&afs_xuser);
+
+    return tu;
+}
+/*!
  * VIOCGETTOK (8) - Get authentication tokens
- *  
+ *
  * \ingroup pioctl
- *      
- * \param[in] ain       userid
+ *
+ * \param[in] ain       cellid to return tokens for
  * \param[out] aout     token
- * 
- * \retval EIO         Error if the afs daemon hasn't started yet
- * \retval EDOM                Error if the input parameter is out of the bounds of the available tokens
- * \retval ENOTCONN    Error if there aren't tokens for this cell
- *  
- * \post If the input paramater exists, get the token that corresponds to the parameter value, if there is no token at this value, get the token for the first cell
+ *
+ * \retval EIO
+ *     Error if the afs daemon hasn't started yet
+ * \retval EDOM
+ *     Error if the input parameter is out of the bounds of the available
+ *     tokens
+ * \retval ENOTCONN
+ *     Error if there aren't tokens for this cell
+ *
+ * \post
+ *     If the input paramater exists, get the token that corresponds to
+ *     the parameter value, if there is no token at this value, get the
+ *     token for the first cell
  *
  * \notes "it's a weird interface (from comments in the code)"
  */
 
 DECL_PIOCTL(PGetTokens)
 {
-    register struct cell *tcell;
-    register afs_int32 i;
-    register struct unixuser *tu;
-    register char *cp;
+    struct cell *tcell;
+    struct unixuser *tu = NULL;
+    union tokenUnion *token;
     afs_int32 iterator = 0;
     int newStyle;
+    int cellNum;
+    int code = E2BIG;
 
     AFS_STATCNT(PGetTokens);
     if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
@@ -1892,69 +2313,76 @@ DECL_PIOCTL(PGetTokens)
      * tokens, the primary cell indicator (an afs_int32 0) and the cell name
      * at the end, in that order.
      */
-    if ((newStyle = (ainSize > 0))) {
-       memcpy((char *)&iterator, ain, sizeof(afs_int32));
-    }
-    i = UHash(areq->uid);
-    ObtainReadLock(&afs_xuser);
-    for (tu = afs_users[i]; tu; tu = tu->next) {
-       if (newStyle) {
-           if (tu->uid == areq->uid && (tu->states & UHasTokens)) {
-               if (iterator-- == 0)
-                   break;      /* are we done yet? */
-           }
-       } else {
-           if (tu->uid == areq->uid && afs_IsPrimaryCellNum(tu->cell))
-               break;
-       }
+    newStyle = (afs_pd_remaining(ain) > 0);
+    if (newStyle) {
+       if (afs_pd_getInt(ain, &iterator) != 0)
+           return EINVAL;
     }
-    if (tu) {
-       /*
-        * No need to hold a read lock on each user entry
-        */
-       tu->refCount++;
+    if (newStyle) {
+       tu = getNthCell(areq->uid, iterator);
+    } else {
+       cellNum = afs_GetPrimaryCellNum();
+       if (cellNum)
+           tu = afs_FindUser(areq->uid, cellNum, READ_LOCK);
     }
-    ReleaseReadLock(&afs_xuser);
-
     if (!tu) {
        return EDOM;
     }
-    if (((tu->states & UHasTokens) == 0)
-       || (tu->ct.EndTimestamp < osi_Time())) {
+    if (!(tu->states & UHasTokens)
+       || !afs_HasUsableTokens(tu->tokens, osi_Time())) {
        tu->states |= (UTokensBad | UNeedsReset);
+       afs_NotifyUser(tu, UTokensDropped);
        afs_PutUser(tu, READ_LOCK);
        return ENOTCONN;
     }
-    /* use iterator for temp */
-    cp = aout;
-    iterator = tu->stLen;      /* for compat, we try to return 56 byte tix if they fit */
+    token = afs_FindToken(tu->tokens, RX_SECIDX_KAD);
+
+    /* If they don't have an RXKAD token, but do have other tokens,
+     * then sadly there's nothing this interface can do to help them. */
+    if (token == NULL)
+       return ENOTCONN;
+
+    /* for compat, we try to return 56 byte tix if they fit */
+    iterator = token->rxkad.ticketLen;
     if (iterator < 56)
        iterator = 56;          /* # of bytes we're returning */
-    memcpy(cp, (char *)&iterator, sizeof(afs_int32));
-    cp += sizeof(afs_int32);
-    memcpy(cp, tu->stp, tu->stLen);    /* copy out st */
-    cp += iterator;
-    iterator = sizeof(struct ClearToken);
-    memcpy(cp, (char *)&iterator, sizeof(afs_int32));
-    cp += sizeof(afs_int32);
-    memcpy(cp, (char *)&tu->ct, sizeof(struct ClearToken));
-    cp += sizeof(struct ClearToken);
+
+    if (afs_pd_putInt(aout, iterator) != 0)
+       goto out;
+    if (afs_pd_putBytes(aout, token->rxkad.ticket, token->rxkad.ticketLen) != 0)
+       goto out;
+    if (token->rxkad.ticketLen < 56) {
+       /* Tokens are always 56 bytes or larger */
+       if (afs_pd_skip(aout, iterator - token->rxkad.ticketLen) != 0) {
+           goto out;
+       }
+    }
+
+    if (afs_pd_putInt(aout, sizeof(struct ClearToken)) != 0)
+       goto out;
+    if (afs_pd_putBytes(aout, &token->rxkad.clearToken,
+                       sizeof(struct ClearToken)) != 0)
+       goto out;
+
     if (newStyle) {
        /* put out primary id and cell name, too */
        iterator = (tu->states & UPrimary ? 1 : 0);
-       memcpy(cp, (char *)&iterator, sizeof(afs_int32));
-       cp += sizeof(afs_int32);
+       if (afs_pd_putInt(aout, iterator) != 0)
+           goto out;
        tcell = afs_GetCell(tu->cell, READ_LOCK);
        if (tcell) {
-           strcpy(cp, tcell->cellName);
-           cp += strlen(tcell->cellName) + 1;
+           if (afs_pd_putString(aout, tcell->cellName) != 0)
+               goto out;
            afs_PutCell(tcell, READ_LOCK);
        } else
-           *cp++ = 0;
+           if (afs_pd_putString(aout, "") != 0)
+               goto out;
     }
-    *aoutSize = cp - aout;
+    /* Got here, all is good */
+    code = 0;
+out:
     afs_PutUser(tu, READ_LOCK);
-    return 0;
+    return code;
 }
 
 /*!
@@ -1974,8 +2402,8 @@ DECL_PIOCTL(PGetTokens)
  */
 DECL_PIOCTL(PUnlog)
 {
-    register afs_int32 i;
-    register struct unixuser *tu;
+    afs_int32 i;
+    struct unixuser *tu;
 
     AFS_STATCNT(PUnlog);
     if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
@@ -1985,19 +2413,18 @@ DECL_PIOCTL(PUnlog)
     ObtainWriteLock(&afs_xuser, 227);
     for (tu = afs_users[i]; tu; tu = tu->next) {
        if (tu->uid == areq->uid) {
-           tu->vid = UNDEFVID;
            tu->states &= ~UHasTokens;
-           /* security is not having to say you're sorry */
-           memset(&tu->ct, 0, sizeof(struct ClearToken));
+           afs_FreeTokens(&tu->tokens);
            tu->refCount++;
            ReleaseWriteLock(&afs_xuser);
-           /* We have to drop the lock over the call to afs_ResetUserConns, since
-            * it obtains the afs_xvcache lock.  We could also keep the lock, and
-            * modify ResetUserConns to take parm saying we obtained the lock
-            * already, but that is overkill.  By keeping the "tu" pointer
-            * held over the released lock, we guarantee that we won't lose our
-            * place, and that we'll pass over every user conn that existed when
-            * we began this call.
+           afs_NotifyUser(tu, UTokensDropped);
+           /* We have to drop the lock over the call to afs_ResetUserConns,
+            * since it obtains the afs_xvcache lock.  We could also keep
+            * the lock, and modify ResetUserConns to take parm saying we
+            * obtained the lock already, but that is overkill.  By keeping
+            * the "tu" pointer held over the released lock, we guarantee
+            * that we won't lose our place, and that we'll pass over
+            * every user conn that existed when we began this call.
             */
            afs_ResetUserConns(tu);
            tu->refCount--;
@@ -2006,7 +2433,6 @@ DECL_PIOCTL(PUnlog)
            /* set the expire times to 0, causes
             * afs_GCUserData to remove this entry
             */
-           tu->ct.EndTimestamp = 0;
            tu->tokenTime = 0;
 #endif /* UKERNEL */
        }
@@ -2023,7 +2449,10 @@ DECL_PIOCTL(PUnlog)
  * \param[in] ain      host address to be set
  * \param[out] aout    old host address
  *
- * \post depending on whether or not a variable is set, either get the host for the cache manager monitor, or set the old address and give it a new address
+ * \post
+ *     depending on whether or not a variable is set, either get the host
+ *     for the cache manager monitor, or set the old address and give it
+ *     a new address
  *
  * \notes Errors turn off mariner
  */
@@ -2039,7 +2468,9 @@ DECL_PIOCTL(PMariner)
     else
        oldHostAddr = 0xffffffff;       /* disabled */
 
-    memcpy((char *)&newHostAddr, ain, sizeof(afs_int32));
+    if (afs_pd_getInt(ain, &newHostAddr) != 0)
+       return EINVAL;
+
     if (newHostAddr == 0xffffffff) {
        /* disable mariner operations */
        afs_mariner = 0;
@@ -2047,8 +2478,10 @@ DECL_PIOCTL(PMariner)
        afs_mariner = 1;
        afs_marinerHost = newHostAddr;
     }
-    memcpy(aout, (char *)&oldHostAddr, sizeof(afs_int32));
-    *aoutSize = sizeof(afs_int32);
+
+    if (afs_pd_putInt(aout, oldHostAddr) != 0)
+       return E2BIG;
+
     return 0;
 }
 
@@ -2064,14 +2497,16 @@ DECL_PIOCTL(PMariner)
  * \retval EACCES      Error if the user doesn't have super-user credentials
  * \retval ENOENT      Error if we are unable to obtain the cell
  *
- * \post Either a fast check (where it doesn't contact servers) or a local check (checks local cell only)
+ * \post
+ *     Either a fast check (where it doesn't contact servers) or a
+ *     local check (checks local cell only)
  */
 DECL_PIOCTL(PCheckServers)
 {
-    register char *cp = 0;
-    register int i;
-    register struct server *ts;
-    afs_int32 temp, *lp = (afs_int32 *) ain, havecell = 0;
+    int i;
+    struct server *ts;
+    afs_int32 temp;
+    char *cellName = NULL;
     struct cell *cellp;
     struct chservinfo *pcheck;
 
@@ -2080,12 +2515,21 @@ DECL_PIOCTL(PCheckServers)
     if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
        return EIO;             /* Inappropriate ioctl for device */
 
-    if (*lp == 0x12345678) {   /* For afs3.3 version */
-       pcheck = (struct chservinfo *)ain;
+    /* This is tricky, because we need to peak at the datastream to see
+     * what we're getting. For now, let's cheat. */
+
+    /* ain contains either an int32 or a string */
+    if (ain->remaining == 0)
+       return EINVAL;
+
+    if (*(afs_int32 *)ain->ptr == 0x12345678) {        /* For afs3.3 version */
+       pcheck = afs_pd_inline(ain, sizeof(*pcheck));
+        if (pcheck == NULL)
+           return EINVAL;
+
        if (pcheck->tinterval >= 0) {
-           cp = aout;
-           memcpy(cp, (char *)&afs_probe_interval, sizeof(afs_int32));
-           *aoutSize = sizeof(afs_int32);
+           if (afs_pd_putInt(aout, afs_probe_interval) != 0)
+               return E2BIG;
            if (pcheck->tinterval > 0) {
                if (!afs_osi_suser(*acred))
                    return EACCES;
@@ -2093,24 +2537,25 @@ DECL_PIOCTL(PCheckServers)
            }
            return 0;
        }
-       if (pcheck->tsize)
-           havecell = 1;
        temp = pcheck->tflags;
-       cp = pcheck->tbuffer;
+       if (pcheck->tsize)
+           cellName = pcheck->tbuffer;
     } else {                   /* For pre afs3.3 versions */
-       memcpy((char *)&temp, ain, sizeof(afs_int32));
-       cp = ain + sizeof(afs_int32);
-       if (ainSize > sizeof(afs_int32))
-           havecell = 1;
+       if (afs_pd_getInt(ain, &temp) != 0)
+           return EINVAL;
+       if (afs_pd_remaining(ain) > 0) {
+           if (afs_pd_getStringPtr(ain, &cellName) != 0)
+               return EINVAL;
+       }
     }
 
     /*
      * 1: fast check, don't contact servers.
      * 2: local cell only.
      */
-    if (havecell) {
+    if (cellName) {
        /* have cell name, too */
-       cellp = afs_GetCellByName(cp, READ_LOCK);
+       cellp = afs_GetCellByName(cellName, READ_LOCK);
        if (!cellp)
            return ENOENT;
     } else
@@ -2124,7 +2569,6 @@ DECL_PIOCTL(PCheckServers)
        afs_CheckServers(0, cellp);     /* check up servers */
     }
     /* now return the current down server list */
-    cp = aout;
     ObtainReadLock(&afs_xserver);
     for (i = 0; i < NSERVERS; i++) {
        for (ts = afs_servers[i]; ts; ts = ts->next) {
@@ -2132,15 +2576,13 @@ DECL_PIOCTL(PCheckServers)
                continue;       /* cell spec'd and wrong */
            if ((ts->flags & SRVR_ISDOWN)
                && ts->addr->sa_portal != ts->cell->vlport) {
-               memcpy(cp, (char *)&ts->addr->sa_ip, sizeof(afs_int32));
-               cp += sizeof(afs_int32);
+               afs_pd_putInt(aout, ts->addr->sa_ip);
            }
        }
     }
     ReleaseReadLock(&afs_xserver);
     if (cellp)
        afs_PutCell(cellp, READ_LOCK);
-    *aoutSize = cp - aout;
     return 0;
 }
 
@@ -2154,7 +2596,10 @@ DECL_PIOCTL(PCheckServers)
  *
  * \retval EIO         Error if the afs daemon hasn't started yet
  *
- * \post Check the root volume, and then check the names if the volume check variable is set to force, has expired, is busy, or if the mount points variable is set
+ * \post
+ *     Check the root volume, and then check the names if the volume
+ *     check variable is set to force, has expired, is busy, or if
+ *     the mount points variable is set
  */
 DECL_PIOCTL(PCheckVolNames)
 {
@@ -2176,9 +2621,13 @@ DECL_PIOCTL(PCheckVolNames)
  * \param[in] ain      not in use
  * \param[out] aout    not in use
  *
- * \retval EACCESS Error if no user is specififed, the user has no tokens set, or if the user's tokens are bad
+ * \retval EACCESS
+ *     Error if no user is specififed, the user has no tokens set,
+ *     or if the user's tokens are bad
  *
- * \post check to see if a user has the correct authentication.  If so, allow access.
+ * \post
+ *     check to see if a user has the correct authentication.
+ *     If so, allow access.
  *
  * \notes Check the connections to all the servers specified
  */
@@ -2186,7 +2635,7 @@ DECL_PIOCTL(PCheckAuth)
 {
     int i;
     struct srvAddr *sa;
-    struct afs_conn *tc;
+    struct sa_conn_vector *tcv;
     struct unixuser *tu;
     afs_int32 retValue;
 
@@ -2209,8 +2658,8 @@ DECL_PIOCTL(PCheckAuth)
        /* all connections in cell 1 working? */
        for (i = 0; i < NSERVERS; i++) {
            for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
-               for (tc = sa->conns; tc; tc = tc->next) {
-                   if (tc->user == tu && (tu->states & UTokensBad))
+               for (tcv = sa->conns; tcv; tcv = tcv->next) {
+                   if (tcv->user == tu && (tu->states & UTokensBad))
                        retValue = EACCES;
                }
            }
@@ -2219,8 +2668,8 @@ DECL_PIOCTL(PCheckAuth)
        ReleaseReadLock(&afs_xconn);
        afs_PutUser(tu, READ_LOCK);
     }
-    memcpy(aout, (char *)&retValue, sizeof(afs_int32));
-    *aoutSize = sizeof(afs_int32);
+    if (afs_pd_putInt(aout, retValue) != 0)
+       return E2BIG;
     return 0;
 }
 
@@ -2228,8 +2677,8 @@ static int
 Prefetch(uparmtype apath, struct afs_ioctl *adata, int afollow,
         afs_ucred_t *acred)
 {
-    register char *tp;
-    register afs_int32 code;
+    char *tp;
+    afs_int32 code;
 #if defined(AFS_SGI61_ENV) || defined(AFS_SUN57_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
     size_t bufferSize;
 #else
@@ -2250,7 +2699,7 @@ Prefetch(uparmtype apath, struct afs_ioctl *adata, int afollow,
        return EWOULDBLOCK;     /* pretty close */
     }
     afs_BQueue(BOP_PATH, (struct vcache *)0, 0, 0, acred, (afs_size_t) 0,
-              (afs_size_t) 0, tp);
+              (afs_size_t) 0, tp, (void *)0, (void *)0);
     return 0;
 }
 
@@ -2271,35 +2720,37 @@ Prefetch(uparmtype apath, struct afs_ioctl *adata, int afollow,
  */
 DECL_PIOCTL(PFindVolume)
 {
-    register struct volume *tvp;
-    register struct server *ts;
-    register afs_int32 i;
-    register char *cp;
+    struct volume *tvp;
+    struct server *ts;
+    afs_int32 i;
+    int code = 0;
 
     AFS_STATCNT(PFindVolume);
     if (!avc)
        return EINVAL;
     tvp = afs_GetVolume(&avc->f.fid, areq, READ_LOCK);
-    if (tvp) {
-       cp = aout;
-       for (i = 0; i < AFS_MAXHOSTS; i++) {
-           ts = tvp->serverHost[i];
-           if (!ts)
-               break;
-           memcpy(cp, (char *)&ts->addr->sa_ip, sizeof(afs_int32));
-           cp += sizeof(afs_int32);
+    if (!tvp)
+       return ENODEV;
+
+    for (i = 0; i < AFS_MAXHOSTS; i++) {
+       ts = tvp->serverHost[i];
+       if (!ts)
+           break;
+       if (afs_pd_putInt(aout, ts->addr->sa_ip) != 0) {
+           code = E2BIG;
+           goto out;
        }
-       if (i < AFS_MAXHOSTS) {
-           /* still room for terminating NULL, add it on */
-           ainSize = 0;        /* reuse vbl */
-           memcpy(cp, (char *)&ainSize, sizeof(afs_int32));
-           cp += sizeof(afs_int32);
+    }
+    if (i < AFS_MAXHOSTS) {
+       /* still room for terminating NULL, add it on */
+       if (afs_pd_putInt(aout, 0) != 0) {
+           code = E2BIG;
+           goto out;
        }
-       *aoutSize = cp - aout;
-       afs_PutVolume(tvp, READ_LOCK);
-       return 0;
     }
-    return ENODEV;
+out:
+    afs_PutVolume(tvp, READ_LOCK);
+    return code;
 }
 
 /*!
@@ -2317,16 +2768,20 @@ DECL_PIOCTL(PFindVolume)
  */
 DECL_PIOCTL(PViceAccess)
 {
-    register afs_int32 code;
+    afs_int32 code;
     afs_int32 temp;
 
     AFS_STATCNT(PViceAccess);
     if (!avc)
        return EINVAL;
+
     code = afs_VerifyVCache(avc, areq);
     if (code)
        return code;
-    memcpy((char *)&temp, ain, sizeof(afs_int32));
+
+    if (afs_pd_getInt(ain, &temp) != 0)
+       return EINVAL;
+
     code = afs_AccessOK(avc, temp, areq, CHECK_MODE_BITS);
     if (code)
        return 0;
@@ -2350,9 +2805,7 @@ DECL_PIOCTL(PGetPAG)
 
     pag = PagInCred(*acred);
 
-    memcpy(aout, (char *)&pag, sizeof(afs_int32));
-    *aoutSize = sizeof(afs_int32);
-    return 0;
+    return afs_pd_putInt(aout, pag);
 }
 
 DECL_PIOCTL(PPrecache)
@@ -2362,7 +2815,10 @@ DECL_PIOCTL(PPrecache)
     /*AFS_STATCNT(PPrecache);*/
     if (!afs_osi_suser(*acred))
        return EACCES;
-    memcpy((char *)&newValue, ain, sizeof(afs_int32));
+
+    if (afs_pd_getInt(ain, &newValue) != 0)
+       return EINVAL;
+
     afs_preCache = newValue*1024;
     return 0;
 }
@@ -2378,9 +2834,12 @@ DECL_PIOCTL(PPrecache)
  * \retval EACCES      Error if the user doesn't have super-user credentials
  * \retval EROFS       Error if the cache is set to be in memory
  *
- * \post Set the cache size based on user input.  If no size is given, set it to the default OpenAFS cache size.
+ * \post
+ *     Set the cache size based on user input.  If no size is given,
+ *     set it to the default OpenAFS cache size.
  *
- * \notes recompute the general cache parameters for every single block allocated
+ * \notes
+ *     recompute the general cache parameters for every single block allocated
  */
 DECL_PIOCTL(PSetCacheSize)
 {
@@ -2388,12 +2847,14 @@ DECL_PIOCTL(PSetCacheSize)
     int waitcnt = 0;
 
     AFS_STATCNT(PSetCacheSize);
+
     if (!afs_osi_suser(*acred))
        return EACCES;
     /* too many things are setup initially in mem cache version */
     if (cacheDiskType == AFS_FCACHE_TYPE_MEM)
        return EROFS;
-    memcpy((char *)&newValue, ain, sizeof(afs_int32));
+    if (afs_pd_getInt(ain, &newValue) != 0)
+       return EINVAL;
     if (newValue == 0)
        afs_cacheBlocks = afs_stats_cmperf.cacheBlocksOrig;
     else {
@@ -2427,24 +2888,24 @@ DECL_PIOCTL(PGetCacheSize)
 {
     afs_int32 results[MAXGCSTATS];
     afs_int32 flags;
-    register struct dcache * tdc;
+    struct dcache * tdc;
     int i, size;
-    
+
     AFS_STATCNT(PGetCacheSize);
 
-    if (sizeof(afs_int32) == ainSize){
-       memcpy((char *)&flags, ain, sizeof(afs_int32));
-    } else if (0 == ainSize){ 
+    if (afs_pd_remaining(ain) == sizeof(afs_int32)) {
+       afs_pd_getInt(ain, &flags); /* can't error, we just checked size */
+    } else if (afs_pd_remaining(ain) == 0) {
        flags = 0;
     } else {
        return EINVAL;
     }
-    
+
     memset(results, 0, sizeof(results));
     results[0] = afs_cacheBlocks;
     results[1] = afs_blocksUsed;
     results[2] = afs_cacheFiles;
-    
+
     if (1 == flags){
         for (i = 0; i < afs_cacheFiles; i++) {
            if (afs_indexFlags[i] & IFFree) results[3]++;
@@ -2471,9 +2932,7 @@ DECL_PIOCTL(PGetCacheSize)
            }
         }
     }
-    memcpy(aout, (char *)results, sizeof(results));
-    *aoutSize = sizeof(results);
-    return 0;
+    return afs_pd_putBytes(aout, results, sizeof(results));
 }
 
 /*!
@@ -2487,12 +2946,15 @@ DECL_PIOCTL(PGetCacheSize)
  * \retval EINVAL      Error if some of the standard args aren't set
  * \retval 0           0 returned if the volume is set to read-only
  *
- * \post Flushes callbacks, by setting the length of callbacks to one, setting the next callback to be sent to the CB_DROPPED value, and then dequeues everything else.
+ * \post
+ *     Flushes callbacks, by setting the length of callbacks to one,
+ *     setting the next callback to be sent to the CB_DROPPED value,
+ *     and then dequeues everything else.
  */
 DECL_PIOCTL(PRemoveCallBack)
 {
-    register struct afs_conn *tc;
-    register afs_int32 code = 0;
+    struct afs_conn *tc;
+    afs_int32 code = 0;
     struct AFSCallBack CallBacks_Array[1];
     struct AFSCBFids theFids;
     struct AFSCBs theCBs;
@@ -2541,8 +3003,12 @@ DECL_PIOCTL(PRemoveCallBack)
  *
  * \ingroup pioctl
  *
- * \param[in] ain      the name of the cell, the hosts that will be a part of the cell, whether or not it's linked with another cell, the other cell it's linked with, the file server port, and the volume server port
- * \param[out] aout    not in use
+ * \param[in] ain
+ *     the name of the cell, the hosts that will be a part of the cell,
+ *     whether or not it's linked with another cell, the other cell it's
+ *     linked with, the file server port, and the volume server port
+ * \param[out] aout
+ *     not in use
  *
  * \retval EIO         Error if the afs daemon hasn't started yet
  * \retval EACCES      Error if the user doesn't have super-user cedentials
@@ -2552,12 +3018,13 @@ DECL_PIOCTL(PRemoveCallBack)
  */
 DECL_PIOCTL(PNewCell)
 {
-    /* create a new cell */
-    afs_int32 cellHosts[AFS_MAXCELLHOSTS], *lp, magic = 0;
-    char *newcell = 0, *linkedcell = 0, *tp = ain;
-    register afs_int32 code, linkedstate = 0, ls;
-    u_short fsport = 0, vlport = 0;
-    afs_int32 scount;
+    afs_int32 cellHosts[AFS_MAXCELLHOSTS], magic = 0;
+    char *newcell = NULL;
+    char *linkedcell = NULL;
+    afs_int32 code, ls;
+    afs_int32 linkedstate = 0;
+    afs_int32 fsport = 0, vlport = 0;
+    int skip;
 
     AFS_STATCNT(PNewCell);
     if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
@@ -2566,8 +3033,8 @@ DECL_PIOCTL(PNewCell)
     if (!afs_osi_suser(*acred))
        return EACCES;
 
-    memcpy((char *)&magic, tp, sizeof(afs_int32));
-    tp += sizeof(afs_int32);
+    if (afs_pd_getInt(ain, &magic) != 0)
+       return EINVAL;
     if (magic != 0x12345678)
        return EINVAL;
 
@@ -2575,25 +3042,46 @@ DECL_PIOCTL(PNewCell)
      * server addresses while the 3.5 fs newcell command passes
      * AFS_MAXHOSTS. To figure out which is which, check if the cellname
      * is good.
+     *
+     * This whole logic is bogus, because it relies on the newer command
+     * sending its 12th address as 0.
      */
-    newcell = tp + (AFS_MAXCELLHOSTS + 3) * sizeof(afs_int32);
-    scount = ((newcell[0] != '\0') ? AFS_MAXCELLHOSTS : AFS_MAXHOSTS);
+    if ((afs_pd_remaining(ain) < AFS_MAXCELLHOSTS +3) * sizeof(afs_int32))
+       return EINVAL;
+
+    newcell = afs_pd_where(ain) + (AFS_MAXCELLHOSTS + 3) * sizeof(afs_int32);
+    if (newcell[0] != '\0') {
+       skip = 0;
+    } else {
+       skip = AFS_MAXHOSTS - AFS_MAXCELLHOSTS;
+    }
 
     /* AFS_MAXCELLHOSTS (=8) is less than AFS_MAXHOSTS (=13) */
-    memcpy((char *)cellHosts, tp, AFS_MAXCELLHOSTS * sizeof(afs_int32));
-    tp += (scount * sizeof(afs_int32));
+    if (afs_pd_getBytes(ain, &cellHosts,
+                       AFS_MAXCELLHOSTS * sizeof(afs_int32)) != 0)
+       return EINVAL;
+    if (afs_pd_skip(ain, skip * sizeof(afs_int32)) !=0)
+       return EINVAL;
 
-    lp = (afs_int32 *) tp;
-    fsport = *lp++;
-    vlport = *lp++;
+    if (afs_pd_getInt(ain, &fsport) != 0)
+       return EINVAL;
     if (fsport < 1024)
        fsport = 0;             /* Privileged ports not allowed */
+
+    if (afs_pd_getInt(ain, &vlport) != 0)
+       return EINVAL;
     if (vlport < 1024)
        vlport = 0;             /* Privileged ports not allowed */
-    tp += (3 * sizeof(afs_int32));
-    newcell = tp;
-    if ((ls = *lp) & 1) {
-       linkedcell = tp + strlen(newcell) + 1;
+
+    if (afs_pd_getInt(ain, &ls) != 0)
+       return EINVAL;
+
+    if (afs_pd_getStringPtr(ain, &newcell) != 0)
+       return EINVAL;
+
+    if (ls & 1) {
+       if (afs_pd_getStringPtr(ain, &linkedcell) != 0)
+           return EINVAL;
        linkedstate |= CLinkedCell;
     }
 
@@ -2607,8 +3095,6 @@ DECL_PIOCTL(PNewCell)
 DECL_PIOCTL(PNewAlias)
 {
     /* create a new cell alias */
-    char *tp = ain;
-    register afs_int32 code;
     char *realName, *aliasName;
 
     if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
@@ -2617,13 +3103,12 @@ DECL_PIOCTL(PNewAlias)
     if (!afs_osi_suser(*acred))
        return EACCES;
 
-    aliasName = tp;
-    tp += strlen(aliasName) + 1;
-    realName = tp;
+    if (afs_pd_getStringPtr(ain, &aliasName) != 0)
+       return EINVAL;
+    if (afs_pd_getStringPtr(ain, &realName) != 0)
+       return EINVAL;
 
-    code = afs_NewCellAlias(aliasName, realName);
-    *aoutSize = 0;
-    return code;
+    return afs_NewCellAlias(aliasName, realName);
 }
 
 /*!
@@ -2642,67 +3127,68 @@ DECL_PIOCTL(PNewAlias)
 DECL_PIOCTL(PListCells)
 {
     afs_int32 whichCell;
-    register struct cell *tcell = 0;
-    register afs_int32 i;
-    register char *cp, *tp = ain;
+    struct cell *tcell = 0;
+    afs_int32 i;
+    int code;
 
     AFS_STATCNT(PListCells);
     if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
        return EIO;             /* Inappropriate ioctl for device */
 
-    memcpy((char *)&whichCell, tp, sizeof(afs_int32));
-    tp += sizeof(afs_int32);
+    if (afs_pd_getInt(ain, &whichCell) != 0)
+       return EINVAL;
+
     tcell = afs_GetCellByIndex(whichCell, READ_LOCK);
-    if (tcell) {
-       cp = aout;
-       memset(cp, 0, AFS_MAXCELLHOSTS * sizeof(afs_int32));
-       for (i = 0; i < AFS_MAXCELLHOSTS; i++) {
-           if (tcell->cellHosts[i] == 0)
-               break;
-           memcpy(cp, (char *)&tcell->cellHosts[i]->addr->sa_ip,
-                  sizeof(afs_int32));
-           cp += sizeof(afs_int32);
-       }
-       cp = aout + AFS_MAXCELLHOSTS * sizeof(afs_int32);
-       strcpy(cp, tcell->cellName);
-       cp += strlen(tcell->cellName) + 1;
-       *aoutSize = cp - aout;
-       afs_PutCell(tcell, READ_LOCK);
-    }
-    if (tcell)
-       return 0;
-    else
+    if (!tcell)
        return EDOM;
+
+    code = E2BIG;
+
+    for (i = 0; i < AFS_MAXCELLHOSTS; i++) {
+       if (tcell->cellHosts[i] == 0)
+           break;
+       if (afs_pd_putInt(aout, tcell->cellHosts[i]->addr->sa_ip) != 0)
+           goto out;
+    }
+    for (;i < AFS_MAXCELLHOSTS; i++) {
+       if (afs_pd_putInt(aout, 0) != 0)
+           goto out;
+    }
+    if (afs_pd_putString(aout, tcell->cellName) != 0)
+       goto out;
+    code = 0;
+
+out:
+    afs_PutCell(tcell, READ_LOCK);
+    return code;
 }
 
 DECL_PIOCTL(PListAliases)
 {
     afs_int32 whichAlias;
-    register struct cell_alias *tcalias = 0;
-    register char *cp, *tp = ain;
+    struct cell_alias *tcalias = 0;
+    int code;
 
     if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
        return EIO;             /* Inappropriate ioctl for device */
-    if (ainSize < sizeof(afs_int32))
-       return EINVAL;
 
-    memcpy((char *)&whichAlias, tp, sizeof(afs_int32));
-    tp += sizeof(afs_int32);
+    if (afs_pd_getInt(ain, &whichAlias) != 0)
+       return EINVAL;
 
     tcalias = afs_GetCellAlias(whichAlias);
-    if (tcalias) {
-       cp = aout;
-       strcpy(cp, tcalias->alias);
-       cp += strlen(tcalias->alias) + 1;
-       strcpy(cp, tcalias->cell);
-       cp += strlen(tcalias->cell) + 1;
-       *aoutSize = cp - aout;
-       afs_PutCellAlias(tcalias);
-    }
-    if (tcalias)
-       return 0;
-    else
+    if (tcalias == NULL)
        return EDOM;
+
+    code = E2BIG;
+    if (afs_pd_putString(aout, tcalias->alias) != 0)
+       goto out;
+    if (afs_pd_putString(aout, tcalias->cell) != 0)
+       goto out;
+
+    code = 0;
+out:
+    afs_PutCellAlias(tcalias);
+    return code;
 }
 
 /*!
@@ -2713,32 +3199,41 @@ DECL_PIOCTL(PListAliases)
  * \param[in] ain      the name of the file in this dir to remove
  * \param[out] aout    not in use
  *
- * \retval EINVAL      Error if some of the standard args aren't set
- * \retval ENOTDIR     Error if the argument to remove is not a directory
- * \retval ENOENT      Error if there is no cache to remove the mount point from or if a vcache doesn't exist
- *
- * \post Ensure that everything is OK before deleting the mountpoint.  If not, don't delete.  Delete a mount point based on a file id.
+ * \retval EINVAL
+ *     Error if some of the standard args aren't set
+ * \retval ENOTDIR
+ *     Error if the argument to remove is not a directory
+ * \retval ENOENT
+ *     Error if there is no cache to remove the mount point from or
+ *     if a vcache doesn't exist
+ *
+ * \post
+ *     Ensure that everything is OK before deleting the mountpoint.
+ *     If not, don't delete.  Delete a mount point based on a file id.
  */
 DECL_PIOCTL(PRemoveMount)
 {
-    register afs_int32 code;
+    afs_int32 code;
     char *bufp;
+    char *name;
     struct sysname_info sysState;
     afs_size_t offset, len;
-    register struct afs_conn *tc;
-    register struct dcache *tdc;
-    register struct vcache *tvc;
+    struct afs_conn *tc;
+    struct dcache *tdc;
+    struct vcache *tvc;
     struct AFSFetchStatus OutDirStatus;
     struct VenusFid tfid;
     struct AFSVolSync tsync;
     XSTATS_DECLS;
 
-
     /* "ain" is the name of the file in this dir to remove */
 
     AFS_STATCNT(PRemoveMount);
     if (!avc)
        return EINVAL;
+    if (afs_pd_getStringPtr(ain, &name) != 0)
+       return EINVAL;
+
     code = afs_VerifyVCache(avc, areq);
     if (code)
        return code;
@@ -2748,7 +3243,7 @@ DECL_PIOCTL(PRemoveMount)
     tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);  /* test for error below */
     if (!tdc)
        return ENOENT;
-    Check_AtSys(avc, ain, &sysState, areq);
+    Check_AtSys(avc, name, &sysState, areq);
     ObtainReadLock(&tdc->lock);
     do {
        code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
@@ -2841,20 +3336,6 @@ DECL_PIOCTL(PRemoveMount)
 }
 
 /*!
- * VIOC_VENUSLOG (34) - Enable/Disable venus logging
- *
- * \ingroup pioctl
- *
- * \retval EINVAL      Error if some of the standard args aren't set
- *
- * \notes Obsoleted, perhaps should be PBogus
- */
-DECL_PIOCTL(PVenusLogging)
-{
-    return EINVAL;             /* OBSOLETE */
-}
-
-/*!
  * VIOC_GETCELLSTATUS (35) - Get cell status info
  *
  * \ingroup pioctl
@@ -2869,21 +3350,24 @@ DECL_PIOCTL(PVenusLogging)
  */
 DECL_PIOCTL(PGetCellStatus)
 {
-    register struct cell *tcell;
+    struct cell *tcell;
+    char *cellName;
     afs_int32 temp;
 
     AFS_STATCNT(PGetCellStatus);
     if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
        return EIO;             /* Inappropriate ioctl for device */
 
-    tcell = afs_GetCellByName(ain, READ_LOCK);
+    if (afs_pd_getStringPtr(ain, &cellName) != 0)
+       return EINVAL;
+
+    tcell = afs_GetCellByName(cellName, READ_LOCK);
     if (!tcell)
        return ENOENT;
     temp = tcell->states;
     afs_PutCell(tcell, READ_LOCK);
-    memcpy(aout, (char *)&temp, sizeof(afs_int32));
-    *aoutSize = sizeof(afs_int32);
-    return 0;
+
+    return afs_pd_putInt(aout, temp);
 }
 
 /*!
@@ -2891,29 +3375,41 @@ DECL_PIOCTL(PGetCellStatus)
  *
  * \ingroup pioctl
  *
- * \param[in] ain      The cell you want to set information about, and the values you want to set
- * \param[out] aout    not in use
+ * \param[in] ain
+ *     The cell you want to set information about, and the values you
+ *     want to set
+ * \param[out] aout
+ *     not in use
  *
  * \retval EIO         Error if the afs daemon hasn't started yet
  * \retval EACCES      Error if the user doesn't have super-user credentials
  *
- * \post Set the state of the cell in a defined struct cell, based on whether or not SetUID is allowed
+ * \post
+ *     Set the state of the cell in a defined struct cell, based on
+ *     whether or not SetUID is allowed
  */
 DECL_PIOCTL(PSetCellStatus)
 {
-    register struct cell *tcell;
-    afs_int32 temp;
+    struct cell *tcell;
+    char *cellName;
+    afs_int32 flags0, flags1;
 
     if (!afs_osi_suser(*acred))
        return EACCES;
     if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
        return EIO;             /* Inappropriate ioctl for device */
 
-    tcell = afs_GetCellByName(ain + 2 * sizeof(afs_int32), WRITE_LOCK);
+    if (afs_pd_getInt(ain, &flags0) != 0)
+       return EINVAL;
+    if (afs_pd_getInt(ain, &flags1) != 0)
+       return EINVAL;
+    if (afs_pd_getStringPtr(ain, &cellName) != 0)
+       return EINVAL;
+
+    tcell = afs_GetCellByName(cellName, WRITE_LOCK);
     if (!tcell)
        return ENOENT;
-    memcpy((char *)&temp, ain, sizeof(afs_int32));
-    if (temp & CNoSUID)
+    if (flags0 & CNoSUID)
        tcell->states |= CNoSUID;
     else
        tcell->states &= ~CNoSUID;
@@ -2932,16 +3428,21 @@ DECL_PIOCTL(PSetCellStatus)
  * \retval EINVAL      Error if some of the standard args aren't set
  * \retval EIO         Error if the afs daemon hasn't started yet
  *
- * \post Wipe everything on the volume.  This is done dependent on which platform this is for.
+ * \post
+ *     Flush all cached contents of a volume.  Exactly what stays and what
+ *     goes depends on the platform.
  *
- * \notes Does not flush a file that a user has open and is using, because it will be re-created on next write.  Also purges the dnlc, because things are screwed up.
+ * \notes
+ *     Does not flush a file that a user has open and is using, because
+ *     it will be re-created on next write.  Also purges the dnlc,
+ *     because things are screwed up.
  */
 DECL_PIOCTL(PFlushVolumeData)
 {
-    register afs_int32 i;
-    register struct dcache *tdc;
-    register struct vcache *tvc;
-    register struct volume *tv;
+    afs_int32 i;
+    struct dcache *tdc;
+    struct vcache *tvc;
+    struct volume *tv;
     afs_int32 cell, volume;
     struct afs_q *tq, *uq;
 #ifdef AFS_DARWIN80_ENV
@@ -2958,8 +3459,8 @@ DECL_PIOCTL(PFlushVolumeData)
     cell = avc->f.fid.Cell;
 
     /*
-     * Clear stat'd flag from all vnodes from this volume; this will invalidate all
-     * the vcaches associated with the volume.
+     * Clear stat'd flag from all vnodes from this volume; this will
+     * invalidate all the vcaches associated with the volume.
      */
  loop:
     ObtainReadLock(&afs_xvcache);
@@ -2975,14 +3476,12 @@ DECL_PIOCTL(PFlushVolumeData)
                }
 #ifdef AFS_DARWIN80_ENV
                if (tvc->f.states & CDeadVnode) {
-                   ReleaseReadLock(&afs_xvcache);
-                   afs_osi_Sleep(&tvc->f.states);
-                   goto loop;
+                   if (!(tvc->f.states & CBulkFetching)) {
+                       ReleaseReadLock(&afs_xvcache);
+                       afs_osi_Sleep(&tvc->f.states);
+                       goto loop;
+                   }
                }
-#endif
-#if    defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV)  || defined(AFS_HPUX_ENV) || defined(AFS_LINUX20_ENV)
-               VN_HOLD(AFSTOV(tvc));
-#elif defined(AFS_DARWIN80_ENV)
                vp = AFSTOV(tvc);
                if (vnode_get(vp))
                    continue;
@@ -2992,10 +3491,13 @@ DECL_PIOCTL(PFlushVolumeData)
                    AFS_GLOCK();
                    continue;
                }
-#elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
-               osi_vnhold(tvc, 0);
+               if (tvc->f.states & (CBulkFetching|CDeadVnode)) {
+                   AFS_GUNLOCK();
+                   vnode_recycle(AFSTOV(tvc));
+                   AFS_GLOCK();
+               }
 #else
-               VREFCOUNT_INC(tvc); /* AIX, apparently */
+               AFS_FAST_HOLD(tvc);
 #endif
                ReleaseReadLock(&afs_xvcache);
 #ifdef AFS_BOZONLOCK_ENV
@@ -3026,22 +3528,22 @@ DECL_PIOCTL(PFlushVolumeData)
     ReleaseReadLock(&afs_xvcache);
 
 
-    ObtainWriteLock(&afs_xdcache, 328);        /* needed if you're going to flush any stuff */
+    ObtainWriteLock(&afs_xdcache, 328);        /* needed to flush any stuff */
     for (i = 0; i < afs_cacheFiles; i++) {
        if (!(afs_indexFlags[i] & IFEverUsed))
            continue;           /* never had any data */
        tdc = afs_GetDSlot(i, NULL);
-       if (tdc->refCount <= 1) {       /* too high, in use by running sys call */
+       if (tdc->refCount <= 1) {    /* too high, in use by running sys call */
            ReleaseReadLock(&tdc->tlock);
            if (tdc->f.fid.Fid.Volume == volume && tdc->f.fid.Cell == cell) {
                if (!(afs_indexFlags[i] & IFDataMod)) {
-                   /* if the file is modified, but has a ref cnt of only 1, then
-                    * someone probably has the file open and is writing into it.
-                    * Better to skip flushing such a file, it will be brought back
-                    * immediately on the next write anyway.
-                    * 
-                    * If we *must* flush, then this code has to be rearranged to call
-                    * afs_storeAllSegments() first */
+                   /* if the file is modified, but has a ref cnt of only 1,
+                    * then someone probably has the file open and is writing
+                    * into it. Better to skip flushing such a file, it will be
+                    * brought back immediately on the next write anyway.
+                    *
+                    * If we *must* flush, then this code has to be rearranged
+                    * to call afs_storeAllSegments() first */
                    afs_FlushDCache(tdc);
                }
            }
@@ -3075,17 +3577,26 @@ DECL_PIOCTL(PFlushVolumeData)
  *
  * \ingroup pioctl
  *
- * \param[in] ain      not in use (avc used)
- * \param[out] aout    vcxstat: the file id, the data version, any lock, the parent vnode, the parent unique id, the trunc position, the callback, cbExpires, what access is being made, what files are open, any users executing/writing, the flock ount, the states, the move stat
- *
- * \retval EINVAL      Error if some of the initial default arguments aren't set
- * \retval EACCES      Error if access to check the mode bits is denied
- *
- * \post gets stats for the vnode, a struct listed in vcxstat
+ * \param[in] ain
+ *     not in use (avc used)
+ * \param[out] aout
+ *     vcxstat: the file id, the data version, any lock, the parent vnode,
+ *     the parent unique id, the trunc position, the callback, cbExpires,
+ *     what access is being made, what files are open,
+ *     any users executing/writing, the flock count, the states,
+ *     the move stat
+ *
+ * \retval EINVAL
+ *     Error if some of the initial default arguments aren't set
+ * \retval EACCES
+ *     Error if access to check the mode bits is denied
+ *
+ * \post
+ *     gets stats for the vnode, a struct listed in vcxstat
  */
 DECL_PIOCTL(PGetVnodeXStatus)
 {
-    register afs_int32 code;
+    afs_int32 code;
     struct vcxstat stat;
     afs_int32 mode, i;
 
@@ -3111,7 +3622,7 @@ DECL_PIOCTL(PGetVnodeXStatus)
     hset(stat.flushDV, avc->flushDV);
     hset(stat.mapDV, avc->mapDV);
     stat.truncPos = avc->f.truncPos;
-    {                          /* just grab the first two - won't break anything... */
+    {                  /* just grab the first two - won't break anything... */
        struct axscache *ac;
 
        for (i = 0, ac = avc->Access; ac && i < CPSIZE; i++, ac = ac->next) {
@@ -3127,15 +3638,13 @@ DECL_PIOCTL(PGetVnodeXStatus)
     stat.flockCount = avc->flockCount;
     stat.mvstat = avc->mvstat;
     stat.states = avc->f.states;
-    memcpy(aout, (char *)&stat, sizeof(struct vcxstat));
-    *aoutSize = sizeof(struct vcxstat);
-    return 0;
+    return afs_pd_putBytes(aout, &stat, sizeof(struct vcxstat));
 }
 
 
 DECL_PIOCTL(PGetVnodeXStatus2)
 {
-    register afs_int32 code;
+    afs_int32 code;
     struct vcxstat2 stat;
     afs_int32 mode;
 
@@ -3158,9 +3667,7 @@ DECL_PIOCTL(PGetVnodeXStatus2)
     stat.mvstat = avc->mvstat;
     stat.callerAccess = afs_GetAccessBits(avc, ~0, areq);
 
-    memcpy(aout, (char *)&stat, sizeof(struct vcxstat2));
-    *aoutSize = sizeof(struct vcxstat2);
-    return 0;
+    return afs_pd_putBytes(aout, &stat, sizeof(struct vcxstat2));
 }
 
 
@@ -3172,24 +3679,36 @@ DECL_PIOCTL(PGetVnodeXStatus2)
  * \param[in] ain      new value for @sys
  * \param[out] aout    count, entry, list (debug values?)
  *
- * \retval EINVAL      Error if afsd isn't running, the new sysname is too large, the new sysname causes issues (starts with a .0 or ..0), there is no PAG set in the credentials, the user of a PAG can't be found, (!(exporter = au->exporter)) "NOT SURE ON THIS"
- * \retval ENODEV      Error if there isn't already a system named that ("I THINK")
- * \retval EACCES      Error if the user doesn't have super-user credentials
- *
- * \post Set the value of @sys if these things work: if the input isn't too long or if input doesn't start with .0 or ..0
- *
- * \notes We require root for local sysname changes, but not for remote (since we don't really believe remote uids anyway) outname[] shouldn't really be needed- this is left as an exercise for the reader.
+ * \retval EINVAL
+ *     Error if afsd isn't running, the new sysname is too large,
+ *     the new sysname causes issues (starts with a . or ..),
+ *     there is no PAG set in the credentials, or the user of a PAG
+ *     can't be found
+ * \retval EACCES
+ *     Error if the user doesn't have super-user credentials
+ *
+ * \post
+ *     Set the value of @sys if these things work: if the input isn't
+ *     too long or if input doesn't start with . or ..
+ *
+ * \notes
+ *     We require root for local sysname changes, but not for remote
+ *     (since we don't really believe remote uids anyway)
+ *     outname[] shouldn't really be needed- this is left as an
+ *     exercise for the reader.
  */
 DECL_PIOCTL(PSetSysName)
 {
-    char *cp, *cp2 = NULL, inname[MAXSYSNAME], outname[MAXSYSNAME];
+    char *inname = NULL;
+    char outname[MAXSYSNAME];
     afs_int32 setsysname;
     int foundname = 0;
-    register struct afs_exporter *exporter;
-    register struct unixuser *au;
-    register afs_int32 pag, error;
+    struct afs_exporter *exporter;
+    struct unixuser *au;
+    afs_int32 pag, error;
     int t, count, num = 0, allpags = 0;
     char **sysnamelist;
+    struct afs_pdata validate;
 
     AFS_STATCNT(PSetSysName);
     if (!afs_globalVFS) {
@@ -3200,9 +3719,8 @@ DECL_PIOCTL(PSetSysName)
        return (EINVAL);
 #endif
     }
-    memset(inname, 0, MAXSYSNAME);
-    memcpy(&setsysname, ain, sizeof(afs_int32));
-    ain += sizeof(afs_int32);
+    if (afs_pd_getInt(ain, &setsysname) != 0)
+       return EINVAL;
     if (setsysname & 0x8000) {
        allpags = 1;
        setsysname &= ~0x8000;
@@ -3212,27 +3730,26 @@ DECL_PIOCTL(PSetSysName)
        /* Check my args */
        if (setsysname < 0 || setsysname > MAXNUMSYSNAMES)
            return EINVAL;
-       cp2 = ain;
-       for (cp = ain, count = 0; count < setsysname; count++) {
-           /* won't go past end of ain since maxsysname*num < ain length */
-           t = strlen(cp);
+       validate = *ain;
+       for (count = 0; count < setsysname; count++) {
+           if (afs_pd_getStringPtr(&validate, &inname) != 0)
+               return EINVAL;
+           t = strlen(inname);
            if (t >= MAXSYSNAME || t <= 0)
                return EINVAL;
            /* check for names that can shoot us in the foot */
-           if (*cp == '.' && (cp[1] == 0 || (cp[1] == '.' && cp[2] == 0)))
+           if (inname[0] == '.' && (inname[1] == 0
+               || (inname[1] == '.' && inname[2] == 0)))
                return EINVAL;
-           cp += t + 1;
        }
-       /* args ok */
+       /* args ok, so go back to the beginning of that section */
 
-       /* inname gets first entry in case we're being a translator */
-       t = strlen(ain);
-       memcpy(inname, ain, t + 1);     /* include terminating null */
-       ain += t + 1;
+       if (afs_pd_getStringPtr(ain, &inname) != 0)
+           return EINVAL;
        num = count;
     }
     if (afs_cr_gid(*acred) == RMTUSER_REQ ||
-       afs_cr_gid(*acred) == RMTUSER_REQ_PRIV) {       /* Handles all exporters */
+       afs_cr_gid(*acred) == RMTUSER_REQ_PRIV) {   /* Handles all exporters */
        if (allpags && afs_cr_gid(*acred) != RMTUSER_REQ_PRIV) {
            return EPERM;
        }
@@ -3247,7 +3764,7 @@ DECL_PIOCTL(PSetSysName)
            afs_PutUser(au, READ_LOCK);
            return EINVAL;      /* Better than panicing */
        }
-       error = EXP_SYSNAME(exporter, (setsysname ? cp2 : NULL), &sysnamelist,
+       error = EXP_SYSNAME(exporter, inname, &sysnamelist,
                            &num, allpags);
        if (error) {
            if (error == ENODEV)
@@ -3282,16 +3799,19 @@ DECL_PIOCTL(PSetSysName)
            /* clear @sys entries from the dnlc, once afs_lookup can
             * do lookups of @sys entries and thinks it can trust them */
            /* privs ok, store the entry, ... */
+
+           if (strlen(inname) >= MAXSYSNAME-1)
+               return EINVAL;
            strcpy(afs_sysname, inname);
+
            if (setsysname > 1) {       /* ... or list */
-               cp = ain;
                for (count = 1; count < setsysname; ++count) {
                    if (!afs_sysnamelist[count])
                        osi_Panic
-                           ("PSetSysName: no afs_sysnamelist entry to write\n");
-                   t = strlen(cp);
-                   memcpy(afs_sysnamelist[count], cp, t + 1);  /* include null */
-                   cp += t + 1;
+                          ("PSetSysName: no afs_sysnamelist entry to write\n");
+                   if (afs_pd_getString(ain, afs_sysnamelist[count],
+                                        MAXSYSNAME) != 0)
+                       return EINVAL;
                }
            }
            afs_sysnamecount = setsysname;
@@ -3299,24 +3819,22 @@ DECL_PIOCTL(PSetSysName)
        }
     }
     if (!setsysname) {
-       cp = aout;              /* not changing so report back the count and ... */
-       memcpy(cp, (char *)&foundname, sizeof(afs_int32));
-       cp += sizeof(afs_int32);
+       if (afs_pd_putInt(aout, foundname) != 0)
+           return E2BIG;
        if (foundname) {
-           strcpy(cp, outname);        /* ... the entry, ... */
-           cp += strlen(outname) + 1;
-           for (count = 1; count < foundname; ++count) {       /* ... or list. */
+           if (afs_pd_putString(aout, outname) != 0)
+               return E2BIG;
+           for (count = 1; count < foundname; ++count) {    /* ... or list. */
                if (!sysnamelist[count])
                    osi_Panic
                        ("PSetSysName: no afs_sysnamelist entry to read\n");
                t = strlen(sysnamelist[count]);
                if (t >= MAXSYSNAME)
                    osi_Panic("PSetSysName: sysname entry garbled\n");
-               strcpy(cp, sysnamelist[count]);
-               cp += t + 1;
+               if (afs_pd_putString(aout, sysnamelist[count]) != 0)
+                   return E2BIG;
            }
        }
-       *aoutSize = cp - aout;
     }
     return 0;
 }
@@ -3353,11 +3871,12 @@ ReSortCells(int s, afs_int32 * l, int vlonly)
 {
     int i;
     struct volume *j;
-    register int k;
+    int k;
 
     if (vlonly) {
        afs_int32 *p;
-       p = (afs_int32 *) afs_osi_Alloc(sizeof(afs_int32) * (s + 1));
+       p = afs_osi_Alloc(sizeof(afs_int32) * (s + 1));
+        osi_Assert(p != NULL);
        p[0] = s;
        memcpy(p + 1, l, s * sizeof(afs_int32));
        afs_TraverseCells(&ReSortCells_cb, p);
@@ -3394,7 +3913,7 @@ afs_setsprefs(struct spref *sp, unsigned int num, unsigned int vlonly)
     touchedSize = 0;
     for (k = 0; k < num; sp++, k++) {
        if (debugsetsp) {
-           printf("sp host=%x, rank=%d\n", sp->host.s_addr, sp->rank);
+           afs_warn("sp host=%x, rank=%d\n", sp->host.s_addr, sp->rank);
        }
        matches = 0;
        ObtainReadLock(&afs_xserver);
@@ -3414,7 +3933,7 @@ afs_setsprefs(struct spref *sp, unsigned int num, unsigned int vlonly)
 
        if (sa && matches) {    /* found one! */
            if (debugsetsp) {
-               printf("sa ip=%x, ip_rank=%d\n", sa->sa_ip, sa->sa_iprank);
+               afs_warn("sa ip=%x, ip_rank=%d\n", sa->sa_ip, sa->sa_iprank);
            }
            sa->sa_iprank = sp->rank + afs_randomMod15();
            afs_SortOneServer(sa->server);
@@ -3459,15 +3978,22 @@ afs_setsprefs(struct spref *sp, unsigned int num, unsigned int vlonly)
  * \param[in] ain      the sprefs value you want the sprefs to be set to
  * \param[out] aout    not in use
  *
- * \retval EIO         Error if the afs daemon hasn't started yet
- * \retval EACCES      Error if the user doesn't have super-user credentials
- * \retval EINVAL      Error if the struct setsprefs is too large or if it multiplied by the number of servers is too large
+ * \retval EIO
+ *     Error if the afs daemon hasn't started yet
+ * \retval EACCES
+ *     Error if the user doesn't have super-user credentials
+ * \retval EINVAL
+ *     Error if the struct setsprefs is too large or if it multiplied
+ *     by the number of servers is too large
  *
  * \post set the sprefs using the afs_setsprefs() function
  */
 DECL_PIOCTL(PSetSPrefs)
 {
     struct setspref *ssp;
+    char *ainPtr;
+    size_t ainSize;
+
     AFS_STATCNT(PSetSPrefs);
 
     if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
@@ -3476,11 +4002,17 @@ DECL_PIOCTL(PSetSPrefs)
     if (!afs_osi_suser(*acred))
        return EACCES;
 
+    /* The I/O handling here is ghastly, as it relies on overrunning the ends
+     * of arrays. But, i'm not quite brave enough to change it yet. */
+    ainPtr = ain->ptr;
+    ainSize = ain->remaining;
+
     if (ainSize < sizeof(struct setspref))
        return EINVAL;
 
-    ssp = (struct setspref *)ain;
-    if (ainSize < sizeof(struct spref) * ssp->num_servers)
+    ssp = (struct setspref *)ainPtr;
+    if (ainSize < (sizeof(struct setspref)
+                  + sizeof(struct spref) * ssp->num_servers-1))
        return EINVAL;
 
     afs_setsprefs(&(ssp->servers[0]), ssp->num_servers,
@@ -3488,7 +4020,7 @@ DECL_PIOCTL(PSetSPrefs)
     return 0;
 }
 
-/* 
+/*
  * VIOC_SETPREFS33 (42) - Set server ranks (deprecated)
  *
  * \param[in] ain      the server preferences to be set
@@ -3503,7 +4035,6 @@ DECL_PIOCTL(PSetSPrefs)
  */
 DECL_PIOCTL(PSetSPrefs33)
 {
-    struct spref *sp;
     AFS_STATCNT(PSetSPrefs);
     if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
        return EIO;             /* Inappropriate ioctl for device */
@@ -3512,12 +4043,13 @@ DECL_PIOCTL(PSetSPrefs33)
     if (!afs_osi_suser(*acred))
        return EACCES;
 
-    sp = (struct spref *)ain;
-    afs_setsprefs(sp, ainSize / (sizeof(struct spref)), 0 /*!vlonly */ );
+    afs_setsprefs((struct spref *)afs_pd_where(ain),
+                 afs_pd_remaining(ain) / sizeof(struct spref),
+                 0 /*!vlonly */ );
     return 0;
 }
 
-/* 
+/*
  * VIOC_GETSPREFS (43) - Get server ranks
  *
  * \ingroup pioctl
@@ -3530,11 +4062,16 @@ DECL_PIOCTL(PSetSPrefs33)
  *
  * \post Get the sprefs
  *
- * \notes in the hash table of server structs, all servers with the same IP address; will be on the same overflow chain; This could be sped slightly in some circumstances by having it cache the immediately previous slot in the hash table and some supporting information; Only reports file servers now.
+ * \notes
+ *     in the hash table of server structs, all servers with the same
+ *     IP address; will be on the same overflow chain; This could be
+ *     sped slightly in some circumstances by having it cache the
+ *     immediately previous slot in the hash table and some
+ *     supporting information; Only reports file servers now.
  */
 DECL_PIOCTL(PGetSPrefs)
 {
-    struct sprefrequest *spin; /* input */
+    struct sprefrequest spin;  /* input */
     struct sprefinfo *spout;   /* output */
     struct spref *srvout;      /* one output component */
     int i, j;                  /* counters for hash table traversal */
@@ -3547,31 +4084,35 @@ DECL_PIOCTL(PGetSPrefs)
     if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
        return EIO;             /* Inappropriate ioctl for device */
 
-
-    if (ainSize < sizeof(struct sprefrequest_33)) {
-       return ENOENT;
+    /* Work out from the size whether we've got a new, or old, style pioctl */
+    if (afs_pd_remaining(ain) < sizeof(struct sprefrequest)) {
+       if (afs_pd_getBytes(ain, &spin, sizeof(struct sprefrequest_33)) != 0)
+          return ENOENT;
+       vlonly = 0;
+       spin.flags = 0;
     } else {
-       spin = ((struct sprefrequest *)ain);
+       if (afs_pd_getBytes(ain, &spin, sizeof(struct sprefrequest)) != 0)
+          return EINVAL;
+       vlonly = (spin.flags & DBservers);
     }
 
-    if (ainSize > sizeof(struct sprefrequest_33)) {
-       vlonly = (spin->flags & DBservers);
-    } else
-       vlonly = 0;
+    /* This code relies on overflowing arrays. It's ghastly, but I'm not
+     * quite brave enough to tackle it yet ...
+     */
 
     /* struct sprefinfo includes 1 server struct...  that size gets added
      * in during the loop that follows.
      */
-    *aoutSize = sizeof(struct sprefinfo) - sizeof(struct spref);
-    spout = (struct sprefinfo *)aout;
-    spout->next_offset = spin->offset;
+    spout = afs_pd_inline(aout,
+                         sizeof(struct sprefinfo) - sizeof(struct spref));
+    spout->next_offset = spin.offset;
     spout->num_servers = 0;
     srvout = spout->servers;
 
     ObtainReadLock(&afs_xserver);
     for (i = 0, j = 0; j < NSERVERS; j++) {    /* sift through hash table */
        for (sa = afs_srvAddrs[j]; sa; sa = sa->next_bkt, i++) {
-           if (spin->offset > (unsigned short)i) {
+           if (spin.offset > (unsigned short)i) {
                continue;       /* catch up to where we left off */
            }
            spout->next_offset++;
@@ -3585,21 +4126,22 @@ DECL_PIOCTL(PGetSPrefs)
                continue;
            }
 
+           /* Check we've actually got the space we're about to use */
+           if (afs_pd_inline(aout, sizeof(struct spref)) == NULL) {
+               ReleaseReadLock(&afs_xserver);  /* no more room! */
+               return 0;
+           }
+
            srvout->host.s_addr = sa->sa_ip;
            srvout->rank = sa->sa_iprank;
-           *aoutSize += sizeof(struct spref);
            spout->num_servers++;
            srvout++;
-
-           if (*aoutSize > (PIGGYSIZE - sizeof(struct spref))) {
-               ReleaseReadLock(&afs_xserver);  /* no more room! */
-               return 0;
-           }
        }
     }
     ReleaseReadLock(&afs_xserver);
 
     spout->next_offset = 0;    /* start over from the beginning next time */
+
     return 0;
 }
 
@@ -3610,25 +4152,30 @@ int afs_NFSRootOnly = 1;
  *
  * \ingroup pioctl
  *
- * \param[in] ain      a struct Vic * EIOctl containing export values needed to change between nfs and afs
- * \param[out] aout    a struct of the exporter states (exporter->exp_states)
+ * \param[in] ain
+ *     an integer containing the desired exportee flags
+ * \param[out] aout
+ *     an integer containing the current exporter flags
  *
  * \retval ENODEV      Error if the exporter doesn't exist
  * \retval EACCES      Error if the user doesn't have super-user credentials
  *
- * \post Changes the state of various values to reflect the change of the export values between nfs and afs.
+ * \post
+ *     Changes the state of various values to reflect the change
+ *     of the export values between nfs and afs.
  *
  * \notes Legacy code obtained from IBM.
  */
 DECL_PIOCTL(PExportAfs)
 {
-    afs_int32 export, newint =
-       0, type, changestate, handleValue, convmode, pwsync, smounts;
+    afs_int32 export, newint = 0;
+    afs_int32 type, changestate, handleValue, convmode, pwsync, smounts;
     afs_int32 rempags = 0, pagcb = 0;
-    register struct afs_exporter *exporter;
+    struct afs_exporter *exporter;
 
     AFS_STATCNT(PExportAfs);
-    memcpy((char *)&handleValue, ain, sizeof(afs_int32));
+    if (afs_pd_getInt(ain, &handleValue) != 0)
+       return EINVAL;
     type = handleValue >> 24;
     if (type == 0x71) {
        newint = 1;
@@ -3656,8 +4203,8 @@ DECL_PIOCTL(PExportAfs)
     }
     if (!changestate) {
        handleValue = exporter->exp_states;
-       memcpy(aout, (char *)&handleValue, sizeof(afs_int32));
-       *aoutSize = sizeof(afs_int32);
+       if (afs_pd_putInt(aout, handleValue) != 0)
+           return E2BIG;
     } else {
        if (!afs_osi_suser(*acred))
            return EACCES;      /* Only superuser can do this */
@@ -3702,8 +4249,8 @@ DECL_PIOCTL(PExportAfs)
                    exporter->exp_states &= ~EXP_CALLBACK;
            }
            handleValue = exporter->exp_states;
-           memcpy(aout, (char *)&handleValue, sizeof(afs_int32));
-           *aoutSize = sizeof(afs_int32);
+           if (afs_pd_putInt(aout, handleValue) != 0)
+               return E2BIG;
        } else {
            if (export)
                exporter->exp_states |= EXP_EXPORTED;
@@ -3749,7 +4296,9 @@ DECL_PIOCTL(PGag)
     if (!afs_osi_suser(*acred))
        return EACCES;
 
-    gagflags = (struct gaginfo *)ain;
+    gagflags = afs_pd_inline(ain, sizeof(*gagflags));
+    if (gagflags == NULL)
+       return EINVAL;
     afs_showflags = gagflags->showflags;
 
     return 0;
@@ -3774,7 +4323,9 @@ DECL_PIOCTL(PTwiddleRx)
     if (!afs_osi_suser(*acred))
        return EACCES;
 
-    rxp = (struct rxparams *)ain;
+    rxp = afs_pd_inline(ain, sizeof(*rxp));
+    if (rxp == NULL)
+       return EINVAL;
 
     if (rxp->rx_initReceiveWindow)
        rx_initReceiveWindow = rxp->rx_initReceiveWindow;
@@ -3808,7 +4359,8 @@ DECL_PIOCTL(PTwiddleRx)
  * \param[in] ain      not in use
  * \param[out] aout    initial cache manager params
  *
- * \retval E2BIG       Error if the initial parameters are bigger than some PIGGYSIZE
+ * \retval E2BIG
+ *     Error if the initial parameters are bigger than some PIGGYSIZE
  *
  * \post return the initial cache manager parameters
  */
@@ -3817,9 +4369,8 @@ DECL_PIOCTL(PGetInitParams)
     if (sizeof(struct cm_initparams) > PIGGYSIZE)
        return E2BIG;
 
-    memcpy(aout, (char *)&cm_initParams, sizeof(struct cm_initparams));
-    *aoutSize = sizeof(struct cm_initparams);
-    return 0;
+    return afs_pd_putBytes(aout, &cm_initParams,
+                          sizeof(struct cm_initparams));
 }
 
 #ifdef AFS_SGI65_ENV
@@ -3845,13 +4396,11 @@ crget(void)
  * \param[in] ain      not in use
  * \param[out] aout    value of cryptall
  *
- * \post get the value of cryptall (presumably whether or not things should be encrypted)
+ * \post Turns on, or disables, rxkad encryption by setting the cryptall global
  */
 DECL_PIOCTL(PGetRxkcrypt)
 {
-    memcpy(aout, (char *)&cryptall, sizeof(afs_int32));
-    *aoutSize = sizeof(afs_int32);
-    return 0;
+    return afs_pd_putInt(aout, cryptall);
 }
 
 /*!
@@ -3862,12 +4411,17 @@ DECL_PIOCTL(PGetRxkcrypt)
  * \param[in] ain      the argument whether or not things should be encrypted
  * \param[out] aout    not in use
  *
- * \retval EPERM       Error if the user doesn't have super-user credentials
- * \retval EINVAL      Error if the input is too big, or if the input is outside the bounds of what it can be set to
+ * \retval EPERM
+ *     Error if the user doesn't have super-user credentials
+ * \retval EINVAL
+ *     Error if the input is too big, or if the input is outside the
+ *     bounds of what it can be set to
  *
  * \post set whether or not things should be encrypted
  *
- * \notes may need to be modified at a later date to take into account other values for cryptall (beyond true or false)
+ * \notes
+ *     may need to be modified at a later date to take into account
+ *     other values for cryptall (beyond true or false)
  */
 DECL_PIOCTL(PSetRxkcrypt)
 {
@@ -3875,9 +4429,8 @@ DECL_PIOCTL(PSetRxkcrypt)
 
     if (!afs_osi_suser(*acred))
        return EPERM;
-    if (ainSize != sizeof(afs_int32) || ain == NULL)
+    if (afs_pd_getInt(ain, &tmpval) != 0)
        return EINVAL;
-    memcpy((char *)&tmpval, ain, sizeof(afs_int32));
     /* if new mappings added later this will need to be changed */
     if (tmpval != 0 && tmpval != 1)
        return EINVAL;
@@ -3906,13 +4459,17 @@ HandleClientContext(struct afs_ioctl *ablob, int *com,
     struct unixuser *au;
     afs_uint32 comp = *com & 0xff00;
     afs_uint32 h, l;
+#if defined(AFS_SUN510_ENV)
+    gid_t gids[2];
+#endif
 
 #if defined(AFS_SGIMP_ENV)
     osi_Assert(ISAFS_GLOCK());
 #endif
     AFS_STATCNT(HandleClientContext);
     if (ablob->in_size < PIOCTL_HEADER * sizeof(afs_int32)) {
-       /* Must at least include the PIOCTL_HEADER header words required by the protocol */
+       /* Must at least include the PIOCTL_HEADER header words
+        * required by the protocol */
        return EINVAL;          /* Too small to be good  */
     }
     ain = inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
@@ -3933,7 +4490,7 @@ HandleClientContext(struct afs_ioctl *ablob, int *com,
     ain += sizeof(g1);
     *com = *((afs_uint32 *) ain);
     ain += sizeof(afs_int32);
-    exporter_type = *((afs_uint32 *) ain);     /* In case we support more than NFS */
+    exporter_type = *((afs_uint32 *) ain);/* In case we support more than NFS */
 
     /*
      * Of course, one must be root for most of these functions, but
@@ -3976,30 +4533,34 @@ HandleClientContext(struct afs_ioctl *ablob, int *com,
     newcred->cr_groupset.gs_union.un_groups[0] = g0;
     newcred->cr_groupset.gs_union.un_groups[1] = g1;
 #elif defined(AFS_LINUX26_ENV)
-#ifdef AFS_LINUX26_ONEGROUP_ENV
-    set_cr_group_info(newcred, groups_alloc(1)); /* not that anything sets this */
+# ifdef AFS_LINUX26_ONEGROUP_ENV
+    afs_set_cr_group_info(newcred, groups_alloc(1)); /* nothing sets this */
     l = (((g0-0x3f00) & 0x3fff) << 14) | ((g1-0x3f00) & 0x3fff);
     h = ((g0-0x3f00) >> 14);
     h = ((g1-0x3f00) >> 14) + h + h + h;
-    GROUP_AT(cr_group_info(newcred), 0) = ((h << 28) | l);
-#else
-    set_cr_group_info(newcred, groups_alloc(2));
-    GROUP_AT(cr_group_info(newcred), 0) = g0;
-    GROUP_AT(cr_group_info(newcred), 1) = g1;
-#endif
+    GROUP_AT(afs_cr_group_info(newcred), 0) = ((h << 28) | l);
+# else
+    afs_set_cr_group_info(newcred, groups_alloc(2));
+    GROUP_AT(afs_cr_group_info(newcred), 0) = g0;
+    GROUP_AT(afs_cr_group_info(newcred), 1) = g1;
+# endif
+#elif defined(AFS_SUN510_ENV)
+    gids[0] = g0;
+    gids[1] = g1;
+    crsetgroups(newcred, 2, gids);
 #else
     newcred->cr_groups[0] = g0;
     newcred->cr_groups[1] = g1;
 #endif
 #ifdef AFS_AIX_ENV
     newcred->cr_ngrps = 2;
-#elif !defined(AFS_LINUX26_ENV)
-#if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV)
+#elif !defined(AFS_LINUX26_ENV) && !defined(AFS_SUN510_ENV)
+# if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_FBSD80_ENV)
     newcred->cr_ngroups = 2;
-#else
+# else
     for (i = 2; i < NGROUPS; i++)
        newcred->cr_groups[i] = NOGROUP;
-#endif
+# endif
 #endif
     if (!(exporter = exporter_find(exporter_type))) {
        /* Exporter wasn't initialized or an invalid exporter type */
@@ -4021,7 +4582,7 @@ HandleClientContext(struct afs_ioctl *ablob, int *com,
        /* Special case for 'setpag' */
        afs_uint32 pagvalue = genpag();
 
-       au = afs_GetUser(pagvalue, -1, WRITE_LOCK);     /* a new unixuser struct */
+       au = afs_GetUser(pagvalue, -1, WRITE_LOCK); /* a new unixuser struct */
        /*
         * Note that we leave the 'outexporter' struct held so it won't
         * dissappear on us
@@ -4038,14 +4599,14 @@ HandleClientContext(struct afs_ioctl *ablob, int *com,
     } else if (!code) {
        EXP_RELE(outexporter);
     }
-    if (!code) 
+    if (!code)
        *com = (*com) | comp;
     return code;
 }
 #endif /* AFS_NEED_CLIENTCONTEXT */
 
 
-/*! 
+/*!
  * VIOC_GETCPREFS (50) - Get client interface
  *
  * \ingroup pioctl
@@ -4056,7 +4617,9 @@ HandleClientContext(struct afs_ioctl *ablob, int *com,
  * \retval EIO         Error if the afs daemon hasn't started yet
  * \retval EINVAL      Error if some of the standard args aren't set
  *
- * \post get all interface addresses and other information of the client interface
+ * \post
+ *     get all interface addresses and other information of the client
+ *     interface
  */
 DECL_PIOCTL(PGetCPrefs)
 {
@@ -4070,11 +4633,13 @@ DECL_PIOCTL(PGetCPrefs)
     if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
        return EIO;             /* Inappropriate ioctl for device */
 
-    if (ainSize < sizeof(struct sprefrequest))
+    spin = afs_pd_inline(ain, sizeof(*spin));
+    if (spin == NULL)
        return EINVAL;
 
-    spin = (struct sprefrequest *)ain;
-    spout = (struct sprefinfo *)aout;
+    /* Output spout relies on writing past the end of arrays. It's horrible,
+     * but I'm not quite brave enough to tackle it yet */
+    spout = (struct sprefinfo *)aout->ptr;
 
     maxNumber = spin->num_servers;     /* max addrs this time */
     srvout = spout->servers;
@@ -4082,14 +4647,14 @@ DECL_PIOCTL(PGetCPrefs)
     ObtainReadLock(&afs_xinterface);
 
     /* copy out the client interface information from the
-     ** kernel data structure "interface" to the output buffer
+     * kernel data structure "interface" to the output buffer
      */
     for (i = spin->offset, j = 0; (i < afs_cb_interface.numberOfInterfaces)
         && (j < maxNumber); i++, j++, srvout++)
        srvout->host.s_addr = afs_cb_interface.addr_in[i];
 
     spout->num_servers = j;
-    *aoutSize = sizeof(struct sprefinfo) + (j - 1) * sizeof(struct spref);
+    aout->ptr += sizeof(struct sprefinfo) + (j - 1) * sizeof(struct spref);
 
     if (i >= afs_cb_interface.numberOfInterfaces)
        spout->next_offset = 0; /* start from beginning again */
@@ -4116,6 +4681,8 @@ DECL_PIOCTL(PGetCPrefs)
  */
 DECL_PIOCTL(PSetCPrefs)
 {
+    char *ainPtr;
+    size_t ainSize;
     struct setspref *sin;
     int i;
 
@@ -4123,7 +4690,13 @@ DECL_PIOCTL(PSetCPrefs)
     if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
        return EIO;             /* Inappropriate ioctl for device */
 
-    sin = (struct setspref *)ain;
+    /* Yuck. Input to this function relies on reading past the end of
+     * structures. Bodge it for now.
+     */
+    ainPtr = ain->ptr;
+    ainSize = ain->remaining;
+
+    sin = (struct setspref *)ainPtr;
 
     if (ainSize < sizeof(struct setspref))
        return EINVAL;
@@ -4148,28 +4721,40 @@ DECL_PIOCTL(PSetCPrefs)
  *
  * \ingroup pioctl
  *
- * \param[in] ain      the last part of a path to a mount point, which tells us what to flush
- * \param[out] aout    not in use
- *
- * \retval EINVAL      Error if some of the initial arguments aren't set
- * \retval ENOTDIR     Error if the initial argument for the mount point isn't a directory
- * \retval ENOENT      Error if the dcache entry isn't set
- *
- * \post remove all of the mount data from the dcache regarding a certain mount point
+ * \param[in] ain
+ *     the last part of a path to a mount point, which tells us what to flush
+ * \param[out] aout
+ *     not in use
+ *
+ * \retval EINVAL
+ *     Error if some of the initial arguments aren't set
+ * \retval ENOTDIR
+ *     Error if the initial argument for the mount point isn't a directory
+ * \retval ENOENT
+ *     Error if the dcache entry isn't set
+ *
+ * \post
+ *     remove all of the mount data from the dcache regarding a
+ *     certain mount point
  */
 DECL_PIOCTL(PFlushMount)
 {
-    register afs_int32 code;
-    register struct vcache *tvc;
-    register struct dcache *tdc;
+    afs_int32 code;
+    struct vcache *tvc;
+    struct dcache *tdc;
     struct VenusFid tfid;
     char *bufp;
+    char *mount;
     struct sysname_info sysState;
     afs_size_t offset, len;
 
     AFS_STATCNT(PFlushMount);
     if (!avc)
        return EINVAL;
+
+    if (afs_pd_getStringPtr(ain, &mount) != 0)
+       return EINVAL;
+
     code = afs_VerifyVCache(avc, areq);
     if (code)
        return code;
@@ -4179,7 +4764,7 @@ DECL_PIOCTL(PFlushMount)
     tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
     if (!tdc)
        return ENOENT;
-    Check_AtSys(avc, ain, &sysState, areq);
+    Check_AtSys(avc, mount, &sysState, areq);
     ObtainReadLock(&tdc->lock);
     do {
        code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
@@ -4243,26 +4828,23 @@ DECL_PIOCTL(PFlushMount)
  * \retval EACCES      Error if the user doesn't have super-user credentials
  * \retval EINVAL      Error if the flag input is too long
  *
- * \post either enable process RPCStats, disable process RPCStats, or clear the process RPCStats
+ * \post
+ *     either enable process RPCStats, disable process RPCStats,
+ *     or clear the process RPCStats
  */
 DECL_PIOCTL(PRxStatProc)
 {
-    int code = 0;
     afs_int32 flags;
 
-    if (!afs_osi_suser(*acred)) {
-       code = EACCES;
-       goto out;
-    }
-    if (ainSize != sizeof(afs_int32)) {
-       code = EINVAL;
-       goto out;
-    }
-    memcpy((char *)&flags, ain, sizeof(afs_int32));
-    if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
-       code = EINVAL;
-       goto out;
-    }
+    if (!afs_osi_suser(*acred))
+       return EACCES;
+
+    if (afs_pd_getInt(ain, &flags) != 0)
+       return EINVAL;
+
+    if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK))
+       return EINVAL;
+
     if (flags & AFSCALL_RXSTATS_ENABLE) {
        rx_enableProcessRPCStats();
     }
@@ -4272,9 +4854,7 @@ DECL_PIOCTL(PRxStatProc)
     if (flags & AFSCALL_RXSTATS_CLEAR) {
        rx_clearProcessRPCStats(AFS_RX_STATS_CLEAR_ALL);
     }
-  out:
-    *aoutSize = 0;
-    return code;
+    return 0;
 }
 
 
@@ -4289,26 +4869,23 @@ DECL_PIOCTL(PRxStatProc)
  * \retval EACCES      Error if the user doesn't have super-user credentials
  * \retval EINVAL      Error if the flag input is too long
  *
- * \post either enable peer RPCStatws, disable peer RPCStats, or clear the peer RPCStats
+ * \post
+ *     either enable peer RPCStatws, disable peer RPCStats,
+ *     or clear the peer RPCStats
  */
 DECL_PIOCTL(PRxStatPeer)
 {
-    int code = 0;
     afs_int32 flags;
 
-    if (!afs_osi_suser(*acred)) {
-       code = EACCES;
-       goto out;
-    }
-    if (ainSize != sizeof(afs_int32)) {
-       code = EINVAL;
-       goto out;
-    }
-    memcpy((char *)&flags, ain, sizeof(afs_int32));
-    if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
-       code = EINVAL;
-       goto out;
-    }
+    if (!afs_osi_suser(*acred))
+       return EACCES;
+
+    if (afs_pd_getInt(ain, &flags) != 0)
+       return EINVAL;
+
+    if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK))
+       return EINVAL;
+
     if (flags & AFSCALL_RXSTATS_ENABLE) {
        rx_enablePeerRPCStats();
     }
@@ -4318,15 +4895,13 @@ DECL_PIOCTL(PRxStatPeer)
     if (flags & AFSCALL_RXSTATS_CLEAR) {
        rx_clearPeerRPCStats(AFS_RX_STATS_CLEAR_ALL);
     }
-  out:
-    *aoutSize = 0;
-    return code;
+    return 0;
 }
 
 DECL_PIOCTL(PPrefetchFromTape)
 {
-    register afs_int32 code, code1;
-    afs_int32 bytes;
+    afs_int32 code, code1;
+    afs_int32 bytes, outval;
     struct afs_conn *tc;
     struct rx_call *tcall;
     struct AFSVolSync tsync;
@@ -4340,10 +4915,10 @@ DECL_PIOCTL(PPrefetchFromTape)
     if (!avc)
        return EINVAL;
 
-    if (ain && (ainSize == 3 * sizeof(afs_int32)))
-       Fid = (struct AFSFid *)ain;
-    else
+    Fid = afs_pd_inline(ain, sizeof(struct AFSFid));
+    if (Fid == NULL)
        Fid = &avc->f.fid.Fid;
+
     tfid.Cell = avc->f.fid.Cell;
     tfid.Fid.Volume = Fid->Volume;
     tfid.Fid.Vnode = Fid->Vnode;
@@ -4368,7 +4943,7 @@ DECL_PIOCTL(PPrefetchFromTape)
                StartRXAFS_FetchData(tcall, (struct AFSFid *)&tvc->f.fid.Fid, 0,
                                     0);
            if (!code) {
-               bytes = rx_Read(tcall, (char *)aout, sizeof(afs_int32));
+               bytes = rx_Read(tcall, (char *)&outval, sizeof(afs_int32));
                code =
                    EndRXAFS_FetchData(tcall, &OutStatus, &CallBack, &tsync);
            }
@@ -4383,15 +4958,15 @@ DECL_PIOCTL(PPrefetchFromTape)
     afs_FetchStatus(tvc, &tfid, areq, &OutStatus);
     afs_PutVCache(tvc);
 
-    if (!code) {
-       *aoutSize = sizeof(afs_int32);
-    }
-    return code;
+    if (code)
+       return code;
+
+    return afs_pd_putInt(aout, outval);
 }
 
 DECL_PIOCTL(PFsCmd)
 {
-    register afs_int32 code;
+    afs_int32 code;
     struct afs_conn *tc;
     struct vcache *tvc;
     struct FsCmdInputs *Inputs;
@@ -4399,13 +4974,17 @@ DECL_PIOCTL(PFsCmd)
     struct VenusFid tfid;
     struct AFSFid *Fid;
 
-    Inputs = (struct FsCmdInputs *)ain;
-    Outputs = (struct FsCmdOutputs *)aout;
     if (!avc)
        return EINVAL;
-    if (!ain || ainSize != sizeof(struct FsCmdInputs))
+
+    Inputs = afs_pd_inline(ain, sizeof(*Inputs));
+    if (Inputs == NULL)
        return EINVAL;
 
+    Outputs = afs_pd_inline(aout, sizeof(*Outputs));
+    if (Outputs == NULL)
+       return E2BIG;
+
     Fid = &Inputs->fid;
     if (!Fid->Volume)
        Fid = &avc->f.fid.Fid;
@@ -4427,7 +5006,7 @@ DECL_PIOCTL(PFsCmd)
            if (tc) {
                RX_AFS_GUNLOCK();
                code =
-                   RXAFS_FsCmd(tc->id, Fid, Inputs, 
+                   RXAFS_FsCmd(tc->id, Fid, Inputs,
                                        (struct FsCmdOutputs *)aout);
                RX_AFS_GLOCK();
            } else
@@ -4437,7 +5016,7 @@ DECL_PIOCTL(PFsCmd)
                  AFS_STATS_FS_RPCIDX_RESIDENCYRPCS, SHARED_LOCK, NULL));
        /* This call is done to have the callback things handled correctly */
        afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
-    } else {                   /* just a status request, return also link data */
+    } else {           /* just a status request, return also link data */
        code = 0;
        Outputs->code = afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
        Outputs->chars[0] = 0;
@@ -4451,9 +5030,6 @@ DECL_PIOCTL(PFsCmd)
 
     afs_PutVCache(tvc);
 
-    if (!code) {
-       *aoutSize = sizeof(struct FsCmdOutputs);
-    }
     return code;
 }
 
@@ -4463,7 +5039,7 @@ DECL_PIOCTL(PNewUuid)
     if (!afs_resourceinit_flag)        /* afs deamons havn't started yet */
        return EIO;             /* Inappropriate ioctl for device */
 
-    if (!afs_osi_suser(acred))
+    if (!afs_osi_suser(*acred))
        return EACCES;
 
     ObtainWriteLock(&afs_xinterface, 555);
@@ -4473,16 +5049,15 @@ DECL_PIOCTL(PNewUuid)
     return 0;
 }
 
-#if defined(AFS_CACHE_BYPASS)
+#if defined(AFS_CACHE_BYPASS) && defined(AFS_LINUX24_ENV)
 
 DECL_PIOCTL(PSetCachingThreshold)
 {
-    afs_int32 getting;
-    afs_int32 setting;
+    afs_int32 getting = 1;
+    afs_int32 setting = 1;
+    afs_int32 threshold = AFS_CACHE_BYPASS_DISABLED;
 
-    setting = getting = 1;
-
-    if (ain == NULL || ainSize < sizeof(afs_int32))
+    if (afs_pd_getInt(ain, &threshold) != 0)
        setting = 0;
 
     if (aout == NULL)
@@ -4490,28 +5065,22 @@ DECL_PIOCTL(PSetCachingThreshold)
 
     if (setting == 0 && getting == 0)
        return EINVAL;
-       
-    /* 
+
+    /*
      * If setting, set first, and return the value now in effect
      */
     if (setting) {
-       afs_int32 threshold;
-
        if (!afs_osi_suser(*acred))
            return EPERM;
-       memcpy((char *)&threshold, ain, sizeof(afs_int32));
        cache_bypass_threshold = threshold;
-        afs_warn("Cache Bypass Threshold set to: %d\n", threshold);            
+        afs_warn("Cache Bypass Threshold set to: %d\n", threshold);
        /* TODO:  move to separate pioctl, or enhance pioctl */
        cache_bypass_strategy = LARGE_FILES_BYPASS_CACHE;
     }
-       
-    if (getting) {
-       /* Return the current size threshold */
-       afs_int32 oldThreshold = cache_bypass_threshold;
-       memcpy(aout, (char *)&oldThreshold, sizeof(afs_int32));
-       *aoutSize = sizeof(afs_int32);
-    }
+
+    /* Return the current size threshold */
+    if (getting)
+       return afs_pd_putInt(aout, cache_bypass_threshold);
 
     return(0);
 }
@@ -4537,11 +5106,9 @@ DECL_PIOCTL(PCallBackAddr)
     if (!afs_osi_suser(acred))
        return EACCES;
 
-    if (ainSize < sizeof(afs_int32))
+    if (afs_pd_getInt(ain, &addr) != 0)
        return EINVAL;
 
-    memcpy(&addr, ain, sizeof(afs_int32));
-
     ObtainReadLock(&afs_xinterface);
     for (i = 0; (unsigned short)i < afs_cb_interface.numberOfInterfaces; i++) {
        if (afs_cb_interface.addr_in[i] == addr)
@@ -4564,6 +5131,7 @@ DECL_PIOCTL(PCallBackAddr)
     }
 
     addrs = afs_osi_Alloc(srvAddrCount * sizeof(*addrs));
+    osi_Assert(addrs != NULL);
     j = 0;
     for (i = 0; i < NSERVERS; i++) {
        for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
@@ -4618,22 +5186,28 @@ DECL_PIOCTL(PCallBackAddr)
 
 DECL_PIOCTL(PDiscon)
 {
-#ifdef AFS_DISCON_ENV
     static afs_int32 mode = 1; /* Start up in 'off' */
     afs_int32 force = 0;
     int code = 0;
+    char flags[4];
+    struct vrequest lreq;
 
-    if (ainSize) {
-
+    if (afs_pd_getBytes(ain, &flags, 4) == 0) {
        if (!afs_osi_suser(*acred))
            return EPERM;
 
-       if (ain[0])
-           mode = ain[0] - 1;
-       if (ain[1])
-           afs_ConflictPolicy = ain[1] - 1;
-       if (ain[2])
+       if (flags[0])
+           mode = flags[0] - 1;
+       if (flags[1])
+           afs_ConflictPolicy = flags[1] - 1;
+       if (flags[2])
            force = 1;
+       if (flags[3]) {
+           /* Fake InitReq support for UID override */
+           memset(&lreq, 0, sizeof(lreq));
+           lreq.uid = flags[3];
+           areq = &lreq; /* override areq we got */
+       }
 
        /*
         * All of these numbers are hard coded in fs.c. If they
@@ -4659,7 +5233,7 @@ DECL_PIOCTL(PDiscon)
            afs_in_sync = 0;
 
            if (code && !force) {
-               printf("Files not synchronized properly, still in discon state. \n"
+               afs_warnuser("Files not synchronized properly, still in discon state. \n"
                       "Please retry or use \"force\".\n");
                mode = 0;
            } else {
@@ -4669,7 +5243,7 @@ DECL_PIOCTL(PDiscon)
                afs_ClearAllStatdFlag();
                afs_is_disconnected = 0;
                afs_is_discon_rw = 0;
-               printf("\nSync succeeded. You are back online.\n");
+               afs_warnuser("\nSync succeeded. You are back online.\n");
            }
 
            ReleaseWriteLock(&afs_discon_lock);
@@ -4681,27 +5255,204 @@ DECL_PIOCTL(PDiscon)
        return EINVAL;
     }
 
-    memcpy(aout, &mode, sizeof(afs_int32));
-    *aoutSize = sizeof(afs_int32);
+    if (code)
+       return code;
+
+    return afs_pd_putInt(aout, mode);
+}
+
+#define MAX_PIOCTL_TOKENS 10
+
+DECL_PIOCTL(PSetTokens2)
+{
+    int code =0;
+    int i, cellNum, primaryFlag;
+    XDR xdrs;
+    struct unixuser *tu;
+    struct vrequest treq;
+    struct ktc_setTokenData tokenSet;
+    struct ktc_tokenUnion decodedToken;
+
+    memset(&tokenSet, 0, sizeof(tokenSet));
+
+    AFS_STATCNT(PSetTokens2);
+    if (!afs_resourceinit_flag)
+       return EIO;
+
+    afs_pd_xdrStart(ain, &xdrs, XDR_DECODE);
+
+    if (!xdr_ktc_setTokenData(&xdrs, &tokenSet)) {
+       afs_pd_xdrEnd(ain, &xdrs);
+       return EINVAL;
+    }
+
+    afs_pd_xdrEnd(ain, &xdrs);
+
+    /* We limit each PAG to 10 tokens to prevent a malicous (or runaway)
+     * process from using up the whole of the kernel memory by allocating
+     * tokens.
+     */
+    if (tokenSet.tokens.tokens_len > MAX_PIOCTL_TOKENS) {
+       xdr_free((xdrproc_t) xdr_ktc_setTokenData, &tokenSet);
+       return E2BIG;
+    }
+
+    code = _settok_tokenCell(tokenSet.cell, &cellNum, &primaryFlag);
+    if (code) {
+       xdr_free((xdrproc_t) xdr_ktc_setTokenData, &tokenSet);
+       return code;
+    }
+
+    if (tokenSet.flags & AFSTOKEN_EX_SETPAG) {
+       if (_settok_setParentPag(acred) == 0) {
+           afs_InitReq(&treq, *acred);
+           areq = &treq;
+       }
+    }
+
+    tu = afs_GetUser(areq->uid, cellNum, WRITE_LOCK);
+    /* Free any tokens that we've already got */
+    afs_FreeTokens(&tu->tokens);
+
+    /* Iterate across the set of tokens we've received, and stuff them
+     * into this user's tokenJar
+     */
+    for (i=0; i < tokenSet.tokens.tokens_len; i++) {
+       xdrmem_create(&xdrs,
+                     tokenSet.tokens.tokens_val[i].token_opaque_val,
+                     tokenSet.tokens.tokens_val[i].token_opaque_len,
+                     XDR_DECODE);
+
+       memset(&decodedToken, 0, sizeof(decodedToken));
+       if (!xdr_ktc_tokenUnion(&xdrs, &decodedToken)) {
+           xdr_destroy(&xdrs);
+           code = EINVAL;
+           goto out;
+       }
+
+       xdr_destroy(&xdrs);
+
+       afs_AddTokenFromPioctl(&tu->tokens, &decodedToken);
+       /* This is untidy - the old token interface supported passing
+        * the primaryFlag as part of the token interface. Current
+        * OpenAFS userland never sets this, but it's specified as being
+        * part of the XG interface, so we should probably still support
+        * it. Rather than add it to our AddToken interface, just handle
+        * it here.
+        */
+       if (decodedToken.at_type == AFSTOKEN_UNION_KAD) {
+           if (decodedToken.ktc_tokenUnion_u.at_kad.rk_primary_flag)
+               primaryFlag = 1;
+       }
+
+       /* XXX - We should think more about destruction here. It's likely that
+        * there is key material in what we're about to throw away, which
+        * we really should zero out before giving back to the allocator */
+       xdr_free((xdrproc_t) xdr_ktc_tokenUnion, &decodedToken);
+    }
+
+    tu->states |= UHasTokens;
+    tu->states &= ~UTokensBad;
+    afs_SetPrimary(tu, primaryFlag);
+    tu->tokenTime = osi_Time();
+
+    xdr_free((xdrproc_t) xdr_ktc_setTokenData, &tokenSet);
+
+out:
+    afs_ResetUserConns(tu);
+    afs_PutUser(tu, WRITE_LOCK);
+
     return code;
-#else
-    return EINVAL;
-#endif
 }
 
+DECL_PIOCTL(PGetTokens2)
+{
+    struct cell *cell;
+    struct unixuser *tu = NULL;
+    afs_int32 iterator;
+    char *cellName = NULL;
+    afs_int32 cellNum;
+    int code = 0;
+    time_t now;
+    XDR xdrs;
+    struct ktc_setTokenData tokenSet;
+
+    AFS_STATCNT(PGetTokens);
+    if (!afs_resourceinit_flag)
+       return EIO;
+
+    memset(&tokenSet, 0, sizeof(tokenSet));
+
+    /* No input data - return tokens for primary cell */
+    /* 4 octets of data is an iterator count */
+    /* Otherwise, treat as string & return tokens for that cell name */
+
+    if (afs_pd_remaining(ain) == sizeof(afs_int32)) {
+       /* Integer iterator - return tokens for the n'th cell found for user */
+       if (afs_pd_getInt(ain, &iterator) != 0)
+           return EINVAL;
+       tu = getNthCell(areq->uid, iterator);
+    } else {
+        if (afs_pd_remaining(ain) > 0) {
+           if (afs_pd_getStringPtr(ain, &cellName) != 0)
+               return EINVAL;
+        } else {
+           cellName = NULL;
+       }
+       code = _settok_tokenCell(cellName, &cellNum, NULL);
+       if (code)
+           return code;
+       tu = afs_FindUser(areq->uid, cellNum, READ_LOCK);
+    }
+    if (tu == NULL)
+       return EDOM;
+
+    now = osi_Time();
+
+    if (!(tu->states & UHasTokens)
+       || !afs_HasValidTokens(tu->tokens, now)) {
+       tu->states |= (UTokensBad | UNeedsReset);
+       afs_PutUser(tu, READ_LOCK);
+       return ENOTCONN;
+    }
+
+    code = afs_ExtractTokensForPioctl(tu->tokens, now, &tokenSet);
+    if (code)
+       goto out;
+
+    cell = afs_GetCell(tu->cell, READ_LOCK);
+    tokenSet.cell = cell->cellName;
+    afs_pd_xdrStart(aout, &xdrs, XDR_ENCODE);
+    if (!xdr_ktc_setTokenData(&xdrs, &tokenSet)) {
+       code = E2BIG;
+       goto out;
+    }
+    afs_pd_xdrEnd(aout, &xdrs);
+
+out:
+    tokenSet.cell = NULL;
+
+    if (tu)
+       afs_PutUser(tu, READ_LOCK);
+    if (cell)
+       afs_PutCell(cell, READ_LOCK);
+    xdr_free((xdrproc_t)xdr_ktc_setTokenData, &tokenSet);
+
+    return code;
+};
+
 DECL_PIOCTL(PNFSNukeCreds)
 {
     afs_uint32 addr;
-    register afs_int32 i;
-    register struct unixuser *tu;
+    afs_int32 i;
+    struct unixuser *tu;
 
     AFS_STATCNT(PUnlog);
     if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
        return EIO;             /* Inappropriate ioctl for device */
 
-    if (ainSize < sizeof(afs_int32))
+    if (afs_pd_getUint(ain, &addr) != 0)
        return EINVAL;
-    memcpy(&addr, ain, sizeof(afs_int32));
 
     if (afs_cr_gid(*acred) == RMTUSER_REQ_PRIV && !addr) {
        tu = afs_GetUser(areq->uid, -1, SHARED_LOCK);
@@ -4718,10 +5469,8 @@ DECL_PIOCTL(PNFSNukeCreds)
     for (i = 0; i < NUSERS; i++) {
        for (tu = afs_users[i]; tu; tu = tu->next) {
            if (tu->exporter && EXP_CHECKHOST(tu->exporter, addr)) {
-               tu->vid = UNDEFVID;
                tu->states &= ~UHasTokens;
-               /* security is not having to say you're sorry */
-               memset(&tu->ct, 0, sizeof(struct ClearToken));
+               afs_FreeTokens(&tu->tokens);
                tu->refCount++;
                ReleaseWriteLock(&afs_xuser);
                afs_ResetUserConns(tu);
@@ -4731,7 +5480,6 @@ DECL_PIOCTL(PNFSNukeCreds)
                /* set the expire times to 0, causes
                 * afs_GCUserData to remove this entry
                 */
-               tu->ct.EndTimestamp = 0;
                tu->tokenTime = 0;
 #endif /* UKERNEL */
            }