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