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