4c15cc8dcc479e7460eac517268c4ece486dd65c
[openafs.git] / src / volser / vos.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12
13
14 #include <sys/types.h>
15 #include <string.h>
16 #ifdef AFS_NT40_ENV
17 #include <fcntl.h>
18 #include <io.h>
19 #include <winsock2.h>
20 #else
21 #include <sys/time.h>
22 #include <sys/file.h>
23 #include <netdb.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
26 #endif
27 #include <sys/stat.h>
28 #ifdef AFS_AIX_ENV
29 #include <sys/statfs.h>
30 #endif
31 #include <errno.h>
32
33 #include <lock.h>
34 #include <afs/stds.h>
35 #include <rx/xdr.h>
36 #include <rx/rx.h>
37 #include <rx/rx_globals.h>
38 #include <afs/nfs.h>
39 #include <afs/vlserver.h>
40 #include <afs/cellconfig.h>
41 #include <afs/keys.h>
42 #include <afs/afsutil.h>
43 #include <ubik.h>
44 #include <afs/afsint.h>
45 #include <afs/cmd.h>
46 #include <afs/usd.h>
47 #include "volser.h"
48 #include "volint.h"
49 #include <afs/ihandle.h>
50 #include <afs/vnode.h>
51 #include <afs/volume.h>
52 #include "dump.h"
53 #include "lockdata.h"
54
55 #ifdef  AFS_AIX32_ENV
56 #include <signal.h>
57 #endif
58 #include "volser_prototypes.h"
59 #include "vsutils_prototypes.h"
60 #include "lockprocs_prototypes.h"
61
62 #ifdef HAVE_POSIX_REGEX
63 #include <regex.h>
64 #endif
65
66 /* Local Prototypes */
67 int PrintDiagnostics(char *astring, afs_int32 acode);
68 int GetVolumeInfo(afs_uint32 volid, afs_int32 *server, afs_int32 *part, 
69                   afs_int32 *voltype, struct nvldbentry *rentry);
70
71 struct tqElem {
72     afs_uint32 volid;
73     struct tqElem *next;
74 };
75
76 struct tqHead {
77     afs_int32 count;
78     struct tqElem *next;
79 };
80
81 #define COMMONPARMS     cmd_Seek(ts, 12);\
82 cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");\
83 cmd_AddParm(ts, "-noauth", CMD_FLAG, CMD_OPTIONAL, "don't authenticate");\
84 cmd_AddParm(ts, "-localauth",CMD_FLAG,CMD_OPTIONAL,"use server tickets");\
85 cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, "verbose");\
86 cmd_AddParm(ts, "-encrypt", CMD_FLAG, CMD_OPTIONAL, "encrypt commands");\
87 cmd_AddParm(ts, "-noresolve", CMD_FLAG, CMD_OPTIONAL, "don't resolve addresses"); \
88
89 #define ERROR_EXIT(code) {error=(code); goto error_exit;}
90
91 int rxInitDone = 0;
92 struct rx_connection *tconn;
93 afs_int32 tserver;
94 extern struct ubik_client *cstruct;
95 const char *confdir;
96
97 static struct tqHead busyHead, notokHead;
98
99 static void
100 qInit(struct tqHead *ahead)
101 {
102     memset((char *)ahead, 0, sizeof(struct tqHead));
103     return;
104 }
105
106
107 static void
108 qPut(struct tqHead *ahead, afs_uint32 volid)
109 {
110     struct tqElem *elem;
111
112     elem = (struct tqElem *)malloc(sizeof(struct tqElem));
113     elem->next = ahead->next;
114     elem->volid = volid;
115     ahead->next = elem;
116     ahead->count++;
117     return;
118 }
119
120 static void
121 qGet(struct tqHead *ahead, afs_uint32 *volid)
122 {
123     struct tqElem *tmp;
124
125     if (ahead->count <= 0)
126         return;
127     *volid = ahead->next->volid;
128     tmp = ahead->next;
129     ahead->next = tmp->next;
130     ahead->count--;
131     free(tmp);
132     return;
133 }
134
135 /* returns 1 if <filename> exists else 0 */
136 static int
137 FileExists(char *filename)
138 {
139     usd_handle_t ufd;
140     int code;
141     afs_hyper_t size;
142
143     code = usd_Open(filename, USD_OPEN_RDONLY, 0, &ufd);
144     if (code) {
145         return 0;
146     }
147     code = USD_IOCTL(ufd, USD_IOCTL_GETSIZE, &size);
148     USD_CLOSE(ufd);
149     if (code) {
150         return 0;
151     }
152     return 1;
153 }
154
155 /* returns 1 if <name> doesnot end in .readonly or .backup, else 0 */
156 static int
157 VolNameOK(char *name)
158 {
159     int total;
160
161
162     total = strlen(name);
163     if (!strcmp(&name[total - 9], ".readonly")) {
164         return 0;
165     } else if (!strcmp(&name[total - 7], ".backup")) {
166         return 0;
167     } else {
168         return 1;
169     }
170 }
171
172 /* return 1 if name is a number else 0 */
173 static int
174 IsNumeric(char *name)
175 {
176     int result, len, i;
177     char *ptr;
178
179     result = 1;
180     ptr = name;
181     len = strlen(name);
182     for (i = 0; i < len; i++) {
183         if (*ptr < '0' || *ptr > '9') {
184             result = 0;
185             break;
186         }
187         ptr++;
188
189     }
190     return result;
191 }
192
193
194 /*
195  * Parse a server name/address and return the address in HOST BYTE order
196  */
197 afs_int32
198 GetServer(char *aname)
199 {
200     register struct hostent *th;
201     afs_int32 addr;
202     int b1, b2, b3, b4;
203     register afs_int32 code;
204     char hostname[MAXHOSTCHARS];
205
206     code = sscanf(aname, "%d.%d.%d.%d", &b1, &b2, &b3, &b4);
207     if (code == 4) {
208         addr = (b1 << 24) | (b2 << 16) | (b3 << 8) | b4;
209         addr = ntohl(addr);     /* convert to host order */
210     } else {
211         th = gethostbyname(aname);
212         if (!th)
213             return 0;
214         memcpy(&addr, th->h_addr, sizeof(addr));
215     }
216
217     if (addr == htonl(0x7f000001)) {    /* local host */
218         code = gethostname(hostname, MAXHOSTCHARS);
219         if (code)
220             return 0;
221         th = gethostbyname(hostname);   /* returns host byte order */
222         if (!th)
223             return 0;
224         memcpy(&addr, th->h_addr, sizeof(addr));
225     }
226
227     return (addr);
228 }
229
230 afs_int32
231 GetVolumeType(char *aname)
232 {
233
234     if (!strcmp(aname, "ro"))
235         return (ROVOL);
236     else if (!strcmp(aname, "rw"))
237         return (RWVOL);
238     else if (!strcmp(aname, "bk"))
239         return (BACKVOL);
240     else
241         return (-1);
242 }
243
244 int
245 IsPartValid(afs_int32 partId, afs_int32 server, afs_int32 *code)
246 {
247     struct partList dummyPartList;
248     int i, success, cnt;
249
250     success = 0;
251     *code = 0;
252
253     *code = UV_ListPartitions(server, &dummyPartList, &cnt);
254     if (*code)
255         return success;
256     for (i = 0; i < cnt; i++) {
257         if (dummyPartList.partFlags[i] & PARTVALID)
258             if (dummyPartList.partId[i] == partId)
259                 success = 1;
260     }
261     return success;
262 }
263
264
265
266  /*sends the contents of file associated with <fd> and <blksize>  to Rx Stream 
267   * associated  with <call> */
268 int 
269 SendFile(usd_handle_t ufd, register struct rx_call *call, long blksize)
270 {
271     char *buffer = (char *)0;
272     afs_int32 error = 0;
273     int done = 0;
274     afs_uint32 nbytes;
275
276     buffer = (char *)malloc(blksize);
277     if (!buffer) {
278         fprintf(STDERR, "malloc failed\n");
279         return -1;
280     }
281
282     while (!error && !done) {
283 #ifndef AFS_NT40_ENV            /* NT csn't select on non-socket fd's */
284         fd_set in;
285         FD_ZERO(&in);
286         FD_SET((int)(ufd->handle), &in);
287         /* don't timeout if read blocks */
288 #if defined(AFS_PTHREAD_ENV)
289         select(((int)(ufd->handle)) + 1, &in, 0, 0, 0);
290 #else
291         IOMGR_Select(((int)(ufd->handle)) + 1, &in, 0, 0, 0);
292 #endif
293 #endif
294         error = USD_READ(ufd, buffer, blksize, &nbytes);
295         if (error) {
296             fprintf(STDERR, "File system read failed\n");
297             break;
298         }
299         if (nbytes == 0) {
300             done = 1;
301             break;
302         }
303         if (rx_Write(call, buffer, nbytes) != nbytes) {
304             error = -1;
305             break;
306         }
307     }
308     if (buffer)
309         free(buffer);
310     return error;
311 }
312
313 /* function invoked by UV_RestoreVolume, reads the data from rx_trx_stream and
314  * writes it out to the volume. */
315 afs_int32
316 WriteData(struct rx_call *call, void *rock)
317 {
318     char *filename = (char *) rock;
319     usd_handle_t ufd;
320     long blksize;
321     afs_int32 error, code;
322     int ufdIsOpen = 0;
323     afs_hyper_t filesize, currOffset; 
324     afs_uint32 buffer;          
325     afs_uint32 got;             
326
327     error = 0;
328
329     if (!filename || !*filename) {
330         usd_StandardInput(&ufd);
331         blksize = 4096;
332         ufdIsOpen = 1;
333     } else {
334         code = usd_Open(filename, USD_OPEN_RDONLY, 0, &ufd);
335         if (code == 0) {
336             ufdIsOpen = 1;
337             code = USD_IOCTL(ufd, USD_IOCTL_GETBLKSIZE, &blksize);
338         }
339         if (code) {
340             fprintf(STDERR, "Could not access file '%s'\n", filename);
341             error = VOLSERBADOP;
342             goto wfail;
343         }
344         /* test if we have a valid dump */
345         hset64(filesize, 0, 0);
346         USD_SEEK(ufd, filesize, SEEK_END, &currOffset);
347         hset64(filesize, hgethi(currOffset), hgetlo(currOffset)-sizeof(afs_uint32));
348         USD_SEEK(ufd, filesize, SEEK_SET, &currOffset);
349         USD_READ(ufd, (char *)&buffer, sizeof(afs_uint32), &got);
350         if ((got != sizeof(afs_uint32)) || (ntohl(buffer) != DUMPENDMAGIC)) {
351             fprintf(STDERR, "Signature missing from end of file '%s'\n", filename);
352             error = VOLSERBADOP;
353             goto wfail;
354         }
355         /* rewind, we are done */
356         hset64(filesize, 0, 0);
357         USD_SEEK(ufd, filesize, SEEK_SET, &currOffset);
358     }
359     code = SendFile(ufd, call, blksize);
360     if (code) {
361         error = code;
362         goto wfail;
363     }
364   wfail:
365     if (ufdIsOpen) {
366         code = USD_CLOSE(ufd);
367         if (code) {
368             fprintf(STDERR, "Could not close dump file %s\n",
369                     (filename && *filename) ? filename : "STDOUT");
370             if (!error)
371                 error = code;
372         }
373     }
374     return error;
375 }
376
377 /* Receive data from <call> stream into file associated
378  * with <fd> <blksize>
379  */
380 int
381 ReceiveFile(usd_handle_t ufd, struct rx_call *call, long blksize)
382 {
383     char *buffer = NULL;
384     afs_int32 bytesread;
385     afs_uint32 bytesleft, w;
386     afs_int32 error = 0;
387
388     buffer = (char *)malloc(blksize);
389     if (!buffer) {
390         fprintf(STDERR, "memory allocation failed\n");
391         ERROR_EXIT(-1);
392     }
393
394     while ((bytesread = rx_Read(call, buffer, blksize)) > 0) {
395         for (bytesleft = bytesread; bytesleft; bytesleft -= w) {
396 #ifndef AFS_NT40_ENV            /* NT csn't select on non-socket fd's */
397             fd_set out;
398             FD_ZERO(&out);
399             FD_SET((int)(ufd->handle), &out);
400             /* don't timeout if write blocks */
401 #if defined(AFS_PTHREAD_ENV)
402             select(((int)(ufd->handle)) + 1, &out, 0, 0, 0);
403 #else
404             IOMGR_Select(((int)(ufd->handle)) + 1, 0, &out, 0, 0);
405 #endif
406 #endif
407             error =
408                 USD_WRITE(ufd, &buffer[bytesread - bytesleft], bytesleft, &w);
409             if (error) {
410                 fprintf(STDERR, "File system write failed\n");
411                 ERROR_EXIT(-1);
412             }
413         }
414     }
415
416   error_exit:
417     if (buffer)
418         free(buffer);
419     return (error);
420 }
421
422 afs_int32
423 DumpFunction(struct rx_call *call, void *rock)
424 {
425     char *filename = (char *)rock;
426     usd_handle_t ufd;           /* default is to stdout */
427     afs_int32 error = 0, code;
428     afs_hyper_t size;
429     long blksize;
430     int ufdIsOpen = 0;
431
432     /* Open the output file */
433     if (!filename || !*filename) {
434         usd_StandardOutput(&ufd);
435         blksize = 4096;
436         ufdIsOpen = 1;
437     } else {
438         code =
439             usd_Open(filename, USD_OPEN_CREATE | USD_OPEN_RDWR, 0666, &ufd);
440         if (code == 0) {
441             ufdIsOpen = 1;
442             hzero(size);
443             code = USD_IOCTL(ufd, USD_IOCTL_SETSIZE, &size);
444         }
445         if (code == 0) {
446             code = USD_IOCTL(ufd, USD_IOCTL_GETBLKSIZE, &blksize);
447         }
448         if (code) {
449             fprintf(STDERR, "Could not create file '%s'\n", filename);
450             ERROR_EXIT(VOLSERBADOP);
451         }
452     }
453
454     code = ReceiveFile(ufd, call, blksize);
455     if (code)
456         ERROR_EXIT(code);
457
458   error_exit:
459     /* Close the output file */
460     if (ufdIsOpen) {
461         code = USD_CLOSE(ufd);
462         if (code) {
463             fprintf(STDERR, "Could not close dump file %s\n",
464                     (filename && *filename) ? filename : "STDIN");
465             if (!error)
466                 error = code;
467         }
468     }
469
470     return (error);
471 }
472
473 static char *
474 vos_ctime(afs_int32 *timep)
475 {
476     time_t foo = *timep;
477     return ctime(&foo);
478 }
479
480 static void
481 DisplayFormat(volintInfo *pntr, afs_int32 server, afs_int32 part,
482               int *totalOK, int *totalNotOK, int *totalBusy, int fast,
483               int longlist, int disp)
484 {
485     char pname[10];
486
487     if (fast) {
488         fprintf(STDOUT, "%-10lu\n", (unsigned long)pntr->volid);
489     } else if (longlist) {
490         if (pntr->status == VOK) {
491             fprintf(STDOUT, "%-32s ", pntr->name);
492             fprintf(STDOUT, "%10lu ", (unsigned long)pntr->volid);
493             if (pntr->type == 0)
494                 fprintf(STDOUT, "RW ");
495             if (pntr->type == 1)
496                 fprintf(STDOUT, "RO ");
497             if (pntr->type == 2)
498                 fprintf(STDOUT, "BK ");
499             fprintf(STDOUT, "%10d K  ", pntr->size);
500             if (pntr->inUse == 1) {
501                 fprintf(STDOUT, "On-line");
502                 *totalOK += 1;
503             } else {
504                 fprintf(STDOUT, "Off-line");
505                 *totalNotOK += 1;
506             }
507             if (pntr->needsSalvaged == 1)
508                 fprintf(STDOUT, "**needs salvage**");
509             fprintf(STDOUT, "\n");
510             MapPartIdIntoName(part, pname);
511             fprintf(STDOUT, "    %s %s \n", hostutil_GetNameByINet(server),
512                     pname);
513             fprintf(STDOUT, "    RWrite %10lu ROnly %10lu Backup %10lu \n",
514                     (unsigned long)pntr->parentID,
515                     (unsigned long)pntr->cloneID,
516                     (unsigned long)pntr->backupID);
517             fprintf(STDOUT, "    MaxQuota %10d K \n", pntr->maxquota);
518             fprintf(STDOUT, "    Creation    %s",
519                     vos_ctime(& pntr->creationDate));
520 #ifdef FULL_LISTVOL_SWITCH
521             fprintf(STDOUT, "    Copy        %s",
522                     vos_ctime( & pntr->copyDate));
523             if (!pntr->backupDate)
524                 fprintf(STDOUT, "    Backup      Never\n");
525             else
526                 fprintf(STDOUT, "    Backup      %s",
527                         vos_ctime( & pntr->backupDate));
528             if (pntr->accessDate)
529                 fprintf(STDOUT, "    Last Access %s",
530                         vos_ctime( & pntr->accessDate));
531 #endif
532             if (!pntr->updateDate)
533                 fprintf(STDOUT, "    Last Update Never\n");
534             else
535                 fprintf(STDOUT, "    Last Update %s",
536                         vos_ctime( & pntr->updateDate));
537             fprintf(STDOUT,
538                     "    %d accesses in the past day (i.e., vnode references)\n",
539                     pntr->dayUse);
540         } else if (pntr->status == VBUSY) {
541             *totalBusy += 1;
542             qPut(&busyHead, pntr->volid);
543             if (disp)
544                 fprintf(STDOUT, "**** Volume %lu is busy ****\n",
545                         (unsigned long)pntr->volid);
546         } else {
547             *totalNotOK += 1;
548             qPut(&notokHead, pntr->volid);
549             if (disp)
550                 fprintf(STDOUT, "**** Could not attach volume %lu ****\n",
551                         (unsigned long)pntr->volid);
552         }
553         fprintf(STDOUT, "\n");
554     } else {                    /* default listing */
555         if (pntr->status == VOK) {
556             fprintf(STDOUT, "%-32s ", pntr->name);
557             fprintf(STDOUT, "%10lu ", (unsigned long)pntr->volid);
558             if (pntr->type == 0)
559                 fprintf(STDOUT, "RW ");
560             if (pntr->type == 1)
561                 fprintf(STDOUT, "RO ");
562             if (pntr->type == 2)
563                 fprintf(STDOUT, "BK ");
564             fprintf(STDOUT, "%10d K ", pntr->size);
565             if (pntr->inUse == 1) {
566                 fprintf(STDOUT, "On-line");
567                 *totalOK += 1;
568             } else {
569                 fprintf(STDOUT, "Off-line");
570                 *totalNotOK += 1;
571             }
572             if (pntr->needsSalvaged == 1)
573                 fprintf(STDOUT, "**needs salvage**");
574             fprintf(STDOUT, "\n");
575         } else if (pntr->status == VBUSY) {
576             *totalBusy += 1;
577             qPut(&busyHead, pntr->volid);
578             if (disp)
579                 fprintf(STDOUT, "**** Volume %lu is busy ****\n",
580                         (unsigned long)pntr->volid);
581         } else {
582             *totalNotOK += 1;
583             qPut(&notokHead, pntr->volid);
584             if (disp)
585                 fprintf(STDOUT, "**** Could not attach volume %lu ****\n",
586                         (unsigned long)pntr->volid);
587         }
588     }
589 }
590
591 /*------------------------------------------------------------------------
592  * PRIVATE XDisplayFormat
593  *
594  * Description:
595  *      Display the contents of one extended volume info structure.
596  *
597  * Arguments:
598  *      a_xInfoP        : Ptr to extended volume info struct to print.
599  *      a_servID        : Server ID to print.
600  *      a_partID        : Partition ID to print.
601  *      a_totalOKP      : Ptr to total-OK counter.
602  *      a_totalNotOKP   : Ptr to total-screwed counter.
603  *      a_totalBusyP    : Ptr to total-busy counter.
604  *      a_fast          : Fast listing?
605  *      a_int32         : Int32 listing?
606  *      a_showProblems  : Show volume problems?
607  *
608  * Returns:
609  *      Nothing.
610  *
611  * Environment:
612  *      Nothing interesting.
613  *
614  * Side Effects:
615  *      As advertised.
616  *------------------------------------------------------------------------*/
617
618 static void
619 XDisplayFormat(volintXInfo *a_xInfoP, afs_int32 a_servID, afs_int32 a_partID,
620                int *a_totalOKP, int *a_totalNotOKP, int *a_totalBusyP,
621                int a_fast, int a_int32, int a_showProblems)
622 {                               /*XDisplayFormat */
623
624     char pname[10];
625
626     if (a_fast) {
627         /*
628          * Short & sweet.
629          */
630         fprintf(STDOUT, "%-10lu\n", (unsigned long)a_xInfoP->volid);
631     } else if (a_int32) {
632         /*
633          * Fully-detailed listing.
634          */
635         if (a_xInfoP->status == VOK) {
636             /*
637              * Volume's status is OK - all the fields are valid.
638              */
639             fprintf(STDOUT, "%-32s ", a_xInfoP->name);
640             fprintf(STDOUT, "%10lu ", (unsigned long)a_xInfoP->volid);
641             if (a_xInfoP->type == 0)
642                 fprintf(STDOUT, "RW ");
643             if (a_xInfoP->type == 1)
644                 fprintf(STDOUT, "RO ");
645             if (a_xInfoP->type == 2)
646                 fprintf(STDOUT, "BK ");
647             fprintf(STDOUT, "%10d K used ", a_xInfoP->size);
648             fprintf(STDOUT, "%d files ", a_xInfoP->filecount);
649             if (a_xInfoP->inUse == 1) {
650                 fprintf(STDOUT, "On-line");
651                 (*a_totalOKP)++;
652             } else {
653                 fprintf(STDOUT, "Off-line");
654                 (*a_totalNotOKP)++;
655             }
656             fprintf(STDOUT, "\n");
657             MapPartIdIntoName(a_partID, pname);
658             fprintf(STDOUT, "    %s %s \n", hostutil_GetNameByINet(a_servID),
659                     pname);
660             fprintf(STDOUT, "    RWrite %10lu ROnly %10lu Backup %10lu \n",
661                     (unsigned long)a_xInfoP->parentID,
662                     (unsigned long)a_xInfoP->cloneID,
663                     (unsigned long)a_xInfoP->backupID);
664             fprintf(STDOUT, "    MaxQuota %10d K \n", a_xInfoP->maxquota);
665             fprintf(STDOUT, "    Creation    %s",
666                     vos_ctime( & a_xInfoP->creationDate));
667 #ifdef FULL_LISTVOL_SWITCH
668             fprintf(STDOUT, "    Copy        %s",
669                     vos_ctime( & a_xInfoP->copyDate));
670             if (!a_xInfoP->backupDate)
671                 fprintf(STDOUT, "    Backup      Never\n");
672             else
673                 fprintf(STDOUT, "    Backup      %s",
674                         vos_ctime( & a_xInfoP->backupDate));
675             if (a_xInfoP->accessDate)
676                 fprintf(STDOUT, "    Last Access %s",
677                         vos_ctime( & a_xInfoP->accessDate));
678 #endif
679             if (!a_xInfoP->updateDate)
680                 fprintf(STDOUT, "    Last Update Never\n");
681             else
682                 fprintf(STDOUT, "    Last Update %s",
683                         vos_ctime( & a_xInfoP->updateDate));
684             fprintf(STDOUT,
685                     "    %d accesses in the past day (i.e., vnode references)\n",
686                     a_xInfoP->dayUse);
687
688             /*
689              * Print all the read/write and authorship stats.
690              */
691             fprintf(STDOUT, "\n                      Raw Read/Write Stats\n");
692             fprintf(STDOUT,
693                     "          |-------------------------------------------|\n");
694             fprintf(STDOUT,
695                     "          |    Same Network     |    Diff Network     |\n");
696             fprintf(STDOUT,
697                     "          |----------|----------|----------|----------|\n");
698             fprintf(STDOUT,
699                     "          |  Total   |   Auth   |   Total  |   Auth   |\n");
700             fprintf(STDOUT,
701                     "          |----------|----------|----------|----------|\n");
702             fprintf(STDOUT, "Reads     | %8d | %8d | %8d | %8d |\n",
703                     a_xInfoP->stat_reads[VOLINT_STATS_SAME_NET],
704                     a_xInfoP->stat_reads[VOLINT_STATS_SAME_NET_AUTH],
705                     a_xInfoP->stat_reads[VOLINT_STATS_DIFF_NET],
706                     a_xInfoP->stat_reads[VOLINT_STATS_DIFF_NET_AUTH]);
707             fprintf(STDOUT, "Writes    | %8d | %8d | %8d | %8d |\n",
708                     a_xInfoP->stat_writes[VOLINT_STATS_SAME_NET],
709                     a_xInfoP->stat_writes[VOLINT_STATS_SAME_NET_AUTH],
710                     a_xInfoP->stat_writes[VOLINT_STATS_DIFF_NET],
711                     a_xInfoP->stat_writes[VOLINT_STATS_DIFF_NET_AUTH]);
712             fprintf(STDOUT,
713                     "          |-------------------------------------------|\n\n");
714
715             fprintf(STDOUT,
716                     "                   Writes Affecting Authorship\n");
717             fprintf(STDOUT,
718                     "          |-------------------------------------------|\n");
719             fprintf(STDOUT,
720                     "          |   File Authorship   | Directory Authorship|\n");
721             fprintf(STDOUT,
722                     "          |----------|----------|----------|----------|\n");
723             fprintf(STDOUT,
724                     "          |   Same   |   Diff   |    Same  |   Diff   |\n");
725             fprintf(STDOUT,
726                     "          |----------|----------|----------|----------|\n");
727             fprintf(STDOUT, "0-60 sec  | %8d | %8d | %8d | %8d |\n",
728                     a_xInfoP->stat_fileSameAuthor[VOLINT_STATS_TIME_IDX_0],
729                     a_xInfoP->stat_fileDiffAuthor[VOLINT_STATS_TIME_IDX_0],
730                     a_xInfoP->stat_dirSameAuthor[VOLINT_STATS_TIME_IDX_0],
731                     a_xInfoP->stat_dirDiffAuthor[VOLINT_STATS_TIME_IDX_0]);
732             fprintf(STDOUT, "1-10 min  | %8d | %8d | %8d | %8d |\n",
733                     a_xInfoP->stat_fileSameAuthor[VOLINT_STATS_TIME_IDX_1],
734                     a_xInfoP->stat_fileDiffAuthor[VOLINT_STATS_TIME_IDX_1],
735                     a_xInfoP->stat_dirSameAuthor[VOLINT_STATS_TIME_IDX_1],
736                     a_xInfoP->stat_dirDiffAuthor[VOLINT_STATS_TIME_IDX_1]);
737             fprintf(STDOUT, "10min-1hr | %8d | %8d | %8d | %8d |\n",
738                     a_xInfoP->stat_fileSameAuthor[VOLINT_STATS_TIME_IDX_2],
739                     a_xInfoP->stat_fileDiffAuthor[VOLINT_STATS_TIME_IDX_2],
740                     a_xInfoP->stat_dirSameAuthor[VOLINT_STATS_TIME_IDX_2],
741                     a_xInfoP->stat_dirDiffAuthor[VOLINT_STATS_TIME_IDX_2]);
742             fprintf(STDOUT, "1hr-1day  | %8d | %8d | %8d | %8d |\n",
743                     a_xInfoP->stat_fileSameAuthor[VOLINT_STATS_TIME_IDX_3],
744                     a_xInfoP->stat_fileDiffAuthor[VOLINT_STATS_TIME_IDX_3],
745                     a_xInfoP->stat_dirSameAuthor[VOLINT_STATS_TIME_IDX_3],
746                     a_xInfoP->stat_dirDiffAuthor[VOLINT_STATS_TIME_IDX_3]);
747             fprintf(STDOUT, "1day-1wk  | %8d | %8d | %8d | %8d |\n",
748                     a_xInfoP->stat_fileSameAuthor[VOLINT_STATS_TIME_IDX_4],
749                     a_xInfoP->stat_fileDiffAuthor[VOLINT_STATS_TIME_IDX_4],
750                     a_xInfoP->stat_dirSameAuthor[VOLINT_STATS_TIME_IDX_4],
751                     a_xInfoP->stat_dirDiffAuthor[VOLINT_STATS_TIME_IDX_4]);
752             fprintf(STDOUT, "> 1wk     | %8d | %8d | %8d | %8d |\n",
753                     a_xInfoP->stat_fileSameAuthor[VOLINT_STATS_TIME_IDX_5],
754                     a_xInfoP->stat_fileDiffAuthor[VOLINT_STATS_TIME_IDX_5],
755                     a_xInfoP->stat_dirSameAuthor[VOLINT_STATS_TIME_IDX_5],
756                     a_xInfoP->stat_dirDiffAuthor[VOLINT_STATS_TIME_IDX_5]);
757             fprintf(STDOUT,
758                     "          |-------------------------------------------|\n");
759         } /*Volume status OK */
760         else if (a_xInfoP->status == VBUSY) {
761             (*a_totalBusyP)++;
762             qPut(&busyHead, a_xInfoP->volid);
763             if (a_showProblems)
764                 fprintf(STDOUT, "**** Volume %lu is busy ****\n",
765                         (unsigned long)a_xInfoP->volid);
766         } /*Busy volume */
767         else {
768             (*a_totalNotOKP)++;
769             qPut(&notokHead, a_xInfoP->volid);
770             if (a_showProblems)
771                 fprintf(STDOUT, "**** Could not attach volume %lu ****\n",
772                         (unsigned long)a_xInfoP->volid);
773         }                       /*Screwed volume */
774         fprintf(STDOUT, "\n");
775     } /*Long listing */
776     else {
777         /*
778          * Default listing.
779          */
780         if (a_xInfoP->status == VOK) {
781             fprintf(STDOUT, "%-32s ", a_xInfoP->name);
782             fprintf(STDOUT, "%10lu ", (unsigned long)a_xInfoP->volid);
783             if (a_xInfoP->type == 0)
784                 fprintf(STDOUT, "RW ");
785             if (a_xInfoP->type == 1)
786                 fprintf(STDOUT, "RO ");
787             if (a_xInfoP->type == 2)
788                 fprintf(STDOUT, "BK ");
789             fprintf(STDOUT, "%10d K ", a_xInfoP->size);
790             if (a_xInfoP->inUse == 1) {
791                 fprintf(STDOUT, "On-line");
792                 (*a_totalOKP)++;
793             } else {
794                 fprintf(STDOUT, "Off-line");
795                 (*a_totalNotOKP)++;
796             }
797             fprintf(STDOUT, "\n");
798         } /*Volume OK */
799         else if (a_xInfoP->status == VBUSY) {
800             (*a_totalBusyP)++;
801             qPut(&busyHead, a_xInfoP->volid);
802             if (a_showProblems)
803                 fprintf(STDOUT, "**** Volume %lu is busy ****\n",
804                         (unsigned long)a_xInfoP->volid);
805         } /*Busy volume */
806         else {
807             (*a_totalNotOKP)++;
808             qPut(&notokHead, a_xInfoP->volid);
809             if (a_showProblems)
810                 fprintf(STDOUT, "**** Could not attach volume %lu ****\n",
811                         (unsigned long)a_xInfoP->volid);
812         }                       /*Screwed volume */
813     }                           /*Default listing */
814 }                               /*XDisplayFormat */
815
816 #ifdef FULL_LISTVOL_SWITCH
817 /*------------------------------------------------------------------------
818  * PRIVATE XDisplayFormat2
819  *
820  * Description:
821  *      Display the formated contents of one extended volume info structure.
822  *
823  * Arguments:
824  *      a_xInfoP        : Ptr to extended volume info struct to print.
825  *      a_servID        : Server ID to print.
826  *      a_partID        : Partition ID to print.
827  *      a_totalOKP      : Ptr to total-OK counter.
828  *      a_totalNotOKP   : Ptr to total-screwed counter.
829  *      a_totalBusyP    : Ptr to total-busy counter.
830  *      a_fast          : Fast listing?
831  *      a_int32         : Int32 listing?
832  *      a_showProblems  : Show volume problems?
833  *
834  * Returns:
835  *      Nothing.
836  *
837  * Environment:
838  *      Nothing interesting.
839  *
840  * Side Effects:
841  *      As advertised.
842  *------------------------------------------------------------------------*/
843
844 static void
845 XDisplayFormat2(volintXInfo *a_xInfoP, afs_int32 a_servID, afs_int32 a_partID,
846                 int *a_totalOKP, int *a_totalNotOKP, int *a_totalBusyP,
847                 int a_fast, int a_int32, int a_showProblems)
848 {                               /*XDisplayFormat */
849     if (a_fast) {
850         /*
851          * Short & sweet.
852          */
853         fprintf(STDOUT, "vold_id\t%-10lu\n", (unsigned long)a_xInfoP->volid);
854     } else if (a_int32) {
855         /*
856          * Fully-detailed listing.
857          */
858         if (a_xInfoP->status == VOK) {
859             /*
860              * Volume's status is OK - all the fields are valid.
861              */
862
863                 static long server_cache = -1, partition_cache = -1;
864                 static char hostname[256], address[32], pname[16];
865                 int i,ai[] = {VOLINT_STATS_TIME_IDX_0,VOLINT_STATS_TIME_IDX_1,VOLINT_STATS_TIME_IDX_2,
866                               VOLINT_STATS_TIME_IDX_3,VOLINT_STATS_TIME_IDX_4,VOLINT_STATS_TIME_IDX_5};
867
868                 if (a_servID != server_cache) {
869                         struct in_addr s;
870
871                         s.s_addr = a_servID;
872                         strcpy(hostname, hostutil_GetNameByINet(a_servID));
873                         strcpy(address, inet_ntoa(s));
874                         server_cache = a_servID;
875                 }
876                 if (a_partID != partition_cache) {
877                         MapPartIdIntoName(a_partID, pname);
878                         partition_cache = a_partID;
879                 }
880
881                 fprintf(STDOUT, "name\t\t%s\n", a_xInfoP->name);
882                 fprintf(STDOUT, "id\t\t%lu\n", afs_cast_uint32(a_xInfoP->volid));
883                 fprintf(STDOUT, "serv\t\t%s\t%s\n", address, hostname);
884                 fprintf(STDOUT, "part\t\t%s\n", pname);
885                 switch (a_xInfoP->status) {
886                 case VOK:
887                         fprintf(STDOUT, "status\t\tOK\n");
888                         break;
889                 case VBUSY:
890                         fprintf(STDOUT, "status\t\tBUSY\n");
891                         return;
892                 default:
893                         fprintf(STDOUT, "status\t\tUNATTACHABLE\n");
894                         return;
895                 }
896                 fprintf(STDOUT, "backupID\t%lu\n", 
897                         afs_cast_uint32(a_xInfoP->backupID));
898                 fprintf(STDOUT, "parentID\t%lu\n", 
899                         afs_cast_uint32(a_xInfoP->parentID));
900                 fprintf(STDOUT, "cloneID\t\t%lu\n", 
901                         afs_cast_uint32(a_xInfoP->cloneID));
902                 fprintf(STDOUT, "inUse\t\t%s\n", a_xInfoP->inUse ? "Y" : "N");
903                 switch (a_xInfoP->type) {
904                 case 0:
905                         fprintf(STDOUT, "type\t\tRW\n");
906                         break;
907                 case 1:
908                         fprintf(STDOUT, "type\t\tRO\n");
909                         break;
910                 case 2:
911                         fprintf(STDOUT, "type\t\tBK\n");
912                         break;
913                 default:
914                         fprintf(STDOUT, "type\t\t?\n");
915                         break;
916                 }
917                 fprintf(STDOUT, "creationDate\t%-9lu\t%s", 
918                         afs_cast_uint32(a_xInfoP->creationDate),
919                         vos_ctime(&a_xInfoP->creationDate));
920                 fprintf(STDOUT, "accessDate\t%-9lu\t%s", 
921                         afs_cast_uint32(a_xInfoP->accessDate),
922                         vos_ctime(&a_xInfoP->accessDate));
923                 fprintf(STDOUT, "updateDate\t%-9lu\t%s", 
924                         afs_cast_uint32(a_xInfoP->updateDate),
925                         vos_ctime(&a_xInfoP->updateDate));
926                 fprintf(STDOUT, "backupDate\t%-9lu\t%s", 
927                         afs_cast_uint32(a_xInfoP->backupDate),
928                         vos_ctime(&a_xInfoP->backupDate));
929                 fprintf(STDOUT, "copyDate\t%-9lu\t%s", 
930                         afs_cast_uint32(a_xInfoP->copyDate),
931                         vos_ctime(&a_xInfoP->copyDate));
932                 
933                 fprintf(STDOUT, "diskused\t%u\n", a_xInfoP->size);
934                 fprintf(STDOUT, "maxquota\t%u\n", a_xInfoP->maxquota);
935
936                 fprintf(STDOUT, "filecount\t%u\n", a_xInfoP->filecount);
937                 fprintf(STDOUT, "dayUse\t\t%u\n", a_xInfoP->dayUse);
938
939
940
941                 fprintf(STDOUT,"reads_same_net\t%8d\n",a_xInfoP->stat_reads[VOLINT_STATS_SAME_NET]);
942                 fprintf(STDOUT,"reads_same_net_auth\t%8d\n",a_xInfoP->stat_reads[VOLINT_STATS_SAME_NET_AUTH]);
943                 fprintf(STDOUT,"reads_diff_net\t%8d\n",a_xInfoP->stat_reads[VOLINT_STATS_DIFF_NET]);
944                 fprintf(STDOUT,"reads_diff_net_auth\t%8d\n",a_xInfoP->stat_reads[VOLINT_STATS_DIFF_NET_AUTH]);
945
946                 fprintf(STDOUT,"writes_same_net\t%8d\n",a_xInfoP->stat_writes[VOLINT_STATS_SAME_NET]);
947                 fprintf(STDOUT,"writes_same_net_auth\t%8d\n",a_xInfoP->stat_writes[VOLINT_STATS_SAME_NET_AUTH]);
948                 fprintf(STDOUT,"writes_diff_net\t%8d\n",a_xInfoP->stat_writes[VOLINT_STATS_DIFF_NET]);
949                 fprintf(STDOUT,"writes_diff_net_auth\t%8d\n",a_xInfoP->stat_writes[VOLINT_STATS_DIFF_NET_AUTH]);
950
951                 for(i=0;i<5;i++)
952                 {
953                         fprintf(STDOUT,"file_same_author_idx_%d\t%8d\n",i+1,a_xInfoP->stat_fileSameAuthor[ai[i]]);
954                         fprintf(STDOUT,"file_diff_author_idx_%d\t%8d\n",i+1,a_xInfoP->stat_fileDiffAuthor[ai[i]]);
955                         fprintf(STDOUT,"dir_same_author_idx_%d\t%8d\n",i+1,a_xInfoP->stat_dirSameAuthor[ai[i]]);
956                         fprintf(STDOUT,"dir_dif_author_idx_%d\t%8d\n",i+1,a_xInfoP->stat_dirDiffAuthor[ai[i]]);
957                 }
958
959         } /*Volume status OK */
960         else if (a_xInfoP->status == VBUSY) {
961             (*a_totalBusyP)++;
962             qPut(&busyHead, a_xInfoP->volid);
963             if (a_showProblems)
964                 fprintf(STDOUT, "BUSY_VOL\t%lu\n",
965                         (unsigned long)a_xInfoP->volid);
966         } /*Busy volume */
967         else {
968             (*a_totalNotOKP)++;
969             qPut(&notokHead, a_xInfoP->volid);
970             if (a_showProblems)
971                 fprintf(STDOUT, "COULD_NOT_ATTACH\t%lu\n",
972                         (unsigned long)a_xInfoP->volid);
973         }                       /*Screwed volume */
974     } /*Long listing */
975     else {
976         /*
977          * Default listing.
978          */
979         if (a_xInfoP->status == VOK) {
980             fprintf(STDOUT, "name\t%-32s\n", a_xInfoP->name);
981             fprintf(STDOUT, "volID\t%10lu\n", (unsigned long)a_xInfoP->volid);
982             if (a_xInfoP->type == 0)
983                 fprintf(STDOUT, "type\tRW\n");
984             if (a_xInfoP->type == 1)
985                 fprintf(STDOUT, "type\tRO\n");
986             if (a_xInfoP->type == 2)
987                 fprintf(STDOUT, "type\tBK\n");
988             fprintf(STDOUT, "size\t%10dK\n", a_xInfoP->size);
989
990             fprintf(STDOUT, "inUse\t%d\n",a_xInfoP->inUse);
991             if (a_xInfoP->inUse == 1)
992                 (*a_totalOKP)++;
993             else
994                 (*a_totalNotOKP)++;
995
996         } /*Volume OK */
997         else if (a_xInfoP->status == VBUSY) {
998             (*a_totalBusyP)++;
999             qPut(&busyHead, a_xInfoP->volid);
1000             if (a_showProblems)
1001                 fprintf(STDOUT, "VOLUME_BUSY\t%lu\n",
1002                         (unsigned long)a_xInfoP->volid);
1003         } /*Busy volume */
1004         else {
1005             (*a_totalNotOKP)++;
1006             qPut(&notokHead, a_xInfoP->volid);
1007             if (a_showProblems)
1008                 fprintf(STDOUT, "COULD_NOT_ATTACH_VOLUME\t%lu\n",
1009                         (unsigned long)a_xInfoP->volid);
1010         }                       /*Screwed volume */
1011     }                           /*Default listing */
1012 }                               /*XDisplayFormat */
1013 #endif /*FULL_LISTVOL_SWITCH*/
1014
1015 #ifdef FULL_LISTVOL_SWITCH
1016 static void
1017 DisplayFormat2(long server, long partition, volintInfo *pntr)
1018 {
1019     static long server_cache = -1, partition_cache = -1;
1020     static char hostname[256], address[32], pname[16];
1021
1022     if (server != server_cache) {
1023         struct in_addr s;
1024
1025         s.s_addr = server;
1026         strcpy(hostname, hostutil_GetNameByINet(server));
1027         strcpy(address, inet_ntoa(s));
1028         server_cache = server;
1029     }
1030     if (partition != partition_cache) {
1031         MapPartIdIntoName(partition, pname);
1032         partition_cache = partition;
1033     }
1034     fprintf(STDOUT, "name\t\t%s\n", pntr->name);
1035     fprintf(STDOUT, "id\t\t%lu\n", 
1036             afs_cast_uint32(pntr->volid));
1037     fprintf(STDOUT, "serv\t\t%s\t%s\n", address, hostname);
1038     fprintf(STDOUT, "part\t\t%s\n", pname);
1039     switch (pntr->status) {
1040     case VOK:
1041         fprintf(STDOUT, "status\t\tOK\n");
1042         break;
1043     case VBUSY:
1044         fprintf(STDOUT, "status\t\tBUSY\n");
1045         return;
1046     default:
1047         fprintf(STDOUT, "status\t\tUNATTACHABLE\n");
1048         return;
1049     }
1050     fprintf(STDOUT, "backupID\t%lu\n", 
1051             afs_cast_uint32(pntr->backupID));
1052     fprintf(STDOUT, "parentID\t%lu\n", 
1053             afs_cast_uint32(pntr->parentID));
1054     fprintf(STDOUT, "cloneID\t\t%lu\n", 
1055             afs_cast_uint32(pntr->cloneID));
1056     fprintf(STDOUT, "inUse\t\t%s\n", pntr->inUse ? "Y" : "N");
1057     fprintf(STDOUT, "needsSalvaged\t%s\n", pntr->needsSalvaged ? "Y" : "N");
1058     /* 0xD3 is from afs/volume.h since I had trouble including the file */
1059     fprintf(STDOUT, "destroyMe\t%s\n", pntr->destroyMe == 0xD3 ? "Y" : "N");
1060     switch (pntr->type) {
1061     case 0:
1062         fprintf(STDOUT, "type\t\tRW\n");
1063         break;
1064     case 1:
1065         fprintf(STDOUT, "type\t\tRO\n");
1066         break;
1067     case 2:
1068         fprintf(STDOUT, "type\t\tBK\n");
1069         break;
1070     default:
1071         fprintf(STDOUT, "type\t\t?\n");
1072         break;
1073     }
1074     fprintf(STDOUT, "creationDate\t%-9lu\t%s", 
1075             afs_cast_uint32(pntr->creationDate),
1076             vos_ctime(&pntr->creationDate));
1077     fprintf(STDOUT, "accessDate\t%-9lu\t%s", 
1078             afs_cast_uint32(pntr->accessDate),
1079             vos_ctime(&pntr->accessDate));
1080     fprintf(STDOUT, "updateDate\t%-9lu\t%s", 
1081             afs_cast_uint32(pntr->updateDate),
1082             vos_ctime(&pntr->updateDate));
1083     fprintf(STDOUT, "backupDate\t%-9lu\t%s", 
1084             afs_cast_uint32(pntr->backupDate),
1085             vos_ctime(&pntr->backupDate));
1086     fprintf(STDOUT, "copyDate\t%-9lu\t%s", 
1087             afs_cast_uint32(pntr->copyDate),
1088             vos_ctime(&pntr->copyDate));
1089     fprintf(STDOUT, "flags\t\t%#lx\t(Optional)\n", 
1090             afs_cast_uint32(pntr->flags));
1091     fprintf(STDOUT, "diskused\t%u\n", pntr->size);
1092     fprintf(STDOUT, "maxquota\t%u\n", pntr->maxquota);
1093     fprintf(STDOUT, "minquota\t%lu\t(Optional)\n", 
1094             afs_cast_uint32(pntr->spare0));
1095     fprintf(STDOUT, "filecount\t%u\n", pntr->filecount);
1096     fprintf(STDOUT, "dayUse\t\t%u\n", pntr->dayUse);
1097     fprintf(STDOUT, "weekUse\t\t%lu\t(Optional)\n",
1098             afs_cast_uint32(pntr->spare1));
1099     fprintf(STDOUT, "spare2\t\t%lu\t(Optional)\n", 
1100             afs_cast_uint32(pntr->spare2));
1101     fprintf(STDOUT, "spare3\t\t%lu\t(Optional)\n", 
1102             afs_cast_uint32(pntr->spare3));
1103     return;
1104 }
1105
1106 static void
1107 DisplayVolumes2(long server, long partition, volintInfo *pntr, long count)
1108 {
1109     long i;
1110
1111     for (i = 0; i < count; i++) {
1112         fprintf(STDOUT, "BEGIN_OF_ENTRY\n");
1113         DisplayFormat2(server, partition, pntr);
1114         fprintf(STDOUT, "END_OF_ENTRY\n\n");
1115         pntr++;
1116     }
1117     return;
1118 }
1119 #endif /* FULL_LISTVOL_SWITCH */
1120
1121 static void
1122 DisplayVolumes(afs_int32 server, afs_int32 part, volintInfo *pntr,
1123                afs_int32 count, afs_int32 longlist, afs_int32 fast,
1124                int quiet)
1125 {
1126     int totalOK, totalNotOK, totalBusy, i;
1127     afs_uint32 volid = 0;
1128
1129     totalOK = 0;
1130     totalNotOK = 0;
1131     totalBusy = 0;
1132     qInit(&busyHead);
1133     qInit(&notokHead);
1134     for (i = 0; i < count; i++) {
1135         DisplayFormat(pntr, server, part, &totalOK, &totalNotOK, &totalBusy,
1136                       fast, longlist, 0);
1137         pntr++;
1138     }
1139     if (totalBusy) {
1140         while (busyHead.count) {
1141             qGet(&busyHead, &volid);
1142             fprintf(STDOUT, "**** Volume %lu is busy ****\n",
1143                     (unsigned long)volid);
1144         }
1145     }
1146     if (totalNotOK) {
1147         while (notokHead.count) {
1148             qGet(&notokHead, &volid);
1149             fprintf(STDOUT, "**** Could not attach volume %lu ****\n",
1150                     (unsigned long)volid);
1151         }
1152     }
1153     if (!quiet) {
1154         fprintf(STDOUT, "\n");
1155         if (!fast) {
1156             fprintf(STDOUT,
1157                     "Total volumes onLine %d ; Total volumes offLine %d ; Total busy %d\n\n",
1158                     totalOK, totalNotOK, totalBusy);
1159         }
1160     }
1161 }
1162 /*------------------------------------------------------------------------
1163  * PRIVATE XDisplayVolumes
1164  *
1165  * Description:
1166  *      Display extended volume information.
1167  *
1168  * Arguments:
1169  *      a_servID : Pointer to the Rx call we're performing.
1170  *      a_partID : Partition for which we want the extended list.
1171  *      a_xInfoP : Ptr to extended volume info.
1172  *      a_count  : Number of volume records contained above.
1173  *      a_int32   : Int32 listing generated?
1174  *      a_fast   : Fast listing generated?
1175  *      a_quiet  : Quiet listing generated?
1176  *
1177  * Returns:
1178  *      Nothing.
1179  *
1180  * Environment:
1181  *      Nothing interesting.
1182  *
1183  * Side Effects:
1184  *      As advertised.
1185  *------------------------------------------------------------------------*/
1186
1187 static void
1188 XDisplayVolumes(afs_int32 a_servID, afs_int32 a_partID, volintXInfo *a_xInfoP,
1189                 afs_int32 a_count, afs_int32 a_int32, afs_int32 a_fast,
1190                 int a_quiet)
1191 {                               /*XDisplayVolumes */
1192
1193     int totalOK;                /*Total OK volumes */
1194     int totalNotOK;             /*Total screwed volumes */
1195     int totalBusy;              /*Total busy volumes */
1196     int i;                      /*Loop variable */
1197     afs_uint32 volid = 0;       /*Current volume ID */
1198
1199     /*
1200      * Initialize counters and (global!!) queues.
1201      */
1202     totalOK = 0;
1203     totalNotOK = 0;
1204     totalBusy = 0;
1205     qInit(&busyHead);
1206     qInit(&notokHead);
1207
1208     /*
1209      * Display each volume in the list.
1210      */
1211     for (i = 0; i < a_count; i++) {
1212         XDisplayFormat(a_xInfoP, a_servID, a_partID, &totalOK, &totalNotOK,
1213                        &totalBusy, a_fast, a_int32, 0);
1214         a_xInfoP++;
1215     }
1216
1217     /*
1218      * If any volumes were found to be busy or screwed, display them.
1219      */
1220     if (totalBusy) {
1221         while (busyHead.count) {
1222             qGet(&busyHead, &volid);
1223             fprintf(STDOUT, "**** Volume %lu is busy ****\n",
1224                     (unsigned long)volid);
1225         }
1226     }
1227     if (totalNotOK) {
1228         while (notokHead.count) {
1229             qGet(&notokHead, &volid);
1230             fprintf(STDOUT, "**** Could not attach volume %lu ****\n",
1231                     (unsigned long)volid);
1232         }
1233     }
1234
1235     if (!a_quiet) {
1236         fprintf(STDOUT, "\n");
1237         if (!a_fast) {
1238             fprintf(STDOUT,
1239                     "Total volumes: %d on-line, %d off-line, %d  busyd\n\n",
1240                     totalOK, totalNotOK, totalBusy);
1241         }
1242     }
1243
1244 }                               /*XDisplayVolumes */
1245 #ifdef FULL_LISTVOL_SWITCH
1246 /*------------------------------------------------------------------------
1247  * PRIVATE XDisplayVolumes2
1248  *
1249  * Description:
1250  *      Display extended formated volume information.
1251  *
1252  * Arguments:
1253  *      a_servID : Pointer to the Rx call we're performing.
1254  *      a_partID : Partition for which we want the extended list.
1255  *      a_xInfoP : Ptr to extended volume info.
1256  *      a_count  : Number of volume records contained above.
1257  *      a_int32   : Int32 listing generated?
1258  *      a_fast   : Fast listing generated?
1259  *      a_quiet  : Quiet listing generated?
1260  *
1261  * Returns:
1262  *      Nothing.
1263  *
1264  * Environment:
1265  *      Nothing interesting.
1266  *
1267  * Side Effects:
1268  *      As advertised.
1269  *------------------------------------------------------------------------*/
1270
1271 static void
1272 XDisplayVolumes2(afs_int32 a_servID, afs_int32 a_partID, volintXInfo *a_xInfoP,
1273                  afs_int32 a_count, afs_int32 a_int32, afs_int32 a_fast,
1274                  int a_quiet)
1275 {                               /*XDisplayVolumes */
1276
1277     int totalOK;                /*Total OK volumes */
1278     int totalNotOK;             /*Total screwed volumes */
1279     int totalBusy;              /*Total busy volumes */
1280     int i;                      /*Loop variable */
1281     afs_uint32 volid = 0;       /*Current volume ID */
1282
1283     /*
1284      * Initialize counters and (global!!) queues.
1285      */
1286     totalOK = 0;
1287     totalNotOK = 0;
1288     totalBusy = 0;
1289     qInit(&busyHead);
1290     qInit(&notokHead);
1291
1292     /*
1293      * Display each volume in the list.
1294      */
1295     for (i = 0; i < a_count; i++) {
1296         fprintf(STDOUT, "BEGIN_OF_ENTRY\n");
1297         XDisplayFormat2(a_xInfoP, a_servID, a_partID, &totalOK, &totalNotOK,
1298                        &totalBusy, a_fast, a_int32, 0);
1299         fprintf(STDOUT, "END_OF_ENTRY\n");
1300         a_xInfoP++;
1301     }
1302
1303     /*
1304      * If any volumes were found to be busy or screwed, display them.
1305      */
1306     if (totalBusy) {
1307         while (busyHead.count) {
1308             qGet(&busyHead, &volid);
1309             fprintf(STDOUT, "BUSY_VOL\t%lu\n",
1310                     (unsigned long)volid);
1311         }
1312     }
1313     if (totalNotOK) {
1314         while (notokHead.count) {
1315             qGet(&notokHead, &volid);
1316             fprintf(STDOUT, "COULD_NOT_ATTACH\t%lu\n",
1317                     (unsigned long)volid);
1318         }
1319     }
1320
1321     if (!a_quiet) {
1322         fprintf(STDOUT, "\n");
1323         if (!a_fast) {
1324             fprintf(STDOUT,
1325                     "VOLUMES_ONLINE\t%d\nVOLUMES_OFFLINE\t%d\nVOLUMES_BUSY\t%d\n",
1326                     totalOK, totalNotOK, totalBusy);
1327         }
1328     }
1329
1330 }                               /*XDisplayVolumes2 */
1331 #endif /* FULL_LISTVOL_SWITCH */
1332
1333
1334 /* set <server> and <part> to the correct values depending on 
1335  * <voltype> and <entry> */
1336 static void
1337 GetServerAndPart(struct nvldbentry *entry, int voltype, afs_int32 *server,
1338                  afs_int32 *part, int *previdx)
1339 {
1340     int i, istart, vtype;
1341
1342     *server = -1;
1343     *part = -1;
1344
1345     /* Doesn't check for non-existance of backup volume */
1346     if ((voltype == RWVOL) || (voltype == BACKVOL)) {
1347         vtype = ITSRWVOL;
1348         istart = 0;             /* seach the entire entry */
1349     } else {
1350         vtype = ITSROVOL;
1351         /* Seach from beginning of entry or pick up where we left off */
1352         istart = ((*previdx < 0) ? 0 : *previdx + 1);
1353     }
1354
1355     for (i = istart; i < entry->nServers; i++) {
1356         if (entry->serverFlags[i] & vtype) {
1357             *server = entry->serverNumber[i];
1358             *part = entry->serverPartition[i];
1359             *previdx = i;
1360             return;
1361         }
1362     }
1363
1364     /* Didn't find any, return -1 */
1365     *previdx = -1;
1366     return;
1367 }
1368
1369 static void
1370 PostVolumeStats(struct nvldbentry *entry)
1371 {
1372     SubEnumerateEntry(entry);
1373     /* Check for VLOP_ALLOPERS */
1374     if (entry->flags & VLOP_ALLOPERS)
1375         fprintf(STDOUT, "    Volume is currently LOCKED  \n");
1376     return;
1377 }
1378
1379 /*------------------------------------------------------------------------
1380  * PRIVATE XVolumeStats
1381  *
1382  * Description:
1383  *      Display extended volume information.
1384  *
1385  * Arguments:
1386  *      a_xInfoP  : Ptr to extended volume info.
1387  *      a_entryP  : Ptr to the volume's VLDB entry.
1388  *      a_srvID   : Server ID.
1389  *      a_partID  : Partition ID.
1390  *      a_volType : Type of volume to print.
1391  *
1392  * Returns:
1393  *      Nothing.
1394  *
1395  * Environment:
1396  *      Nothing interesting.
1397  *
1398  * Side Effects:
1399  *      As advertised.
1400  *------------------------------------------------------------------------*/
1401
1402 static void
1403 XVolumeStats(volintXInfo *a_xInfoP, struct nvldbentry *a_entryP,
1404              afs_int32 a_srvID, afs_int32 a_partID, int a_volType)
1405 {                               /*XVolumeStats */
1406
1407     int totalOK, totalNotOK, totalBusy; /*Dummies - we don't really count here */
1408
1409     XDisplayFormat(a_xInfoP,    /*Ptr to extended volume info */
1410                    a_srvID,     /*Server ID to print */
1411                    a_partID,    /*Partition ID to print */
1412                    &totalOK,    /*Ptr to total-OK counter */
1413                    &totalNotOK, /*Ptr to total-screwed counter */
1414                    &totalBusy,  /*Ptr to total-busy counter */
1415                    0,           /*Don't do a fast listing */
1416                    1,           /*Do a long listing */
1417                    1);          /*Show volume problems */
1418     return;
1419
1420 }                               /*XVolumeStats */
1421
1422 static void
1423 VolumeStats_int(volintInfo *pntr, struct nvldbentry *entry, afs_int32 server, 
1424              afs_int32 part, int voltype)
1425 {
1426     int totalOK, totalNotOK, totalBusy;
1427
1428     DisplayFormat(pntr, server, part, &totalOK, &totalNotOK, &totalBusy, 0, 1,
1429                   1);
1430     return;
1431 }
1432
1433 /* command to forcibly remove a volume */
1434 static int
1435 NukeVolume(register struct cmd_syndesc *as)
1436 {
1437     register afs_int32 code;
1438     afs_uint32 volID;
1439     afs_int32  err;
1440     afs_int32 partID;
1441     afs_int32 server;
1442     register char *tp;
1443
1444     server = GetServer(tp = as->parms[0].items->data);
1445     if (!server) {
1446         fprintf(STDERR, "vos: server '%s' not found in host table\n", tp);
1447         return 1;
1448     }
1449
1450     partID = volutil_GetPartitionID(tp = as->parms[1].items->data);
1451     if (partID == -1) {
1452         fprintf(STDERR, "vos: could not parse '%s' as a partition name", tp);
1453         return 1;
1454     }
1455
1456     volID = vsu_GetVolumeID(tp = as->parms[2].items->data, cstruct, &err);
1457     if (volID == 0) {
1458         if (err)
1459             PrintError("", err);
1460         else
1461             fprintf(STDERR,
1462                     "vos: could not parse '%s' as a numeric volume ID", tp);
1463         return 1;
1464     }
1465
1466     fprintf(STDOUT,
1467             "vos: forcibly removing all traces of volume %d, please wait...",
1468             volID);
1469     fflush(STDOUT);
1470     code = UV_NukeVolume(server, partID, volID);
1471     if (code == 0)
1472         fprintf(STDOUT, "done.\n");
1473     else
1474         fprintf(STDOUT, "failed with code %d.\n", code);
1475     return code;
1476 }
1477
1478
1479 /*------------------------------------------------------------------------
1480  * PRIVATE ExamineVolume
1481  *
1482  * Description:
1483  *      Routine used to examine a single volume, contacting the VLDB as
1484  *      well as the Volume Server.
1485  *
1486  * Arguments:
1487  *      as : Ptr to parsed command line arguments.
1488  *
1489  * Returns:
1490  *      0 for a successful operation,
1491  *      Otherwise, one of the ubik or VolServer error values.
1492  *
1493  * Environment:
1494  *      Nothing interesting.
1495  *
1496  * Side Effects:
1497  *      As advertised.
1498  *------------------------------------------------------------------------
1499  */
1500 static int
1501 ExamineVolume(register struct cmd_syndesc *as, void *arock)
1502 {
1503     struct nvldbentry entry;
1504     afs_int32 vcode = 0;
1505     volintInfo *pntr = (volintInfo *) 0;
1506     volintXInfo *xInfoP = (volintXInfo *) 0;
1507     afs_uint32 volid;
1508     afs_int32 code, err, error = 0;
1509     int voltype, foundserv = 0, foundentry = 0;
1510     afs_int32 aserver, apart;
1511     int previdx = -1;
1512     int wantExtendedInfo;       /*Do we want extended vol info? */
1513
1514     wantExtendedInfo = (as->parms[1].items ? 1 : 0);    /* -extended */
1515
1516     volid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);   /* -id */
1517     if (volid == 0) {
1518         if (err)
1519             PrintError("", err);
1520         else
1521             fprintf(STDERR, "Unknown volume ID or name '%s'\n",
1522                     as->parms[0].items->data);
1523         return -1;
1524     }
1525
1526     if (verbose) {
1527         fprintf(STDOUT, "Fetching VLDB entry for %lu .. ",
1528                 (unsigned long)volid);
1529         fflush(STDOUT);
1530     }
1531     vcode = VLDB_GetEntryByID(volid, -1, &entry);
1532     if (vcode) {
1533         fprintf(STDERR,
1534                 "Could not fetch the entry for volume number %lu from VLDB \n",
1535                 (unsigned long)volid);
1536         return (vcode);
1537     }
1538     if (verbose)
1539         fprintf(STDOUT, "done\n");
1540     MapHostToNetwork(&entry);
1541
1542     if (entry.volumeId[RWVOL] == volid)
1543         voltype = RWVOL;
1544     else if (entry.volumeId[BACKVOL] == volid)
1545         voltype = BACKVOL;
1546     else                        /* (entry.volumeId[ROVOL] == volid) */
1547         voltype = ROVOL;
1548
1549     do {                        /* do {...} while (voltype == ROVOL) */
1550         /* Get the entry for the volume. If its a RW vol, get the RW entry.
1551          * It its a BK vol, get the RW entry (even if VLDB may say the BK doen't exist).
1552          * If its a RO vol, get the next RO entry.
1553          */
1554         GetServerAndPart(&entry, ((voltype == ROVOL) ? ROVOL : RWVOL),
1555                          &aserver, &apart, &previdx);
1556         if (previdx == -1) {    /* searched all entries */
1557             if (!foundentry) {
1558                 fprintf(STDERR, "Volume %s does not exist in VLDB\n\n",
1559                         as->parms[0].items->data);
1560                 error = ENOENT;
1561             }
1562             break;
1563         }
1564         foundentry = 1;
1565
1566         /* Get information about the volume from the server */
1567         if (verbose) {
1568             fprintf(STDOUT, "Getting volume listing from the server %s .. ",
1569                     hostutil_GetNameByINet(aserver));
1570             fflush(STDOUT);
1571         }
1572         if (wantExtendedInfo)
1573             code = UV_XListOneVolume(aserver, apart, volid, &xInfoP);
1574         else
1575             code = UV_ListOneVolume(aserver, apart, volid, &pntr);
1576         if (verbose)
1577             fprintf(STDOUT, "done\n");
1578
1579         if (code) {
1580             error = code;
1581             if (code == ENODEV) {
1582                 if ((voltype == BACKVOL) && !(entry.flags & BACK_EXISTS)) {
1583                     /* The VLDB says there is no backup volume and its not on disk */
1584                     fprintf(STDERR, "Volume %s does not exist\n",
1585                             as->parms[0].items->data);
1586                     error = ENOENT;
1587                 } else {
1588                     fprintf(STDERR,
1589                             "Volume does not exist on server %s as indicated by the VLDB\n",
1590                             hostutil_GetNameByINet(aserver));
1591                 }
1592             } else {
1593                 PrintDiagnostics("examine", code);
1594             }
1595             fprintf(STDOUT, "\n");
1596         } else {
1597             foundserv = 1;
1598             if (wantExtendedInfo)
1599                 XVolumeStats(xInfoP, &entry, aserver, apart, voltype);
1600             else
1601 #ifdef FULL_LISTVOL_SWITCH
1602             if (as->parms[2].items) {
1603                 DisplayFormat2(aserver, apart, pntr);
1604                 EnumerateEntry(&entry);
1605             } else
1606 #endif /* FULL_LISTVOL_SWITCH */
1607                 VolumeStats_int(pntr, &entry, aserver, apart, voltype);
1608
1609             if ((voltype == BACKVOL) && !(entry.flags & BACK_EXISTS)) {
1610                 /* The VLDB says there is no backup volume yet we found one on disk */
1611                 fprintf(STDERR, "Volume %s does not exist in VLDB\n",
1612                         as->parms[0].items->data);
1613                 error = ENOENT;
1614             }
1615         }
1616
1617         if (pntr)
1618             free(pntr);
1619         if (xInfoP)
1620             free(xInfoP);
1621     } while (voltype == ROVOL);
1622
1623     if (!foundserv) {
1624         fprintf(STDERR, "Dump only information from VLDB\n\n");
1625         fprintf(STDOUT, "%s \n", entry.name);   /* PostVolumeStats doesn't print name */
1626     }
1627     PostVolumeStats(&entry);
1628
1629     return (error);
1630 }
1631
1632 /*------------------------------------------------------------------------
1633  * PRIVATE SetFields
1634  *
1635  * Description:
1636  *      Routine used to change the status of a single volume.
1637  *
1638  * Arguments:
1639  *      as : Ptr to parsed command line arguments.
1640  *
1641  * Returns:
1642  *      0 for a successful operation,
1643  *      Otherwise, one of the ubik or VolServer error values.
1644  *
1645  * Environment:
1646  *      Nothing interesting.
1647  *
1648  * Side Effects:
1649  *      As advertised.
1650  *------------------------------------------------------------------------
1651  */
1652 static int
1653 SetFields(register struct cmd_syndesc *as, void *arock)
1654 {
1655     struct nvldbentry entry;
1656     volintInfo info;
1657     afs_uint32 volid;
1658     afs_int32 code, err;
1659     afs_int32 aserver, apart;
1660     int previdx = -1;
1661
1662     volid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);   /* -id */
1663     if (volid == 0) {
1664         if (err)
1665             PrintError("", err);
1666         else
1667             fprintf(STDERR, "Unknown volume ID or name '%s'\n",
1668                     as->parms[0].items->data);
1669         return -1;
1670     }
1671
1672     code = VLDB_GetEntryByID(volid, RWVOL, &entry);
1673     if (code) {
1674         fprintf(STDERR,
1675                 "Could not fetch the entry for volume number %lu from VLDB \n",
1676                 (unsigned long)volid);
1677         return (code);
1678     }
1679     MapHostToNetwork(&entry);
1680
1681     GetServerAndPart(&entry, RWVOL, &aserver, &apart, &previdx);
1682     if (previdx == -1) {
1683         fprintf(STDERR, "Volume %s does not exist in VLDB\n\n",
1684                 as->parms[0].items->data);
1685         return (ENOENT);
1686     }
1687
1688     init_volintInfo(&info);
1689     info.volid = volid;
1690     info.type = RWVOL;
1691
1692     if (as->parms[1].items) {
1693         /* -max <quota> */
1694         code = util_GetInt32(as->parms[1].items->data, &info.maxquota);
1695         if (code) {
1696             fprintf(STDERR, "invalid quota value\n");
1697             return code;
1698         }
1699     }
1700     if (as->parms[2].items) {
1701         /* -clearuse */
1702         info.dayUse = 0;
1703     }
1704     if (as->parms[3].items) {
1705         /* -clearVolUpCounter */
1706         info.spare2 = 0;
1707     }
1708     code = UV_SetVolumeInfo(aserver, apart, volid, &info);
1709     if (code)
1710         fprintf(STDERR,
1711                 "Could not update volume info fields for volume number %lu\n",
1712                 (unsigned long)volid);
1713     return (code);
1714 }
1715
1716 /*------------------------------------------------------------------------
1717  * PRIVATE volOnline
1718  *
1719  * Description:
1720  *      Brings a volume online.
1721  *
1722  * Arguments:
1723  *      as : Ptr to parsed command line arguments.
1724  *
1725  * Returns:
1726  *      0 for a successful operation,
1727  *
1728  * Environment:
1729  *      Nothing interesting.
1730  *
1731  * Side Effects:
1732  *      As advertised.
1733  *------------------------------------------------------------------------
1734  */
1735 static int
1736 volOnline(register struct cmd_syndesc *as, void *arock)
1737 {
1738     afs_int32 server, partition;
1739     afs_uint32 volid;
1740     afs_int32 code, err = 0;
1741
1742     server = GetServer(as->parms[0].items->data);
1743     if (server == 0) {
1744         fprintf(STDERR, "vos: server '%s' not found in host table\n",
1745                 as->parms[0].items->data);
1746         return -1;
1747     }
1748
1749     partition = volutil_GetPartitionID(as->parms[1].items->data);
1750     if (partition < 0) {
1751         fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
1752                 as->parms[1].items->data);
1753         return ENOENT;
1754     }
1755
1756     volid = vsu_GetVolumeID(as->parms[2].items->data, cstruct, &err);   /* -id */
1757     if (!volid) {
1758         if (err)
1759             PrintError("", err);
1760         else
1761             fprintf(STDERR, "Unknown volume ID or name '%s'\n",
1762                     as->parms[0].items->data);
1763         return -1;
1764     }
1765
1766     code = UV_SetVolume(server, partition, volid, ITOffline, 0 /*online */ ,
1767                         0 /*sleep */ );
1768     if (code) {
1769         fprintf(STDERR, "Failed to set volume. Code = %d\n", code);
1770         return -1;
1771     }
1772
1773     return 0;
1774 }
1775
1776 /*------------------------------------------------------------------------
1777  * PRIVATE volOffline
1778  *
1779  * Description:
1780  *      Brings a volume offline.
1781  *
1782  * Arguments:
1783  *      as : Ptr to parsed command line arguments.
1784  *
1785  * Returns:
1786  *      0 for a successful operation,
1787  *
1788  * Environment:
1789  *      Nothing interesting.
1790  *
1791  * Side Effects:
1792  *      As advertised.
1793  *------------------------------------------------------------------------
1794  */
1795 static int
1796 volOffline(register struct cmd_syndesc *as, void *arock)
1797 {
1798     afs_int32 server, partition;
1799     afs_uint32 volid;
1800     afs_int32 code, err = 0;
1801     afs_int32 transflag, sleeptime, transdone;
1802
1803     server = GetServer(as->parms[0].items->data);
1804     if (server == 0) {
1805         fprintf(STDERR, "vos: server '%s' not found in host table\n",
1806                 as->parms[0].items->data);
1807         return -1;
1808     }
1809
1810     partition = volutil_GetPartitionID(as->parms[1].items->data);
1811     if (partition < 0) {
1812         fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
1813                 as->parms[1].items->data);
1814         return ENOENT;
1815     }
1816
1817     volid = vsu_GetVolumeID(as->parms[2].items->data, cstruct, &err);   /* -id */
1818     if (!volid) {
1819         if (err)
1820             PrintError("", err);
1821         else
1822             fprintf(STDERR, "Unknown volume ID or name '%s'\n",
1823                     as->parms[0].items->data);
1824         return -1;
1825     }
1826
1827     transflag = (as->parms[4].items ? ITBusy : ITOffline);
1828     sleeptime = (as->parms[3].items ? atol(as->parms[3].items->data) : 0);
1829     transdone = (sleeptime ? 0 /*online */ : VTOutOfService);
1830     if (as->parms[4].items && !as->parms[3].items) {
1831         fprintf(STDERR, "-sleep option must be used with -busy flag\n");
1832         return -1;
1833     }
1834
1835     code =
1836         UV_SetVolume(server, partition, volid, transflag, transdone,
1837                      sleeptime);
1838     if (code) {
1839         fprintf(STDERR, "Failed to set volume. Code = %d\n", code);
1840         return -1;
1841     }
1842
1843     return 0;
1844 }
1845
1846 static int
1847 CreateVolume(register struct cmd_syndesc *as, void *arock)
1848 {
1849     afs_int32 pnum;
1850     char part[10];
1851     afs_uint32 volid;
1852     afs_int32 code;
1853     struct nvldbentry entry;
1854     afs_int32 vcode;
1855     afs_int32 quota;
1856
1857     quota = 5000;
1858     tserver = GetServer(as->parms[0].items->data);
1859     if (!tserver) {
1860         fprintf(STDERR, "vos: host '%s' not found in host table\n",
1861                 as->parms[0].items->data);
1862         return ENOENT;
1863     }
1864     pnum = volutil_GetPartitionID(as->parms[1].items->data);
1865     if (pnum < 0) {
1866         fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
1867                 as->parms[1].items->data);
1868         return ENOENT;
1869     }
1870     if (!IsPartValid(pnum, tserver, &code)) {   /*check for validity of the partition */
1871         if (code)
1872             PrintError("", code);
1873         else
1874             fprintf(STDERR,
1875                     "vos : partition %s does not exist on the server\n",
1876                     as->parms[1].items->data);
1877         return ENOENT;
1878     }
1879     if (!ISNAMEVALID(as->parms[2].items->data)) {
1880         fprintf(STDERR,
1881                 "vos: the name of the root volume %s exceeds the size limit of %d\n",
1882                 as->parms[2].items->data, VOLSER_OLDMAXVOLNAME - 10);
1883         return E2BIG;
1884     }
1885     if (!VolNameOK(as->parms[2].items->data)) {
1886         fprintf(STDERR,
1887                 "Illegal volume name %s, should not end in .readonly or .backup\n",
1888                 as->parms[2].items->data);
1889         return EINVAL;
1890     }
1891     if (IsNumeric(as->parms[2].items->data)) {
1892         fprintf(STDERR, "Illegal volume name %s, should not be a number\n",
1893                 as->parms[2].items->data);
1894         return EINVAL;
1895     }
1896     vcode = VLDB_GetEntryByName(as->parms[2].items->data, &entry);
1897     if (!vcode) {
1898         fprintf(STDERR, "Volume %s already exists\n",
1899                 as->parms[2].items->data);
1900         PrintDiagnostics("create", code);
1901         return EEXIST;
1902     }
1903
1904     if (as->parms[3].items) {
1905         if (!IsNumeric(as->parms[3].items->data)) {
1906             fprintf(STDERR, "Initial quota %s should be numeric.\n",
1907                     as->parms[3].items->data);
1908             return EINVAL;
1909         }
1910
1911         code = util_GetInt32(as->parms[3].items->data, &quota);
1912         if (code) {
1913             fprintf(STDERR, "vos: bad integer specified for quota.\n");
1914             return code;
1915         }
1916     }
1917
1918     code =
1919         UV_CreateVolume2(tserver, pnum, as->parms[2].items->data, quota, 0,
1920                          0, 0, 0, &volid);
1921     if (code) {
1922         PrintDiagnostics("create", code);
1923         return code;
1924     }
1925     MapPartIdIntoName(pnum, part);
1926     fprintf(STDOUT, "Volume %lu created on partition %s of %s\n",
1927             (unsigned long)volid, part, as->parms[0].items->data);
1928
1929     return 0;
1930 }
1931
1932 #if 0
1933 static afs_int32
1934 DeleteAll(struct nvldbentry *entry)
1935 {
1936     int i;
1937     afs_int32 error, code, curserver, curpart;
1938     afs_uint32 volid;
1939
1940     MapHostToNetwork(entry);
1941     error = 0;
1942     for (i = 0; i < entry->nServers; i++) {
1943         curserver = entry->serverNumber[i];
1944         curpart = entry->serverPartition[i];
1945         if (entry->serverFlags[i] & ITSROVOL) {
1946             volid = entry->volumeId[ROVOL];
1947         } else {
1948             volid = entry->volumeId[RWVOL];
1949         }
1950         code = UV_DeleteVolume(curserver, curpart, volid);
1951         if (code && !error)
1952             error = code;
1953     }
1954     return error;
1955 }
1956 #endif
1957
1958 static int
1959 DeleteVolume(struct cmd_syndesc *as, void *arock)
1960 {
1961     afs_int32 err, code = 0;
1962     afs_int32 server = 0, partition = -1;
1963     afs_uint32 volid;
1964     char pname[10];
1965     afs_int32 idx, j;
1966
1967     if (as->parms[0].items) {
1968         server = GetServer(as->parms[0].items->data);
1969         if (!server) {
1970             fprintf(STDERR, "vos: server '%s' not found in host table\n",
1971                     as->parms[0].items->data);
1972             return ENOENT;
1973         }
1974     }
1975
1976     if (as->parms[1].items) {
1977         partition = volutil_GetPartitionID(as->parms[1].items->data);
1978         if (partition < 0) {
1979             fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
1980                     as->parms[1].items->data);
1981             return EINVAL;
1982         }
1983
1984         /* Check for validity of the partition */
1985         if (!IsPartValid(partition, server, &code)) {
1986             if (code) {
1987                 PrintError("", code);
1988             } else {
1989                 fprintf(STDERR,
1990                         "vos : partition %s does not exist on the server\n",
1991                         as->parms[1].items->data);
1992             }
1993             return ENOENT;
1994         }
1995     }
1996
1997     volid = vsu_GetVolumeID(as->parms[2].items->data, cstruct, &err);
1998     if (volid == 0) {
1999         fprintf(STDERR, "Can't find volume name '%s' in VLDB\n",
2000                 as->parms[2].items->data);
2001         if (err)
2002             PrintError("", err);
2003         return ENOENT;
2004     }
2005
2006     /* If the server or partition option are not complete, try to fill
2007      * them in from the VLDB entry.
2008      */
2009     if ((partition == -1) || !server) {
2010         struct nvldbentry entry;
2011
2012         code = VLDB_GetEntryByID(volid, -1, &entry);
2013         if (code) {
2014             fprintf(STDERR,
2015                     "Could not fetch the entry for volume %lu from VLDB\n",
2016                     (unsigned long)volid);
2017             PrintError("", code);
2018             return (code);
2019         }
2020
2021         if (((volid == entry.volumeId[RWVOL]) && (entry.flags & RW_EXISTS))
2022             || ((volid == entry.volumeId[BACKVOL])
2023                 && (entry.flags & BACK_EXISTS))) {
2024             idx = Lp_GetRwIndex(&entry);
2025             if ((idx == -1) || (server && (server != entry.serverNumber[idx]))
2026                 || ((partition != -1)
2027                     && (partition != entry.serverPartition[idx]))) {
2028                 fprintf(STDERR, "VLDB: Volume '%s' no match\n",
2029                         as->parms[2].items->data);
2030                 return ENOENT;
2031             }
2032         } else if ((volid == entry.volumeId[ROVOL])
2033                    && (entry.flags & RO_EXISTS)) {
2034             for (idx = -1, j = 0; j < entry.nServers; j++) {
2035                 if (entry.serverFlags[j] != ITSROVOL)
2036                     continue;
2037
2038                 if (((server == 0) || (server == entry.serverNumber[j]))
2039                     && ((partition == -1)
2040                         || (partition == entry.serverPartition[j]))) {
2041                     if (idx != -1) {
2042                         fprintf(STDERR,
2043                                 "VLDB: Volume '%s' matches more than one RO\n",
2044                                 as->parms[2].items->data);
2045                         return ENOENT;
2046                     }
2047                     idx = j;
2048                 }
2049             }
2050             if (idx == -1) {
2051                 fprintf(STDERR, "VLDB: Volume '%s' no match\n",
2052                         as->parms[2].items->data);
2053                 return ENOENT;
2054             }
2055         } else {
2056             fprintf(STDERR, "VLDB: Volume '%s' no match\n",
2057                     as->parms[2].items->data);
2058             return ENOENT;
2059         }
2060
2061         server = htonl(entry.serverNumber[idx]);
2062         partition = entry.serverPartition[idx];
2063     }
2064
2065
2066     code = UV_DeleteVolume(server, partition, volid);
2067     if (code) {
2068         PrintDiagnostics("remove", code);
2069         return code;
2070     }
2071
2072     MapPartIdIntoName(partition, pname);
2073     fprintf(STDOUT, "Volume %lu on partition %s server %s deleted\n",
2074             (unsigned long)volid, pname, hostutil_GetNameByINet(server));
2075     return 0;
2076 }
2077
2078 #define TESTM   0               /* set for move space tests, clear for production */
2079 static int
2080 MoveVolume(register struct cmd_syndesc *as, void *arock)
2081 {
2082
2083     afs_uint32 volid;
2084     afs_int32 fromserver, toserver, frompart, topart;
2085     afs_int32 flags, code, err;
2086     char fromPartName[10], toPartName[10];
2087
2088     struct diskPartition64 partition;   /* for space check */
2089     volintInfo *p;
2090
2091     volid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);
2092     if (volid == 0) {
2093         if (err)
2094             PrintError("", err);
2095         else
2096             fprintf(STDERR, "vos: can't find volume ID or name '%s'\n",
2097                     as->parms[0].items->data);
2098         return ENOENT;
2099     }
2100     fromserver = GetServer(as->parms[1].items->data);
2101     if (fromserver == 0) {
2102         fprintf(STDERR, "vos: server '%s' not found in host table\n",
2103                 as->parms[1].items->data);
2104         return ENOENT;
2105     }
2106     toserver = GetServer(as->parms[3].items->data);
2107     if (toserver == 0) {
2108         fprintf(STDERR, "vos: server '%s' not found in host table\n",
2109                 as->parms[3].items->data);
2110         return ENOENT;
2111     }
2112     frompart = volutil_GetPartitionID(as->parms[2].items->data);
2113     if (frompart < 0) {
2114         fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
2115                 as->parms[2].items->data);
2116         return EINVAL;
2117     }
2118     if (!IsPartValid(frompart, fromserver, &code)) {    /*check for validity of the partition */
2119         if (code)
2120             PrintError("", code);
2121         else
2122             fprintf(STDERR,
2123                     "vos : partition %s does not exist on the server\n",
2124                     as->parms[2].items->data);
2125         return ENOENT;
2126     }
2127     topart = volutil_GetPartitionID(as->parms[4].items->data);
2128     if (topart < 0) {
2129         fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
2130                 as->parms[4].items->data);
2131         return EINVAL;
2132     }
2133     if (!IsPartValid(topart, toserver, &code)) {        /*check for validity of the partition */
2134         if (code)
2135             PrintError("", code);
2136         else
2137             fprintf(STDERR,
2138                     "vos : partition %s does not exist on the server\n",
2139                     as->parms[4].items->data);
2140         return ENOENT;
2141     }
2142
2143     flags = 0;
2144     if (as->parms[5].items) flags |= RV_NOCLONE;
2145
2146     /*
2147      * check source partition for space to clone volume
2148      */
2149
2150     MapPartIdIntoName(topart, toPartName);
2151     MapPartIdIntoName(frompart, fromPartName);
2152
2153     /*
2154      * check target partition for space to move volume
2155      */
2156
2157     code = UV_PartitionInfo64(toserver, toPartName, &partition);
2158     if (code) {
2159         fprintf(STDERR, "vos: cannot access partition %s\n", toPartName);
2160         exit(1);
2161     }
2162     if (TESTM)
2163         fprintf(STDOUT, "target partition %s free space %" AFS_INT64_FMT "\n", toPartName,
2164                 partition.free);
2165
2166     p = (volintInfo *) 0;
2167     code = UV_ListOneVolume(fromserver, frompart, volid, &p);
2168     if (code) {
2169         fprintf(STDERR, "vos:cannot access volume %lu\n",
2170                 (unsigned long)volid);
2171         exit(1);
2172     }
2173     if (TESTM)
2174         fprintf(STDOUT, "volume %lu size %d\n", (unsigned long)volid,
2175                 p->size);
2176     if (partition.free <= p->size) {
2177         fprintf(STDERR,
2178                 "vos: no space on target partition %s to move volume %lu\n",
2179                 toPartName, (unsigned long)volid);
2180         free(p);
2181         exit(1);
2182     }
2183     free(p);
2184
2185     if (TESTM) {
2186         fprintf(STDOUT, "size test - don't do move\n");
2187         exit(0);
2188     }
2189
2190     /* successful move still not guaranteed but shoot for it */
2191
2192     code =
2193         UV_MoveVolume2(volid, fromserver, frompart, toserver, topart, flags);
2194     if (code) {
2195         PrintDiagnostics("move", code);
2196         return code;
2197     }
2198     MapPartIdIntoName(topart, toPartName);
2199     MapPartIdIntoName(frompart, fromPartName);
2200     fprintf(STDOUT, "Volume %lu moved from %s %s to %s %s \n",
2201             (unsigned long)volid, as->parms[1].items->data, fromPartName,
2202             as->parms[3].items->data, toPartName);
2203
2204     return 0;
2205 }
2206
2207 static int
2208 CopyVolume(register struct cmd_syndesc *as, void *arock)
2209 {
2210     afs_uint32 volid;
2211     afs_int32 fromserver, toserver, frompart, topart, code, err, flags;
2212     char fromPartName[10], toPartName[10], *tovolume;
2213     struct nvldbentry entry;
2214     struct diskPartition64 partition;   /* for space check */
2215     volintInfo *p;
2216
2217     volid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);
2218     if (volid == 0) {
2219         if (err)
2220             PrintError("", err);
2221         else
2222             fprintf(STDERR, "vos: can't find volume ID or name '%s'\n",
2223                     as->parms[0].items->data);
2224         return ENOENT;
2225     }
2226     fromserver = GetServer(as->parms[1].items->data);
2227     if (fromserver == 0) {
2228         fprintf(STDERR, "vos: server '%s' not found in host table\n",
2229                 as->parms[1].items->data);
2230         return ENOENT;
2231     }
2232
2233     toserver = GetServer(as->parms[4].items->data);
2234     if (toserver == 0) {
2235         fprintf(STDERR, "vos: server '%s' not found in host table\n",
2236                 as->parms[4].items->data);
2237         return ENOENT;
2238     }
2239
2240     tovolume = as->parms[3].items->data;
2241     if (!ISNAMEVALID(tovolume)) {
2242         fprintf(STDERR,
2243                 "vos: the name of the root volume %s exceeds the size limit of %d\n",
2244                 tovolume, VOLSER_OLDMAXVOLNAME - 10);
2245         return E2BIG;
2246     }
2247     if (!VolNameOK(tovolume)) {
2248         fprintf(STDERR,
2249                 "Illegal volume name %s, should not end in .readonly or .backup\n",
2250                 tovolume);
2251         return EINVAL;
2252     }
2253     if (IsNumeric(tovolume)) {
2254         fprintf(STDERR, "Illegal volume name %s, should not be a number\n",
2255                 tovolume);
2256         return EINVAL;
2257     }
2258     code = VLDB_GetEntryByName(tovolume, &entry);
2259     if (!code) {
2260         fprintf(STDERR, "Volume %s already exists\n", tovolume);
2261         PrintDiagnostics("copy", code);
2262         return EEXIST;
2263     }
2264
2265     frompart = volutil_GetPartitionID(as->parms[2].items->data);
2266     if (frompart < 0) {
2267         fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
2268                 as->parms[2].items->data);
2269         return EINVAL;
2270     }
2271     if (!IsPartValid(frompart, fromserver, &code)) {    /*check for validity of the partition */
2272         if (code)
2273             PrintError("", code);
2274         else
2275             fprintf(STDERR,
2276                     "vos : partition %s does not exist on the server\n",
2277                     as->parms[2].items->data);
2278         return ENOENT;
2279     }
2280
2281     topart = volutil_GetPartitionID(as->parms[5].items->data);
2282     if (topart < 0) {
2283         fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
2284                 as->parms[5].items->data);
2285         return EINVAL;
2286     }
2287     if (!IsPartValid(topart, toserver, &code)) {        /*check for validity of the partition */
2288         if (code)
2289             PrintError("", code);
2290         else
2291             fprintf(STDERR,
2292                     "vos : partition %s does not exist on the server\n",
2293                     as->parms[5].items->data);
2294         return ENOENT;
2295     }
2296
2297     flags = 0;
2298     if (as->parms[6].items) flags |= RV_OFFLINE;
2299     if (as->parms[7].items) flags |= RV_RDONLY;
2300     if (as->parms[8].items) flags |= RV_NOCLONE;
2301
2302     MapPartIdIntoName(topart, toPartName);
2303     MapPartIdIntoName(frompart, fromPartName);
2304
2305     /*
2306      * check target partition for space to move volume
2307      */
2308
2309     code = UV_PartitionInfo64(toserver, toPartName, &partition);
2310     if (code) {
2311         fprintf(STDERR, "vos: cannot access partition %s\n", toPartName);
2312         exit(1);
2313     }
2314     if (TESTM)
2315         fprintf(STDOUT, "target partition %s free space %" AFS_INT64_FMT "\n", toPartName,
2316                 partition.free);
2317
2318     p = (volintInfo *) 0;
2319     code = UV_ListOneVolume(fromserver, frompart, volid, &p);
2320     if (code) {
2321         fprintf(STDERR, "vos:cannot access volume %lu\n",
2322                 (unsigned long)volid);
2323         exit(1);
2324     }
2325
2326     if (partition.free <= p->size) {
2327         fprintf(STDERR,
2328                 "vos: no space on target partition %s to copy volume %lu\n",
2329                 toPartName, (unsigned long)volid);
2330         free(p);
2331         exit(1);
2332     }
2333     free(p);
2334
2335     /* successful copy still not guaranteed but shoot for it */
2336
2337     code =
2338         UV_CopyVolume2(volid, fromserver, frompart, tovolume, toserver,
2339                        topart, 0, flags);
2340     if (code) {
2341         PrintDiagnostics("copy", code);
2342         return code;
2343     }
2344     MapPartIdIntoName(topart, toPartName);
2345     MapPartIdIntoName(frompart, fromPartName);
2346     fprintf(STDOUT, "Volume %lu copied from %s %s to %s on %s %s \n",
2347             (unsigned long)volid, as->parms[1].items->data, fromPartName,
2348             tovolume, as->parms[4].items->data, toPartName);
2349
2350     return 0;
2351 }
2352
2353
2354 static int
2355 ShadowVolume(register struct cmd_syndesc *as, void *arock)
2356 {
2357     afs_uint32 volid, tovolid;
2358     afs_int32 fromserver, toserver, frompart, topart;
2359     afs_int32 code, err, flags;
2360     char fromPartName[10], toPartName[10], toVolName[32], *tovolume;
2361     struct diskPartition64 partition;   /* for space check */
2362     volintInfo *p, *q;
2363
2364     p = (volintInfo *) 0;
2365     q = (volintInfo *) 0;
2366
2367     volid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);
2368     if (volid == 0) {
2369         if (err)
2370             PrintError("", err);
2371         else
2372             fprintf(STDERR, "vos: can't find volume ID or name '%s'\n",
2373                     as->parms[0].items->data);
2374         return ENOENT;
2375     }
2376     fromserver = GetServer(as->parms[1].items->data);
2377     if (fromserver == 0) {
2378         fprintf(STDERR, "vos: server '%s' not found in host table\n",
2379                 as->parms[1].items->data);
2380         return ENOENT;
2381     }
2382
2383     toserver = GetServer(as->parms[3].items->data);
2384     if (toserver == 0) {
2385         fprintf(STDERR, "vos: server '%s' not found in host table\n",
2386                 as->parms[3].items->data);
2387         return ENOENT;
2388     }
2389
2390     frompart = volutil_GetPartitionID(as->parms[2].items->data);
2391     if (frompart < 0) {
2392         fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
2393                 as->parms[2].items->data);
2394         return EINVAL;
2395     }
2396     if (!IsPartValid(frompart, fromserver, &code)) {    /*check for validity of the partition */
2397         if (code)
2398             PrintError("", code);
2399         else
2400             fprintf(STDERR,
2401                     "vos : partition %s does not exist on the server\n",
2402                     as->parms[2].items->data);
2403         return ENOENT;
2404     }
2405
2406     topart = volutil_GetPartitionID(as->parms[4].items->data);
2407     if (topart < 0) {
2408         fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
2409                 as->parms[4].items->data);
2410         return EINVAL;
2411     }
2412     if (!IsPartValid(topart, toserver, &code)) {        /*check for validity of the partition */
2413         if (code)
2414             PrintError("", code);
2415         else
2416             fprintf(STDERR,
2417                     "vos : partition %s does not exist on the server\n",
2418                     as->parms[4].items->data);
2419         return ENOENT;
2420     }
2421
2422     if (as->parms[5].items) {
2423         tovolume = as->parms[5].items->data;
2424         if (!ISNAMEVALID(tovolume)) {
2425             fprintf(STDERR,
2426                 "vos: the name of the root volume %s exceeds the size limit of %d\n",
2427                 tovolume, VOLSER_OLDMAXVOLNAME - 10);
2428             return E2BIG;
2429         }
2430         if (!VolNameOK(tovolume)) {
2431             fprintf(STDERR,
2432                 "Illegal volume name %s, should not end in .readonly or .backup\n",
2433                 tovolume);
2434             return EINVAL;
2435         }
2436         if (IsNumeric(tovolume)) {
2437             fprintf(STDERR,
2438                 "Illegal volume name %s, should not be a number\n",
2439                 tovolume);
2440             return EINVAL;
2441         }
2442     } else {
2443         /* use actual name of source volume */
2444         code = UV_ListOneVolume(fromserver, frompart, volid, &p);
2445         if (code) {
2446             fprintf(STDERR, "vos:cannot access volume %lu\n",
2447                 (unsigned long)volid);
2448             exit(1);
2449         }
2450         strcpy(toVolName, p->name);
2451         tovolume = toVolName;
2452         /* save p for size checks later */
2453     }
2454
2455     if (as->parms[6].items) {
2456         tovolid = vsu_GetVolumeID(as->parms[6].items->data, cstruct, &err);
2457         if (tovolid == 0) {
2458             if (err)
2459                 PrintError("", err);
2460             else
2461                 fprintf(STDERR, "vos: can't find volume ID or name '%s'\n",
2462                         as->parms[6].items->data);
2463             if (p)
2464                 free(p);
2465             return ENOENT;
2466         }
2467     } else {
2468         tovolid = vsu_GetVolumeID(tovolume, cstruct, &err);
2469         if (tovolid == 0) {
2470             if (err)
2471                 PrintError("", err);
2472             else
2473                 fprintf(STDERR, "vos: can't find volume ID or name '%s'\n",
2474                         tovolume);
2475             if (p)
2476                 free(p);
2477             return ENOENT;
2478         }
2479     }
2480
2481     flags = RV_NOVLDB;
2482     if (as->parms[7].items) flags |= RV_OFFLINE;
2483     if (as->parms[8].items) flags |= RV_RDONLY;
2484     if (as->parms[9].items) flags |= RV_NOCLONE;
2485     if (as->parms[10].items) flags |= RV_CPINCR;
2486
2487     MapPartIdIntoName(topart, toPartName);
2488     MapPartIdIntoName(frompart, fromPartName);
2489
2490     /*
2491      * check target partition for space to move volume
2492      */
2493
2494     code = UV_PartitionInfo64(toserver, toPartName, &partition);
2495     if (code) {
2496         fprintf(STDERR, "vos: cannot access partition %s\n", toPartName);
2497         exit(1);
2498     }
2499     if (TESTM)
2500         fprintf(STDOUT, "target partition %s free space %" AFS_INT64_FMT "\n", toPartName,
2501                 partition.free);
2502
2503     /* Don't do this again if we did it above */
2504     if (!p) {
2505         code = UV_ListOneVolume(fromserver, frompart, volid, &p);
2506         if (code) {
2507             fprintf(STDERR, "vos:cannot access volume %lu\n",
2508                 (unsigned long)volid);
2509             exit(1);
2510         }
2511     }
2512
2513     /* OK if this fails */
2514     code = UV_ListOneVolume(toserver, topart, tovolid, &q);
2515
2516     /* Treat existing volume size as "free" */
2517     if (q)
2518         p->size = (q->size < p->size) ? p->size - q->size : 0;
2519
2520     if (partition.free <= p->size) {
2521         fprintf(STDERR,
2522                 "vos: no space on target partition %s to copy volume %lu\n",
2523                 toPartName, (unsigned long)volid);
2524         free(p);
2525         if (q) free(q);
2526         exit(1);
2527     }
2528     free(p);
2529     if (q) free(q);
2530
2531     /* successful copy still not guaranteed but shoot for it */
2532
2533     code =
2534         UV_CopyVolume2(volid, fromserver, frompart, tovolume, toserver,
2535                        topart, tovolid, flags);
2536     if (code) {
2537         PrintDiagnostics("shadow", code);
2538         return code;
2539     }
2540     MapPartIdIntoName(topart, toPartName);
2541     MapPartIdIntoName(frompart, fromPartName);
2542     fprintf(STDOUT, "Volume %lu shadowed from %s %s to %s %s \n",
2543             (unsigned long)volid, as->parms[1].items->data, fromPartName,
2544             as->parms[3].items->data, toPartName);
2545
2546     return 0;
2547 }
2548
2549
2550 static int
2551 CloneVolume(register struct cmd_syndesc *as, void *arock)
2552 {
2553     afs_uint32 volid, cloneid;
2554     afs_int32 server, part, voltype;
2555     char partName[10], *volname;
2556     afs_int32 code, err, flags;
2557     struct nvldbentry entry;
2558
2559     volid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);
2560     if (volid == 0) {
2561         if (err)
2562             PrintError("", err);
2563         else
2564             fprintf(STDERR, "vos: can't find volume ID or name '%s'\n",
2565                     as->parms[0].items->data);
2566         return ENOENT;
2567     }
2568
2569     if (as->parms[1].items || as->parms[2].items) {
2570         if (!as->parms[1].items || !as->parms[2].items) {
2571             fprintf(STDERR,
2572                     "Must specify both -server and -partition options\n");
2573             return -1;
2574         }
2575         server = GetServer(as->parms[1].items->data);
2576         if (server == 0) {
2577             fprintf(STDERR, "vos: server '%s' not found in host table\n",
2578                     as->parms[1].items->data);
2579             return ENOENT;
2580         }
2581         part = volutil_GetPartitionID(as->parms[2].items->data);
2582         if (part < 0) {
2583             fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
2584                     as->parms[2].items->data);
2585             return EINVAL;
2586         }
2587         if (!IsPartValid(part, server, &code)) {        /*check for validity of the partition */
2588             if (code)
2589                 PrintError("", code);
2590             else
2591                 fprintf(STDERR,
2592                     "vos : partition %s does not exist on the server\n",
2593                     as->parms[2].items->data);
2594             return ENOENT;
2595         }
2596     } else {
2597         code = GetVolumeInfo(volid, &server, &part, &voltype, &entry);
2598         if (code)
2599             return code;
2600     }
2601
2602     volname = 0;
2603     if (as->parms[3].items) {
2604         volname = as->parms[3].items->data;
2605         if (strlen(volname) > VOLSER_OLDMAXVOLNAME - 1) {
2606             fprintf(STDERR,
2607                 "vos: the name of the root volume %s exceeds the size limit of %d\n",
2608                 volname, VOLSER_OLDMAXVOLNAME - 1);
2609             return E2BIG;
2610         }
2611 #if 0
2612         /* 
2613          * In order that you be able to make clones of RO or BK, this
2614          * check must be omitted.
2615          */
2616         if (!VolNameOK(volname)) {
2617             fprintf(STDERR,
2618                 "Illegal volume name %s, should not end in .readonly or .backup\n",
2619                 volname);
2620             return EINVAL;
2621         }
2622 #endif
2623         if (IsNumeric(volname)) {
2624             fprintf(STDERR,
2625                 "Illegal volume name %s, should not be a number\n",
2626                 volname);
2627             return EINVAL;
2628         }
2629     }
2630
2631     cloneid = 0;
2632     if (as->parms[4].items) {
2633         cloneid = vsu_GetVolumeID(as->parms[4].items->data, cstruct, &err);
2634         if (cloneid == 0) {
2635             if (err)
2636                 PrintError("", err);
2637             else
2638                 fprintf(STDERR, "vos: can't find volume ID or name '%s'\n",
2639                         as->parms[4].items->data);
2640             return ENOENT;
2641         }
2642     }
2643
2644     flags = 0;
2645     if (as->parms[5].items) flags |= RV_OFFLINE;
2646     if (as->parms[6].items) flags |= RV_RDONLY;
2647
2648
2649     code = 
2650         UV_CloneVolume(server, part, volid, cloneid, volname, flags);
2651
2652     if (code) {
2653         PrintDiagnostics("clone", code);
2654         return code;
2655     }
2656     MapPartIdIntoName(part, partName);
2657     fprintf(STDOUT, "Created clone for volume %s\n",
2658             as->parms[0].items->data);
2659
2660     return 0;
2661 }
2662
2663
2664 static int
2665 BackupVolume(register struct cmd_syndesc *as, void *arock)
2666 {
2667     afs_uint32 avolid;
2668     afs_int32 aserver, apart, vtype, code, err;
2669     struct nvldbentry entry;
2670
2671     afs_uint32 buvolid;
2672     afs_int32 buserver, bupart, butype;
2673     struct nvldbentry buentry;
2674
2675     avolid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);
2676     if (avolid == 0) {
2677         if (err)
2678             PrintError("", err);
2679         else
2680             fprintf(STDERR, "vos: can't find volume ID or name '%s'\n",
2681                     as->parms[0].items->data);
2682         return ENOENT;
2683     }
2684     code = GetVolumeInfo(avolid, &aserver, &apart, &vtype, &entry);
2685     if (code)
2686         exit(1);
2687
2688     /* verify this is a readwrite volume */
2689
2690     if (vtype != RWVOL) {
2691         fprintf(STDERR, "%s not RW volume\n", as->parms[0].items->data);
2692         exit(1);
2693     }
2694
2695     /* is there a backup volume already? */
2696
2697     if (entry.flags & BACK_EXISTS) {
2698         /* yep, where is it? */
2699
2700         buvolid = entry.volumeId[BACKVOL];
2701         code = GetVolumeInfo(buvolid, &buserver, &bupart, &butype, &buentry);
2702         if (code)
2703             exit(1);
2704
2705         /* is it local? */
2706         code = VLDB_IsSameAddrs(buserver, aserver, &err);
2707         if (err) {
2708             fprintf(STDERR,
2709                     "Failed to get info about server's %d address(es) from vlserver; aborting call!\n",
2710                     buserver);
2711             exit(1);
2712         }
2713         if (!code) {
2714             fprintf(STDERR,
2715                     "FATAL ERROR: backup volume %lu exists on server %lu\n",
2716                     (unsigned long)buvolid, (unsigned long)buserver);
2717             exit(1);
2718         }
2719     }
2720
2721     /* nope, carry on */
2722
2723     code = UV_BackupVolume(aserver, apart, avolid);
2724
2725     if (code) {
2726         PrintDiagnostics("backup", code);
2727         return code;
2728     }
2729     fprintf(STDOUT, "Created backup volume for %s \n",
2730             as->parms[0].items->data);
2731     return 0;
2732 }
2733
2734 static int
2735 ReleaseVolume(register struct cmd_syndesc *as, void *arock)
2736 {
2737
2738     struct nvldbentry entry;
2739     afs_uint32 avolid;
2740     afs_int32 aserver, apart, vtype, code, err;
2741     int force = 0;
2742
2743     if (as->parms[1].items)
2744         force = 1;
2745     avolid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);
2746     if (avolid == 0) {
2747         if (err)
2748             PrintError("", err);
2749         else
2750             fprintf(STDERR, "vos: can't find volume '%s'\n",
2751                     as->parms[0].items->data);
2752         return ENOENT;
2753     }
2754     code = GetVolumeInfo(avolid, &aserver, &apart, &vtype, &entry);
2755     if (code)
2756         return code;
2757
2758     if (vtype != RWVOL) {
2759         fprintf(STDERR, "%s not a RW volume\n", as->parms[0].items->data);
2760         return (ENOENT);
2761     }
2762
2763     if (!ISNAMEVALID(entry.name)) {
2764         fprintf(STDERR,
2765                 "Volume name %s is too long, rename before releasing\n",
2766                 entry.name);
2767         return E2BIG;
2768     }
2769
2770     code = UV_ReleaseVolume(avolid, aserver, apart, force);
2771     if (code) {
2772         PrintDiagnostics("release", code);
2773         return code;
2774     }
2775     fprintf(STDOUT, "Released volume %s successfully\n",
2776             as->parms[0].items->data);
2777     return 0;
2778 }
2779
2780 static int
2781 DumpVolumeCmd(register struct cmd_syndesc *as, void *arock)
2782 {
2783     afs_uint32 avolid;
2784     afs_int32 aserver, apart, voltype, fromdate = 0, code, err, i, flags;
2785     char filename[MAXPATHLEN];
2786     struct nvldbentry entry;
2787
2788     rx_SetRxDeadTime(60 * 10);
2789     for (i = 0; i < MAXSERVERS; i++) {
2790         struct rx_connection *rxConn = ubik_GetRPCConn(cstruct, i);
2791         if (rxConn == 0)
2792             break;
2793         rx_SetConnDeadTime(rxConn, rx_connDeadTime);
2794         if (rxConn->service)
2795             rxConn->service->connDeadTime = rx_connDeadTime;
2796     }
2797
2798     avolid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);
2799     if (avolid == 0) {
2800         if (err)
2801             PrintError("", err);
2802         else
2803             fprintf(STDERR, "vos: can't find volume '%s'\n",
2804                     as->parms[0].items->data);
2805         return ENOENT;
2806     }
2807
2808     if (as->parms[3].items || as->parms[4].items) {
2809         if (!as->parms[3].items || !as->parms[4].items) {
2810             fprintf(STDERR,
2811                     "Must specify both -server and -partition options\n");
2812             return -1;
2813         }
2814         aserver = GetServer(as->parms[3].items->data);
2815         if (aserver == 0) {
2816             fprintf(STDERR, "Invalid server name\n");
2817             return -1;
2818         }
2819         apart = volutil_GetPartitionID(as->parms[4].items->data);
2820         if (apart < 0) {
2821             fprintf(STDERR, "Invalid partition name\n");
2822             return -1;
2823         }
2824     } else {
2825         code = GetVolumeInfo(avolid, &aserver, &apart, &voltype, &entry);
2826         if (code)
2827             return code;
2828     }
2829
2830     if (as->parms[1].items && strcmp(as->parms[1].items->data, "0")) {
2831         code = ktime_DateToInt32(as->parms[1].items->data, &fromdate);
2832         if (code) {
2833             fprintf(STDERR, "vos: failed to parse date '%s' (error=%d))\n",
2834                     as->parms[1].items->data, code);
2835             return code;
2836         }
2837     }
2838     if (as->parms[2].items) {
2839         strcpy(filename, as->parms[2].items->data);
2840     } else {
2841         strcpy(filename, "");
2842     }
2843
2844     flags = as->parms[6].items ? VOLDUMPV2_OMITDIRS : 0;
2845 retry_dump:
2846     if (as->parms[5].items) {
2847         code =
2848             UV_DumpClonedVolume(avolid, aserver, apart, fromdate,
2849                                 DumpFunction, filename, flags);
2850     } else {
2851         code =
2852             UV_DumpVolume(avolid, aserver, apart, fromdate, DumpFunction,
2853                           filename, flags);
2854     }
2855     if ((code == RXGEN_OPCODE) && (as->parms[6].items)) {
2856         flags &= ~VOLDUMPV2_OMITDIRS;
2857         goto retry_dump;
2858     }
2859     if (code) {
2860         PrintDiagnostics("dump", code);
2861         return code;
2862     }
2863     if (strcmp(filename, ""))
2864         fprintf(STDERR, "Dumped volume %s in file %s\n",
2865                 as->parms[0].items->data, filename);
2866     else
2867         fprintf(STDERR, "Dumped volume %s in stdout \n",
2868                 as->parms[0].items->data);
2869     return 0;
2870 }
2871
2872 #define ASK   0
2873 #define ABORT 1
2874 #define FULL  2
2875 #define INC   3
2876
2877 #define TS_DUMP 1
2878 #define TS_KEEP 2
2879 #define TS_NEW  3
2880
2881 static int
2882 RestoreVolumeCmd(register struct cmd_syndesc *as, void *arock)
2883 {
2884     afs_uint32 avolid, aparentid;
2885     afs_int32 aserver, apart, code, vcode, err;
2886     afs_int32 aoverwrite = ASK;
2887     afs_int32 acreation = 0, alastupdate = 0;
2888     int restoreflags = 0;
2889     int readonly = 0, offline = 0, voltype = RWVOL;
2890     char prompt;
2891     char afilename[MAXPATHLEN], avolname[VOLSER_MAXVOLNAME + 1], apartName[10];
2892     char volname[VOLSER_MAXVOLNAME + 1];
2893     struct nvldbentry entry;
2894
2895     prompt = 'n';
2896
2897     aparentid = 0;
2898     if (as->parms[4].items) {
2899         avolid = vsu_GetVolumeID(as->parms[4].items->data, cstruct, &err);
2900         if (avolid == 0) {
2901             if (err)
2902                 PrintError("", err);
2903             else
2904                 fprintf(STDERR, "vos: can't find volume '%s'\n",
2905                         as->parms[4].items->data);
2906             exit(1);
2907         }
2908     } else
2909         avolid = 0;
2910
2911     if (as->parms[5].items) {
2912         if ((strcmp(as->parms[5].items->data, "a") == 0)
2913             || (strcmp(as->parms[5].items->data, "abort") == 0)) {
2914             aoverwrite = ABORT;
2915         } else if ((strcmp(as->parms[5].items->data, "f") == 0)
2916                    || (strcmp(as->parms[5].items->data, "full") == 0)) {
2917             aoverwrite = FULL;
2918         } else if ((strcmp(as->parms[5].items->data, "i") == 0)
2919                    || (strcmp(as->parms[5].items->data, "inc") == 0)
2920                    || (strcmp(as->parms[5].items->data, "increment") == 0)
2921                    || (strcmp(as->parms[5].items->data, "incremental") == 0)) {
2922             aoverwrite = INC;
2923         } else {
2924             fprintf(STDERR, "vos: %s is not a valid argument to -overwrite\n",
2925                     as->parms[5].items->data);
2926             exit(1);
2927         }
2928     }
2929     if (as->parms[6].items)
2930         offline = 1;
2931     if (as->parms[7].items) {
2932         readonly = 1;
2933         voltype = ROVOL;
2934     }
2935
2936     if (as->parms[8].items) {
2937         if ((strcmp(as->parms[8].items->data, "d") == 0)
2938             || (strcmp(as->parms[8].items->data, "dump") == 0)) {
2939             acreation = TS_DUMP;
2940         } else if ((strcmp(as->parms[8].items->data, "k") == 0)
2941             || (strcmp(as->parms[8].items->data, "keep") == 0)) {
2942             acreation = TS_KEEP;
2943         } else if ((strcmp(as->parms[8].items->data, "n") == 0)
2944             || (strcmp(as->parms[8].items->data, "new") == 0)) {
2945             acreation = TS_NEW;
2946         } else {
2947             fprintf(STDERR, "vos: %s is not a valid argument to -creation\n",
2948                     as->parms[8].items->data);
2949             exit(1);
2950         }
2951     }
2952
2953     if (as->parms[9].items) {
2954         if ((strcmp(as->parms[9].items->data, "d") == 0)
2955             || (strcmp(as->parms[9].items->data, "dump") == 0)) {
2956             alastupdate = TS_DUMP;
2957         } else if ((strcmp(as->parms[9].items->data, "k") == 0)
2958             || (strcmp(as->parms[9].items->data, "keep") == 0)) {
2959             alastupdate = TS_KEEP;
2960         } else if ((strcmp(as->parms[9].items->data, "n") == 0)
2961             || (strcmp(as->parms[9].items->data, "new") == 0)) {
2962             alastupdate = TS_NEW;
2963         } else {
2964             fprintf(STDERR, "vos: %s is not a valid argument to -lastupdate\n",
2965                     as->parms[9].items->data);
2966             exit(1);
2967         }
2968     }
2969
2970     aserver = GetServer(as->parms[0].items->data);
2971     if (aserver == 0) {
2972         fprintf(STDERR, "vos: server '%s' not found in host table\n",
2973                 as->parms[0].items->data);
2974         exit(1);
2975     }
2976     apart = volutil_GetPartitionID(as->parms[1].items->data);
2977     if (apart < 0) {
2978         fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
2979                 as->parms[1].items->data);
2980         exit(1);
2981     }
2982     if (!IsPartValid(apart, aserver, &code)) {  /*check for validity of the partition */
2983         if (code)
2984             PrintError("", code);
2985         else
2986             fprintf(STDERR,
2987                     "vos : partition %s does not exist on the server\n",
2988                     as->parms[1].items->data);
2989         exit(1);
2990     }
2991     strcpy(avolname, as->parms[2].items->data);
2992     if (!ISNAMEVALID(avolname)) {
2993         fprintf(STDERR,
2994                 "vos: the name of the volume %s exceeds the size limit\n",
2995                 avolname);
2996         exit(1);
2997     }
2998     if (!VolNameOK(avolname)) {
2999         fprintf(STDERR,
3000                 "Illegal volume name %s, should not end in .readonly or .backup\n",
3001                 avolname);
3002         exit(1);
3003     }
3004     if (as->parms[3].items) {
3005         strcpy(afilename, as->parms[3].items->data);
3006         if (!FileExists(afilename)) {
3007             fprintf(STDERR, "Can't access file %s\n", afilename);
3008             exit(1);
3009         }
3010     } else {
3011         strcpy(afilename, "");
3012     }
3013
3014     /* Check if volume exists or not */
3015
3016     vsu_ExtractName(volname, avolname);
3017     vcode = VLDB_GetEntryByName(volname, &entry);
3018     if (vcode) {                /* no volume - do a full restore */
3019         restoreflags = RV_FULLRST;
3020         if ((aoverwrite == INC) || (aoverwrite == ABORT))
3021             fprintf(STDERR,
3022                     "Volume does not exist; Will perform a full restore\n");
3023     }
3024
3025     else if ((!readonly && Lp_GetRwIndex(&entry) == -1) /* RW volume does not exist - do a full */
3026              ||(readonly && !Lp_ROMatch(0, 0, &entry))) {       /* RO volume does not exist - do a full */
3027         restoreflags = RV_FULLRST;
3028         if ((aoverwrite == INC) || (aoverwrite == ABORT))
3029             fprintf(STDERR,
3030                     "%s Volume does not exist; Will perform a full restore\n",
3031                     readonly ? "RO" : "RW");
3032
3033         if (avolid == 0) {
3034             avolid = entry.volumeId[voltype];
3035         } else if (entry.volumeId[voltype] != 0
3036                    && entry.volumeId[voltype] != avolid) {
3037             avolid = entry.volumeId[voltype];
3038         }
3039         aparentid = entry.volumeId[RWVOL];
3040     }
3041
3042     else {                      /* volume exists - do we do a full incremental or abort */
3043         int Oserver, Opart, Otype, vol_elsewhere = 0;
3044         struct nvldbentry Oentry;
3045         int c, dc;
3046
3047         if (avolid == 0) {
3048             avolid = entry.volumeId[voltype];
3049         } else if (entry.volumeId[voltype] != 0
3050                    && entry.volumeId[voltype] != avolid) {
3051             avolid = entry.volumeId[voltype];
3052         }
3053         aparentid = entry.volumeId[RWVOL];
3054
3055         /* A file name was specified  - check if volume is on another partition */
3056         vcode = GetVolumeInfo(avolid, &Oserver, &Opart, &Otype, &Oentry);
3057         if (vcode)
3058             exit(1);
3059
3060         vcode = VLDB_IsSameAddrs(Oserver, aserver, &err);
3061         if (err) {
3062             fprintf(STDERR,
3063                     "Failed to get info about server's %d address(es) from vlserver (err=%d); aborting call!\n",
3064                     Oserver, err);
3065             exit(1);
3066         }
3067         if (!vcode || (Opart != apart))
3068             vol_elsewhere = 1;
3069
3070         if (aoverwrite == ASK) {
3071             if (strcmp(afilename, "") == 0) {   /* The file is from standard in */
3072                 fprintf(STDERR,
3073                         "Volume exists and no -overwrite option specified; Aborting restore command\n");
3074                 exit(1);
3075             }
3076
3077             /* Ask what to do */
3078             if (vol_elsewhere) {
3079                 fprintf(STDERR,
3080                         "The volume %s %u already exists on a different server/part\n",
3081                         volname, entry.volumeId[voltype]);
3082                 fprintf(STDERR,
3083                         "Do you want to do a full restore or abort? [fa](a): ");
3084             } else {
3085                 fprintf(STDERR,
3086                         "The volume %s %u already exists in the VLDB\n",
3087                         volname, entry.volumeId[voltype]);
3088                 fprintf(STDERR,
3089                         "Do you want to do a full/incremental restore or abort? [fia](a): ");
3090             }
3091             dc = c = getchar();
3092             while (!(dc == EOF || dc == '\n'))
3093                 dc = getchar(); /* goto end of line */
3094             if ((c == 'f') || (c == 'F'))
3095                 aoverwrite = FULL;
3096             else if ((c == 'i') || (c == 'I'))
3097                 aoverwrite = INC;
3098             else
3099                 aoverwrite = ABORT;
3100         }
3101
3102         if (aoverwrite == ABORT) {
3103             fprintf(STDERR, "Volume exists; Aborting restore command\n");
3104             exit(1);
3105         } else if (aoverwrite == FULL) {
3106             restoreflags = RV_FULLRST;
3107             fprintf(STDERR,
3108                     "Volume exists; Will delete and perform full restore\n");
3109         } else if (aoverwrite == INC) {
3110             restoreflags = 0;
3111             if (vol_elsewhere) {
3112                 fprintf(STDERR,
3113                         "%s volume %lu already exists on a different server/part; not allowed\n",
3114                         readonly ? "RO" : "RW", (unsigned long)avolid);
3115                 exit(1);
3116             }
3117         }
3118     }
3119     if (offline)
3120         restoreflags |= RV_OFFLINE;
3121     if (readonly)
3122         restoreflags |= RV_RDONLY;
3123
3124     switch (acreation) {
3125         case TS_DUMP:
3126             restoreflags |= RV_CRDUMP;
3127             break;
3128         case TS_KEEP:
3129             restoreflags |= RV_CRKEEP;
3130             break;
3131         case TS_NEW:
3132             restoreflags |= RV_CRNEW;
3133             break;
3134         default:
3135             if (aoverwrite == FULL)
3136                 restoreflags |= RV_CRNEW;
3137             else
3138                 restoreflags |= RV_CRKEEP;
3139     }
3140
3141     switch (alastupdate) {
3142         case TS_DUMP:
3143             restoreflags |= RV_LUDUMP;
3144             break;
3145         case TS_KEEP:
3146             restoreflags |= RV_LUKEEP;
3147             break;
3148         case TS_NEW:
3149             restoreflags |= RV_LUNEW;
3150             break;
3151         default:
3152             restoreflags |= RV_LUDUMP;
3153     }
3154     if (as->parms[10].items) {
3155         restoreflags |= RV_NODEL;
3156     }
3157     
3158
3159     code =
3160         UV_RestoreVolume2(aserver, apart, avolid, aparentid,
3161                           avolname, restoreflags, WriteData, afilename);
3162     if (code) {
3163         PrintDiagnostics("restore", code);
3164         exit(1);
3165     }
3166     MapPartIdIntoName(apart, apartName);
3167
3168     /*
3169      * patch typo here - originally "parms[1]", should be "parms[0]"
3170      */
3171
3172     fprintf(STDOUT, "Restored volume %s on %s %s\n", avolname,
3173             as->parms[0].items->data, apartName);
3174     return 0;
3175 }
3176
3177 static int
3178 LockReleaseCmd(register struct cmd_syndesc *as, void *arock)
3179 {
3180     afs_uint32 avolid;
3181     afs_int32 code, err;
3182
3183     avolid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);
3184     if (avolid == 0) {
3185         if (err)
3186             PrintError("", err);
3187         else
3188             fprintf(STDERR, "vos: can't find volume '%s'\n",
3189                     as->parms[0].items->data);
3190         exit(1);
3191     }
3192
3193     code = UV_LockRelease(avolid);
3194     if (code) {
3195         PrintDiagnostics("unlock", code);
3196         exit(1);
3197     }
3198     fprintf(STDOUT, "Released lock on vldb entry for volume %s\n",
3199             as->parms[0].items->data);
3200     return 0;
3201 }
3202
3203 static int
3204 AddSite(register struct cmd_syndesc *as, void *arock)
3205 {
3206     afs_uint32 avolid;
3207     afs_int32 aserver, apart, code, err, valid = 0;
3208     char apartName[10], avolname[VOLSER_MAXVOLNAME + 1];
3209
3210     vsu_ExtractName(avolname, as->parms[2].items->data);;
3211     avolid = vsu_GetVolumeID(avolname, cstruct, &err);
3212     if (avolid == 0) {
3213         if (err)
3214             PrintError("", err);
3215         else
3216             fprintf(STDERR, "vos: can't find volume '%s'\n",
3217                     as->parms[2].items->data);
3218         exit(1);
3219     }
3220     aserver = GetServer(as->parms[0].items->data);
3221     if (aserver == 0) {
3222         fprintf(STDERR, "vos: server '%s' not found in host table\n",
3223                 as->parms[0].items->data);
3224         exit(1);
3225     }
3226     apart = volutil_GetPartitionID(as->parms[1].items->data);
3227     if (apart < 0) {
3228         fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
3229                 as->parms[1].items->data);
3230         exit(1);
3231     }
3232     if (!IsPartValid(apart, aserver, &code)) {  /*check for validity of the partition */
3233         if (code)
3234             PrintError("", code);
3235         else
3236             fprintf(STDERR,
3237                     "vos : partition %s does not exist on the server\n",
3238                     as->parms[1].items->data);
3239         exit(1);
3240     }
3241     if (as->parms[3].items) {
3242         valid = 1;
3243     }
3244     code = UV_AddSite(aserver, apart, avolid, valid);
3245     if (code) {
3246         PrintDiagnostics("addsite", code);
3247         exit(1);
3248     }
3249     MapPartIdIntoName(apart, apartName);
3250     fprintf(STDOUT, "Added replication site %s %s for volume %s\n",
3251             as->parms[0].items->data, apartName, as->parms[2].items->data);
3252     return 0;
3253 }
3254
3255 static int
3256 RemoveSite(register struct cmd_syndesc *as, void *arock)
3257 {
3258
3259     afs_uint32 avolid;
3260     afs_int32 aserver, apart, code, err;
3261     char apartName[10], avolname[VOLSER_MAXVOLNAME + 1];
3262
3263     vsu_ExtractName(avolname, as->parms[2].items->data);
3264     avolid = vsu_GetVolumeID(avolname, cstruct, &err);
3265     if (avolid == 0) {
3266         if (err)
3267             PrintError("", err);
3268         else
3269             fprintf(STDERR, "vos: can't find volume '%s'\n",
3270                     as->parms[2].items->data);
3271         exit(1);
3272     }
3273     aserver = GetServer(as->parms[0].items->data);
3274     if (aserver == 0) {
3275         fprintf(STDERR, "vos: server '%s' not found in host table\n",
3276                 as->parms[0].items->data);
3277         exit(1);
3278     }
3279     apart = volutil_GetPartitionID(as->parms[1].items->data);
3280     if (apart < 0) {
3281         fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
3282                 as->parms[1].items->data);
3283         exit(1);
3284     }
3285 /*
3286  *skip the partition validity check, since it is possible that the partition
3287  *has since been decomissioned.
3288  */
3289 /*
3290         if (!IsPartValid(apart,aserver,&code)){
3291             if(code) PrintError("",code);
3292             else fprintf(STDERR,"vos : partition %s does not exist on the server\n",as->parms[1].items->data);
3293             exit(1);
3294         }
3295 */
3296     code = UV_RemoveSite(aserver, apart, avolid);
3297     if (code) {
3298         PrintDiagnostics("remsite", code);
3299         exit(1);
3300     }
3301     MapPartIdIntoName(apart, apartName);
3302     fprintf(STDOUT, "Removed replication site %s %s for volume %s\n",
3303             as->parms[0].items->data, apartName, as->parms[2].items->data);
3304     return 0;
3305 }
3306
3307 static int
3308 ChangeLocation(register struct cmd_syndesc *as, void *arock)
3309 {
3310     afs_uint32 avolid;
3311     afs_int32 aserver, apart, code, err;
3312     char apartName[10];
3313
3314     avolid = vsu_GetVolumeID(as->parms[2].items->data, cstruct, &err);
3315     if (avolid == 0) {
3316         if (err)
3317             PrintError("", err);
3318         else
3319             fprintf(STDERR, "vos: can't find volume '%s'\n",
3320                     as->parms[2].items->data);
3321         exit(1);
3322     }
3323     aserver = GetServer(as->parms[0].items->data);
3324     if (aserver == 0) {
3325         fprintf(STDERR, "vos: server '%s' not found in host table\n",
3326                 as->parms[0].items->data);
3327         exit(1);
3328     }
3329     apart = volutil_GetPartitionID(as->parms[1].items->data);
3330     if (apart < 0) {
3331         fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
3332                 as->parms[1].items->data);
3333         exit(1);
3334     }
3335     if (!IsPartValid(apart, aserver, &code)) {  /*check for validity of the partition */
3336         if (code)
3337             PrintError("", code);
3338         else
3339             fprintf(STDERR,
3340                     "vos : partition %s does not exist on the server\n",
3341                     as->parms[1].items->data);
3342         exit(1);
3343     }
3344     code = UV_ChangeLocation(aserver, apart, avolid);
3345     if (code) {
3346         PrintDiagnostics("addsite", code);
3347         exit(1);
3348     }
3349     MapPartIdIntoName(apart, apartName);
3350     fprintf(STDOUT, "Changed location to %s %s for volume %s\n",
3351             as->parms[0].items->data, apartName, as->parms[2].items->data);
3352     return 0;
3353 }
3354
3355 static int
3356 ListPartitions(register struct cmd_syndesc *as, void *arock)
3357 {
3358     afs_int32 aserver, code;
3359     struct partList dummyPartList;
3360     int i;
3361     char pname[10];
3362     int total, cnt;
3363
3364     aserver = GetServer(as->parms[0].items->data);
3365     if (aserver == 0) {
3366         fprintf(STDERR, "vos: server '%s' not found in host table\n",
3367                 as->parms[0].items->data);
3368         exit(1);
3369     }
3370
3371
3372     code = UV_ListPartitions(aserver, &dummyPartList, &cnt);
3373     if (code) {
3374         PrintDiagnostics("listpart", code);
3375         exit(1);
3376     }
3377     total = 0;
3378     fprintf(STDOUT, "The partitions on the server are:\n");
3379     for (i = 0; i < cnt; i++) {
3380         if (dummyPartList.partFlags[i] & PARTVALID) {
3381             memset(pname, 0, sizeof(pname));
3382             MapPartIdIntoName(dummyPartList.partId[i], pname);
3383             fprintf(STDOUT, " %10s ", pname);
3384             total++;
3385             if ((i % 5) == 0 && (i != 0))
3386                 fprintf(STDOUT, "\n");
3387         }
3388     }
3389     fprintf(STDOUT, "\n");
3390     fprintf(STDOUT, "Total: %d\n", total);
3391     return 0;
3392
3393 }
3394
3395 static int
3396 CompareVolName(const void *p1, const void *p2)
3397 {
3398     volintInfo *arg1, *arg2;
3399
3400     arg1 = (volintInfo *) p1;
3401     arg2 = (volintInfo *) p2;
3402     return (strcmp(arg1->name, arg2->name));
3403
3404 }
3405
3406 /*------------------------------------------------------------------------
3407  * PRIVATE XCompareVolName
3408  *
3409  * Description:
3410  *      Comparison routine for volume names coming from an extended
3411  *      volume listing.
3412  *
3413  * Arguments:
3414  *      a_obj1P : Char ptr to first extended vol info object
3415  *      a_obj1P : Char ptr to second extended vol info object
3416  *
3417  * Returns:
3418  *      The value of strcmp() on the volume names within the passed
3419  *      objects (i,e., -1, 0, or 1).
3420  *
3421  * Environment:
3422  *      Passed to qsort() as the designated comparison routine.
3423  *
3424  * Side Effects:
3425  *      As advertised.
3426  *------------------------------------------------------------------------*/
3427
3428 static int
3429 XCompareVolName(const void *a_obj1P, const void *a_obj2P)
3430 {                               /*XCompareVolName */
3431
3432     return (strcmp
3433             (((struct volintXInfo *)(a_obj1P))->name,
3434              ((struct volintXInfo *)(a_obj2P))->name));
3435
3436 }                               /*XCompareVolName */
3437
3438 static int
3439 CompareVolID(const void *p1, const void *p2)
3440 {
3441     volintInfo *arg1, *arg2;
3442
3443     arg1 = (volintInfo *) p1;
3444     arg2 = (volintInfo *) p2;
3445     if (arg1->volid == arg2->volid)
3446         return 0;
3447     if (arg1->volid > arg2->volid)
3448         return 1;
3449     else
3450         return -1;
3451
3452 }
3453
3454 /*------------------------------------------------------------------------
3455  * PRIVATE XCompareVolID
3456  *
3457  * Description:
3458  *      Comparison routine for volume IDs coming from an extended
3459  *      volume listing.
3460  *
3461  * Arguments:
3462  *      a_obj1P : Char ptr to first extended vol info object
3463  *      a_obj1P : Char ptr to second extended vol info object
3464  *
3465  * Returns:
3466  *      The value of strcmp() on the volume names within the passed
3467  *      objects (i,e., -1, 0, or 1).
3468  *
3469  * Environment:
3470  *      Passed to qsort() as the designated comparison routine.
3471  *
3472  * Side Effects:
3473  *      As advertised.
3474  *------------------------------------------------------------------------*/
3475
3476 static int
3477 XCompareVolID(const void *a_obj1P, const void *a_obj2P)
3478 {                               /*XCompareVolID */
3479
3480     afs_int32 id1, id2;         /*Volume IDs we're comparing */
3481
3482     id1 = ((struct volintXInfo *)(a_obj1P))->volid;
3483     id2 = ((struct volintXInfo *)(a_obj2P))->volid;
3484     if (id1 == id2)
3485         return (0);
3486     else if (id1 > id2)
3487         return (1);
3488     else
3489         return (-1);
3490
3491 }                               /*XCompareVolID */
3492
3493 /*------------------------------------------------------------------------
3494  * PRIVATE ListVolumes
3495  *
3496  * Description:
3497  *      Routine used to list volumes, contacting the Volume Server
3498  *      directly, bypassing the VLDB.
3499  *
3500  * Arguments:
3501  *      as : Ptr to parsed command line arguments.
3502  *
3503  * Returns:
3504  *      0                       Successful operation
3505  *
3506  * Environment:
3507  *      Nothing interesting.
3508  *
3509  * Side Effects:
3510  *      As advertised.
3511  *------------------------------------------------------------------------*/
3512
3513 static int
3514 ListVolumes(register struct cmd_syndesc *as, void *arock)
3515 {
3516     afs_int32 apart, int32list, fast;
3517     afs_int32 aserver, code;
3518     volintInfo *pntr;
3519     volintInfo *oldpntr = NULL;
3520     afs_int32 count;
3521     int i;
3522     char *base;
3523     volintXInfo *xInfoP;
3524     volintXInfo *origxInfoP = NULL; /*Ptr to current/orig extended vol info */
3525     int wantExtendedInfo;       /*Do we want extended vol info? */
3526
3527     char pname[10];
3528     struct partList dummyPartList;
3529     int all;
3530     int quiet, cnt;
3531
3532     apart = -1;
3533     fast = 0;
3534     int32list = 0;
3535
3536     if (as->parms[3].items)
3537         int32list = 1;
3538     if (as->parms[4].items)
3539         quiet = 1;
3540     else
3541         quiet = 0;
3542     if (as->parms[2].items)
3543         fast = 1;
3544     if (fast)
3545         all = 0;
3546     else
3547         all = 1;
3548     if (as->parms[5].items) {
3549         /*
3550          * We can't coexist with the fast flag.
3551          */
3552         if (fast) {
3553             fprintf(STDERR,
3554                     "vos: Can't use the -fast and -extended flags together\n");
3555             exit(1);
3556         }
3557
3558         /*
3559          * We need to turn on ``long'' listings to get the full effect.
3560          */
3561         wantExtendedInfo = 1;
3562         int32list = 1;
3563     } else
3564         wantExtendedInfo = 0;
3565     if (as->parms[1].items) {
3566         apart = volutil_GetPartitionID(as->parms[1].items->data);
3567         if (apart < 0) {
3568             fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
3569                     as->parms[1].items->data);
3570             exit(1);
3571         }
3572         dummyPartList.partId[0] = apart;
3573         dummyPartList.partFlags[0] = PARTVALID;
3574         cnt = 1;
3575     }
3576     aserver = GetServer(as->parms[0].items->data);
3577     if (aserver == 0) {
3578         fprintf(STDERR, "vos: server '%s' not found in host table\n",
3579                 as->parms[0].items->data);
3580         exit(1);
3581     }
3582
3583     if (apart != -1) {
3584         if (!IsPartValid(apart, aserver, &code)) {      /*check for validity of the partition */
3585             if (code)
3586                 PrintError("", code);
3587             else
3588                 fprintf(STDERR,
3589                         "vos : partition %s does not exist on the server\n",
3590                         as->parms[1].items->data);
3591             exit(1);
3592         }
3593     } else {
3594         code = UV_ListPartitions(aserver, &dummyPartList, &cnt);
3595         if (code) {
3596             PrintDiagnostics("listvol", code);
3597             exit(1);
3598         }
3599     }
3600     for (i = 0; i < cnt; i++) {
3601         if (dummyPartList.partFlags[i] & PARTVALID) {
3602             if (wantExtendedInfo)
3603                 code =
3604                     UV_XListVolumes(aserver, dummyPartList.partId[i], all,
3605                                     &xInfoP, &count);
3606             else
3607                 code =
3608                     UV_ListVolumes(aserver, dummyPartList.partId[i], all,
3609                                    &pntr, &count);
3610             if (code) {
3611                 PrintDiagnostics("listvol", code);
3612                 if (pntr)
3613                     free(pntr);
3614                 exit(1);
3615             }
3616             if (wantExtendedInfo) {
3617                 origxInfoP = xInfoP;
3618                 base = (char *)xInfoP;
3619             } else {
3620                 oldpntr = pntr;
3621                 base = (char *)pntr;
3622             }
3623
3624             if (!fast) {
3625                 if (wantExtendedInfo)
3626                     qsort(base, count, sizeof(volintXInfo), XCompareVolName);
3627                 else
3628                     qsort(base, count, sizeof(volintInfo), CompareVolName);
3629             } else {
3630                 if (wantExtendedInfo)
3631                     qsort(base, count, sizeof(volintXInfo), XCompareVolID);
3632                 else
3633                     qsort(base, count, sizeof(volintInfo), CompareVolID);
3634             }
3635             MapPartIdIntoName(dummyPartList.partId[i], pname);
3636             if (!quiet)
3637                 fprintf(STDOUT,
3638                         "Total number of volumes on server %s partition %s: %lu \n",
3639                         as->parms[0].items->data, pname,
3640                         (unsigned long)count);
3641             if (wantExtendedInfo) {
3642 #ifdef FULL_LISTVOL_SWITCH
3643                 if (as->parms[6].items)
3644                     XDisplayVolumes2(aserver, dummyPartList.partId[i], origxInfoP,
3645                                 count, int32list, fast, quiet);
3646                 else
3647 #endif /* FULL_LISTVOL_SWITCH */
3648                 XDisplayVolumes(aserver, dummyPartList.partId[i], origxInfoP,
3649                                 count, int32list, fast, quiet);
3650                 if (xInfoP)
3651                     free(xInfoP);
3652                 xInfoP = (volintXInfo *) 0;
3653             } else {
3654 #ifdef FULL_LISTVOL_SWITCH
3655                 if (as->parms[6].items)
3656                     DisplayVolumes2(aserver, dummyPartList.partId[i], oldpntr,
3657                                     count);
3658                 else
3659 #endif /* FULL_LISTVOL_SWITCH */
3660                     DisplayVolumes(aserver, dummyPartList.partId[i], oldpntr,
3661                                    count, int32list, fast, quiet);
3662                 if (pntr)
3663                     free(pntr);
3664                 pntr = (volintInfo *) 0;
3665             }
3666         }
3667     }
3668     return 0;
3669 }
3670
3671 static int
3672 SyncVldb(register struct cmd_syndesc *as, void *arock)
3673 {
3674     afs_int32 pnum = 0, code;   /* part name */
3675     char part[10];
3676     int flags = 0;
3677     char *volname = 0;
3678
3679     tserver = 0;
3680     if (as->parms[0].items) {
3681         tserver = GetServer(as->parms[0].items->data);
3682         if (!tserver) {
3683             fprintf(STDERR, "vos: host '%s' not found in host table\n",
3684                     as->parms[0].items->data);
3685             exit(1);
3686         }
3687     }
3688
3689     if (as->parms[1].items) {
3690         pnum = volutil_GetPartitionID(as->parms[1].items->data);
3691         if (pnum < 0) {
3692             fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
3693                     as->parms[1].items->data);
3694             exit(1);
3695         }
3696         if (!IsPartValid(pnum, tserver, &code)) {       /*check for validity of the partition */
3697             if (code)
3698                 PrintError("", code);
3699             else
3700                 fprintf(STDERR,
3701                         "vos: partition %s does not exist on the server\n",
3702                         as->parms[1].items->data);
3703             exit(1);
3704         }
3705         flags = 1;
3706
3707         if (!tserver) {
3708             fprintf(STDERR,
3709                     "The -partition option requires a -server option\n");
3710             exit(1);
3711         }
3712     }
3713
3714     if (as->parms[3].items) {
3715         flags |= 2; /* don't update */
3716     }
3717
3718     if (as->parms[2].items) {
3719         /* Synchronize an individual volume */
3720         volname = as->parms[2].items->data;
3721         code = UV_SyncVolume(tserver, pnum, volname, flags);
3722     } else {
3723         if (!tserver) {
3724             fprintf(STDERR,
3725                     "Without a -volume option, the -server option is required\n");
3726             exit(1);
3727         }
3728         code = UV_SyncVldb(tserver, pnum, flags, 0 /*unused */ );
3729     }
3730
3731     if (code) {
3732         PrintDiagnostics("syncvldb", code);
3733         exit(1);
3734     }
3735
3736     /* Print a summary of what we did */
3737     if (volname)
3738         fprintf(STDOUT, "VLDB volume %s synchronized", volname);
3739     else
3740         fprintf(STDOUT, "VLDB synchronized");
3741     if (tserver) {
3742         fprintf(STDOUT, " with state of server %s", as->parms[0].items->data);
3743     }
3744     if (flags & 1) {
3745         MapPartIdIntoName(pnum, part);
3746         fprintf(STDOUT, " partition %s\n", part);
3747     }
3748     fprintf(STDOUT, "\n");
3749
3750     return 0;
3751 }
3752
3753 static int
3754 SyncServer(register struct cmd_syndesc *as, void *arock)
3755 {
3756     afs_int32 pnum, code;       /* part name */
3757     char part[10];
3758
3759     int flags = 0;
3760
3761     tserver = GetServer(as->parms[0].items->data);
3762     if (!tserver) {
3763         fprintf(STDERR, "vos: host '%s' not found in host table\n",
3764                 as->parms[0].items->data);
3765         exit(1);
3766     }
3767     if (as->parms[1].items) {
3768         pnum = volutil_GetPartitionID(as->parms[1].items->data);
3769         if (pnum < 0) {
3770             fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
3771                     as->parms[1].items->data);
3772             exit(1);
3773         }
3774         if (!IsPartValid(pnum, tserver, &code)) {       /*check for validity of the partition */
3775             if (code)
3776                 PrintError("", code);
3777             else
3778                 fprintf(STDERR,
3779                         "vos : partition %s does not exist on the server\n",
3780                         as->parms[1].items->data);
3781             exit(1);
3782         }
3783         flags = 1;
3784     } else {
3785         pnum = -1;
3786     }
3787
3788     if (as->parms[2].items) {
3789         flags |= 2; /* don't update */
3790     }
3791     code = UV_SyncServer(tserver, pnum, flags, 0 /*unused */ );
3792     if (code) {
3793         PrintDiagnostics("syncserv", code);
3794         exit(1);
3795     }
3796     if (flags & 1) {
3797         MapPartIdIntoName(pnum, part);
3798         fprintf(STDOUT, "Server %s partition %s synchronized with VLDB\n",
3799                 as->parms[0].items->data, part);
3800     } else
3801         fprintf(STDOUT, "Server %s synchronized with VLDB\n",
3802                 as->parms[0].items->data);
3803     return 0;
3804
3805 }
3806
3807 static int
3808 VolumeInfoCmd(char *name)
3809 {
3810     struct nvldbentry entry;
3811     afs_int32 vcode;
3812
3813     /* The vlserver will handle names with the .readonly
3814      * and .backup extension as well as volume ids.
3815      */
3816     vcode = VLDB_GetEntryByName(name, &entry);
3817     if (vcode) {
3818         PrintError("", vcode);
3819         exit(1);
3820     }
3821     MapHostToNetwork(&entry);
3822     EnumerateEntry(&entry);
3823
3824     /* Defect #3027: grubby check to handle locked volume.
3825      * If VLOP_ALLOPERS is set, the entry is locked.
3826      * Leave this routine as is, but put in correct check.
3827      */
3828     if (entry.flags & VLOP_ALLOPERS)
3829         fprintf(STDOUT, "    Volume is currently LOCKED  \n");
3830
3831     return 0;
3832 }
3833
3834 static int
3835 VolumeZap(register struct cmd_syndesc *as, void *arock)
3836 {
3837     struct nvldbentry entry;
3838     afs_uint32 volid, zapbackupid = 0, backupid = 0;
3839     afs_int32 code, server, part, err;
3840
3841     if (as->parms[3].items) {
3842         /* force flag is on, use the other version */
3843         return NukeVolume(as);
3844     }
3845
3846     if (as->parms[4].items) {
3847         zapbackupid = 1;
3848     }
3849
3850     volid = vsu_GetVolumeID(as->parms[2].items->data, cstruct, &err);
3851     if (volid == 0) {
3852         if (err)
3853             PrintError("", err);
3854         else
3855             fprintf(STDERR, "vos: can't find volume '%s'\n",
3856                     as->parms[2].items->data);
3857         exit(1);
3858     }
3859     part = volutil_GetPartitionID(as->parms[1].items->data);
3860     if (part < 0) {
3861         fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
3862                 as->parms[1].items->data);
3863         exit(1);
3864     }
3865     server = GetServer(as->parms[0].items->data);
3866     if (!server) {
3867         fprintf(STDERR, "vos: host '%s' not found in host table\n",
3868                 as->parms[0].items->data);
3869         exit(1);
3870     }
3871     if (!IsPartValid(part, server, &code)) {    /*check for validity of the partition */
3872         if (code)
3873             PrintError("", code);
3874         else
3875             fprintf(STDERR,
3876                     "vos : partition %s does not exist on the server\n",
3877                     as->parms[1].items->data);
3878         exit(1);
3879     }
3880     code = VLDB_GetEntryByID(volid, -1, &entry);
3881     if (!code) {
3882         if (volid == entry.volumeId[RWVOL])
3883             backupid = entry.volumeId[BACKVOL];
3884         fprintf(STDERR,
3885                 "Warning: Entry for volume number %lu exists in VLDB (but we're zapping it anyway!)\n",
3886                 (unsigned long)volid);
3887     }
3888     if (zapbackupid) {
3889         volintInfo *pntr = (volintInfo *) 0;
3890
3891         if (!backupid) {
3892             code = UV_ListOneVolume(server, part, volid, &pntr);
3893             if (!code) {
3894                 if (volid == pntr->parentID)
3895                     backupid = pntr->backupID;
3896                 if (pntr)
3897                     free(pntr);
3898             }
3899         }
3900         if (backupid) {
3901             code = UV_VolumeZap(server, part, backupid);
3902             if (code) {
3903                 PrintDiagnostics("zap", code);
3904                 exit(1);
3905             }
3906             fprintf(STDOUT, "Backup Volume %lu deleted\n",
3907                     (unsigned long)backupid);
3908         }
3909     }
3910     code = UV_VolumeZap(server, part, volid);
3911     if (code) {
3912         PrintDiagnostics("zap", code);
3913         exit(1);
3914     }
3915     fprintf(STDOUT, "Volume %lu deleted\n", (unsigned long)volid);
3916
3917     return 0;
3918 }
3919
3920 static int
3921 VolserStatus(register struct cmd_syndesc *as, void *arock)
3922 {
3923     afs_int32 server, code;
3924     transDebugInfo *pntr, *oldpntr;
3925     afs_int32 count;
3926     int i;
3927     char pname[10];
3928
3929     server = GetServer(as->parms[0].items->data);
3930     if (!server) {
3931         fprintf(STDERR, "vos: host '%s' not found in host table\n",
3932                 as->parms[0].items->data);
3933         exit(1);
3934     }
3935     code = UV_VolserStatus(server, &pntr, &count);
3936     if (code) {
3937         PrintDiagnostics("status", code);
3938         exit(1);
3939     }
3940     oldpntr = pntr;
3941     if (count == 0)
3942         fprintf(STDOUT, "No active transactions on %s\n",
3943                 as->parms[0].items->data);
3944     else {
3945         fprintf(STDOUT, "Total transactions: %d\n", count);
3946     }
3947     for (i = 0; i < count; i++) {
3948         /*print out the relevant info */
3949         fprintf(STDOUT, "--------------------------------------\n");
3950         fprintf(STDOUT, "transaction: %lu  created: %s",
3951                 (unsigned long)pntr->tid, vos_ctime( & pntr->time));
3952         if (pntr->returnCode) {
3953             fprintf(STDOUT, "returnCode: %lu\n",
3954                     (unsigned long)pntr->returnCode);
3955         }
3956         if (pntr->iflags) {
3957             fprintf(STDOUT, "attachFlags:  ");
3958             switch (pntr->iflags) {
3959             case ITOffline:
3960                 fprintf(STDOUT, "offline ");
3961                 break;
3962             case ITBusy:
3963                 fprintf(STDOUT, "busy ");
3964                 break;
3965             case ITReadOnly:
3966                 fprintf(STDOUT, "readonly ");
3967                 break;
3968             case ITCreate:
3969                 fprintf(STDOUT, "create ");
3970                 break;
3971             case ITCreateVolID:
3972                 fprintf(STDOUT, "create volid ");
3973                 break;
3974             }
3975             fprintf(STDOUT, "\n");
3976         }
3977         if (pntr->vflags) {
3978             fprintf(STDOUT, "volumeStatus: ");
3979             switch (pntr->vflags) {
3980             case VTDeleteOnSalvage:
3981                 fprintf(STDOUT, "deleteOnSalvage ");
3982             case VTOutOfService:
3983                 fprintf(STDOUT, "outOfService ");
3984             case VTDeleted:
3985                 fprintf(STDOUT, "deleted ");
3986             }
3987             fprintf(STDOUT, "\n");
3988         }
3989         if (pntr->tflags) {
3990             fprintf(STDOUT, "transactionFlags: ");
3991             fprintf(STDOUT, "delete\n");
3992         }
3993         MapPartIdIntoName(pntr->partition, pname);
3994         fprintf(STDOUT, "volume: %lu  partition: %s  procedure: %s\n",
3995                 (unsigned long)pntr->volid, pname, pntr->lastProcName);
3996         if (pntr->callValid) {
3997             fprintf(STDOUT,
3998                     "packetRead: %lu  lastReceiveTime: %d  packetSend: %lu  lastSendTime: %d\n",
3999                     (unsigned long)pntr->readNext, pntr->lastReceiveTime,
4000                     (unsigned long)pntr->transmitNext, pntr->lastSendTime);
4001         }
4002         pntr++;
4003         fprintf(STDOUT, "--------------------------------------\n");
4004         fprintf(STDOUT, "\n");
4005     }
4006     if (oldpntr)
4007         free(oldpntr);
4008     return 0;
4009 }
4010
4011 static int
4012 RenameVolume(register struct cmd_syndesc *as, void *arock)
4013 {
4014     afs_int32 code1, code2, code;
4015     struct nvldbentry entry;
4016
4017     code1 = VLDB_GetEntryByName(as->parms[0].items->data, &entry);
4018     if (code1) {
4019         fprintf(STDERR, "vos: Could not find entry for volume %s\n",
4020                 as->parms[0].items->data);
4021         exit(1);
4022     }
4023     code2 = VLDB_GetEntryByName(as->parms[1].items->data, &entry);
4024     if ((!code1) && (!code2)) { /*the newname already exists */
4025         fprintf(STDERR, "vos: volume %s already exists\n",
4026                 as->parms[1].items->data);
4027         exit(1);
4028     }
4029
4030     if (code1 && code2) {
4031         fprintf(STDERR, "vos: Could not find entry for volume %s or %s\n",
4032                 as->parms[0].items->data, as->parms[1].items->data);
4033         exit(1);
4034     }
4035     if (!VolNameOK(as->parms[0].items->data)) {
4036         fprintf(STDERR,
4037                 "Illegal volume name %s, should not end in .readonly or .backup\n",
4038                 as->parms[0].items->data);
4039         exit(1);
4040     }
4041     if (!ISNAMEVALID(as->parms[1].items->data)) {
4042         fprintf(STDERR,
4043                 "vos: the new volume name %s exceeds the size limit of %d\n",
4044                 as->parms[1].items->data, VOLSER_OLDMAXVOLNAME - 10);
4045         exit(1);
4046     }
4047     if (!VolNameOK(as->parms[1].items->data)) {
4048         fprintf(STDERR,
4049                 "Illegal volume name %s, should not end in .readonly or .backup\n",
4050                 as->parms[1].items->data);
4051         exit(1);
4052     }
4053     if (IsNumeric(as->parms[1].items->data)) {
4054         fprintf(STDERR, "Illegal volume name %s, should not be a number\n",
4055                 as->parms[1].items->data);
4056         exit(1);
4057     }
4058     MapHostToNetwork(&entry);
4059     code =
4060         UV_RenameVolume(&entry, as->parms[0].items->data,
4061                         as->parms[1].items->data);
4062     if (code) {
4063         PrintDiagnostics("rename", code);
4064         exit(1);
4065     }
4066     fprintf(STDOUT, "Renamed volume %s to %s\n", as->parms[0].items->data,
4067             as->parms[1].items->data);
4068     return 0;
4069 }
4070
4071 int
4072 GetVolumeInfo(afs_uint32 volid, afs_int32 *server, afs_int32 *part, afs_int32 *voltype, 
4073               struct nvldbentry *rentry)
4074 {
4075     afs_int32 vcode;
4076     int i, index = -1;
4077
4078     vcode = VLDB_GetEntryByID(volid, -1, rentry);
4079     if (vcode) {
4080         fprintf(STDERR,
4081                 "Could not fetch the entry for volume %lu from VLDB \n",
4082                 (unsigned long)volid);
4083         PrintError("", vcode);
4084         return (vcode);
4085     }
4086     MapHostToNetwork(rentry);
4087     if (volid == rentry->volumeId[ROVOL]) {
4088         *voltype = ROVOL;
4089         for (i = 0; i < rentry->nServers; i++) {
4090             if ((index == -1) && (rentry->serverFlags[i] & ITSROVOL)
4091                 && !(rentry->serverFlags[i] & RO_DONTUSE))
4092                 index = i;
4093         }
4094         if (index == -1) {
4095             fprintf(STDERR,
4096                     "RO volume is not found in VLDB entry for volume %lu\n",
4097                     (unsigned long)volid);
4098             return -1;
4099         }
4100
4101         *server = rentry->serverNumber[index];
4102         *part = rentry->serverPartition[index];
4103         return 0;
4104     }
4105
4106     index = Lp_GetRwIndex(rentry);
4107     if (index == -1) {
4108         fprintf(STDERR,
4109                 "RW Volume is not found in VLDB entry for volume %lu\n",
4110                 (unsigned long)volid);
4111         return -1;
4112     }
4113     if (volid == rentry->volumeId[RWVOL]) {
4114         *voltype = RWVOL;
4115         *server = rentry->serverNumber[index];
4116         *part = rentry->serverPartition[index];
4117         return 0;
4118     }
4119     if (volid == rentry->volumeId[BACKVOL]) {
4120         *voltype = BACKVOL;
4121         *server = rentry->serverNumber[index];
4122         *part = rentry->serverPartition[index];
4123         return 0;
4124     }
4125     fprintf(STDERR,
4126             "unexpected volume type for volume %lu\n",
4127             (unsigned long)volid);
4128     return -1;
4129 }
4130
4131 static int
4132 DeleteEntry(register struct cmd_syndesc *as, void *arock)
4133 {
4134     afs_int32 apart = 0;
4135     afs_uint32 avolid;
4136     afs_int32 vcode;
4137     struct VldbListByAttributes attributes;
4138     nbulkentries arrayEntries;
4139     register struct nvldbentry *vllist;
4140     struct cmd_item *itp;
4141     afs_int32 nentries;
4142     int j;
4143     char prefix[VOLSER_MAXVOLNAME + 1];
4144     int seenprefix = 0;
4145     afs_int32 totalBack = 0, totalFail = 0, err;
4146
4147     if (as->parms[0].items) {   /* -id */
4148         if (as->parms[1].items || as->parms[2].items || as->parms[3].items) {
4149             fprintf(STDERR,
4150                     "You cannot use -server, -partition, or -prefix with the -id argument\n");
4151             exit(-2);
4152         }
4153         for (itp = as->parms[0].items; itp; itp = itp->next) {
4154             avolid = vsu_GetVolumeID(itp->data, cstruct, &err);
4155             if (avolid == 0) {
4156                 if (err)
4157                     PrintError("", err);
4158                 else
4159                     fprintf(STDERR, "vos: can't find volume '%s'\n",
4160                             itp->data);
4161                 continue;
4162             }
4163             if (as->parms[4].items) {   /* -noexecute */
4164                 fprintf(STDOUT, "Would have deleted VLDB entry for %s \n",
4165                         itp->data);
4166                 fflush(STDOUT);
4167                 continue;
4168             }
4169             vcode = ubik_VL_DeleteEntry(cstruct, 0, avolid, RWVOL);
4170             if (vcode) {
4171                 fprintf(STDERR, "Could not delete entry for volume %s\n",
4172                         itp->data);
4173                 fprintf(STDERR,
4174                         "You must specify a RW volume name or ID "
4175                         "(the entire VLDB entry will be deleted)\n");
4176                 PrintError("", vcode);
4177                 totalFail++;
4178                 continue;
4179             }
4180             totalBack++;
4181         }
4182         fprintf(STDOUT, "Deleted %d VLDB entries\n", totalBack);
4183         return (totalFail);
4184     }
4185
4186     if (!as->parms[1].items && !as->parms[2].items && !as->parms[3].items) {
4187         fprintf(STDERR, "You must specify an option\n");
4188         exit(-2);
4189     }
4190
4191     /* Zero out search attributes */
4192     memset(&attributes, 0, sizeof(struct VldbListByAttributes));
4193
4194     if (as->parms[1].items) {   /* -prefix */
4195         strncpy(prefix, as->parms[1].items->data, VOLSER_MAXVOLNAME);
4196         seenprefix = 1;
4197         if (!as->parms[2].items && !as->parms[3].items) {       /* a single entry only */
4198             fprintf(STDERR,
4199                     "You must provide -server with the -prefix argument\n");
4200             exit(-2);
4201         }
4202     }
4203
4204     if (as->parms[2].items) {   /* -server */
4205         afs_int32 aserver;
4206         aserver = GetServer(as->parms[2].items->data);
4207         if (aserver == 0) {
4208             fprintf(STDERR, "vos: server '%s' not found in host table\n",
4209                     as->parms[2].items->data);
4210             exit(-1);
4211         }
4212         attributes.server = ntohl(aserver);
4213         attributes.Mask |= VLLIST_SERVER;
4214     }
4215
4216     if (as->parms[3].items) {   /* -partition */
4217         if (!as->parms[2].items) {
4218             fprintf(STDERR,
4219                     "You must provide -server with the -partition argument\n");
4220             exit(-2);
4221         }
4222         apart = volutil_GetPartitionID(as->parms[3].items->data);
4223         if (apart < 0) {
4224             fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
4225                     as->parms[3].items->data);
4226             exit(-1);
4227         }
4228         attributes.partition = apart;
4229         attributes.Mask |= VLLIST_PARTITION;
4230     }
4231
4232     /* Print status line of what we are doing */
4233     fprintf(STDOUT, "Deleting VLDB entries for ");
4234     if (as->parms[2].items) {
4235         fprintf(STDOUT, "server %s ", as->parms[2].items->data);
4236     }
4237     if (as->parms[3].items) {
4238         char pname[10];
4239         MapPartIdIntoName(apart, pname);
4240         fprintf(STDOUT, "partition %s ", pname);
4241     }
4242     if (seenprefix) {
4243         fprintf(STDOUT, "which are prefixed with %s ", prefix);
4244     }
4245     fprintf(STDOUT, "\n");
4246     fflush(STDOUT);
4247
4248     /* Get all the VLDB entries on a server and/or partition */
4249     memset(&arrayEntries, 0, sizeof(arrayEntries));
4250     vcode = VLDB_ListAttributes(&attributes, &nentries, &arrayEntries);
4251     if (vcode) {
4252         fprintf(STDERR, "Could not access the VLDB for attributes\n");
4253         PrintError("", vcode);
4254         exit(-1);
4255     }
4256
4257     /* Process each entry */
4258     for (j = 0; j < nentries; j++) {
4259         vllist = &arrayEntries.nbulkentries_val[j];
4260         if (seenprefix) {
4261             /* It only deletes the RW volumes */
4262             if (strncmp(vllist->name, prefix, strlen(prefix))) {
4263                 if (verbose) {
4264                     fprintf(STDOUT,
4265                             "Omitting to delete %s due to prefix %s mismatch\n",
4266                             vllist->name, prefix);
4267                 }
4268                 fflush(STDOUT);
4269                 continue;
4270             }
4271         }
4272
4273         if (as->parms[4].items) {       /* -noexecute */
4274             fprintf(STDOUT, "Would have deleted VLDB entry for %s \n",
4275                     vllist->name);
4276             fflush(STDOUT);
4277             continue;
4278         }
4279
4280         /* Only matches the RW volume name */
4281         avolid = vllist->volumeId[RWVOL];
4282         vcode = ubik_VL_DeleteEntry(cstruct, 0, avolid, RWVOL);
4283         if (vcode) {
4284             fprintf(STDOUT, "Could not delete VDLB entry for  %s\n",
4285                     vllist->name);
4286             totalFail++;
4287             PrintError("", vcode);
4288             continue;
4289         } else {
4290             totalBack++;
4291             if (verbose)
4292                 fprintf(STDOUT, "Deleted VLDB entry for %s \n", vllist->name);
4293         }
4294         fflush(STDOUT);
4295     }                           /*for */
4296
4297     fprintf(STDOUT, "----------------------\n");
4298     fprintf(STDOUT,
4299             "Total VLDB entries deleted: %lu; failed to delete: %lu\n",
4300             (unsigned long)totalBack, (unsigned long)totalFail);
4301     if (arrayEntries.nbulkentries_val)
4302         free(arrayEntries.nbulkentries_val);
4303     return 0;
4304 }
4305
4306
4307 static int
4308 CompareVldbEntryByName(const void *p1, const void *p2)
4309 {
4310     struct nvldbentry *arg1, *arg2;
4311
4312     arg1 = (struct nvldbentry *)p1;
4313     arg2 = (struct nvldbentry *)p2;
4314     return (strcmp(arg1->name, arg2->name));
4315 }
4316
4317 /*
4318 static int CompareVldbEntry(char *p1, char *p2)
4319 {
4320     struct nvldbentry *arg1,*arg2;
4321     int i;
4322     int pos1, pos2;
4323     char comp1[100],comp2[100];
4324     char temp1[20],temp2[20];
4325
4326     arg1 = (struct nvldbentry *)p1;
4327     arg2 = (struct nvldbentry *)p2;
4328     pos1 = -1;
4329     pos2 = -1;
4330
4331     for(i = 0; i < arg1->nServers; i++)
4332         if(arg1->serverFlags[i] & ITSRWVOL) pos1 = i;
4333     for(i = 0; i < arg2->nServers; i++)
4334         if(arg2->serverFlags[i] & ITSRWVOL) pos2 = i;
4335     if(pos1 == -1 || pos2 == -1){
4336         pos1 = 0;
4337         pos2 = 0;
4338     }
4339     sprintf(comp1,"%10u",arg1->serverNumber[pos1]);
4340     sprintf(comp2,"%10u",arg2->serverNumber[pos2]);
4341     sprintf(temp1,"%10u",arg1->serverPartition[pos1]);
4342     sprintf(temp2,"%10u",arg2->serverPartition[pos2]);
4343     strcat(comp1,temp1);
4344     strcat(comp2,temp2);
4345     strcat(comp1,arg1->name);
4346     strcat(comp1,arg2->name);
4347     return(strcmp(comp1,comp2));
4348
4349 }
4350
4351 */
4352 static int
4353 ListVLDB(struct cmd_syndesc *as, void *arock)
4354 {
4355     afs_int32 apart;
4356     afs_int32 aserver, code;
4357     afs_int32 vcode;
4358     struct VldbListByAttributes attributes;
4359     nbulkentries arrayEntries;
4360     struct nvldbentry *vllist, *tarray = 0, *ttarray;
4361     afs_int32 centries, nentries = 0;
4362     afs_int32 tarraysize = 0;
4363     afs_int32 parraysize;
4364     int j;
4365     char pname[10];
4366     int quiet, sort, lock;
4367     afs_int32 thisindex, nextindex;
4368
4369     aserver = 0;
4370     apart = 0;
4371
4372     attributes.Mask = 0;
4373     lock = (as->parms[3].items ? 1 : 0);        /* -lock   flag */
4374     quiet = (as->parms[4].items ? 1 : 0);       /* -quit   flag */
4375     sort = (as->parms[5].items ? 0 : 1);        /* -nosort flag */
4376
4377     /* If the volume name is given, Use VolumeInfoCmd to look it up
4378      * and not ListAttributes.
4379      */
4380     if (as->parms[0].items) {
4381         if (lock) {
4382             fprintf(STDERR,
4383                     "vos: illegal use of '-locked' switch, need to specify server and/or partition\n");
4384             exit(1);
4385         }
4386         code = VolumeInfoCmd(as->parms[0].items->data);
4387         if (code) {
4388             PrintError("", code);
4389             exit(1);
4390         }
4391         return 0;
4392     }
4393
4394     /* Server specified */
4395     if (as->parms[1].items) {
4396         aserver = GetServer(as->parms[1].items->data);
4397         if (aserver == 0) {
4398             fprintf(STDERR, "vos: server '%s' not found in host table\n",
4399                     as->parms[1].items->data);
4400             exit(1);
4401         }
4402         attributes.server = ntohl(aserver);
4403         attributes.Mask |= VLLIST_SERVER;
4404     }
4405
4406     /* Partition specified */
4407     if (as->parms[2].items) {
4408         apart = volutil_GetPartitionID(as->parms[2].items->data);
4409         if (apart < 0) {
4410             fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
4411                     as->parms[2].items->data);
4412             exit(1);
4413         }
4414         attributes.partition = apart;
4415         attributes.Mask |= VLLIST_PARTITION;
4416     }
4417
4418     if (lock) {
4419         attributes.Mask |= VLLIST_FLAG;
4420         attributes.flag = VLOP_ALLOPERS;
4421     }
4422
4423     /* Print header information */
4424     if (!quiet) {
4425         MapPartIdIntoName(apart, pname);
4426         fprintf(STDOUT, "VLDB entries for %s %s%s%s %s\n",
4427                 (as->parms[1].items ? "server" : "all"),
4428                 (as->parms[1].items ? as->parms[1].items->data : "servers"),
4429                 (as->parms[2].items ? " partition " : ""),
4430                 (as->parms[2].items ? pname : ""),
4431                 (lock ? "which are locked:" : ""));
4432     }
4433
4434     for (thisindex = 0; (thisindex != -1); thisindex = nextindex) {
4435         memset(&arrayEntries, 0, sizeof(arrayEntries));
4436         centries = 0;
4437         nextindex = -1;
4438
4439         vcode =
4440             VLDB_ListAttributesN2(&attributes, 0, thisindex, &centries,
4441                                   &arrayEntries, &nextindex);
4442         if (vcode == RXGEN_OPCODE) {
4443             /* Vlserver not running with ListAttributesN2. Fall back */
4444             vcode =
4445                 VLDB_ListAttributes(&attributes, &centries, &arrayEntries);
4446             nextindex = -1;
4447         }
4448         if (vcode) {
4449             fprintf(STDERR, "Could not access the VLDB for attributes\n");
4450             PrintError("", vcode);
4451             exit(1);
4452         }
4453         nentries += centries;
4454
4455         /* We don't sort, so just print the entries now */
4456         if (!sort) {
4457             for (j = 0; j < centries; j++) {    /* process each entry */
4458                 vllist = &arrayEntries.nbulkentries_val[j];
4459                 MapHostToNetwork(vllist);
4460                 EnumerateEntry(vllist);
4461
4462                 if (vllist->flags & VLOP_ALLOPERS)
4463                     fprintf(STDOUT, "    Volume is currently LOCKED  \n");
4464             }
4465         }
4466
4467         /* So we sort. First we must collect all the entries and keep
4468          * them in memory.
4469          */
4470         else if (centries > 0) {
4471             if (!tarray) {
4472                 /* steal away the first bulk entries array */
4473                 tarray = (struct nvldbentry *)arrayEntries.nbulkentries_val;
4474                 tarraysize = centries * sizeof(struct nvldbentry);
4475                 arrayEntries.nbulkentries_val = 0;
4476             } else {
4477                 /* Grow the tarray to keep the extra entries */
4478                 parraysize = (centries * sizeof(struct nvldbentry));
4479                 ttarray =
4480                     (struct nvldbentry *)realloc(tarray,
4481                                                  tarraysize + parraysize);
4482                 if (!ttarray) {
4483                     fprintf(STDERR,
4484                             "Could not allocate enough space for  the VLDB entries\n");
4485                     goto bypass;
4486                 }
4487                 tarray = ttarray;
4488
4489                 /* Copy them in */
4490                 memcpy(((char *)tarray) + tarraysize,
4491                        (char *)arrayEntries.nbulkentries_val, parraysize);
4492                 tarraysize += parraysize;
4493             }
4494         }
4495
4496         /* Free the bulk array */
4497         if (arrayEntries.nbulkentries_val) {
4498             free(arrayEntries.nbulkentries_val);
4499             arrayEntries.nbulkentries_val = 0;
4500         }
4501     }
4502
4503     /* Here is where we now sort all the entries and print them */
4504     if (sort && (nentries > 0)) {
4505         qsort((char *)tarray, nentries, sizeof(struct nvldbentry),
4506               CompareVldbEntryByName);
4507         for (vllist = tarray, j = 0; j < nentries; j++, vllist++) {
4508             MapHostToNetwork(vllist);
4509             EnumerateEntry(vllist);
4510
4511             if (vllist->flags & VLOP_ALLOPERS)
4512                 fprintf(STDOUT, "    Volume is currently LOCKED  \n");
4513         }
4514     }
4515
4516   bypass:
4517     if (!quiet)
4518         fprintf(STDOUT, "\nTotal entries: %lu\n", (unsigned long)nentries);
4519     if (tarray)
4520         free(tarray);
4521     return 0;
4522 }
4523
4524 static int
4525 BackSys(register struct cmd_syndesc *as, void *arock)
4526 {
4527     afs_uint32 avolid;
4528     afs_int32 apart = 0;
4529     afs_int32 aserver = 0, code, aserver1, apart1;
4530     afs_int32 vcode;
4531     struct VldbListByAttributes attributes;
4532     nbulkentries arrayEntries;
4533     register struct nvldbentry *vllist;
4534     afs_int32 nentries;
4535     int j;
4536     char pname[10];
4537     int seenprefix, seenxprefix, exclude, ex, exp, noaction;
4538     afs_int32 totalBack = 0;
4539     afs_int32 totalFail = 0;
4540     int previdx = -1;
4541     int error;
4542     int same = 0;
4543     struct cmd_item *ti;
4544     int match = 0;
4545 #ifndef HAVE_POSIX_REGEX
4546     char *ccode;
4547 #endif
4548
4549     memset(&attributes, 0, sizeof(struct VldbListByAttributes));
4550     attributes.Mask = 0;
4551
4552     seenprefix = (as->parms[0].items ? 1 : 0);
4553     exclude = (as->parms[3].items ? 1 : 0);
4554     seenxprefix = (as->parms[4].items ? 1 : 0);
4555     noaction = (as->parms[5].items ? 1 : 0);
4556
4557     if (as->parms[1].items) {   /* -server */
4558         aserver = GetServer(as->parms[1].items->data);
4559         if (aserver == 0) {
4560             fprintf(STDERR, "vos: server '%s' not found in host table\n",
4561                     as->parms[1].items->data);
4562             exit(1);
4563         }
4564         attributes.server = ntohl(aserver);
4565         attributes.Mask |= VLLIST_SERVER;
4566     }
4567
4568     if (as->parms[2].items) {   /* -partition */
4569         apart = volutil_GetPartitionID(as->parms[2].items->data);
4570         if (apart < 0) {
4571             fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
4572                     as->parms[2].items->data);
4573             exit(1);
4574         }
4575         attributes.partition = apart;
4576         attributes.Mask |= VLLIST_PARTITION;
4577     }
4578
4579     /* Check to make sure the prefix and xprefix expressions compile ok */
4580     if (seenprefix) {
4581         for (ti = as->parms[0].items; ti; ti = ti->next) {
4582             if (strncmp(ti->data, "^", 1) == 0) {
4583 #ifdef HAVE_POSIX_REGEX
4584                 regex_t re;
4585                 char errbuf[256];
4586
4587                 code = regcomp(&re, ti->data, REG_NOSUB);
4588                 if (code != 0) {
4589                     regerror(code, &re, errbuf, sizeof errbuf);
4590                     fprintf(STDERR,
4591                             "Unrecognizable -prefix regular expression: '%s': %s\n",
4592                             ti->data, errbuf);
4593                     exit(1);
4594                 }
4595                 regfree(&re);
4596 #else
4597                 ccode = (char *)re_comp(ti->data);
4598                 if (ccode) {
4599                     fprintf(STDERR,
4600                             "Unrecognizable -prefix regular expression: '%s': %s\n",
4601                             ti->data, ccode);
4602                     exit(1);
4603                 }
4604 #endif
4605             }
4606         }
4607     }
4608     if (seenxprefix) {
4609         for (ti = as->parms[4].items; ti; ti = ti->next) {
4610             if (strncmp(ti->data, "^", 1) == 0) {
4611 #ifdef HAVE_POSIX_REGEX
4612                 regex_t re;
4613                 char errbuf[256];
4614
4615                 code = regcomp(&re, ti->data, REG_NOSUB);
4616                 if (code != 0) {
4617                     regerror(code, &re, errbuf, sizeof errbuf);
4618                     fprintf(STDERR,
4619                             "Unrecognizable -xprefix regular expression: '%s': %s\n",
4620                             ti->data, errbuf);
4621                     exit(1);
4622                 }
4623                 regfree(&re);
4624 #else
4625                 ccode = (char *)re_comp(ti->data);
4626                 if (ccode) {
4627                     fprintf(STDERR,
4628                             "Unrecognizable -xprefix regular expression: '%s': %s\n",
4629                             ti->data, ccode);
4630                     exit(1);
4631                 }
4632 #endif
4633             }
4634         }
4635     }
4636
4637     memset(&arrayEntries, 0, sizeof(arrayEntries));     /* initialize to hint the stub to alloc space */
4638     vcode = VLDB_ListAttributes(&attributes, &nentries, &arrayEntries);
4639     if (vcode) {
4640         fprintf(STDERR, "Could not access the VLDB for attributes\n");
4641         PrintError("", vcode);
4642         exit(1);
4643     }
4644
4645     if (as->parms[1].items || as->parms[2].items || verbose) {
4646         fprintf(STDOUT, "%s up volumes",
4647                 (noaction ? "Would have backed" : "Backing"));
4648
4649         if (as->parms[1].items) {
4650             fprintf(STDOUT, " on server %s", as->parms[1].items->data);
4651         } else if (as->parms[2].items) {
4652             fprintf(STDOUT, " for all servers");
4653         }
4654
4655         if (as->parms[2].items) {
4656             MapPartIdIntoName(apart, pname);
4657             fprintf(STDOUT, " partition %s", pname);
4658         }
4659
4660         if (seenprefix || (!seenprefix && seenxprefix)) {
4661             ti = (seenprefix ? as->parms[0].items : as->parms[4].items);
4662             ex = (seenprefix ? exclude : !exclude);
4663             exp = (strncmp(ti->data, "^", 1) == 0);
4664             fprintf(STDOUT, " which %smatch %s '%s'", (ex ? "do not " : ""),
4665                     (exp ? "expression" : "prefix"), ti->data);
4666             for (ti = ti->next; ti; ti = ti->next) {
4667                 exp = (strncmp(ti->data, "^", 1) == 0);
4668                 printf(" %sor %s '%s'", (ex ? "n" : ""),
4669                        (exp ? "expression" : "prefix"), ti->data);
4670             }
4671         }
4672
4673         if (seenprefix && seenxprefix) {
4674             ti = as->parms[4].items;
4675             exp = (strncmp(ti->data, "^", 1) == 0);
4676             fprintf(STDOUT, " %swhich match %s '%s'",
4677                     (exclude ? "adding those " : "removing those "),
4678                     (exp ? "expression" : "prefix"), ti->data);
4679             for (ti = ti->next; ti; ti = ti->next) {
4680                 exp = (strncmp(ti->data, "^", 1) == 0);
4681                 printf(" or %s '%s'", (exp ? "expression" : "prefix"),
4682                        ti->data);
4683             }
4684         }
4685         fprintf(STDOUT, " .. ");
4686         if (verbose)
4687             fprintf(STDOUT, "\n");
4688         fflush(STDOUT);
4689     }
4690
4691     for (j = 0; j < nentries; j++) {    /* process each vldb entry */
4692         vllist = &arrayEntries.nbulkentries_val[j];
4693
4694         if (seenprefix) {
4695             for (ti = as->parms[0].items; ti; ti = ti->next) {
4696                 if (strncmp(ti->data, "^", 1) == 0) {
4697 #ifdef HAVE_POSIX_REGEX
4698                     regex_t re;
4699                     char errbuf[256];
4700
4701                     /* XXX -- should just do the compile once! */
4702                     code = regcomp(&re, ti->data, REG_NOSUB);
4703                     if (code != 0) {
4704                         regerror(code, &re, errbuf, sizeof errbuf);
4705                         fprintf(STDERR,
4706                                 "Error in -prefix regular expression: '%s': %s\n",
4707                                 ti->data, errbuf);
4708                         exit(1);
4709                     }
4710                     match = (regexec(&re, vllist->name, 0, NULL, 0) == 0);
4711                     regfree(&re);
4712 #else
4713                     ccode = (char *)re_comp(ti->data);
4714                     if (ccode) {
4715                         fprintf(STDERR,
4716                                 "Error in -prefix regular expression: '%s': %s\n",
4717                                 ti->data, ccode);
4718                         exit(1);
4719                     }
4720                     match = (re_exec(vllist->name) == 1);
4721 #endif
4722                 } else {
4723                     match =
4724                         (strncmp(vllist->name, ti->data, strlen(ti->data)) ==
4725                          0);
4726                 }
4727                 if (match)
4728                     break;
4729             }
4730         } else {
4731             match = 1;
4732         }
4733
4734         /* Without the -exclude flag: If it matches the prefix, then
4735          *    check if we want to exclude any from xprefix.
4736          * With the -exclude flag: If it matches the prefix, then
4737          *    check if we want to add any from xprefix.
4738          */
4739         if (match && seenxprefix) {
4740             for (ti = as->parms[4].items; ti; ti = ti->next) {
4741                 if (strncmp(ti->data, "^", 1) == 0) {
4742 #ifdef HAVE_POSIX_REGEX
4743                     regex_t re;
4744                     char errbuf[256];
4745
4746                     /* XXX -- should just do the compile once! */
4747                     code = regcomp(&re, ti->data, REG_NOSUB);
4748                     if (code != 0) {
4749                         regerror(code, &re, errbuf, sizeof errbuf);
4750                         fprintf(STDERR,
4751                                 "Error in -xprefix regular expression: '%s': %s\n",
4752                                 ti->data, errbuf);
4753                         exit(1);
4754                     }
4755                     if (regexec(&re, vllist->name, 0, NULL, 0) == 0)
4756                             match = 0;
4757                     regfree(&re);
4758 #else
4759                     ccode = (char *)re_comp(ti->data);
4760                     if (ccode) {
4761                         fprintf(STDERR,
4762                                 "Error in -xprefix regular expression: '%s': %s\n",
4763                                 ti->data, ccode);
4764                         exit(1);
4765                     }
4766                     if (re_exec(vllist->name) == 1) {
4767                         match = 0;
4768                         break;
4769                     }
4770 #endif
4771                 } else {
4772                     if (strncmp(vllist->name, ti->data, strlen(ti->data)) ==
4773                         0) {
4774                         match = 0;
4775                         break;
4776                     }
4777                 }
4778             }
4779         }
4780
4781         if (exclude)
4782             match = !match;     /* -exclude will reverse the match */
4783         if (!match)
4784             continue;           /* Skip if no match */
4785
4786         /* Print list of volumes to backup */
4787         if (noaction) {
4788             fprintf(STDOUT, "     %s\n", vllist->name);
4789             continue;
4790         }
4791
4792         if (!(vllist->flags & RW_EXISTS)) {
4793             if (verbose) {
4794                 fprintf(STDOUT,
4795                         "Omitting to backup %s since RW volume does not exist \n",
4796                         vllist->name);
4797                 fprintf(STDOUT, "\n");
4798             }
4799             fflush(STDOUT);
4800             continue;
4801         }
4802
4803         avolid = vllist->volumeId[RWVOL];
4804         MapHostToNetwork(vllist);
4805         GetServerAndPart(vllist, RWVOL, &aserver1, &apart1, &previdx);
4806         if (aserver1 == -1 || apart1 == -1) {
4807             fprintf(STDOUT, "could not backup %s, invalid VLDB entry\n",
4808                     vllist->name);
4809             totalFail++;
4810             continue;
4811         }
4812         if (aserver) {
4813             same = VLDB_IsSameAddrs(aserver, aserver1, &error);
4814             if (error) {
4815                 fprintf(STDERR,
4816                         "Failed to get info about server's %d address(es) from vlserver (err=%d); aborting call!\n",
4817                         aserver, error);
4818                 totalFail++;
4819                 continue;
4820             }
4821         }
4822         if ((aserver && !same) || (apart && (apart != apart1))) {
4823             if (verbose) {
4824                 fprintf(STDOUT,
4825                         "Omitting to backup %s since the RW is in a different location\n",
4826                         vllist->name);
4827             }
4828             continue;
4829         }
4830         if (verbose) {
4831             time_t now = time(0);
4832             fprintf(STDOUT, "Creating backup volume for %s on %s",
4833                     vllist->name, ctime(&now));
4834             fflush(STDOUT);
4835         }
4836
4837         code = UV_BackupVolume(aserver1, apart1, avolid);
4838         if (code) {
4839             fprintf(STDOUT, "Could not backup %s\n", vllist->name);
4840             totalFail++;
4841         } else {
4842             totalBack++;
4843         }
4844         if (verbose)
4845             fprintf(STDOUT, "\n");
4846         fflush(STDOUT);
4847     }                           /* process each vldb entry */
4848     fprintf(STDOUT, "done\n");
4849     fprintf(STDOUT, "Total volumes backed up: %lu; failed to backup: %lu\n",
4850             (unsigned long)totalBack, (unsigned long)totalFail);
4851     fflush(STDOUT);
4852     if (arrayEntries.nbulkentries_val)
4853         free(arrayEntries.nbulkentries_val);
4854     return 0;
4855 }
4856
4857 static int
4858 UnlockVLDB(register struct cmd_syndesc *as, void *arock)
4859 {
4860     afs_int32 apart;
4861     afs_int32 aserver = 0;
4862     afs_int32 code;
4863     afs_int32 vcode;
4864     struct VldbListByAttributes attributes;
4865     nbulkentries arrayEntries;
4866     register struct nvldbentry *vllist;
4867     afs_int32 nentries;
4868     int j;
4869     afs_uint32 volid;
4870     afs_int32 totalE;
4871     char pname[10];
4872
4873     apart = -1;
4874     totalE = 0;
4875     attributes.Mask = 0;
4876
4877     if (as->parms[0].items) {   /* server specified */
4878         aserver = GetServer(as->parms[0].items->data);
4879         if (aserver == 0) {
4880             fprintf(STDERR, "vos: server '%s' not found in host table\n",
4881                     as->parms[0].items->data);
4882             exit(1);
4883         }
4884         attributes.server = ntohl(aserver);
4885         attributes.Mask |= VLLIST_SERVER;
4886     }
4887     if (as->parms[1].items) {   /* partition specified */
4888         apart = volutil_GetPartitionID(as->parms[1].items->data);
4889         if (apart < 0) {
4890             fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
4891                     as->parms[1].items->data);
4892             exit(1);
4893         }
4894         if (!IsPartValid(apart, aserver, &code)) {      /*check for validity of the partition */
4895             if (code)
4896                 PrintError("", code);
4897             else
4898                 fprintf(STDERR,
4899                         "vos : partition %s does not exist on the server\n",
4900                         as->parms[1].items->data);
4901             exit(1);
4902         }
4903         attributes.partition = apart;
4904         attributes.Mask |= VLLIST_PARTITION;
4905     }
4906     attributes.flag = VLOP_ALLOPERS;
4907     attributes.Mask |= VLLIST_FLAG;
4908     memset(&arrayEntries, 0, sizeof(arrayEntries));     /*initialize to hint the stub  to alloc space */
4909     vcode = VLDB_ListAttributes(&attributes, &nentries, &arrayEntries);
4910     if (vcode) {
4911         fprintf(STDERR, "Could not access the VLDB for attributes\n");
4912         PrintError("", vcode);
4913         exit(1);
4914     }
4915     for (j = 0; j < nentries; j++) {    /* process each entry */
4916         vllist = &arrayEntries.nbulkentries_val[j];
4917         volid = vllist->volumeId[RWVOL];
4918         vcode =
4919             ubik_VL_ReleaseLock(cstruct, 0, volid, -1,
4920                                 LOCKREL_OPCODE | LOCKREL_AFSID | 
4921                                 LOCKREL_TIMESTAMP);
4922         if (vcode) {
4923             fprintf(STDERR, "Could not unlock entry for volume %s\n",
4924                     vllist->name);
4925             PrintError("", vcode);
4926             totalE++;
4927         }
4928
4929     }
4930     MapPartIdIntoName(apart, pname);
4931     if (totalE)
4932         fprintf(STDOUT,
4933                 "Could not lock %lu VLDB entries of %lu locked entries\n",
4934                 (unsigned long)totalE, (unsigned long)nentries);
4935     else {
4936         if (as->parms[0].items) {
4937             fprintf(STDOUT,
4938                     "Unlocked all the VLDB entries for volumes on server %s ",
4939                     as->parms[0].items->data);
4940             if (as->parms[1].items) {
4941                 MapPartIdIntoName(apart, pname);
4942                 fprintf(STDOUT, "partition %s\n", pname);
4943             } else
4944                 fprintf(STDOUT, "\n");
4945
4946         } else if (as->parms[1].items) {
4947             MapPartIdIntoName(apart, pname);
4948             fprintf(STDOUT,
4949                     "Unlocked all the VLDB entries for volumes on partition %s on all servers\n",
4950                     pname);
4951         }
4952     }
4953
4954     if (arrayEntries.nbulkentries_val)
4955         free(arrayEntries.nbulkentries_val);
4956     return 0;
4957 }
4958
4959 static char *
4960 PrintInt64Size(afs_uint64 in)
4961 {
4962     register afs_uint32 hi, lo;
4963     register char * units;
4964     static char output[16];
4965
4966     SplitInt64(in,hi,lo);
4967
4968     if (hi == 0) {
4969         units = "KB";
4970     } else if (!(hi & 0xFFFFFC00)) {
4971         units = "MB";
4972         lo = (hi << 22) | (lo >> 10);
4973     } else if (!(hi & 0xFFF00000)) {
4974         units = "GB";
4975         lo = (hi << 12) | (lo >> 20);
4976     } else if (!(hi & 0xC0000000)) {
4977         units = "TB";
4978         lo = (hi << 2) | (lo >> 30);
4979     } else {
4980         units = "PB";
4981         lo = (hi >> 8);
4982     }
4983     sprintf(output,"%u %s", lo, units);
4984     return output;
4985 }
4986
4987 static int
4988 PartitionInfo(register struct cmd_syndesc *as, void *arock)
4989 {
4990     afs_int32 apart;
4991     afs_int32 aserver, code;
4992     char pname[10];
4993     struct diskPartition64 partition;
4994     struct partList dummyPartList;
4995     int i, cnt;
4996     int printSummary=0, sumPartitions=0;
4997     afs_uint64 sumFree, sumStorage;
4998
4999     ZeroInt64(sumFree);
5000     ZeroInt64(sumStorage);
5001     apart = -1;
5002     aserver = GetServer(as->parms[0].items->data);
5003     if (aserver == 0) {
5004         fprintf(STDERR, "vos: server '%s' not found in host table\n",
5005                 as->parms[0].items->data);
5006         exit(1);
5007     }
5008     if (as->parms[1].items) {
5009         apart = volutil_GetPartitionID(as->parms[1].items->data);
5010         if (apart < 0) {
5011             fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
5012                     as->parms[1].items->data);
5013             exit(1);
5014         }
5015         dummyPartList.partId[0] = apart;
5016         dummyPartList.partFlags[0] = PARTVALID;
5017         cnt = 1;
5018     }
5019     if (as->parms[2].items) {
5020         printSummary = 1;
5021     }
5022     if (apart != -1) {
5023         if (!IsPartValid(apart, aserver, &code)) {      /*check for validity of the partition */
5024             if (code)
5025                 PrintError("", code);
5026             else
5027                 fprintf(STDERR,
5028                         "vos : partition %s does not exist on the server\n",
5029                         as->parms[1].items->data);
5030             exit(1);
5031         }
5032     } else {
5033         code = UV_ListPartitions(aserver, &dummyPartList, &cnt);
5034         if (code) {
5035             PrintDiagnostics("listpart", code);
5036             exit(1);
5037         }
5038     }
5039     for (i = 0; i < cnt; i++) {
5040         if (dummyPartList.partFlags[i] & PARTVALID) {
5041             MapPartIdIntoName(dummyPartList.partId[i], pname);
5042             code = UV_PartitionInfo64(aserver, pname, &partition);
5043             if (code) {
5044                 fprintf(STDERR, "Could not get information on partition %s\n",
5045                         pname);
5046                 PrintError("", code);
5047                 exit(1);
5048             }
5049             fprintf(STDOUT,
5050                     "Free space on partition %s: %" AFS_INT64_FMT " K blocks out of total %" AFS_INT64_FMT "\n",
5051                     pname, partition.free, partition.minFree);
5052             sumPartitions++;
5053             AddUInt64(sumFree,partition.free,&sumFree);
5054             AddUInt64(sumStorage,partition.minFree,&sumStorage);
5055         }
5056     }
5057     if (printSummary) {
5058         fprintf(STDOUT,
5059                 "Summary: %s free out of ",
5060                 PrintInt64Size(sumFree));
5061         fprintf(STDOUT,
5062                 "%s on %d partitions\n",
5063                 PrintInt64Size(sumStorage), 
5064                 sumPartitions);
5065     }
5066     return 0;
5067 }
5068
5069 static int
5070 ChangeAddr(register struct cmd_syndesc *as, void *arock)
5071 {
5072     afs_int32 ip1, ip2, vcode;
5073     int remove = 0;
5074
5075     ip1 = GetServer(as->parms[0].items->data);
5076     if (!ip1) {
5077         fprintf(STDERR, "vos: invalid host address\n");
5078         return (EINVAL);
5079     }
5080
5081     if ((as->parms[1].items && as->parms[2].items)
5082         || (!as->parms[1].items && !as->parms[2].items)) {
5083         fprintf(STDERR,
5084                 "vos: Must specify either '-newaddr <addr>' or '-remove' flag\n");
5085         return (EINVAL);
5086     }
5087
5088     if (as->parms[1].items) {
5089         ip2 = GetServer(as->parms[1].items->data);
5090         if (!ip2) {
5091             fprintf(STDERR, "vos: invalid host address\n");
5092             return (EINVAL);
5093         }
5094     } else {
5095         /* Play a trick here. If we are removing an address, ip1 will be -1
5096          * and ip2 will be the original address. This switch prevents an 
5097          * older revision vlserver from removing the IP address.
5098          */
5099         remove = 1;
5100         ip2 = ip1;
5101         ip1 = 0xffffffff;
5102     }
5103
5104     vcode = ubik_Call_New(VL_ChangeAddr, cstruct, 0, ntohl(ip1), ntohl(ip2));
5105     if (vcode) {
5106         if (remove) {
5107             fprintf(STDERR, "Could not remove server %s from the VLDB\n",
5108                     as->parms[0].items->data);
5109             if (vcode == VL_NOENT) {
5110                 fprintf(STDERR,
5111                         "vlserver does not support the remove flag or ");
5112             }
5113         } else {
5114             fprintf(STDERR, "Could not change server %s to server %s\n",
5115                     as->parms[0].items->data, as->parms[1].items->data);
5116         }
5117         PrintError("", vcode);
5118         return (vcode);
5119     }
5120
5121     if (remove) {
5122         fprintf(STDOUT, "Removed server %s from the VLDB\n",
5123                 as->parms[0].items->data);
5124     } else {
5125         fprintf(STDOUT, "Changed server %s to server %s\n",
5126                 as->parms[0].items->data, as->parms[1].items->data);
5127     }
5128     return 0;
5129 }
5130
5131 static void
5132 print_addrs(const bulkaddrs * addrs, const afsUUID * m_uuid, int nentries,
5133             int print)
5134 {
5135     afs_int32 vcode;
5136     afs_int32 i, j;
5137     struct VLCallBack vlcb;
5138     afs_int32 *addrp;
5139     bulkaddrs m_addrs;
5140     ListAddrByAttributes m_attrs;
5141     afs_int32 m_nentries, *m_addrp;
5142     afs_int32 base, index;
5143     char buf[1024];
5144
5145     if (print) {
5146         afsUUID_to_string(m_uuid, buf, sizeof(buf));
5147         printf("UUID: %s\n", buf);
5148     }
5149
5150     /* print out the list of all the server */
5151     addrp = (afs_int32 *) addrs->bulkaddrs_val;
5152     for (i = 0; i < nentries; i++, addrp++) {
5153         /* If it is a multihomed address, then we will need to 
5154          * get the addresses for this multihomed server from
5155          * the vlserver and print them.
5156          */
5157         if (((*addrp & 0xff000000) == 0xff000000) && ((*addrp) & 0xffff)) {
5158             /* Get the list of multihomed fileservers */
5159             base = (*addrp >> 16) & 0xff;
5160             index = (*addrp) & 0xffff;
5161
5162             if ((base >= 0) && (base <= VL_MAX_ADDREXTBLKS) && (index >= 1)
5163                 && (index <= VL_MHSRV_PERBLK)) {
5164                 m_attrs.Mask = VLADDR_INDEX;
5165                 m_attrs.index = (base * VL_MHSRV_PERBLK) + index;
5166                 m_nentries = 0;
5167                 m_addrs.bulkaddrs_val = 0;
5168                 m_addrs.bulkaddrs_len = 0;
5169                 vcode =
5170                     ubik_VL_GetAddrsU(cstruct, 0, &m_attrs, &m_uuid,
5171                                       (afs_int32 *)&vlcb, &m_nentries, &m_addrs);
5172                 if (vcode) {
5173                     fprintf(STDERR,
5174                             "vos: could not list the multi-homed server addresses\n");
5175                     PrintError("", vcode);
5176                 }
5177
5178                 /* Print the list */
5179                 m_addrp = (afs_int32 *) m_addrs.bulkaddrs_val;
5180                 for (j = 0; j < m_nentries; j++, m_addrp++) {
5181                     *m_addrp = htonl(*m_addrp);
5182                     if (noresolve) {
5183                         char hoststr[16];
5184                         printf("%s ", afs_inet_ntoa_r(*m_addrp, hoststr));
5185                     } else {
5186                         printf("%s ", hostutil_GetNameByINet(*m_addrp));
5187                     }
5188                 }
5189                 if (j == 0) {
5190                     printf("<unknown>\n");
5191                 } else {
5192                     printf("\n");
5193                 }
5194
5195                 continue;
5196             }
5197         }
5198
5199         /* Otherwise, it is a non-multihomed entry and contains
5200          * the IP address of the server - print it.
5201          */
5202         *addrp = htonl(*addrp);
5203         if (noresolve) {
5204             char hoststr[16];
5205             printf("%s\n", afs_inet_ntoa_r(*addrp, hoststr));
5206         } else {
5207             printf("%s\n", hostutil_GetNameByINet(*addrp));
5208         }
5209     }
5210
5211     if (print) {
5212         printf("\n");
5213     }
5214     return;
5215 }
5216
5217 static int
5218 ListAddrs(register struct cmd_syndesc *as, void *arock)
5219 {
5220     afs_int32 vcode;
5221     afs_int32 i, printuuid = 0;
5222     struct VLCallBack vlcb;
5223     afs_int32 nentries;
5224     bulkaddrs m_addrs;
5225     ListAddrByAttributes m_attrs;
5226     afsUUID m_uuid, askuuid;
5227     afs_int32 m_nentries;
5228
5229     memset(&m_attrs, 0, sizeof(struct ListAddrByAttributes));
5230     m_attrs.Mask = VLADDR_INDEX;
5231
5232     memset(&m_addrs, 0, sizeof(bulkaddrs));
5233     memset(&askuuid, 0, sizeof(afsUUID));
5234     if (as->parms[0].items) {
5235         /* -uuid */
5236         if (afsUUID_from_string(as->parms[0].items->data, &askuuid) < 0) {
5237             fprintf(STDERR, "vos: invalid UUID '%s'\n", 
5238                     as->parms[0].items->data);
5239             exit(-1);
5240         }
5241         m_attrs.Mask = VLADDR_UUID;
5242         m_attrs.uuid = askuuid;
5243     }
5244     if (as->parms[1].items) {
5245         /* -host */
5246         struct hostent *he;
5247         afs_int32 saddr;
5248         he = hostutil_GetHostByName((char *)as->parms[1].items->data);
5249         if (he == NULL) {
5250             fprintf(STDERR, "vos: Can't get host info for '%s'\n",
5251                     as->parms[1].items->data);
5252             exit(-1);
5253         }
5254         memcpy(&saddr, he->h_addr, 4);
5255         m_attrs.Mask = VLADDR_IPADDR;
5256         m_attrs.ipaddr = ntohl(saddr);
5257     }
5258     if (as->parms[2].items) {
5259         printuuid = 1;
5260     }
5261
5262     m_addrs.bulkaddrs_val = 0;
5263     m_addrs.bulkaddrs_len = 0;
5264
5265     vcode =
5266         ubik_Call_New(VL_GetAddrs, cstruct, 0, 0, 0, &vlcb, &nentries,
5267                       &m_addrs);
5268     if (vcode) {
5269         fprintf(STDERR, "vos: could not list the server addresses\n");
5270         PrintError("", vcode);
5271         return (vcode);
5272     }
5273
5274     m_nentries = 0;
5275     m_addrs.bulkaddrs_val = 0;
5276     m_addrs.bulkaddrs_len = 0;
5277     i = 1;
5278     while (1) {
5279         m_attrs.index = i;
5280
5281         vcode =
5282             ubik_Call_New(VL_GetAddrsU, cstruct, 0, &m_attrs, &m_uuid,
5283                           &vlcb, &m_nentries, &m_addrs);
5284
5285         if (vcode == VL_NOENT) {
5286             if (m_attrs.Mask == VLADDR_UUID) {
5287                 fprintf(STDERR, "vos: no entry for UUID '%s' found in VLDB\n",
5288                         as->parms[0].items->data);
5289                 exit(-1);
5290             } else if (m_attrs.Mask == VLADDR_IPADDR) {
5291                 fprintf(STDERR, "vos: no entry for host '%s' [0x%08x] found in VLDB\n",
5292                         as->parms[1].items->data, m_attrs.ipaddr);
5293                 exit(-1);
5294             } else {
5295                 i++;
5296                 nentries++;
5297                 continue;
5298             }
5299         }
5300
5301         if (vcode == VL_INDEXERANGE) {
5302             break;
5303         }
5304
5305         if (vcode) {
5306             fprintf(STDERR, "vos: could not list the server addresses\n");
5307             PrintError("", vcode);
5308             return (vcode);
5309         }
5310
5311         print_addrs(&m_addrs, &m_uuid, m_nentries, printuuid);
5312         i++;
5313
5314         if ((as->parms[1].items) || (as->parms[0].items) || (i > nentries))
5315             break;
5316     }
5317
5318     return 0;
5319 }
5320
5321 static int
5322 LockEntry(register struct cmd_syndesc *as, void *arock)
5323 {
5324     afs_uint32 avolid;
5325     afs_int32 vcode, err;
5326
5327     avolid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);
5328     if (avolid == 0) {
5329         if (err)
5330             PrintError("", err);
5331         else
5332             fprintf(STDERR, "vos: can't find volume '%s'\n",
5333                     as->parms[0].items->data);
5334         exit(1);
5335     }
5336     vcode = ubik_VL_SetLock(cstruct, 0, avolid, -1, VLOP_DELETE);
5337     if (vcode) {
5338         fprintf(STDERR, "Could not lock VLDB entry for volume %s\n",
5339                 as->parms[0].items->data);
5340         PrintError("", vcode);
5341         exit(1);
5342     }
5343     fprintf(STDOUT, "Locked VLDB entry for volume %s\n",
5344             as->parms[0].items->data);
5345     return 0;
5346 }
5347
5348 static int
5349 ConvertRO(register struct cmd_syndesc *as, void *arock)
5350 {
5351     afs_int32 partition = -1;
5352     afs_uint32 volid;
5353     afs_int32 server, code, i, same;
5354     struct nvldbentry entry, storeEntry;
5355     afs_int32 vcode;
5356     afs_int32 rwindex = 0;
5357     afs_int32 rwserver = 0;
5358     afs_int32 rwpartition = 0;
5359     afs_int32 roindex = 0;
5360     afs_int32 roserver = 0;
5361     afs_int32 ropartition = 0;
5362     int force = 0;
5363     struct rx_connection *aconn;
5364     char c, dc;
5365
5366     server = GetServer(as->parms[0].items->data);
5367     if (!server) {
5368         fprintf(STDERR, "vos: host '%s' not found in host table\n",
5369                 as->parms[0].items->data);
5370         return ENOENT;
5371     }
5372     partition = volutil_GetPartitionID(as->parms[1].items->data);
5373     if (partition < 0) {
5374         fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
5375                 as->parms[1].items->data);
5376         return ENOENT;
5377     }
5378     if (!IsPartValid(partition, server, &code)) {
5379         if (code)
5380             PrintError("", code);
5381         else
5382             fprintf(STDERR,
5383                     "vos : partition %s does not exist on the server\n",
5384                     as->parms[1].items->data);
5385         return ENOENT;
5386     }
5387     volid = vsu_GetVolumeID(as->parms[2].items->data, cstruct, &code);
5388     if (volid == 0) {
5389         if (code)
5390             PrintError("", code);
5391         else
5392             fprintf(STDERR, "Unknown volume ID or name '%s'\n",
5393                     as->parms[0].items->data);
5394         return -1;
5395     }
5396     if (as->parms[3].items)
5397         force = 1;
5398
5399     vcode = VLDB_GetEntryByID(volid, -1, &entry);
5400     if (vcode) {
5401         fprintf(STDERR,
5402                 "Could not fetch the entry for volume %lu from VLDB\n",
5403                 (unsigned long)volid);
5404         PrintError("convertROtoRW", code);
5405         return vcode;
5406     }
5407
5408     /* use RO volid even if user specified RW or BK volid */
5409
5410     if (volid != entry.volumeId[ROVOL])
5411         volid = entry.volumeId[ROVOL];
5412
5413     MapHostToNetwork(&entry);
5414     for (i = 0; i < entry.nServers; i++) {
5415         if (entry.serverFlags[i] & ITSRWVOL) {
5416             rwindex = i;
5417             rwserver = entry.serverNumber[i];
5418             rwpartition = entry.serverPartition[i];
5419         }
5420         if (entry.serverFlags[i] & ITSROVOL) {
5421             same = VLDB_IsSameAddrs(server, entry.serverNumber[i], &code);
5422             if (code) {
5423                 fprintf(STDERR,
5424                         "Failed to get info about server's %d address(es) from vlserver (err=%d); aborting call!\n",
5425                         server, code);
5426                 return ENOENT;
5427             }
5428             if (same) {
5429                 roindex = i;
5430                 roserver = entry.serverNumber[i];
5431                 ropartition = entry.serverPartition[i];
5432                 break;
5433             }
5434         }
5435     }
5436     if (!roserver) {
5437         fprintf(STDERR, "Warning: RO volume didn't exist in vldb!\n");
5438     }
5439     if (ropartition != partition) {
5440         fprintf(STDERR,
5441                 "Warning: RO volume should be in partition %d instead of %d (vldb)\n",
5442                 ropartition, partition);
5443     }
5444
5445     if (rwserver) {
5446         fprintf(STDERR,
5447                 "VLDB indicates that a RW volume exists already on %s in partition %s.\n",
5448                 hostutil_GetNameByINet(rwserver),
5449                 volutil_PartitionName(rwpartition));
5450         if (!force) {
5451             fprintf(STDERR, "Overwrite this VLDB entry? [y|n] (n)\n");
5452             dc = c = getchar();
5453             while (!(dc == EOF || dc == '\n'))
5454                 dc = getchar(); /* goto end of line */
5455             if ((c != 'y') && (c != 'Y')) {
5456                 fprintf(STDERR, "aborted.\n");
5457                 return -1;
5458             }
5459         }
5460     }
5461
5462     vcode =
5463         ubik_VL_SetLock(cstruct, 0, entry.volumeId[RWVOL], RWVOL,
5464                   VLOP_MOVE);
5465     aconn = UV_Bind(server, AFSCONF_VOLUMEPORT);
5466     code = AFSVolConvertROtoRWvolume(aconn, partition, volid);
5467     if (code) {
5468         fprintf(STDERR,
5469                 "Converting RO volume %lu to RW volume failed with code %d\n",
5470                 (unsigned long)volid, code);
5471         PrintError("convertROtoRW ", code);
5472         return -1;
5473     }
5474     entry.serverFlags[roindex] = ITSRWVOL;
5475     entry.flags |= RW_EXISTS;
5476     entry.flags &= ~BACK_EXISTS;
5477     if (rwserver) {
5478         (entry.nServers)--;
5479         if (rwindex != entry.nServers) {
5480             entry.serverNumber[rwindex] = entry.serverNumber[entry.nServers];
5481             entry.serverPartition[rwindex] =
5482                 entry.serverPartition[entry.nServers];
5483             entry.serverFlags[rwindex] = entry.serverFlags[entry.nServers];
5484             entry.serverNumber[entry.nServers] = 0;
5485             entry.serverPartition[entry.nServers] = 0;
5486             entry.serverFlags[entry.nServers] = 0;
5487         }
5488     }
5489     entry.flags &= ~RO_EXISTS;
5490     for (i = 0; i < entry.nServers; i++) {
5491         if (entry.serverFlags[i] & ITSROVOL) {
5492             if (!(entry.serverFlags[i] & (RO_DONTUSE | NEW_REPSITE)))
5493                 entry.flags |= RO_EXISTS;
5494         }
5495     }
5496     MapNetworkToHost(&entry, &storeEntry);
5497     code =
5498         VLDB_ReplaceEntry(entry.volumeId[RWVOL], RWVOL, &storeEntry,
5499                           (LOCKREL_OPCODE | LOCKREL_AFSID |
5500                            LOCKREL_TIMESTAMP));
5501     if (code) {
5502         fprintf(STDERR,
5503                 "Warning: volume converted, but vldb update failed with code %d!\n",
5504                 code);
5505     }
5506     vcode = UV_LockRelease(entry.volumeId[RWVOL]);
5507     if (vcode) {
5508         PrintDiagnostics("unlock", vcode);
5509     }
5510     return code;
5511 }
5512
5513 static int
5514 Sizes(register struct cmd_syndesc *as, void *arock)
5515 {
5516     afs_uint32 avolid;
5517     afs_int32 aserver, apart, voltype, fromdate = 0, code, err, i;
5518     struct nvldbentry entry;
5519     volintSize vol_size;
5520
5521     rx_SetRxDeadTime(60 * 10);
5522     for (i = 0; i < MAXSERVERS; i++) {
5523         struct rx_connection *rxConn = ubik_GetRPCConn(cstruct, i);
5524         if (rxConn == 0)
5525             break;
5526         rx_SetConnDeadTime(rxConn, rx_connDeadTime);
5527         if (rxConn->service)
5528             rxConn->service->connDeadTime = rx_connDeadTime;
5529     }
5530
5531     avolid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);
5532     if (avolid == 0) {
5533         if (err)
5534             PrintError("", err);
5535         else
5536             fprintf(STDERR, "vos: can't find volume '%s'\n",
5537                     as->parms[0].items->data);
5538         return ENOENT;
5539     }
5540
5541     if (as->parms[1].items || as->parms[2].items) {
5542         if (!as->parms[1].items || !as->parms[2].items) {
5543             fprintf(STDERR,
5544                     "Must specify both -server and -partition options\n");
5545             return -1;
5546         }
5547         aserver = GetServer(as->parms[2].items->data);
5548         if (aserver == 0) {
5549             fprintf(STDERR, "Invalid server name\n");
5550             return -1;
5551         }
5552         apart = volutil_GetPartitionID(as->parms[1].items->data);
5553         if (apart < 0) {
5554             fprintf(STDERR, "Invalid partition name\n");
5555             return -1;
5556         }
5557     } else {
5558         code = GetVolumeInfo(avolid, &aserver, &apart, &voltype, &entry);
5559         if (code)
5560             return code;
5561     }
5562
5563     fromdate = 0;
5564
5565     if (as->parms[4].items && strcmp(as->parms[4].items->data, "0")) {
5566         code = ktime_DateToInt32(as->parms[4].items->data, &fromdate);
5567         if (code) {
5568             fprintf(STDERR, "vos: failed to parse date '%s' (error=%d))\n",
5569                     as->parms[4].items->data, code);
5570             return code;
5571         }
5572     }
5573
5574     fprintf(STDOUT, "Volume: %s\n", as->parms[0].items->data);
5575
5576     if (as->parms[3].items) {   /* do the dump estimate */
5577 #ifdef AFS_64BIT_ENV
5578         vol_size.dump_size = 0;
5579 #else
5580    FillInt64(vol_size.dump_size,0, 1);
5581 #endif
5582         code = UV_GetSize(avolid, aserver, apart, fromdate, &vol_size);
5583         if (code) {
5584             PrintDiagnostics("size", code);
5585             return code;
5586         }
5587         /* presumably the size info is now gathered in pntr */
5588         /* now we display it */
5589
5590         fprintf(STDOUT, "dump_size: %llu\n", vol_size.dump_size);
5591     }
5592
5593     /* Display info */
5594
5595     return 0;
5596 }
5597
5598 int
5599 PrintDiagnostics(char *astring, afs_int32 acode)
5600 {
5601     if (acode == EACCES) {
5602         fprintf(STDERR,
5603                 "You are not authorized to perform the 'vos %s' command (%d)\n",
5604                 astring, acode);
5605     } else {
5606         fprintf(STDERR, "Error in vos %s command.\n", astring);
5607         PrintError("", acode);
5608     }
5609     return 0;
5610 }
5611
5612
5613 static int
5614 MyBeforeProc(struct cmd_syndesc *as, void *arock)
5615 {
5616     register char *tcell;
5617     register afs_int32 code;
5618     register afs_int32 sauth;
5619
5620     /* Initialize the ubik_client connection */
5621     rx_SetRxDeadTime(90);
5622     cstruct = (struct ubik_client *)0;
5623
5624     sauth = 0;
5625     tcell = NULL;
5626     if (as->parms[12].items)    /* if -cell specified */
5627         tcell = as->parms[12].items->data;
5628     if (as->parms[14].items)    /* -serverauth specified */
5629         sauth = 1;
5630     if (as->parms[16].items)    /* -crypt specified */
5631         vsu_SetCrypt(1);
5632     if ((code =
5633          vsu_ClientInit((as->parms[13].items != 0), confdir, tcell, sauth,
5634                         &cstruct, UV_SetSecurity))) {
5635         fprintf(STDERR, "could not initialize VLDB library (code=%lu) \n",
5636                 (unsigned long)code);
5637         exit(1);
5638     }
5639     rxInitDone = 1;
5640     if (as->parms[15].items)    /* -verbose flag set */
5641         verbose = 1;
5642     else
5643         verbose = 0;
5644     if (as->parms[17].items)    /* -noresolve flag set */
5645         noresolve = 1;
5646     else
5647         noresolve = 0;
5648     return 0;
5649 }
5650
5651 int
5652 osi_audit(void)
5653 {
5654 /* this sucks but it works for now.
5655 */
5656     return 0;
5657 }
5658
5659 #include "AFS_component_version_number.c"
5660
5661 int
5662 main(int argc, char **argv)
5663 {
5664     register afs_int32 code;
5665
5666     register struct cmd_syndesc *ts;
5667
5668 #ifdef  AFS_AIX32_ENV
5669     /*
5670      * The following signal action for AIX is necessary so that in case of a 
5671      * crash (i.e. core is generated) we can include the user's data section 
5672      * in the core dump. Unfortunately, by default, only a partial core is
5673      * generated which, in many cases, isn't too useful.
5674      */
5675     struct sigaction nsa;
5676
5677     sigemptyset(&nsa.sa_mask);
5678     nsa.sa_handler = SIG_DFL;
5679     nsa.sa_flags = SA_FULLDUMP;
5680     sigaction(SIGSEGV, &nsa, NULL);
5681 #endif
5682
5683     confdir = AFSDIR_CLIENT_ETC_DIRPATH;
5684
5685     cmd_SetBeforeProc(MyBeforeProc, NULL);
5686
5687     ts = cmd_CreateSyntax("create", CreateVolume, NULL, "create a new volume");
5688     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
5689     cmd_AddParm(ts, "-partition", CMD_SINGLE, 0, "partition name");
5690     cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "volume name");
5691     cmd_AddParm(ts, "-maxquota", CMD_SINGLE, CMD_OPTIONAL,
5692                 "initial quota (KB)");
5693 #ifdef notdef
5694     cmd_AddParm(ts, "-minquota", CMD_SINGLE, CMD_OPTIONAL, "");
5695 #endif
5696     COMMONPARMS;
5697
5698     ts = cmd_CreateSyntax("remove", DeleteVolume, NULL, "delete a volume");
5699     cmd_AddParm(ts, "-server", CMD_SINGLE, CMD_OPTIONAL, "machine name");
5700     cmd_AddParm(ts, "-partition", CMD_SINGLE, CMD_OPTIONAL, "partition name");
5701     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
5702
5703     COMMONPARMS;
5704
5705     ts = cmd_CreateSyntax("move", MoveVolume, NULL, "move a volume");
5706     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
5707     cmd_AddParm(ts, "-fromserver", CMD_SINGLE, 0, "machine name on source");
5708     cmd_AddParm(ts, "-frompartition", CMD_SINGLE, 0,
5709                 "partition name on source");
5710     cmd_AddParm(ts, "-toserver", CMD_SINGLE, 0,
5711                 "machine name on destination");
5712     cmd_AddParm(ts, "-topartition", CMD_SINGLE, 0,
5713                 "partition name on destination");
5714     cmd_AddParm(ts, "-live", CMD_FLAG, CMD_OPTIONAL,
5715                 "copy live volume without cloning");
5716     COMMONPARMS;
5717
5718     ts = cmd_CreateSyntax("copy", CopyVolume, NULL, "copy a volume");
5719     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID on source");
5720     cmd_AddParm(ts, "-fromserver", CMD_SINGLE, 0, "machine name on source");
5721     cmd_AddParm(ts, "-frompartition", CMD_SINGLE, 0,
5722                 "partition name on source");
5723     cmd_AddParm(ts, "-toname", CMD_SINGLE, 0, "volume name on destination");
5724     cmd_AddParm(ts, "-toserver", CMD_SINGLE, 0,
5725                 "machine name on destination");
5726     cmd_AddParm(ts, "-topartition", CMD_SINGLE, 0,
5727                 "partition name on destination");
5728     cmd_AddParm(ts, "-offline", CMD_FLAG, CMD_OPTIONAL,
5729                 "leave new volume offline");
5730     cmd_AddParm(ts, "-readonly", CMD_FLAG, CMD_OPTIONAL,
5731                 "make new volume read-only");
5732     cmd_AddParm(ts, "-live", CMD_FLAG, CMD_OPTIONAL,
5733                 "copy live volume without cloning");
5734     COMMONPARMS;
5735
5736     ts = cmd_CreateSyntax("shadow", ShadowVolume, NULL,
5737                           "make or update a shadow volume");
5738     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID on source");
5739     cmd_AddParm(ts, "-fromserver", CMD_SINGLE, 0, "machine name on source");
5740     cmd_AddParm(ts, "-frompartition", CMD_SINGLE, 0,
5741                 "partition name on source");
5742     cmd_AddParm(ts, "-toserver", CMD_SINGLE, 0,
5743                 "machine name on destination");
5744     cmd_AddParm(ts, "-topartition", CMD_SINGLE, 0,
5745                 "partition name on destination");
5746     cmd_AddParm(ts, "-toname", CMD_SINGLE, CMD_OPTIONAL,
5747                 "volume name on destination");
5748     cmd_AddParm(ts, "-toid", CMD_SINGLE, CMD_OPTIONAL,
5749                 "volume ID on destination");
5750     cmd_AddParm(ts, "-offline", CMD_FLAG, CMD_OPTIONAL,
5751                 "leave shadow volume offline");
5752     cmd_AddParm(ts, "-readonly", CMD_FLAG, CMD_OPTIONAL,
5753                 "make shadow volume read-only");
5754     cmd_AddParm(ts, "-live", CMD_FLAG, CMD_OPTIONAL,
5755                 "copy live volume without cloning");
5756     cmd_AddParm(ts, "-incremental", CMD_FLAG, CMD_OPTIONAL,
5757                 "do incremental update if target exists");
5758     COMMONPARMS;
5759
5760     ts = cmd_CreateSyntax("backup", BackupVolume, NULL,
5761                           "make backup of a volume");
5762     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
5763     COMMONPARMS;
5764
5765     ts = cmd_CreateSyntax("clone", CloneVolume, NULL,
5766                           "make clone of a volume");
5767     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
5768     cmd_AddParm(ts, "-server", CMD_SINGLE, CMD_OPTIONAL, "server");
5769     cmd_AddParm(ts, "-partition", CMD_SINGLE, CMD_OPTIONAL, "partition");
5770     cmd_AddParm(ts, "-toname", CMD_SINGLE, CMD_OPTIONAL,
5771                 "volume name on destination");
5772     cmd_AddParm(ts, "-toid", CMD_SINGLE, CMD_OPTIONAL,
5773                 "volume ID on destination");
5774     cmd_AddParm(ts, "-offline", CMD_FLAG, CMD_OPTIONAL,
5775                 "leave clone volume offline");
5776     cmd_AddParm(ts, "-readonly", CMD_FLAG, CMD_OPTIONAL,
5777                 "make clone volume read-only, not readwrite");
5778     COMMONPARMS;
5779
5780     ts = cmd_CreateSyntax("release", ReleaseVolume, NULL, "release a volume");
5781     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
5782     cmd_AddParm(ts, "-force", CMD_FLAG, CMD_OPTIONAL,
5783                 "force a complete release");
5784     COMMONPARMS;
5785
5786     ts = cmd_CreateSyntax("dump", DumpVolumeCmd, NULL, "dump a volume");
5787     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
5788     cmd_AddParm(ts, "-time", CMD_SINGLE, CMD_OPTIONAL, "dump from time");
5789     cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_OPTIONAL, "dump file");
5790     cmd_AddParm(ts, "-server", CMD_SINGLE, CMD_OPTIONAL, "server");
5791     cmd_AddParm(ts, "-partition", CMD_SINGLE, CMD_OPTIONAL, "partition");
5792     cmd_AddParm(ts, "-clone", CMD_FLAG, CMD_OPTIONAL,
5793                 "dump a clone of the volume");
5794     cmd_AddParm(ts, "-omitdirs", CMD_FLAG, CMD_OPTIONAL,
5795                 "omit unchanged directories from an incremental dump");
5796     COMMONPARMS;
5797
5798     ts = cmd_CreateSyntax("restore", RestoreVolumeCmd, NULL,
5799                           "restore a volume");
5800     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
5801     cmd_AddParm(ts, "-partition", CMD_SINGLE, 0, "partition name");
5802     cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of volume to be restored");
5803     cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_OPTIONAL, "dump file");
5804     cmd_AddParm(ts, "-id", CMD_SINGLE, CMD_OPTIONAL, "volume ID");
5805     cmd_AddParm(ts, "-overwrite", CMD_SINGLE, CMD_OPTIONAL,
5806                 "abort | full | incremental");
5807     cmd_AddParm(ts, "-offline", CMD_FLAG, CMD_OPTIONAL,
5808                 "leave restored volume offline");
5809     cmd_AddParm(ts, "-readonly", CMD_FLAG, CMD_OPTIONAL,
5810                 "make restored volume read-only");
5811     cmd_AddParm(ts, "-creation", CMD_SINGLE, CMD_OPTIONAL,
5812                 "dump | keep | new");
5813     cmd_AddParm(ts, "-lastupdate", CMD_SINGLE, CMD_OPTIONAL,
5814                 "dump | keep | new");
5815     cmd_AddParm(ts, "-nodelete", CMD_FLAG, CMD_OPTIONAL,
5816                 "do not delete old site when restoring to a new site");
5817     COMMONPARMS;
5818
5819     ts = cmd_CreateSyntax("unlock", LockReleaseCmd, NULL,
5820                           "release lock on VLDB entry for a volume");
5821     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
5822     COMMONPARMS;
5823
5824     ts = cmd_CreateSyntax("changeloc", ChangeLocation, NULL,
5825                           "change an RW volume's location in the VLDB");
5826     cmd_AddParm(ts, "-server", CMD_SINGLE, 0,
5827                 "machine name for new location");
5828     cmd_AddParm(ts, "-partition", CMD_SINGLE, 0,
5829                 "partition name for new location");
5830     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
5831     COMMONPARMS;
5832
5833     ts = cmd_CreateSyntax("addsite", AddSite, NULL, "add a replication site");
5834     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name for new site");
5835     cmd_AddParm(ts, "-partition", CMD_SINGLE, 0,
5836                 "partition name for new site");
5837     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
5838     cmd_AddParm(ts, "-valid", CMD_FLAG, CMD_OPTIONAL, "publish as an up-to-date site in VLDB");
5839     COMMONPARMS;
5840
5841     ts = cmd_CreateSyntax("remsite", RemoveSite, NULL,
5842                           "remove a replication site");
5843     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
5844     cmd_AddParm(ts, "-partition", CMD_SINGLE, 0, "partition name");
5845     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
5846     COMMONPARMS;
5847
5848     ts = cmd_CreateSyntax("listpart", ListPartitions, NULL, "list partitions");
5849     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
5850     COMMONPARMS;
5851
5852     ts = cmd_CreateSyntax("listvol", ListVolumes, NULL,
5853                           "list volumes on server (bypass VLDB)");
5854     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
5855     cmd_AddParm(ts, "-partition", CMD_SINGLE, CMD_OPTIONAL, "partition name");
5856     cmd_AddParm(ts, "-fast", CMD_FLAG, CMD_OPTIONAL, "minimal listing");
5857     cmd_AddParm(ts, "-long", CMD_FLAG, CMD_OPTIONAL,
5858                 "list all normal volume fields");
5859     cmd_AddParm(ts, "-quiet", CMD_FLAG, CMD_OPTIONAL,
5860                 "generate minimal information");
5861     cmd_AddParm(ts, "-extended", CMD_FLAG, CMD_OPTIONAL,
5862                 "list extended volume fields");
5863 #ifdef FULL_LISTVOL_SWITCH
5864     cmd_AddParm(ts, "-format", CMD_FLAG, CMD_OPTIONAL,
5865                 "machine readable format");
5866 #endif /* FULL_LISTVOL_SWITCH */
5867     COMMONPARMS;
5868
5869     ts = cmd_CreateSyntax("syncvldb", SyncVldb, NULL,
5870                           "synchronize VLDB with server");
5871     cmd_AddParm(ts, "-server", CMD_SINGLE, CMD_OPTIONAL, "machine name");
5872     cmd_AddParm(ts, "-partition", CMD_SINGLE, CMD_OPTIONAL, "partition name");
5873     cmd_AddParm(ts, "-volume", CMD_SINGLE, CMD_OPTIONAL, "volume name or ID");
5874     cmd_AddParm(ts, "-dryrun", CMD_FLAG, CMD_OPTIONAL, "report without updating");
5875     COMMONPARMS;
5876
5877     ts = cmd_CreateSyntax("syncserv", SyncServer, NULL,
5878                           "synchronize server with VLDB");
5879     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
5880     cmd_AddParm(ts, "-partition", CMD_SINGLE, CMD_OPTIONAL, "partition name");
5881     cmd_AddParm(ts, "-dryrun", CMD_FLAG, CMD_OPTIONAL, "report without updating");
5882     COMMONPARMS;
5883
5884     ts = cmd_CreateSyntax("examine", ExamineVolume, NULL,
5885                           "everything about the volume");
5886     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
5887     cmd_AddParm(ts, "-extended", CMD_FLAG, CMD_OPTIONAL,
5888                 "list extended volume fields");
5889 #ifdef FULL_LISTVOL_SWITCH
5890     cmd_AddParm(ts, "-format", CMD_FLAG, CMD_OPTIONAL,
5891                 "machine readable format");
5892 #endif /* FULL_LISTVOL_SWITCH */
5893     COMMONPARMS;
5894     cmd_CreateAlias(ts, "volinfo");
5895
5896     ts = cmd_CreateSyntax("setfields", SetFields, NULL,
5897                           "change volume info fields");
5898     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
5899     cmd_AddParm(ts, "-maxquota", CMD_SINGLE, CMD_OPTIONAL, "quota (KB)");
5900     cmd_AddParm(ts, "-clearuse", CMD_FLAG, CMD_OPTIONAL, "clear dayUse");
5901     cmd_AddParm(ts, "-clearVolUpCounter", CMD_FLAG, CMD_OPTIONAL, "clear volUpdateCounter");
5902     COMMONPARMS;
5903
5904     ts = cmd_CreateSyntax("offline", volOffline, NULL, "force the volume status to offline");
5905     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "server name");
5906     cmd_AddParm(ts, "-partition", CMD_SINGLE, 0, "partition name");
5907     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
5908     cmd_AddParm(ts, "-sleep", CMD_SINGLE, CMD_OPTIONAL, "seconds to sleep");
5909     cmd_AddParm(ts, "-busy", CMD_FLAG, CMD_OPTIONAL, "busy volume");
5910     COMMONPARMS;
5911
5912     ts = cmd_CreateSyntax("online", volOnline, NULL, "force the volume status to online");
5913     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "server name");
5914     cmd_AddParm(ts, "-partition", CMD_SINGLE, 0, "partition name");
5915     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
5916     COMMONPARMS;
5917
5918     ts = cmd_CreateSyntax("zap", VolumeZap, NULL,
5919                           "delete the volume, don't bother with VLDB");
5920     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
5921     cmd_AddParm(ts, "-partition", CMD_SINGLE, 0, "partition name");
5922     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume ID");
5923     cmd_AddParm(ts, "-force", CMD_FLAG, CMD_OPTIONAL,
5924                 "force deletion of bad volumes");
5925     cmd_AddParm(ts, "-backup", CMD_FLAG, CMD_OPTIONAL,
5926                 "also delete backup volume if one is found");
5927     COMMONPARMS;
5928
5929     ts = cmd_CreateSyntax("status", VolserStatus, NULL,
5930                           "report on volser status");
5931     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
5932     COMMONPARMS;
5933
5934     ts = cmd_CreateSyntax("rename", RenameVolume, NULL, "rename a volume");
5935     cmd_AddParm(ts, "-oldname", CMD_SINGLE, 0, "old volume name ");
5936     cmd_AddParm(ts, "-newname", CMD_SINGLE, 0, "new volume name ");
5937     COMMONPARMS;
5938
5939     ts = cmd_CreateSyntax("listvldb", ListVLDB, NULL,
5940                           "list volumes in the VLDB");
5941     cmd_AddParm(ts, "-name", CMD_SINGLE, CMD_OPTIONAL, "volume name or ID");
5942     cmd_AddParm(ts, "-server", CMD_SINGLE, CMD_OPTIONAL, "machine name");
5943     cmd_AddParm(ts, "-partition", CMD_SINGLE, CMD_OPTIONAL, "partition name");
5944     cmd_AddParm(ts, "-locked", CMD_FLAG, CMD_OPTIONAL, "locked volumes only");
5945     cmd_AddParm(ts, "-quiet", CMD_FLAG, CMD_OPTIONAL,
5946                 "generate minimal information");
5947     cmd_AddParm(ts, "-nosort", CMD_FLAG, CMD_OPTIONAL,
5948                 "do not alphabetically sort the volume names");
5949     COMMONPARMS;
5950
5951     ts = cmd_CreateSyntax("backupsys", BackSys, NULL, "en masse backups");
5952     cmd_AddParm(ts, "-prefix", CMD_LIST, CMD_OPTIONAL,
5953                 "common prefix on volume(s)");
5954     cmd_AddParm(ts, "-server", CMD_SINGLE, CMD_OPTIONAL, "machine name");
5955     cmd_AddParm(ts, "-partition", CMD_SINGLE, CMD_OPTIONAL, "partition name");
5956     cmd_AddParm(ts, "-exclude", CMD_FLAG, CMD_OPTIONAL,
5957                 "exclude common prefix volumes");
5958     cmd_AddParm(ts, "-xprefix", CMD_LIST, CMD_OPTIONAL,
5959                 "negative prefix on volume(s)");
5960     cmd_AddParm(ts, "-dryrun", CMD_FLAG, CMD_OPTIONAL, "no action");
5961     COMMONPARMS;
5962
5963     ts = cmd_CreateSyntax("delentry", DeleteEntry, NULL,
5964                           "delete VLDB entry for a volume");
5965     cmd_AddParm(ts, "-id", CMD_LIST, CMD_OPTIONAL, "volume name or ID");
5966     cmd_AddParm(ts, "-prefix", CMD_SINGLE, CMD_OPTIONAL,
5967                 "prefix of the volume whose VLDB entry is to be deleted");
5968     cmd_AddParm(ts, "-server", CMD_SINGLE, CMD_OPTIONAL, "machine name");
5969     cmd_AddParm(ts, "-partition", CMD_SINGLE, CMD_OPTIONAL, "partition name");
5970     cmd_AddParm(ts, "-noexecute", CMD_FLAG, CMD_OPTIONAL,
5971                 "no execute");
5972     COMMONPARMS;
5973
5974     ts = cmd_CreateSyntax("partinfo", PartitionInfo, NULL,
5975                           "list partition information");
5976     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
5977     cmd_AddParm(ts, "-partition", CMD_SINGLE, CMD_OPTIONAL, "partition name");
5978     cmd_AddParm(ts, "-summary", CMD_FLAG, CMD_OPTIONAL,
5979                 "print storage summary");
5980     COMMONPARMS;
5981
5982     ts = cmd_CreateSyntax("unlockvldb", UnlockVLDB, NULL,
5983                           "unlock all the locked entries in the VLDB");
5984     cmd_AddParm(ts, "-server", CMD_SINGLE, CMD_OPTIONAL, "machine name");
5985     cmd_AddParm(ts, "-partition", CMD_SINGLE, CMD_OPTIONAL, "partition name");
5986     COMMONPARMS;
5987
5988     ts = cmd_CreateSyntax("lock", LockEntry, NULL,
5989                           "lock VLDB entry for a volume");
5990     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
5991     COMMONPARMS;
5992
5993     ts = cmd_CreateSyntax("changeaddr", ChangeAddr, NULL,
5994                           "change the IP address of a file server");
5995     cmd_AddParm(ts, "-oldaddr", CMD_SINGLE, 0, "original IP address");
5996     cmd_AddParm(ts, "-newaddr", CMD_SINGLE, CMD_OPTIONAL, "new IP address");
5997     cmd_AddParm(ts, "-remove", CMD_FLAG, CMD_OPTIONAL,
5998                 "remove the IP address from the VLDB");
5999     COMMONPARMS;
6000
6001     ts = cmd_CreateSyntax("listaddrs", ListAddrs, NULL,
6002                           "list the IP address of all file servers registered in the VLDB");
6003     cmd_AddParm(ts, "-uuid", CMD_SINGLE, CMD_OPTIONAL, "uuid of server");
6004     cmd_AddParm(ts, "-host", CMD_SINGLE, CMD_OPTIONAL, "address of host");
6005     cmd_AddParm(ts, "-printuuid", CMD_FLAG, CMD_OPTIONAL,
6006                 "print uuid of hosts");
6007     COMMONPARMS;
6008
6009     ts = cmd_CreateSyntax("convertROtoRW", ConvertRO, NULL,
6010                           "convert a RO volume into a RW volume (after loss of old RW volume)");
6011     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
6012     cmd_AddParm(ts, "-partition", CMD_SINGLE, 0, "partition name");
6013     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
6014     cmd_AddParm(ts, "-force", CMD_FLAG, CMD_OPTIONAL, "don't ask");
6015     COMMONPARMS;
6016
6017     ts = cmd_CreateSyntax("size", Sizes, NULL,
6018                           "obtain various sizes of the volume.");
6019     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
6020     cmd_AddParm(ts, "-partition", CMD_SINGLE, CMD_OPTIONAL, "partition name");
6021     cmd_AddParm(ts, "-server", CMD_SINGLE, CMD_OPTIONAL, "machine name");
6022     cmd_AddParm(ts, "-dump", CMD_FLAG, CMD_OPTIONAL,
6023                 "Obtain the size of the dump");
6024     cmd_AddParm(ts, "-time", CMD_SINGLE, CMD_OPTIONAL, "dump from time");
6025     COMMONPARMS;
6026
6027     code = cmd_Dispatch(argc, argv);
6028     if (rxInitDone) {
6029         /* Shut down the ubik_client and rx connections */
6030         if (cstruct) {
6031             (void)ubik_ClientDestroy(cstruct);
6032             cstruct = 0;
6033         }
6034         rx_Finalize();
6035     }
6036
6037     exit((code ? -1 : 0));
6038 }