volser-restore-timestamp-cleanup-20040728
[openafs.git] / src / volser / vos.c
index a50d8f6..5c4d4e2 100644 (file)
@@ -23,6 +23,7 @@ RCSID
 #include <sys/file.h>
 #include <netdb.h>
 #include <netinet/in.h>
+#include <arpa/inet.h>
 #endif
 #include <sys/stat.h>
 #ifdef AFS_AIX_ENV
@@ -76,9 +77,6 @@ struct tqHead {
     struct tqElem *next;
 };
 
-
-struct hostent *hostutil_GetHostByName(register char *ahost);
-
 #define COMMONPARMS     cmd_Seek(ts, 12);\
 cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");\
 cmd_AddParm(ts, "-noauth", CMD_FLAG, CMD_OPTIONAL, "don't authenticate");\
@@ -94,23 +92,6 @@ struct rx_connection *tconn;
 afs_int32 tserver;
 extern struct ubik_client *cstruct;
 const char *confdir;
-extern struct rx_connection *UV_Bind();
-extern int UV_SetSecurity();
-extern int UV_SetVolumeInfo();
-extern int vsu_SetCrypt();
-extern VL_SetLock();
-extern VL_ReleaseLock();
-extern VL_DeleteEntry();
-extern VL_ListEntry();
-extern VL_GetAddrs();
-extern VL_GetAddrsU();
-extern VL_ChangeAddr();
-
-extern int vsu_ExtractName();
-extern PrintError();
-extern void EnumerateEntry();
-extern void SubEnumerateEntry();
-
 
 static struct tqHead busyHead, notokHead;
 
@@ -518,12 +499,8 @@ DisplayFormat(pntr, server, part, totalOK, totalNotOK, totalBusy, fast,
                fprintf(STDOUT, "    Last Access %s",
                        ctime((time_t *) & pntr->accessDate));
 #endif
-           if (pntr->updateDate < pntr->creationDate)
-               fprintf(STDOUT, "    Last Update %s",
-                       ctime((time_t *) & pntr->creationDate));
-           else
-               fprintf(STDOUT, "    Last Update %s",
-                       ctime((time_t *) & pntr->updateDate));
+           fprintf(STDOUT, "    Last Update %s",
+                   ctime((time_t *) & pntr->updateDate));
            fprintf(STDOUT,
                    "    %d accesses in the past day (i.e., vnode references)\n",
                    pntr->dayUse);
@@ -675,12 +652,8 @@ XDisplayFormat(a_xInfoP, a_servID, a_partID, a_totalOKP, a_totalNotOKP,
                fprintf(STDOUT, "    Last Access %s",
                        ctime((time_t *) & a_xInfoP->accessDate));
 #endif
-           if (a_xInfoP->updateDate < a_xInfoP->creationDate)
-               fprintf(STDOUT, "    Last Update %s",
-                       ctime((time_t *) & a_xInfoP->creationDate));
-           else
-               fprintf(STDOUT, "    Last Update %s",
-                       ctime((time_t *) & a_xInfoP->updateDate));
+           fprintf(STDOUT, "    Last Update %s",
+                   ctime((time_t *) & a_xInfoP->updateDate));
            fprintf(STDOUT,
                    "    %d accesses in the past day (i.e., vnode references)\n",
                    a_xInfoP->dayUse);
@@ -833,6 +806,8 @@ DisplayFormat2(server, partition, pntr)
     if (partition != partition_cache) {
        MapPartIdIntoName(partition, pname);
        partition_cache = partition;
+    } else {
+        pname[0] = '\0';
     }
     fprintf(STDOUT, "name\t\t%s\n", pntr->name);
     fprintf(STDOUT, "id\t\t%lu\n", pntr->volid);
@@ -1149,7 +1124,6 @@ VolumeStats(pntr, entry, server, part, voltype)
      afs_int32 server, part;
 {
     int totalOK, totalNotOK, totalBusy;
-    afs_int32 vcode, vcode2;
 
     DisplayFormat(pntr, server, part, &totalOK, &totalNotOK, &totalBusy, 0, 1,
                  1);
@@ -1577,7 +1551,7 @@ volOffline(register struct cmd_syndesc *as)
 static int
 CreateVolume(register struct cmd_syndesc *as)
 {
-    afs_int32 pname;
+    afs_int32 pnum;
     char part[10];
     afs_int32 volid, code;
     struct nvldbentry entry;
@@ -1591,13 +1565,13 @@ CreateVolume(register struct cmd_syndesc *as)
                as->parms[0].items->data);
        return ENOENT;
     }
-    pname = volutil_GetPartitionID(as->parms[1].items->data);
-    if (pname < 0) {
+    pnum = volutil_GetPartitionID(as->parms[1].items->data);
+    if (pnum < 0) {
        fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
                as->parms[1].items->data);
        return ENOENT;
     }
-    if (!IsPartValid(pname, tserver, &code)) { /*check for validity of the partition */
+    if (!IsPartValid(pnum, tserver, &code)) {  /*check for validity of the partition */
        if (code)
            PrintError("", code);
        else
@@ -1646,13 +1620,13 @@ CreateVolume(register struct cmd_syndesc *as)
     }
 
     code =
-       UV_CreateVolume2(tserver, pname, as->parms[2].items->data, quota, 0,
+       UV_CreateVolume2(tserver, pnum, as->parms[2].items->data, quota, 0,
                         0, 0, 0, &volid);
     if (code) {
        PrintDiagnostics("create", code);
        return code;
     }
-    MapPartIdIntoName(pname, part);
+    MapPartIdIntoName(pnum, part);
     fprintf(STDOUT, "Volume %lu created on partition %s of %s\n",
            (unsigned long)volid, part, as->parms[0].items->data);
 
@@ -1809,7 +1783,8 @@ MoveVolume(as)
      register struct cmd_syndesc *as;
 {
 
-    afs_int32 volid, fromserver, toserver, frompart, topart, code, err;
+    afs_int32 volid, fromserver, toserver, frompart, topart;
+    afs_int32 flags, code, err;
     char fromPartName[10], toPartName[10];
 
     struct diskPartition partition;    /* for space check */
@@ -1867,6 +1842,9 @@ MoveVolume(as)
        return ENOENT;
     }
 
+    flags = 0;
+    if (as->parms[5].items) flags |= RV_NOCLONE;
+
     /*
      * check source partition for space to clone volume
      */
@@ -1914,7 +1892,8 @@ MoveVolume(as)
 
     /* successful move still not guaranteed but shoot for it */
 
-    code = UV_MoveVolume(volid, fromserver, frompart, toserver, topart);
+    code =
+       UV_MoveVolume2(volid, fromserver, frompart, toserver, topart, flags);
     if (code) {
        PrintDiagnostics("move", code);
        return code;
@@ -1932,7 +1911,7 @@ static
 CopyVolume(as)
      register struct cmd_syndesc *as;
 {
-    afs_int32 volid, fromserver, toserver, frompart, topart, code, err;
+    afs_int32 volid, fromserver, toserver, frompart, topart, code, err, flags;
     char fromPartName[10], toPartName[10], *tovolume;
     struct nvldbentry entry;
     struct diskPartition partition;    /* for space check */
@@ -1957,7 +1936,7 @@ CopyVolume(as)
     toserver = GetServer(as->parms[4].items->data);
     if (toserver == 0) {
        fprintf(STDERR, "vos: server '%s' not found in host table\n",
-               as->parms[3].items->data);
+               as->parms[4].items->data);
        return ENOENT;
     }
 
@@ -2005,7 +1984,7 @@ CopyVolume(as)
     topart = volutil_GetPartitionID(as->parms[5].items->data);
     if (topart < 0) {
        fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
-               as->parms[4].items->data);
+               as->parms[5].items->data);
        return EINVAL;
     }
     if (!IsPartValid(topart, toserver, &code)) {       /*check for validity of the partition */
@@ -2014,13 +1993,14 @@ CopyVolume(as)
        else
            fprintf(STDERR,
                    "vos : partition %s does not exist on the server\n",
-                   as->parms[4].items->data);
+                   as->parms[5].items->data);
        return ENOENT;
     }
 
-    /*
-     * check source partition for space to clone volume
-     */
+    flags = 0;
+    if (as->parms[6].items) flags |= RV_OFFLINE;
+    if (as->parms[7].items) flags |= RV_RDONLY;
+    if (as->parms[8].items) flags |= RV_NOCLONE;
 
     MapPartIdIntoName(topart, toPartName);
     MapPartIdIntoName(frompart, fromPartName);
@@ -2059,8 +2039,8 @@ CopyVolume(as)
     /* successful copy still not guaranteed but shoot for it */
 
     code =
-       UV_CopyVolume(volid, fromserver, frompart, tovolume, toserver,
-                     topart);
+       UV_CopyVolume2(volid, fromserver, frompart, tovolume, toserver,
+                      topart, 0, flags);
     if (code) {
        PrintDiagnostics("copy", code);
        return code;
@@ -2076,6 +2056,311 @@ CopyVolume(as)
 
 
 static
+ShadowVolume(as)
+     register struct cmd_syndesc *as;
+{
+    afs_int32 volid, fromserver, toserver, frompart, topart, tovolid;
+    afs_int32 code, err, flags;
+    char fromPartName[10], toPartName[10], toVolName[32], *tovolume;
+    struct nvldbentry entry;
+    struct diskPartition partition;    /* for space check */
+    volintInfo *p, *q;
+
+    p = (volintInfo *) 0;
+    q = (volintInfo *) 0;
+
+    volid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);
+    if (volid == 0) {
+       if (err)
+           PrintError("", err);
+       else
+           fprintf(STDERR, "vos: can't find volume ID or name '%s'\n",
+                   as->parms[0].items->data);
+       return ENOENT;
+    }
+    fromserver = GetServer(as->parms[1].items->data);
+    if (fromserver == 0) {
+       fprintf(STDERR, "vos: server '%s' not found in host table\n",
+               as->parms[1].items->data);
+       return ENOENT;
+    }
+
+    toserver = GetServer(as->parms[3].items->data);
+    if (toserver == 0) {
+       fprintf(STDERR, "vos: server '%s' not found in host table\n",
+               as->parms[3].items->data);
+       return ENOENT;
+    }
+
+    frompart = volutil_GetPartitionID(as->parms[2].items->data);
+    if (frompart < 0) {
+       fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
+               as->parms[2].items->data);
+       return EINVAL;
+    }
+    if (!IsPartValid(frompart, fromserver, &code)) {   /*check for validity of the partition */
+       if (code)
+           PrintError("", code);
+       else
+           fprintf(STDERR,
+                   "vos : partition %s does not exist on the server\n",
+                   as->parms[2].items->data);
+       return ENOENT;
+    }
+
+    topart = volutil_GetPartitionID(as->parms[4].items->data);
+    if (topart < 0) {
+       fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
+               as->parms[4].items->data);
+       return EINVAL;
+    }
+    if (!IsPartValid(topart, toserver, &code)) {       /*check for validity of the partition */
+       if (code)
+           PrintError("", code);
+       else
+           fprintf(STDERR,
+                   "vos : partition %s does not exist on the server\n",
+                   as->parms[4].items->data);
+       return ENOENT;
+    }
+
+    if (as->parms[5].items) {
+       tovolume = as->parms[5].items->data;
+       if (!ISNAMEVALID(tovolume)) {
+           fprintf(STDERR,
+               "vos: the name of the root volume %s exceeds the size limit of %d\n",
+               tovolume, VOLSER_OLDMAXVOLNAME - 10);
+           return E2BIG;
+       }
+       if (!VolNameOK(tovolume)) {
+           fprintf(STDERR,
+               "Illegal volume name %s, should not end in .readonly or .backup\n",
+               tovolume);
+           return EINVAL;
+       }
+       if (IsNumeric(tovolume)) {
+           fprintf(STDERR,
+               "Illegal volume name %s, should not be a number\n",
+               tovolume);
+           return EINVAL;
+       }
+    } else {
+       /* use actual name of source volume */
+       code = UV_ListOneVolume(fromserver, frompart, volid, &p);
+       if (code) {
+           fprintf(STDERR, "vos:cannot access volume %lu\n",
+               (unsigned long)volid);
+           exit(1);
+       }
+       strcpy(toVolName, p->name);
+       tovolume = toVolName;
+       /* save p for size checks later */
+    }
+
+    if (as->parms[6].items) {
+       tovolid = vsu_GetVolumeID(as->parms[6].items->data, cstruct, &err);
+       if (tovolid == 0) {
+           if (err)
+               PrintError("", err);
+           else
+               fprintf(STDERR, "vos: can't find volume ID or name '%s'\n",
+                       as->parms[6].items->data);
+           if (p)
+               free(p);
+           return ENOENT;
+       }
+    } else {
+       tovolid = vsu_GetVolumeID(tovolume, cstruct, &err);
+       if (tovolid == 0) {
+           if (err)
+               PrintError("", err);
+           else
+               fprintf(STDERR, "vos: can't find volume ID or name '%s'\n",
+                       tovolume);
+           if (p)
+               free(p);
+           return ENOENT;
+       }
+    }
+
+    flags = RV_NOVLDB;
+    if (as->parms[7].items) flags |= RV_OFFLINE;
+    if (as->parms[8].items) flags |= RV_RDONLY;
+    if (as->parms[9].items) flags |= RV_NOCLONE;
+    if (as->parms[10].items) flags |= RV_CPINCR;
+
+    MapPartIdIntoName(topart, toPartName);
+    MapPartIdIntoName(frompart, fromPartName);
+
+    /*
+     * check target partition for space to move volume
+     */
+
+    code = UV_PartitionInfo(toserver, toPartName, &partition);
+    if (code) {
+       fprintf(STDERR, "vos: cannot access partition %s\n", toPartName);
+       exit(1);
+    }
+    if (TESTM)
+       fprintf(STDOUT, "target partition %s free space %d\n", toPartName,
+               partition.free);
+
+    /* Don't do this again if we did it above */
+    if (!p) {
+       code = UV_ListOneVolume(fromserver, frompart, volid, &p);
+       if (code) {
+           fprintf(STDERR, "vos:cannot access volume %lu\n",
+               (unsigned long)volid);
+           exit(1);
+       }
+    }
+
+    /* OK if this fails */
+    code = UV_ListOneVolume(toserver, topart, tovolid, &q);
+
+    /* Treat existing volume size as "free" */
+    if (q)
+       p->size = (q->size < p->size) ? p->size - q->size : 0;
+
+    if (partition.free <= p->size) {
+       fprintf(STDERR,
+               "vos: no space on target partition %s to copy volume %lu\n",
+               toPartName, (unsigned long)volid);
+       free(p);
+       if (q) free(q);
+       exit(1);
+    }
+    free(p);
+    if (q) free(q);
+
+    /* successful copy still not guaranteed but shoot for it */
+
+    code =
+       UV_CopyVolume2(volid, fromserver, frompart, tovolume, toserver,
+                      topart, tovolid, flags);
+    if (code) {
+       PrintDiagnostics("shadow", code);
+       return code;
+    }
+    MapPartIdIntoName(topart, toPartName);
+    MapPartIdIntoName(frompart, fromPartName);
+    fprintf(STDOUT, "Volume %lu shadowed from %s %s to %s %s \n",
+           (unsigned long)volid, as->parms[1].items->data, fromPartName,
+           as->parms[4].items->data, toPartName);
+
+    return 0;
+}
+
+
+static
+CloneVolume(as)
+     register struct cmd_syndesc *as;
+{
+    afs_int32 server, part, volid, cloneid, voltype;
+    char partName[10], *volname;
+    afs_int32 code, err, flags;
+    struct nvldbentry entry;
+
+    volid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);
+    if (volid == 0) {
+       if (err)
+           PrintError("", err);
+       else
+           fprintf(STDERR, "vos: can't find volume ID or name '%s'\n",
+                   as->parms[0].items->data);
+       return ENOENT;
+    }
+
+    if (as->parms[1].items || as->parms[2].items) {
+       if (!as->parms[1].items || !as->parms[2].items) {
+           fprintf(STDERR,
+                   "Must specify both -server and -partition options\n");
+           return -1;
+       }
+       server = GetServer(as->parms[1].items->data);
+       if (server == 0) {
+           fprintf(STDERR, "vos: server '%s' not found in host table\n",
+                   as->parms[1].items->data);
+           return ENOENT;
+       }
+       part = volutil_GetPartitionID(as->parms[2].items->data);
+       if (part < 0) {
+           fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
+                   as->parms[2].items->data);
+           return EINVAL;
+       }
+       if (!IsPartValid(part, server, &code)) {        /*check for validity of the partition */
+           if (code)
+               PrintError("", code);
+           else
+               fprintf(STDERR,
+                   "vos : partition %s does not exist on the server\n",
+                   as->parms[2].items->data);
+           return ENOENT;
+        }
+    } else {
+       code = GetVolumeInfo(volid, &server, &part, &voltype, &entry);
+       if (code)
+           return code;
+    }
+
+    volname = 0;
+    if (as->parms[3].items) {
+       volname = as->parms[3].items->data;
+       if (strlen(volname) > VOLSER_OLDMAXVOLNAME - 1) {
+           fprintf(STDERR,
+               "vos: the name of the root volume %s exceeds the size limit of %d\n",
+               volname, VOLSER_OLDMAXVOLNAME - 1);
+           return E2BIG;
+       }
+       if (!VolNameOK(volname)) {
+           fprintf(STDERR,
+               "Illegal volume name %s, should not end in .readonly or .backup\n",
+               volname);
+           return EINVAL;
+       }
+       if (IsNumeric(volname)) {
+           fprintf(STDERR,
+               "Illegal volume name %s, should not be a number\n",
+               volname);
+           return EINVAL;
+       }
+    }
+
+    cloneid = 0;
+    if (as->parms[4].items) {
+       cloneid = vsu_GetVolumeID(as->parms[4].items->data, cstruct, &err);
+       if (cloneid == 0) {
+           if (err)
+               PrintError("", err);
+           else
+               fprintf(STDERR, "vos: can't find volume ID or name '%s'\n",
+                       as->parms[4].items->data);
+           return ENOENT;
+       }
+    }
+
+    flags = 0;
+    if (as->parms[5].items) flags |= RV_OFFLINE;
+    if (as->parms[6].items) flags |= RV_RDONLY;
+
+
+    code = 
+       UV_CloneVolume(server, part, volid, cloneid, volname, flags);
+
+    if (code) {
+       PrintDiagnostics("clone", code);
+       return code;
+    }
+    MapPartIdIntoName(part, partName);
+    fprintf(STDOUT, "Created clone for volume %lu\n",
+           as->parms[0].items->data);
+
+    return 0;
+}
+
+
+static
 BackupVolume(as)
      register struct cmd_syndesc *as;
 {
@@ -2084,9 +2369,6 @@ BackupVolume(as)
 
     afs_int32 buvolid, buserver, bupart, butype;
     struct nvldbentry buentry;
-    struct rx_connection *conn;
-    volEntries volInfo;
-    struct nvldbentry store;
 
     avolid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);
     if (avolid == 0) {
@@ -2285,6 +2567,10 @@ DumpVolume(as)
 #define FULL  2
 #define INC   3
 
+#define TS_DUMP        1
+#define TS_KEEP        2
+#define TS_NEW 3
+
 static
 RestoreVolume(as)
      register struct cmd_syndesc *as;
@@ -2292,6 +2578,7 @@ RestoreVolume(as)
 {
     afs_int32 avolid, aserver, apart, code, vcode, err;
     afs_int32 aoverwrite = ASK;
+    afs_int32 acreation = 0, alastupdate = 0;
     int restoreflags, readonly = 0, offline = 0, voltype = RWVOL;
     char prompt;
     char afilename[NameLen], avolname[VOLSER_MAXVOLNAME + 1], apartName[10];
@@ -2338,6 +2625,40 @@ RestoreVolume(as)
        voltype = ROVOL;
     }
 
+    if (as->parms[8].items) {
+       if ((strcmp(as->parms[8].items->data, "d") == 0)
+           || (strcmp(as->parms[8].items->data, "dump") == 0)) {
+           acreation = TS_DUMP;
+       } else if ((strcmp(as->parms[8].items->data, "k") == 0)
+           || (strcmp(as->parms[8].items->data, "keep") == 0)) {
+           acreation = TS_KEEP;
+       } else if ((strcmp(as->parms[8].items->data, "n") == 0)
+           || (strcmp(as->parms[8].items->data, "new") == 0)) {
+           acreation = TS_NEW;
+       } else {
+           fprintf(STDERR, "vos: %s is not a valid argument to -creation\n",
+                   as->parms[8].items->data);
+           exit(1);
+       }
+    }
+
+    if (as->parms[9].items) {
+       if ((strcmp(as->parms[9].items->data, "d") == 0)
+           || (strcmp(as->parms[9].items->data, "dump") == 0)) {
+           alastupdate = TS_DUMP;
+       } else if ((strcmp(as->parms[9].items->data, "k") == 0)
+           || (strcmp(as->parms[9].items->data, "keep") == 0)) {
+           alastupdate = TS_KEEP;
+       } else if ((strcmp(as->parms[9].items->data, "n") == 0)
+           || (strcmp(as->parms[9].items->data, "new") == 0)) {
+           alastupdate = TS_NEW;
+       } else {
+           fprintf(STDERR, "vos: %s is not a valid argument to -lastupdate\n",
+                   as->parms[9].items->data);
+           exit(1);
+       }
+    }
+
     aserver = GetServer(as->parms[0].items->data);
     if (aserver == 0) {
        fprintf(STDERR, "vos: server '%s' not found in host table\n",
@@ -2489,6 +2810,38 @@ RestoreVolume(as)
        restoreflags |= RV_OFFLINE;
     if (readonly)
        restoreflags |= RV_RDONLY;
+
+    switch (acreation) {
+       case TS_DUMP:
+           restoreflags |= RV_CRDUMP;
+           break;
+       case TS_KEEP:
+           restoreflags |= RV_CRKEEP;
+           break;
+       case TS_NEW:
+           restoreflags |= RV_CRNEW;
+           break;
+       default:
+           if (aoverwrite == FULL)
+               restoreflags |= RV_CRNEW;
+           else
+               restoreflags |= RV_CRKEEP;
+    }
+
+    switch (alastupdate) {
+       case TS_DUMP:
+           restoreflags |= RV_LUDUMP;
+           break;
+       case TS_KEEP:
+           restoreflags |= RV_LUKEEP;
+           break;
+       case TS_NEW:
+           restoreflags |= RV_LUNEW;
+           break;
+       default:
+           restoreflags |= RV_LUKEEP;
+    }
+
     code =
        UV_RestoreVolume(aserver, apart, avolid, avolname, restoreflags,
                         WriteData, afilename);
@@ -3003,7 +3356,7 @@ static
 SyncVldb(as)
      register struct cmd_syndesc *as;
 {
-    afs_int32 pname, code;     /* part name */
+    afs_int32 pnum, code;      /* part name */
     char part[10];
     int flags = 0;
     char *volname = 0;
@@ -3019,13 +3372,13 @@ SyncVldb(as)
     }
 
     if (as->parms[1].items) {
-       pname = volutil_GetPartitionID(as->parms[1].items->data);
-       if (pname < 0) {
+       pnum = volutil_GetPartitionID(as->parms[1].items->data);
+       if (pnum < 0) {
            fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
                    as->parms[1].items->data);
            exit(1);
        }
-       if (!IsPartValid(pname, tserver, &code)) {      /*check for validity of the partition */
+       if (!IsPartValid(pnum, tserver, &code)) {       /*check for validity of the partition */
            if (code)
                PrintError("", code);
            else
@@ -3046,14 +3399,14 @@ SyncVldb(as)
     if (as->parms[2].items) {
        /* Synchronize an individual volume */
        volname = as->parms[2].items->data;
-       code = UV_SyncVolume(tserver, pname, volname, flags);
+       code = UV_SyncVolume(tserver, pnum, volname, flags);
     } else {
        if (!tserver) {
            fprintf(STDERR,
                    "Without a -volume option, the -server option is required\n");
            exit(1);
        }
-       code = UV_SyncVldb(tserver, pname, flags, 0 /*unused */ );
+       code = UV_SyncVldb(tserver, pnum, flags, 0 /*unused */ );
     }
 
     if (code) {
@@ -3070,7 +3423,7 @@ SyncVldb(as)
        fprintf(STDOUT, " with state of server %s", as->parms[0].items->data);
     }
     if (flags) {
-       MapPartIdIntoName(pname, part);
+       MapPartIdIntoName(pnum, part);
        fprintf(STDOUT, " partition %s\n", part);
     }
     fprintf(STDOUT, "\n");
@@ -3083,7 +3436,7 @@ SyncServer(as)
      register struct cmd_syndesc *as;
 
 {
-    afs_int32 pname, code;     /* part name */
+    afs_int32 pnum, code;      /* part name */
     char part[10];
 
     int flags = 0;
@@ -3095,13 +3448,13 @@ SyncServer(as)
        exit(1);
     }
     if (as->parms[1].items) {
-       pname = volutil_GetPartitionID(as->parms[1].items->data);
-       if (pname < 0) {
+       pnum = volutil_GetPartitionID(as->parms[1].items->data);
+       if (pnum < 0) {
            fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
                    as->parms[1].items->data);
            exit(1);
        }
-       if (!IsPartValid(pname, tserver, &code)) {      /*check for validity of the partition */
+       if (!IsPartValid(pnum, tserver, &code)) {       /*check for validity of the partition */
            if (code)
                PrintError("", code);
            else
@@ -3111,15 +3464,17 @@ SyncServer(as)
            exit(1);
        }
        flags = 1;
+    } else {
+        pnum = -1;
     }
 
-    code = UV_SyncServer(tserver, pname, flags, 0 /*unused */ );
+    code = UV_SyncServer(tserver, pnum, flags, 0 /*unused */ );
     if (code) {
        PrintDiagnostics("syncserv", code);
        exit(1);
     }
     if (flags) {
-       MapPartIdIntoName(pname, part);
+       MapPartIdIntoName(pnum, part);
        fprintf(STDOUT, "Server %s partition %s synchronized with VLDB\n",
                as->parms[0].items->data, part);
     } else
@@ -3452,6 +3807,10 @@ GetVolumeInfo(volid, server, part, voltype, rentry)
        *part = rentry->serverPartition[index];
        return 0;
     }
+    fprintf(STDERR,
+            "unexpected volume type for volume %lu\n",
+            (unsigned long)volid);
+    return -1;
 }
 
 static
@@ -3868,7 +4227,6 @@ BackSys(as)
     afs_int32 totalFail = 0;
     int previdx = -1, error, same;
     int comp = 0;
-    char compstr[50];
     struct cmd_item *ti;
     char *ccode;
     int match;
@@ -4416,11 +4774,11 @@ print_addrs(const bulkaddrs * addrs, const afsUUID * m_uuid, int nentries,
 {
     afs_int32 vcode;
     afs_int32 i, j;
-    struct VLCallBack unused;
+    struct VLCallBack vlcb;
     afs_int32 *addrp;
     bulkaddrs m_addrs;
     ListAddrByAttributes m_attrs;
-    afs_int32 m_unique, m_nentries, *m_addrp;
+    afs_int32 m_nentries, *m_addrp;
     afs_int32 base, index;
     char buf[1024];
 
@@ -4450,7 +4808,7 @@ print_addrs(const bulkaddrs * addrs, const afsUUID * m_uuid, int nentries,
                m_addrs.bulkaddrs_len = 0;
                vcode =
                    ubik_Call(VL_GetAddrsU, cstruct, 0, &m_attrs, &m_uuid,
-                             &m_unique, &m_nentries, &m_addrs);
+                             &vlcb, &m_nentries, &m_addrs);
                if (vcode) {
                    fprintf(STDERR,
                            "vos: could not list the multi-homed server addresses\n");
@@ -4501,14 +4859,13 @@ ListAddrs(as)
      register struct cmd_syndesc *as;
 {
     afs_int32 vcode;
-    afs_int32 i, j, noresolve = 0, printuuid = 0;
-    struct VLCallBack unused;
-    afs_int32 nentries, *addrp;
-    bulkaddrs addrs, m_addrs;
+    afs_int32 i, noresolve = 0, printuuid = 0;
+    struct VLCallBack vlcb;
+    afs_int32 nentries;
+    bulkaddrs m_addrs;
     ListAddrByAttributes m_attrs;
     afsUUID m_uuid, askuuid;
-    afs_int32 m_unique, m_nentries, *m_addrp;
-    afs_int32 base, index;
+    afs_int32 m_nentries;
 
     memset(&m_attrs, 0, sizeof(struct ListAddrByAttributes));
     m_attrs.Mask = VLADDR_INDEX;
@@ -4546,7 +4903,7 @@ ListAddrs(as)
     m_addrs.bulkaddrs_len = 0;
 
     vcode =
-       ubik_Call_New(VL_GetAddrs, cstruct, 0, 0, 0, &m_unique, &nentries,
+       ubik_Call_New(VL_GetAddrs, cstruct, 0, 0, 0, &vlcb, &nentries,
                      &m_addrs);
     if (vcode) {
        fprintf(STDERR, "vos: could not list the server addresses\n");
@@ -4563,7 +4920,7 @@ ListAddrs(as)
 
        vcode =
            ubik_Call_New(VL_GetAddrsU, cstruct, 0, &m_attrs, &m_uuid,
-                         &m_unique, &m_nentries, &m_addrs);
+                         &vlcb, &m_nentries, &m_addrs);
        if (vcode == VL_NOENT) {
            i++;
            nentries++;
@@ -4985,6 +5342,8 @@ main(argc, argv)
                "machine name on destination");
     cmd_AddParm(ts, "-topartition", CMD_SINGLE, 0,
                "partition name on destination");
+    cmd_AddParm(ts, "-live", CMD_FLAG, CMD_OPTIONAL,
+               "copy live volume without cloning");
     COMMONPARMS;
 
     ts = cmd_CreateSyntax("copy", CopyVolume, 0, "copy a volume");
@@ -4997,6 +5356,36 @@ main(argc, argv)
                "machine name on destination");
     cmd_AddParm(ts, "-topartition", CMD_SINGLE, 0,
                "partition name on destination");
+    cmd_AddParm(ts, "-offline", CMD_FLAG, CMD_OPTIONAL,
+               "leave new volume offline");
+    cmd_AddParm(ts, "-readonly", CMD_FLAG, CMD_OPTIONAL,
+               "make new volume read-only");
+    cmd_AddParm(ts, "-live", CMD_FLAG, CMD_OPTIONAL,
+               "copy live volume without cloning");
+    COMMONPARMS;
+
+    ts = cmd_CreateSyntax("shadow", ShadowVolume, 0,
+                         "make or update a shadow volume");
+    cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID on source");
+    cmd_AddParm(ts, "-fromserver", CMD_SINGLE, 0, "machine name on source");
+    cmd_AddParm(ts, "-frompartition", CMD_SINGLE, 0,
+               "partition name on source");
+    cmd_AddParm(ts, "-toserver", CMD_SINGLE, 0,
+               "machine name on destination");
+    cmd_AddParm(ts, "-topartition", CMD_SINGLE, 0,
+               "partition name on destination");
+    cmd_AddParm(ts, "-toname", CMD_SINGLE, CMD_OPTIONAL,
+               "volume name on destination");
+    cmd_AddParm(ts, "-toid", CMD_SINGLE, CMD_OPTIONAL,
+               "volume ID on destination");
+    cmd_AddParm(ts, "-offline", CMD_FLAG, CMD_OPTIONAL,
+               "leave shadow volume offline");
+    cmd_AddParm(ts, "-readonly", CMD_FLAG, CMD_OPTIONAL,
+               "make shadow volume read-only");
+    cmd_AddParm(ts, "-live", CMD_FLAG, CMD_OPTIONAL,
+               "copy live volume without cloning");
+    cmd_AddParm(ts, "-incremental", CMD_FLAG, CMD_OPTIONAL,
+               "do incremental update if target exists");
     COMMONPARMS;
 
     ts = cmd_CreateSyntax("backup", BackupVolume, 0,
@@ -5004,6 +5393,21 @@ main(argc, argv)
     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
     COMMONPARMS;
 
+    ts = cmd_CreateSyntax("clone", CloneVolume, 0,
+                         "make clone of a volume");
+    cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
+    cmd_AddParm(ts, "-server", CMD_SINGLE, CMD_OPTIONAL, "server");
+    cmd_AddParm(ts, "-partition", CMD_SINGLE, CMD_OPTIONAL, "partition");
+    cmd_AddParm(ts, "-toname", CMD_SINGLE, CMD_OPTIONAL,
+               "volume name on destination");
+    cmd_AddParm(ts, "-toid", CMD_SINGLE, CMD_OPTIONAL,
+               "volume ID on destination");
+    cmd_AddParm(ts, "-offline", CMD_FLAG, CMD_OPTIONAL,
+               "leave clone volume offline");
+    cmd_AddParm(ts, "-readonly", CMD_FLAG, CMD_OPTIONAL,
+               "make clone volume read-only, not readwrite");
+    COMMONPARMS;
+
     ts = cmd_CreateSyntax("release", ReleaseVolume, 0, "release a volume");
     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
     cmd_AddParm(ts, "-force", CMD_FLAG, CMD_OPTIONAL,
@@ -5032,6 +5436,10 @@ main(argc, argv)
                "leave restored volume offline");
     cmd_AddParm(ts, "-readonly", CMD_FLAG, CMD_OPTIONAL,
                "make restored volume read-only");
+    cmd_AddParm(ts, "-creation", CMD_SINGLE, CMD_OPTIONAL,
+               "dump | keep | new");
+    cmd_AddParm(ts, "-lastupdate", CMD_SINGLE, CMD_OPTIONAL,
+               "dump | keep | new");
     COMMONPARMS;
 
     ts = cmd_CreateSyntax("unlock", LockReleaseCmd, 0,