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