Remove kauth from libuafs
[openafs.git] / src / afs / UKERNEL / afs_usrops.c
index 094c141..95cea9e 100644 (file)
@@ -1,3 +1,4 @@
+
 /*
  * Copyright 2000, International Business Machines Corporation and others.
  * All Rights Reserved.
 #include <afsconfig.h>
 #include "afs/param.h"
 
-RCSID
-    ("$Header$");
-
-
 #ifdef UKERNEL
 
 #include "afs/sysincludes.h"   /* Standard vendor system headers */
 #include <net/if.h>
+
 #include "afsincludes.h"       /* Afs-based standard headers */
 #include "afs_usrops.h"
 #include "afs/afs_stats.h"
 #include "afs/auth.h"
 #include "afs/cellconfig.h"
 #include "afs/vice.h"
+#include "afs/kauth.h"
 #include "afs/kautils.h"
 #include "afs/afsutil.h"
+#include "afs/afs_bypasscache.h"
 #include "rx/rx_globals.h"
+#include "afsd/afsd.h"
 
 #define VFS 1
 #undef VIRTUE
 #undef VICE
 
+#ifndef AFS_CACHE_VNODE_PATH
+#error You must compile UKERNEL code with -DAFS_CACHE_VNODE_PATH
+#endif
+
 #define CACHEINFOFILE  "cacheinfo"
 #define        AFSLOGFILE      "AFSLog"
 #define        DCACHEFILE      "CacheItems"
@@ -54,81 +59,40 @@ extern int cacheDiskType;
 
 char afs_LclCellName[64];
 
-struct usr_vnode *afs_FileTable[MAX_OSI_FILES];
-int afs_FileFlags[MAX_OSI_FILES];
-int afs_FileOffsets[MAX_OSI_FILES];
+static struct usr_vnode *afs_FileTable[MAX_OSI_FILES];
+static int afs_FileFlags[MAX_OSI_FILES];
+static off_t afs_FileOffsets[MAX_OSI_FILES];
 
 #define MAX_CACHE_LOOPS 4
 
-struct usr_vfs afs_RootVfs;
-struct usr_vnode *afs_RootVnode = NULL;
-struct usr_vnode *afs_CurrentDir = NULL;
-
-afs_int32 cacheBlocks;         /* Num blocks in cache */
-afs_int32 cacheFiles = 1000;   /* Num files in workstation cache */
-afs_int32 cacheStatEntries = 300;      /* Num of stat cache entries */
-char cacheBaseDir[1024];       /* AFS cache directory */
-char confDir[1024];            /* AFS configuration directory */
-char afs_mountDir[1024];       /* AFS mount point */
-int afs_mountDirLen;           /* strlen of AFS mount point */
-char fullpn_DCacheFile[1024];  /* Full pathname of DCACHEFILE */
-char fullpn_VolInfoFile[1024]; /* Full pathname of VOLINFOFILE */
-char fullpn_CellInfoFile[1024];        /* Full pathname of CELLINFOFILE */
-char fullpn_AFSLogFile[1024];  /* Full pathname of AFSLOGFILE */
-char fullpn_CacheInfo[1024];   /* Full pathname of CACHEINFO */
-char fullpn_VFile[1024];       /* Full pathname of data cache files */
-char *vFileNumber;             /* Ptr to number in file pathname */
-char rootVolume[64] = "root.afs";      /* AFS root volume name */
-afs_int32 isHomeCell;          /* Is current cell info for home cell */
-int createAndTrunc = O_CREAT | O_TRUNC;        /* Create & truncate on open */
-int ownerRWmode = 0600;                /* Read/write OK by owner */
-static int nDaemons = 2;       /* Number of background daemons */
-static int chunkSize = 0;      /* 2^chunkSize bytes per chunk */
-static int dCacheSize = 300;   /* # of dcache entries */
-static int vCacheSize = 50;    /* # of volume cache entries */
-static int cacheFlags = 0;     /* Flags to cache manager */
-static int preallocs = 400;    /* Def # of allocated memory blocks */
-int afsd_verbose = 0;          /* Are we being chatty? */
-int afsd_debug = 0;            /* Are we printing debugging info? */
-int afsd_CloseSynch = 0;       /* Are closes synchronous or not? */
-
-#define AFSD_INO_T afs_uint32
-char **pathname_for_V;         /* Array of cache file pathnames */
-int missing_DCacheFile = 1;    /* Is the DCACHEFILE missing? */
-int missing_VolInfoFile = 1;   /* Is the VOLINFOFILE missing? */
-int missing_CellInfoFile = 1;
-struct afs_cacheParams cparams;        /* params passed to cache manager */
-struct afsconf_dir *afs_cdir;  /* config dir */
+static struct usr_vfs afs_RootVfs;
+static struct usr_vnode *afs_RootVnode = NULL;
+static struct usr_vnode *afs_CurrentDir = NULL;
 
-static int HandleMTab();
+static char afs_mountDir[1024];        /* AFS mount point */
+static int afs_mountDirLen;            /* strlen of AFS mount point */
 
-int afs_bufferpages = 100;
-int usr_udpcksum = 0;
+struct afsconf_dir *afs_cdir;  /* config dir */
 
-usr_key_t afs_global_u_key;
+int afs_bufferpages = 100;
 
-struct usr_proc *afs_global_procp;
-struct usr_ucred *afs_global_ucredp;
-struct usr_sysent usr_sysent[200];
+static usr_key_t afs_global_u_key;
 
-#ifdef AFS_USR_OSF_ENV
-char V = 'V';
-#else /* AFS_USR_OSF_ENV */
-long V = 'V';
-#endif /* AFS_USR_OSF_ENV */
+static struct usr_proc *afs_global_procp = NULL;
+static struct usr_ucred *afs_global_ucredp = NULL;
 
 struct usr_ucred afs_osi_cred, *afs_osi_credp;
 usr_mutex_t afs_global_lock;
 usr_thread_t afs_global_owner;
 usr_mutex_t rx_global_lock;
 usr_thread_t rx_global_owner;
-usr_mutex_t osi_inode_lock;
-usr_mutex_t osi_waitq_lock;
-usr_mutex_t osi_authenticate_lock;
+
+static usr_mutex_t osi_dummy_lock;
+static usr_mutex_t osi_waitq_lock;
+static usr_mutex_t osi_authenticate_lock;
 afs_lock_t afs_ftf;
 afs_lock_t osi_flplock;
 afs_lock_t osi_fsplock;
-void *vnodefops;
 
 #ifndef NETSCAPE_NSAPI
 
@@ -141,6 +105,7 @@ pthread_cond_t usr_sleep_cond;
 #endif /* !NETSCAPE_NSAPI */
 
 int call_syscall(long, long, long, long, long, long);
+int fork_syscall(long, long, long, long, long, long);
 
 
 /*
@@ -161,17 +126,17 @@ typedef struct osi_wait {
 /*
  * Head of the linked list of available waitq structures.
  */
-osi_wait_t *osi_waithash_avail;
+static osi_wait_t *osi_waithash_avail;
 
 /*
  * List of timed waits, NSAPI does not provide a cond_timed
  * wait, so we need to keep track of the timed waits ourselves and
  * periodically check for expirations
  */
-osi_wait_t *osi_timedwait_head;
-osi_wait_t *osi_timedwait_tail;
+static osi_wait_t *osi_timedwait_head;
+static osi_wait_t *osi_timedwait_tail;
 
-struct {
+static struct {
     osi_wait_t *head;
     osi_wait_t *tail;
 } osi_waithash_table[OSI_WAITHASH_SIZE];
@@ -254,21 +219,21 @@ usr_ioctl(void)
  * We do not support the inode related system calls
  */
 int
-afs_syscall_icreate(void)
+afs_syscall_icreate(long a, long b, long c, long d, long e, long f)
 {
     usr_assert(0);
     return 0;
 }
 
 int
-afs_syscall_iincdec(void)
+afs_syscall_iincdec(int dev, int inode, int inode_p1, int amount)
 {
     usr_assert(0);
     return 0;
 }
 
 int
-afs_syscall_iopen(void)
+afs_syscall_iopen(int dev, int inode, int usrmod)
 {
     usr_assert(0);
     return 0;
@@ -364,7 +329,7 @@ usr_crcopy(struct usr_ucred *credp)
 {
     struct usr_ucred *newcredp;
 
-    newcredp = (struct usr_ucred *)afs_osi_Alloc(sizeof(struct usr_ucred));
+    newcredp = afs_osi_Alloc(sizeof(struct usr_ucred));
     *newcredp = *credp;
     newcredp->cr_ref = 1;
     return newcredp;
@@ -375,7 +340,7 @@ usr_crget(void)
 {
     struct usr_ucred *newcredp;
 
-    newcredp = (struct usr_ucred *)afs_osi_Alloc(sizeof(struct usr_ucred));
+    newcredp = afs_osi_Alloc(sizeof(struct usr_ucred));
     newcredp->cr_ref = 1;
     return newcredp;
 }
@@ -426,9 +391,7 @@ uafs_InitThread(void)
      * allocate the data block, so pthread_finish can free the buffer
      * when this thread terminates.
      */
-    uptr =
-       (struct usr_user *)malloc(sizeof(struct usr_user) +
-                                 sizeof(struct usr_ucred));
+    uptr = malloc(sizeof(struct usr_user) + sizeof(struct usr_ucred));
     usr_assert(uptr != NULL);
     uptr->u_error = 0;
     uptr->u_prio = 0;
@@ -449,11 +412,12 @@ get_user_struct(void)
 {
     struct usr_user *uptr;
     int st;
-    st = usr_getspecific(afs_global_u_key, (void **)&uptr);
+
+    st = usr_getspecific(afs_global_u_key, &uptr);
     usr_assert(st == 0);
     if (uptr == NULL) {
        uafs_InitThread();
-       st = usr_getspecific(afs_global_u_key, (void **)&uptr);
+       st = usr_getspecific(afs_global_u_key, &uptr);
        usr_assert(st == 0);
        usr_assert(uptr != NULL);
     }
@@ -482,7 +446,7 @@ afs_osi_Sleep(void *x)
     }
     index = WAITHASH(x);
     if (osi_waithash_avail == NULL) {
-       waitp = (osi_wait_t *) afs_osi_Alloc(sizeof(osi_wait_t));
+       waitp = afs_osi_Alloc(sizeof(osi_wait_t));
        usr_cond_init(&waitp->cond);
     } else {
        waitp = osi_waithash_avail;
@@ -536,6 +500,12 @@ afs_osi_Wakeup(void *x)
 }
 
 int
+afs_osi_TimedSleep(void *event, afs_int32 ams, int aintok)
+{
+    return afs_osi_Wait(ams, event, aintok);
+}
+
+int
 afs_osi_Wait(afs_int32 msec, struct afs_osi_WaitHandle *handle, int intok)
 {
     int index;
@@ -562,7 +532,7 @@ afs_osi_Wait(afs_int32 msec, struct afs_osi_WaitHandle *handle, int intok)
        }
        index = WAITHASH((caddr_t) handle);
        if (osi_waithash_avail == NULL) {
-           waitp = (osi_wait_t *) afs_osi_Alloc(sizeof(osi_wait_t));
+           waitp = afs_osi_Alloc(sizeof(osi_wait_t));
            usr_cond_init(&waitp->cond);
        } else {
            waitp = osi_waithash_avail;
@@ -628,18 +598,19 @@ afs_osi_CheckTimedWaits(void)
 }
 
 /*
- * I-node numbers are indeces into a table containing a filename
- * i-node structure and a vnode structure. When we create an i-node,
- * we copy the name into the array and initialize enough of the fields
- * in the inode and vnode structures to get the client to work.
+ * 'dummy' vnode, for non-AFS files. We don't actually need most vnode
+ * information for non-AFS files, so point all of them towards this vnode
+ * to save memory.
  */
-typedef struct {
-    struct usr_inode i_node;
-    char *name;
-} osi_file_table_t;
-osi_file_table_t *osi_file_table;
-int n_osi_files = 0;
-int max_osi_files = 0;
+static struct usr_vnode dummy_vnode = {
+    0,    /* v_flag */
+    1024, /* v_count */
+    NULL, /* v_op */
+    NULL, /* v_vfsp */
+    0,    /* v_type */
+    0,    /* v_rdev */
+    NULL  /* v_data */
+};
 
 /*
  * Allocate a slot in the file table if there is not one there already,
@@ -649,12 +620,7 @@ int
 lookupname(char *fnamep, int segflg, int followlink,
           struct usr_vnode **compvpp)
 {
-    int i;
     int code;
-    struct usr_inode *ip;
-    struct usr_vnode *vp;
-
-    /*usr_assert(followlink == 0); */
 
     /*
      * Assume relative pathnames refer to files in AFS
@@ -666,34 +632,17 @@ lookupname(char *fnamep, int segflg, int followlink,
        return code;
     }
 
-    usr_mutex_lock(&osi_inode_lock);
+    /* For non-afs files, nobody really looks at the meaningful values in the
+     * returned vnode, so we can return a 'fake' one. The vnode can be held,
+     * released, etc. and some callers check for a NULL vnode anyway, so we
+     * to return something. */
 
-    for (i = 0; i < n_osi_files; i++) {
-       if (strcmp(fnamep, osi_file_table[i].name) == 0) {
-           *compvpp = &osi_file_table[i].i_node.i_vnode;
-           (*compvpp)->v_count++;
-           usr_mutex_unlock(&osi_inode_lock);
-           return 0;
-       }
-    }
+    usr_mutex_lock(&osi_dummy_lock);
+    VN_HOLD(&dummy_vnode);
+    usr_mutex_unlock(&osi_dummy_lock);
 
-    if (n_osi_files == max_osi_files) {
-       usr_mutex_unlock(&osi_inode_lock);
-       return ENOSPC;
-    }
+    *compvpp = &dummy_vnode;
 
-    osi_file_table[n_osi_files].name = afs_osi_Alloc(strlen(fnamep) + 1);
-    usr_assert(osi_file_table[n_osi_files].name != NULL);
-    strcpy(osi_file_table[n_osi_files].name, fnamep);
-    ip = &osi_file_table[i].i_node;
-    vp = &ip->i_vnode;
-    vp->v_data = (caddr_t) ip;
-    ip->i_dev = -1;
-    n_osi_files++;
-    ip->i_number = n_osi_files;
-    vp->v_count = 2;
-    usr_mutex_unlock(&osi_inode_lock);
-    *compvpp = vp;
     return 0;
 }
 
@@ -701,7 +650,7 @@ lookupname(char *fnamep, int segflg, int followlink,
  * open a file given its i-node number
  */
 void *
-osi_UFSOpen(afs_int32 ino)
+osi_UFSOpen(afs_dcache_id_t *ino)
 {
     int rc;
     struct osi_file *fp;
@@ -709,31 +658,28 @@ osi_UFSOpen(afs_int32 ino)
 
     AFS_ASSERT_GLOCK();
 
-    if (ino > n_osi_files) {
-       u.u_error = ENOENT;
-       return NULL;
-    }
-
     AFS_GUNLOCK();
-    fp = (struct osi_file *)afs_osi_Alloc(sizeof(struct osi_file));
+    fp = afs_osi_Alloc(sizeof(struct osi_file));
     usr_assert(fp != NULL);
-    fp->fd = open(osi_file_table[ino - 1].name, O_RDWR | O_CREAT, 0);
+
+    usr_assert(ino->ufs);
+
+    fp->fd = open(ino->ufs, O_RDWR | O_CREAT, 0);
     if (fp->fd < 0) {
-       u.u_error = errno;
+       get_user_struct()->u_error = errno;
        afs_osi_Free((char *)fp, sizeof(struct osi_file));
        AFS_GLOCK();
        return NULL;
     }
     rc = fstat(fp->fd, &st);
     if (rc < 0) {
-       u.u_error = errno;
+       get_user_struct()->u_error = errno;
        afs_osi_Free((void *)fp, sizeof(struct osi_file));
        AFS_GLOCK();
        return NULL;
     }
     fp->size = st.st_size;
     fp->offset = 0;
-    fp->inum = ino;
     fp->vnode = (struct usr_vnode *)fp;
 
     AFS_GLOCK();
@@ -750,7 +696,7 @@ osi_UFSClose(struct osi_file *fp)
     AFS_GUNLOCK();
     rc = close(fp->fd);
     if (rc < 0) {
-       u.u_error = errno;
+       get_user_struct()->u_error = errno;
        afs_osi_Free((void *)fp, sizeof(struct osi_file));
        AFS_GLOCK();
        return -1;
@@ -770,7 +716,7 @@ osi_UFSTruncate(struct osi_file *fp, afs_int32 len)
     AFS_GUNLOCK();
     rc = ftruncate(fp->fd, len);
     if (rc < 0) {
-       u.u_error = errno;
+       get_user_struct()->u_error = errno;
        AFS_GLOCK();
        return -1;
     }
@@ -783,7 +729,6 @@ int
 afs_osi_Read(struct osi_file *fp, int offset, void *buf, afs_int32 len)
 {
     int rc, ret;
-    int code;
     struct stat st;
 
     AFS_ASSERT_GLOCK();
@@ -795,21 +740,21 @@ afs_osi_Read(struct osi_file *fp, int offset, void *buf, afs_int32 len)
        rc = lseek(fp->fd, fp->offset, SEEK_SET);
     }
     if (rc < 0) {
-       u.u_error = errno;
+       get_user_struct()->u_error = errno;
        AFS_GLOCK();
        return -1;
     }
     fp->offset = rc;
     ret = read(fp->fd, buf, len);
     if (ret < 0) {
-       u.u_error = errno;
+       get_user_struct()->u_error = errno;
        AFS_GLOCK();
        return -1;
     }
     fp->offset += ret;
     rc = fstat(fp->fd, &st);
     if (rc < 0) {
-       u.u_error = errno;
+       get_user_struct()->u_error = errno;
        AFS_GLOCK();
        return -1;
     }
@@ -822,7 +767,6 @@ int
 afs_osi_Write(struct osi_file *fp, afs_int32 offset, void *buf, afs_int32 len)
 {
     int rc, ret;
-    int code;
     struct stat st;
 
     AFS_ASSERT_GLOCK();
@@ -834,21 +778,21 @@ afs_osi_Write(struct osi_file *fp, afs_int32 offset, void *buf, afs_int32 len)
        rc = lseek(fp->fd, fp->offset, SEEK_SET);
     }
     if (rc < 0) {
-       u.u_error = errno;
+       get_user_struct()->u_error = errno;
        AFS_GLOCK();
        return -1;
     }
     fp->offset = rc;
     ret = write(fp->fd, buf, len);
     if (ret < 0) {
-       u.u_error = errno;
+       get_user_struct()->u_error = errno;
        AFS_GLOCK();
        return -1;
     }
     fp->offset += ret;
     rc = fstat(fp->fd, &st);
     if (rc < 0) {
-       u.u_error = errno;
+       get_user_struct()->u_error = errno;
        AFS_GLOCK();
        return -1;
     }
@@ -866,7 +810,7 @@ afs_osi_Stat(struct osi_file *fp, struct osi_stat *stp)
     AFS_GUNLOCK();
     rc = fstat(fp->fd, &st);
     if (rc < 0) {
-       u.u_error = errno;
+       get_user_struct()->u_error = errno;
        AFS_GLOCK();
        return -1;
     }
@@ -903,7 +847,7 @@ afs_osi_VOP_RDWR(struct usr_vnode *vnodeP, struct usr_uio *uioP, int rw,
                          uioP->uio_iov[0].iov_len);
     }
     if (rc < 0) {
-       return u.u_error;
+       return get_user_struct()->u_error;
     }
 
     uioP->uio_resid -= rc;
@@ -913,13 +857,6 @@ afs_osi_VOP_RDWR(struct usr_vnode *vnodeP, struct usr_uio *uioP, int rw,
     return 0;
 }
 
-/*
- * Use malloc/free routines with check patterns before and after each block
- */
-
-static char *afs_check_string1 = "UAFS";
-static char *afs_check_string2 = "AFS_OSI_";
-
 void *
 afs_osi_Alloc(size_t size)
 {
@@ -1004,6 +941,12 @@ afs_osi_Invisible(void)
     return;
 }
 
+void
+afs_osi_Visible(void)
+{
+    return;
+}
+
 int
 osi_GetTime(struct timeval *tv)
 {
@@ -1027,7 +970,7 @@ osi_Active(struct vcache *avc)
 }
 
 int
-afs_osi_MapStrategy(int (*aproc) (), struct usr_buf *bp)
+afs_osi_MapStrategy(int (*aproc) (struct usr_buf *), struct usr_buf *bp)
 {
     afs_int32 returnCode;
     returnCode = (*aproc) (bp);
@@ -1035,25 +978,25 @@ afs_osi_MapStrategy(int (*aproc) (), struct usr_buf *bp)
 }
 
 void
-osi_FlushPages(register struct vcache *avc, struct AFS_UCRED *credp)
+osi_FlushPages(struct vcache *avc, afs_ucred_t *credp)
 {
     ObtainSharedLock(&avc->lock, 555);
-    if ((hcmp((avc->m.DataVersion), (avc->mapDV)) <= 0)
+    if ((hcmp((avc->f.m.DataVersion), (avc->mapDV)) <= 0)
        || ((avc->execsOrWriters > 0) && afs_DirtyPages(avc))) {
        ReleaseSharedLock(&avc->lock);
        return;
     }
     UpgradeSToWLock(&avc->lock, 565);
-    hset(avc->mapDV, avc->m.DataVersion);
+    hset(avc->mapDV, avc->f.m.DataVersion);
     ReleaseWriteLock(&avc->lock);
     return;
 }
 
 void
-osi_FlushText_really(register struct vcache *vp)
+osi_FlushText_really(struct vcache *vp)
 {
-    if (hcmp(vp->m.DataVersion, vp->flushDV) > 0) {
-       hset(vp->flushDV, vp->m.DataVersion);
+    if (hcmp(vp->f.m.DataVersion, vp->flushDV) > 0) {
+       hset(vp->flushDV, vp->f.m.DataVersion);
     }
     return;
 }
@@ -1074,16 +1017,42 @@ void
 osi_Init(void)
 {
     int i;
-    int rc;
-    usr_thread_t tid;
+    int st;
+
+    /*
+     * Use the thread specific data to implement the user structure
+     */
+    usr_keycreate(&afs_global_u_key, free);
+
+    /*
+     * Initialize the global ucred structure
+     */
+    afs_global_ucredp = (struct usr_ucred *)
+       afs_osi_Alloc(sizeof(struct usr_ucred));
+    usr_assert(afs_global_ucredp != NULL);
+    afs_global_ucredp->cr_ref = 1;
+    afs_set_cr_uid(afs_global_ucredp, geteuid());
+    afs_set_cr_gid(afs_global_ucredp, getegid());
+    afs_set_cr_ruid(afs_global_ucredp, getuid());
+    afs_set_cr_rgid(afs_global_ucredp, getgid());
+    afs_global_ucredp->cr_suid = afs_cr_ruid(afs_global_ucredp);
+    afs_global_ucredp->cr_sgid = afs_cr_rgid(afs_global_ucredp);
+    st = getgroups(NGROUPS, &afs_global_ucredp->cr_groups[0]);
+    usr_assert(st >= 0);
+    afs_global_ucredp->cr_ngroups = (unsigned long)st;
+    for (i = st; i < NGROUPS; i++) {
+       afs_global_ucredp->cr_groups[i] = NOGROUP;
+    }
 
     /*
-     * Allocate the table used to implement psuedo-inodes.
+     * Initialize the global process structure
      */
-    max_osi_files = cacheFiles + 100;
-    osi_file_table = (osi_file_table_t *)
-       afs_osi_Alloc(max_osi_files * sizeof(osi_file_table_t));
-    usr_assert(osi_file_table != NULL);
+    afs_global_procp = (struct usr_proc *)
+       afs_osi_Alloc(sizeof(struct usr_proc));
+    usr_assert(afs_global_procp != NULL);
+    afs_global_procp->p_pid = osi_getpid();
+    afs_global_procp->p_ppid = (pid_t) 1;
+    afs_global_procp->p_ucred = afs_global_ucredp;
 
 #ifndef NETSCAPE_NSAPI
     /*
@@ -1115,7 +1084,7 @@ osi_Init(void)
      */
     usr_mutex_init(&afs_global_lock);
     usr_mutex_init(&rx_global_lock);
-    usr_mutex_init(&osi_inode_lock);
+    usr_mutex_init(&osi_dummy_lock);
     usr_mutex_init(&osi_waitq_lock);
     usr_mutex_init(&osi_authenticate_lock);
 
@@ -1124,324 +1093,8 @@ osi_Init(void)
      */
     afs_osi_cred = *afs_global_ucredp;
     afs_osi_credp = &afs_osi_cred;
-}
-
-/* ParseArgs is now obsolete, being handled by cmd */
-
-/*---------------------------------------------------------------------
-  * GetVFileNumber
-  *
-  * Description:
-  *    Given the final component of a filename expected to be a data cache file,
-  *    return the integer corresponding to the file.  Note: we reject names that
-  *    are not a ``V'' followed by an integer.  We also reject those names having
-  *    the right format but lying outside the range [0..cacheFiles-1].
-  *
-  * Arguments:
-  *    fname : Char ptr to the filename to parse.
-  *
-  * Returns:
-  *    >= 0 iff the file is really a data cache file numbered from 0 to cacheFiles-1, or
-  *    -1      otherwise.
-  *
-  * Environment:
-  *    Nothing interesting.
-  *
-  * Side Effects:
-  *    None.
-  *------------------------------------------------------------------------*/
-
-int
-GetVFileNumber(char *fname)
-{
-    int computedVNumber;       /*The computed file number we return */
-    int filenameLen;           /*Number of chars in filename */
-    int currDigit;             /*Current digit being processed */
-
-    /*
-     * The filename must have at least two characters, the first of which must be a ``V''
-     * and the second of which cannot be a zero unless the file is exactly two chars long.
-     */
-    filenameLen = strlen(fname);
-    if (filenameLen < 2)
-       return (-1);
-    if (fname[0] != 'V')
-       return (-1);
-    if ((filenameLen > 2) && (fname[1] == '0'))
-       return (-1);
-
-    /*
-     * Scan through the characters in the given filename, failing immediately if a non-digit
-     * is found.
-     */
-    for (currDigit = 1; currDigit < filenameLen; currDigit++)
-       if (isdigit(fname[currDigit]) == 0)
-           return (-1);
-
-    /*
-     * All relevant characters are digits.  Pull out the decimal number they represent.
-     * Reject it if it's out of range, otherwise return it.
-     */
-    computedVNumber = atoi(++fname);
-    if (computedVNumber < cacheFiles)
-       return (computedVNumber);
-    else
-       return (-1);
-}
-
-/*---------------------------------------------------------------------
-  * CreateCacheFile
-  *
-  * Description:
-  *    Given a full pathname for a file we need to create for the workstation AFS
-  *    cache, go ahead and create the file.
-  *
-  * Arguments:
-  *    fname : Full pathname of file to create.
-  *
-  * Returns:
-  *    0   iff the file was created,
-  *    -1  otherwise.
-  *
-  * Environment:
-  *    The given cache file has been found to be missing.
-  *
-  * Side Effects:
-  *    As described.
-  *------------------------------------------------------------------------*/
-
-int
-CreateCacheFile(char *fname)
-{
-    static char rn[] = "CreateCacheFile";      /*Routine name */
-    int cfd;                   /*File descriptor to AFS cache file */
-    int closeResult;           /*Result of close() */
-
-    if (afsd_verbose)
-       printf("%s: Creating cache file '%s'\n", rn, fname);
-    cfd = open(fname, createAndTrunc, ownerRWmode);
-    if (cfd <= 0) {
-       printf("%s: Can't create '%s', error return is %d (%d)\n", rn, fname,
-              cfd, errno);
-       return (-1);
-    }
-    closeResult = close(cfd);
-    if (closeResult) {
-       printf
-           ("%s: Can't close newly-created AFS cache file '%s' (code %d)\n",
-            rn, fname, errno);
-       return (-1);
-    }
-
-    return (0);
-}
-
-/*---------------------------------------------------------------------
-  * SweepAFSCache
-  *
-  * Description:
-  *    Sweep through the AFS cache directory, recording the inode number for
-  *    each valid data cache file there.  Also, delete any file that doesn't beint32
-  *    in the cache directory during this sweep, and remember which of the other
-  *    residents of this directory were seen.  After the sweep, we create any data
-  *    cache files that were missing.
-  *
-  * Arguments:
-  *    vFilesFound : Set to the number of data cache files found.
-  *
-  * Returns:
-  *    0   if everything went well,
-  *    -1 otherwise.
-  *
-  * Environment:
-  *    This routine may be called several times.  If the number of data cache files
-  *    found is less than the global cacheFiles, then the caller will need to call it
-  *    again to record the inodes of the missing zero-length data cache files created
-  *    in the previous call.
-  *
-  * Side Effects:
-  *    Fills up the global pathname_for_V array, may create and/or
-  *     delete files as explained above.
-  *------------------------------------------------------------------------*/
-
-int
-SweepAFSCache(int *vFilesFound)
-{
-    static char rn[] = "SweepAFSCache";        /*Routine name */
-    char fullpn_FileToDelete[1024];    /*File to be deleted from cache */
-    char *fileToDelete;                /*Ptr to last component of above */
-    DIR *cdirp;                        /*Ptr to cache directory structure */
-#undef dirent
-    struct dirent *currp;      /*Current directory entry */
-    int vFileNum;              /*Data cache file's associated number */
-
-    if (cacheFlags & AFSCALL_INIT_MEMCACHE) {
-       if (afsd_debug)
-           printf("%s: Memory Cache, no cache sweep done\n", rn);
-       *vFilesFound = 0;
-       return 0;
-    }
-
-    if (afsd_debug)
-       printf("%s: Opening cache directory '%s'\n", rn, cacheBaseDir);
-
-    if (chmod(cacheBaseDir, 0700)) {   /* force it to be 700 */
-       printf("%s: Can't 'chmod 0700' the cache dir, '%s'.\n", rn,
-              cacheBaseDir);
-       return (-1);
-    }
-    cdirp = opendir(cacheBaseDir);
-    if (cdirp == (DIR *) 0) {
-       printf("%s: Can't open AFS cache directory, '%s'.\n", rn,
-              cacheBaseDir);
-       return (-1);
-    }
-
-    /*
-     * Scan the directory entries, remembering data cache file inodes and the existance
-     * of other important residents.  Delete all files that don't belong here.
-     */
-    *vFilesFound = 0;
-    sprintf(fullpn_FileToDelete, "%s/", cacheBaseDir);
-    fileToDelete = fullpn_FileToDelete + strlen(fullpn_FileToDelete);
-
-    for (currp = readdir(cdirp); currp; currp = readdir(cdirp)) {
-       if (afsd_debug) {
-           printf("%s: Current directory entry:\n", rn);
-           printf("\tinode=%d, reclen=%d, name='%s'\n", currp->d_ino,
-                  currp->d_reclen, currp->d_name);
-       }
-
-       /*
-        * Guess current entry is for a data cache file.
-        */
-       vFileNum = GetVFileNumber(currp->d_name);
-       if (vFileNum >= 0) {
-           /*
-            * Found a valid data cache filename.  Remember this file's name
-            * and bump the number of files found.
-            */
-           pathname_for_V[vFileNum] =
-               afs_osi_Alloc(strlen(currp->d_name) + strlen(cacheBaseDir) +
-                             2);
-           usr_assert(pathname_for_V[vFileNum] != NULL);
-           sprintf(pathname_for_V[vFileNum], "%s/%s", cacheBaseDir,
-                   currp->d_name);
-           (*vFilesFound)++;
-       } else if (strcmp(currp->d_name, DCACHEFILE) == 0) {
-           /*
-            * Found the file holding the dcache entries.
-            */
-           missing_DCacheFile = 0;
-       } else if (strcmp(currp->d_name, VOLINFOFILE) == 0) {
-           /*
-            * Found the file holding the volume info.
-            */
-           missing_VolInfoFile = 0;
-       } else if (strcmp(currp->d_name, CELLINFOFILE) == 0) {
-           missing_CellInfoFile = 0;
-       } else if ((strcmp(currp->d_name, ".") == 0)
-                  || (strcmp(currp->d_name, "..") == 0)
-                  || (strcmp(currp->d_name, "lost+found") == 0)) {
-           /*
-            * Don't do anything - this file is legit, and is to be left alone.
-            */
-       } else {
-           /*
-            * This file doesn't belong in the cache.  Nuke it.
-            */
-           sprintf(fileToDelete, "%s", currp->d_name);
-           if (afsd_verbose)
-               printf("%s: Deleting '%s'\n", rn, fullpn_FileToDelete);
-           if (unlink(fullpn_FileToDelete)) {
-               printf("%s: Can't unlink '%s', errno is %d\n", rn,
-                      fullpn_FileToDelete, errno);
-           }
-       }
-    }
 
-    /*
-     * Create all the cache files that are missing.
-     */
-    if (missing_DCacheFile) {
-       if (afsd_verbose)
-           printf("%s: Creating '%s'\n", rn, fullpn_DCacheFile);
-       if (CreateCacheFile(fullpn_DCacheFile))
-           printf("%s: Can't create '%s'\n", rn, fullpn_DCacheFile);
-    }
-    if (missing_VolInfoFile) {
-       if (afsd_verbose)
-           printf("%s: Creating '%s'\n", rn, fullpn_VolInfoFile);
-       if (CreateCacheFile(fullpn_VolInfoFile))
-           printf("%s: Can't create '%s'\n", rn, fullpn_VolInfoFile);
-    }
-    if (missing_CellInfoFile) {
-       if (afsd_verbose)
-           printf("%s: Creating '%s'\n", rn, fullpn_CellInfoFile);
-       if (CreateCacheFile(fullpn_CellInfoFile))
-           printf("%s: Can't create '%s'\n", rn, fullpn_CellInfoFile);
-    }
-
-    if (*vFilesFound < cacheFiles) {
-       /*
-        * We came up short on the number of data cache files found.  Scan through the inode
-        * list and create all missing files.
-        */
-       for (vFileNum = 0; vFileNum < cacheFiles; vFileNum++)
-           if (pathname_for_V[vFileNum] == (AFSD_INO_T) 0) {
-               sprintf(vFileNumber, "%d", vFileNum);
-               if (afsd_verbose)
-                   printf("%s: Creating '%s'\n", rn, fullpn_VFile);
-               if (CreateCacheFile(fullpn_VFile))
-                   printf("%s: Can't create '%s'\n", rn, fullpn_VFile);
-           }
-    }
-
-    /*
-     * Close the directory, return success.
-     */
-    if (afsd_debug)
-       printf("%s: Closing cache directory.\n", rn);
-    closedir(cdirp);
-    return (0);
-}
-
-static int
-ConfigCell(register struct afsconf_cell *aci, void *arock,
-          struct afsconf_dir *adir)
-{
-    register int isHomeCell;
-    register int i;
-    afs_int32 cellFlags = 0;
-    afs_int32 hosts[MAXHOSTSPERCELL];
-
-    /* figure out if this is the home cell */
-    isHomeCell = (strcmp(aci->name, afs_LclCellName) == 0);
-    if (!isHomeCell)
-       cellFlags = 2;          /* not home, suid is forbidden */
-
-    /* build address list */
-    for (i = 0; i < MAXHOSTSPERCELL; i++)
-       memcpy(&hosts[i], &aci->hostAddr[i].sin_addr, sizeof(afs_int32));
-
-    if (aci->linkedCell)
-       cellFlags |= 4;         /* Flag that linkedCell arg exists,
-                                * for upwards compatibility */
-
-    /* configure one cell */
-    call_syscall(AFSCALL_CALL, AFSOP_ADDCELL2, (long)hosts,    /* server addresses */
-                (long)aci->name,       /* cell name */
-                (long)cellFlags,       /* is this the home cell? */
-                (long)aci->linkedCell);        /* Linked cell, if any */
-    return 0;
-}
-
-static int
-ConfigCellAlias(struct afsconf_cellalias *aca, void *arock, struct afsconf_dir *adir)
-{
-       call_syscall(AFSOP_ADDCELLALIAS, (long)aca->aliasName, 
-                    (long)aca->realName, 0, 0, 0);
-       return 0;
+    init_et_to_sys_error();
 }
 
 /*
@@ -1454,444 +1107,172 @@ uafs_SetRxPort(int port)
     usr_rx_port = port;
 }
 
-
 /*
- * Initialize the user space client.
+ * uafs_Init is for backwards compatibility only! Do not use it; use
+ * uafs_Setup, uafs_ParseArgs, and uafs_Run instead.
  */
 void
 uafs_Init(char *rn, char *mountDirParam, char *confDirParam,
-         char *cacheBaseDirParam, int cacheBlocksParam, int cacheFilesParam,
-         int cacheStatEntriesParam, int dCacheSizeParam, int vCacheSizeParam,
-         int chunkSizeParam, int closeSynchParam, int debugParam,
-         int nDaemonsParam, int cacheFlagsParam, char *logFile)
+          char *cacheBaseDirParam, int cacheBlocksParam, int cacheFilesParam,
+          int cacheStatEntriesParam, int dCacheSizeParam, int vCacheSizeParam,
+          int chunkSizeParam, int closeSynchParam, int debugParam,
+          int nDaemonsParam, int cacheFlagsParam, char *logFile)
 {
-    int st;
-    struct usr_proc *procp;
-    struct usr_ucred *ucredp;
+    int code;
+    int argc = 0;
+    char *argv[32];
+    int freeargc = 0;
+    void *freeargv[32];
+    char buf[1024];
     int i;
-    int rc;
-    int currVFile;             /* Current AFS cache file number */
-    int lookupResult;          /* Result of GetLocalCellName() */
-    int cacheIteration;                /* cache verification loop counter */
-    int vFilesFound;           /* Num data cache files found in sweep */
-    FILE *logfd;
-    afs_int32 vfs1_type = -1;
-    struct afs_ioctl iob;
-    char tbuffer[1024];
-    char *p;
-    char lastchar;
-    afs_int32 buffer[MAXIPADDRS];
-    afs_int32 maskbuffer[MAXIPADDRS];
-    afs_int32 mtubuffer[MAXIPADDRS];
-
-    /*
-     * Use the thread specific data to implement the user structure
-     */
-    usr_keycreate(&afs_global_u_key, free);
-
-    /*
-     * Initialize the global ucred structure
-     */
-    afs_global_ucredp = (struct usr_ucred *)
-       afs_osi_Alloc(sizeof(struct usr_ucred));
-    usr_assert(afs_global_ucredp != NULL);
-    afs_global_ucredp->cr_ref = 1;
-    afs_global_ucredp->cr_uid = geteuid();
-    afs_global_ucredp->cr_gid = getegid();
-    afs_global_ucredp->cr_ruid = getuid();
-    afs_global_ucredp->cr_rgid = getgid();
-    afs_global_ucredp->cr_suid = afs_global_ucredp->cr_ruid;
-    afs_global_ucredp->cr_sgid = afs_global_ucredp->cr_rgid;
-    st = getgroups(NGROUPS, &afs_global_ucredp->cr_groups[0]);
-    usr_assert(st >= 0);
-    afs_global_ucredp->cr_ngroups = (unsigned long)st;
-    for (i = st; i < NGROUPS; i++) {
-       afs_global_ucredp->cr_groups[i] = NOGROUP;
-    }
 
-    /*
-     * Initialize the global process structure
-     */
-    afs_global_procp = (struct usr_proc *)
-       afs_osi_Alloc(sizeof(struct usr_proc));
-    usr_assert(afs_global_procp != NULL);
-    afs_global_procp->p_pid = getpid();
-    afs_global_procp->p_ppid = (pid_t) 1;
-    afs_global_procp->p_ucred = afs_global_ucredp;
+    code = uafs_Setup(mountDirParam);
+    usr_assert(code == 0);
 
-    /*
-     * Initialize the AFS mount point, default is '/afs'.
-     * Strip duplicate/trailing slashes from mount point string.
-     * afs_mountDirLen is set to strlen(afs_mountDir).
-     */
+    argv[argc++] = rn;
     if (mountDirParam) {
-       sprintf(tbuffer, "%s", mountDirParam);
-    } else {
-       sprintf(tbuffer, "afs");
+       argv[argc++] = "-mountdir";
+       argv[argc++] = mountDirParam;
     }
-    afs_mountDir[0] = '/';
-    afs_mountDirLen = 1;
-    for (lastchar = '/', p = &tbuffer[0]; *p != '\0'; p++) {
-       if (lastchar != '/' || *p != '/') {
-           afs_mountDir[afs_mountDirLen++] = lastchar = *p;
-       }
+    if (confDirParam) {
+       argv[argc++] = "-confdir";
+       argv[argc++] = confDirParam;
+    }
+    if (cacheBaseDirParam) {
+       argv[argc++] = "-cachedir";
+       argv[argc++] = cacheBaseDirParam;
     }
-    if (lastchar == '/' && afs_mountDirLen > 1)
-       afs_mountDirLen--;
-    afs_mountDir[afs_mountDirLen] = '\0';
-    usr_assert(afs_mountDirLen > 1);
+    if (cacheBlocksParam) {
+       snprintf(buf, sizeof(buf), "%d", cacheBlocksParam);
 
-    /*
-     * Initialize cache parameters using the input arguments
-     */
+       argv[argc++] = "-blocks";
+       argv[argc++] = freeargv[freeargc++] = strdup(buf);
+    }
+    if (cacheFilesParam) {
+       snprintf(buf, sizeof(buf), "%d", cacheFilesParam);
 
-    cacheBlocks = cacheBlocksParam;
-    if (cacheFilesParam != 0) {
-       cacheFiles = cacheFilesParam;
-    } else {
-       cacheFiles = cacheBlocks / 10;
+       argv[argc++] = "-files";
+       argv[argc++] = freeargv[freeargc++] = strdup(buf);
     }
-    if (cacheStatEntriesParam != 0) {
-       cacheStatEntries = cacheStatEntriesParam;
+    if (cacheStatEntriesParam) {
+       snprintf(buf, sizeof(buf), "%d", cacheStatEntriesParam);
+
+       argv[argc++] = "-stat";
+       argv[argc++] = freeargv[freeargc++] = strdup(buf);
     }
-    strcpy(cacheBaseDir, cacheBaseDirParam);
-    if (nDaemons != 0) {
-       nDaemons = nDaemonsParam;
-    } else {
-       nDaemons = 3;
+    if (dCacheSizeParam) {
+       snprintf(buf, sizeof(buf), "%d", dCacheSizeParam);
+
+       argv[argc++] = "-dcache";
+       argv[argc++] = freeargv[freeargc++] = strdup(buf);
     }
-    afsd_verbose = debugParam;
-    afsd_debug = debugParam;
-    chunkSize = chunkSizeParam;
-    if (dCacheSizeParam != 0) {
-       dCacheSize = dCacheSizeParam;
-    } else {
-       dCacheSize = cacheFiles / 2;
+    if (vCacheSizeParam) {
+       snprintf(buf, sizeof(buf), "%d", vCacheSizeParam);
+
+       argv[argc++] = "-volumes";
+       argv[argc++] = freeargv[freeargc++] = strdup(buf);
     }
-    if (vCacheSizeParam != 0) {
-       vCacheSize = vCacheSizeParam;
+    if (chunkSizeParam) {
+       snprintf(buf, sizeof(buf), "%d", chunkSizeParam);
+
+       argv[argc++] = "-chunksize";
+       argv[argc++] = freeargv[freeargc++] = strdup(buf);
     }
-    strcpy(confDir, confDirParam);
-    afsd_CloseSynch = closeSynchParam;
-    if (cacheFlagsParam >= 0) {
-       cacheFlags = cacheFlagsParam;
+    if (closeSynchParam) {
+       argv[argc++] = "-waitclose";
     }
-    if (cacheFlags & AFSCALL_INIT_MEMCACHE) {
-       cacheFiles = dCacheSize;
+    if (debugParam) {
+       argv[argc++] = "-debug";
     }
+    if (nDaemonsParam) {
+       snprintf(buf, sizeof(buf), "%d", nDaemonsParam);
 
-    sprintf(fullpn_CacheInfo, "%s/%s", confDir, CACHEINFOFILE);
-    if (logFile == NULL) {
-       sprintf(fullpn_AFSLogFile, "%s/%s", confDir, AFSLOGFILE);
-    } else {
-       strcpy(fullpn_AFSLogFile, logFile);
-    }
-
-    printf("\n%s: Initializing user space AFS client\n\n", rn);
-    printf("    mountDir:           %s\n", afs_mountDir);
-    printf("    confDir:            %s\n", confDir);
-    printf("    cacheBaseDir:       %s\n", cacheBaseDir);
-    printf("    cacheBlocks:        %d\n", cacheBlocks);
-    printf("    cacheFiles:         %d\n", cacheFiles);
-    printf("    cacheStatEntries:   %d\n", cacheStatEntries);
-    printf("    dCacheSize:         %d\n", dCacheSize);
-    printf("    vCacheSize:         %d\n", vCacheSize);
-    printf("    chunkSize:          %d\n", chunkSize);
-    printf("    afsd_CloseSynch:    %d\n", afsd_CloseSynch);
-    printf("    afsd_debug/verbose: %d/%d\n", afsd_debug, afsd_verbose);
-    printf("    nDaemons:           %d\n", nDaemons);
-    printf("    cacheFlags:         %d\n", cacheFlags);
-    printf("    logFile:            %s\n", fullpn_AFSLogFile);
-    printf("\n");
-    fflush(stdout);
-
-    /*
-     * Initialize the AFS client
-     */
-    osi_Init();
-
-    /*
-     * Pull out all the configuration info for the workstation's AFS cache and
-     * the cellular community we're willing to let our users see.
-     */
-    afs_cdir = afsconf_Open(confDir);
-    if (!afs_cdir) {
-       printf("afsd: some file missing or bad in %s\n", confDir);
-       exit(1);
-    }
-
-    lookupResult =
-       afsconf_GetLocalCell(afs_cdir, afs_LclCellName,
-                            sizeof(afs_LclCellName));
-    if (lookupResult) {
-       printf("%s: Can't get my home cell name!  [Error is %d]\n", rn,
-              lookupResult);
-    } else {
-       if (afsd_verbose)
-           printf("%s: My home cell is '%s'\n", rn, afs_LclCellName);
+       argv[argc++] = "-daemons";
+       argv[argc++] = freeargv[freeargc++] = strdup(buf);
     }
-
-    /*
-     * Set the primary cell name.
-     */
-    call_syscall(AFSOP_SET_THISCELL, (long)afs_LclCellName, 0, 0, 0, 0);
-
-    if ((logfd = fopen(fullpn_AFSLogFile, "r+")) == 0) {
-       if (afsd_verbose)
-           printf("%s: Creating '%s'\n", rn, fullpn_AFSLogFile);
-       if (CreateCacheFile(fullpn_AFSLogFile)) {
-           printf
-               ("%s: Can't create '%s' (You may want to use the -logfile option)\n",
-                rn, fullpn_AFSLogFile);
-           exit(1);
+    if (cacheFlagsParam) {
+       if (cacheFlagsParam & AFSCALL_INIT_MEMCACHE) {
+           argv[argc++] = "-memcache";
        }
-    } else
-       fclose(logfd);
-
-    /*
-     * Create and zero the pathname table for the desired cache files.
-     */
-    pathname_for_V = (char **)afs_osi_Alloc(cacheFiles * sizeof(char *));
-    if (pathname_for_V == NULL) {
-       printf("%s: malloc() failed for cache file table with %d entries.\n",
-              rn, cacheFiles);
-       exit(1);
     }
-    memset(pathname_for_V, 0, (cacheFiles * sizeof(char *)));
-    if (afsd_debug)
-       printf("%s: %d pathname_for_V entries at 0x%x, %d bytes\n", rn,
-              cacheFiles, pathname_for_V, (cacheFiles * sizeof(AFSD_INO_T)));
-
-    /*
-     * Set up all the pathnames we'll need for later.
-     */
-    sprintf(fullpn_DCacheFile, "%s/%s", cacheBaseDir, DCACHEFILE);
-    sprintf(fullpn_VolInfoFile, "%s/%s", cacheBaseDir, VOLINFOFILE);
-    sprintf(fullpn_CellInfoFile, "%s/%s", cacheBaseDir, CELLINFOFILE);
-    sprintf(fullpn_VFile, "%s/V", cacheBaseDir);
-    vFileNumber = fullpn_VFile + strlen(fullpn_VFile);
-
-    /*
-     * Start the RX listener.
-     */
-    if (afsd_debug)
-       printf("%s: Calling AFSOP_RXLISTENER_DAEMON\n", rn);
-    fork_syscall(AFSCALL_CALL, AFSOP_RXLISTENER_DAEMON, FALSE, FALSE, FALSE);
-
-    /*
-     * Start the RX event handler.
-     */
-    if (afsd_debug)
-       printf("%s: Calling AFSOP_RXEVENT_DAEMON\n", rn);
-    fork_syscall(AFSCALL_CALL, AFSOP_RXEVENT_DAEMON, FALSE);
-
-    /*
-     * Set up all the kernel processes needed for AFS.
-     */
-
-    /* initialize AFS callback interface */
-    {
-       /* parse multihomed address files */
-       char reason[1024];
-       st = parseNetFiles((afs_uint32*)buffer,(afs_uint32*) maskbuffer, (afs_uint32*)mtubuffer, MAXIPADDRS, reason,
-                          AFSDIR_CLIENT_NETINFO_FILEPATH,
-                          AFSDIR_CLIENT_NETRESTRICT_FILEPATH);
-       if (st > 0)
-           call_syscall(AFSCALL_CALL, AFSOP_ADVISEADDR, st,
-                        (long)(&buffer[0]), (long)(&maskbuffer[0]),
-                        (long)(&mtubuffer[0]));
-       else {
-           printf("ADVISEADDR: Error in specifying interface addresses:%s\n",
-                  reason);
-           exit(1);
-       }
+    if (logFile) {
+       argv[argc++] = "-logfile";
+       argv[argc++] = logFile;
     }
 
-    if (afsd_verbose)
-       printf("%s: Forking rx callback listener.\n", rn);
-    /* Child */
-    if (preallocs < cacheStatEntries + 50)
-       preallocs = cacheStatEntries + 50;
-    fork_syscall(AFSCALL_CALL, AFSOP_START_RXCALLBACK, preallocs);
-
-    if (afsd_verbose)
-       printf("%s: Initializing AFS daemon.\n", rn);
-    call_syscall(AFSCALL_CALL, AFSOP_BASIC_INIT, 1, 0, 0, 0);
+    argv[argc] = NULL;
 
-    /*
-     * Tell the kernel some basic information about the workstation's cache.
-     */
-    if (afsd_verbose)
-       printf("%s: Calling AFSOP_CACHEINIT: %d stat cache entries,"
-              " %d optimum cache files, %d blocks in the cache,"
-              " flags = 0x%x, dcache entries %d\n", rn, cacheStatEntries,
-              cacheFiles, cacheBlocks, cacheFlags, dCacheSize);
-    memset(&cparams, 0, sizeof(cparams));
-    cparams.cacheScaches = cacheStatEntries;
-    cparams.cacheFiles = cacheFiles;
-    cparams.cacheBlocks = cacheBlocks;
-    cparams.cacheDcaches = dCacheSize;
-    cparams.cacheVolumes = vCacheSize;
-    cparams.chunkSize = chunkSize;
-    cparams.setTimeFlag = FALSE;
-    cparams.memCacheFlag = cacheFlags;
-    call_syscall(AFSCALL_CALL, AFSOP_CACHEINIT, (long)&cparams, 0, 0, 0);
-    if (afsd_CloseSynch)
-       call_syscall(AFSCALL_CALL, AFSOP_CLOSEWAIT, 0, 0, 0, 0);
+    code = uafs_ParseArgs(argc, argv);
+    usr_assert(code == 0);
 
-    /*
-     * Sweep the workstation AFS cache directory, remembering the inodes of
-     * valid files and deleting extraneous files.  Keep sweeping until we
-     * have the right number of data cache files or we've swept too many
-     * times.
-     */
-    if (afsd_verbose)
-       printf("%s: Sweeping workstation's AFS cache directory.\n", rn);
-    cacheIteration = 0;
-    /* Memory-cache based system doesn't need any of this */
-    if (!(cacheFlags & AFSCALL_INIT_MEMCACHE)) {
-       do {
-           cacheIteration++;
-           if (SweepAFSCache(&vFilesFound)) {
-               printf("%s: Error on sweep %d of workstation AFS cache \
-                      directory.\n", rn, cacheIteration);
-               exit(1);
-           }
-           if (afsd_verbose)
-               printf
-                   ("%s: %d out of %d data cache files found in sweep %d.\n",
-                    rn, vFilesFound, cacheFiles, cacheIteration);
-       } while ((vFilesFound < cacheFiles)
-                && (cacheIteration < MAX_CACHE_LOOPS));
-    } else if (afsd_verbose)
-       printf("%s: Using memory cache, not swept\n", rn);
-
-    /*
-     * Pass the kernel the name of the workstation cache file holding the 
-     * dcache entries.
-     */
-    if (afsd_debug)
-       printf("%s: Calling AFSOP_CACHEINFO: dcache file is '%s'\n", rn,
-              fullpn_DCacheFile);
-    /* once again, meaningless for a memory-based cache. */
-    if (!(cacheFlags & AFSCALL_INIT_MEMCACHE))
-       call_syscall(AFSCALL_CALL, AFSOP_CACHEINFO, (long)fullpn_DCacheFile,
-                    0, 0, 0);
-
-    call_syscall(AFSCALL_CALL, AFSOP_CELLINFO, (long)fullpn_CellInfoFile, 0,
-                0, 0);
-
-    /*
-     * Pass the kernel the name of the workstation cache file holding the
-     * volume information.
-     */
-    if (afsd_debug)
-       printf("%s: Calling AFSOP_VOLUMEINFO: volume info file is '%s'\n", rn,
-              fullpn_VolInfoFile);
-    call_syscall(AFSCALL_CALL, AFSOP_VOLUMEINFO, (long)fullpn_VolInfoFile, 0,
-                0, 0);
-
-    /*
-     * Pass the kernel the name of the afs logging file holding the volume
-     * information.
-     */
-    if (afsd_debug)
-       printf("%s: Calling AFSOP_AFSLOG: volume info file is '%s'\n", rn,
-              fullpn_AFSLogFile);
-    if (!(cacheFlags & AFSCALL_INIT_MEMCACHE)) /* ... nor this ... */
-       call_syscall(AFSCALL_CALL, AFSOP_AFSLOG, (long)fullpn_AFSLogFile, 0,
-                    0, 0);
-
-    /*
-     * Tell the kernel about each cell in the configuration.
-     */
-    afsconf_CellApply(afs_cdir, ConfigCell, NULL);
-    afsconf_CellAliasApply(afs_cdir, ConfigCellAlias, NULL);
+    for (i = 0; i < freeargc; i++) {
+       free(freeargv[i]);
+    }
 
-    if (afsd_verbose)
-       printf("%s: Forking AFS daemon.\n", rn);
-    fork_syscall(AFSCALL_CALL, AFSOP_START_AFS);
+    code = uafs_Run();
+    usr_assert(code == 0);
+}
 
-    if (afsd_verbose)
-       printf("%s: Forking check server daemon.\n", rn);
-    fork_syscall(AFSCALL_CALL, AFSOP_START_CS);
+/**
+ * Calculate the cacheMountDir used for a specified dir.
+ *
+ * @param[in]  dir      Desired mount dir
+ * @param[out] mountdir On success, contains the literal string that should
+ *                      be used as the cache mount dir.
+ * @param[in]  size     The number of bytes allocated in mountdir
+ *
+ * @post On success, mountdir begins with a slash, and does not contain two
+ * slashes adjacent to each other
+ *
+ * @return operation status
+ *  @retval 0 success
+ *  @retval ENAMETOOLONG the specified dir is too long to fix in the given
+ *                       mountdir buffer
+ *  @retval EINVAL the specified dir does not actually specify any meaningful
+ *                 mount directory
+ */
+static int
+calcMountDir(const char *dir, char *mountdir, size_t size)
+{
+    char buf[1024];
+    char lastchar;
+    char *p;
+    int len;
 
-    if (afsd_verbose)
-       printf("%s: Forking %d background daemons.\n", rn, nDaemons);
-    for (i = 0; i < nDaemons; i++) {
-       fork_syscall(AFSCALL_CALL, AFSOP_START_BKG);
+    if (dir && strlen(dir) > size-1) {
+       return ENAMETOOLONG;
     }
 
-    if (afsd_verbose)
-       printf("%s: Calling AFSOP_ROOTVOLUME with '%s'\n", rn, rootVolume);
-    call_syscall(AFSCALL_CALL, AFSOP_ROOTVOLUME, (long)rootVolume, 0, 0, 0);
-
     /*
-     * Give the kernel the names of the AFS files cached on the workstation's
-     * disk.
-     */
-    if (afsd_debug)
-       printf
-           ("%s: Calling AFSOP_CACHEFILES for each of the %d files in '%s'\n",
-            rn, cacheFiles, cacheBaseDir);
-    if (!(cacheFlags & AFSCALL_INIT_MEMCACHE)) /* ... and again ... */
-       for (currVFile = 0; currVFile < cacheFiles; currVFile++) {
-           call_syscall(AFSCALL_CALL, AFSOP_CACHEFILE,
-                        (long)pathname_for_V[currVFile], 0, 0, 0);
-       }
-    /*end for */
-#ifndef NETSCAPE_NSAPI
-    /*
-     * Copy our tokens from the kernel to the user space client
+     * Initialize the AFS mount point, default is '/afs'.
+     * Strip duplicate/trailing slashes from mount point string.
+     * afs_mountDirLen is set to strlen(afs_mountDir).
      */
-    for (i = 0; i < 200; i++) {
-       /*
-        * Get the i'th token from the kernel
-        */
-       memset((void *)&tbuffer[0], 0, sizeof(tbuffer));
-       memcpy((void *)&tbuffer[0], (void *)&i, sizeof(int));
-       iob.in = tbuffer;
-       iob.in_size = sizeof(int);
-       iob.out = tbuffer;
-       iob.out_size = sizeof(tbuffer);
-
-#if defined(AFS_USR_SUN5_ENV) || defined(AFS_USR_OSF_ENV) || defined(AFS_USR_HPUX_ENV) || defined(AFS_USR_LINUX22_ENV) || defined(AFS_USR_DARWIN_ENV) || defined(AFS_USR_FBSD_ENV)
-       rc = syscall(AFS_SYSCALL, AFSCALL_PIOCTL, 0, _VICEIOCTL(8), &iob, 0);
-#elif defined(AFS_USR_SGI_ENV)
-       rc = syscall(AFS_PIOCTL, 0, _VICEIOCTL(8), &iob, 0);
-#else /* AFS_USR_AIX_ENV */
-       rc = lpioctl(0, _VICEIOCTL(8), &iob, 0);
-#endif
-       if (rc < 0) {
-           usr_assert(errno == EDOM || errno == ENOSYS);
-           break;
-       }
-
-       /*
-        * Now pass the token into the user space kernel
-        */
-       rc = uafs_SetTokens(tbuffer, iob.out_size);
-       usr_assert(rc == 0);
+    if (!dir) {
+       dir = "afs";
     }
-#endif /* !NETSCAPE_NSAPI */
+    sprintf(buf, "%s", dir);
 
-    /*
-     * All the necessary info has been passed into the kernel to run an AFS
-     * system.  Give the kernel our go-ahead.
-     */
-    if (afsd_debug)
-       printf("%s: Calling AFSOP_GO\n", rn);
-    call_syscall(AFSCALL_CALL, AFSOP_GO, FALSE, 0, 0, 0);
+    mountdir[0] = '/';
+    len = 1;
+    for (lastchar = '/', p = &buf[0]; *p != '\0'; p++) {
+        if (lastchar != '/' || *p != '/') {
+            mountdir[len++] = lastchar = *p;
+        }
+    }
+    if (lastchar == '/' && len > 1)
+        len--;
+    mountdir[len] = '\0';
+    if (len <= 1) {
+       return EINVAL;
+    }
 
-    /*
-     * At this point, we have finished passing the kernel all the info 
-     * it needs to set up the AFS.  Mount the AFS root.
-     */
-    printf("%s: All AFS daemons started.\n", rn);
+    return 0;
+}
 
-    if (afsd_verbose)
-       printf("%s: Forking trunc-cache daemon.\n", rn);
-    fork_syscall(AFSCALL_CALL, AFSOP_START_TRUNCDAEMON);
+void
+uafs_mount(void) {
+    int rc;
 
     /*
      * Mount the AFS filesystem
@@ -1913,6 +1294,45 @@ uafs_Init(char *rn, char *mountDirParam, char *confDirParam,
 }
 
 void
+uafs_setMountDir(const char *dir)
+{
+    if (dir) {
+       int rc;
+       char tmp_mountDir[1024];
+
+       rc = calcMountDir(dir, tmp_mountDir, sizeof(tmp_mountDir));
+       if (rc) {
+           afs_warn("Invalid mount dir specification (error %d): %s\n", rc, dir);
+       } else {
+           if (strcmp(tmp_mountDir, afs_mountDir) != 0) {
+               /* mount dir changed */
+               strcpy(afs_mountDir, tmp_mountDir);
+               afs_mountDirLen = strlen(afs_mountDir);
+           }
+       }
+    }
+}
+
+int
+uafs_statvfs(struct statvfs *buf)
+{
+    int rc;
+
+    AFS_GLOCK();
+
+    rc = afs_statvfs(&afs_RootVfs, buf);
+
+    AFS_GUNLOCK();
+
+    if (rc) {
+       errno = rc;
+       return -1;
+    }
+
+    return 0;
+}
+
+void
 uafs_Shutdown(void)
 {
     int rc;
@@ -1920,7 +1340,9 @@ uafs_Shutdown(void)
     printf("\n");
 
     AFS_GLOCK();
-    VN_RELE(afs_CurrentDir);
+    if (afs_CurrentDir) {
+       VN_RELE(afs_CurrentDir);
+    }
     rc = afs_unmount(&afs_RootVfs);
     usr_assert(rc == 0);
     AFS_GUNLOCK();
@@ -1979,10 +1401,10 @@ syscallThread(void *argp)
     /*
      * AFS daemons run authenticated
      */
-    u.u_viceid = getuid();
-    crp = u.u_cred;
-    crp->cr_uid = getuid();
-    crp->cr_ruid = getuid();
+    get_user_struct()->u_viceid = getuid();
+    crp = get_user_struct()->u_cred;
+    afs_set_cr_uid(crp, getuid());
+    afs_set_cr_ruid(crp, getuid());
     crp->cr_suid = getuid();
     crp->cr_groups[0] = getgid();
     crp->cr_ngroups = 1;
@@ -1997,8 +1419,9 @@ syscallThread(void *argp)
     return 0;
 }
 
-fork_syscall(syscall, afscall, param1, param2, param3, param4)
-     long syscall, afscall, param1, param2, param3, param4;
+int
+fork_syscall(long syscall, long afscall, long param1, long param2,
+            long param3, long param4)
 {
     usr_thread_t tid;
     struct syscallThreadArgs *sysArgsP;
@@ -2018,8 +1441,9 @@ fork_syscall(syscall, afscall, param1, param2, param3, param4)
     return 0;
 }
 
-call_syscall(syscall, afscall, param1, param2, param3, param4)
-     long syscall, afscall, param1, param2, param3, param4;
+int
+call_syscall(long syscall, long afscall, long param1, long param2,
+            long param3, long param4)
 {
     int code = 0;
     struct a {
@@ -2038,14 +1462,58 @@ call_syscall(syscall, afscall, param1, param2, param3, param4)
     a.parm3 = param3;
     a.parm4 = param4;
 
-    u.u_error = 0;
-    u.u_ap = (char *)&a;
+    get_user_struct()->u_error = 0;
+    get_user_struct()->u_ap = (char *)&a;
 
     code = Afs_syscall();
     return code;
 }
 
 int
+uafs_Setup(const char *mount)
+{
+    int rc;
+    static int inited = 0;
+
+    if (inited) {
+       return EEXIST;
+    }
+    inited = 1;
+
+    rc = calcMountDir(mount, afs_mountDir, sizeof(afs_mountDir));
+    if (rc) {
+       return rc;
+    }
+    afs_mountDirLen = strlen(afs_mountDir);
+
+    /* initialize global vars and such */
+    osi_Init();
+
+    /* initialize cache manager foo */
+    afsd_init();
+
+    return 0;
+}
+
+int
+uafs_ParseArgs(int argc, char **argv)
+{
+    return afsd_parse(argc, argv);
+}
+
+int
+uafs_Run(void)
+{
+    return afsd_run();
+}
+
+const char *
+uafs_MountDir(void)
+{
+    return afsd_cacheMountDir;
+}
+
+int
 uafs_SetTokens(char *tbuffer, int tlen)
 {
     int rc;
@@ -2056,6 +1524,7 @@ uafs_SetTokens(char *tbuffer, int tlen)
     iob.in_size = tlen;
     iob.out = &outbuf[0];
     iob.out_size = sizeof(outbuf);
+
     rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(3), (long)&iob, 0, 0);
     if (rc != 0) {
        errno = rc;
@@ -2195,11 +1664,12 @@ int
 uafs_LookupName(char *path, struct usr_vnode *parentVp,
                struct usr_vnode **vpp, int follow, int no_eval_mtpt)
 {
-    int code;
+    int code = 0;
     int linkCount;
     struct usr_vnode *vp;
     struct usr_vnode *nextVp;
     struct usr_vnode *linkVp;
+    struct vcache *nextVc;
     char *tmpPath;
     char *pathP;
     char *nextPathP = NULL;
@@ -2258,7 +1728,7 @@ uafs_LookupName(char *path, struct usr_vnode *parentVp,
            /*
             * We need execute permission to search a directory
             */
-           code = afs_access(VTOAFS(vp), VEXEC, u.u_cred);
+           code = afs_access(VTOAFS(vp), VEXEC, get_user_struct()->u_cred);
            if (code != 0) {
                VN_RELE(vp);
                afs_osi_Free(tmpPath, strlen(path) + 1);
@@ -2269,17 +1739,16 @@ uafs_LookupName(char *path, struct usr_vnode *parentVp,
             * lookup the next component in the path, we can release the
             * subdirectory since we hold the global lock
             */
+           nextVc = NULL;
            nextVp = NULL;
-#ifdef AFS_WEB_ENHANCEMENTS
            if ((nextPathP != NULL && *nextPathP != '\0') || !no_eval_mtpt)
-               code = afs_lookup(vp, pathP, &nextVp, u.u_cred, 0);
+               code = afs_lookup(VTOAFS(vp), pathP, &nextVc, get_user_struct()->u_cred, 0);
            else
                code =
-                   afs_lookup(vp, pathP, &nextVp, u.u_cred,
+                   afs_lookup(VTOAFS(vp), pathP, &nextVc, get_user_struct()->u_cred,
                               AFS_LOOKUP_NOEVAL);
-#else
-           code = afs_lookup(vp, pathP, &nextVp, u.u_cred, 0);
-#endif /* AFS_WEB_ENHANCEMENTS */
+           if (nextVc)
+               nextVp=AFSTOV(nextVc);
            if (code != 0) {
                VN_RELE(vp);
                afs_osi_Free(tmpPath, strlen(path) + 1);
@@ -2369,7 +1838,7 @@ uafs_LookupLink(struct usr_vnode *vp, struct usr_vnode *parentVp,
     /*
      * Read the link data
      */
-    code = afs_readlink(vp, &uio, u.u_cred);
+    code = afs_readlink(VTOAFS(vp), &uio, get_user_struct()->u_cred);
     if (code) {
        afs_osi_Free(pathP, MAX_OSI_PATH + 1);
        return code;
@@ -2532,7 +2001,7 @@ uafs_mkdir_r(char *path, int mode)
     int code;
     char *nameP;
     struct vnode *parentP;
-    struct vnode *dirP;
+    struct vcache *dirP;
     struct usr_vattr attrs;
 
     if (uafs_IsRoot(path)) {
@@ -2570,16 +2039,16 @@ uafs_mkdir_r(char *path, int mode)
     usr_vattr_null(&attrs);
     attrs.va_type = VREG;
     attrs.va_mode = mode;
-    attrs.va_uid = u.u_cred->cr_uid;
-    attrs.va_gid = u.u_cred->cr_gid;
+    attrs.va_uid = afs_cr_uid(get_user_struct()->u_cred);
+    attrs.va_gid = afs_cr_gid(get_user_struct()->u_cred);
     dirP = NULL;
-    code = afs_mkdir(parentP, nameP, &attrs, &dirP, u.u_cred);
+    code = afs_mkdir(VTOAFS(parentP), nameP, &attrs, &dirP, get_user_struct()->u_cred);
     VN_RELE(parentP);
     if (code != 0) {
        errno = code;
        return -1;
     }
-    VN_RELE(dirP);
+    VN_RELE(AFSTOV(dirP));
     return 0;
 }
 
@@ -2669,8 +2138,8 @@ uafs_open_r(char *path, int flags, int mode)
            usr_vattr_null(&attrs);
            attrs.va_type = VREG;
            attrs.va_mode = mode;
-           attrs.va_uid = u.u_cred->cr_uid;
-           attrs.va_gid = u.u_cred->cr_gid;
+           attrs.va_uid = afs_cr_uid(get_user_struct()->u_cred);
+           attrs.va_gid = afs_cr_gid(get_user_struct()->u_cred);
            if (flags & O_TRUNC) {
                attrs.va_size = 0;
            }
@@ -2679,12 +2148,13 @@ uafs_open_r(char *path, int flags, int mode)
            code =
                afs_create(VTOAFS(dirP), nameP, &attrs,
                           (flags & O_EXCL) ? usr_EXCL : usr_NONEXCL, mode,
-                          &vc, u.u_cred);
+                          &vc, get_user_struct()->u_cred);
            VN_RELE(dirP);
            if (code != 0) {
                errno = code;
                return -1;
            }
+           fileP = AFSTOV(vc);
        } else {
            fileP = NULL;
            code = uafs_LookupName(nameP, dirP, &fileP, 1, 0);
@@ -2706,7 +2176,7 @@ uafs_open_r(char *path, int flags, int mode)
            }
            if (!fileMode)
                fileMode = VREAD;       /* since O_RDONLY is 0 */
-           code = afs_access(VTOAFS(fileP), fileMode, u.u_cred);
+           code = afs_access(VTOAFS(fileP), fileMode, get_user_struct()->u_cred);
            if (code != 0) {
                VN_RELE(fileP);
                errno = code;
@@ -2716,7 +2186,7 @@ uafs_open_r(char *path, int flags, int mode)
            /*
             * Get the file attributes, all we need is the size
             */
-           code = afs_getattr(VTOAFS(fileP), &attrs, u.u_cred);
+           code = afs_getattr(VTOAFS(fileP), &attrs, get_user_struct()->u_cred);
            if (code != 0) {
                VN_RELE(fileP);
                errno = code;
@@ -2757,8 +2227,9 @@ uafs_open_r(char *path, int flags, int mode)
      */
     if ((flags & O_TRUNC) && (attrs.va_size != 0)) {
        usr_vattr_null(&attrs);
+       attrs.va_mask = ATTR_SIZE;
        attrs.va_size = 0;
-       code = afs_setattr(VTOAFS(fileP), &attrs, u.u_cred);
+       code = afs_setattr(VTOAFS(fileP), &attrs, get_user_struct()->u_cred);
        if (code != 0) {
            VN_RELE(fileP);
            errno = code;
@@ -2770,7 +2241,7 @@ uafs_open_r(char *path, int flags, int mode)
     /*
      * do the open
      */
-    code = afs_open(&vc, openFlags, u.u_cred);
+    code = afs_open(&vc, openFlags, get_user_struct()->u_cred);
     if (code != 0) {
        VN_RELE(fileP);
        errno = code;
@@ -2828,13 +2299,23 @@ uafs_write(int fd, char *buf, int len)
 {
     int retval;
     AFS_GLOCK();
-    retval = uafs_write_r(fd, buf, len);
+    retval = uafs_pwrite_r(fd, buf, len, afs_FileOffsets[fd]);
     AFS_GUNLOCK();
     return retval;
 }
 
 int
-uafs_write_r(int fd, char *buf, int len)
+uafs_pwrite(int fd, char *buf, int len, off_t offset)
+{
+    int retval;
+    AFS_GLOCK();
+    retval = uafs_pwrite_r(fd, buf, len, offset);
+    AFS_GUNLOCK();
+    return retval;
+}
+
+int
+uafs_pwrite_r(int fd, char *buf, int len, off_t offset)
 {
     int code;
     struct usr_uio uio;
@@ -2857,7 +2338,7 @@ uafs_write_r(int fd, char *buf, int len)
     iov[0].iov_len = len;
     uio.uio_iov = &iov[0];
     uio.uio_iovcnt = 1;
-    uio.uio_offset = afs_FileOffsets[fd];
+    uio.uio_offset = offset;
     uio.uio_segflg = 0;
     uio.uio_fmode = FWRITE;
     uio.uio_resid = len;
@@ -2866,7 +2347,7 @@ uafs_write_r(int fd, char *buf, int len)
      * do the write
      */
 
-    code = afs_write(VTOAFS(fileP), &uio, afs_FileFlags[fd], u.u_cred, 0);
+    code = afs_write(VTOAFS(fileP), &uio, afs_FileFlags[fd], get_user_struct()->u_cred, 0);
     if (code) {
        errno = code;
        return -1;
@@ -2884,19 +2365,93 @@ uafs_read(int fd, char *buf, int len)
 {
     int retval;
     AFS_GLOCK();
-    retval = uafs_read_r(fd, buf, len);
+    retval = uafs_pread_r(fd, buf, len, afs_FileOffsets[fd]);
+    AFS_GUNLOCK();
+    return retval;
+}
+
+int
+uafs_pread_nocache(int fd, char *buf, int len, off_t offset)
+{
+    int retval;
+    AFS_GLOCK();
+    retval = uafs_pread_nocache_r(fd, buf, len, offset);
     AFS_GUNLOCK();
     return retval;
 }
 
 int
-uafs_read_r(int fd, char *buf, int len)
+uafs_pread_nocache_r(int fd, char *buf, int len, off_t offset)
+{
+    int code;
+    struct iovec iov[1];
+    struct usr_vnode *fileP;
+    struct nocache_read_request *bparms;
+    struct usr_uio uio;
+
+    /*
+     * Make sure this is an open file
+     */
+    fileP = afs_FileTable[fd];
+    if (fileP == NULL) {
+       errno = EBADF;
+       return -1;
+    }
+
+    /* these get freed in PrefetchNoCache, so... */
+    bparms = afs_osi_Alloc(sizeof(struct nocache_read_request));
+    bparms->areq = afs_osi_Alloc(sizeof(struct vrequest));
+
+    afs_InitReq(bparms->areq, get_user_struct()->u_cred);
+
+    bparms->auio = &uio;
+    bparms->offset = offset;
+    bparms->length = len;
+
+    /*
+     * set up the uio buffer
+     */
+    iov[0].iov_base = buf;
+    iov[0].iov_len = len;
+    uio.uio_iov = &iov[0];
+    uio.uio_iovcnt = 1;
+    uio.uio_offset = offset;
+    uio.uio_segflg = 0;
+    uio.uio_fmode = FREAD;
+    uio.uio_resid = len;
+
+    /*
+     * do the read
+     */
+    code = afs_PrefetchNoCache(VTOAFS(fileP), get_user_struct()->u_cred,
+                              bparms);
+
+    if (code) {
+       errno = code;
+       return -1;
+    }
+
+    afs_FileOffsets[fd] = uio.uio_offset;
+    return (len - uio.uio_resid);
+}
+
+int
+uafs_pread(int fd, char *buf, int len, off_t offset)
+{
+    int retval;
+    AFS_GLOCK();
+    retval = uafs_pread_r(fd, buf, len, offset);
+    AFS_GUNLOCK();
+    return retval;
+}
+
+int
+uafs_pread_r(int fd, char *buf, int len, off_t offset)
 {
     int code;
     struct usr_uio uio;
     struct iovec iov[1];
     struct usr_vnode *fileP;
-    struct usr_buf *bufP;
 
     /*
      * Make sure this is an open file
@@ -2914,7 +2469,7 @@ uafs_read_r(int fd, char *buf, int len)
     iov[0].iov_len = len;
     uio.uio_iov = &iov[0];
     uio.uio_iovcnt = 1;
-    uio.uio_offset = afs_FileOffsets[fd];
+    uio.uio_offset = offset;
     uio.uio_segflg = 0;
     uio.uio_fmode = FREAD;
     uio.uio_resid = len;
@@ -2922,7 +2477,7 @@ uafs_read_r(int fd, char *buf, int len)
     /*
      * do the read
      */
-    code = afs_read(VTOAFS(fileP), &uio, u.u_cred, 0, &bufP, 0);
+    code = afs_read(VTOAFS(fileP), &uio, get_user_struct()->u_cred, 0);
     if (code) {
        errno = code;
        return -1;
@@ -2948,7 +2503,7 @@ uafs_GetAttr(struct usr_vnode *vp, struct stat *stats)
     /*
      * Get the attributes
      */
-    code = afs_getattr(VTOAFS(vp), &attrs, u.u_cred);
+    code = afs_getattr(VTOAFS(vp), &attrs, get_user_struct()->u_cred);
     if (code != 0) {
        return code;
     }
@@ -2968,6 +2523,16 @@ uafs_GetAttr(struct usr_vnode *vp, struct stat *stats)
     stats->st_atime = attrs.va_atime.tv_sec;
     stats->st_mtime = attrs.va_mtime.tv_sec;
     stats->st_ctime = attrs.va_ctime.tv_sec;
+    /* preserve dv if possible */
+#if defined(HAVE_STRUCT_STAT_ST_CTIMESPEC)
+    stats->st_atimespec.tv_nsec = attrs.va_atime.tv_usec * 1000;
+    stats->st_mtimespec.tv_nsec = attrs.va_mtime.tv_usec * 1000;
+    stats->st_ctimespec.tv_nsec = attrs.va_ctime.tv_usec * 1000;
+#elif defined(HAVE_STRUCT_STAT_ST_CTIMENSEC)
+    stats->st_atimensec = attrs.va_atime.tv_usec * 1000;
+    stats->st_mtimensec = attrs.va_mtime.tv_usec * 1000;
+    stats->st_ctimensec = attrs.va_ctime.tv_usec * 1000;
+#endif
     stats->st_blksize = attrs.va_blocksize;
     stats->st_blocks = attrs.va_blocks;
 
@@ -3098,8 +2663,9 @@ uafs_chmod_r(char *path, int mode)
        return -1;
     }
     usr_vattr_null(&attrs);
+    attrs.va_mask = ATTR_MODE;
     attrs.va_mode = mode;
-    code = afs_setattr(VTOAFS(vp), &attrs, u.u_cred);
+    code = afs_setattr(VTOAFS(vp), &attrs, get_user_struct()->u_cred);
     VN_RELE(vp);
     if (code != 0) {
        errno = code;
@@ -3134,8 +2700,9 @@ uafs_fchmod_r(int fd, int mode)
        return -1;
     }
     usr_vattr_null(&attrs);
+    attrs.va_mask = ATTR_MODE;
     attrs.va_mode = mode;
-    code = afs_setattr(VTOAFS(vp), &attrs, u.u_cred);
+    code = afs_setattr(VTOAFS(vp), &attrs, get_user_struct()->u_cred);
     if (code != 0) {
        errno = code;
        return -1;
@@ -3169,8 +2736,9 @@ uafs_truncate_r(char *path, int length)
        return -1;
     }
     usr_vattr_null(&attrs);
+    attrs.va_mask = ATTR_SIZE;
     attrs.va_size = length;
-    code = afs_setattr(VTOAFS(vp), &attrs, u.u_cred);
+    code = afs_setattr(VTOAFS(vp), &attrs, get_user_struct()->u_cred);
     VN_RELE(vp);
     if (code != 0) {
        errno = code;
@@ -3205,8 +2773,9 @@ uafs_ftruncate_r(int fd, int length)
        return -1;
     }
     usr_vattr_null(&attrs);
+    attrs.va_mask = ATTR_SIZE;
     attrs.va_size = length;
-    code = afs_setattr(VTOAFS(vp), &attrs, u.u_cred);
+    code = afs_setattr(VTOAFS(vp), &attrs, get_user_struct()->u_cred);
     if (code != 0) {
        errno = code;
        return -1;
@@ -3248,7 +2817,7 @@ uafs_lseek_r(int fd, int offset, int whence)
        newpos = offset;
        break;
     case SEEK_END:
-       code = afs_getattr(VTOAFS(vp), &attrs, u.u_cred);
+       code = afs_getattr(VTOAFS(vp), &attrs, get_user_struct()->u_cred);
        if (code != 0) {
            errno = code;
            return -1;
@@ -3293,7 +2862,7 @@ uafs_fsync_r(int fd)
        return -1;
     }
 
-    code = afs_fsync(fileP, u.u_cred);
+    code = afs_fsync(VTOAFS(fileP), get_user_struct()->u_cred);
     if (code != 0) {
        errno = code;
        return -1;
@@ -3328,7 +2897,7 @@ uafs_close_r(int fd)
     }
     afs_FileTable[fd] = NULL;
 
-    code = afs_close(fileP, afs_FileFlags[fd], u.u_cred);
+    code = afs_close(VTOAFS(fileP), afs_FileFlags[fd], get_user_struct()->u_cred);
     VN_RELE(fileP);
     if (code != 0) {
        errno = code;
@@ -3403,7 +2972,7 @@ uafs_link_r(char *existing, char *new)
     /*
      * Create the link
      */
-    code = afs_link(existP, dirP, nameP, u.u_cred);
+    code = afs_link(VTOAFS(existP), VTOAFS(dirP), nameP, get_user_struct()->u_cred);
     VN_RELE(existP);
     VN_RELE(dirP);
     if (code != 0) {
@@ -3470,9 +3039,9 @@ uafs_symlink_r(char *target, char *source)
     usr_vattr_null(&attrs);
     attrs.va_type = VLNK;
     attrs.va_mode = 0777;
-    attrs.va_uid = u.u_cred->cr_uid;
-    attrs.va_gid = u.u_cred->cr_gid;
-    code = afs_symlink(dirP, nameP, &attrs, target, u.u_cred);
+    attrs.va_uid = afs_cr_uid(get_user_struct()->u_cred);
+    attrs.va_gid = afs_cr_gid(get_user_struct()->u_cred);
+    code = afs_symlink(VTOAFS(dirP), nameP, &attrs, target, get_user_struct()->u_cred);
     VN_RELE(dirP);
     if (code != 0) {
        errno = code;
@@ -3529,7 +3098,7 @@ uafs_readlink_r(char *path, char *buf, int len)
     /*
      * Read the the link
      */
-    code = afs_readlink(vp, &uio, u.u_cred);
+    code = afs_readlink(VTOAFS(vp), &uio, get_user_struct()->u_cred);
     VN_RELE(vp);
     if (code) {
        errno = code;
@@ -3560,8 +3129,6 @@ int
 uafs_unlink_r(char *path)
 {
     int code;
-    int openFlags;
-    struct usr_vnode *fileP;
     struct usr_vnode *dirP;
     char *nameP;
 
@@ -3597,7 +3164,7 @@ uafs_unlink_r(char *path)
     /*
      * Remove the file
      */
-    code = afs_remove(dirP, nameP, u.u_cred);
+    code = afs_remove(VTOAFS(dirP), nameP, get_user_struct()->u_cred);
     VN_RELE(dirP);
     if (code != 0) {
        errno = code;
@@ -3674,7 +3241,7 @@ uafs_rename_r(char *old, char *new)
     /*
      * Rename the file
      */
-    code = afs_rename(odirP, onameP, ndirP, nnameP, u.u_cred);
+    code = afs_rename(VTOAFS(odirP), onameP, VTOAFS(ndirP), nnameP, get_user_struct()->u_cred);
     VN_RELE(odirP);
     VN_RELE(ndirP);
     if (code != 0) {
@@ -3703,8 +3270,6 @@ int
 uafs_rmdir_r(char *path)
 {
     int code;
-    int openFlags;
-    struct usr_vnode *fileP;
     struct usr_vnode *dirP;
     char *nameP;
 
@@ -3740,7 +3305,7 @@ uafs_rmdir_r(char *path)
     /*
      * Remove the directory
      */
-    code = afs_rmdir(dirP, nameP, u.u_cred);
+    code = afs_rmdir(VTOAFS(dirP), nameP, get_user_struct()->u_cred);
     VN_RELE(dirP);
     if (code != 0) {
        errno = code;
@@ -3827,9 +3392,8 @@ uafs_opendir_r(char *path)
     /*
      * Set up the directory structures
      */
-    dirp =
-       (usr_DIR *) afs_osi_Alloc(sizeof(usr_DIR) + USR_DIRSIZE +
-                                 sizeof(struct usr_dirent));
+    dirp = afs_osi_Alloc(sizeof(usr_DIR) + USR_DIRSIZE +
+                        sizeof(struct usr_dirent));
     usr_assert(dirp != NULL);
     dirp->dd_buf = (char *)(dirp + 1);
     dirp->dd_fd = fd;
@@ -3888,7 +3452,7 @@ uafs_getdents_r(int fd, struct min_direct *buf, int len)
     /*
      * read the next chunk from the directory
      */
-    code = afs_readdir(vp, &uio, u.u_cred);
+    code = afs_readdir(VTOAFS(vp), &uio, get_user_struct()->u_cred);
     if (code != 0) {
        errno = code;
        return -1;
@@ -3914,7 +3478,6 @@ uafs_readdir(usr_DIR * dirp)
 struct usr_dirent *
 uafs_readdir_r(usr_DIR * dirp)
 {
-    int rc;
     int code;
     int len;
     struct usr_uio uio;
@@ -3923,6 +3486,11 @@ uafs_readdir_r(usr_DIR * dirp)
     struct usr_dirent *direntP;
     struct min_direct *directP;
 
+    if (!dirp) {
+       errno = EBADF;
+       return NULL;
+    }
+
     /*
      * Make sure this is an open file
      */
@@ -3953,7 +3521,7 @@ uafs_readdir_r(usr_DIR * dirp)
        /*
         * read the next chunk from the directory
         */
-       code = afs_readdir(vp, &uio, u.u_cred);
+       code = afs_readdir(VTOAFS(vp), &uio, get_user_struct()->u_cred);
        if (code != 0) {
            errno = code;
            return NULL;
@@ -4010,6 +3578,11 @@ uafs_closedir_r(usr_DIR * dirp)
     int fd;
     int rc;
 
+    if (!dirp) {
+       errno = EBADF;
+       return -1;
+    }
+
     fd = dirp->dd_fd;
     afs_osi_Free((char *)dirp,
                 sizeof(usr_DIR) + USR_DIRSIZE + sizeof(struct usr_dirent));
@@ -4018,34 +3591,6 @@ uafs_closedir_r(usr_DIR * dirp)
 }
 
 /*
- * Do AFS authentication
- */
-int
-uafs_klog(char *user, char *cell, char *passwd, char **reason)
-{
-    int code;
-    afs_int32 password_expires = -1;
-
-    usr_mutex_lock(&osi_authenticate_lock);
-    code =
-       ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION +
-                                  KA_USERAUTH_DOSETPAG2, user, NULL, cell,
-                                  passwd, 0, &password_expires, 0, reason);
-    usr_mutex_unlock(&osi_authenticate_lock);
-    return code;
-}
-
-int
-uafs_klog_r(char *user, char *cell, char *passwd, char **reason)
-{
-    int retval;
-    AFS_GUNLOCK();
-    retval = uafs_klog(user, cell, passwd, reason);
-    AFS_GLOCK();
-    return retval;
-}
-
-/*
  * Destroy AFS credentials from the kernel cache
  */
 int
@@ -4108,26 +3653,6 @@ uafs_afsPathName(char *path)
     return NULL;
 }
 
-#ifdef AFS_WEB_ENHANCEMENTS
-/*
- * uafs_klog_nopag
- * klog but don't allocate a new pag
- */
-int
-uafs_klog_nopag(char *user, char *cell, char *passwd, char **reason)
-{
-    int code;
-    afs_int32 password_expires = -1;
-
-    usr_mutex_lock(&osi_authenticate_lock);
-    code = ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION
-                                     /*+KA_USERAUTH_DOSETPAG2 */ , user,
-                                     NULL, cell, passwd, 0,
-                                     &password_expires, 0, reason);
-    usr_mutex_unlock(&osi_authenticate_lock);
-    return code;
-}
-
 /*
  * uafs_getcellstatus
  * get the cell status
@@ -4151,7 +3676,7 @@ uafs_getcellstatus(char *cell, afs_int32 * status)
        return -1;
     }
 
-    *status = (afs_int32) iob.out;
+    *status = (intptr_t)iob.out;
     return 0;
 }
 
@@ -4164,13 +3689,12 @@ uafs_getvolquota(char *path, afs_int32 * BlocksInUse, afs_int32 * MaxQuota)
 {
     int rc;
     struct afs_ioctl iob;
-    VolumeStatus *status;
-    char buf[1024];
+    VolumeStatus status;
 
     iob.in = 0;
     iob.in_size = 0;
-    iob.out = buf;
-    iob.out_size = 1024;
+    iob.out = (char *)&status;
+    iob.out_size = sizeof status;
 
     rc = call_syscall(AFSCALL_PIOCTL, (long)path, _VICEIOCTL(4), (long)&iob,
                      0, 0);
@@ -4180,9 +3704,8 @@ uafs_getvolquota(char *path, afs_int32 * BlocksInUse, afs_int32 * MaxQuota)
        return -1;
     }
 
-    status = (VolumeStatus *) buf;
-    *BlocksInUse = status->BlocksInUse;
-    *MaxQuota = status->MaxQuota;
+    *BlocksInUse = status.BlocksInUse;
+    *MaxQuota = status.MaxQuota;
     return 0;
 }
 
@@ -4195,18 +3718,15 @@ uafs_setvolquota(char *path, afs_int32 MaxQuota)
 {
     int rc;
     struct afs_ioctl iob;
-    VolumeStatus *status;
-    char buf[1024];
+    VolumeStatus status = { 0 };
 
-    iob.in = buf;
-    iob.in_size = 1024;
+    iob.in = (char *)&status;
+    iob.in_size = sizeof status;
     iob.out = 0;
     iob.out_size = 0;
 
-    memset(buf, 0, sizeof(VolumeStatus));
-    status = (VolumeStatus *) buf;
-    status->MaxQuota = MaxQuota;
-    status->MinQuota = -1;
+    status.MaxQuota = MaxQuota;
+    status.MinQuota = -1;
 
     rc = call_syscall(AFSCALL_PIOCTL, (long)path, _VICEIOCTL(5), (long)&iob,
                      0, 0);
@@ -4228,8 +3748,6 @@ int
 uafs_statmountpoint(char *path)
 {
     int retval;
-    int code;
-    char buf[256];
 
     AFS_GLOCK();
     retval = uafs_statmountpoint_r(path);
@@ -4243,7 +3761,6 @@ uafs_statmountpoint_r(char *path)
     int code;
     struct vnode *vp;
     struct vcache *avc;
-    struct vrequest treq;
     int r;
 
     code = uafs_LookupName(path, afs_CurrentDir, &vp, 0, 1);
@@ -4264,9 +3781,48 @@ uafs_statmountpoint_r(char *path)
  * Get a list of rights for the current user on path.
  */
 int
+uafs_access(char *path, int flags)
+{
+    int code;
+    struct vnode *vp;
+    int fileMode = 0;
+
+    if (flags & R_OK) {
+       fileMode |= VREAD;
+    }
+    if (flags & W_OK) {
+       fileMode |= VWRITE;
+    }
+    if (flags & X_OK) {
+       fileMode |= VEXEC;
+    }
+
+    AFS_GLOCK();
+    code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0);
+    if (code != 0) {
+       errno = code;
+       AFS_GUNLOCK();
+       return -1;
+    }
+
+    code = afs_access(VTOAFS(vp), fileMode, get_user_struct()->u_cred);
+    VN_RELE(vp);
+
+    if (code != 0)
+       errno = code;
+
+    AFS_GUNLOCK();
+    return code ? -1 : 0;
+}
+
+/*
+ * uafs_getRights
+ * Get a list of rights for the current user on path.
+ */
+int
 uafs_getRights(char *path)
 {
-    int code, rc;
+    int code;
     struct vnode *vp;
     int afs_rights;
 
@@ -4282,11 +3838,9 @@ uafs_getRights(char *path)
        PRSFS_READ | PRSFS_WRITE | PRSFS_INSERT | PRSFS_LOOKUP | PRSFS_DELETE
        | PRSFS_LOCK | PRSFS_ADMINISTER;
 
-    afs_rights = afs_getRights(vp, afs_rights, u.u_cred);
+    afs_rights = afs_getRights(VTOAFS(vp), afs_rights, get_user_struct()->u_cred);
 
     AFS_GUNLOCK();
     return afs_rights;
 }
-#endif /* AFS_WEB_ENHANCEMENTS */
-
 #endif /* UKERNEL */