fs: fix setserverprefs where long is larger than afs_int32
[openafs.git] / src / venus / fs.c
index 96ce349..31d20d4 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright 2000, International Business Machines Corporation and others.
  * All Rights Reserved.
- * 
+ *
  * This software has been released under the terms of the IBM Public
  * License.  For details, see the LICENSE file in the top-level source
  * directory or online at http://www.openafs.org/dl/license10.html
@@ -9,26 +9,19 @@
 
 #include <afsconfig.h>
 #include <afs/param.h>
+#include <afs/stds.h>
+
+#include <roken.h>
 
+#include <ctype.h>
 
+#include <afs/afs_consts.h>
 #include <afs/afs_args.h>
 #include <rx/xdr.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <netdb.h>
-#include <errno.h>
-#include <stdio.h>
-#include <netinet/in.h>
-#include <sys/stat.h>
-#include <afs/stds.h>
 #include <afs/vice.h>
 #include <afs/venus.h>
 #include <afs/com_err.h>
-#ifdef AFS_AIX32_ENV
-#include <signal.h>
-#endif
-
-#include <string.h>
+#include <afs/afs_consts.h>
 
 #undef VIRTUE
 #undef VICE
 #include <afs/volser.h>
 #include <afs/vlserver.h>
 #include <afs/cmd.h>
-#include <afs/afsutil.h>
 #include <afs/com_err.h>
-#include <stdlib.h>
-#include <assert.h>
 #include <afs/ptclient.h>
 #include <afs/ptuser.h>
 #include <afs/afsutil.h>
 #include <afs/sys_prototypes.h>
-    
-#define        MAXHOSTS 13
-#define        OMAXHOSTS 8
-#define MAXCELLHOSTS 8
+
 #define MAXNAME 100
-#define        MAXSIZE 2048
 #define MAXINSIZE 1300         /* pioctl complains if data is larger than this */
 #define VMSGSIZE 128           /* size of msg buf in volume hdr */
 
-static char space[MAXSIZE];
+static char space[AFS_PIOCTL_MAXSIZE];
 static char tspace[1024];
 static struct ubik_client *uclient;
 
@@ -291,7 +277,7 @@ InAFS(char *apath)
     afs_int32 code;
 
     blob.in_size = 0;
-    blob.out_size = MAXSIZE;
+    blob.out_size = AFS_PIOCTL_MAXSIZE;
     blob.out = space;
 
     code = pioctl(apath, VIOC_FILE_CELL_NAME, &blob, 1);
@@ -319,17 +305,33 @@ Parent(char *apath)
     return tspace;
 }
 
-enum rtype { add, destroy, deny };
+                                /* added relative add resp. delete    */
+                                /* (so old add really means to set)   */
+enum rtype { add, destroy, deny, reladd, reldel };
 
 static afs_int32
 Convert(char *arights, int dfs, enum rtype *rtypep)
 {
-    int i, len;
     afs_int32 mode;
     char tc;
+    char *tcp;                  /* to walk through the rights string  */
 
     *rtypep = add;             /* add rights, by default */
 
+                                /* analyze last character of string   */
+    tcp = arights + strlen(arights);
+    if ( tcp-- > arights ) {    /* assure non-empty string            */
+        if ( *tcp == '+' )
+            *rtypep = reladd;   /* '+' indicates more rights          */
+        else if ( *tcp == '-' )
+            *rtypep = reldel;   /* '-' indicates less rights          */
+        else if ( *tcp == '=' )
+            *rtypep = add;      /* '=' also allows old behaviour      */
+        else
+            tcp++;              /* back to original null byte         */
+        *tcp = '\0';            /* do not disturb old strcmp-s        */
+    }
+
     if (dfs) {
        if (!strcmp(arights, "null")) {
            *rtypep = deny;
@@ -359,10 +361,9 @@ Convert(char *arights, int dfs, enum rtype *rtypep)
        *rtypep = destroy;      /* Remove entire entry */
        return 0;
     }
-    len = strlen(arights);
     mode = 0;
-    for (i = 0; i < len; i++) {
-       tc = *arights++;
+    tcp = arights;
+    while ((tc = *tcp++ )) {
        if (dfs) {
            if (tc == '-')
                continue;
@@ -469,20 +470,35 @@ SetDotDefault(struct cmd_item **aitemp)
 }
 
 static void
-ChangeList(struct Acl *al, afs_int32 plus, char *aname, afs_int32 arights)
+ChangeList(struct Acl *al, afs_int32 plus, char *aname, afs_int32 arights,
+          enum rtype *artypep)
 {
     struct AclEntry *tlist;
     tlist = (plus ? al->pluslist : al->minuslist);
     tlist = FindList(tlist, aname);
     if (tlist) {
-       /* Found the item already in the list. */
-       tlist->rights = arights;
+       /* Found the item already in the list.
+        * modify rights in case of reladd and reladd only,
+        * use standard - add, ie. set - otherwise
+        */
+        if ( artypep == NULL )
+            tlist->rights = arights;
+        else if ( *artypep == reladd )
+            tlist->rights |= arights;
+        else if ( *artypep == reldel )
+            tlist->rights &= ~arights;
+        else
+            tlist->rights = arights;
+
        if (plus)
            al->nplus -= PruneList(&al->pluslist, al->dfs);
        else
            al->nminus -= PruneList(&al->minuslist, al->dfs);
        return;
     }
+    if ( artypep != NULL && *artypep == reldel )
+        return;                 /* can't reduce non-existing rights   */
+
     /* Otherwise we make a new item and plug in the new data. */
     tlist = (struct AclEntry *)malloc(sizeof(struct AclEntry));
     assert(tlist);
@@ -641,8 +657,30 @@ PrintStatus(VolumeStatus * status, char *name, char *offmsg)
     return 0;
 }
 
+static const char power_letter[] = {
+  'K',  /* kibi */
+  'M',  /* mebi */
+  'G',  /* gibi */
+  'T',  /* tebi */
+  'P',  /* pebi */
+};
+
+static void
+HumanPrintSpace(afs_int32 int_space)
+{
+    int exponent = 0;
+    int exponent_max = sizeof(power_letter) - 1;
+    float space = int_space;
+
+    while (space >= 1024 && exponent < exponent_max) {
+       exponent++;
+       space /= 1024;
+    }
+    printf("%9.1f%c", space, power_letter[exponent]);
+}
+
 static int
-QuickPrintStatus(VolumeStatus * status, char *name)
+QuickPrintStatus(VolumeStatus * status, char *name, int human)
 {
     double QuotaUsed = 0.0;
     double PartUsed = 0.0;
@@ -650,11 +688,22 @@ QuickPrintStatus(VolumeStatus * status, char *name)
     printf("%-25.25s", name);
 
     if (status->MaxQuota != 0) {
-       printf(" %10d %10d", status->MaxQuota, status->BlocksInUse);
+       if (human) {
+           printf(" ");
+           HumanPrintSpace(status->MaxQuota);
+           printf(" ");
+           HumanPrintSpace(status->BlocksInUse);
+       }
+       else
+           printf(" %10d %10d", status->MaxQuota, status->BlocksInUse);
        QuotaUsed =
            ((((double)status->BlocksInUse) / status->MaxQuota) * 100.0);
     } else {
-       printf("   no limit %10d", status->BlocksInUse);
+       printf("   no limit ");
+       if (human)
+           HumanPrintSpace(status->BlocksInUse);
+       else
+           printf("%10d", status->BlocksInUse);
     }
     if (QuotaUsed > 90.0) {
        printf("%5.0f%%<<", QuotaUsed);
@@ -678,15 +727,21 @@ QuickPrintStatus(VolumeStatus * status, char *name)
 }
 
 static int
-QuickPrintSpace(VolumeStatus * status, char *name)
+QuickPrintSpace(VolumeStatus * status, char *name, int human)
 {
     double PartUsed = 0.0;
     int WARN = 0;
     printf("%-25.25s", name);
 
-    printf("%10d%10d%10d", status->PartMaxBlocks,
-          status->PartMaxBlocks - status->PartBlocksAvail,
-          status->PartBlocksAvail);
+    if (human) {
+       HumanPrintSpace(status->PartMaxBlocks);
+       HumanPrintSpace(status->PartMaxBlocks - status->PartBlocksAvail);
+       HumanPrintSpace(status->PartBlocksAvail);
+    }
+    else
+       printf("%10d%10d%10d", status->PartMaxBlocks,
+               status->PartMaxBlocks - status->PartBlocksAvail,
+               status->PartBlocksAvail);
 
     PartUsed =
        (100.0 -
@@ -707,8 +762,8 @@ QuickPrintSpace(VolumeStatus * status, char *name)
 static char *
 AclToString(struct Acl *acl)
 {
-    static char mydata[MAXSIZE];
-    char tstring[MAXSIZE];
+    static char mydata[AFS_PIOCTL_MAXSIZE];
+    char tstring[AFS_PIOCTL_MAXSIZE];
     char dfsstring[30];
     struct AclEntry *tp;
 
@@ -747,7 +802,7 @@ SetACLCmd(struct cmd_syndesc *as, void *arock)
        clear = 0;
     plusp = !(as->parms[3].items);
     for (ti = as->parms[0].items; ti; ti = ti->next) {
-       blob.out_size = MAXSIZE;
+       blob.out_size = AFS_PIOCTL_MAXSIZE;
        blob.in_size = idf;
        blob.in = blob.out = space;
        code = pioctl(ti->data, VIOCGETAL, &blob, 1);
@@ -796,7 +851,7 @@ SetACLCmd(struct cmd_syndesc *as, void *arock)
                plusp = 0;
            if (rtype == destroy && ta->dfs)
                rights = -1;
-           ChangeList(ta, plusp, ui->data, rights);
+           ChangeList(ta, plusp, ui->data, rights, &rtype);
        }
        blob.in = AclToString(ta);
        blob.out_size = 0;
@@ -878,7 +933,7 @@ CopyACLCmd(struct cmd_syndesc *as, void *arock)
        clear = 1;
     else
        clear = 0;
-    blob.out_size = MAXSIZE;
+    blob.out_size = AFS_PIOCTL_MAXSIZE;
     blob.in_size = idf;
     blob.in = blob.out = space;
     code = pioctl(as->parms[0].items->data, VIOCGETAL, &blob, 1);
@@ -889,7 +944,7 @@ CopyACLCmd(struct cmd_syndesc *as, void *arock)
     fa = ParseAcl(space);
     CleanAcl(fa, as->parms[0].items->data);
     for (ti = as->parms[1].items; ti; ti = ti->next) {
-       blob.out_size = MAXSIZE;
+       blob.out_size = AFS_PIOCTL_MAXSIZE;
        blob.in_size = idf;
        blob.in = blob.out = space;
        code = pioctl(ti->data, VIOCGETAL, &blob, 1);
@@ -923,10 +978,11 @@ CopyACLCmd(struct cmd_syndesc *as, void *arock)
            }
            strcpy(ta->cell, fa->cell);
        }
+                                /* NULL rtype for standard handling   */
        for (tp = fa->pluslist; tp; tp = tp->next)
-           ChangeList(ta, 1, tp->name, tp->rights);
+           ChangeList(ta, 1, tp->name, tp->rights, NULL);
        for (tp = fa->minuslist; tp; tp = tp->next)
-           ChangeList(ta, 0, tp->name, tp->rights);
+           ChangeList(ta, 0, tp->name, tp->rights, NULL);
        blob.in = AclToString(ta);
        blob.out_size = 0;
        blob.in_size = 1 + strlen(blob.in);
@@ -1053,7 +1109,7 @@ CleanACLCmd(struct cmd_syndesc *as, void *arock)
 
     SetDotDefault(&as->parms[0].items);
     for (ti = as->parms[0].items; ti; ti = ti->next) {
-       blob.out_size = MAXSIZE;
+       blob.out_size = AFS_PIOCTL_MAXSIZE;
        blob.in_size = 0;
        blob.out = space;
        code = pioctl(ti->data, VIOCGETAL, &blob, 1);
@@ -1140,7 +1196,7 @@ ListACLCmd(struct cmd_syndesc *as, void *arock)
 
     SetDotDefault(&as->parms[0].items);
     for (ti = as->parms[0].items; ti; ti = ti->next) {
-       blob.out_size = MAXSIZE;
+       blob.out_size = AFS_PIOCTL_MAXSIZE;
        blob.in_size = idf;
        blob.in = blob.out = space;
        code = pioctl(ti->data, VIOCGETAL, &blob, 1);
@@ -1259,11 +1315,11 @@ FlushVolumeCmd(struct cmd_syndesc *as, void *arock)
     return error;
 }
 
-/* 
+/*
  * The Windows version of UuidCmd displays the UUID.
  * When the UNIX version is updated to do the same
  * be sure to replace the CMD_REQUIRED flag with
- * CMD_OPTIONAL in the cmd_AddParam(-generate) call 
+ * CMD_OPTIONAL in the cmd_AddParam(-generate) call
  */
 static int
 UuidCmd(struct cmd_syndesc *as, void *arock)
@@ -1273,7 +1329,7 @@ UuidCmd(struct cmd_syndesc *as, void *arock)
 
     blob.in_size = 0;
     blob.out_size = 0;
-    
+
     if (as->parms[0].items) {
         if (geteuid()) {
             fprintf (stderr, "Permission denied: requires root access.\n");
@@ -1302,41 +1358,45 @@ UuidCmd(struct cmd_syndesc *as, void *arock)
  * With a threshold of 0, the cache is always bypassed.  With a threshold of -1,
  * cache bypass is disabled.
  */
+
 static int
-BypassThresholdCmd(struct cmd_syndesc *as, char *arock)
+BypassThresholdCmd(struct cmd_syndesc *as, void *arock)
 {
     afs_int32 code;
-    afs_int32 size;
     struct ViceIoctl blob;
     afs_int32 threshold_i, threshold_o;
-    char *tp;  
-    
+    char *tp;
+
     /* if new threshold supplied, then set and confirm, else,
      * get current threshold and print
      */
-        
+
     if(as->parms[0].items) {
        int digit, ix, len;
-                               
+
        tp = as->parms[0].items->data;
        len = strlen(tp);
-       digit = 1; 
-       for(ix = 0; ix < len; ++ix) {
-           if(!isdigit(tp[0])) {
-               digit = 0;
-               break;
-           }
-       }
-       if (digit == 0) {
-           fprintf(stderr, "fs bypassthreshold -size: %s must be an undecorated digit string.\n", tp);
-           return EINVAL;
-       }
-       threshold_i = atoi(tp);
-       if(ix > 9 && threshold_i < 2147483647) 
-           threshold_i = 2147483647;
-       blob.in = (char *) &threshold_i;
-       blob.in_size = sizeof(threshold_i);
+
+        if (!strcmp(tp,"-1")) {
+            threshold_i = -1;
+        } else {
+            digit = 1;
+            for(ix = 0; ix < len; ++ix) {
+                if(!isdigit(tp[0])) {
+                    digit = 0;
+                    break;
+                }
+            }
+            if (digit == 0) {
+                fprintf(stderr, "fs bypassthreshold -size: %s must be an integer between -1 and 2^31\n", tp);
+                return EINVAL;
+            }
+            threshold_i = atoi(tp);
+            if(ix > 9 && threshold_i < 2147483647)
+                threshold_i = 2147483647;
+        }
+        blob.in = (char *) &threshold_i;
+        blob.in_size = sizeof(threshold_i);
     } else {
        blob.in = NULL;
        blob.in_size = 0;
@@ -1348,7 +1408,7 @@ BypassThresholdCmd(struct cmd_syndesc *as, char *arock)
     if (code) {
        Die(errno, NULL);
        return 1;
-    } else {           
+    } else {
        printf("Cache bypass threshold %d", threshold_o);
        if(threshold_o ==  -1)
            printf(" (disabled)");
@@ -1410,7 +1470,7 @@ SetVolCmd(struct cmd_syndesc *as, void *arock)
     SetDotDefault(&as->parms[0].items);
     for (ti = as->parms[0].items; ti; ti = ti->next) {
        /* once per file */
-       blob.out_size = MAXSIZE;
+       blob.out_size = AFS_PIOCTL_MAXSIZE;
        blob.in_size = sizeof(*status) + 3;     /* for the three terminating nulls */
        blob.out = space;
        blob.in = space;
@@ -1476,7 +1536,7 @@ ExamineCmd(struct cmd_syndesc *as, void *arock)
        struct VenusFid vfid;
 
        /* once per file */
-       blob.out_size = MAXSIZE;
+       blob.out_size = AFS_PIOCTL_MAXSIZE;
        blob.in_size = 0;
        blob.out = space;
        code = pioctl(ti->data, VIOCGETVOLSTAT, &blob, 1);
@@ -1511,13 +1571,17 @@ ListQuotaCmd(struct cmd_syndesc *as, void *arock)
     struct VolumeStatus *status;
     char *name;
     int error = 0;
+    int human = 0;
+
+    if (as->parms[1].items)
+       human = 1;
 
     printf("%-25s%-11s%-11s%-7s%-11s\n", "Volume Name", "      Quota",
           "       Used", " %Used", "  Partition");
     SetDotDefault(&as->parms[0].items);
     for (ti = as->parms[0].items; ti; ti = ti->next) {
        /* once per file */
-       blob.out_size = MAXSIZE;
+       blob.out_size = AFS_PIOCTL_MAXSIZE;
        blob.in_size = 0;
        blob.out = space;
        code = pioctl(ti->data, VIOCGETVOLSTAT, &blob, 1);
@@ -1528,7 +1592,7 @@ ListQuotaCmd(struct cmd_syndesc *as, void *arock)
        }
        status = (VolumeStatus *) space;
        name = (char *)status + sizeof(*status);
-       QuickPrintStatus(status, name);
+       QuickPrintStatus(status, name, human);
     }
     return error;
 }
@@ -1547,7 +1611,7 @@ WhereIsCmd(struct cmd_syndesc *as, void *arock)
     SetDotDefault(&as->parms[0].items);
     for (ti = as->parms[0].items; ti; ti = ti->next) {
        /* once per file */
-       blob.out_size = MAXSIZE;
+       blob.out_size = AFS_PIOCTL_MAXSIZE;
        blob.in_size = 0;
        blob.out = space;
        memset(space, 0, sizeof(space));
@@ -1560,7 +1624,7 @@ WhereIsCmd(struct cmd_syndesc *as, void *arock)
        hosts = (afs_int32 *) space;
        printf("File %s is on host%s ", ti->data,
               (hosts[0] && !hosts[1]) ? "" : "s");
-       for (j = 0; j < MAXHOSTS; j++) {
+       for (j = 0; j < AFS_MAXHOSTS; j++) {
            if (hosts[j] == 0)
                break;
            tp = hostutil_GetNameByINet(hosts[j]);
@@ -1581,13 +1645,17 @@ DiskFreeCmd(struct cmd_syndesc *as, void *arock)
     char *name;
     struct VolumeStatus *status;
     int error = 0;
+    int human = 0;
 
-    printf("%-25s%-10s%-10s%-10s%-6s\n", "Volume Name", "    kbytes",
-          "      used", "     avail", " %used");
+    if (as->parms[1].items)
+       human = 1;
+
+    printf("%-25s%10s%10s%10s%6s\n", "Volume Name",
+          human ? "total" : "kbytes", "used", "avail", "%used");
     SetDotDefault(&as->parms[0].items);
     for (ti = as->parms[0].items; ti; ti = ti->next) {
        /* once per file */
-       blob.out_size = MAXSIZE;
+       blob.out_size = AFS_PIOCTL_MAXSIZE;
        blob.in_size = 0;
        blob.out = space;
        code = pioctl(ti->data, VIOCGETVOLSTAT, &blob, 1);
@@ -1598,7 +1666,7 @@ DiskFreeCmd(struct cmd_syndesc *as, void *arock)
        }
        status = (VolumeStatus *) space;
        name = (char *)status + sizeof(*status);
-       QuickPrintSpace(status, name);
+       QuickPrintSpace(status, name, human);
     }
     return error;
 }
@@ -1616,7 +1684,7 @@ QuotaCmd(struct cmd_syndesc *as, void *arock)
     SetDotDefault(&as->parms[0].items);
     for (ti = as->parms[0].items; ti; ti = ti->next) {
        /* once per file */
-       blob.out_size = MAXSIZE;
+       blob.out_size = AFS_PIOCTL_MAXSIZE;
        blob.in_size = 0;
        blob.out = space;
        code = pioctl(ti->data, VIOCGETVOLSTAT, &blob, 1);
@@ -1637,113 +1705,136 @@ QuotaCmd(struct cmd_syndesc *as, void *arock)
 }
 
 static int
-ListMountCmd(struct cmd_syndesc *as, void *arock)
+GetLastComponent(const char *data, char **outdir, char **outbase,
+                int *thru_symlink)
 {
-    afs_int32 code;
-    struct ViceIoctl blob;
-    struct cmd_item *ti;
     char orig_name[1024];      /*Original name, may be modified */
     char true_name[1024];      /*``True'' dirname (e.g., symlink target) */
-    char parent_dir[1024];     /*Parent directory of true name */
-    char *last_component;      /*Last component of true name */
+    char *lastSlash;
     struct stat statbuff;      /*Buffer for status info */
     int link_chars_read;       /*Num chars read in readlink() */
-    int thru_symlink;          /*Did we get to a mount point via a symlink? */
-    int error = 0;
+    char *dirname = NULL;
+    char *basename = NULL;
 
-    for (ti = as->parms[0].items; ti; ti = ti->next) {
-       /* once per file */
-       thru_symlink = 0;
-       sprintf(orig_name, "%s%s", (ti->data[0] == '/') ? "" : "./",
-               ti->data);
+    if (thru_symlink)
+       *thru_symlink = 0;
+
+    snprintf(orig_name, sizeof(orig_name), "%s%s",
+            (data[0] == '/') ? "" : "./", data);
 
-       if (lstat(orig_name, &statbuff) < 0) {
-           /* if lstat fails, we should still try the pioctl, since it
-            * may work (for example, lstat will fail, but pioctl will
-            * work if the volume of offline (returning ENODEV). */
-           statbuff.st_mode = S_IFDIR; /* lie like pros */
+    if (lstat(orig_name, &statbuff) < 0) {
+       /* if lstat fails, we should still try the pioctl, since it
+        * may work (for example, lstat will fail, but pioctl will
+        * work if the volume of offline (returning ENODEV). */
+       statbuff.st_mode = S_IFDIR;     /* lie like pros */
+    }
+
+    /*
+     * The lstat succeeded.  If the given file is a symlink, substitute
+     * the file name with the link name.
+     */
+    if ((statbuff.st_mode & S_IFMT) == S_IFLNK) {
+       if (thru_symlink)
+            *thru_symlink = 1;
+
+       /* Read name of resolved file */
+       link_chars_read = readlink(orig_name, true_name, 1024);
+       if (link_chars_read <= 0) {
+           fprintf(stderr,
+                   "%s: Can't read target name for '%s' symbolic link!\n",
+                   pn, orig_name);
+           goto out;
        }
 
+       /* Add a trailing null to what was read, bump the length. */
+       true_name[link_chars_read++] = 0;
+
        /*
-        * The lstat succeeded.  If the given file is a symlink, substitute
-        * the file name with the link name.
+        * If the symlink is an absolute pathname, we're fine.  Otherwise, we
+        * have to create a full pathname using the original name and the
+        * relative symlink name.  Find the rightmost slash in the original
+        * name (we know there is one) and splice in the symlink value.
         */
-       if ((statbuff.st_mode & S_IFMT) == S_IFLNK) {
-           thru_symlink = 1;
-           /*
-            * Read name of resolved file.
-            */
-           link_chars_read = readlink(orig_name, true_name, 1024);
-           if (link_chars_read <= 0) {
-               fprintf(stderr,
-                       "%s: Can't read target name for '%s' symbolic link!\n",
-                       pn, orig_name);
-               error = 1;
-               continue;
-           }
-
-           /*
-            * Add a trailing null to what was read, bump the length.
-            */
-           true_name[link_chars_read++] = 0;
-
-           /*
-            * If the symlink is an absolute pathname, we're fine.  Otherwise, we
-            * have to create a full pathname using the original name and the
-            * relative symlink name.  Find the rightmost slash in the original
-            * name (we know there is one) and splice in the symlink value.
-            */
-           if (true_name[0] != '/') {
-               last_component = (char *)strrchr(orig_name, '/');
-               strcpy(++last_component, true_name);
-               strcpy(true_name, orig_name);
-           }
-       } else
+       if (true_name[0] != '/') {
+           lastSlash = strrchr(orig_name, '/');
+           strcpy(++lastSlash, true_name);
            strcpy(true_name, orig_name);
-
+       }
+     } else {
+       strcpy(true_name, orig_name);
+     }
+
+    /* Find rightmost slash, if any. */
+    lastSlash = strrchr(true_name, '/');
+    if (lastSlash == true_name) {
+       dirname = strdup("/");
+       basename = strdup(lastSlash+1);
+    } else if (lastSlash != NULL) {
        /*
-        * Find rightmost slash, if any.
+        * Found it.  Designate everything before it as the parent directory,
+        * everything after it as the final component.
         */
-       last_component = (char *)strrchr(true_name, '/');
-       if (last_component == (char *)true_name) {
-           strcpy(parent_dir, "/");
-           last_component++;
-       }
-       else if (last_component != (char *)NULL) {
-           /*
-            * Found it.  Designate everything before it as the parent directory,
-            * everything after it as the final component.
-            */
-           strncpy(parent_dir, true_name, last_component - true_name);
-           parent_dir[last_component - true_name] = 0;
-           last_component++;   /*Skip the slash */
-       } else {
-           /*
-            * No slash appears in the given file name.  Set parent_dir to the current
-            * directory, and the last component as the given name.
-            */
-           strcpy(parent_dir, ".");
-           last_component = true_name;
-       }
+       *lastSlash = '\0';
+       dirname = strdup(true_name);
+       basename = strdup(lastSlash+1);
+    } else {
+       /*
+        * No slash appears in the given file name.  Set parent_dir to the current
+        * directory, and the last component as the given name.
+        */
+       dirname = strdup(".");
+       basename = strdup(true_name);
+    }
 
-       if (strcmp(last_component, ".") == 0
-           || strcmp(last_component, "..") == 0) {
-           fprintf(stderr,
-                   "%s: you may not use '.' or '..' as the last component\n",
-                   pn);
-           fprintf(stderr, "%s: of a name in the 'fs lsmount' command.\n",
-                   pn);
+    if (strcmp(basename, ".") == 0
+       || strcmp(basename, "..") == 0) {
+       fprintf(stderr,
+               "%s: you may not use '.' or '..' as the last component\n", pn);
+       fprintf(stderr, "%s: of a name in this fs command.\n", pn);
+       goto out;
+    }
+
+    *outdir = dirname;
+    *outbase = basename;
+
+    return 0;
+
+out:
+    if (outdir)
+       free(outdir);
+    if (outbase)
+       free(outbase);
+    return -1;
+}
+
+
+static int
+ListMountCmd(struct cmd_syndesc *as, void *arock)
+{
+    afs_int32 code;
+    struct ViceIoctl blob;
+    struct cmd_item *ti;
+    char *last_component;
+    char *parent_dir;
+    int thru_symlink = 0;
+    int error = 0;
+
+    for (ti = as->parms[0].items; ti; ti = ti->next) {
+       if (GetLastComponent(ti->data, &parent_dir,
+                            &last_component, &thru_symlink) != 0) {
            error = 1;
            continue;
        }
 
        blob.in = last_component;
        blob.in_size = strlen(last_component) + 1;
-       blob.out_size = MAXSIZE;
+       blob.out_size = AFS_PIOCTL_MAXSIZE;
        blob.out = space;
-       memset(space, 0, MAXSIZE);
+       memset(space, 0, AFS_PIOCTL_MAXSIZE);
 
        code = pioctl(parent_dir, VIOC_AFS_STAT_MT_PT, &blob, 1);
+       free(last_component);
+       free(parent_dir);
 
        if (code == 0) {
            printf("'%s' is a %smount point for volume '%s'\n", ti->data,
@@ -1816,7 +1907,7 @@ defect #3069
 
     if (!cellName) {
        blob.in_size = 0;
-       blob.out_size = MAXSIZE;
+       blob.out_size = AFS_PIOCTL_MAXSIZE;
        blob.out = space;
        code =
            pioctl(Parent(as->parms[0].items->data), VIOC_FILE_CELL_NAME,
@@ -1895,7 +1986,7 @@ RemoveMountCmd(struct cmd_syndesc *as, void *arock)
        blob.in_size = strlen(tp) + 1;
        blob.out = lsbuffer;
        blob.out_size = sizeof(lsbuffer);
-       code = pioctl(tbuffer, VIOC_AFS_STAT_MT_PT, &blob, 0);
+       code = pioctl(tbuffer, VIOC_AFS_STAT_MT_PT, &blob, 1);
        if (code) {
            if (errno == EINVAL) {
                fprintf(stderr, "%s: '%s' is not a mount point.\n", pn,
@@ -1909,7 +2000,7 @@ RemoveMountCmd(struct cmd_syndesc *as, void *arock)
        blob.out_size = 0;
        blob.in = tp;
        blob.in_size = strlen(tp) + 1;
-       code = pioctl(tbuffer, VIOC_AFS_DELETE_MT_PT, &blob, 0);
+       code = pioctl(tbuffer, VIOC_AFS_DELETE_MT_PT, &blob, 1);
        if (code) {
            Die(errno, ti->data);
            error = 1;
@@ -1936,7 +2027,7 @@ CheckServersCmd(struct cmd_syndesc *as, void *arock)
     blob.in_size = sizeof(struct chservinfo);
     blob.in = (caddr_t) & checkserv;
 
-    blob.out_size = MAXSIZE;
+    blob.out_size = AFS_PIOCTL_MAXSIZE;
     blob.out = space;
     memset(space, 0, sizeof(afs_int32));       /* so we assure zero when nothing is copied back */
 
@@ -2029,7 +2120,7 @@ MessagesCmd(struct cmd_syndesc *as, void *arock)
     memset(&gagflags, 0, sizeof(struct gaginfo));
     blob.in_size = sizeof(struct gaginfo);
     blob.in = (caddr_t) & gagflags;
-    blob.out_size = MAXSIZE;
+    blob.out_size = AFS_PIOCTL_MAXSIZE;
     blob.out = space;
     memset(space, 0, sizeof(afs_int32));       /* so we assure zero when nothing is copied back */
 
@@ -2086,7 +2177,7 @@ PreCacheCmd(struct cmd_syndesc *as, void *arock)
     afs_int32 code;
     struct ViceIoctl blob;
     afs_int32 temp;
-    
+
     if (!as->parms[0].items && !as->parms[1].items) {
        fprintf(stderr, "%s: syntax error in precache cmd.\n", pn);
        return 1;
@@ -2108,7 +2199,7 @@ PreCacheCmd(struct cmd_syndesc *as, void *arock)
        Die(errno, NULL);
        return 1;
     }
-    
+
     printf("New precache size set.\n");
     return 0;
 }
@@ -2206,26 +2297,26 @@ GetCacheParmsCmd(struct cmd_syndesc *as, void *arock)
            percentFiles, filesUsed, parms[2]);
     if (flags == 2){
        printf("        afs_cacheFiles: %10d\n", parms[2]);
-       printf("        IFFree:         %10d\n", parms[3]); 
-       printf("        IFEverUsed:     %10d\n", parms[4]); 
-       printf("        IFDataMod:      %10d\n", parms[5]); 
+       printf("        IFFree:         %10d\n", parms[3]);
+       printf("        IFEverUsed:     %10d\n", parms[4]);
+       printf("        IFDataMod:      %10d\n", parms[5]);
        printf("        IFDirtyPages:   %10d\n", parms[6]);
-       printf("        IFAnyPages:     %10d\n", parms[7]); 
+       printf("        IFAnyPages:     %10d\n", parms[7]);
        printf("        IFDiscarded:    %10d\n", parms[8]);
        printf("        DCentries:  %10d\n", parms[9]);
-       printf("          0k-   4K: %10d\n", parms[10]); 
-       printf("          4k-  16k: %10d\n", parms[11]); 
-       printf("         16k-  64k: %10d\n", parms[12]); 
-       printf("         64k- 256k: %10d\n", parms[13]); 
-       printf("        256k-   1M: %10d\n", parms[14]); 
-       printf("              >=1M: %10d\n", parms[15]); 
+       printf("          0k-   4K: %10d\n", parms[10]);
+       printf("          4k-  16k: %10d\n", parms[11]);
+       printf("         16k-  64k: %10d\n", parms[12]);
+       printf("         64k- 256k: %10d\n", parms[13]);
+       printf("        256k-   1M: %10d\n", parms[14]);
+       printf("              >=1M: %10d\n", parms[15]);
     }
 
     if (percentBlocks > 90)
        printf("[cache size usage over 90%%, consider increasing cache size]\n");
     if (percentFiles > 90)
        printf("[cache file usage over 90%%, consider increasing '-files' argument to afsd]\n");
-        
+
     return 0;
 }
 
@@ -2243,7 +2334,7 @@ ListCellsCmd(struct cmd_syndesc *as, void *arock)
     for (i = 0;; i++) {
        tp = space;
        memcpy(tp, &i, sizeof(afs_int32));
-       blob.out_size = MAXSIZE;
+       blob.out_size = AFS_PIOCTL_MAXSIZE;
        blob.in_size = sizeof(afs_int32);
        blob.in = space;
        blob.out = space;
@@ -2255,8 +2346,8 @@ ListCellsCmd(struct cmd_syndesc *as, void *arock)
            return 1;
        }
        tp = space;
-       printf("Cell %s on hosts", tp + MAXCELLHOSTS * sizeof(afs_int32));
-       for (j = 0; j < MAXCELLHOSTS; j++) {
+       printf("Cell %s on hosts", tp + AFS_MAXCELLHOSTS * sizeof(afs_int32));
+       for (j = 0; j < AFS_MAXCELLHOSTS; j++) {
            afs_int32 addr;
            char *name, tbuffer[20];
 
@@ -2289,7 +2380,7 @@ ListAliasesCmd(struct cmd_syndesc *as, void *arock)
     for (i = 0;; i++) {
        tp = space;
        memcpy(tp, &i, sizeof(afs_int32));
-       blob.out_size = MAXSIZE;
+       blob.out_size = AFS_PIOCTL_MAXSIZE;
        blob.in_size = sizeof(afs_int32);
        blob.in = space;
        blob.out = space;
@@ -2317,10 +2408,8 @@ CallBackRxConnCmd(struct cmd_syndesc *as, void *arock)
     struct cmd_item *ti;
     afs_int32 hostAddr;
     struct hostent *thp;
-    int setp;
-    
+
     ti = as->parms[0].items;
-    setp = 1;
     if (ti) {
         thp = hostutil_GetHostByName(ti->data);
        if (!thp) {
@@ -2330,15 +2419,14 @@ CallBackRxConnCmd(struct cmd_syndesc *as, void *arock)
        else memcpy(&hostAddr, thp->h_addr, sizeof(afs_int32));
     } else {
         hostAddr = 0;   /* means don't set host */
-       setp = 0;       /* aren't setting host */
     }
-    
+
     /* now do operation */
     blob.in_size = sizeof(afs_int32);
     blob.out_size = sizeof(afs_int32);
     blob.in = (char *) &hostAddr;
     blob.out = (char *) &hostAddr;
-    
+
     code = pioctl(0, VIOC_CBADDR, &blob, 1);
     if (code < 0) {
        Die(errno, 0);
@@ -2355,7 +2443,7 @@ NukeNFSCredsCmd(struct cmd_syndesc *as, void *arock)
     struct cmd_item *ti;
     afs_int32 hostAddr;
     struct hostent *thp;
-    
+
     ti = as->parms[0].items;
     thp = hostutil_GetHostByName(ti->data);
     if (!thp) {
@@ -2363,13 +2451,13 @@ NukeNFSCredsCmd(struct cmd_syndesc *as, void *arock)
        return 1;
     }
     else memcpy(&hostAddr, thp->h_addr, sizeof(afs_int32));
-    
+
     /* now do operation */
     blob.in_size = sizeof(afs_int32);
     blob.out_size = sizeof(afs_int32);
     blob.in = (char *) &hostAddr;
     blob.out = (char *) &hostAddr;
-    
+
     code = pioctl(0, VIOC_NFS_NUKE_CREDS, &blob, 1);
     if (code < 0) {
        Die(errno, 0);
@@ -2391,8 +2479,8 @@ NewCellCmd(struct cmd_syndesc *as, void *arock)
 
     /* Yuck!
      * With the NEWCELL pioctl call, 3.4 clients take an array of
-     * MAXHOSTS (13) servers while 3.5 clients take an array of
-     * MAXCELLHOSTS (8) servers. To determine which we are talking to,
+     * AFS_MAXHOSTS (13) servers while 3.5 clients take an array of
+     * AFS_MAXCELLHOSTS (8) servers. To determine which we are talking to,
      * do a GETCELL pioctl and pass it a magic number. If an array of
      * 8 comes back, its a 3.5 client. If not, its a 3.4 client.
      * If we get back EDOM, there are no cells in the kernel yet,
@@ -2402,7 +2490,7 @@ NewCellCmd(struct cmd_syndesc *as, void *arock)
     lp = (afs_int32 *) tp;
     *lp++ = 0;                 /* first cell entry */
     *lp = 0x12345678;          /* magic */
-    blob.out_size = MAXSIZE;
+    blob.out_size = AFS_PIOCTL_MAXSIZE;
     blob.in_size = sizeof(afs_int32) + sizeof(afs_int32);
     blob.in = space;
     blob.out = space;
@@ -2412,11 +2500,11 @@ NewCellCmd(struct cmd_syndesc *as, void *arock)
        return 1;
     }
     if (code < 1 && errno == EDOM) {
-       scount = MAXHOSTS;
+       scount = AFS_MAXHOSTS;
     } else {
        tp = space;
-       cellname = tp + MAXCELLHOSTS * sizeof(afs_int32);
-       scount = ((cellname[0] != '\0') ? MAXCELLHOSTS : MAXHOSTS);
+       cellname = tp + AFS_MAXCELLHOSTS * sizeof(afs_int32);
+       scount = ((cellname[0] != '\0') ? AFS_MAXCELLHOSTS : AFS_MAXHOSTS);
     }
 
     /* Now setup and do the NEWCELL pioctl call */
@@ -2558,7 +2646,7 @@ WSCellCmd(struct cmd_syndesc *as, void *arock)
 
     blob.in_size = 0;
     blob.in = NULL;
-    blob.out_size = MAXSIZE;
+    blob.out_size = AFS_PIOCTL_MAXSIZE;
     blob.out = space;
 
     code = pioctl(NULL, VIOC_GET_WS_CELL, &blob, 1);
@@ -2653,13 +2741,13 @@ SysNameCmd(struct cmd_syndesc *as, void *arock)
     ti = as->parms[0].items;
     blob.in = space;
     blob.out = space;
-    blob.out_size = MAXSIZE;
+    blob.out_size = AFS_PIOCTL_MAXSIZE;
     blob.in_size = sizeof(afs_int32);
     input += sizeof(afs_int32);
     for (; ti; ti = ti->next) {
        setp++;
        blob.in_size += strlen(ti->data) + 1;
-       if (blob.in_size > MAXSIZE) {
+       if (blob.in_size > AFS_PIOCTL_MAXSIZE) {
            fprintf(stderr, "%s: sysname%s too long.\n", pn,
                    setp > 1 ? "s" : "");
            return 1;
@@ -2701,7 +2789,7 @@ ExportAfsCmd(struct cmd_syndesc *as, void *arock)
     afs_int32 code;
     struct ViceIoctl blob;
     struct cmd_item *ti;
-    int export = 0, type = 0, mode = 0, exp = 0, exportcall, pwsync =
+    int export = 0, type = 0, mode = 0, exportcall, pwsync =
        0, smounts = 0, clipags = 0, pagcb = 0;
 
     ti = as->parms[0].items;
@@ -2723,7 +2811,6 @@ ExportAfsCmd(struct cmd_syndesc *as, void *arock)
            fprintf(stderr, "Illegal argument %s\n", ti->data);
            return 1;
        }
-       exp = 1;
     }
     if ((ti = as->parms[2].items)) {   /* -noconvert */
        if (strcmp(ti->data, "on") == 0)
@@ -2953,7 +3040,7 @@ VLDBInit(int noAuthFlag, struct afsconf_cell *info)
     afs_int32 code;
 
     code = ugen_ClientInit(noAuthFlag, (char *) AFSDIR_CLIENT_ETC_DIRPATH,
-                          info->name, 0, &uclient, 
+                          info->name, 0, &uclient,
                            NULL, pn, rxkad_clear,
                            VLDB_MAXSERVERS, AFSCONF_VLDBSERVICE, 50,
                            0, 0, USER_SERVICE_ID);
@@ -3063,7 +3150,7 @@ SetPrefCmd(struct cmd_syndesc *as, void *arock)
     afs_int32 code;
     struct cmd_item *ti;
     char name[80];
-    afs_int32 rank;
+    int rank;
     struct setspref *ssp;
     int error = 0;             /* -1 means error message printed,
                                 * >0 means errno value for unprinted message */
@@ -3074,7 +3161,7 @@ SetPrefCmd(struct cmd_syndesc *as, void *arock)
     gblob.in_size = ((char *)&(ssp->servers[0])) - (char *)ssp;
     gblob.in = space;
     gblob.out = space;
-    gblob.out_size = MAXSIZE;
+    gblob.out_size = AFS_PIOCTL_MAXSIZE;
 
 
     if (geteuid()) {
@@ -3090,7 +3177,7 @@ SetPrefCmd(struct cmd_syndesc *as, void *arock)
            perror(ti->data);
            error = -1;
        } else {
-           while (fscanf(infd, "%79s%ld", name, (long int *)&rank) != EOF) {
+           while (fscanf(infd, "%79s%d", name, &rank) != EOF) {
                code = addServer(name, (unsigned short)rank);
                if (code)
                    error = code;
@@ -3100,7 +3187,7 @@ SetPrefCmd(struct cmd_syndesc *as, void *arock)
 
     ti = as->parms[3].items;   /* -stdin */
     if (ti) {
-       while (scanf("%79s%ld", name, (long int *)&rank) != EOF) {
+       while (scanf("%79s%d", name, &rank) != EOF) {
            code = addServer(name, (unsigned short)rank);
            if (code)
                error = code;
@@ -3200,17 +3287,26 @@ GetPrefCmd(struct cmd_syndesc *as, void *arock)
        blob.in_size = sizeof(struct sprefrequest);
        blob.in = (char *)in;
        blob.out = space;
-       blob.out_size = MAXSIZE;
+       blob.out_size = AFS_PIOCTL_MAXSIZE;
 
        in->num_servers =
-           (MAXSIZE - 2 * sizeof(short)) / sizeof(struct spref);
+           (AFS_PIOCTL_MAXSIZE - 2 * sizeof(short)) / sizeof(struct spref);
        in->flags = vlservers;
 
-       code = pioctl(0, VIOC_GETSPREFS, &blob, 1);
-       if (code) {
-           perror("getserverprefs pioctl");
-           return 1;
-       }
+       do {
+           code = pioctl(0, VIOC_GETSPREFS, &blob, 1);
+           if (code) {
+               if ((errno != E2BIG) || (2 * blob.out_size > 0x7FFF)) {
+                   perror("getserverprefs pioctl");
+                   return 1;
+               }
+               blob.out_size *= 2;
+               if (blob.out == space)
+                   blob.out = malloc(blob.out_size);
+               else
+                   blob.out = realloc(blob.out, blob.out_size);
+           }
+       } while (code != 0);
 
        out = (struct sprefinfo *)blob.out;
 
@@ -3229,6 +3325,9 @@ GetPrefCmd(struct cmd_syndesc *as, void *arock)
        in->offset = out->next_offset;
     } while (out->next_offset > 0);
 
+    if (blob.out != space)
+       free(blob.out);
+
     return 0;
 }
 
@@ -3278,13 +3377,14 @@ StoreBehindCmd(struct cmd_syndesc *as, void *arock)
        verbose = 1;
 
     blob.in = (char *)&tsb;
-    blob.out = (char *)&tsb2;
-    blob.in_size = blob.out_size = sizeof(struct sbstruct);
-    memset(&tsb2, 0, sizeof(tsb2));
+    blob.in_size = sizeof(struct sbstruct);
 
     /* once per -file */
     for (ti = as->parms[1].items; ti; ti = ti->next) {
        /* Do this solely to see if the file is there */
+
+        blob.out = space;
+       blob.out_size = AFS_PIOCTL_MAXSIZE;
        code = pioctl(ti->data, VIOCWHEREIS, &blob, 1);
        if (code) {
            Die(errno, ti->data);
@@ -3292,6 +3392,9 @@ StoreBehindCmd(struct cmd_syndesc *as, void *arock)
            continue;
        }
 
+       memset(&tsb2, 0, sizeof(tsb2));
+       blob.out = (char *)&tsb2;
+       blob.out_size = sizeof(struct sbstruct);
        code = pioctl(ti->data, VIOC_STORBEHIND, &blob, 1);
        if (code) {
            Die(errno, ti->data);
@@ -3316,6 +3419,9 @@ StoreBehindCmd(struct cmd_syndesc *as, void *arock)
      */
     if (!as->parms[1].items || (allfiles != -1)) {
        tsb.sb_default = allfiles;
+        memset(&tsb2, 0, sizeof(tsb2));
+       blob.out = (char *)&tsb2;
+       blob.out_size = sizeof(struct sbstruct);
        code = pioctl(0, VIOC_STORBEHIND, &blob, 1);
        if (code) {
            Die(errno, ((allfiles == -1) ? 0 : "-allfiles"));
@@ -3324,7 +3430,7 @@ StoreBehindCmd(struct cmd_syndesc *as, void *arock)
     }
 
     /* Having no arguments also reports the default store asynchrony */
-    if (verbose && (blob.out_size == sizeof(tsb2))) {
+    if (!error && verbose && (blob.out_size == sizeof(tsb2))) {
        fprintf(stdout, "Default store asynchrony is %d kbytes.\n",
                (tsb2.sb_default / 1024));
     }
@@ -3388,7 +3494,6 @@ GetCryptCmd(struct cmd_syndesc *as, void *arock)
     return 0;
 }
 
-#ifdef AFS_DISCON_ENV
 static char *modenames[] = {
     "offline",
     "online",
@@ -3413,13 +3518,13 @@ DisconCmd(struct cmd_syndesc *as, void *arock)
     char *modename;
     char *policyname;
     int modelen, policylen;
-    afs_int32 mode, policy, code;
+    afs_int32 mode, policy, code, unixuid = 0;
     struct ViceIoctl blob;
 
     blob.in = NULL;
     blob.in_size = 0;
 
-    space[0] = space[1] = space[2] = 0;
+    space[0] = space[1] = space[2] = space[3] = 0;
 
     ti = as->parms[0].items;
     if (ti) {
@@ -3453,8 +3558,19 @@ DisconCmd(struct cmd_syndesc *as, void *arock)
        printf("force on\n");
     }
 
+    ti = as->parms[3].items;
+    if (ti) {
+       code = util_GetInt32(ti->data, &unixuid);
+       if (code) {
+           fprintf(stderr, "%s: bad integer specified for uid.\n", pn);
+            return 1;
+        }
+       space[3] = unixuid;
+    } else
+       space[3] = 0;
+
     blob.in = space;
-    blob.in_size = 3 * sizeof(afs_int32);
+    blob.in_size = 4 * sizeof(afs_int32);
 
     blob.out_size = sizeof(mode);
     blob.out = space;
@@ -3471,7 +3587,6 @@ DisconCmd(struct cmd_syndesc *as, void *arock)
 
     return 0;
 }
-#endif
 
 #include "AFS_component_version_number.c"
 
@@ -3603,11 +3718,13 @@ main(int argc, char **argv)
 
     ts = cmd_CreateSyntax("listquota", ListQuotaCmd, NULL, "list volume quota");
     cmd_AddParm(ts, "-path", CMD_LIST, CMD_OPTIONAL, "dir/file path");
+    cmd_AddParm(ts, "-human", CMD_FLAG, CMD_OPTIONAL, "human-readable listing");
     cmd_CreateAlias(ts, "lq");
 
     ts = cmd_CreateSyntax("diskfree", DiskFreeCmd, NULL,
                          "show server disk space usage");
     cmd_AddParm(ts, "-path", CMD_LIST, CMD_OPTIONAL, "dir/file path");
+    cmd_AddParm(ts, "-human", CMD_FLAG, CMD_OPTIONAL, "human-readable listing");
     cmd_CreateAlias(ts, "df");
 
     ts = cmd_CreateSyntax("quota", QuotaCmd, NULL, "show volume quota usage");
@@ -3797,13 +3914,12 @@ defect 3069
                          "get fid for file(s)");
     cmd_AddParm(ts, "-path", CMD_LIST, CMD_OPTIONAL, "dir/file path");
 
-#ifdef AFS_DISCON_ENV
     ts = cmd_CreateSyntax("discon", DisconCmd, NULL,
                          "disconnection mode");
     cmd_AddParm(ts, "-mode", CMD_SINGLE, CMD_REQUIRED, "offline | online");
     cmd_AddParm(ts, "-policy", CMD_SINGLE, CMD_OPTIONAL, "client | server");
     cmd_AddParm(ts, "-force", CMD_FLAG, CMD_OPTIONAL, "Force reconnection, despite any synchronization issues.");
-#endif
+    cmd_AddParm(ts, "-uid", CMD_SINGLE, CMD_OPTIONAL, "Numeric UID of user whose tokens to use at reconnect.");
 
     ts = cmd_CreateSyntax("nukenfscreds", NukeNFSCredsCmd, NULL, "nuke credentials for NFS client");
     cmd_AddParm(ts, "-addr", CMD_SINGLE, 0, "host name or address");
@@ -3882,10 +3998,10 @@ GetClientAddrsCmd(struct cmd_syndesc *as, void *arock)
        blob.in_size = sizeof(struct sprefrequest);
        blob.in = (char *)in;
        blob.out = space;
-       blob.out_size = MAXSIZE;
+       blob.out_size = AFS_PIOCTL_MAXSIZE;
 
        in->num_servers =
-           (MAXSIZE - 2 * sizeof(short)) / sizeof(struct spref);
+           (AFS_PIOCTL_MAXSIZE - 2 * sizeof(short)) / sizeof(struct spref);
        /* returns addr in network byte order */
        code = pioctl(0, VIOC_GETCPREFS, &blob, 1);
        if (code) {
@@ -3927,7 +4043,7 @@ SetClientAddrsCmd(struct cmd_syndesc *as, void *arock)
     ssp->num_servers = 0;
     blob.in = space;
     blob.out = space;
-    blob.out_size = MAXSIZE;
+    blob.out_size = AFS_PIOCTL_MAXSIZE;
 
     if (geteuid()) {
        fprintf(stderr, "Permission denied: requires root access.\n");
@@ -3990,97 +4106,13 @@ FlushMountCmd(struct cmd_syndesc *as, void *arock)
     afs_int32 code;
     struct ViceIoctl blob;
     struct cmd_item *ti;
-    char orig_name[1024];      /*Original name, may be modified */
-    char true_name[1024];      /*``True'' dirname (e.g., symlink target) */
-    char parent_dir[1024];     /*Parent directory of true name */
-    char *last_component;      /*Last component of true name */
-    struct stat statbuff;      /*Buffer for status info */
-    int link_chars_read;       /*Num chars read in readlink() */
-    int thru_symlink;          /*Did we get to a mount point via a symlink? */
+    char *last_component;
+    char *parent_dir;
     int error = 0;
 
     for (ti = as->parms[0].items; ti; ti = ti->next) {
-       /* once per file */
-       thru_symlink = 0;
-       sprintf(orig_name, "%s%s", (ti->data[0] == '/') ? "" : "./",
-               ti->data);
-
-       if (lstat(orig_name, &statbuff) < 0) {
-           /* if lstat fails, we should still try the pioctl, since it
-            * may work (for example, lstat will fail, but pioctl will
-            * work if the volume of offline (returning ENODEV). */
-           statbuff.st_mode = S_IFDIR; /* lie like pros */
-       }
-
-       /*
-        * The lstat succeeded.  If the given file is a symlink, substitute
-        * the file name with the link name.
-        */
-       if ((statbuff.st_mode & S_IFMT) == S_IFLNK) {
-           thru_symlink = 1;
-           /*
-            * Read name of resolved file.
-            */
-           link_chars_read = readlink(orig_name, true_name, 1024);
-           if (link_chars_read <= 0) {
-               fprintf(stderr,
-                       "%s: Can't read target name for '%s' symbolic link!\n",
-                       pn, orig_name);
-               error = 1;
-               continue;
-           }
-
-           /*
-            * Add a trailing null to what was read, bump the length.
-            */
-           true_name[link_chars_read++] = 0;
-
-           /*
-            * If the symlink is an absolute pathname, we're fine.  Otherwise, we
-            * have to create a full pathname using the original name and the
-            * relative symlink name.  Find the rightmost slash in the original
-            * name (we know there is one) and splice in the symlink value.
-            */
-           if (true_name[0] != '/') {
-               last_component = (char *)strrchr(orig_name, '/');
-               strcpy(++last_component, true_name);
-               strcpy(true_name, orig_name);
-           }
-       } else
-           strcpy(true_name, orig_name);
-
-       /*
-        * Find rightmost slash, if any.
-        */
-       last_component = (char *)strrchr(true_name, '/');
-       if (last_component == (char *)true_name) {
-           strcpy(parent_dir, "/");
-           last_component++;
-       }
-       else if (last_component != (char *)NULL) {
-           /*
-            * Found it.  Designate everything before it as the parent directory,
-            * everything after it as the final component.
-            */
-           strncpy(parent_dir, true_name, last_component - true_name);
-           parent_dir[last_component - true_name] = 0;
-           last_component++;   /*Skip the slash */
-       } else {
-           /*
-            * No slash appears in the given file name.  Set parent_dir to the current
-            * directory, and the last component as the given name.
-            */
-           strcpy(parent_dir, ".");
-           last_component = true_name;
-       }
-
-       if (strcmp(last_component, ".") == 0
-           || strcmp(last_component, "..") == 0) {
-           fprintf(stderr,
-                   "%s: you may not use '.' or '..' as the last component\n",
-                   pn);
-           fprintf(stderr, "%s: of a name in the 'fs flushmount' command.\n",
-                   pn);
+       if (GetLastComponent(ti->data, &parent_dir,
+                            &last_component, NULL) != 0) {
            error = 1;
            continue;
        }
@@ -4088,10 +4120,12 @@ FlushMountCmd(struct cmd_syndesc *as, void *arock)
        blob.in = last_component;
        blob.in_size = strlen(last_component) + 1;
        blob.out_size = 0;
-       memset(space, 0, MAXSIZE);
 
        code = pioctl(parent_dir, VIOC_AFS_FLUSHMOUNT, &blob, 1);
 
+       free(last_component);
+       free(parent_dir);
+
        if (code != 0) {
            if (errno == EINVAL) {
                fprintf(stderr, "'%s' is not a mount point.\n", ti->data);
@@ -4177,20 +4211,42 @@ GetFidCmd(struct cmd_syndesc *as, void *arock)
 {
     struct ViceIoctl blob;
     struct cmd_item *ti;
+
+    afs_int32 code;
+    int error = 0;
+    char cell[MAXCELLCHARS];
+
+    SetDotDefault(&as->parms[0].items);
     for (ti = as->parms[0].items; ti; ti = ti->next) {
-      struct VenusFid vfid;
-      
-      blob.out_size = sizeof(struct VenusFid);
-      blob.out = (char *) &vfid;
-      blob.in_size = 0;
-      
-      if (0 == pioctl(ti->data, VIOCGETFID, &blob, 1)) {
-       printf("File %s (%u.%u.%u) contained in volume %u\n",
-              ti->data, vfid.Fid.Volume, vfid.Fid.Vnode, vfid.Fid.Unique,
-              vfid.Fid.Volume);
-      }
+        struct VenusFid vfid;
+
+        blob.out_size = sizeof(struct VenusFid);
+        blob.out = (char *) &vfid;
+        blob.in_size = 0;
+
+        code = pioctl(ti->data, VIOCGETFID, &blob, 1);
+        if (code) {
+            Die(errno,ti->data);
+            error = 1;
+            continue;
+        }
+
+        code = GetCell(ti->data, cell);
+        if (code) {
+           if (errno == ENOENT)
+               fprintf(stderr, "%s: no such cell as '%s'\n", pn, ti->data);
+           else
+               Die(errno, ti->data);
+           error = 1;
+           continue;
+        }
+
+        printf("File %s (%u.%u.%u) located in cell %s\n",
+               ti->data, vfid.Fid.Volume, vfid.Fid.Vnode, vfid.Fid.Unique,
+               cell);
+
     }
 
-    return 0;
+    return error;
 }