dynroot-allow-cell-aliases-20011101
authorNickolai Zeldovich <kolya@mit.edu>
Thu, 1 Nov 2001 05:24:30 +0000 (05:24 +0000)
committerDerrick Brashear <shadow@dementia.org>
Thu, 1 Nov 2001 05:24:30 +0000 (05:24 +0000)
allow cell aliases. includes support for non-'V' pioctls

19 files changed:
NEWS
src/afs/IRIX/osi_vfsops.c
src/afs/VNOPS/afs_vnop_remove.c
src/afs/VNOPS/afs_vnop_symlink.c
src/afs/afs.h
src/afs/afs_call.c
src/afs/afs_cell.c
src/afs/afs_dynroot.c
src/afs/afs_osi_vget.c
src/afs/afs_pioctl.c
src/afsd/afsd.c
src/auth/cellconfig.c
src/auth/cellconfig.p.h
src/config/afs_args.h
src/config/venus.h
src/util/dirpath.c
src/util/dirpath.hin
src/util/vice.h
src/venus/fs.c

diff --git a/NEWS b/NEWS
index a805cee..535c528 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,11 @@
-OpenAFS News -- history of user-visible changes. October 13, 2001
+OpenAFS News -- history of user-visible changes. October 19, 2001
+
+* Changes incorporated in OpenAFS 1.2.3
+
+** Cell aliases for dynroot can be specified in the CellAlias file in
+   /usr/vice/etc or /usr/local/etc/openafs, in format "realname alias",
+   one per line.  They can also be managed at runtime with "fs newalias"
+   and "fs listaliases".
 
 * Changes incorporated in OpenAFS 1.2.2
 
index 7d3e74a..93d3bd0 100644 (file)
@@ -537,7 +537,7 @@ afs_vget(OSI_VFS_DECL(afsp), vnode_t **avcp, struct fid *fidp)
     afid2 = (afs_fid2_t*)fidp;
     if (afid2->af_len == sizeof(afs_fid2_t) - sizeof(afid2->af_len)) {
        /* It's a checkpoint restart fid. */
-       tcell = afs_GetCellByIndex(afid2->af_cell, READ_LOCK);
+       tcell = afs_GetCellByIndex(afid2->af_cell, READ_LOCK, 0 /* !refresh */);
        if (!tcell) {
            code = ENOENT;
            goto out;
index fe2cf69..375f9cc 100644 (file)
@@ -232,6 +232,10 @@ afs_remove(OSI_VC_ARG(adp), aname, acred)
     afs_Trace2(afs_iclSetp, CM_TRACE_REMOVE, ICL_TYPE_POINTER, adp,
               ICL_TYPE_STRING, aname);
 
+    /* Check if this is dynroot */
+    if (afs_IsDynroot(adp))
+       return afs_DynrootVOPRemove(adp, acred, aname);
+
     if (code = afs_InitReq(&treq, acred))
       return code;
 tagain:
index 72f0d6e..64edc41 100644 (file)
@@ -78,6 +78,10 @@ afs_symlink
     AFS_STATCNT(afs_symlink);
     afs_Trace2(afs_iclSetp, CM_TRACE_SYMLINK, ICL_TYPE_POINTER, adp,
                 ICL_TYPE_STRING, aname);
+
+    if (afs_IsDynroot(adp))
+       return afs_DynrootVOPSymlink(adp, acred, aname, atargetName);
+
     if (code = afs_InitReq(&treq, acred))
        return code;
 
index d37fe87..bd6bf5b 100644 (file)
@@ -200,7 +200,7 @@ struct cell {
     short states;                          /* state flags */
     short cellIndex;                       /* relative index number per cell */
     time_t timeout;                        /* data expire time, if non-zero */
-    struct cell *alias;                            /* what this cell is an alias for */
+    char *realName;                        /* who this cell is an alias for */
 };
 
 #define        afs_PutCell(cellp, locktype)
@@ -967,6 +967,7 @@ extern struct brequest afs_brs[NBRS];               /* request structures */
 
 extern struct cell         *afs_GetCell();
 extern struct cell         *afs_GetCellByName();
+extern struct cell         *afs_GetCellByName2();
 extern struct cell         *afs_GetCellByIndex();
 extern struct unixuser     *afs_GetUser();
 extern struct volume       *afs_GetVolume();
@@ -1010,6 +1011,8 @@ extern void afs_PutDynroot();
 extern int afs_DynrootNewVnode();
 extern int afs_SetDynrootEnable();
 extern int afs_GetDynrootEnable();
+extern int afs_DynrootVOPSymlink();
+extern int afs_DynrootVOPRemove();
 
 
 /* Performance hack - we could replace VerifyVCache2 with the appropriate
index f4e029a..8054de5 100644 (file)
@@ -326,6 +326,33 @@ long parm, parm2, parm3, parm4, parm5, parm6;
        osi_FreeSmallSpace(tbuffer);
        osi_FreeSmallSpace(tbuffer1);
     }
+    else if (parm == AFSOP_ADDCELLALIAS) {
+       /*
+        * Call arguments:
+        * parm2 is the alias name
+        * parm3 is the real cell name
+        */
+#if defined(AFS_SGI61_ENV) || defined(AFS_SUN57_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
+       size_t bufferSize;
+#else /* AFS_SGI61_ENV */
+       u_int bufferSize;       
+#endif /* AFS_SGI61_ENV */
+       char *aliasName = osi_AllocSmallSpace(AFS_SMALLOCSIZ);
+       char *cellName = osi_AllocSmallSpace(AFS_SMALLOCSIZ);
+
+       AFS_COPYINSTR((char *)parm2, aliasName, AFS_SMALLOCSIZ, &bufferSize, code);
+       if (!code) AFS_COPYINSTR((char *)parm3, cellName, AFS_SMALLOCSIZ, &bufferSize, code);
+       if (!code) afs_NewCell(aliasName,       /* new entry name */
+                              0,               /* host list */
+                              CAlias,          /* flags */
+                              (char *) 0,      /* linked cell */
+                              0, 0,            /* fs & vl ports */
+                              0,               /* timeout */
+                              cellName);       /* real cell name */
+
+       osi_FreeSmallSpace(aliasName);
+       osi_FreeSmallSpace(cellName);
+    }
     else if (parm == AFSOP_CACHEINIT) {
        struct afs_cacheParams cparms;
 
index add7e60..5870679 100644 (file)
@@ -78,7 +78,7 @@ char afs_AfsdbHandler_ReqPending = 0;
 char afs_AfsdbHandler_Completed = 0;
 
 
-static struct cell *afs_GetCellByName_int();
+struct cell *afs_GetCellByName2();
 
 int afs_strcasecmp(s1, s2)
     register char *s1, *s2;
@@ -271,7 +271,7 @@ struct cell *afs_GetCellByName_Dns(acellName, locktype)
 
     if (realName)
        afs_osi_Free(realName, strlen(realName) + 1);
-    return afs_GetCellByName_int(acellName, locktype, 0);
+    return afs_GetCellByName2(acellName, locktype, 0);
 
 bad:
     if (realName)
@@ -280,15 +280,17 @@ bad:
 }
 
 
-static struct cell *afs_GetCellByName_int(acellName, locktype, trydns)
+struct cell *afs_GetCellByName2(acellName, locktype, trydns)
     register char *acellName;
     afs_int32 locktype;
     char trydns;
 {
     register struct cell *tc;
     register struct afs_q *cq, *tq;
+    int didAlias = 0;
 
     AFS_STATCNT(afs_GetCellByName);
+retry:
     ObtainWriteLock(&afs_xcell,100);
     for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
        tc = QTOC(cq); tq = QNext(cq);
@@ -297,9 +299,11 @@ static struct cell *afs_GetCellByName_int(acellName, locktype, trydns)
            QAdd(&CellLRU, &tc->lruq);
            ReleaseWriteLock(&afs_xcell);
            afs_RefreshCell(tc);
-           if (tc->states & CAlias) {
-               tc = tc->alias;
-               afs_RefreshCell(tc);
+           if ((tc->states & CAlias) && (didAlias == 0)) {
+               acellName = tc->realName;
+               if (!acellName) return (struct cell *) 0;
+               didAlias = 1;
+               goto retry;
            }
            return tc;
        }
@@ -308,14 +312,14 @@ static struct cell *afs_GetCellByName_int(acellName, locktype, trydns)
     return trydns ? afs_GetCellByName_Dns(acellName, locktype)
                  : (struct cell *) 0;
 
-} /*afs_GetCellByName_int*/
+} /*afs_GetCellByName2*/
 
 
 struct cell *afs_GetCellByName(acellName, locktype)
     register char *acellName;
     afs_int32 locktype;
 {
-    return afs_GetCellByName_int(acellName, locktype, 1);
+    return afs_GetCellByName2(acellName, locktype, 1);
 
 } /*afs_GetCellByName*/
 
@@ -346,9 +350,10 @@ struct cell *afs_GetCell(acell, locktype)
 } /*afs_GetCell*/
 
 
-struct cell *afs_GetCellByIndex(cellindex, locktype)
+struct cell *afs_GetCellByIndex(cellindex, locktype, refresh)
     register afs_int32 cellindex;
     afs_int32 locktype;
+    afs_int32 refresh;
 {
     register struct cell *tc;
     register struct afs_q *cq, *tq;
@@ -361,7 +366,7 @@ struct cell *afs_GetCellByIndex(cellindex, locktype)
            QRemove(&tc->lruq);
            QAdd(&CellLRU, &tc->lruq);
            ReleaseWriteLock(&afs_xcell);
-           afs_RefreshCell(tc);
+           if (refresh) afs_RefreshCell(tc);
            return tc;
        }
     }
@@ -419,6 +424,7 @@ afs_int32 afs_NewCell(acellName, acellHosts, aflags, linkedcname, fsport, vlport
     }
     else {
        tc = (struct cell *) afs_osi_Alloc(sizeof(struct cell));
+       memset((char *)tc, 0, sizeof(*tc));
        QAdd(&CellLRU, &tc->lruq);                      /* put in lruq */
        tc->cellName = (char *) afs_osi_Alloc(strlen(acellName)+1);
        strcpy(tc->cellName, acellName);
@@ -464,25 +470,19 @@ afs_int32 afs_NewCell(acellName, acellHosts, aflags, linkedcname, fsport, vlport
     }
     tc->states |= aflags;
     tc->timeout = timeout;
+
+    /* Allow converting an alias into a real cell */
+    if (!(aflags & CAlias)) tc->states &= ~CAlias;
  
     memset((char *)tc->cellHosts, 0, sizeof(tc->cellHosts));
     if (aflags & CAlias) {
-       struct cell *tca = NULL;
-
        if (!aliasFor) {
            code = EINVAL;
            goto bad;
        }
-       for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
-           tca = QTOC(cq); tq = QNext(cq);
-           if (!afs_strcasecmp(tca->cellName, aliasFor))
-               break;
-       }
-       if (!tca) {
-           code = ENOENT;
-           goto bad;
-       }
-       tc->alias = tca;
+       if (tc->realName) afs_osi_Free(tc->realName, strlen(tc->realName)+1);
+       tc->realName = (char *) afs_osi_Alloc(strlen(aliasFor)+1);
+       strcpy(tc->realName, aliasFor);
        goto done;
     }
 
index 6e42e2b..bba3d42 100644 (file)
@@ -20,6 +20,8 @@
  * afs_DynrootNewVnode
  * afs_SetDynrootEnable
  * afs_GetDynrootEnable
+ * afs_DynrootVOPRemove
+ * afs_DynrootVOPSymlink
  *
  */
 
 #define AFS_DYNROOT_VNODE      1
 #define AFS_DYNROOT_UNIQUE     1
 
-#define VNUM2CIDX(vnum)                ((vnum) >> 2)
-#define VNUM2RW(vnum)          (((vnum) >> 1) & 1)
-#define CIDXRW2VNUM(cidx, rw)  (((cidx) << 2) | ((rw) << 1))
+/*
+ * Vnode numbers in dynroot are composed of a type field (upper 8 bits)
+ * and a type-specific identifier in the lower 24 bits.
+ */
+#define VN_TYPE_CELL           0x01    /* Corresponds to a struct cell */
+#define VN_TYPE_SYMLINK                0x02    /* User-created symlink in /afs */
+
+#define VNUM_TO_VNTYPE(vnum)   ((vnum) >> 24)
+#define VNUM_TO_VNID(vnum)     ((vnum) & 0x00ffffff)
+#define VNUM_FROM_TYPEID(type, id) \
+                               ((type) << 24 | (id))
+#define VNUM_TO_CIDX(vnum)     (VNUM_TO_VNID(vnum) >> 2)
+#define VNUM_TO_RW(vnum)       (VNUM_TO_VNID(vnum) >> 1 & 1)
+#define VNUM_FROM_CIDX_RW(cidx, rw) \
+                               VNUM_FROM_TYPEID(VN_TYPE_CELL, \
+                                                ((cidx) << 2 | (rw) << 1))
 
 static int afs_dynrootEnable = 0;
 
@@ -57,6 +72,20 @@ static int afs_dynrootVersion = 1;
 static int afs_dynrootVersionHigh = 1;
 /* End of variables protected by afs_dynrootDirLock */
 
+/* A dynamically-created symlink in a dynroot /afs */
+struct afs_dynSymlink {
+    struct afs_dynSymlink *next;
+    int index;
+    char *name;
+    char *target;
+};
+
+static afs_rwlock_t afs_dynSymlinkLock;
+/* Start of variables protected by afs_dynSymlinkLock */
+static struct afs_dynSymlink *afs_dynSymlinkBase = NULL;
+static int afs_dynSymlinkIndex = 0;
+/* End of variables protected by afs_dynSymlinkLock */
+
 extern afs_int32 afs_cellindex;
 extern afs_rwlock_t afs_xvcache;
 
@@ -178,13 +207,15 @@ afs_RefreshDynroot()
     int cellidx, maxcellidx, i;
     struct cell *c;
     int curChunk, curPage;
-    int dirSize;
+    int dirSize, sizeOfCurEntry;
     char *newDir, *dotCell;
     struct DirHeader *dirHeader;
     struct PageHeader *pageHeader;
     struct DirEntry *dirEntry;
     int doFlush = 0;
     int linkCount = 0;
+    struct afs_dynSymlink *ts;
+    int newCellCount;
 
     /*
      * Save afs_cellindex here, in case it changes between the
@@ -199,9 +230,7 @@ afs_RefreshDynroot()
     curPage = 0;
 
     for (cellidx = 0; cellidx < maxcellidx; cellidx++) {
-       int sizeOfCurEntry;
-
-       c = afs_GetCellByIndex(cellidx, READ_LOCK);
+       c = afs_GetCellByIndex(cellidx, READ_LOCK, 0 /* don't refresh */);
        if (!c) continue;
 
        sizeOfCurEntry = afs_dir_NameBlobs(c->cellName);
@@ -224,6 +253,18 @@ afs_RefreshDynroot()
        afs_PutCell(c, READ_LOCK);
     }
 
+    ObtainReadLock(&afs_dynSymlinkLock);
+    ts = afs_dynSymlinkBase;
+    while (ts) {
+       sizeOfCurEntry = afs_dir_NameBlobs(ts->name);
+       if (curChunk + sizeOfCurEntry > EPP) {
+           curPage++;
+           curChunk = 1;
+       }
+       curChunk += sizeOfCurEntry;
+       ts = ts->next;
+    }
+
     dirSize = (curPage + 1) * AFS_PAGESIZE;
     newDir = afs_osi_Alloc(dirSize);
 
@@ -254,31 +295,41 @@ afs_RefreshDynroot()
     linkCount += 2;
 
     for (cellidx = 0; cellidx < maxcellidx; cellidx++) {
-       c = afs_GetCellByIndex(cellidx, READ_LOCK);
+       c = afs_GetCellByIndex(cellidx, READ_LOCK, 0 /* don't refresh */);
        afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk,
-                             c->cellName, CIDXRW2VNUM(cellidx, 0));
+                             c->cellName, VNUM_FROM_CIDX_RW(cellidx, 0));
 
        dotCell = afs_osi_Alloc(strlen(c->cellName) + 2);
        strcpy(dotCell, ".");
        strcat(dotCell, c->cellName);
        afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk,
-                             dotCell, CIDXRW2VNUM(cellidx, 1));
-
-       linkCount += 2;
+                             dotCell, VNUM_FROM_CIDX_RW(cellidx, 1));
 
+       if (!(c->states & CAlias)) linkCount += 2;
        afs_PutCell(c, READ_LOCK);
     }
 
+    ts = afs_dynSymlinkBase;
+    while (ts) {
+       int vnum = VNUM_FROM_TYPEID(VN_TYPE_SYMLINK, ts->index);
+       afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk,
+                             ts->name, vnum);
+       ts = ts->next;
+    }
+
+    newCellCount = maxcellidx + afs_dynSymlinkIndex;
+    ReleaseReadLock(&afs_dynSymlinkLock);
+
     ObtainWriteLock(&afs_dynrootDirLock, 549);
     if (afs_dynrootDir) afs_osi_Free(afs_dynrootDir, afs_dynrootDirLen);
     afs_dynrootDir = newDir;
     afs_dynrootDirLen = dirSize;
     afs_dynrootDirLinkcnt = linkCount;
-    if (afs_dynrootCellCount != maxcellidx) {
+    if (afs_dynrootCellCount != newCellCount) {
        /*
-        * New cells added -- bump data version, invalidate vcache.
+        * New cells/symlinks added -- bump data version, invalidate vcache.
         */
-       afs_dynrootCellCount = maxcellidx;
+       afs_dynrootCellCount = newCellCount;
        afs_dynrootVersion++;
        afs_dynrootVersionHigh = osi_Time();
        doFlush = 1;
@@ -376,37 +427,75 @@ afs_DynrootNewVnode(avc, status)
        struct cell *c;
        int namelen, linklen, cellidx, rw;
 
-       cellidx = VNUM2CIDX(avc->fid.Fid.Vnode);
-       rw = VNUM2RW(avc->fid.Fid.Vnode);
+       memset(status, 0, sizeof(struct AFSFetchStatus));
 
-       c = afs_GetCellByIndex(cellidx, READ_LOCK);
+       status->FileType        = SymbolicLink;
+       status->LinkCount       = 1;
+       status->DataVersion     = 1;
+       status->CallerAccess    = PRSFS_LOOKUP | PRSFS_READ;
+       status->AnonymousAccess = PRSFS_LOOKUP | PRSFS_READ;
+       status->ParentVnode     = 1;
+       status->ParentUnique    = 1;
+
+       if (VNUM_TO_VNTYPE(avc->fid.Fid.Vnode) == VN_TYPE_SYMLINK) {
+           struct afs_dynSymlink *ts;
+           int index = VNUM_TO_VNID(avc->fid.Fid.Vnode);
+
+           ObtainReadLock(&afs_dynSymlinkLock);
+           ts = afs_dynSymlinkBase;
+           while (ts) {
+               if (ts->index == index) break;
+               ts = ts->next;
+           }
+
+           if (ts) {
+               linklen = strlen(ts->target);
+               avc->linkData = afs_osi_Alloc(linklen + 1);
+               strcpy(avc->linkData, ts->target);
+
+               status->Length       = linklen;
+               status->UnixModeBits = 0755;
+           }
+           ReleaseReadLock(&afs_dynSymlinkLock);
+
+           return ts ? 1 : 0;
+       }
+
+       if (VNUM_TO_VNTYPE(avc->fid.Fid.Vnode) != VN_TYPE_CELL) {
+           afs_warn("dynroot vnode inconsistency, unknown VNTYPE %d\n",
+                    VNUM_TO_VNTYPE(avc->fid.Fid.Vnode));
+           return 0;
+       }
+
+       cellidx = VNUM_TO_CIDX(avc->fid.Fid.Vnode);
+       rw = VNUM_TO_RW(avc->fid.Fid.Vnode);
+
+       c = afs_GetCellByIndex(cellidx, READ_LOCK, 1 /* refresh */);
        if (!c) {
            afs_warn("dynroot vnode inconsistency, can't find cell %d\n",
                     cellidx);
            return 0;
        }
 
-       memset(status, 0, sizeof(struct AFSFetchStatus));
-
        if (c->states & CAlias) {
            /*
             * linkData needs to contain the name of the cell
             * we're aliasing for.
             */
-           struct cell *tca = c->alias;
+           char *realName = c->realName;
 
-           if (!tca) {
-               afs_warn("dynroot: alias %s missing cell alias pointer\n",
+           if (!realName) {
+               afs_warn("dynroot: alias %s missing real cell name\n",
                         c->cellName);
                linklen = 7;
                avc->linkData = afs_osi_Alloc(linklen + 1);
                strcpy(avc->linkData, "unknown");
            } else {
-               int namelen = strlen(tca->cellName);
+               int namelen = strlen(realName);
                linklen = rw + namelen;
                avc->linkData = afs_osi_Alloc(linklen + 1);
                strcpy(avc->linkData, rw ? "." : "");
-               strcat(avc->linkData, tca->cellName);
+               strcat(avc->linkData, realName);
            }
 
            status->UnixModeBits = 0755;
@@ -424,15 +513,7 @@ afs_DynrootNewVnode(avc, status)
            status->UnixModeBits = 0644;
        }
 
-       status->FileType        = SymbolicLink;
-       status->LinkCount       = 1;
-       status->Length          = linklen;
-       status->DataVersion     = 1;
-       status->CallerAccess    = PRSFS_LOOKUP | PRSFS_READ;
-       status->AnonymousAccess = PRSFS_LOOKUP | PRSFS_READ;
-       status->ParentVnode     = 1;
-       status->ParentUnique    = 1;
-
+       status->Length = linklen;
        afs_PutCell(c, READ_LOCK);
        return 1;
     }
@@ -459,3 +540,100 @@ afs_GetDynrootEnable()
 {
     return afs_dynrootEnable;
 }
+
+/*
+ * Remove a temporary symlink entry from /afs.
+ */
+int
+afs_DynrootVOPRemove(avc, acred, aname)
+    struct vcache *avc;
+    struct AFS_UCRED *acred;
+    char *aname;
+{
+    struct afs_dynSymlink **tpps;
+    struct afs_dynSymlink *tps;
+    struct cell *c;
+    int found = 0;
+
+    if (acred->cr_uid)
+       return EPERM;
+
+    ObtainWriteLock(&afs_dynSymlinkLock, 97);
+    tpps = &afs_dynSymlinkBase;
+    while (*tpps) {
+       tps = *tpps;
+       if (afs_strcasecmp(aname, tps->name) == 0) {
+           afs_osi_Free(tps->name, strlen(tps->name) + 1);
+           afs_osi_Free(tps->target, strlen(tps->target) + 1);
+           *tpps = tps->next;
+           afs_osi_Free(tps, sizeof(*tps));
+           afs_dynSymlinkIndex++;
+           found = 1;
+           break;
+       }
+       tpps = &(tps->next);
+    }
+    ReleaseWriteLock(&afs_dynSymlinkLock);
+    if (found) {
+       afs_RefreshDynroot();
+       return 0;
+    }
+
+    /* Check if this is an actual cell? */
+    c = afs_GetCellByName2(aname, READ_LOCK, 0 /* no AFSDB */);
+    if (c) {
+       afs_PutCell(c, READ_LOCK);
+       return EROFS;
+    } else {
+       return ENOENT;
+    }
+}
+
+/*
+ * Create a temporary symlink entry in /afs.
+ */
+int
+afs_DynrootVOPSymlink(avc, acred, aname, atargetName)
+    struct vcache *avc;
+    struct AFS_UCRED *acred;
+    char *aname;
+    char *atargetName;
+{
+    struct afs_dynSymlink *tps;
+    struct cell *c;
+
+    if (acred->cr_uid)
+       return EPERM;
+
+    /* Check if it's already a cell */
+    c = afs_GetCellByName2(aname, READ_LOCK, 0 /* no AFSDB */);
+    if (c) {
+       afs_PutCell(c, READ_LOCK);
+       return EEXIST;
+    }
+
+    /* Check if it's already a symlink */
+    ObtainWriteLock(&afs_dynSymlinkLock, 91);
+    tps = afs_dynSymlinkBase;
+    while (tps) {
+       if (afs_strcasecmp(aname, tps->name) == 0) {
+           ReleaseWriteLock(&afs_dynSymlinkLock);
+           return EEXIST;
+       }
+       tps = tps->next;
+    }
+
+    /* Doesn't already exist -- go ahead and create it */
+    tps = afs_osi_Alloc(sizeof(*tps));
+    tps->index = afs_dynSymlinkIndex++;
+    tps->next = afs_dynSymlinkBase;
+    tps->name = afs_osi_Alloc(strlen(aname) + 1);
+    strcpy(tps->name, aname);
+    tps->target = afs_osi_Alloc(strlen(atargetName) + 1);
+    strcpy(tps->target, atargetName);
+    afs_dynSymlinkBase = tps;
+    ReleaseWriteLock(&afs_dynSymlinkLock);
+
+    afs_RefreshDynroot();
+    return 0;
+}
index 94ab8d9..873f24f 100644 (file)
@@ -55,7 +55,7 @@ int afs_osi_vget(struct vcache **avcpp, struct fid *afidp,
         */
        struct cell *tcell;
        cellindex = (Sfid.CellAndUnique >> 24) & 0xff;
-       tcell = afs_GetCellByIndex(cellindex, READ_LOCK);
+       tcell = afs_GetCellByIndex(cellindex, READ_LOCK, 0 /* don't refresh */);
        if (!tcell) {
            return ENOENT;
         }
index ebda69c..bfc89a9 100644 (file)
@@ -66,13 +66,14 @@ static int PGetCPrefs(), PSetCPrefs(); /* client network addresses */
 static int PGetInitParams(), PFlushMount(), PRxStatProc(), PRxStatPeer();
 static int PGetRxkcrypt(), PSetRxkcrypt();
 static int PPrefetchFromTape(), PResidencyCmd();
+static int PNewAlias(), PListAliases();
 int PExportAfs();
 
 static int HandleClientContext(struct afs_ioctl *ablob, int *com, struct AFS_UCRED **acred, struct AFS_UCRED *credp);
 
 extern struct cm_initparams cm_initParams;
 
-static int (*(pioctlSw[]))() = {
+static int (*(VpioctlSw[]))() = {
   PBogus,                      /* 0 */
   PSetAcl,                     /* 1 */
   PGetAcl,                     /* 2 */
@@ -141,6 +142,13 @@ static int (*(pioctlSw[]))() = {
   PNoop,                       /* 65 -- arla: break callback */
   PPrefetchFromTape,            /* 66 -- MR-AFS: prefetch file from tape */
   PResidencyCmd,                /* 67 -- MR-AFS: generic commnd interface */
+  PNoop,                       /* 68 -- arla: fetch stats */
+};
+
+static int (*(CpioctlSw[]))() = {
+  PBogus,                      /* 0 */
+  PNewAlias,                   /* 1 -- create new cell alias */
+  PListAliases,                        /* 2 -- list cell aliases */
 };
 
 #define PSetClientContext 99   /*  Special pioctl to setup caller's creds  */
@@ -741,21 +749,6 @@ afs_syscall_pioctl(path, com, cmarg, follow)
 #endif
     AFS_STATCNT(afs_syscall_pioctl);
     if (follow) follow = 1;    /* compat. with old venus */
-#ifndef        AFS_SUN5_ENV
-    if (! _VALIDVICEIOCTL(com)) {
-       PIOCTL_FREE_CRED();
-#if defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
-        return EINVAL;
-#else  /* AFS_OSF_ENV */
-#if defined(AFS_SGI64_ENV) || defined(AFS_LINUX22_ENV)
-        return EINVAL;
-#else
-       setuerror(EINVAL);
-       return EINVAL;
-#endif
-#endif
-    }
-#endif
     code = copyin_afs_ioctl(cmarg, &data);
     if (code) {
        PIOCTL_FREE_CRED();
@@ -1036,16 +1029,31 @@ afs_HandlePioctl(avc, acom, ablob, afollow, acred)
 {
     struct vrequest treq;
     register afs_int32 code;
-    register afs_int32 function;
+    register afs_int32 function, device;
     afs_int32 inSize, outSize;
     char *inData, *outData;
+    int (*(*pioctlSw))();
+    int pioctlSwSize;
 
     afs_Trace3(afs_iclSetp, CM_TRACE_PIOCTL, ICL_TYPE_INT32, acom & 0xff,
               ICL_TYPE_POINTER, avc, ICL_TYPE_INT32, afollow);
     AFS_STATCNT(HandlePioctl);
     if (code = afs_InitReq(&treq, *acred)) return code;
+    device = (acom & 0xff00) >> 8;
+    switch (device) {
+       case 'V':       /* Original pioctl's */
+               pioctlSw = VpioctlSw;
+               pioctlSwSize = sizeof(VpioctlSw);
+               break;
+       case 'C':       /* Coordinated/common pioctl's */
+               pioctlSw = CpioctlSw;
+               pioctlSwSize = sizeof(CpioctlSw);
+               break;
+       default:
+               return EINVAL;
+    }
     function = acom & 0xff;
-    if (function >= (sizeof(pioctlSw) / sizeof(char *))) {
+    if (function >= (pioctlSwSize / sizeof(char *))) {
       return EINVAL;   /* out of range */
     }
     inSize = ablob->in_size;
@@ -1061,7 +1069,7 @@ afs_HandlePioctl(avc, acom, ablob, afollow, acred)
     }
     outData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
     outSize = 0;
-    if (function == 3) /* PSetTokens */
+    if (function == 3 && device == 'V')        /* PSetTokens */
        code = (*pioctlSw[function])(avc, function, &treq, inData, outData, inSize, &outSize, acred);
     else
        code = (*pioctlSw[function])(avc, function, &treq, inData, outData, inSize, &outSize, *acred);
@@ -2299,6 +2307,53 @@ static PNewCell(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
     return code;
 }
 
+static PNewAlias(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
+    struct vcache *avc;
+    int afun;
+    struct vrequest *areq;
+    register char *ain;
+    char *aout;
+    afs_int32 ainSize;
+    struct AFS_UCRED *acred;
+    afs_int32 *aoutSize;       /* set this */
+{
+    /* create a new cell alias */
+    register struct cell *tcell;
+    char *tp = ain;
+    register afs_int32 code;
+    char *realName, *aliasName;
+    register struct afs_q *cq, *tq;
+    
+    if ( !afs_resourceinit_flag )      /* afs deamons havn't started yet */
+       return EIO;          /* Inappropriate ioctl for device */
+
+    if (!afs_osi_suser(acred))
+       return EACCES;
+
+    aliasName = tp;
+    tp += strlen(aliasName) + 1;
+    realName = tp;
+
+    /*
+     * Prevent user from shooting themselves in the foot -- don't allow
+     * creation of aliases when a real cell already exists with that name.
+     */
+    ObtainReadLock(&afs_xcell);
+    for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
+       tcell = QTOC(cq); tq = QNext(cq);
+       if ((afs_strcasecmp(tcell->cellName, aliasName) == 0) &&
+           !(tcell->states & CAlias)) {
+           ReleaseReadLock(&afs_xcell);
+           return EEXIST;
+       }
+    }
+    ReleaseReadLock(&afs_xcell);
+
+    code = afs_NewCell(aliasName, 0, CAlias, 0, 0, 0, 0, realName);
+    *aoutSize = 0;
+    return code;
+}
+
 static PListCells(avc, afun, areq, ain, aout, ainSize, aoutSize)
     struct vcache *avc;
     int afun;
@@ -2321,8 +2376,12 @@ static PListCells(avc, afun, areq, ain, aout, ainSize, aoutSize)
     ObtainReadLock(&afs_xcell);
     for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
        tcell = QTOC(cq); tq = QNext(cq);
+       if (tcell->states & CAlias) {
+           tcell = 0;
+           continue;
+       }
        if (whichCell == 0) break;
-       if (tq == &CellLRU) tcell = 0;
+       tcell = 0;
        whichCell--;
     }
     if (tcell) {
@@ -2343,6 +2402,51 @@ static PListCells(avc, afun, areq, ain, aout, ainSize, aoutSize)
     else return EDOM;
 }
 
+static PListAliases(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 */
+{
+    afs_int32 whichAlias;
+    register struct cell *tcell=0;
+    register char *cp, *tp = ain;
+    register struct afs_q *cq, *tq;
+
+    if ( !afs_resourceinit_flag )      /* afs deamons havn't started yet */
+       return EIO;          /* Inappropriate ioctl for device */
+    if (ainSize < sizeof(afs_int32))
+       return EINVAL;
+
+    memcpy((char *)&whichAlias, tp, sizeof(afs_int32));
+    tp += sizeof(afs_int32);
+
+    ObtainReadLock(&afs_xcell);
+    for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
+       tcell = QTOC(cq); tq = QNext(cq);
+       if (!(tcell->states & CAlias)) {
+           tcell = 0;
+           continue;
+       }
+       if (whichAlias == 0) break;
+       tcell = 0;
+       whichAlias--;
+    }
+    if (tcell) {       
+       cp = aout;
+       strcpy(cp, tcell->cellName);
+       cp += strlen(tcell->cellName)+1;
+       strcpy(cp, tcell->realName);
+       cp += strlen(tcell->realName)+1;
+       *aoutSize = cp - aout;
+    }
+    ReleaseReadLock(&afs_xcell);
+    if (tcell) return 0;
+    else return EDOM;
+}
+
 static PRemoveMount(avc, afun, areq, ain, aout, ainSize, aoutSize)
     struct vcache *avc;
     int afun;
index 66f507a..5d4fb28 100644 (file)
@@ -1058,6 +1058,16 @@ struct afsconf_dir *adir; {
     return 0;
 }
 
+static ConfigCellAlias(aca, arock, adir)
+    register struct afsconf_cellalias *aca;
+    char *arock;
+    struct afsconf_dir *adir;
+{
+    /* push the alias into the kernel */
+    call_syscall(AFSOP_ADDCELLALIAS, aca->aliasName, aca->realName);
+    return 0;
+}
+
 #ifdef AFS_AFSDB_ENV
 static AfsdbLookupHandler()
 {
@@ -1612,6 +1622,7 @@ mainproc(as, arock)
     lookingForHomeCell = 1;
 
     afsconf_CellApply(cdir, ConfigCell, (char *) 0);
+    afsconf_CellAliasApply(cdir, ConfigCellAlias, (char *) 0);
 
     /*
      * If we're still looking for the home cell after the whole cell configuration database
index cf40e41..8e299f4 100644 (file)
@@ -357,6 +357,7 @@ char clones[];
     FILE *tf;
     register char *tp, *bp;
     register struct afsconf_entry *curEntry;
+    struct afsconf_aliasentry *curAlias;
     register afs_int32 code;
     afs_int32 i;
     char tbuffer[256], tbuf1[256];
@@ -469,7 +470,44 @@ char clones[];
        curEntry->next = adir->entries;
        adir->entries = curEntry;
     }
-    
+
+    /* Read in the alias list */
+    strcompose(tbuffer, 256, adir->name, "/", AFSDIR_CELLALIAS_FILE, NULL);
+
+    tf = fopen(tbuffer, "r");
+    while (tf) {
+       char *aliasPtr;
+
+       tp = fgets(tbuffer, sizeof(tbuffer), tf);
+       if (!tp) break;
+       TrimLine(tbuffer);  /* remove white space */
+
+       if (tbuffer[0] == '\0' ||
+           tbuffer[0] == '\n' ||
+           tbuffer[0] == '#') continue;        /* empty line */
+
+       tp = tbuffer;
+       while (tp[0] != '\0' && tp[0] != ' ' && tp[0] != '\t') tp++;
+       if (tp[0] == '\0') continue;            /* invalid line */
+
+       while (tp[0] != '\0' && (tp[0] == ' ' || tp[0] == '\t')) 0[tp++] = '\0';
+       if (tp[0] == '\0') continue;            /* invalid line */
+
+       aliasPtr = tp;
+       while (tp[0] != '\0' && tp[0] != ' ' && tp[0] != '\t' &&
+              tp[0] != '\r' && tp[0] != '\n') tp++;
+       tp[0] = '\0';
+
+       curAlias = malloc(sizeof(*curAlias));
+       memset(curAlias, 0, sizeof(*curAlias));
+
+       strcpy(curAlias->aliasInfo.aliasName, aliasPtr);
+       strcpy(curAlias->aliasInfo.realName, tbuffer);
+
+       curAlias->next = adir->alias_entries;
+       adir->alias_entries = curAlias;
+    }
+
     /* now read the fs keys, if possible */
     adir->keystr = (struct afsconf_keys *) 0;
     afsconf_IntGetKeys(adir);
@@ -545,6 +583,28 @@ char *arock; {
     return 0;
 }
 
+/* call aproc(entry, arock, adir) for all cell aliases.
+ * Proc must return 0, or we'll stop early and return the code it returns
+ */
+afsconf_CellAliasApply(adir, aproc, arock)
+    struct afsconf_dir *adir;
+    int (*aproc)();
+    char *arock;
+{
+    register struct afsconf_aliasentry *tde;
+    register afs_int32 code;
+    LOCK_GLOBAL_MUTEX
+    for(tde=adir->alias_entries; tde; tde=tde->next) {
+       code = (*aproc)(&tde->aliasInfo, arock, adir);
+       if (code) {
+           UNLOCK_GLOBAL_MUTEX
+           return code;
+       }
+    }
+    UNLOCK_GLOBAL_MUTEX
+    return 0;
+}
+
 afs_int32 afsconf_SawCell = 0;
 
 afsconf_GetExtendedCellInfo(adir, acellName, aservice, acellInfo, clones)
@@ -734,6 +794,7 @@ char *aservice;
 char *acellName;
 struct afsconf_cell *acellInfo; {
     register struct afsconf_entry *tce;
+    struct afsconf_aliasentry *tcae;
     struct afsconf_entry *bestce;
     register afs_int32 i;
     int tservice;
@@ -765,6 +826,15 @@ struct afsconf_cell *acellInfo; {
        UNLOCK_GLOBAL_MUTEX
        return 0;
     }
+
+    /* Look through the list of aliases */
+    for (tcae = adir->alias_entries; tcae; tcae = tcae->next) {
+       if (strcasecmp(tcae->aliasInfo.aliasName, tcell) == 0) {
+           tcell = tcae->aliasInfo.realName;
+           break;
+       }
+    }
+
     for(tce=adir->entries;tce;tce=tce->next) {
        if (strcasecmp(tce->cellInfo.name, tcell) == 0) {
            /* found our cell */
@@ -797,7 +867,7 @@ struct afsconf_cell *acellInfo; {
     else {
        UNLOCK_GLOBAL_MUTEX
 #ifdef AFS_AFSDB_ENV
-       return afsconf_GetAfsdbInfo(acellName, aservice, acellInfo);
+       return afsconf_GetAfsdbInfo(tcell, aservice, acellInfo);
 #else
        return AFSCONF_NOTFOUND;
 #endif /* AFS_AFSDB_ENV */
index d5fa161..5fa71d1 100644 (file)
@@ -69,17 +69,28 @@ struct afsconf_cell {
     int timeout;                               /* Data timeout, if non-zero */
 };
 
+struct afsconf_cellalias {
+    char aliasName[MAXCELLCHARS];
+    char realName[MAXCELLCHARS];
+};
+
 struct afsconf_entry {
     struct afsconf_entry *next;        /* next guy in afsconf_dir */
     struct afsconf_cell        cellInfo;       /* info for this cell */
 };
 
+struct afsconf_aliasentry {
+    struct afsconf_aliasentry *next;
+    struct afsconf_cellalias aliasInfo;
+};
+
 struct afsconf_dir {
     char *name;            /* pointer to dir prefix */
     char *cellName; /* cell name, if any, we're in */
     struct afsconf_entry *entries; /* list of cell entries */
     struct afsconf_keys        *keystr;    /* structure containing keys */
     afs_int32 timeRead;                    /* time stamp of file last read */
+    struct afsconf_aliasentry *alias_entries; /* cell aliases */
 };
 
 extern struct afsconf_dir *afsconf_Open();
index 93a50a9..14644a2 100644 (file)
@@ -40,6 +40,7 @@
 #define        AFSOP_ADDCELL2           29     /* 2nd add cell protocol interface */
 #define        AFSOP_AFSDB_HANDLER      30     /* userspace AFSDB lookup handler */
 #define        AFSOP_SET_DYNROOT        31     /* enable/disable dynroot support */
+#define        AFSOP_ADDCELLALIAS       32     /* create alias for existing cell */
 
 /* The range 20-30 is reserved for AFS system offsets in the afs_syscall */
 #define        AFSCALL_PIOCTL          20
index 13f85f3..2680126 100644 (file)
@@ -177,4 +177,9 @@ struct cm_initparams {
 #define VIOC_PREFETCHTAPE       _VICEIOCTL(66)  /* MR-AFS prefetch from tape */
 #define VIOC_RESIDENCY_CMD      _VICEIOCTL(67)  /* generic MR-AFS cmds */
 #define VIOC_STATISTICS         _VICEIOCTL(68)  /* arla: fetch statistics */
+
+/* Coordinated 'C' pioctl's */
+#define VIOC_NEWALIAS          _VICEIOCTL2('C', 1) /* create new cell alias */
+#define VIOC_GETALIAS          _VICEIOCTL2('C', 2) /* get alias info */
+
 #endif /* AFS_VENUS_H */
index ec8374d..5e69bc4 100644 (file)
@@ -357,12 +357,17 @@ static void initDirPathArray(void)
         "/NoUsrViceEtcThisCellFileOnWindows");
   sprintf(dirPathArray[AFSDIR_CLIENT_CELLSERVDB_FILEPATH_ID], "%s/%s",
          ntClientConfigDirShort, AFSDIR_CELLSERVDB_FILE_NTCLIENT);
+  strcpy(dirPathArray[AFSDIR_CLIENT_CELLALIAS_FILEPATH_ID],
+        "/NoCellAliasOnWindows");
 #else
   pathp = dirPathArray[AFSDIR_CLIENT_THISCELL_FILEPATH_ID];
   AFSDIR_CLIENT_FILEPATH(pathp, AFSDIR_CLIENT_ETC_DIR, AFSDIR_THISCELL_FILE);
 
   pathp = dirPathArray[AFSDIR_CLIENT_CELLSERVDB_FILEPATH_ID]; 
   AFSDIR_CLIENT_FILEPATH(pathp, AFSDIR_CLIENT_ETC_DIR, AFSDIR_CELLSERVDB_FILE);
+
+  pathp = dirPathArray[AFSDIR_CLIENT_CELLALIAS_FILEPATH_ID]; 
+  AFSDIR_CLIENT_FILEPATH(pathp, AFSDIR_CLIENT_ETC_DIR, AFSDIR_CELLALIAS_FILE);
 #endif /* AFS_NT40_ENV */
 
   pathp = dirPathArray[AFSDIR_CLIENT_NETINFO_FILEPATH_ID];
index a4efdb4..b94d8d7 100644 (file)
@@ -118,6 +118,7 @@ ConstructLocalLogPath(const char *cpath,
 /* file names */ 
 #define AFSDIR_THISCELL_FILE    "ThisCell"
 #define AFSDIR_CELLSERVDB_FILE  "CellServDB"
+#define AFSDIR_CELLALIAS_FILE   "CellAlias"
 #define AFSDIR_KEY_FILE         "KeyFile"
 #define AFSDIR_ULIST_FILE       "UserList"
 #define AFSDIR_NOAUTH_FILE      "NoAuth"
@@ -260,6 +261,7 @@ typedef enum afsdir_id {
       AFSDIR_SERVER_MIGRATE_DIRPATH_ID,
       AFSDIR_SERVER_MIGRATELOG_FILEPATH_ID,
       AFSDIR_SERVER_BIN_FILE_DIRPATH_ID,
+      AFSDIR_CLIENT_CELLALIAS_FILEPATH_ID,
       AFSDIR_PATHSTRING_MAX } afsdir_id_t;
 
 /* getDirPath() returns a pointer to a string from an internal array of path strings 
@@ -331,6 +333,7 @@ const char *getDirPath(afsdir_id_t string_id);
 /* client file paths */
 #define AFSDIR_CLIENT_THISCELL_FILEPATH getDirPath(AFSDIR_CLIENT_THISCELL_FILEPATH_ID)
 #define AFSDIR_CLIENT_CELLSERVDB_FILEPATH getDirPath(AFSDIR_CLIENT_CELLSERVDB_FILEPATH_ID)  
+#define AFSDIR_CLIENT_CELLALIAS_FILEPATH getDirPath(AFSDIR_CLIENT_CELLALIAS_FILEPATH_ID)  
 #define AFSDIR_CLIENT_NETINFO_FILEPATH getDirPath(AFSDIR_CLIENT_NETINFO_FILEPATH_ID)
 #define AFSDIR_CLIENT_NETRESTRICT_FILEPATH getDirPath(AFSDIR_CLIENT_NETRESTRICT_FILEPATH_ID)
 
index ad817fa..52e0e59 100644 (file)
@@ -62,8 +62,10 @@ struct ViceIoctl {
  */
 #if defined(KERNEL) && !defined(AFS_OSF_ENV) && !defined(AFS_ALPHA_LINUX20_ENV)
 #define _VICEIOCTL(id)  ((unsigned int ) _IOW('V', id, struct ViceIoctl32))
+#define _VICEIOCTL2(dev, id) ((unsigned int ) _IOW(dev, id, struct ViceIoctl32))
 #else
 #define _VICEIOCTL(id)  ((unsigned int ) _IOW('V', id, struct ViceIoctl))
+#define _VICEIOCTL2(dev, id) ((unsigned int ) _IOW(dev, id, struct ViceIoctl))
 #endif
 
 /* Use this macro to define up to 256 vice ioctl's.  These ioctl's
@@ -72,4 +74,3 @@ struct ViceIoctl {
    into the kernel by the normal ioctl parameter passing mechanism.
  */
 
-#define _VALIDVICEIOCTL(com) (com >= _VICEIOCTL(0) && com <= _VICEIOCTL(255))
index ea197b0..dbc27cd 100644 (file)
@@ -1863,6 +1863,35 @@ static ListCellsCmd(as)
     return 0;
 }
 
+static ListAliasesCmd(as)
+    struct cmd_syndesc *as;
+{
+    afs_int32 code, i;
+    char *tp, *aliasName, *realName;
+    struct ViceIoctl blob;
+
+    for(i=0;;i++) {
+       tp = space;
+       memcpy(tp, &i, sizeof(afs_int32));
+       blob.out_size = MAXSIZE;
+       blob.in_size = sizeof(afs_int32);
+       blob.in = space;
+       blob.out = space;
+       code = pioctl(0, VIOC_GETALIAS, &blob, 1);
+       if (code < 0) {
+           if (errno == EDOM) break;   /* done with the list */
+           Die(errno, 0);
+           return 1;
+       }
+       tp = space;
+       aliasName = tp;
+       tp += strlen(aliasName) + 1;
+       realName = tp;
+       printf("Alias %s for cell %s\n", aliasName, realName);
+    }
+    return 0;
+}
+
 static NewCellCmd(as)
     struct cmd_syndesc *as;
 {
@@ -1964,6 +1993,40 @@ static NewCellCmd(as)
     return 0;
 }
 
+static NewAliasCmd(as)
+    struct cmd_syndesc *as;
+{
+    afs_int32 code;
+    struct ViceIoctl blob;
+    char *tp;
+    char *aliasName, *realName;
+
+    /* Now setup and do the NEWCELL pioctl call */
+    aliasName = as->parms[0].items->data;
+    realName = as->parms[1].items->data;
+    tp = space;
+    strcpy(tp, aliasName);
+    tp += strlen(aliasName) + 1;
+    strcpy(tp, realName);
+    tp += strlen(realName) + 1;
+
+    blob.in_size = tp - space;
+    blob.in = space;
+    blob.out_size = 0;
+    blob.out = space;
+    code = pioctl(0, VIOC_NEWALIAS, &blob, 1);
+    if (code < 0) {
+       if (errno == EEXIST) {
+           fprintf(stderr, "%s: cell name `%s' in use by an existing cell.\n",
+                   pn, aliasName);
+       } else {
+           Die(errno, 0);
+       }
+       return 1;
+    }
+    return 0;
+}
+
 static WhichCellCmd(as)
   struct cmd_syndesc *as;
 {
@@ -2984,6 +3047,8 @@ defect 3069
     ts = cmd_CreateSyntax("listcells", ListCellsCmd, 0, "list configured cells");
     cmd_AddParm(ts, "-numeric", CMD_FLAG, CMD_OPTIONAL, "addresses only");
 
+    ts = cmd_CreateSyntax("listaliases", ListAliasesCmd, 0, "list configured cell aliases");
+
     ts = cmd_CreateSyntax("setquota", SetQuotaCmd, 0, "set volume quota");
     cmd_AddParm(ts, "-path", CMD_SINGLE, CMD_OPTIONAL, "dir/file path");
     cmd_AddParm(ts, "-max", CMD_SINGLE, 0, "max quota in kbytes");
@@ -2997,6 +3062,10 @@ defect 3069
     cmd_AddParm(ts, "-servers", CMD_LIST, CMD_REQUIRED, "primary servers");
     cmd_AddParm(ts, "-linkedcell", CMD_SINGLE, CMD_OPTIONAL, "linked cell name");
 
+    ts = cmd_CreateSyntax("newalias", NewAliasCmd, 0, "configure new cell alias");
+    cmd_AddParm(ts, "-alias", CMD_SINGLE, 0, "alias name");
+    cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "real name of cell");
+
 #ifdef FS_ENABLE_SERVER_DEBUG_PORTS
 /*
  * Turn this on only if you wish to be able to talk to a server which is listening