sysname-list-instead-of-simple-name-20010605
authorTed McCabe <ted@mit.edu>
Tue, 5 Jun 2001 15:46:24 +0000 (15:46 +0000)
committerDerrick Brashear <shadow@dementia.org>
Tue, 5 Jun 2001 15:46:24 +0000 (15:46 +0000)
allow a sysname list which is interated in lookup instead of a simple
namespace

====================
This delta was composed from multiple commits as part of the CVS->Git migration.
The checkin message with each commit was inconsistent.
The following are the additional commit messages.
====================

remove bit which leaked in

src/afs/VNOPS/afs_vnop_lookup.c
src/afs/afs.h
src/afs/afs_init.c
src/afs/afs_pioctl.c
src/venus/fs.c

index 289c15b..93980d2 100644 (file)
@@ -40,6 +40,8 @@ extern afs_rwlock_t afs_xvcache;
 extern afs_rwlock_t afs_xcbhash;
 extern struct afs_exporter *afs_nfsexporter;
 extern char *afs_sysname;
+extern char *afs_sysnamelist[];
+extern int afs_sysnamecount;
 extern struct afs_q VLRU;                      /*vcache LRU*/
 #ifdef AFS_LINUX22_ENV
 extern struct inode_operations afs_symlink_iops, afs_dir_iops;
@@ -242,85 +244,82 @@ afs_ENameOK(aname)
     return 1;
 }
 
-Check_AtSys(avc, aname, outb, areq)
-    register struct vcache *avc;
-    char *aname, **outb;
-    struct vrequest *areq;
-{
-    register char *tname;
-    register int error = 0, offset = -1;
-
-    for (tname=aname; *tname; tname++) /*Move to the end of the string*/;
-
-    /*
-     * If the current string is 4 chars long or more, check to see if the
-     * tail end is "@sys".
-     */
-    if ((tname >= aname + 4) && (AFS_EQ_ATSYS(tname-4)))
-       offset = (tname - 4) - aname;
-    if (offset < 0) {
-       tname = aname;
-    }  else {
-       tname = (char *) osi_AllocLargeSpace(AFS_LRALLOCSIZ);
-       if (offset)
-           strncpy(tname, aname, offset);
-       if (!afs_nfsexporter) 
-           strcpy(tname+offset, (afs_sysname ? afs_sysname : SYS_NAME ));
-       else {
-           register struct unixuser *au;
-           register afs_int32 error;
-           au = afs_GetUser(areq->uid, avc->fid.Cell, 0); afs_PutUser(au, 0);  
-           if (au->exporter) {
-               error = EXP_SYSNAME(au->exporter, (char *)0, tname+offset);
-               if (error) 
-                   strcpy(tname+offset, "@sys");
-           } else {
-               strcpy(tname+offset, (afs_sysname ? afs_sysname : SYS_NAME ));
-           }
-       }
-       error = 1;
-    }
-    *outb = tname;
-    return error;
-}
-
-
-char *afs_getsysname(areq, adp)
+afs_getsysname(areq, adp, bufp)
     register struct vrequest *areq;
-    register struct vcache *adp; {
+    register struct vcache *adp;
+    register char *bufp;
+{
     static char sysname[MAXSYSNAME];
     register struct unixuser *au;
     register afs_int32 error;
 
+    if (!afs_nfsexporter) {
+      strcpy(bufp, afs_sysname);
+      return 0;
+    }
     AFS_STATCNT(getsysname);
-    /* this whole interface is wrong, it should take a buffer ptr and copy
-     * the data out.
-     */
     au = afs_GetUser(areq->uid, adp->fid.Cell, 0);
     afs_PutUser(au, 0);        
     if (au->exporter) {
-      error = EXP_SYSNAME(au->exporter, (char *)0, sysname);
-      if (error) return "@sys";
-      else return sysname;
+      error = EXP_SYSNAME(au->exporter, (char *)0, bufp);
+      if (error) 
+       strcpy(bufp, "@sys");
+      return -1;
     } else {
-      return (afs_sysname == 0? SYS_NAME : afs_sysname);
+      strcpy(bufp, afs_sysname);
+      return 0;
     }
 }
 
-void afs_HandleAtName(aname, aresult, areq, adp)
-    register char *aname;
-    register char *aresult;
-    register struct vrequest *areq;
-    register struct vcache *adp; {
-    register int tlen;
-    AFS_STATCNT(HandleAtName);
-    tlen = strlen(aname);
-    if (tlen >= 4 && strcmp(aname+tlen-4, "@sys")==0) {
-       strncpy(aresult, aname, tlen-4);
-       strcpy(aresult+tlen-4, afs_getsysname(areq, adp));
-    }
-    else strcpy(aresult, aname);
+Check_AtSys(avc, aname, state, areq)
+    register struct vcache *avc;
+    char *aname;
+    struct sysname_info *state;
+    struct vrequest *areq;
+{
+    if (AFS_EQ_ATSYS(aname)) {
+      state->offset = 0;
+      state->name = (char *) osi_AllocLargeSpace(AFS_SMALLOCSIZ);
+      state->allocked = 1;
+      state->index = afs_getsysname(areq, avc, state->name);
+    } else {
+      state->offset = -1;
+      state->allocked = 0;
+      state->index = 0;
+      state->name = aname;
     }
+}
+
+Next_AtSys(avc, areq, state)
+     register struct vcache *avc;
+     struct vrequest *areq;
+     struct sysname_info *state;
+{
+  if (state->index == -1)
+    return 0;  /* No list */
+
+  /* Check for the initial state of aname != "@sys" in Check_AtSys*/
+  if (state->offset == -1 && state->allocked == 0) {
+    register char *tname;
+    /* Check for .*@sys */
+      for (tname=state->name; *tname; tname++)
+       /*Move to the end of the string*/;
+      if ((tname > state->name + 4) && (AFS_EQ_ATSYS(tname-4))) {
+       state->offset = (tname - 4) - state->name;
+       tname = (char *) osi_AllocLargeSpace(AFS_LRALLOCSIZ);
+       strncpy(tname, state->name, state->offset);
+       state->name = tname;
+       state->allocked = 1;
+       state->index = afs_getsysname(areq, avc, state->name+state->offset);
+       return 1;
+      } else
+       return 0; /* .*@sys doesn't match either */
+  } else if (++(state->index) >= afs_sysnamecount
+            || !afs_sysnamelist[state->index])
+    return 0;  /* end of list */
+  strcpy(state->name+state->offset, afs_sysnamelist[state->index]);
+  return 1;
+}
 
 #if (defined(AFS_SGI62_ENV) || defined(AFS_SUN57_64BIT_ENV))
 extern int BlobScan(ino64_t *afile, afs_int32 ablob);
@@ -884,6 +883,7 @@ afs_lookup(adp, aname, avcp, acred)
     OSI_VC_CONVERT(adp)
     afs_hyper_t versionNo;
     int no_read_access = 0;
+    struct sysname_info sysState;   /* used only for @sys checking */
 
     AFS_STATCNT(afs_lookup);
 #ifdef AFS_OSF_ENV
@@ -898,39 +898,6 @@ afs_lookup(adp, aname, avcp, acred)
       goto done;
     }
 
-    /* lookup the name aname in the appropriate dir, and return a cache entry
-      on the resulting fid */
-
-    /*
-     * check for, and handle "@sys" if it's there.  We should be able
-     * to avoid the alloc and the strcpy with a little work, but it's
-     * not pressing.  If there aren't any remote users (ie, via the 
-     * NFS translator), we have a slightly easier job.
-     * the faster way to do this is to check for *aname == '@' and if 
-     * it's there, check for @sys, otherwise, assume there's no @sys 
-     * then, if the lookup fails, check for .*@sys...
-     */
-    if (!AFS_EQ_ATSYS(aname)) {
-      tname = aname;
-    }
-    else {
-       tname = (char *) osi_AllocLargeSpace(AFS_SMALLOCSIZ);
-       if (!afs_nfsexporter) 
-         strcpy(tname, (afs_sysname ? afs_sysname : SYS_NAME ));
-       else {
-         register struct unixuser *au;
-         register afs_int32 error;
-         au = afs_GetUser(treq.uid, adp->fid.Cell, 0); afs_PutUser(au, 0);     
-         if (au->exporter) {
-           error = EXP_SYSNAME(au->exporter, (char *)0, tname);
-           if (error) 
-             strcpy(tname, "@sys");
-         } else {
-             strcpy(tname, (afs_sysname ? afs_sysname : SYS_NAME ));
-         }
-       }
-      }
-
     /* come back to here if we encounter a non-existent object in a read-only
        volume's directory */
 
@@ -944,7 +911,7 @@ afs_lookup(adp, aname, avcp, acred)
     else code = 0;
 
     /* watch for ".." in a volume root */
-    if (adp->mvstat == 2 && tname[0] == '.' && tname[1] == '.' && !tname[2]) {
+    if (adp->mvstat == 2 && aname[0] == '.' && aname[1] == '.' && !aname[2]) {
        /* looking up ".." in root via special hacks */
        if (adp->mvid == (struct VenusFid *) 0 || adp->mvid->Fid.Volume == 0) {
 #ifdef AFS_OSF_ENV
@@ -1001,7 +968,7 @@ afs_lookup(adp, aname, avcp, acred)
      * I'm not fiddling with the LRUQ here, either, perhaps I should, or else 
      * invent a lightweight version of GetVCache.
      */
-    if (tname[0] == '.' && !tname[1]) { /* special case */
+    if (aname[0] == '.' && !aname[1]) { /* special case */
        ObtainReadLock(&afs_xvcache);   
        osi_vnhold(adp, 0);
        ReleaseReadLock(&afs_xvcache);  
@@ -1014,6 +981,16 @@ afs_lookup(adp, aname, avcp, acred)
       goto done;
     }
 
+    Check_AtSys(adp, aname, &sysState, &treq);
+    tname = sysState.name;
+
+    /* 1st Check_AtSys and lookup by tname is required here, for now,
+       because the dnlc is *not* told to remove entries for the parent
+       dir of file/dir op that afs_LocalHero likes, but dnlc is informed
+       if the cached entry for the parent dir is invalidated for a
+       non-local change.
+       Otherwise, we'd be able to do a dnlc lookup on an entry ending
+       w/@sys and know the dnlc was consistent with reality. */
     tvc = osi_dnlc_lookup (adp, tname, WRITE_LOCK);
     *avcp = tvc;  /* maybe wasn't initialized, but it is now */
     if (tvc) {
@@ -1057,7 +1034,6 @@ afs_lookup(adp, aname, avcp, acred)
 
     /* now we will just call dir package with appropriate inode.
       Dirs are always fetched in their entirety for now */
-    /* If the first lookup doesn't succeed, maybe it's got @sys in the name */
     ObtainReadLock(&adp->lock);
 
     /*
@@ -1084,17 +1060,28 @@ afs_lookup(adp, aname, avcp, acred)
     /* Save the version number for when we call osi_dnlc_enter */
     hset(versionNo, tdc->f.versionNo);
 
+    /*
+     * check for, and handle "@sys" if it's there.  We should be able
+     * to avoid the alloc and the strcpy with a little work, but it's
+     * not pressing.  If there aren't any remote users (ie, via the 
+     * NFS translator), we have a slightly easier job.
+     * the faster way to do this is to check for *aname == '@' and if 
+     * it's there, check for @sys, otherwise, assume there's no @sys 
+     * then, if the lookup fails, check for .*@sys...
+     */
+    /* above now implemented by Check_AtSys and Next_AtSys */
+
+    /* lookup the name in the appropriate dir, and return a cache entry
+       on the resulting fid */
     theDir = tdc->f.inode;
-    code = afs_dir_LookupOffset(&theDir, tname, &tfid.Fid, &dirCookie);
-    if (code == ENOENT && tname == aname) {
-      int len;
-      len = strlen(aname);
-      if (len >= 4 && AFS_EQ_ATSYS(aname+len-4)) {
-       tname = (char *) osi_AllocLargeSpace(AFS_LRALLOCSIZ);
-       afs_HandleAtName(aname, tname, &treq, adp);
-       code = afs_dir_LookupOffset(&theDir, tname, &tfid.Fid, &dirCookie);
-      }
+    code = afs_dir_LookupOffset(&theDir, sysState.name, &tfid.Fid, &dirCookie);
+
+    /* If the first lookup doesn't succeed, maybe it's got @sys in the name */
+    while (code == ENOENT && Next_AtSys(adp, &treq, &sysState)) {
+      code = afs_dir_LookupOffset(&theDir, sysState.name, &tfid.Fid, &dirCookie);
     }
+    tname = sysState.name;
+
     ReleaseReadLock(&adp->lock);
     afs_PutDCache(tdc);
 
index 8a957a6..121ccd5 100644 (file)
@@ -63,6 +63,7 @@ extern int afs_shuttingdown;
 #define        PIGGYSIZE       1350        /* max piggyback size */
 #define        MAXVOLS         128         /* max vols we can store */
 #define        MAXSYSNAME      128         /* max sysname (i.e. @sys) size */
+#define MAXNUMSYSNAMES 16          /* max that current constants allow */
 #define        NOTOKTIMEOUT    (2*3600)    /* time after which to timeout conns sans tokens */
 #define        NOPAG           0xffffffff
 #define AFS_NCBRS      300         /* max # of call back return entries */
@@ -74,6 +75,11 @@ extern int afs_shuttingdown;
 #define        AFS_RXDEADTIME  50
 #define AFS_HARDDEADTIME        120
 
+struct sysname_info {
+  char *name;
+  short offset;
+  char index, allocked;
+};
 
 /* flags to use with AFSOP_CACHEINIT */
 #define AFSCALL_INIT_MEMCACHE        0x1         /* use a memory-based cache */
index 6276984..482bf92 100644 (file)
@@ -108,6 +108,8 @@ struct vfs *afs_cacheVfsp=0;
 afs_rwlock_t afs_puttofileLock; /* not used */
 char *afs_sysname = 0;                 /* So that superuser may change the
                                         * local value of @sys */
+char *afs_sysnamelist[MAXNUMSYSNAMES]; /* For support of a list of sysname */
+int afs_sysnamecount = 0;
 struct volume *Initialafs_freeVolList;
 int afs_memvolumes = 0;
 
@@ -525,8 +527,11 @@ afs_ResourceInit(preallocs)
        afs_resourceinit_flag = 1;
        for (i=0;i<NFENTRIES;i++)
            fvTable[i] = 0;
-       afs_sysname = afs_osi_Alloc(MAXSYSNAME);
+       for(i=0;i<MAXNUMSYSNAMES;i++)
+         afs_sysnamelist[i] = afs_osi_Alloc(MAXSYSNAME);
+       afs_sysname = afs_sysnamelist[0];
        strcpy(afs_sysname, SYS_NAME);
+       afs_sysnamecount = 1;
        QInit(&CellLRU);        
 #if    defined(AFS_AIX32_ENV) || defined(AFS_HPUX_ENV)
     {  extern afs_int32 afs_preallocs;
@@ -837,8 +842,10 @@ void shutdown_AFS()
       for (i=0; i<NFENTRIES; i++)
        fvTable[i] = 0;
       /* Reinitialize local globals to defaults */
-      afs_osi_Free(afs_sysname, MAXSYSNAME);
+      for(i=0; i<MAXNUMSYSNAMES; i++)
+       afs_osi_Free(afs_sysnamelist[i], MAXSYSNAME);
       afs_sysname = 0;
+      afs_sysnamecount = 0;
       afs_marinerHost = 0;
       QInit(&CellLRU);      
       afs_setTimeHost = (struct server *)0;
index 62dae24..9d3b466 100644 (file)
@@ -1664,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;
@@ -1676,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;
@@ -1717,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;
 }
 
@@ -2341,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;
@@ -2362,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;
@@ -2446,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;    
 }
 
@@ -2676,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;
@@ -2691,9 +2698,11 @@ 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);
@@ -2709,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;
     }
@@ -2738,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;
     }
@@ -3498,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;
@@ -3510,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;
@@ -3556,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;
 }
 
index 9de42c6..2fdaf07 100644 (file)
@@ -2085,29 +2085,33 @@ static SysNameCmd(as)
     struct ViceIoctl blob;
     struct cmd_item *ti;
     char *input = space;
-    afs_int32 setp = 1;
+    afs_int32 setp = 0;
 
     ti = as->parms[0].items;
-    if (!ti) setp = 0;
     blob.in = space;
     blob.out = space;
     blob.out_size = MAXSIZE;
     blob.in_size = sizeof(afs_int32);
-    bcopy(&setp, input, sizeof(afs_int32));
     input += sizeof(afs_int32);
-    if (ti) {
-       strcpy(input, ti->data);
+    for(; ti; ti=ti->next) {
+       setp++;
        blob.in_size += strlen(ti->data) + 1;
+       if (blob.in_size > MAXSIZE) {
+         fprintf(stderr, "%s: sysname%s too long.\n", pn, setp > 1 ? "s" : "");
+         return 1;
+       }
+       strcpy(input, ti->data);
        input += strlen(ti->data);
        *(input++) = '\0';
     }
+    bcopy(&setp, space, sizeof(afs_int32));
     code = pioctl(0, VIOC_AFS_SYSNAME, &blob, 1);
     if (code) {
        Die(errno, 0);
        return 1;
     }
     if (setp) {
-       printf("%s: new sysname set.\n", pn);
+       printf("%s: new sysname%s set.\n", pn, setp > 1 ? " list" : "");
        return 0;
     }
     input = space;
@@ -2117,7 +2121,12 @@ static SysNameCmd(as)
        fprintf(stderr, "No sysname name value was found\n");
        return 1;
     }
-    printf("Current sysname is '%s'\n", input);
+    printf("Current sysname%s is:", setp>1 ? " list" : "");
+    for(;setp>0;--setp) {
+      printf(" %s", input);
+      input += strlen(input) + 1;
+    }
+    printf("\n");
     return 0;
 }
 
@@ -3024,7 +3033,7 @@ defect 3069
     cmd_AddParm(ts, "-path", CMD_LIST, CMD_OPTIONAL, "dir/file path");
 
     ts = cmd_CreateSyntax("sysname", SysNameCmd, 0, "get/set sysname (i.e. @sys) value");
-    cmd_AddParm(ts, "-newsys", CMD_SINGLE, CMD_OPTIONAL, "new sysname");
+    cmd_AddParm(ts, "-newsys", CMD_LIST, CMD_OPTIONAL, "new sysname");
 
     ts = cmd_CreateSyntax("exportafs", ExportAfsCmd, 0, "enable/disable translators to AFS");
     cmd_AddParm(ts, "-type", CMD_SINGLE, 0, "exporter name");