sysname-list-instead-of-simple-name-20010605
[openafs.git] / src / afs / afs_pioctl.c
index 314f617..9d3b466 100644 (file)
@@ -61,6 +61,7 @@ static int PSetSPrefs33(), PStoreBehind(), PGCPAGs();
 static int PGetCPrefs(), PSetCPrefs(); /* client network addresses */
 static int PGetInitParams(), PFlushMount(), PRxStatProc(), PRxStatPeer();
 static int PGetRxkcrypt(), PSetRxkcrypt();
+static int PPrefetchFromTape(), PResidencyCmd();
 int PExportAfs();
 
 static int HandleClientContext(struct afs_ioctl *ablob, int *com, struct AFS_UCRED **acred, struct AFS_UCRED *credp);
@@ -134,6 +135,8 @@ static int (*(pioctlSw[]))() = {
   PNoop,                       /* 63 -- arla: print xfs status */
   PNoop,                       /* 64 -- arla: force cache check */
   PNoop,                       /* 65 -- arla: break callback */
+  PPrefetchFromTape,            /* 66 -- MR-AFS: prefetch file from tape */
+  PResidencyCmd,                /* 67 -- MR-AFS: generic commnd interface */
 };
 
 #define PSetClientContext 99   /*  Special pioctl to setup caller's creds  */
@@ -193,14 +196,15 @@ copyin_afs_ioctl(caddr_t cmarg, struct afs_ioctl *dst)
        }
 #endif /* defined(AFS_SGI_ENV) && (_MIPS_SZLONG==64) */
 
-#if defined(AFS_LINUX_64BIT_KERNEL)
+#if defined(AFS_LINUX_64BIT_KERNEL) && !defined(AFS_ALPHA_LINUX20_ENV)
        struct afs_ioctl32 dst32;
 
 #ifdef AFS_SPARC64_LINUX20_ENV
-       if (current->tss.flags & SPARC_FLAG_32BIT) {
+       if (current->tss.flags & SPARC_FLAG_32BIT) 
 #else
 #error Not done for this linux type
-#endif
+#endif /* AFS_SPARC64_LINUX20_ENV */
+         {
                AFS_COPYIN(cmarg, (caddr_t) &dst32, sizeof dst32, code);
                if (!code)
                        afs_ioctl32_to_afs_ioctl(&dst32, dst);
@@ -377,6 +381,18 @@ afs_xioctl (p, args, retval)
         caddr_t arg;
     } *uap = (struct a *)args;
 #else /* AFS_OSF_ENV */
+#ifdef AFS_DARWIN_ENV
+struct ioctl_args {
+        int fd;
+        u_long com;
+        caddr_t arg;
+};
+afs_xioctl(p, uap, retval) 
+        struct proc *p; 
+        register struct ioctl_args *uap;
+        register_t *retval;
+{
+#else
 #ifdef AFS_LINUX22_ENV
 struct afs_ioctl_sys {
     unsigned int com;
@@ -395,11 +411,12 @@ afs_xioctl ()
        caddr_t arg;
       } *uap = (struct a *)u.u_ap;
 #endif /* AFS_LINUX22_ENV */
+#endif /* AFS_DARWIN_ENV */
 #endif /* AFS_OSF_ENV */
 #endif /* AFS_SUN5_ENV */
 #endif
 #ifndef AFS_LINUX22_ENV
-#if    defined(AFS_AIX32_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV)
+#if    defined(AFS_AIX32_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV)
       struct file *fd;
 #else
       register struct file *fd;
@@ -409,6 +426,10 @@ afs_xioctl ()
       register int ioctlDone = 0, code = 0;
       
       AFS_STATCNT(afs_xioctl);
+#ifdef AFS_DARWIN_ENV
+        if ((code=fdgetf(p, uap->fd, &fd)))
+           return code;
+#else
 #ifdef AFS_LINUX22_ENV
     ua.com = com;
     ua.arg = arg;
@@ -445,6 +466,7 @@ afs_xioctl ()
 #endif
 #endif
 #endif
+#endif
       
       /* first determine whether this is any sort of vnode */
 #ifdef AFS_LINUX22_ENV
@@ -480,6 +502,9 @@ afs_xioctl ()
            if (code) {
              osi_FreeSmallSpace(datap);
              AFS_GUNLOCK();
+#ifdef AFS_DARWIN_ENV
+              return code;
+#else 
 #if    defined(AFS_SUN5_ENV)
 #ifdef AFS_SUN54_ENV
              releasef(uap->fd);
@@ -507,6 +532,7 @@ afs_xioctl ()
 #endif
 #endif
 #endif
+#endif
            }
            code = HandleIoctl(tvc, uap->com, datap);
            osi_FreeSmallSpace(datap);
@@ -549,6 +575,9 @@ afs_xioctl ()
 #endif
           code = ioctl(uap, rvp);
 #else
+#if defined(AFS_DARWIN_ENV)
+        return ioctl(p, uap, retval);
+#else
 #ifdef  AFS_OSF_ENV
          code = ioctl(p, args, retval);
 #ifdef AFS_OSF30_ENV
@@ -565,6 +594,7 @@ afs_xioctl ()
 #endif
 #endif
 #endif
+#endif
       }
 #ifdef AFS_SUN5_ENV
       if (ioctlDone)
@@ -578,7 +608,7 @@ afs_xioctl ()
 #ifdef AFS_LINUX22_ENV
       return -code;
 #else
-#if    !defined(AFS_OSF_ENV)
+#if    !defined(AFS_OSF_ENV) && !defined(AFS_DARWIN_ENV)
       if (!getuerror())
          setuerror(code);
 #if    defined(AFS_AIX32_ENV) && !defined(AFS_AIX41_ENV)
@@ -589,7 +619,7 @@ afs_xioctl ()
 #endif
 #endif /* AFS_LINUX22_ENV */
 #endif /* AFS_SUN5_ENV */
-#ifdef AFS_OSF_ENV
+#if defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV)
       return (code);
 #endif
     }
@@ -641,8 +671,28 @@ afs_pioctl(p, args, retval)
 
 extern struct mount *afs_globalVFS;
 #else  /* AFS_OSF_ENV */
+#ifdef AFS_DARWIN_ENV
+afs_pioctl(p, args, retval)
+        struct proc *p;
+        void *args;
+        int *retval;
+{
+    struct a {
+        char    *path;
+        int     cmd;
+        caddr_t cmarg;
+        int     follow; 
+    } *uap = (struct a *) args;
+    
+    AFS_STATCNT(afs_pioctl);
+    return (afs_syscall_pioctl(uap->path, uap->cmd, uap->cmarg, uap->follow, p->p_cred->pc_ucred));
+}   
+
+extern struct mount *afs_globalVFS;
+#else   /* AFS_OSF_ENV */
 extern struct vfs *afs_globalVFS;
 #endif
+#endif
 
 /* macro to avoid adding any more #ifdef's to pioctl code. */
 #if defined(AFS_LINUX22_ENV) || defined(AFS_AIX41_ENV)
@@ -656,10 +706,15 @@ afs_syscall_pioctl(path, com, cmarg, follow, rvp, credp)
     rval_t *rvp;
     struct AFS_UCRED *credp;
 #else
+#ifdef AFS_DARWIN_ENV
+afs_syscall_pioctl(path, com, cmarg, follow, credp)
+    struct AFS_UCRED *credp;
+#else
 afs_syscall_pioctl(path, com, cmarg, follow)
 #endif
+#endif
     char *path;
-    int        com;
+    unsigned int       com;
     caddr_t cmarg;
     int        follow;
 {
@@ -682,7 +737,7 @@ afs_syscall_pioctl(path, com, cmarg, follow)
 #ifndef        AFS_SUN5_ENV
     if (! _VALIDVICEIOCTL(com)) {
        PIOCTL_FREE_CRED();
-#ifdef AFS_OSF_ENV
+#if defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV)
         return EINVAL;
 #else  /* AFS_OSF_ENV */
 #if defined(AFS_SGI64_ENV) || defined(AFS_LINUX22_ENV)
@@ -697,7 +752,7 @@ afs_syscall_pioctl(path, com, cmarg, follow)
     code = copyin_afs_ioctl(cmarg, &data);
     if (code) {
        PIOCTL_FREE_CRED();
-#if    defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SGI64_ENV) || defined(AFS_LINUX22_ENV)
+#if    defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SGI64_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV)
        return (code);
 #else
        setuerror(code);
@@ -705,9 +760,9 @@ afs_syscall_pioctl(path, com, cmarg, follow)
 #endif
   }
     if ((com & 0xff) == PSetClientContext) {
-#ifdef AFS_LINUX22_ENV
+#if defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV)
        return EINVAL; /* Not handling these yet. */
-#endif
+#else
 #if    defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV)
        code = HandleClientContext(&data, &com, &foreigncreds, credp);
 #else
@@ -721,19 +776,20 @@ afs_syscall_pioctl(path, com, cmarg, follow)
 #endif /* AFS_SGI_ENV */
 #endif
 #endif
+#endif
       if (code) {
          if (foreigncreds) {
              crfree(foreigncreds);
          }
          PIOCTL_FREE_CRED();
-#if    defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SGI64_ENV) || defined(AFS_LINUX22_ENV)
+#if    defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SGI64_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV)
          return (code);
 #else
          return (setuerror(code), code);
 #endif
       }
     } 
-#ifndef AFS_LINUX22_ENV
+#if !defined(AFS_LINUX22_ENV) && !defined(AFS_DARWIN_ENV)
     if (foreigncreds) {
       /*
        * We could have done without temporary setting the u.u_cred below
@@ -770,7 +826,7 @@ afs_syscall_pioctl(path, com, cmarg, follow)
     if ((com & 0xff) == 15) {
       /* special case prefetch so entire pathname eval occurs in helper process.
         otherwise, the pioctl call is essentially useless */
-#if    defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV)
+#if    defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV)
        code =  Prefetch(path, &data, follow,
                         foreigncreds ? foreigncreds : credp);
 #else
@@ -784,7 +840,7 @@ afs_syscall_pioctl(path, com, cmarg, follow)
 #endif /* AFS_SGI64_ENV */
 #endif /* AFS_HPUX101_ENV */
 #endif
-#ifndef AFS_LINUX22_ENV
+#if !defined(AFS_LINUX22_ENV) && !defined(AFS_DARWIN_ENV)
        if (foreigncreds) {
 #ifdef AFS_AIX41_ENV
            crset(tmpcred);     /* restore original credentials */
@@ -805,7 +861,7 @@ afs_syscall_pioctl(path, com, cmarg, follow)
        }
 #endif /* AFS_LINUX22_ENV */
        PIOCTL_FREE_CRED();
-#if    defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SGI64_ENV) || defined(AFS_LINUX22_ENV)
+#if    defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SGI64_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV)
        return (code);
 #else
        return (setuerror(code), code);
@@ -827,7 +883,7 @@ afs_syscall_pioctl(path, com, cmarg, follow)
 #endif /* AFS_AIX41_ENV */
        AFS_GLOCK();
        if (code) {
-#ifndef AFS_LINUX22_ENV
+#if !defined(AFS_LINUX22_ENV) && !defined(AFS_DARWIN_ENV)
            if (foreigncreds) {
 #ifdef AFS_AIX41_ENV
                crset(tmpcred); /* restore original credentials */
@@ -848,7 +904,7 @@ afs_syscall_pioctl(path, com, cmarg, follow)
            }
 #endif /* AFS_LINUX22_ENV */
            PIOCTL_FREE_CRED();
-#if    defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SGI64_ENV) || defined(AFS_LINUX22_ENV)
+#if    defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SGI64_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV)
            return (code);
 #else
            return(setuerror(code), code);
@@ -903,7 +959,7 @@ afs_syscall_pioctl(path, com, cmarg, follow)
       code = afs_HandlePioctl(vp, com, &data, follow, &credp);
       }
 #else
-#ifdef AFS_LINUX22_ENV
+#if defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV)
       code = afs_HandlePioctl(vp, com, &data, follow, &credp);
 #else
       code = afs_HandlePioctl(vp, com, &data, follow, &u.u_cred);
@@ -913,7 +969,7 @@ afs_syscall_pioctl(path, com, cmarg, follow)
 #endif /* AFS_AIX41_ENV */
 #endif /* AFS_SUN5_ENV */
     } else {
-#if    defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SGI64_ENV) || defined(AFS_LINUX22_ENV)
+#if    defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SGI64_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV)
        code = EINVAL;  /* not in /afs */
 #else
        setuerror(EINVAL);
@@ -926,7 +982,7 @@ afs_syscall_pioctl(path, com, cmarg, follow)
 #endif
     }
 
-#ifndef AFS_LINUX22_ENV
+#if !defined(AFS_LINUX22_ENV) && !defined(AFS_DARWIN_ENV)
     if (foreigncreds) {
 #ifdef AFS_AIX41_ENV
        crset(tmpcred);
@@ -954,7 +1010,7 @@ afs_syscall_pioctl(path, com, cmarg, follow)
 #endif
     }
     PIOCTL_FREE_CRED();
-#if    defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SGI64_ENV) || defined(AFS_LINUX22_ENV)
+#if    defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SGI64_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV)
     return (code);
 #else
     if (!getuerror())  
@@ -1365,11 +1421,18 @@ static PGCPAGs(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
     afs_PutCell(tcell, READ_LOCK);
     if (set_parent_pag) {
        int pag;
+#ifdef AFS_DARWIN_ENV
+        struct proc *p=current_proc(); /* XXX */
+        uprintf("Process %d (%s) tried to change pags in PSetTokens\n",
+                p->p_pid, p->p_comm);
+        if (!setpag(p, acred, -1, &pag, 1)) {
+#else   
 #ifdef AFS_OSF_ENV
        if (!setpag(u.u_procp, acred, -1, &pag, 1)) {   /* XXX u.u_procp is a no-op XXX */
 #else
        if (!setpag(acred, -1, &pag, 1)) {
 #endif
+#endif
            afs_InitReq(&treq, *acred);
            areq = &treq;
        }
@@ -1499,10 +1562,16 @@ static PSetVolumeStatus(avc, afun, areq, ain, aout, ainSize, aoutSize)
     cp = ain;
     bcopy(cp, (char *)&volstat, sizeof(AFSFetchVolumeStatus));
     cp += sizeof(AFSFetchVolumeStatus);
+    if (strlen(cp) >= sizeof(volName))
+       return E2BIG;
     strcpy(volName, cp);
     cp += strlen(volName)+1;
+    if (strlen(cp) >= sizeof(offLineMsg))
+       return E2BIG;
     strcpy(offLineMsg, cp);
     cp +=  strlen(offLineMsg)+1;
+    if (strlen(cp) >= sizeof(motd))
+       return E2BIG;
     strcpy(motd, cp);
     storeStat.Mask = 0;
     if (volstat.MinQuota != -1) {
@@ -1595,8 +1664,9 @@ static PNewStatMount(avc, afun, areq, ain, aout, ainSize, aoutSize)
     register struct vcache *tvc;
     register struct dcache *tdc;
     struct VenusFid tfid;
-    char *bufp = 0;
-    afs_int32 offset, len, hasatsys=0;
+    char *bufp;
+    struct sysname_info sysState;
+    afs_int32 offset, len;
 
     AFS_STATCNT(PNewStatMount);
     if (!avc) return EINVAL;
@@ -1607,8 +1677,11 @@ static PNewStatMount(avc, afun, areq, ain, aout, ainSize, aoutSize)
     }
     tdc = afs_GetDCache(avc, 0, areq, &offset, &len, 1);
     if (!tdc) return ENOENT;
-    hasatsys = Check_AtSys(avc, ain, &bufp, areq);
-    code = afs_dir_Lookup(&tdc->f.inode, bufp, &tfid.Fid);
+    Check_AtSys(avc, ain, &sysState, areq);
+    do {
+      code = afs_dir_Lookup(&tdc->f.inode, sysState.name, &tfid.Fid);
+    } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
+    bufp = sysState.name;
     if (code) {
        afs_PutDCache(tdc);
        goto out;
@@ -1648,7 +1721,7 @@ static PNewStatMount(avc, afun, areq, ain, aout, ainSize, aoutSize)
     ReleaseWriteLock(&tvc->lock);
     afs_PutVCache(tvc, WRITE_LOCK);
 out:
-    if (hasatsys) osi_FreeLargeSpace(bufp);
+    if (sysState.allocked) osi_FreeLargeSpace(bufp);
     return code;
 }
 
@@ -1776,6 +1849,13 @@ static PUnlog(avc, afun, areq, ain, aout, ainSize, aoutSize)
            afs_ResetUserConns(tu);
            tu->refCount--;
            ObtainWriteLock(&afs_xuser,228);
+#ifdef UKERNEL
+            /* set the expire times to 0, causes
+             * afs_GCUserData to remove this entry
+             */
+            tu->ct.EndTimestamp = 0;
+            tu->tokenTime = 0;
+#endif  /* UKERNEL */
        }
     }
     ReleaseWriteLock(&afs_xuser);
@@ -1966,7 +2046,11 @@ struct AFS_UCRED *acred;
 {
     register char *tp;
     register afs_int32 code;
+#if defined(AFS_SGI61_ENV) || defined(AFS_SUN57_ENV) || defined(AFS_DARWIN_ENV)
+    size_t bufferSize;
+#else
     u_int bufferSize;
+#endif
 
     AFS_STATCNT(Prefetch);
     if (!apath) return EINVAL;
@@ -2204,7 +2288,7 @@ static PNewCell(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
     }
 
     linkedstate |= CNoSUID; /* setuid is disabled by default for fs newcell */
-    code = afs_NewCell(newcell, cellHosts, linkedstate, linkedcell, fsport, vlport);
+    code = afs_NewCell(newcell, cellHosts, linkedstate, linkedcell, fsport, vlport, (int)0);
     return code;
 }
 
@@ -2261,8 +2345,9 @@ static PRemoveMount(avc, afun, areq, ain, aout, ainSize, aoutSize)
     afs_int32 ainSize;
     afs_int32 *aoutSize;       /* set this */ {
     register afs_int32 code;
-    char *bufp = 0;
-    afs_int32 offset, len, hasatsys = 0;
+    char *bufp;
+    struct sysname_info sysState;
+    afs_int32 offset, len;
     register struct conn *tc;
     register struct dcache *tdc;
     register struct vcache *tvc;
@@ -2282,8 +2367,11 @@ static PRemoveMount(avc, afun, areq, ain, aout, ainSize, aoutSize)
 
     tdc        = afs_GetDCache(avc, 0, areq, &offset,  &len, 1);       /* test for error below */
     if (!tdc) return ENOENT;
-    hasatsys = Check_AtSys(avc, ain, &bufp, areq);
-    code = afs_dir_Lookup(&tdc->f.inode, bufp, &tfid.Fid);
+    Check_AtSys(avc, ain, &sysState, areq);
+    do {
+      code = afs_dir_Lookup(&tdc->f.inode, sysState.name, &tfid.Fid);
+    } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
+    bufp = sysState.name;
     if (code) {
        afs_PutDCache(tdc);
        goto out;
@@ -2366,7 +2454,7 @@ static PRemoveMount(avc, afun, areq, ain, aout, ainSize, aoutSize)
     ReleaseWriteLock(&avc->lock);
     code = 0;
 out:
-    if (hasatsys) osi_FreeLargeSpace(bufp);
+    if (sysState.allocked) osi_FreeLargeSpace(bufp);
     return code;    
 }
 
@@ -2468,8 +2556,12 @@ struct AFS_UCRED *acred;
 #if    defined(AFS_SGI_ENV) || defined(AFS_ALPHA_ENV)  || defined(AFS_SUN5_ENV)  || defined(AFS_HPUX_ENV)
                VN_HOLD((struct vnode *)tvc);
 #else
+#if defined(AFS_DARWIN_ENV)
+               osi_vnhold(tvc, 0);
+#else
                tvc->vrefCount++;
 #endif
+#endif
                ReleaseReadLock(&afs_xvcache);
 #if    defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
                afs_BozonLock(&tvc->pvnLock, tvc);      /* Since afs_TryToSmush will do a pvn_vptrunc */
@@ -2592,7 +2684,6 @@ static PGetVnodeXStatus(avc, afun, areq, ain, aout, ainSize, aoutSize)
 /* (since we don't really believe remote uids anyway) */
  /* outname[] shouldn't really be needed- this is left as an excercise */
  /* for the reader.  */
-
 static PSetSysName(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
 struct vcache *avc;
 int afun;
@@ -2607,15 +2698,17 @@ register struct AFS_UCRED *acred;
     register struct afs_exporter *exporter;
     extern struct unixuser *afs_FindUser();
     extern char *afs_sysname;
+    extern char *afs_sysnamelist[];
+    extern int afs_sysnamecount;
     register struct unixuser *au;
     register afs_int32 pag, error;
-    int t;
+    int t, count;
 
 
     AFS_STATCNT(PSetSysName);
     if (!afs_globalVFS) {
       /* Afsd is NOT running; disable it */
-#if    defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SGI64_ENV) || defined(AFS_LINUX22_ENV)
+#if    defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SGI64_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV)
        return (EINVAL);
 #else
        return (setuerror(EINVAL), EINVAL);
@@ -2625,9 +2718,24 @@ register struct AFS_UCRED *acred;
     bcopy(ain, (char *)&setsysname, sizeof(afs_int32));
     ain += sizeof(afs_int32);
     if (setsysname) {
-      t = strlen(ain);
-      if (t > MAXSYSNAME)
+
+      /* Check my args */
+      if (setsysname < 0 || setsysname > MAXNUMSYSNAMES)
        return EINVAL;
+      for(cp = ain,count = 0;count < setsysname;count++) {
+       /* won't go past end of ain since maxsysname*num < ain length */
+       t = strlen(cp);
+       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)))
+         return EINVAL;
+       cp += t+1;
+      }
+      /* args ok */
+
+      /* inname gets first entry in case we're being a translater */
+      t = strlen(ain);
       bcopy(ain, inname, t+1);  /* include terminating null */
       ain += t + 1;
     }
@@ -2654,23 +2762,50 @@ register struct AFS_UCRED *acred;
        else foundname = 1;
        afs_PutUser(au, READ_LOCK);
     } else {
+
+      /* Not xlating, so local case */
        if (!afs_sysname) osi_Panic("PSetSysName: !afs_sysname\n");
-       if (!setsysname) {
+       if (!setsysname) {      /* user just wants the info */
            strcpy(outname, afs_sysname);
-           foundname = 1;
-       } else {
-           if (!afs_osi_suser(acred))     /* Local guy; only root can change sysname */
+           foundname = afs_sysnamecount;
+       } else {     /* Local guy; only root can change sysname */
+           if (!afs_osi_suser(acred))
                return EACCES;
+          
+           /* 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, ... */
            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);
+               bcopy(cp, afs_sysnamelist[count], t+1); /* include null */
+               cp += t+1;
+             }
+           }
+           afs_sysnamecount = setsysname;
        }
     }
     if (!setsysname) {
-       cp = aout;
+       cp = aout;  /* not changing so report back the count and ... */
        bcopy((char *)&foundname, cp, sizeof(afs_int32));
        cp += sizeof(afs_int32);
        if (foundname) {
-           strcpy(cp, outname);
+           strcpy(cp, outname);                /* ... the entry, ... */
            cp += strlen(outname)+1;
+           for(count=1; count < foundname; ++count) { /* ... or list. */
+             /* Note: we don't support @sys lists for exporters */
+             if (!afs_sysnamelist[count])
+               osi_Panic("PSetSysName: no afs_sysnamelist entry to read\n");
+             t = strlen(afs_sysnamelist[count]);
+             if (t >= MAXSYSNAME)
+               osi_Panic("PSetSysName: sysname entry garbled\n");
+             strcpy(cp, afs_sysnamelist[count]);
+             cp += t + 1;
+           }
        }
        *aoutSize = cp - aout;
     }
@@ -3414,8 +3549,9 @@ static PFlushMount(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
     register struct vcache *tvc;
     register struct dcache *tdc;
     struct VenusFid tfid;
-    char *bufp = 0;
-    afs_int32 offset, len, hasatsys=0;
+    char *bufp;
+    struct sysname_info sysState;
+    afs_int32 offset, len;
 
     AFS_STATCNT(PFlushMount);
     if (!avc) return EINVAL;
@@ -3426,8 +3562,11 @@ static PFlushMount(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
     }
     tdc = afs_GetDCache(avc, 0, areq, &offset, &len, 1);
     if (!tdc) return ENOENT;
-    hasatsys = Check_AtSys(avc, ain, &bufp, areq);
-    code = afs_dir_Lookup(&tdc->f.inode, bufp, &tfid.Fid);
+    Check_AtSys(avc, ain, &sysState, areq);
+    do {
+      code = afs_dir_Lookup(&tdc->f.inode, sysState.name, &tfid.Fid);
+    } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
+    bufp = sysState.name;
     if (code) {
        afs_PutDCache(tdc);
        goto out;
@@ -3472,7 +3611,7 @@ static PFlushMount(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
 #endif
     afs_PutVCache(tvc, WRITE_LOCK);
 out:
-    if (hasatsys) osi_FreeLargeSpace(bufp);
+    if (sysState.allocked) osi_FreeLargeSpace(bufp);
     return code;
 }
 
@@ -3555,3 +3694,163 @@ out:
     return code;
 }
 
+static PPrefetchFromTape(avc, afun, areq, ain, aout, ainSize, aoutSize)
+  struct vcache *avc;
+  int afun;
+  struct vrequest *areq;
+  char *ain, *aout;
+  afs_int32 ainSize;
+  afs_int32 *aoutSize;  /* set this */
+{
+    register afs_int32 code, code1;
+    afs_int32 bytes;
+    struct conn *tc;
+    struct rx_call *tcall;
+    struct AFSVolSync tsync;
+    struct AFSFetchStatus OutStatus;
+    struct AFSCallBack CallBack;
+    struct VenusFid tfid;
+    struct AFSFid *Fid;
+    struct vcache *tvc;
+    XSTATS_DECLS;
+
+    AFS_STATCNT(PSetAcl);
+    if (!avc)
+      return EINVAL;
+
+    if (ain && (ainSize == 3 * sizeof(afs_int32)))
+        Fid = (struct AFSFid *) ain;
+    else
+        Fid = &avc->fid.Fid;
+    tfid.Cell = avc->fid.Cell;
+    tfid.Fid.Volume = Fid->Volume;
+    tfid.Fid.Vnode = Fid->Vnode;
+    tfid.Fid.Unique = Fid->Unique;
+
+    tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0, (struct vcache *)0,
+                                WRITE_LOCK);
+    if (!tvc) {
+        afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD,
+                ICL_TYPE_POINTER, tvc,
+                ICL_TYPE_FID, &tfid,
+                ICL_TYPE_FID, &avc->fid);
+        return ENOENT;
+    }
+    afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD,
+                ICL_TYPE_POINTER, tvc,
+                ICL_TYPE_FID, &tfid,
+                ICL_TYPE_FID, &tvc->fid);
+
+    do {
+        tc = afs_Conn(&tvc->fid, areq, SHARED_LOCK);
+        if (tc) {
+
+#ifdef RX_ENABLE_LOCKS
+            AFS_GUNLOCK();
+#endif /* RX_ENABLE_LOCKS */
+            tcall = rx_NewCall(tc->id);
+            code = StartRXAFS_FetchData(tcall,
+                                (struct AFSFid *) &tvc->fid.Fid, 0, 0);
+            if (!code) {
+                bytes = rx_Read(tcall, (char *) aout, sizeof(afs_int32));
+                code = EndRXAFS_FetchData(tcall, &OutStatus, &CallBack, &tsync);
+            }
+            code1 = rx_EndCall(tcall, code);
+#ifdef RX_ENABLE_LOCKS
+            AFS_GLOCK();
+#endif /* RX_ENABLE_LOCKS */
+        } else
+            code = -1;
+    } while
+        (afs_Analyze(tc, code, &tvc->fid, areq, 
+               AFS_STATS_FS_RPCIDX_RESIDENCYRPCS, SHARED_LOCK, 
+               (struct cell *)0));
+    /* This call is done only to have the callback things handled correctly */
+    afs_FetchStatus(tvc, &tfid, areq, &OutStatus);
+    afs_PutVCache(tvc, WRITE_LOCK);
+
+    if (!code) {
+        *aoutSize = sizeof(afs_int32);
+    }
+    return code;
+}
+
+static PResidencyCmd(avc, afun, areq, ain, aout, ainSize, aoutSize)
+struct vcache *avc;
+int afun;
+struct vrequest *areq;
+char *ain, *aout;
+afs_int32 ainSize;
+afs_int32 *aoutSize;        /* set this */
+{
+    register afs_int32 code;
+    struct conn *tc;
+    struct vcache *tvc;
+    struct ResidencyCmdInputs *Inputs;
+    struct ResidencyCmdOutputs *Outputs;
+    struct VenusFid tfid;
+    struct AFSFid *Fid;
+
+    Inputs = (struct ResidencyCmdInputs *) ain;
+    Outputs = (struct ResidencyCmdOutputs *) aout;
+    if (!avc) return EINVAL;
+    if (!ain || ainSize != sizeof(struct ResidencyCmdInputs)) return EINVAL;
+
+    Fid = &Inputs->fid;
+    if (!Fid->Volume)
+        Fid = &avc->fid.Fid;
+
+    tfid.Cell = avc->fid.Cell;
+    tfid.Fid.Volume = Fid->Volume;
+    tfid.Fid.Vnode = Fid->Vnode;
+    tfid.Fid.Unique = Fid->Unique;
+
+    tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0, (struct vcache *)0,
+                                WRITE_LOCK);
+    afs_Trace3(afs_iclSetp, CM_TRACE_RESIDCMD,
+                ICL_TYPE_POINTER, tvc,
+                ICL_TYPE_INT32, Inputs->command,
+                ICL_TYPE_FID, &tfid);
+    if (!tvc)
+        return ENOENT;
+
+    if (Inputs->command) {
+        do {
+            tc = afs_Conn(&tvc->fid, areq, SHARED_LOCK);
+            if (tc) {
+#ifdef RX_ENABLE_LOCKS
+                AFS_GUNLOCK();
+#endif /* RX_ENABLE_LOCKS */
+                code = RXAFS_ResidencyCmd(tc->id, Fid,
+                                 Inputs,
+                                 (struct ResidencyCmdOutputs *) aout);
+#ifdef RX_ENABLE_LOCKS
+                AFS_GLOCK();
+#endif /* RX_ENABLE_LOCKS */
+            } else
+                code = -1;
+        } while
+          (afs_Analyze(tc, code, &tvc->fid, areq, 
+               AFS_STATS_FS_RPCIDX_RESIDENCYRPCS, SHARED_LOCK,
+                (struct cell *)0));
+       /* 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 */
+        code = 0;
+        Outputs->code = afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
+        Outputs->chars[0] = 0;
+        if (vType(tvc) == VLNK) {
+            ObtainWriteLock(&tvc->lock,555);
+            if (afs_HandleLink(tvc, areq) == 0)
+                strncpy((char *) &Outputs->chars, tvc->linkData, MAXCMDCHARS);
+            ReleaseWriteLock(&tvc->lock);
+        }
+    }
+
+    afs_PutVCache(tvc, WRITE_LOCK);
+
+    if (!code) {
+        *aoutSize = sizeof(struct ResidencyCmdOutputs);
+    }
+    return code;
+}