d1f9519a16b695272d2f5f3d9edd8f38f0315de3
[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("$Header$");
14
15 #include <sys/types.h>
16 #ifdef AFS_NT40_ENV
17 #include <fcntl.h>
18 #include <io.h>
19 #include <winsock2.h>
20 #else
21 #include <sys/time.h>
22 #include <sys/file.h>
23 #include <netdb.h>
24 #include <netinet/in.h>
25 #endif
26 #include <sys/stat.h>
27 #ifdef AFS_AIX_ENV
28 #include <sys/statfs.h>
29 #endif
30 #include <errno.h>
31
32 #ifdef HAVE_STRING_H
33 #include <string.h>
34 #else
35 #ifdef HAVE_STRINGS_H
36 #include <strings.h>
37 #endif
38 #endif
39
40 #include <lock.h>
41 #include <afs/stds.h>
42 #include <rx/xdr.h>
43 #include <rx/rx.h>
44 #include <rx/rx_globals.h>
45 #include <afs/nfs.h>
46 #include <afs/vlserver.h>
47 #include <afs/auth.h>
48 #include <afs/cellconfig.h>
49 #include <afs/keys.h>
50 #include <afs/afsutil.h>
51 #include <ubik.h>
52 #include <afs/afsint.h>
53 #include <afs/cmd.h>
54 #include <afs/usd.h>
55 #include <rx/rxkad.h>
56 #include "volser.h"
57 #include "volint.h"
58 #include "lockdata.h"
59 #ifdef  AFS_AIX32_ENV
60 #include <signal.h>
61 #endif
62 #include "volser_prototypes.h"
63
64 struct tqElem {
65     afs_int32 volid;
66     struct tqElem *next;
67 };
68
69 struct tqHead {
70     afs_int32 count;
71     struct tqElem *next;
72 };
73
74
75 struct hostent *hostutil_GetHostByName(register char *ahost);
76
77 #define COMMONPARMS     cmd_Seek(ts, 12);\
78 cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");\
79 cmd_AddParm(ts, "-noauth", CMD_FLAG, CMD_OPTIONAL, "don't authenticate");\
80 cmd_AddParm(ts, "-localauth",CMD_FLAG,CMD_OPTIONAL,"use server tickets");\
81 cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, "verbose");\
82 cmd_AddParm(ts, "-encrypt", CMD_FLAG, CMD_OPTIONAL, "encrypt commands");\
83
84 #define ERROR_EXIT(code) {error=(code); goto error_exit;}
85
86 extern int verbose;
87 int rxInitDone = 0;
88 struct rx_connection *tconn;
89 afs_int32 tserver;
90 extern struct ubik_client *cstruct;
91 const char *confdir;
92 extern struct rx_connection *UV_Bind();
93 extern int UV_SetSecurity();
94 extern int UV_SetVolumeInfo();
95 extern int vsu_SetCrypt();
96 extern VL_SetLock();
97 extern VL_ReleaseLock();
98 extern VL_DeleteEntry();
99 extern VL_ListEntry();
100 extern VL_GetAddrs();
101 extern VL_GetAddrsU();
102 extern VL_ChangeAddr();
103
104 extern int vsu_ExtractName();
105 extern PrintError();
106 extern void EnumerateEntry();
107 extern void SubEnumerateEntry();
108
109
110 static struct tqHead busyHead, notokHead;
111
112 static void qInit(ahead)
113 struct tqHead *ahead;
114 {
115     memset((char *)ahead, 0, sizeof(struct tqHead));
116     return;
117 }
118
119
120 static void qPut(ahead,volid)
121 struct tqHead *ahead;
122 afs_int32 volid;
123 {
124     struct tqElem *elem;
125
126     elem = (struct tqElem *)malloc(sizeof(struct tqElem));
127     elem->next = ahead->next;
128     elem->volid = volid;
129     ahead->next = elem;
130     ahead->count++;
131     return;
132 }
133
134 static void qGet(ahead,volid)
135 struct tqHead *ahead;
136 afs_int32 *volid;
137 {
138     struct tqElem *tmp;
139
140     if(ahead->count <= 0) return;
141     *volid = ahead->next->volid;
142     tmp = ahead->next;
143     ahead->next = tmp->next;
144     ahead->count--;
145     free(tmp);
146     return;
147 }
148
149 /* returns 1 if <filename> exists else 0 */
150 static FileExists(filename)
151 char *filename;
152 {
153     usd_handle_t ufd;
154     int code;
155     afs_hyper_t size;
156
157     code = usd_Open(filename, USD_OPEN_RDONLY, 0, &ufd);
158     if (code) {
159         return 0;
160     }
161     code = USD_IOCTL(ufd, USD_IOCTL_GETSIZE, &size);
162     USD_CLOSE(ufd);
163     if (code) {
164         return 0;
165     }
166     return 1;
167 }
168
169 /* returns 1 if <name> doesnot end in .readonly or .backup, else 0 */
170 static VolNameOK(name)
171 char *name;
172 {   
173     int total;
174
175     
176     total = strlen(name);
177     if(!strcmp(&name[total - 9],".readonly")) {
178         return 0;
179     }
180     else if(!strcmp(&name[total - 7 ],".backup")) {
181         return 0;
182     }
183     else {
184         return 1;
185     }
186 }
187
188 /* return 1 if name is a number else 0 */
189 static IsNumeric(name)
190 char *name;
191 {
192     int result, len,i;
193     char *ptr;
194
195     result = 1;
196     ptr = name;
197     len = strlen(name);
198     for(i = 0; i < len ; i++){
199         if(*ptr < '0' || *ptr > '9'){
200             result = 0;
201             break;
202         }
203         ptr++;
204         
205     }
206     return result;
207         
208
209 }
210
211
212 /*
213  * Parse a server name/address and return the address in HOST BYTE order
214  */
215 afs_int32 GetServer(aname)
216 char *aname; {
217     register struct hostent *th;
218     afs_int32 addr;
219     int b1, b2, b3, b4;
220     register afs_int32 code;
221     char hostname[MAXHOSTCHARS];
222
223     code = sscanf(aname, "%d.%d.%d.%d", &b1, &b2, &b3, &b4);
224     if (code == 4) {
225         addr = (b1<<24) | (b2<<16) | (b3<<8) | b4;
226         addr = ntohl(addr); /* convert to host order */
227     } else {
228         th = gethostbyname(aname);
229         if (!th) return 0;
230         memcpy(&addr, th->h_addr, sizeof(addr));
231     }
232
233     if (addr == htonl(0x7f000001)) {                /* local host */
234        code = gethostname(hostname, MAXHOSTCHARS);
235        if (code) return 0;
236        th = gethostbyname(hostname); /* returns host byte order */
237        if (!th) return 0;
238        memcpy(&addr, th->h_addr, sizeof(addr));
239     }
240
241     return (addr); 
242 }
243
244 afs_int32 GetVolumeType(aname)
245 char *aname;
246 {
247
248     if(!strcmp(aname,"ro"))
249         return(ROVOL);
250     else if(!strcmp(aname, "rw"))
251         return(RWVOL);
252     else if(!strcmp(aname,"bk"))
253         return(BACKVOL);
254     else return(-1);
255 }
256
257 int IsPartValid(partId, server, code)
258 afs_int32 server, partId,*code;
259
260 {   
261     struct partList dummyPartList;
262     int i,success, cnt;
263     
264
265     
266     success = 0;
267     *code = 0;
268
269     *code = UV_ListPartitions(server,&dummyPartList, &cnt);
270     if(*code) return success;
271     for(i = 0 ; i < cnt ; i++) {
272         if(dummyPartList.partFlags[i] & PARTVALID)
273             if(dummyPartList.partId[i] == partId)
274                 success = 1;
275     }
276     return success;
277 }
278
279
280
281  /*sends the contents of file associated with <fd> and <blksize>  to Rx Stream 
282 * associated  with <call> */
283 SendFile(ufd, call, blksize)
284 usd_handle_t ufd;
285 register struct rx_call *call;
286 long blksize;
287 {
288     char *buffer = (char*) 0;
289     afs_int32 error = 0;
290     int done = 0;
291     afs_uint32 nbytes;
292
293     buffer = (char *)malloc(blksize);
294     if (!buffer) {
295         fprintf(STDERR,"malloc failed\n");
296         return -1;
297     }
298
299     while (!error && !done) {
300 #ifndef AFS_NT40_ENV  /* NT csn't select on non-socket fd's */
301         fd_set in;
302         FD_ZERO(&in);
303         FD_SET((int)(ufd->handle), &in);
304         /* don't timeout if read blocks */
305         IOMGR_Select(((int)(ufd->handle))+1, &in, 0, 0, 0);
306 #endif
307         error = USD_READ(ufd, buffer, blksize, &nbytes);
308         if (error) {
309             fprintf(STDERR, "File system read failed\n");
310             break;
311         }
312         if(nbytes == 0){
313             done = 1;
314             break;
315         }
316         if (rx_Write(call, buffer, nbytes) != nbytes){
317             error = -1;
318             break;
319         }
320     }
321     if (buffer) free(buffer);
322     return error;
323 }
324
325 /* function invoked by UV_RestoreVolume, reads the data from rx_trx_stream and
326  * writes it out to the volume. */
327 afs_int32 WriteData(call,rock)
328 struct rx_call *call;
329 char *rock;
330 {
331     char *filename;
332     usd_handle_t ufd;
333     long blksize;
334     afs_int32 error,code;
335     int ufdIsOpen = 0;
336
337     error = 0;
338
339     filename = rock;
340     if(!filename || !*filename) {
341         usd_StandardInput(&ufd);
342         blksize = 4096;
343         ufdIsOpen = 1;
344     } else {
345         code = usd_Open(filename, USD_OPEN_RDONLY, 0, &ufd);
346         if (code == 0) {
347             ufdIsOpen = 1;
348             code = USD_IOCTL(ufd, USD_IOCTL_GETBLKSIZE, &blksize);
349         }
350         if (code){
351             fprintf(STDERR,"Could not access file '%s'\n", filename);
352             error = VOLSERBADOP;
353             goto wfail;
354         }
355     }
356     code = SendFile(ufd,call,blksize);
357     if(code) {
358         error = code;
359         goto wfail;
360     }
361   wfail:
362     if(ufdIsOpen) {
363         code = USD_CLOSE(ufd);
364         if(code){
365             fprintf(STDERR,"Could not close dump file %s\n",
366                     (filename && *filename)?filename:"STDOUT");
367             if(!error) error = code;
368         }
369     }
370     return error;
371 }
372
373 /* Receive data from <call> stream into file associated
374  * with <fd> <blksize>
375  */
376 int ReceiveFile(ufd, call, blksize)
377     usd_handle_t ufd;
378     struct rx_call *call;
379     long blksize;
380 {
381     char *buffer = NULL;
382     afs_int32  bytesread;
383     afs_uint32  bytesleft, w;
384     afs_int32 error = 0;
385
386     buffer = (char *)malloc(blksize);
387     if (!buffer) {
388        fprintf(STDERR,"memory allocation failed\n");
389        ERROR_EXIT(-1);
390     }
391
392     while ((bytesread=rx_Read(call,buffer,blksize)) > 0) {
393        for (bytesleft=bytesread; bytesleft; bytesleft-=w) {
394 #ifndef AFS_NT40_ENV  /* NT csn't select on non-socket fd's */
395           fd_set out;
396           FD_ZERO(&out);
397           FD_SET((int)(ufd->handle), &out);
398           /* don't timeout if write blocks */
399           IOMGR_Select(((int)(ufd->handle))+1, 0, &out, 0, 0);
400 #endif
401           error = USD_WRITE(ufd, &buffer[bytesread-bytesleft], bytesleft, &w);
402           if (error) {
403              fprintf(STDERR,"File system write failed\n");
404              ERROR_EXIT(-1);
405           }
406        }
407     }
408
409   error_exit:
410     if (buffer) free(buffer);
411     return(error);
412 }
413
414 afs_int32 DumpFunction(call, filename)
415     struct rx_call *call;
416     char *filename;
417 {
418     usd_handle_t ufd;             /* default is to stdout */
419     afs_int32 error=0, code;
420     afs_hyper_t size;
421     long blksize;
422     int ufdIsOpen = 0;
423
424     /* Open the output file */
425     if (!filename || !*filename) {
426         usd_StandardOutput(&ufd);
427         blksize = 4096;
428         ufdIsOpen = 1;
429     } else {
430         code = usd_Open(filename, USD_OPEN_CREATE|USD_OPEN_RDWR, 0666, &ufd);
431         if (code == 0) {
432             ufdIsOpen = 1;
433             hzero(size);
434             code = USD_IOCTL(ufd, USD_IOCTL_SETSIZE, &size);
435         }
436         if (code == 0) {
437             code = USD_IOCTL(ufd, USD_IOCTL_GETBLKSIZE, &blksize);
438         }
439         if (code){
440             fprintf(STDERR, "Could not create file '%s'\n", filename);
441             ERROR_EXIT(VOLSERBADOP);
442         }
443     }
444
445     code = ReceiveFile(ufd, call, blksize);
446     if (code) ERROR_EXIT(code);
447
448   error_exit:
449     /* Close the output file */
450     if (ufdIsOpen) {
451        code = USD_CLOSE(ufd);
452        if (code) {
453           fprintf(STDERR,"Could not close dump file %s\n",
454                   (filename && *filename)?filename:"STDIN");
455           if (!error) error = code;
456        }
457     }
458
459     return(error);
460 }   
461     
462 static void DisplayFormat(pntr,server,part,totalOK,totalNotOK,totalBusy,fast,longlist,disp)
463 volintInfo *pntr;
464 afs_int32 server,part;
465 int *totalOK,*totalNotOK,*totalBusy;
466 int fast,longlist, disp;
467 {
468     char pname[10];
469
470     if(fast){
471         fprintf(STDOUT,"%-10lu\n", (unsigned long) pntr->volid);
472     }
473     else if(longlist){
474         if(pntr->status == VOK){
475             fprintf(STDOUT,"%-32s ",pntr->name);
476             fprintf(STDOUT,"%10lu ", (unsigned long) pntr->volid);
477             if(pntr->type == 0) fprintf(STDOUT,"RW ");
478             if(pntr->type == 1) fprintf(STDOUT,"RO ");
479             if(pntr->type == 2) fprintf(STDOUT,"BK ");
480             fprintf(STDOUT,"%10d K  ",pntr->size);
481             if(pntr->inUse == 1) {
482                 fprintf(STDOUT,"On-line");
483                 *totalOK += 1;
484             } else {
485                 fprintf(STDOUT,"Off-line");
486                 *totalNotOK++;
487             }
488             if(pntr->needsSalvaged == 1) fprintf(STDOUT,"**needs salvage**");
489             fprintf(STDOUT,"\n");
490             MapPartIdIntoName(part,pname);
491             fprintf(STDOUT,"    %s %s \n",hostutil_GetNameByINet(server),pname);
492             fprintf(STDOUT,"    RWrite %10lu ROnly %10lu Backup %10lu \n",
493                     (unsigned long) pntr->parentID,
494                     (unsigned long) pntr->cloneID,
495                     (unsigned long) pntr->backupID);
496             fprintf(STDOUT,"    MaxQuota %10d K \n",pntr->maxquota);
497             fprintf(STDOUT,"    Creation    %s",
498                     ctime((time_t *)&pntr->creationDate));
499 #ifdef FULL_LISTVOL_SWITCH
500             fprintf(STDOUT,"    Copy        %s",
501                     ctime((time_t *)&pntr->copyDate));
502             if(!pntr->backupDate)
503               fprintf(STDOUT,"    Backup      Never\n");
504             else
505               fprintf(STDOUT,"    Backup      %s",
506                       ctime((time_t *)&pntr->backupDate));
507             if (pntr->accessDate)
508               fprintf(STDOUT,"    Last Access %s",
509                       ctime((time_t *)&pntr->accessDate));
510 #endif
511             if(pntr->updateDate < pntr->creationDate)
512                 fprintf(STDOUT,"    Last Update %s",
513                         ctime((time_t *)&pntr->creationDate));
514             else
515                 fprintf(STDOUT,"    Last Update %s",
516                         ctime((time_t *)&pntr->updateDate));
517             fprintf(STDOUT, "    %d accesses in the past day (i.e., vnode references)\n",
518                     pntr->dayUse);
519         }
520         else if (pntr->status == VBUSY) {
521             *totalBusy += 1;
522             qPut(&busyHead,pntr->volid);
523             if (disp) fprintf(STDOUT,"**** Volume %lu is busy ****\n",
524                               (unsigned long) pntr->volid);
525         }
526         else {
527             *totalNotOK += 1;
528             qPut(&notokHead,pntr->volid);
529             if (disp) fprintf(STDOUT,"**** Could not attach volume %lu ****\n",
530                               (unsigned long) pntr->volid);
531         }
532         fprintf(STDOUT,"\n");
533     }
534     else {/* default listing */
535         if(pntr->status == VOK){
536             fprintf(STDOUT,"%-32s ",pntr->name);
537             fprintf(STDOUT,"%10lu ",(unsigned long) pntr->volid);
538             if(pntr->type == 0) fprintf(STDOUT,"RW ");
539             if(pntr->type == 1) fprintf(STDOUT,"RO ");
540             if(pntr->type == 2) fprintf(STDOUT,"BK ");
541             fprintf(STDOUT,"%10d K ",pntr->size);
542             if(pntr->inUse == 1) {
543                 fprintf(STDOUT,"On-line");
544                 *totalOK += 1;
545             } else {
546                 fprintf(STDOUT,"Off-line");
547                 *totalNotOK += 1;
548             }
549             if(pntr->needsSalvaged == 1) fprintf(STDOUT,"**needs salvage**");
550             fprintf(STDOUT,"\n");
551         }
552         else if (pntr->status == VBUSY) {
553             *totalBusy += 1;
554             qPut(&busyHead,pntr->volid);
555             if (disp) fprintf(STDOUT,"**** Volume %lu is busy ****\n",
556                               (unsigned long) pntr->volid);
557         }
558         else {
559             *totalNotOK += 1;
560             qPut(&notokHead,pntr->volid);
561             if (disp) fprintf(STDOUT,"**** Could not attach volume %lu ****\n",
562                               (unsigned long) pntr->volid);
563         }
564     }
565 }
566
567 /*------------------------------------------------------------------------
568  * PRIVATE XDisplayFormat
569  *
570  * Description:
571  *      Display the contents of one extended volume info structure.
572  *
573  * Arguments:
574  *      a_xInfoP        : Ptr to extended volume info struct to print.
575  *      a_servID        : Server ID to print.
576  *      a_partID        : Partition ID to print.
577  *      a_totalOKP      : Ptr to total-OK counter.
578  *      a_totalNotOKP   : Ptr to total-screwed counter.
579  *      a_totalBusyP    : Ptr to total-busy counter.
580  *      a_fast          : Fast listing?
581  *      a_int32         : Int32 listing?
582  *      a_showProblems  : Show volume problems?
583  *
584  * Returns:
585  *      Nothing.
586  *
587  * Environment:
588  *      Nothing interesting.
589  *
590  * Side Effects:
591  *      As advertised.
592  *------------------------------------------------------------------------*/
593
594 static void XDisplayFormat(a_xInfoP, a_servID, a_partID, a_totalOKP,
595                            a_totalNotOKP, a_totalBusyP, a_fast, a_int32,
596                            a_showProblems)
597     volintXInfo *a_xInfoP;
598     afs_int32 a_servID;
599     afs_int32 a_partID;
600     int *a_totalOKP;
601     int *a_totalNotOKP;
602     int *a_totalBusyP;
603     int a_fast;
604     int a_int32;
605     int a_showProblems;
606
607 { /*XDisplayFormat*/
608
609     char pname[10];
610
611     if (a_fast) {
612         /*
613          * Short & sweet.
614          */
615         fprintf(STDOUT, "%-10lu\n", (unsigned long) a_xInfoP->volid);
616     }
617     else
618         if (a_int32) {
619             /*
620              * Fully-detailed listing.
621              */
622             if (a_xInfoP->status == VOK) {
623                 /*
624                  * Volume's status is OK - all the fields are valid.
625                  */
626                 fprintf(STDOUT, "%-32s ", a_xInfoP->name);
627                 fprintf(STDOUT, "%10lu ",  (unsigned long) a_xInfoP->volid);
628                 if (a_xInfoP->type == 0) fprintf(STDOUT,"RW ");
629                 if (a_xInfoP->type == 1) fprintf(STDOUT,"RO ");
630                 if (a_xInfoP->type == 2) fprintf(STDOUT,"BK ");
631                 fprintf(STDOUT, "%10d K used ", a_xInfoP->size);
632                 fprintf(STDOUT, "%d files ", a_xInfoP->filecount);
633                 if(a_xInfoP->inUse == 1) {
634                     fprintf(STDOUT, "On-line");
635                     (*a_totalOKP)++;
636                 }
637                 else {
638                     fprintf(STDOUT, "Off-line");
639                     (*a_totalNotOKP)++;
640                 }
641                 fprintf(STDOUT, "\n");
642                 MapPartIdIntoName(a_partID, pname);
643                 fprintf(STDOUT, "    %s %s \n",
644                         hostutil_GetNameByINet(a_servID),
645                         pname);
646                 fprintf(STDOUT, "    RWrite %10lu ROnly %10lu Backup %10lu \n",
647                         (unsigned long) a_xInfoP->parentID,
648                         (unsigned long) a_xInfoP->cloneID,
649                         (unsigned long) a_xInfoP->backupID);
650                 fprintf(STDOUT, "    MaxQuota %10d K \n",
651                         a_xInfoP->maxquota);
652                 fprintf(STDOUT, "    Creation    %s",
653                         ctime((time_t *)&a_xInfoP->creationDate));
654 #ifdef FULL_LISTVOL_SWITCH
655                 fprintf(STDOUT,"    Copy        %s",
656                         ctime((time_t *)&a_xInfoP->copyDate));
657                 if(!a_xInfoP->backupDate)
658                     fprintf(STDOUT,"    Backup      Never\n");
659                 else
660                     fprintf(STDOUT,"    Backup      %s",
661                             ctime((time_t *)&a_xInfoP->backupDate));
662                 if (a_xInfoP->accessDate)
663                     fprintf(STDOUT,"    Last Access %s",
664                             ctime((time_t *)&a_xInfoP->accessDate));
665 #endif
666                 if (a_xInfoP->updateDate < a_xInfoP->creationDate)
667                     fprintf(STDOUT, "    Last Update %s",
668                             ctime((time_t *)&a_xInfoP->creationDate));
669                 else
670                     fprintf(STDOUT, "    Last Update %s",
671                             ctime((time_t *)&a_xInfoP->updateDate));
672                 fprintf(STDOUT, "    %d accesses in the past day (i.e., vnode references)\n",
673                         a_xInfoP->dayUse);
674
675                 /*
676                  * Print all the read/write and authorship stats.
677                  */
678                 fprintf(STDOUT,
679                         "\n                      Raw Read/Write Stats\n");
680                 fprintf(STDOUT,
681                         "          |-------------------------------------------|\n");
682                 fprintf(STDOUT,
683                         "          |    Same Network     |    Diff Network     |\n");
684                 fprintf(STDOUT,
685                         "          |----------|----------|----------|----------|\n");
686                 fprintf(STDOUT,
687                         "          |  Total   |   Auth   |   Total  |   Auth   |\n");
688                 fprintf(STDOUT,
689                         "          |----------|----------|----------|----------|\n");
690                 fprintf(STDOUT,
691                         "Reads     | %8d | %8d | %8d | %8d |\n",
692                         a_xInfoP->stat_reads[VOLINT_STATS_SAME_NET],
693                         a_xInfoP->stat_reads[VOLINT_STATS_SAME_NET_AUTH],
694                         a_xInfoP->stat_reads[VOLINT_STATS_DIFF_NET],
695                         a_xInfoP->stat_reads[VOLINT_STATS_DIFF_NET_AUTH]);
696                 fprintf(STDOUT,
697                         "Writes    | %8d | %8d | %8d | %8d |\n",
698                         a_xInfoP->stat_writes[VOLINT_STATS_SAME_NET],
699                         a_xInfoP->stat_writes[VOLINT_STATS_SAME_NET_AUTH],
700                         a_xInfoP->stat_writes[VOLINT_STATS_DIFF_NET],
701                         a_xInfoP->stat_writes[VOLINT_STATS_DIFF_NET_AUTH]);
702                 fprintf(STDOUT,
703                         "          |-------------------------------------------|\n\n");
704
705                 fprintf(STDOUT,
706                         "                   Writes Affecting Authorship\n");
707                 fprintf(STDOUT,
708                         "          |-------------------------------------------|\n");
709                 fprintf(STDOUT,
710                         "          |   File Authorship   | Directory Authorship|\n");
711                 fprintf(STDOUT,
712                         "          |----------|----------|----------|----------|\n");
713                 fprintf(STDOUT,
714                         "          |   Same   |   Diff   |    Same  |   Diff   |\n");
715                 fprintf(STDOUT,
716                         "          |----------|----------|----------|----------|\n");
717                 fprintf(STDOUT,
718                         "0-60 sec  | %8d | %8d | %8d | %8d |\n",
719                         a_xInfoP->stat_fileSameAuthor[VOLINT_STATS_TIME_IDX_0],
720                         a_xInfoP->stat_fileDiffAuthor[VOLINT_STATS_TIME_IDX_0],
721                         a_xInfoP->stat_dirSameAuthor[VOLINT_STATS_TIME_IDX_0],
722                         a_xInfoP->stat_dirDiffAuthor[VOLINT_STATS_TIME_IDX_0]);
723                 fprintf(STDOUT,
724                         "1-10 min  | %8d | %8d | %8d | %8d |\n",
725                         a_xInfoP->stat_fileSameAuthor[VOLINT_STATS_TIME_IDX_1],
726                         a_xInfoP->stat_fileDiffAuthor[VOLINT_STATS_TIME_IDX_1],
727                         a_xInfoP->stat_dirSameAuthor[VOLINT_STATS_TIME_IDX_1],
728                         a_xInfoP->stat_dirDiffAuthor[VOLINT_STATS_TIME_IDX_1]);
729                 fprintf(STDOUT,
730                         "10min-1hr | %8d | %8d | %8d | %8d |\n",
731                         a_xInfoP->stat_fileSameAuthor[VOLINT_STATS_TIME_IDX_2],
732                         a_xInfoP->stat_fileDiffAuthor[VOLINT_STATS_TIME_IDX_2],
733                         a_xInfoP->stat_dirSameAuthor[VOLINT_STATS_TIME_IDX_2],
734                         a_xInfoP->stat_dirDiffAuthor[VOLINT_STATS_TIME_IDX_2]);
735                 fprintf(STDOUT,
736                         "1hr-1day  | %8d | %8d | %8d | %8d |\n",
737                         a_xInfoP->stat_fileSameAuthor[VOLINT_STATS_TIME_IDX_3],
738                         a_xInfoP->stat_fileDiffAuthor[VOLINT_STATS_TIME_IDX_3],
739                         a_xInfoP->stat_dirSameAuthor[VOLINT_STATS_TIME_IDX_3],
740                         a_xInfoP->stat_dirDiffAuthor[VOLINT_STATS_TIME_IDX_3]);
741                 fprintf(STDOUT,
742                         "1day-1wk  | %8d | %8d | %8d | %8d |\n",
743                         a_xInfoP->stat_fileSameAuthor[VOLINT_STATS_TIME_IDX_4],
744                         a_xInfoP->stat_fileDiffAuthor[VOLINT_STATS_TIME_IDX_4],
745                         a_xInfoP->stat_dirSameAuthor[VOLINT_STATS_TIME_IDX_4],
746                         a_xInfoP->stat_dirDiffAuthor[VOLINT_STATS_TIME_IDX_4]);
747                 fprintf(STDOUT,
748                         "> 1wk     | %8d | %8d | %8d | %8d |\n",
749                         a_xInfoP->stat_fileSameAuthor[VOLINT_STATS_TIME_IDX_5],
750                         a_xInfoP->stat_fileDiffAuthor[VOLINT_STATS_TIME_IDX_5],
751                         a_xInfoP->stat_dirSameAuthor[VOLINT_STATS_TIME_IDX_5],
752                         a_xInfoP->stat_dirDiffAuthor[VOLINT_STATS_TIME_IDX_5]);
753                 fprintf(STDOUT,
754                         "          |-------------------------------------------|\n");
755             } /*Volume status OK*/
756             else
757                 if (a_xInfoP->status == VBUSY) {
758                     (*a_totalBusyP)++;
759                     qPut(&busyHead, a_xInfoP->volid);
760                     if (a_showProblems)
761                         fprintf(STDOUT, "**** Volume %lu is busy ****\n",
762                                 (unsigned long) a_xInfoP->volid);
763                 } /*Busy volume*/
764                 else {
765                     (*a_totalNotOKP)++;
766                     qPut(&notokHead, a_xInfoP->volid);
767                     if (a_showProblems)
768                         fprintf(STDOUT, "**** Could not attach volume %lu ****\n",
769                                 (unsigned long) a_xInfoP->volid);
770                 } /*Screwed volume*/
771             fprintf(STDOUT,"\n");
772         } /*Long listing*/
773         else {
774             /*
775              * Default listing.
776              */
777             if (a_xInfoP->status == VOK) {
778                 fprintf(STDOUT, "%-32s ", a_xInfoP->name);
779                 fprintf(STDOUT, "%10lu ", (unsigned long) a_xInfoP->volid);
780                 if (a_xInfoP->type == 0) fprintf(STDOUT, "RW ");
781                 if (a_xInfoP->type == 1) fprintf(STDOUT, "RO ");
782                 if (a_xInfoP->type == 2) fprintf(STDOUT, "BK ");
783                 fprintf(STDOUT, "%10d K ", a_xInfoP->size);
784                 if(a_xInfoP->inUse == 1) {
785                     fprintf(STDOUT, "On-line");
786                     (*a_totalOKP)++;
787                 } else {
788                     fprintf(STDOUT, "Off-line");
789                     (*a_totalNotOKP)++;
790                 }
791                 fprintf(STDOUT, "\n");
792             } /*Volume OK*/
793             else
794                 if (a_xInfoP->status == VBUSY) {
795                     (*a_totalBusyP)++;
796                     qPut(&busyHead, a_xInfoP->volid);
797                     if (a_showProblems)
798                         fprintf(STDOUT,"**** Volume %lu is busy ****\n",
799                                 (unsigned long) a_xInfoP->volid);
800                 } /*Busy volume*/
801                 else {
802                     (*a_totalNotOKP)++;
803                     qPut(&notokHead, a_xInfoP->volid);
804                     if (a_showProblems)
805                         fprintf(STDOUT,"**** Could not attach volume %lu ****\n",
806                                 (unsigned long) a_xInfoP->volid);
807                 } /*Screwed volume*/
808         } /*Default listing*/
809 } /*XDisplayFormat*/
810
811 #ifdef FULL_LISTVOL_SWITCH
812 static void  DisplayFormat2(server, partition, pntr)
813     long    server, partition;
814     volintInfo *pntr;
815 {
816   static long server_cache = -1, partition_cache = -1;
817   static char hostname[256],
818   address[32],
819   pname[16];
820
821   if (server != server_cache) {
822     struct in_addr s;
823     
824     s.s_addr = server;
825     strcpy(hostname, hostutil_GetNameByINet(server));
826     strcpy(address, inet_ntoa(s));
827     server_cache = server;
828   }
829   if (partition != partition_cache) {
830     MapPartIdIntoName(partition, pname);
831     partition_cache = partition;
832   }
833   fprintf(STDOUT, "name\t\t%s\n", pntr->name);
834   fprintf(STDOUT, "id\t\t%lu\n", pntr->volid);
835   fprintf(STDOUT, "serv\t\t%s\t%s\n", address, hostname);
836   fprintf(STDOUT, "part\t\t%s\n", pname);
837   switch (pntr->status) {
838   case VOK:
839     fprintf(STDOUT, "status\t\tOK\n");
840     break;
841   case VBUSY:
842     fprintf(STDOUT, "status\t\tBUSY\n");
843     return;
844   default:
845     fprintf(STDOUT, "status\t\tUNATTACHABLE\n");
846     return;
847   }
848   fprintf(STDOUT, "backupID\t%lu\n", pntr->backupID);
849   fprintf(STDOUT, "parentID\t%lu\n", pntr->parentID);
850   fprintf(STDOUT, "cloneID\t\t%lu\n", pntr->cloneID);
851   fprintf(STDOUT, "inUse\t\t%s\n", pntr->inUse ? "Y" : "N");
852   fprintf(STDOUT, "needsSalvaged\t%s\n", pntr->needsSalvaged ? "Y" : "N");
853   /* 0xD3 is from afs/volume.h since I had trouble including the file */
854   fprintf(STDOUT, "destroyMe\t%s\n", pntr->destroyMe == 0xD3 ? "Y" : "N");
855   switch (pntr->type) {
856   case 0:
857     fprintf(STDOUT, "type\t\tRW\n");
858     break;
859   case 1:
860     fprintf(STDOUT, "type\t\tRO\n");
861     break;
862   case 2:
863     fprintf(STDOUT, "type\t\tBK\n");
864     break;
865   default:
866     fprintf(STDOUT, "type\t\t?\n");
867     break;
868   }
869   fprintf(STDOUT, "creationDate\t%-9lu\t%s", pntr->creationDate, ctime(&pntr->creationDate));
870   fprintf(STDOUT, "accessDate\t%-9lu\t%s", pntr->accessDate, ctime(&pntr->accessDate));
871   fprintf(STDOUT, "updateDate\t%-9lu\t%s", pntr->updateDate, ctime(&pntr->updateDate));
872   fprintf(STDOUT, "backupDate\t%-9lu\t%s", pntr->backupDate, ctime(&pntr->backupDate));
873   fprintf(STDOUT, "copyDate\t%-9lu\t%s", pntr->copyDate, ctime(&pntr->copyDate));
874   fprintf(STDOUT, "flags\t\t%#lx\t(Optional)\n", pntr->flags);
875   fprintf(STDOUT, "diskused\t%u\n", pntr->size);
876   fprintf(STDOUT, "maxquota\t%u\n", pntr->maxquota);
877   fprintf(STDOUT, "minquota\t%lu\t(Optional)\n", pntr->spare0);
878   fprintf(STDOUT, "filecount\t%u\n", pntr->filecount);
879   fprintf(STDOUT, "dayUse\t\t%u\n", pntr->dayUse);
880   fprintf(STDOUT, "weekUse\t\t%lu\t(Optional)\n", pntr->spare1);
881   fprintf(STDOUT, "spare2\t\t%lu\t(Optional)\n", pntr->spare2);
882   fprintf(STDOUT, "spare3\t\t%lu\t(Optional)\n", pntr->spare3);
883   return;
884 }
885
886 static void DisplayVolumes2(server, partition, pntr, count)
887     volintInfo *pntr;
888     long    server, partition, count;
889 {
890   long    i;
891   
892   for (i = 0; i < count; i++) {
893     fprintf(STDOUT, "BEGIN_OF_ENTRY\n");
894     DisplayFormat2(server, partition, pntr);
895     fprintf(STDOUT, "END_OF_ENTRY\n\n");
896     pntr++;
897   }
898   return;
899 }
900 #endif /* FULL_LISTVOL_SWITCH */
901
902 static void DisplayVolumes(server,part,pntr,count,longlist,fast,quiet)
903 afs_int32 server,part;
904 volintInfo *pntr;
905 afs_int32 count,longlist,fast;
906 int quiet;
907 {
908     int totalOK,totalNotOK,totalBusy, i;
909     afs_int32 volid;
910
911     totalOK = 0;
912     totalNotOK = 0;
913     totalBusy = 0;
914     qInit(&busyHead);
915     qInit(&notokHead);
916     for(i = 0; i < count; i++){
917         DisplayFormat(pntr,server,part,&totalOK,&totalNotOK,&totalBusy,fast,longlist,0);
918         pntr++;
919     }
920     if(totalBusy){
921         while(busyHead.count){
922             qGet(&busyHead,&volid);
923             fprintf(STDOUT,"**** Volume %lu is busy ****\n",
924                     (unsigned long) volid);
925         }
926     }
927     if(totalNotOK){
928         while(notokHead.count){
929             qGet(&notokHead,&volid);
930             fprintf(STDOUT,"**** Could not attach volume %lu ****\n",
931                     (unsigned long) volid);
932         }
933     }
934     if(!quiet){
935         fprintf(STDOUT,"\n");
936         if(!fast){
937             fprintf(STDOUT,"Total volumes onLine %d ; Total volumes offLine %d ; Total busy %d\n\n",totalOK,totalNotOK,totalBusy);
938         }
939     }
940 }
941
942 /*------------------------------------------------------------------------
943  * PRIVATE XDisplayVolumes
944  *
945  * Description:
946  *      Display extended volume information.
947  *
948  * Arguments:
949  *      a_servID : Pointer to the Rx call we're performing.
950  *      a_partID : Partition for which we want the extended list.
951  *      a_xInfoP : Ptr to extended volume info.
952  *      a_count  : Number of volume records contained above.
953  *      a_int32   : Int32 listing generated?
954  *      a_fast   : Fast listing generated?
955  *      a_quiet  : Quiet listing generated?
956  *
957  * Returns:
958  *      Nothing.
959  *
960  * Environment:
961  *      Nothing interesting.
962  *
963  * Side Effects:
964  *      As advertised.
965  *------------------------------------------------------------------------*/
966
967 static void XDisplayVolumes(a_servID, a_partID, a_xInfoP,
968                             a_count, a_int32, a_fast, a_quiet)
969     afs_int32 a_servID;
970     afs_int32 a_partID;
971     volintXInfo *a_xInfoP;
972     afs_int32 a_count;
973     afs_int32 a_int32;
974     afs_int32 a_fast;
975     int a_quiet;
976
977 { /*XDisplayVolumes*/
978
979     int totalOK;        /*Total OK volumes*/
980     int totalNotOK;     /*Total screwed volumes*/
981     int totalBusy;      /*Total busy volumes*/
982     int i;              /*Loop variable*/
983     afs_int32 volid;            /*Current volume ID*/
984
985     /*
986      * Initialize counters and (global!!) queues.
987      */
988     totalOK = 0;
989     totalNotOK = 0;
990     totalBusy = 0;
991     qInit(&busyHead);
992     qInit(&notokHead);
993
994     /*
995      * Display each volume in the list.
996      */
997     for(i = 0; i < a_count; i++) {
998         XDisplayFormat(a_xInfoP,
999                        a_servID,
1000                        a_partID,
1001                        &totalOK,
1002                        &totalNotOK,
1003                        &totalBusy,
1004                        a_fast,
1005                        a_int32,
1006                        0);
1007         a_xInfoP++;
1008     }
1009
1010     /*
1011      * If any volumes were found to be busy or screwed, display them.
1012      */
1013     if (totalBusy) {
1014         while (busyHead.count) {
1015             qGet(&busyHead, &volid);
1016             fprintf(STDOUT, "**** Volume %lu is busy ****\n", 
1017                     (unsigned long) volid);
1018         }
1019     }
1020     if (totalNotOK) {
1021         while (notokHead.count) {
1022             qGet(&notokHead, &volid);
1023             fprintf(STDOUT, "**** Could not attach volume %lu ****\n",
1024                     (unsigned long) volid);
1025         }
1026     }
1027
1028     if (!a_quiet) {
1029         fprintf(STDOUT, "\n");
1030         if (!a_fast) {
1031             fprintf(STDOUT,
1032                     "Total volumes: %d on-line, %d off-line, %d  busyd\n\n",
1033                     totalOK, totalNotOK, totalBusy);
1034         }
1035     }
1036
1037 } /*XDisplayVolumes*/
1038
1039 /* set <server> and <part> to the correct values depending on 
1040  * <voltype> and <entry> */
1041 static void GetServerAndPart (entry, voltype, server, part, previdx)
1042     struct nvldbentry *entry;
1043     afs_int32 *server,*part;
1044     int voltype;
1045     int *previdx;
1046 {
1047     int i, istart, vtype;
1048
1049     *server = -1;
1050     *part   = -1;
1051
1052     /* Doesn't check for non-existance of backup volume */
1053     if ((voltype == RWVOL) || (voltype == BACKVOL)) {
1054        vtype = ITSRWVOL;
1055        istart = 0;      /* seach the entire entry */
1056     } else {
1057        vtype = ITSROVOL;
1058        /* Seach from beginning of entry or pick up where we left off */
1059        istart = ((*previdx < 0) ? 0 : *previdx+1);
1060     }
1061
1062     for (i = istart; i < entry->nServers; i++) {
1063        if (entry->serverFlags[i] & vtype) {
1064           *server = entry->serverNumber[i];
1065           *part   = entry->serverPartition[i];
1066           *previdx = i;
1067           return;
1068        }
1069     }
1070
1071     /* Didn't find any, return -1 */
1072     *previdx = -1;
1073     return;
1074 }
1075
1076 static void PostVolumeStats(entry)
1077 struct nvldbentry *entry;
1078 {
1079     SubEnumerateEntry(entry);
1080     /* Check for VLOP_ALLOPERS */
1081     if (entry->flags & VLOP_ALLOPERS)
1082        fprintf(STDOUT,"    Volume is currently LOCKED  \n");
1083     return;
1084 }
1085
1086 /*------------------------------------------------------------------------
1087  * PRIVATE XVolumeStats
1088  *
1089  * Description:
1090  *      Display extended volume information.
1091  *
1092  * Arguments:
1093  *      a_xInfoP  : Ptr to extended volume info.
1094  *      a_entryP  : Ptr to the volume's VLDB entry.
1095  *      a_srvID   : Server ID.
1096  *      a_partID  : Partition ID.
1097  *      a_volType : Type of volume to print.
1098  *
1099  * Returns:
1100  *      Nothing.
1101  *
1102  * Environment:
1103  *      Nothing interesting.
1104  *
1105  * Side Effects:
1106  *      As advertised.
1107  *------------------------------------------------------------------------*/
1108
1109 static void XVolumeStats(a_xInfoP, a_entryP, a_srvID, a_partID, a_volType)
1110     volintXInfo *a_xInfoP;
1111     struct nvldbentry *a_entryP;
1112     afs_int32 a_srvID;
1113     afs_int32 a_partID;
1114     int a_volType;
1115
1116 { /*XVolumeStats*/
1117
1118     int totalOK, totalNotOK, totalBusy; /*Dummies - we don't really count here*/
1119     
1120     XDisplayFormat(a_xInfoP,            /*Ptr to extended volume info*/
1121                    a_srvID,             /*Server ID to print*/
1122                    a_partID,            /*Partition ID to print*/
1123                    &totalOK,            /*Ptr to total-OK counter*/
1124                    &totalNotOK,         /*Ptr to total-screwed counter*/
1125                    &totalBusy,          /*Ptr to total-busy counter*/
1126                    0,                   /*Don't do a fast listing*/
1127                    1,                   /*Do a long listing*/
1128                    1);                  /*Show volume problems*/
1129     return;
1130
1131 } /*XVolumeStats*/
1132
1133 static void VolumeStats(pntr,entry,server,part,voltype)
1134 volintInfo *pntr;
1135 struct nvldbentry *entry;
1136 int voltype;
1137 afs_int32 server,part;
1138 {
1139     int totalOK,totalNotOK,totalBusy;
1140     afs_int32 vcode,vcode2;
1141     
1142     DisplayFormat(pntr,server,part,&totalOK,&totalNotOK,&totalBusy,0,1,1);
1143     return;
1144 }
1145
1146 /* command to forcibly remove a volume */
1147 static NukeVolume(as)
1148 register struct cmd_syndesc *as; {
1149     register afs_int32 code;
1150     afs_int32 volID, err;
1151     afs_int32 partID;
1152     afs_int32 server;
1153     register char *tp;
1154
1155     server = GetServer(tp = as->parms[0].items->data);
1156     if (!server) {
1157         fprintf(STDERR,"vos: server '%s' not found in host table\n", tp);
1158         return 1;
1159     }
1160
1161     partID = volutil_GetPartitionID(tp = as->parms[1].items->data);
1162     if (partID == -1) {
1163         fprintf(STDERR, "vos: could not parse '%s' as a partition name", tp);
1164         return 1;
1165     }
1166
1167     volID = vsu_GetVolumeID(tp = as->parms[2].items->data, cstruct, &err);
1168     if (volID == 0) {
1169         if (err) PrintError("", err);
1170         else fprintf(STDERR, "vos: could not parse '%s' as a numeric volume ID", tp);
1171         return 1;
1172     }
1173
1174     fprintf(STDOUT, "vos: forcibly removing all traces of volume %d, please wait...", volID);
1175     fflush(STDOUT);
1176     code = UV_NukeVolume(server, partID, volID);
1177     if (code == 0)
1178         fprintf(STDOUT, "done.\n");
1179     else
1180         fprintf(STDOUT, "failed with code %d.\n", code);
1181     return code;
1182 }
1183
1184
1185 /*------------------------------------------------------------------------
1186  * PRIVATE ExamineVolume
1187  *
1188  * Description:
1189  *      Routine used to examine a single volume, contacting the VLDB as
1190  *      well as the Volume Server.
1191  *
1192  * Arguments:
1193  *      as : Ptr to parsed command line arguments.
1194  *
1195  * Returns:
1196  *      0 for a successful operation,
1197  *      Otherwise, one of the ubik or VolServer error values.
1198  *
1199  * Environment:
1200  *      Nothing interesting.
1201  *
1202  * Side Effects:
1203  *      As advertised.
1204  *------------------------------------------------------------------------
1205  */
1206 static ExamineVolume(as)
1207 register struct cmd_syndesc *as;
1208 {
1209     struct nvldbentry entry;
1210     afs_int32 vcode = 0;
1211     volintInfo *pntr = (volintInfo *)0;
1212     volintXInfo *xInfoP = (volintXInfo *)0;
1213     afs_int32 volid;
1214     afs_int32 code, err, error = 0;
1215     int voltype, foundserv = 0, foundentry = 0;
1216     afs_int32 aserver, apart;
1217     int previdx = -1;
1218     int wantExtendedInfo;               /*Do we want extended vol info?*/
1219
1220     wantExtendedInfo = (as->parms[1].items ? 1 : 0);       /* -extended */
1221
1222     volid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);    /* -id */
1223     if (volid == 0) {
1224         if (err) PrintError("", err);
1225         else fprintf(STDERR, "Unknown volume ID or name '%s'\n", as->parms[0].items->data);
1226         return -1;
1227     }
1228
1229     if (verbose) {
1230        fprintf(STDOUT, "Fetching VLDB entry for %lu .. ",
1231                (unsigned long) volid);
1232        fflush(STDOUT);
1233     }
1234     vcode = VLDB_GetEntryByID (volid, -1, &entry);
1235     if (vcode) {
1236         fprintf(STDERR, "Could not fetch the entry for volume number %lu from VLDB \n",
1237                 (unsigned long) volid);
1238         return (vcode);
1239     }
1240     if (verbose)
1241        fprintf(STDOUT, "done\n");
1242     MapHostToNetwork(&entry);
1243
1244     if (entry.volumeId[RWVOL] == volid)
1245        voltype = RWVOL;
1246     else if (entry.volumeId[BACKVOL] == volid)
1247        voltype = BACKVOL;
1248     else                          /* (entry.volumeId[ROVOL] == volid) */
1249        voltype = ROVOL;
1250
1251     do {                     /* do {...} while (voltype == ROVOL) */
1252        /* Get the entry for the volume. If its a RW vol, get the RW entry.
1253         * It its a BK vol, get the RW entry (even if VLDB may say the BK doen't exist).
1254         * If its a RO vol, get the next RO entry.
1255         */
1256        GetServerAndPart(&entry, ((voltype == ROVOL) ? ROVOL : RWVOL), &aserver, &apart, &previdx);
1257        if (previdx == -1) { /* searched all entries */
1258           if (!foundentry) {
1259              fprintf(STDERR,"Volume %s does not exist in VLDB\n\n", as->parms[0].items->data);
1260              error = ENOENT;
1261           }
1262           break;
1263        }
1264        foundentry = 1;
1265
1266        /* Get information about the volume from the server */
1267        if (verbose) {
1268           fprintf(STDOUT,"Getting volume listing from the server %s .. ",
1269                   hostutil_GetNameByINet(aserver));
1270           fflush(STDOUT);
1271        }
1272        if (wantExtendedInfo)
1273           code = UV_XListOneVolume(aserver, apart, volid, &xInfoP);
1274        else
1275           code = UV_ListOneVolume(aserver, apart, volid, &pntr);
1276        if (verbose)
1277           fprintf(STDOUT,"done\n");
1278
1279        if (code) {
1280           error = code;
1281           if (code == ENODEV) {
1282              if ((voltype == BACKVOL) && !(entry.flags & BACK_EXISTS)) {
1283                 /* The VLDB says there is no backup volume and its not on disk */
1284                 fprintf(STDERR, "Volume %s does not exist\n", as->parms[0].items->data);
1285                 error = ENOENT;
1286              } else {
1287                 fprintf(STDERR, "Volume does not exist on server %s as indicated by the VLDB\n", 
1288                         hostutil_GetNameByINet(aserver));
1289              }
1290           } else {
1291              PrintDiagnostics("examine", code);
1292           }
1293           fprintf(STDOUT, "\n");
1294        } else {
1295           foundserv = 1;
1296           if (wantExtendedInfo)
1297              XVolumeStats(xInfoP, &entry, aserver, apart, voltype);
1298           else
1299 #ifdef FULL_LISTVOL_SWITCH
1300             if (as->parms[2].items) {
1301               DisplayFormat2(aserver, apart, pntr);
1302               EnumerateEntry(&entry);
1303             } else
1304 #endif /* FULL_LISTVOL_SWITCH */
1305              VolumeStats(pntr, &entry, aserver, apart, voltype);
1306
1307           if ((voltype == BACKVOL) && !(entry.flags & BACK_EXISTS)) {
1308              /* The VLDB says there is no backup volume yet we found one on disk */
1309              fprintf(STDERR, "Volume %s does not exist in VLDB\n", as->parms[0].items->data);
1310              error = ENOENT;
1311           }
1312        }
1313
1314        if (pntr)   free(pntr);
1315        if (xInfoP) free(xInfoP);
1316     } while (voltype == ROVOL);
1317
1318     if (!foundserv) {
1319        fprintf(STDERR,"Dump only information from VLDB\n\n");           
1320        fprintf(STDOUT,"%s \n", entry.name);    /* PostVolumeStats doesn't print name */
1321     }
1322     PostVolumeStats(&entry);
1323
1324     return (error);
1325 }
1326
1327 /*------------------------------------------------------------------------
1328  * PRIVATE SetFields
1329  *
1330  * Description:
1331  *      Routine used to change the status of a single volume.
1332  *
1333  * Arguments:
1334  *      as : Ptr to parsed command line arguments.
1335  *
1336  * Returns:
1337  *      0 for a successful operation,
1338  *      Otherwise, one of the ubik or VolServer error values.
1339  *
1340  * Environment:
1341  *      Nothing interesting.
1342  *
1343  * Side Effects:
1344  *      As advertised.
1345  *------------------------------------------------------------------------
1346  */
1347 static SetFields(as)
1348 register struct cmd_syndesc *as;
1349 {
1350     struct nvldbentry entry;
1351     afs_int32 vcode = 0;
1352     volintInfo info;
1353     afs_int32 volid;
1354     afs_int32 code, err;
1355     afs_int32 aserver, apart;
1356     int previdx = -1;
1357
1358     volid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);    /* -id */
1359     if (volid == 0) {
1360         if (err) PrintError("", err);
1361         else fprintf(STDERR, "Unknown volume ID or name '%s'\n", as->parms[0].items->data);
1362         return -1;
1363     }
1364
1365     code = VLDB_GetEntryByID (volid, RWVOL, &entry);
1366     if (code) {
1367         fprintf(STDERR, "Could not fetch the entry for volume number %lu from VLDB \n",
1368                 (unsigned long) volid);
1369         return (code);
1370     }
1371     MapHostToNetwork(&entry);
1372
1373     GetServerAndPart(&entry, RWVOL, &aserver, &apart, &previdx);
1374     if (previdx == -1) {
1375         fprintf(STDERR,"Volume %s does not exist in VLDB\n\n", as->parms[0].items->data);
1376         return (ENOENT);
1377     }
1378
1379     memset(&info, 0, sizeof(info));
1380     info.volid    = volid;
1381     info.type     = RWVOL;
1382     info.dayUse   = -1;
1383     info.maxquota = -1;
1384     info.flags    = -1;
1385     info.spare0   = -1;
1386     info.spare1   = -1;
1387     info.spare2   = -1;
1388     info.spare3   = -1;
1389
1390     if (as->parms[1].items) {
1391         /* -max <quota> */
1392         code = util_GetInt32(as->parms[1].items->data, &info.maxquota);
1393         if (code) {
1394             fprintf(STDERR,"invalid quota value\n");
1395             return code;
1396         }
1397     }
1398     if (as->parms[2].items) {
1399         /* -clearuse */
1400         info.dayUse = 0;
1401     }
1402     code = UV_SetVolumeInfo(aserver, apart, volid, &info);
1403     if (code)
1404         fprintf(STDERR,"Could not update volume info fields for volume number %lu\n",
1405                 (unsigned long) volid);
1406     return (code);
1407 }
1408
1409 /*------------------------------------------------------------------------
1410  * PRIVATE volOnline
1411  *
1412  * Description:
1413  *      Brings a volume online.
1414  *
1415  * Arguments:
1416  *      as : Ptr to parsed command line arguments.
1417  *
1418  * Returns:
1419  *      0 for a successful operation,
1420  *
1421  * Environment:
1422  *      Nothing interesting.
1423  *
1424  * Side Effects:
1425  *      As advertised.
1426  *------------------------------------------------------------------------
1427  */
1428 static volOnline(as)
1429     register struct cmd_syndesc *as;
1430 {
1431     afs_int32 server, partition, volid;
1432     afs_int32 code, err=0;
1433
1434     server = GetServer(as->parms[0].items->data);
1435     if (server == 0) {
1436         fprintf(STDERR,"vos: server '%s' not found in host table\n", as->parms[0].items->data);
1437         return -1;
1438     }
1439
1440     partition = volutil_GetPartitionID(as->parms[1].items->data);
1441     if (partition < 0) {
1442         fprintf(STDERR,"vos: could not interpret partition name '%s'\n", as->parms[1].items->data);
1443         return ENOENT;
1444     }
1445
1446     volid = vsu_GetVolumeID(as->parms[2].items->data, cstruct, &err);    /* -id */
1447     if (!volid) {
1448        if (err) PrintError("", err);
1449        else fprintf(STDERR, "Unknown volume ID or name '%s'\n", as->parms[0].items->data);
1450        return -1;
1451     }
1452
1453     code = UV_SetVolume(server, partition, volid, ITOffline, 0/*online*/, 0/*sleep*/);
1454     if (code) {
1455        fprintf(STDERR, "Failed to set volume. Code = %d\n", code);
1456        return -1;
1457     }
1458
1459     return 0;
1460 }
1461
1462 /*------------------------------------------------------------------------
1463  * PRIVATE volOffline
1464  *
1465  * Description:
1466  *      Brings a volume offline.
1467  *
1468  * Arguments:
1469  *      as : Ptr to parsed command line arguments.
1470  *
1471  * Returns:
1472  *      0 for a successful operation,
1473  *
1474  * Environment:
1475  *      Nothing interesting.
1476  *
1477  * Side Effects:
1478  *      As advertised.
1479  *------------------------------------------------------------------------
1480  */
1481 static int volOffline(register struct cmd_syndesc *as)
1482 {
1483     afs_int32 server, partition, volid;
1484     afs_int32 code, err=0;
1485     afs_int32 transflag, sleeptime, transdone;
1486
1487     server = GetServer(as->parms[0].items->data);
1488     if (server == 0) {
1489         fprintf(STDERR,"vos: server '%s' not found in host table\n", as->parms[0].items->data);
1490         return -1;
1491     }
1492
1493     partition = volutil_GetPartitionID(as->parms[1].items->data);
1494     if (partition < 0) {
1495         fprintf(STDERR,"vos: could not interpret partition name '%s'\n", as->parms[1].items->data);
1496         return ENOENT;
1497     }
1498
1499     volid = vsu_GetVolumeID(as->parms[2].items->data, cstruct, &err); /* -id */
1500     if (!volid) {
1501        if (err) PrintError("", err);
1502        else fprintf(STDERR, "Unknown volume ID or name '%s'\n", as->parms[0].items->data);
1503        return -1;
1504     }
1505
1506     transflag = (as->parms[4].items ? ITBusy : ITOffline);
1507     sleeptime = (as->parms[3].items ? atol(as->parms[3].items->data) : 0);
1508     transdone = (sleeptime ? 0/*online*/ : VTOutOfService);
1509     if (as->parms[4].items && !as->parms[3].items) {
1510         fprintf(STDERR,"-sleep option must be used with -busy flag\n");
1511         return -1;
1512     }
1513
1514     code = UV_SetVolume(server, partition, volid, transflag, transdone, sleeptime);
1515     if (code) {
1516        fprintf(STDERR, "Failed to set volume. Code = %d\n", code);
1517        return -1;
1518     }
1519
1520     return 0;
1521 }
1522
1523 static int CreateVolume(register struct cmd_syndesc *as)
1524 {
1525     afs_int32 pname;
1526     char part[10];
1527     afs_int32 volid,code;
1528     struct nvldbentry entry;
1529     afs_int32 vcode;
1530     afs_int32 quota;
1531
1532     quota = 5000;
1533     tserver = GetServer(as->parms[0].items->data);
1534     if (!tserver) {
1535         fprintf(STDERR,"vos: host '%s' not found in host table\n",as->parms[0].items->data );
1536         return ENOENT;
1537     }
1538     pname = volutil_GetPartitionID(as->parms[1].items->data);
1539     if (pname < 0) {
1540         fprintf(STDERR,"vos: could not interpret partition name '%s'\n",as->parms[1].items->data );
1541         return ENOENT;
1542     }
1543     if (!IsPartValid(pname,tserver,&code)){/*check for validity of the partition */
1544         if(code) PrintError("",code);
1545         else fprintf(STDERR,"vos : partition %s does not exist on the server\n",as->parms[1].items->data);
1546         return ENOENT;
1547     }
1548     if(!ISNAMEVALID(as->parms[2].items->data)) {
1549         fprintf(STDERR,"vos: the name of the root volume %s exceeds the size limit of %d\n",as->parms[2].items->data,VOLSER_OLDMAXVOLNAME - 10);
1550         return E2BIG;
1551     }
1552     if(!VolNameOK(as->parms[2].items->data)){
1553         fprintf(STDERR,"Illegal volume name %s, should not end in .readonly or .backup\n",as->parms[2].items->data);
1554         return EINVAL;
1555     }
1556     if(IsNumeric(as->parms[2].items->data)){
1557         fprintf(STDERR,"Illegal volume name %s, should not be a number\n",as->parms[2].items->data);
1558         return EINVAL;
1559     }
1560     vcode = VLDB_GetEntryByName(as->parms[2].items->data, &entry);
1561     if(!vcode) {
1562         fprintf(STDERR,"Volume %s already exists\n",as->parms[2].items->data);
1563         PrintDiagnostics("create", code);
1564         return EEXIST;
1565     }
1566
1567     if (as->parms[3].items) {
1568        if (!IsNumeric(as->parms[3].items->data)){
1569          fprintf(STDERR,"Initial quota %s should be numeric.\n", as->parms[3].items->data);
1570          return EINVAL;
1571        }
1572
1573       code = util_GetInt32(as->parms[3].items->data, &quota);
1574       if (code) {
1575         fprintf(STDERR,"vos: bad integer specified for quota.\n");
1576         return code;
1577       }
1578     }
1579
1580     code = UV_CreateVolume2(tserver, pname,as->parms[2].items->data,
1581                             quota, 0, 0, 0, 0, &volid);
1582     if (code) {
1583         PrintDiagnostics("create", code);
1584         return code;
1585     }
1586     MapPartIdIntoName(pname, part);
1587     fprintf(STDOUT,"Volume %lu created on partition %s of %s\n",
1588             (unsigned long) volid, part,as->parms[0].items->data );
1589
1590     return 0;
1591 }
1592
1593 static afs_int32 DeleteAll(entry)
1594 struct nvldbentry *entry;
1595 {
1596     int i;
1597     afs_int32 error, code, curserver, curpart, volid;
1598
1599     MapHostToNetwork(entry);
1600     error = 0;
1601     for(i=0; i < entry->nServers; i++){
1602         curserver = entry->serverNumber[i];
1603         curpart = entry->serverPartition[i];
1604         if(entry->serverFlags[i] & ITSROVOL){
1605             volid = entry->volumeId[ROVOL];
1606         }
1607         else{
1608             volid = entry->volumeId[RWVOL];
1609         }
1610         code = UV_DeleteVolume(curserver,curpart,volid);
1611         if(code && !error)
1612             error = code;
1613     }
1614     return error;
1615 }
1616
1617 static DeleteVolume(as)
1618     struct cmd_syndesc *as;
1619 {
1620     afs_int32 err, code = 0;
1621     afs_int32 server = 0, partition = -1, volid;
1622     char pname[10];
1623     afs_int32 idx, j;
1624
1625     if (as->parms[0].items) {
1626        server = GetServer(as->parms[0].items->data);
1627        if (!server) {
1628           fprintf(STDERR,"vos: server '%s' not found in host table\n",
1629                   as->parms[0].items->data);
1630           return ENOENT;
1631        }
1632     }
1633
1634     if (as->parms[1].items) {
1635        partition = volutil_GetPartitionID(as->parms[1].items->data);
1636        if (partition < 0) {
1637           fprintf(STDERR,"vos: could not interpret partition name '%s'\n",
1638                   as->parms[1].items->data );
1639           return EINVAL;
1640        }
1641
1642        /* Check for validity of the partition */
1643        if (!IsPartValid(partition, server, &code)) {
1644           if (code) {
1645              PrintError("", code);
1646           } else {
1647              fprintf(STDERR,"vos : partition %s does not exist on the server\n",
1648                      as->parms[1].items->data);
1649           }
1650           return ENOENT;
1651        }
1652     }
1653
1654     volid = vsu_GetVolumeID(as->parms[2].items->data, cstruct, &err);
1655     if (volid == 0) {
1656         fprintf(STDERR, "Can't find volume name '%s' in VLDB\n",
1657                 as->parms[2].items->data);
1658         if (err) PrintError("", err);
1659         return ENOENT;
1660     }
1661
1662     /* If the server or partition option are not complete, try to fill
1663      * them in from the VLDB entry.
1664      */
1665     if ((partition == -1) || !server) {
1666        struct nvldbentry entry;
1667
1668        code = VLDB_GetEntryByID(volid, -1, &entry);
1669        if (code) {
1670           fprintf(STDERR,"Could not fetch the entry for volume %lu from VLDB\n",
1671                   (unsigned long) volid);
1672           PrintError("",code);
1673           return (code);
1674        }
1675        
1676        if (((volid == entry.volumeId[RWVOL])   && (entry.flags & RW_EXISTS)) ||
1677            ((volid == entry.volumeId[BACKVOL]) && (entry.flags & BACK_EXISTS)) ) {
1678           idx = Lp_GetRwIndex(&entry);
1679           if ( (idx == -1) ||
1680                (server && (server != entry.serverNumber[idx])) ||
1681                ((partition != -1) && (partition != entry.serverPartition[idx])) ) {
1682              fprintf(STDERR,"VLDB: Volume '%s' no match\n", as->parms[2].items->data);
1683              return ENOENT;
1684           }
1685        } 
1686        else if ((volid == entry.volumeId[ROVOL]) && (entry.flags & RO_EXISTS)) {
1687           for (idx=-1,j=0; j<entry.nServers; j++) {
1688              if (entry.serverFlags[j] != ITSROVOL) continue;
1689
1690              if ( ((server    ==  0) || (server    == entry.serverNumber[j])) &&
1691                   ((partition == -1) || (partition == entry.serverPartition[j])) ) {
1692                 if (idx != -1) {
1693                    fprintf(STDERR,"VLDB: Volume '%s' matches more than one RO\n",
1694                            as->parms[2].items->data);
1695                    return ENOENT;
1696                 }
1697                 idx = j;
1698              }
1699           }
1700           if (idx == -1) {
1701              fprintf(STDERR,"VLDB: Volume '%s' no match\n", as->parms[2].items->data);
1702              return ENOENT;
1703           }
1704        }
1705        else {
1706           fprintf(STDERR,"VLDB: Volume '%s' no match\n", as->parms[2].items->data);
1707           return ENOENT;
1708        }
1709
1710        server    = htonl(entry.serverNumber[idx]);
1711        partition = entry.serverPartition[idx];
1712     }
1713
1714
1715     code = UV_DeleteVolume(server, partition, volid);
1716     if (code) {
1717        PrintDiagnostics("remove", code);
1718        return code;
1719     }
1720
1721     MapPartIdIntoName(partition, pname);
1722     fprintf(STDOUT,"Volume %lu on partition %s server %s deleted\n",
1723             (unsigned long) volid, pname, hostutil_GetNameByINet(server));
1724     return 0;
1725 }
1726
1727 #define TESTM   0       /* set for move space tests, clear for production */
1728 static MoveVolume(as)
1729 register struct cmd_syndesc *as;
1730 {
1731     
1732     afs_int32 volid, fromserver, toserver, frompart, topart,code, err;
1733     char fromPartName[10], toPartName[10];
1734
1735         struct diskPartition partition;         /* for space check */
1736         volintInfo *p;
1737
1738         volid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);
1739         if (volid == 0) {
1740         if (err) PrintError("", err);
1741         else  fprintf(STDERR, "vos: can't find volume ID or name '%s'\n",
1742                     as->parms[0].items->data);
1743             return ENOENT;
1744         }
1745         fromserver = GetServer(as->parms[1].items->data);
1746         if (fromserver == 0) {
1747             fprintf(STDERR,"vos: server '%s' not found in host table\n", as->parms[1].items->data);
1748             return ENOENT;
1749         }
1750         toserver = GetServer(as->parms[3].items->data);
1751         if (toserver == 0) {
1752             fprintf(STDERR,"vos: server '%s' not found in host table\n", as->parms[3].items->data);
1753             return ENOENT;
1754         }
1755         frompart = volutil_GetPartitionID(as->parms[2].items->data);
1756         if (frompart < 0) {
1757             fprintf(STDERR,"vos: could not interpret partition name '%s'\n", as->parms[2].items->data);
1758             return EINVAL;
1759         }
1760         if (!IsPartValid(frompart,fromserver,&code)){/*check for validity of the partition */
1761             if(code) PrintError("",code);
1762             else fprintf(STDERR,"vos : partition %s does not exist on the server\n",as->parms[2].items->data);
1763             return ENOENT;
1764         }
1765         topart = volutil_GetPartitionID(as->parms[4].items->data);
1766         if (topart < 0) {
1767             fprintf(STDERR,"vos: could not interpret partition name '%s'\n",as->parms[4].items->data);
1768             return EINVAL;
1769         }
1770         if (!IsPartValid(topart,toserver,&code)){/*check for validity of the partition */
1771             if(code) PrintError("",code);
1772             else fprintf(STDERR,"vos : partition %s does not exist on the server\n",as->parms[4].items->data);
1773             return ENOENT;
1774         }
1775
1776         /*
1777                 check source partition for space to clone volume
1778         */
1779
1780         MapPartIdIntoName(topart,toPartName);
1781         MapPartIdIntoName(frompart, fromPartName);
1782
1783         /*
1784                 check target partition for space to move volume
1785         */
1786
1787         code=UV_PartitionInfo(toserver,toPartName,&partition);
1788         if(code)
1789         {
1790                 fprintf(STDERR,"vos: cannot access partition %s\n",toPartName);
1791                 exit(1);
1792         }
1793         if(TESTM)
1794                 fprintf(STDOUT,"target partition %s free space %d\n",
1795                         toPartName,partition.free);
1796
1797         p=(volintInfo *)0;
1798         code=UV_ListOneVolume(fromserver,frompart,volid,&p);
1799         if(code)
1800         {
1801                 fprintf(STDERR,"vos:cannot access volume %lu\n",
1802                         (unsigned long) volid);
1803                 free(p);
1804                 exit(1);
1805         }
1806         if(TESTM)
1807                 fprintf(STDOUT,"volume %lu size %d\n",
1808                         (unsigned long) volid,p->size);
1809         if(partition.free<=p->size)
1810         {
1811                 fprintf(STDERR,"vos: no space on target partition %s to move volume %lu\n",
1812                         toPartName,(unsigned long) volid);
1813                 free(p);
1814                 exit(1);
1815         }
1816         free(p);
1817
1818         if(TESTM)
1819         {
1820                 fprintf(STDOUT,"size test - don't do move\n");
1821                 exit(0);
1822         }
1823
1824         /* successful move still not guaranteed but shoot for it */
1825
1826         code = UV_MoveVolume(volid, fromserver, frompart, toserver, topart);
1827         if (code) {
1828             PrintDiagnostics("move", code);
1829             return code;
1830         }
1831         MapPartIdIntoName(topart,toPartName);
1832         MapPartIdIntoName(frompart, fromPartName);
1833         fprintf(STDOUT,"Volume %lu moved from %s %s to %s %s \n",
1834                 (unsigned long) volid,
1835                 as->parms[1].items->data,fromPartName,
1836                 as->parms[3].items->data,toPartName);
1837
1838     return 0;
1839 }
1840
1841 static CopyVolume(as)
1842 register struct cmd_syndesc *as;
1843 {
1844     afs_int32 volid, fromserver, toserver, frompart, topart,code, err;
1845     char fromPartName[10], toPartName[10], *tovolume;
1846     struct nvldbentry entry;
1847     struct diskPartition partition; /* for space check */
1848     volintInfo *p;
1849
1850     volid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);
1851     if (volid == 0) {
1852         if (err) PrintError("", err);
1853         else  fprintf(STDERR, "vos: can't find volume ID or name '%s'\n",
1854                       as->parms[0].items->data);
1855         return ENOENT;
1856     }
1857     fromserver = GetServer(as->parms[1].items->data);
1858     if (fromserver == 0) {
1859         fprintf(STDERR,"vos: server '%s' not found in host table\n", as->parms[1].items->data);
1860         return ENOENT;
1861     }
1862
1863     toserver = GetServer(as->parms[4].items->data);
1864     if (toserver == 0) {
1865         fprintf(STDERR,"vos: server '%s' not found in host table\n", as->parms[3].items->data);
1866         return ENOENT;
1867     }
1868
1869     tovolume = as->parms[3].items->data;
1870     if(!ISNAMEVALID(tovolume)) {
1871         fprintf(STDERR,"vos: the name of the root volume %s exceeds the size limit of %d\n",
1872                 tovolume,VOLSER_OLDMAXVOLNAME - 10);
1873         return E2BIG;
1874     }
1875     if(!VolNameOK(tovolume)){
1876         fprintf(STDERR,"Illegal volume name %s, should not end in .readonly or .backup\n",tovolume);
1877         return EINVAL;
1878     }
1879     if(IsNumeric(tovolume)){
1880         fprintf(STDERR,"Illegal volume name %s, should not be a number\n",tovolume);
1881         return EINVAL;
1882     }
1883     code = VLDB_GetEntryByName(tovolume, &entry);
1884     if(!code) {
1885         fprintf(STDERR,"Volume %s already exists\n",tovolume);
1886         PrintDiagnostics("copy", code);
1887         return EEXIST;
1888     }
1889
1890     frompart = volutil_GetPartitionID(as->parms[2].items->data);
1891     if (frompart < 0) {
1892         fprintf(STDERR,"vos: could not interpret partition name '%s'\n", as->parms[2].items->data);
1893         return EINVAL;
1894     }
1895     if (!IsPartValid(frompart,fromserver,&code)){ /*check for validity of the partition */
1896         if(code) PrintError("",code);
1897         else fprintf(STDERR,"vos : partition %s does not exist on the server\n",as->parms[2].items->data);
1898         return ENOENT;
1899     }
1900
1901     topart = volutil_GetPartitionID(as->parms[5].items->data);
1902     if (topart < 0) {
1903         fprintf(STDERR,"vos: could not interpret partition name '%s'\n",as->parms[4].items->data);
1904         return EINVAL;
1905     }
1906     if (!IsPartValid(topart,toserver,&code)){ /*check for validity of the partition */
1907         if(code) PrintError("",code);
1908         else fprintf(STDERR,"vos : partition %s does not exist on the server\n",as->parms[4].items->data);
1909         return ENOENT;
1910     }
1911
1912     /*
1913      * check source partition for space to clone volume
1914      */
1915
1916     MapPartIdIntoName(topart,toPartName);
1917     MapPartIdIntoName(frompart, fromPartName);
1918
1919     /*
1920      * check target partition for space to move volume
1921      */
1922
1923     code=UV_PartitionInfo(toserver,toPartName,&partition);
1924     if(code)
1925     {
1926         fprintf(STDERR,"vos: cannot access partition %s\n",toPartName);
1927         exit(1);
1928     }
1929     if(TESTM)
1930         fprintf(STDOUT,"target partition %s free space %d\n",
1931                 toPartName,partition.free);
1932
1933     p=(volintInfo *)0;
1934     code=UV_ListOneVolume(fromserver,frompart,volid,&p);
1935     if(code)
1936     {
1937         fprintf(STDERR,"vos:cannot access volume %lu\n",
1938                 (unsigned long) volid);
1939         free(p);
1940         exit(1);
1941     }
1942
1943     if(partition.free<=p->size)
1944     {
1945         fprintf(STDERR,"vos: no space on target partition %s to copy volume %lu\n",
1946                 toPartName,(unsigned long) volid);
1947         free(p);
1948         exit(1);
1949     }
1950     free(p);
1951
1952     /* successful copy still not guaranteed but shoot for it */
1953
1954     code = UV_CopyVolume(volid, fromserver, frompart, tovolume, toserver, topart);
1955     if (code) {
1956         PrintDiagnostics("copy", code);
1957         return code;
1958     }
1959     MapPartIdIntoName(topart,toPartName);
1960     MapPartIdIntoName(frompart, fromPartName);
1961     fprintf(STDOUT,"Volume %lu copied from %s %s to %s on %s %s \n",
1962             (unsigned long) volid,
1963             as->parms[1].items->data,fromPartName,
1964             tovolume, as->parms[4].items->data,toPartName);
1965
1966     return 0;
1967 }
1968
1969
1970 static BackupVolume(as)
1971 register struct cmd_syndesc *as;
1972 {
1973    afs_int32 avolid, aserver, apart,vtype,code, err;
1974    struct nvldbentry entry;
1975
1976         afs_int32 buvolid,buserver,bupart,butype;
1977         struct nvldbentry buentry;
1978         struct rx_connection *conn;
1979         volEntries volInfo;
1980         struct nvldbentry store;
1981    
1982         avolid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);
1983         if (avolid == 0) {
1984             if (err) PrintError("", err);
1985             else fprintf(STDERR, "vos: can't find volume ID or name '%s'\n",
1986                     as->parms[0].items->data);
1987             return ENOENT;
1988         }
1989         code = GetVolumeInfo( avolid,&aserver, &apart,&vtype,&entry);
1990         if(code) exit(1);
1991
1992         /* verify this is a readwrite volume */
1993
1994         if(vtype != RWVOL)
1995         {
1996                 fprintf(STDERR,"%s not RW volume\n",as->parms[0].items->data);
1997                 exit(1);
1998         }
1999
2000         /* is there a backup volume already? */
2001
2002         if(entry.flags & BACK_EXISTS)
2003         {
2004                 /* yep, where is it? */
2005
2006                 buvolid=entry.volumeId[BACKVOL];
2007                 code=GetVolumeInfo(buvolid,&buserver,&bupart,&butype,&buentry);
2008                 if(code) exit(1);
2009
2010                 /* is it local? */
2011                 code = VLDB_IsSameAddrs(buserver, aserver, &err);
2012                 if (err) {
2013                     fprintf(STDERR,"Failed to get info about server's %d address(es) from vlserver; aborting call!\n", buserver);
2014                     exit(1);
2015                 }
2016                 if (!code)
2017                 {
2018                         fprintf(STDERR,"FATAL ERROR: backup volume %lu exists on server %lu\n",
2019                                 (unsigned long) buvolid,
2020                                 (unsigned long) buserver);
2021                         exit(1);
2022                 }
2023         }
2024
2025         /* nope, carry on */
2026
2027         code = UV_BackupVolume(aserver, apart, avolid);
2028
2029         if (code) {
2030             PrintDiagnostics("backup", code);
2031             return code;
2032         }
2033         fprintf(STDOUT,"Created backup volume for %s \n",as->parms[0].items->data); 
2034    return 0;
2035 }
2036 static ReleaseVolume(as)
2037 register struct cmd_syndesc *as;
2038 {
2039
2040     struct nvldbentry entry;
2041     afs_int32 avolid, aserver, apart,vtype,code, err;
2042     int force = 0;
2043
2044     if(as->parms[1].items) force = 1;
2045     avolid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);
2046     if (avolid == 0) {
2047         if (err) PrintError("", err);
2048         else fprintf(STDERR, "vos: can't find volume '%s'\n", as->parms[0].items->data);
2049         return ENOENT;
2050     }
2051     code = GetVolumeInfo( avolid,&aserver, &apart,&vtype,&entry);
2052     if(code) return code;
2053
2054     if (vtype != RWVOL) {
2055        fprintf(STDERR,"%s not a RW volume\n", as->parms[0].items->data);
2056        return(ENOENT);
2057     }
2058
2059     if(!ISNAMEVALID(entry.name)){
2060         fprintf(STDERR,"Volume name %s is too long, rename before releasing\n",entry.name);
2061         return E2BIG;
2062     }
2063
2064     code = UV_ReleaseVolume(avolid, aserver, apart, force);
2065     if (code) {
2066         PrintDiagnostics("release", code);
2067         return code;
2068     }
2069     fprintf(STDOUT,"Released volume %s successfully\n",as->parms[0].items->data );
2070     return 0;
2071 }
2072 static DumpVolume(as)
2073 register struct cmd_syndesc *as;
2074
2075 {    
2076         afs_int32 avolid, aserver, apart,voltype,fromdate=0,code, err, i;
2077         char filename[NameLen];
2078         struct nvldbentry entry;
2079
2080         rx_SetRxDeadTime(60 * 10);
2081         for (i = 0; i<MAXSERVERS; i++) {
2082             struct rx_connection *rxConn = ubik_GetRPCConn(cstruct,i);
2083             if (rxConn == 0) break;
2084             rx_SetConnDeadTime(rxConn, rx_connDeadTime);
2085             if (rxConn->service)  rxConn->service->connDeadTime = rx_connDeadTime;
2086         }
2087
2088         avolid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);
2089         if (avolid == 0) {
2090             if (err) PrintError("", err);
2091             else  fprintf(STDERR, "vos: can't find volume '%s'\n", as->parms[0].items->data);
2092             return ENOENT;
2093         }
2094
2095         if (as->parms[3].items || as->parms[4].items) {
2096            if (!as->parms[3].items || !as->parms[4].items) {
2097               fprintf(STDERR, "Must specify both -server and -partition options\n");
2098               return -1;
2099            }
2100            aserver = GetServer(as->parms[3].items->data);
2101            if (aserver == 0) {
2102               fprintf(STDERR, "Invalid server name\n");
2103               return -1;
2104            }
2105            apart = volutil_GetPartitionID(as->parms[4].items->data);
2106            if (apart < 0) {
2107               fprintf(STDERR, "Invalid partition name\n");
2108               return -1;
2109            }
2110         } else {
2111            code = GetVolumeInfo(avolid, &aserver, &apart, &voltype, &entry);
2112            if (code) return code;
2113         }
2114
2115         if (as->parms[1].items && strcmp(as->parms[1].items->data,"0")) {
2116             code = ktime_DateToInt32(as->parms[1].items->data, &fromdate);
2117             if (code) {
2118                fprintf(STDERR,"vos: failed to parse date '%s' (error=%d))\n",
2119                        as->parms[1].items->data, code);
2120                return code;
2121             }
2122         }
2123         if(as->parms[2].items){
2124             strcpy(filename,as->parms[2].items->data);
2125         }
2126         else{
2127             strcpy(filename,"");
2128         }
2129
2130     if (as->parms[5].items) {
2131                 code = UV_DumpClonedVolume(avolid, aserver, apart, fromdate, DumpFunction, filename);
2132         } else {
2133                 code = UV_DumpVolume(avolid, aserver, apart, fromdate, DumpFunction, filename);
2134         }               
2135         if (code) {
2136             PrintDiagnostics("dump", code);
2137             return code;
2138         }
2139         if(strcmp(filename,""))
2140             fprintf(STDERR,"Dumped volume %s in file %s\n",as->parms[0].items->data, filename);
2141         else
2142             fprintf(STDERR,"Dumped volume %s in stdout \n",as->parms[0].items->data);
2143         return 0;
2144 }
2145
2146 #define ASK   0
2147 #define ABORT 1
2148 #define FULL  2
2149 #define INC   3
2150
2151 static RestoreVolume(as)
2152 register struct cmd_syndesc *as;
2153
2154 {    
2155         afs_int32 avolid, aserver, apart, code,vcode, err;
2156         afs_int32 aoverwrite = ASK;
2157         int restoreflags, readonly = 0, offline = 0, voltype = RWVOL;
2158         char prompt;
2159         char afilename[NameLen], avolname[VOLSER_MAXVOLNAME +1],apartName[10];
2160         char volname[VOLSER_MAXVOLNAME +1];
2161         struct nvldbentry entry;
2162
2163         prompt = 'n';
2164
2165         if(as->parms[4].items){
2166             avolid = vsu_GetVolumeID(as->parms[4].items->data, cstruct, &err);
2167             if (avolid == 0) {
2168                 if (err) PrintError("", err);
2169                 else fprintf(STDERR, "vos: can't find volume '%s'\n", as->parms[4].items->data);
2170                 exit(1);
2171             }
2172         }
2173         else
2174             avolid = 0;
2175
2176         if (as->parms[5].items) {
2177             if ( (strcmp(as->parms[5].items->data, "a")     == 0) ||
2178                  (strcmp(as->parms[5].items->data, "abort") == 0) ) {
2179                 aoverwrite = ABORT;
2180             }
2181             else if ( (strcmp(as->parms[5].items->data, "f")    == 0) ||
2182                       (strcmp(as->parms[5].items->data, "full") == 0) ) {
2183                 aoverwrite = FULL;
2184             }
2185             else if ( (strcmp(as->parms[5].items->data, "i")           == 0) ||
2186                       (strcmp(as->parms[5].items->data, "inc")         == 0) ||
2187                       (strcmp(as->parms[5].items->data, "increment")   == 0) ||
2188                       (strcmp(as->parms[5].items->data, "incremental") == 0) ) {
2189                 aoverwrite = INC;
2190             }
2191             else {
2192                 fprintf(STDERR, "vos: %s is not a valid argument to -overwrite\n", 
2193                         as->parms[5].items->data);
2194                 exit(1);
2195             }
2196         }
2197         if (as->parms[6].items) offline = 1;
2198         if (as->parms[7].items) {
2199             readonly = 1;
2200             voltype = ROVOL;
2201         }
2202
2203         aserver = GetServer(as->parms[0].items->data);
2204         if (aserver == 0) {
2205             fprintf(STDERR,"vos: server '%s' not found in host table\n", as->parms[0].items->data);
2206             exit(1);
2207         }
2208         apart = volutil_GetPartitionID(as->parms[1].items->data);
2209         if (apart < 0) {
2210             fprintf(STDERR,"vos: could not interpret partition name '%s'\n",as->parms[1].items->data );
2211             exit(1);
2212         }
2213         if (!IsPartValid(apart,aserver,&code)){/*check for validity of the partition */
2214             if(code) PrintError("",code);
2215             else fprintf(STDERR,"vos : partition %s does not exist on the server\n",as->parms[1].items->data);
2216             exit(1);
2217         }
2218         strcpy(avolname,as->parms[2].items->data );
2219         if(!ISNAMEVALID(avolname)) {
2220             fprintf(STDERR,"vos: the name of the volume %s exceeds the size limit\n",avolname);
2221             exit(1);
2222         }
2223         if(!VolNameOK(avolname)){
2224             fprintf(STDERR,"Illegal volume name %s, should not end in .readonly or .backup\n",avolname);
2225             exit(1);
2226         }
2227         if(as->parms[3].items){
2228             strcpy(afilename,as->parms[3].items->data );
2229             if(!FileExists(afilename)){
2230                 fprintf(STDERR,"Can't access file %s\n",afilename);
2231                 exit(1);
2232             }
2233         }
2234         else {
2235             strcpy(afilename,"");
2236         }
2237
2238         /* Check if volume exists or not */
2239
2240         vsu_ExtractName(volname,avolname);
2241         vcode = VLDB_GetEntryByName(volname, &entry);
2242         if (vcode) {              /* no volume - do a full restore */
2243             restoreflags = RV_FULLRST;
2244             if ( (aoverwrite == INC) || (aoverwrite == ABORT) )
2245                 fprintf(STDERR,"Volume does not exist; Will perform a full restore\n");
2246         }
2247
2248         else if ((!readonly && Lp_GetRwIndex(&entry) == -1)        /* RW volume does not exist - do a full */
2249              ||  (readonly && !Lp_ROMatch(0, 0, &entry))) {        /* RO volume does not exist - do a full */
2250             restoreflags = RV_FULLRST;
2251             if ( (aoverwrite == INC) || (aoverwrite == ABORT) )
2252                 fprintf(STDERR,"%s Volume does not exist; Will perform a full restore\n",
2253                         readonly ? "RO" : "RW");
2254
2255             if (avolid == 0) {
2256                 avolid = entry.volumeId[voltype];
2257             }
2258             else if (entry.volumeId[voltype] != 0  && entry.volumeId[voltype] != avolid) {
2259                 avolid = entry.volumeId[voltype];
2260             }
2261         }
2262
2263         else {                    /* volume exists - do we do a full incremental or abort */
2264             int Oserver, Opart, Otype, vol_elsewhere = 0;
2265             struct nvldbentry Oentry;
2266             int   c, dc;
2267
2268             if(avolid == 0) {
2269                 avolid = entry.volumeId[voltype];
2270             }
2271             else if(entry.volumeId[voltype] != 0  && entry.volumeId[voltype] != avolid) {
2272                 avolid = entry.volumeId[voltype];
2273             }
2274             
2275             /* A file name was specified  - check if volume is on another partition */
2276             vcode = GetVolumeInfo(avolid, &Oserver, &Opart, &Otype, &Oentry);
2277             if (vcode) exit(1);
2278
2279             vcode = VLDB_IsSameAddrs(Oserver, aserver, &err);
2280             if (err) {
2281                 fprintf(STDERR,"Failed to get info about server's %d address(es) from vlserver (err=%d); aborting call!\n", 
2282                         Oserver, err);
2283                 exit(1);
2284             }
2285             if (!vcode || (Opart != apart)) vol_elsewhere = 1;
2286
2287             if (aoverwrite == ASK) {
2288                 if (strcmp(afilename,"") == 0) {  /* The file is from standard in */
2289                     fprintf(STDERR,"Volume exists and no -overwrite option specified; Aborting restore command\n");
2290                     exit(1);
2291                 }
2292                 
2293                 /* Ask what to do */
2294                 if (vol_elsewhere) {
2295                     fprintf(STDERR,"The volume %s %u already exists on a different server/part\n",
2296                             volname, entry.volumeId[voltype]);
2297                     fprintf(STDERR, 
2298                             "Do you want to do a full restore or abort? [fa](a): ");
2299                 }
2300                 else
2301                 {
2302                     fprintf(STDERR,"The volume %s %u already exists in the VLDB\n",
2303                             volname, entry.volumeId[voltype]);
2304                     fprintf(STDERR, 
2305                             "Do you want to do a full/incremental restore or abort? [fia](a): ");
2306                 }
2307                 dc = c = getchar();
2308                 while (!(dc==EOF || dc=='\n')) dc=getchar(); /* goto end of line */
2309                 if      ((c == 'f') || (c == 'F')) aoverwrite = FULL;
2310                 else if ((c == 'i') || (c == 'I')) aoverwrite = INC;
2311                 else aoverwrite = ABORT;
2312             }
2313
2314             if (aoverwrite == ABORT) {
2315                 fprintf(STDERR,"Volume exists; Aborting restore command\n");
2316                 exit(1);
2317             }
2318             else if (aoverwrite == FULL) {
2319                 restoreflags = RV_FULLRST;
2320                 fprintf(STDERR,"Volume exists; Will delete and perform full restore\n");
2321             }
2322             else if (aoverwrite == INC) {
2323                 restoreflags = 0;
2324                 if (vol_elsewhere) {
2325                     fprintf(STDERR,
2326                             "%s volume %lu already exists on a different server/part; not allowed\n",
2327                             readonly ? "RO" : "RW", (unsigned long) avolid);
2328                     exit(1);
2329                 }
2330             }
2331         }
2332         if (offline)  restoreflags |= RV_OFFLINE;
2333         if (readonly) restoreflags |= RV_RDONLY;
2334         code = UV_RestoreVolume(aserver, apart, avolid, avolname,
2335                                 restoreflags, WriteData, afilename);
2336         if (code) {
2337             PrintDiagnostics("restore", code);
2338             exit(1);
2339         }
2340         MapPartIdIntoName(apart,apartName);
2341
2342         /*
2343                 patch typo here - originally "parms[1]", should be "parms[0]"
2344         */
2345
2346         fprintf(STDOUT,"Restored volume %s on %s %s\n",
2347                 avolname, as->parms[0].items->data, apartName);
2348         return 0;
2349 }
2350 static LockReleaseCmd(as)
2351 register struct cmd_syndesc *as;
2352
2353 {
2354     afs_int32 avolid,code, err;
2355
2356         avolid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);
2357         if (avolid == 0) {
2358             if (err) PrintError("", err);
2359             else fprintf(STDERR, "vos: can't find volume '%s'\n", as->parms[0].items->data);
2360             exit(1);
2361         }
2362         
2363         code = UV_LockRelease(avolid);
2364         if (code) {
2365             PrintDiagnostics("unlock", code);
2366             exit(1);
2367         }
2368         fprintf(STDOUT,"Released lock on vldb entry for volume %s\n",as->parms[0].items->data);
2369     return 0;
2370 }
2371 static AddSite(as)
2372 register struct cmd_syndesc *as;
2373 {
2374    afs_int32 avolid, aserver, apart,code, err;
2375    char apartName[10], avolname[VOLSER_MAXVOLNAME+1];
2376
2377         vsu_ExtractName(avolname, as->parms[2].items->data);;
2378         avolid = vsu_GetVolumeID(avolname, cstruct, &err);
2379         if (avolid == 0) {
2380             if (err) PrintError("", err);
2381             else fprintf(STDERR, "vos: can't find volume '%s'\n", as->parms[2].items->data);
2382             exit(1);
2383         }
2384         aserver = GetServer(as->parms[0].items->data);
2385         if (aserver == 0) {
2386             fprintf(STDERR,"vos: server '%s' not found in host table\n", as->parms[0].items->data);
2387             exit(1);
2388         }
2389         apart = volutil_GetPartitionID(as->parms[1].items->data);
2390         if (apart < 0) {
2391             fprintf(STDERR,"vos: could not interpret partition name '%s'\n",as->parms[1].items->data );
2392             exit(1);
2393         }
2394         if (!IsPartValid(apart,aserver,&code)){/*check for validity of the partition */
2395             if(code) PrintError("",code);
2396             else fprintf(STDERR,"vos : partition %s does not exist on the server\n",as->parms[1].items->data);
2397             exit(1);
2398         }
2399         code = UV_AddSite(aserver, apart, avolid);
2400         if (code) {
2401             PrintDiagnostics("addsite", code);
2402             exit(1);
2403         }
2404         MapPartIdIntoName(apart,apartName);
2405         fprintf(STDOUT,"Added replication site %s %s for volume %s\n",as->parms[0].items->data, apartName,as->parms[2].items->data);
2406    return 0;
2407 }
2408
2409 static RemoveSite(as)
2410 register struct cmd_syndesc *as;
2411
2412
2413     afs_int32 avolid, aserver, apart, code, err;
2414     char apartName[10], avolname[VOLSER_MAXVOLNAME+1];
2415
2416         vsu_ExtractName(avolname, as->parms[2].items->data);
2417         avolid = vsu_GetVolumeID(avolname, cstruct, &err);
2418         if (avolid == 0) {
2419             if (err) PrintError("", err);
2420             else fprintf(STDERR, "vos: can't find volume '%s'\n", as->parms[2].items->data);
2421             exit(1);
2422         }
2423         aserver = GetServer(as->parms[0].items->data);
2424         if (aserver == 0) {
2425             fprintf(STDERR,"vos: server '%s' not found in host table\n", as->parms[0].items->data);
2426             exit(1);
2427         }
2428         apart = volutil_GetPartitionID(as->parms[1].items->data);
2429         if (apart < 0) {
2430             fprintf(STDERR,"vos: could not interpret partition name '%s'\n",as->parms[1].items->data );
2431             exit(1);
2432         }
2433 /*
2434  *skip the partition validity check, since it is possible that the partition
2435  *has since been decomissioned.
2436  */
2437 /*
2438         if (!IsPartValid(apart,aserver,&code)){
2439             if(code) PrintError("",code);
2440             else fprintf(STDERR,"vos : partition %s does not exist on the server\n",as->parms[1].items->data);
2441             exit(1);
2442         }
2443 */
2444         code = UV_RemoveSite(aserver, apart, avolid);
2445         if (code) {
2446             PrintDiagnostics("remsite", code);
2447             exit(1);
2448         }
2449         MapPartIdIntoName(apart,apartName);
2450         fprintf(STDOUT,"Removed replication site %s %s for volume %s\n",as->parms[0].items->data,apartName,as->parms[2].items->data);
2451     return 0;
2452 }
2453 static ChangeLocation(as)
2454 register struct cmd_syndesc *as;
2455 {
2456    afs_int32 avolid, aserver, apart,code, err;
2457    char apartName[10];
2458
2459         avolid = vsu_GetVolumeID(as->parms[2].items->data, cstruct, &err);
2460         if (avolid == 0) {
2461             if (err) PrintError("", err);
2462             else fprintf(STDERR, "vos: can't find volume '%s'\n", as->parms[2].items->data);
2463             exit(1);
2464         }
2465         aserver = GetServer(as->parms[0].items->data);
2466         if (aserver == 0) {
2467             fprintf(STDERR,"vos: server '%s' not found in host table\n", as->parms[0].items->data);
2468             exit(1);
2469         }
2470         apart = volutil_GetPartitionID(as->parms[1].items->data);
2471         if (apart < 0) {
2472             fprintf(STDERR,"vos: could not interpret partition name '%s'\n",as->parms[1].items->data );
2473             exit(1);
2474         }
2475         if (!IsPartValid(apart,aserver,&code)){/*check for validity of the partition */
2476             if(code) PrintError("",code);
2477             else fprintf(STDERR,"vos : partition %s does not exist on the server\n",as->parms[1].items->data);
2478             exit(1);
2479         }
2480         code = UV_ChangeLocation(aserver, apart, avolid);
2481         if (code) {
2482             PrintDiagnostics("addsite", code);
2483             exit(1);
2484         }
2485         MapPartIdIntoName(apart,apartName);
2486         fprintf(STDOUT,"Changed location to %s %s for volume %s\n",as->parms[0].items->data, apartName,as->parms[2].items->data);
2487    return 0;
2488 }
2489
2490 static ListPartitions(as)
2491 register struct cmd_syndesc *as;
2492 {
2493     afs_int32 aserver,code;
2494     struct partList dummyPartList;
2495     int i;
2496     char pname[10];
2497     int total, cnt;
2498
2499     aserver = GetServer(as->parms[0].items->data);
2500     if (aserver == 0) {
2501         fprintf(STDERR,"vos: server '%s' not found in host table\n", as->parms[0].items->data);
2502         exit(1);
2503     }
2504
2505
2506     code = UV_ListPartitions(aserver,&dummyPartList, &cnt);
2507     if (code) {
2508         PrintDiagnostics("listpart", code);
2509         exit(1);
2510     }
2511     total = 0;
2512     fprintf(STDOUT,"The partitions on the server are:\n");
2513     for(i = 0 ; i < cnt ; i++){
2514         if(dummyPartList.partFlags[i] & PARTVALID){
2515             memset(pname, 0, sizeof(pname));
2516             MapPartIdIntoName(dummyPartList.partId[i],pname);
2517             fprintf(STDOUT," %10s ",pname);
2518             total++;
2519             if( (i % 5) == 0 && (i != 0)) fprintf(STDOUT,"\n");
2520         }
2521     }
2522     fprintf(STDOUT,"\n");
2523     fprintf(STDOUT,"Total: %d\n",total);
2524     return 0;
2525         
2526 }
2527
2528 static int CompareVolName(p1,p2)
2529 char *p1,*p2;
2530 {
2531     volintInfo *arg1,*arg2;
2532
2533     arg1 = (volintInfo *)p1;
2534     arg2 = (volintInfo *)p2;
2535     return(strcmp(arg1->name,arg2->name));
2536     
2537 }
2538
2539 /*------------------------------------------------------------------------
2540  * PRIVATE XCompareVolName
2541  *
2542  * Description:
2543  *      Comparison routine for volume names coming from an extended
2544  *      volume listing.
2545  *
2546  * Arguments:
2547  *      a_obj1P : Char ptr to first extended vol info object
2548  *      a_obj1P : Char ptr to second extended vol info object
2549  *
2550  * Returns:
2551  *      The value of strcmp() on the volume names within the passed
2552  *      objects (i,e., -1, 0, or 1).
2553  *
2554  * Environment:
2555  *      Passed to qsort() as the designated comparison routine.
2556  *
2557  * Side Effects:
2558  *      As advertised.
2559  *------------------------------------------------------------------------*/
2560
2561 static int XCompareVolName(a_obj1P, a_obj2P)
2562     char *a_obj1P, *a_obj2P;
2563
2564 { /*XCompareVolName*/
2565
2566     return(strcmp(((struct volintXInfo *)(a_obj1P))->name,
2567                   ((struct volintXInfo *)(a_obj2P))->name));
2568
2569 } /*XCompareVolName*/
2570
2571 static int CompareVolID(p1,p2)
2572 char *p1,*p2;
2573 {
2574     volintInfo *arg1,*arg2;
2575
2576     arg1 = (volintInfo *)p1;
2577     arg2 = (volintInfo *)p2;
2578     if(arg1->volid == arg2->volid) return 0;
2579     if(arg1->volid > arg2->volid) return 1;
2580     else return -1;
2581     
2582 }
2583
2584 /*------------------------------------------------------------------------
2585  * PRIVATE XCompareVolID
2586  *
2587  * Description:
2588  *      Comparison routine for volume IDs coming from an extended
2589  *      volume listing.
2590  *
2591  * Arguments:
2592  *      a_obj1P : Char ptr to first extended vol info object
2593  *      a_obj1P : Char ptr to second extended vol info object
2594  *
2595  * Returns:
2596  *      The value of strcmp() on the volume names within the passed
2597  *      objects (i,e., -1, 0, or 1).
2598  *
2599  * Environment:
2600  *      Passed to qsort() as the designated comparison routine.
2601  *
2602  * Side Effects:
2603  *      As advertised.
2604  *------------------------------------------------------------------------*/
2605
2606 static int XCompareVolID(a_obj1P, a_obj2P)
2607     char *a_obj1P, *a_obj2P;
2608
2609 { /*XCompareVolID*/
2610
2611     afs_int32 id1, id2; /*Volume IDs we're comparing*/
2612
2613     id1 = ((struct volintXInfo *)(a_obj1P))->volid;
2614     id2 = ((struct volintXInfo *)(a_obj2P))->volid;
2615     if (id1 == id2)
2616         return(0);
2617     else
2618         if (id1 > id2)
2619             return(1);
2620     else
2621        return(-1);
2622
2623 } /*XCompareVolID*/
2624
2625 /*------------------------------------------------------------------------
2626  * PRIVATE ListVolumes
2627  *
2628  * Description:
2629  *      Routine used to list volumes, contacting the Volume Server
2630  *      directly, bypassing the VLDB.
2631  *
2632  * Arguments:
2633  *      as : Ptr to parsed command line arguments.
2634  *
2635  * Returns:
2636  *      0                       Successful operation
2637  *
2638  * Environment:
2639  *      Nothing interesting.
2640  *
2641  * Side Effects:
2642  *      As advertised.
2643  *------------------------------------------------------------------------*/
2644
2645 static ListVolumes(as)
2646 register struct cmd_syndesc *as;
2647 {  
2648     afs_int32 apart,int32list,fast;
2649     afs_int32 aserver,code;
2650     volintInfo *pntr,*oldpntr;
2651     afs_int32 count;
2652     int i;
2653     char *base;
2654     volintXInfo *xInfoP, *origxInfoP;   /*Ptr to current/orig extended vol info*/
2655     int wantExtendedInfo;               /*Do we want extended vol info?*/
2656
2657     char pname[10];
2658     struct partList dummyPartList;
2659     int all;
2660     int quiet, cnt;
2661
2662     apart = -1;
2663     fast = 0;
2664     int32list = 0;
2665
2666     if(as->parms[3].items) int32list = 1;
2667     if(as->parms[4].items) quiet = 1;
2668     else quiet = 0;
2669     if(as->parms[2].items) fast = 1;
2670     if(fast) all = 0;
2671     else all = 1;
2672     if (as->parms[5].items) {
2673         /*
2674          * We can't coexist with the fast flag.
2675          */
2676         if (fast) {
2677             fprintf(STDERR,
2678                     "vos: Can't use the -fast and -extended flags together\n");
2679             exit(1);
2680         }
2681
2682         /*
2683          * We need to turn on ``long'' listings to get the full effect.
2684          */
2685         wantExtendedInfo = 1;
2686         int32list = 1;
2687     }
2688     else
2689         wantExtendedInfo = 0;
2690     if(as->parms[1].items){
2691         apart = volutil_GetPartitionID(as->parms[1].items->data);
2692         if (apart < 0) {
2693             fprintf(STDERR,"vos: could not interpret partition name '%s'\n", as->parms[1].items->data);
2694             exit(1);
2695         }
2696         dummyPartList.partId[0] = apart;
2697         dummyPartList.partFlags[0] = PARTVALID;
2698         cnt = 1;
2699     }
2700     aserver = GetServer(as->parms[0].items->data);
2701     if (aserver == 0) {
2702         fprintf(STDERR,"vos: server '%s' not found in host table\n",as->parms[0].items->data );
2703         exit(1);
2704     }
2705
2706     if(apart != -1) {
2707         if (!IsPartValid(apart,aserver,&code)){/*check for validity of the partition */
2708             if(code) PrintError("",code);
2709             else fprintf(STDERR,"vos : partition %s does not exist on the server\n",as->parms[1].items->data);
2710             exit(1);
2711         }
2712     }
2713     else {
2714         code = UV_ListPartitions(aserver,&dummyPartList, &cnt);
2715         if (code) {
2716             PrintDiagnostics("listvol", code);
2717             exit(1);
2718         }
2719     }
2720     for(i = 0 ; i < cnt ; i++){
2721         if(dummyPartList.partFlags[i] & PARTVALID){
2722             if (wantExtendedInfo)
2723                 code = UV_XListVolumes(aserver,
2724                                        dummyPartList.partId[i],
2725                                        all,
2726                                        &xInfoP,
2727                                        &count);
2728             else
2729                 code = UV_ListVolumes(aserver,
2730                                       dummyPartList.partId[i],
2731                                       all,
2732                                       &pntr,
2733                                       &count);
2734             if (code) {
2735                 PrintDiagnostics("listvol", code);
2736                 if(pntr) free(pntr);
2737                 exit(1);
2738             }
2739             if (wantExtendedInfo) {
2740                 origxInfoP = xInfoP;
2741                 base = (char *)xInfoP;
2742             } else {
2743                 oldpntr = pntr;
2744                 base = (char *)pntr;
2745             }
2746
2747             if(!fast) {
2748                 if (wantExtendedInfo) 
2749                     qsort(base, count, sizeof(volintXInfo), XCompareVolName);
2750                 else
2751                     qsort(base, count, sizeof(volintInfo), CompareVolName);
2752             } else {
2753                 if (wantExtendedInfo) 
2754                     qsort(base, count, sizeof(volintXInfo), XCompareVolID);
2755                 else
2756                     qsort(base, count, sizeof(volintInfo), CompareVolID);
2757             }
2758             MapPartIdIntoName(dummyPartList.partId[i],pname);
2759             if(!quiet)
2760                 fprintf(STDOUT,"Total number of volumes on server %s partition %s: %lu \n",as->parms[0].items->data,pname, (unsigned long) count);
2761             if (wantExtendedInfo) {
2762                 XDisplayVolumes(aserver,
2763                                 dummyPartList.partId[i],
2764                                 origxInfoP,
2765                                 count,
2766                                 int32list,
2767                                 fast,
2768                                 quiet);
2769                 if(xInfoP)
2770                     free(xInfoP);
2771                 xInfoP = (volintXInfo *)0;
2772             }
2773             else {
2774 #ifdef FULL_LISTVOL_SWITCH
2775               if (as->parms[6].items)
2776                 DisplayVolumes2(aserver, dummyPartList.partId[i], oldpntr, 
2777                                 count);
2778               else
2779 #endif /* FULL_LISTVOL_SWITCH */
2780                 DisplayVolumes(aserver,
2781                                dummyPartList.partId[i],
2782                                oldpntr,
2783                                count,
2784                                int32list,
2785                                fast,
2786                                quiet);
2787                 if (pntr)
2788                     free(pntr);
2789                 pntr = (volintInfo *)0;
2790             }
2791         }
2792     }
2793     return 0;
2794 }
2795
2796 static SyncVldb(as)
2797   register struct cmd_syndesc *as;
2798 {
2799   afs_int32 pname, code;        /* part name */
2800   char part[10];
2801   int flags = 0;
2802   char *volname = 0;
2803
2804   tserver = 0;
2805   if (as->parms[0].items) {
2806      tserver = GetServer(as->parms[0].items->data);
2807      if (!tserver) {
2808         fprintf(STDERR,"vos: host '%s' not found in host table\n",as->parms[0].items->data );
2809         exit(1);
2810      }
2811   }
2812
2813   if (as->parms[1].items) {
2814      pname = volutil_GetPartitionID(as->parms[1].items->data);
2815      if (pname < 0) {
2816         fprintf(STDERR,"vos: could not interpret partition name '%s'\n",as->parms[1].items->data );
2817         exit(1);
2818      }
2819      if (!IsPartValid(pname,tserver,&code)) { /*check for validity of the partition */
2820         if(code) PrintError("",code);
2821         else fprintf(STDERR,"vos: partition %s does not exist on the server\n",
2822                      as->parms[1].items->data);
2823         exit(1);
2824      }
2825      flags = 1;
2826      
2827      if (!tserver) {
2828         fprintf(STDERR,"The -partition option requires a -server option\n");
2829         exit(1);
2830      }
2831   }
2832
2833   if (as->parms[2].items) {
2834      /* Synchronize an individual volume */
2835      volname = as->parms[2].items->data;
2836      code = UV_SyncVolume(tserver, pname, volname, flags);
2837   } else {
2838      if (!tserver) {
2839         fprintf(STDERR,"Without a -volume option, the -server option is required\n");
2840         exit(1);
2841      }
2842      code = UV_SyncVldb(tserver, pname, flags, 0/*unused*/);
2843   }
2844
2845   if (code) {
2846      PrintDiagnostics("syncvldb", code);
2847      exit(1);
2848   }
2849
2850   /* Print a summary of what we did */
2851   if (volname) fprintf(STDOUT,"VLDB volume %s synchronized", volname);
2852   else         fprintf(STDOUT,"VLDB synchronized");
2853   if (tserver) {
2854      fprintf(STDOUT," with state of server %s", as->parms[0].items->data);
2855   }
2856   if (flags) {
2857      MapPartIdIntoName(pname,part);
2858      fprintf(STDOUT," partition %s\n", part);
2859   }
2860   fprintf(STDOUT, "\n");
2861
2862   return 0;
2863 }
2864     
2865 static SyncServer(as)
2866 register struct cmd_syndesc *as;
2867
2868 {
2869     afs_int32 pname,code;       /* part name */
2870     char part[10];
2871         
2872         int flags = 0;
2873
2874         tserver = GetServer(as->parms[0].items->data);
2875         if (!tserver) {
2876             fprintf(STDERR,"vos: host '%s' not found in host table\n",as->parms[0].items->data );
2877             exit(1);
2878         }
2879         if(as->parms[1].items){
2880             pname = volutil_GetPartitionID(as->parms[1].items->data);
2881             if (pname < 0) {
2882                 fprintf(STDERR,"vos: could not interpret partition name '%s'\n",as->parms[1].items->data);
2883                 exit(1);
2884             }
2885             if (!IsPartValid(pname,tserver,&code)){/*check for validity of the partition */
2886                 if(code) PrintError("",code);
2887                 else fprintf(STDERR,"vos : partition %s does not exist on the server\n",as->parms[1].items->data);
2888                 exit(1);
2889             }
2890             flags = 1;
2891         }
2892         
2893         code = UV_SyncServer(tserver, pname, flags, 0/*unused*/);
2894         if (code) {
2895             PrintDiagnostics("syncserv", code);
2896             exit(1);
2897         }
2898         if(flags){
2899             MapPartIdIntoName(pname,part);
2900             fprintf(STDOUT,"Server %s partition %s synchronized with VLDB\n",as->parms[0].items->data,part);
2901         }
2902         else fprintf(STDOUT,"Server %s synchronized with VLDB\n",as->parms[0].items->data);
2903     return 0;
2904         
2905 }
2906
2907 static VolumeInfoCmd(name)
2908 char *name;
2909 {  
2910     struct nvldbentry entry;
2911     afs_int32 vcode;
2912
2913     /* The vlserver will handle names with the .readonly
2914      * and .backup extension as well as volume ids.
2915      */
2916     vcode = VLDB_GetEntryByName(name, &entry);
2917     if (vcode) {
2918         PrintError("", vcode);
2919         exit(1);
2920     }
2921     MapHostToNetwork(&entry);
2922     EnumerateEntry(&entry);
2923
2924     /* Defect #3027: grubby check to handle locked volume.
2925      * If VLOP_ALLOPERS is set, the entry is locked.
2926      * Leave this routine as is, but put in correct check.
2927      */
2928     if (entry.flags & VLOP_ALLOPERS)
2929         fprintf(STDOUT,"    Volume is currently LOCKED  \n");
2930
2931     return 0;
2932 }
2933
2934 static VolumeZap(as)
2935 register struct cmd_syndesc *as;
2936
2937 {
2938     struct nvldbentry entry;
2939     afs_int32 volid,code,server,part, zapbackupid=0, backupid=0, err;
2940     
2941     if (as->parms[3].items) {
2942         /* force flag is on, use the other version */
2943         return NukeVolume(as);
2944     }
2945
2946     if (as->parms[4].items) {
2947         zapbackupid = 1;
2948     }
2949
2950     volid = vsu_GetVolumeID(as->parms[2].items->data, cstruct, &err);
2951     if(volid == 0) {
2952         if (err) PrintError("", err);
2953         else fprintf(STDERR, "vos: can't find volume '%s'\n", as->parms[2].items->data);
2954         exit(1);
2955     }
2956     part = volutil_GetPartitionID(as->parms[1].items->data);
2957     if (part < 0) {
2958         fprintf(STDERR,"vos: could not interpret partition name '%s'\n",as->parms[1].items->data );
2959         exit(1);
2960     }
2961     server = GetServer(as->parms[0].items->data);
2962     if (!server) {
2963             fprintf(STDERR,"vos: host '%s' not found in host table\n",as->parms[0].items->data );
2964             exit(1);
2965     }
2966     if (!IsPartValid(part,server,&code)){/*check for validity of the partition */
2967             if(code) PrintError("",code);
2968             else fprintf(STDERR,"vos : partition %s does not exist on the server\n",as->parms[1].items->data);
2969             exit(1);
2970         }
2971     code = VLDB_GetEntryByID(volid,-1, &entry);
2972     if (!code) {
2973         if (volid == entry.volumeId[RWVOL])
2974             backupid = entry.volumeId[BACKVOL];
2975         fprintf(STDERR,"Warning: Entry for volume number %lu exists in VLDB (but we're zapping it anyway!)\n",
2976                 (unsigned long) volid);
2977     }
2978     if (zapbackupid) {
2979         volintInfo *pntr = (volintInfo *)0;
2980
2981         if (!backupid) {
2982             code = UV_ListOneVolume(server, part, volid, &pntr);
2983             if (!code) {
2984                 if (volid == pntr->parentID)
2985                     backupid = pntr->backupID;
2986                 if (pntr) free(pntr);
2987             }
2988         }
2989         if (backupid) {
2990             code = UV_VolumeZap(server,part, backupid);
2991             if (code) {
2992                 PrintDiagnostics("zap", code);
2993                 exit(1);
2994             }
2995             fprintf(STDOUT,"Backup Volume %lu deleted\n",
2996                     (unsigned long) backupid);
2997         }
2998     }
2999     code = UV_VolumeZap(server,part,volid);
3000     if (code) {
3001         PrintDiagnostics("zap", code);
3002         exit(1);
3003     }
3004     fprintf(STDOUT,"Volume %lu deleted\n", (unsigned long) volid);
3005
3006     return 0;
3007 }
3008    
3009 static VolserStatus(as)
3010 register struct cmd_syndesc *as;
3011
3012 {   
3013     afs_int32 server, code;
3014     transDebugInfo *pntr,*oldpntr;
3015     afs_int32 count;
3016     int i;
3017     char pname[10];
3018
3019     server = GetServer(as->parms[0].items->data);
3020     if (!server) {
3021             fprintf(STDERR,"vos: host '%s' not found in host table\n",as->parms[0].items->data );
3022             exit(1);
3023     }
3024     code = UV_VolserStatus(server,&pntr,&count);
3025     if(code) {
3026         PrintDiagnostics("status",code);
3027         exit(1);
3028     }
3029     oldpntr = pntr;
3030     if(count == 0) 
3031         fprintf(STDOUT,"No active transactions on %s\n",as->parms[0].items->data);
3032     else {
3033         fprintf(STDOUT,"Total transactions: %d\n",count);
3034     }
3035     for(i = 0; i < count ; i++){
3036         /*print out the relevant info */
3037         fprintf(STDOUT,"--------------------------------------\n");
3038         fprintf(STDOUT,"transaction: %lu  created: %s",
3039                 (unsigned long) pntr->tid,
3040                 ctime((time_t *)&pntr->time));
3041         if(pntr->returnCode){
3042             fprintf(STDOUT,"returnCode: %lu\n",
3043                     (unsigned long) pntr->returnCode);
3044         }
3045         if(pntr->iflags){
3046             fprintf(STDOUT,"attachFlags:  ");
3047             switch(pntr->iflags){
3048               case ITOffline: fprintf(STDOUT,"offline ");
3049                 break;
3050               case ITBusy: fprintf(STDOUT,"busy ");
3051                 break;
3052               case ITReadOnly: fprintf(STDOUT,"readonly ");
3053                 break;
3054               case ITCreate: fprintf(STDOUT,"create ");
3055                 break;
3056               case ITCreateVolID: fprintf(STDOUT,"create volid ");
3057                 break;
3058             }
3059             fprintf(STDOUT,"\n");
3060         }
3061         if(pntr->vflags){
3062             fprintf(STDOUT,"volumeStatus: ");
3063             switch(pntr->vflags){
3064               case VTDeleteOnSalvage: fprintf(STDOUT,"deleteOnSalvage ");
3065               case VTOutOfService: fprintf(STDOUT,"outOfService ");
3066               case VTDeleted: fprintf(STDOUT,"deleted ");
3067             }
3068             fprintf(STDOUT,"\n");
3069         }
3070         if(pntr->tflags){
3071             fprintf(STDOUT,"transactionFlags: ");
3072             fprintf(STDOUT,"delete\n");
3073         }
3074         MapPartIdIntoName(pntr->partition ,pname);
3075         fprintf(STDOUT,"volume: %lu  partition: %s  procedure: %s\n",
3076                 (unsigned long) pntr->volid, pname,
3077                 pntr->lastProcName);
3078         if(pntr->callValid){
3079             fprintf(STDOUT,"packetRead: %lu  lastReceiveTime: %d  packetSend: %lu  lastSendTime: %d\n",
3080                     (unsigned long) pntr->readNext,pntr->lastReceiveTime,
3081                     (unsigned long) pntr->transmitNext, pntr->lastSendTime);
3082         }
3083         pntr++;
3084         fprintf(STDOUT,"--------------------------------------\n");
3085         fprintf(STDOUT,"\n");
3086     }
3087     if(oldpntr) free(oldpntr);
3088     return 0;
3089 }
3090  
3091 static RenameVolume(as)
3092 register struct cmd_syndesc *as;
3093 {
3094    afs_int32 code1,code2,code;
3095    struct nvldbentry entry;
3096
3097         code1 = VLDB_GetEntryByName(as->parms[0].items->data, &entry);
3098         if(code1){
3099             fprintf(STDERR,"vos: Could not find entry for volume %s\n",as->parms[0].items->data);
3100             exit(1);
3101         }
3102         code2 = VLDB_GetEntryByName(as->parms[1].items->data, &entry);
3103         if((!code1) && (!code2)) { /*the newname already exists */
3104             fprintf(STDERR,"vos: volume %s already exists\n",as->parms[1].items->data);
3105             exit(1);
3106         }
3107
3108         if(code1 && code2){
3109             fprintf(STDERR,"vos: Could not find entry for volume %s or %s\n",as->parms[0].items->data,as->parms[1].items->data);
3110             exit(1);
3111         }
3112     if(!VolNameOK(as->parms[0].items->data)){
3113         fprintf(STDERR,"Illegal volume name %s, should not end in .readonly or .backup\n",as->parms[0].items->data);
3114         exit(1);
3115     }
3116    if(!ISNAMEVALID(as->parms[1].items->data)) {
3117         fprintf(STDERR,"vos: the new volume name %s exceeds the size limit of %d\n",as->parms[1].items->data,VOLSER_OLDMAXVOLNAME - 10);
3118         exit(1);
3119     }
3120     if(!VolNameOK(as->parms[1].items->data)){
3121         fprintf(STDERR,"Illegal volume name %s, should not end in .readonly or .backup\n",as->parms[1].items->data);
3122         exit(1);
3123     }
3124     if(IsNumeric(as->parms[1].items->data)){
3125         fprintf(STDERR,"Illegal volume name %s, should not be a number\n",as->parms[1].items->data);
3126         exit(1);
3127     }
3128         MapHostToNetwork(&entry);
3129         code = UV_RenameVolume(&entry,as->parms[0].items->data,as->parms[1].items->data);
3130         if (code) {
3131             PrintDiagnostics("rename", code);
3132             exit(1);
3133         }
3134         fprintf(STDOUT,"Renamed volume %s to %s\n",as->parms[0].items->data,as->parms[1].items->data); 
3135    return 0;
3136 }
3137
3138 GetVolumeInfo(volid, server, part, voltype,rentry)
3139 afs_int32 *server, volid, *part, *voltype;
3140 register struct nvldbentry *rentry;
3141 {
3142     afs_int32 vcode;
3143     int i,index = -1;
3144
3145     vcode = VLDB_GetEntryByID(volid, -1, rentry);
3146     if(vcode) {
3147                 fprintf(STDERR,"Could not fetch the entry for volume %lu from VLDB \n",
3148                         (unsigned long) volid);
3149                 PrintError("",vcode);
3150                 return (vcode);
3151     }
3152     MapHostToNetwork(rentry);
3153     if(volid == rentry->volumeId[ROVOL]){
3154         *voltype = ROVOL;
3155         for (i = 0; i < rentry->nServers; i++) {
3156             if ( (index == -1) && (rentry->serverFlags[i] & ITSROVOL) &&
3157                 !(rentry->serverFlags[i] & RO_DONTUSE) )
3158                 index = i;
3159         }
3160         if(index == -1) {
3161             fprintf(STDERR,"RO volume is not found in VLDB entry for volume %lu\n", (unsigned long) volid);
3162             return -1;
3163         }
3164
3165         *server = rentry->serverNumber[index];
3166         *part = rentry->serverPartition[index];
3167         return 0;
3168     }
3169                 
3170     index = Lp_GetRwIndex(rentry);
3171     if(index == -1) {
3172         fprintf(STDERR,"RW Volume is not found in VLDB entry for volume %lu\n",
3173                 (unsigned long) volid);
3174         return -1;
3175     }
3176     if(volid == rentry->volumeId[RWVOL]){
3177         *voltype = RWVOL;
3178         *server = rentry->serverNumber[index];
3179         *part = rentry->serverPartition[index];
3180         return 0;
3181     }
3182     if(volid == rentry->volumeId[BACKVOL]){
3183         *voltype = BACKVOL;
3184         *server = rentry->serverNumber[index];
3185         *part = rentry->serverPartition[index];
3186         return 0;
3187     }
3188 }
3189
3190 static DeleteEntry(as)
3191 register struct cmd_syndesc *as;
3192
3193 {
3194     afs_int32 apart;
3195     afs_int32 avolid;
3196     afs_int32 vcode;
3197     struct VldbListByAttributes attributes;
3198     nbulkentries arrayEntries;
3199     register struct nvldbentry *vllist;
3200     struct cmd_item *itp;
3201     afs_int32 nentries;
3202     int j;
3203     char prefix[VOLSER_MAXVOLNAME+1];
3204     int seenprefix=0;
3205     afs_int32 totalBack=0, totalFail=0, err;
3206
3207     if (as->parms[0].items) { /* -id */
3208        if (as->parms[1].items || as->parms[2].items || as->parms[3].items) {
3209           fprintf(STDERR,"You cannot use -server, -partition, or -prefix with the -id argument\n");
3210           exit(-2);
3211        }
3212        for (itp=as->parms[0].items; itp; itp=itp->next) {
3213           avolid = vsu_GetVolumeID(itp->data, cstruct, &err);
3214           if (avolid == 0) {
3215              if (err) PrintError("", err);
3216              else fprintf(STDERR, "vos: can't find volume '%s'\n", itp->data);
3217              continue;
3218           }
3219           if (as->parms[4].items) { /* -noexecute */
3220              fprintf(STDOUT,"Would have deleted VLDB entry for %s \n", itp->data);
3221              fflush(STDOUT);
3222              continue;
3223           }
3224           vcode = ubik_Call(VL_DeleteEntry,cstruct, 0, avolid, RWVOL);
3225           if (vcode) {
3226              fprintf(STDERR,"Could not delete entry for volume %s\n", itp->data);
3227              fprintf(STDERR,"You must specify a RW volume name or ID "
3228                             "(the entire VLDB entry will be deleted)\n", itp->data);
3229              PrintError("",vcode);
3230              totalFail++;
3231              continue;
3232           }
3233           totalBack++;
3234        }
3235        fprintf(STDOUT,"Deleted %d VLDB entries\n", totalBack);
3236        return(totalFail);
3237     }
3238
3239     if (!as->parms[1].items && !as->parms[2].items && !as->parms[3].items) {
3240        fprintf(STDERR,"You must specify an option\n");
3241        exit(-2);
3242     }
3243
3244     /* Zero out search attributes */
3245     memset(&attributes, 0, sizeof(struct VldbListByAttributes));
3246
3247     if (as->parms[1].items) { /* -prefix */
3248        strncpy(prefix, as->parms[1].items->data, VOLSER_MAXVOLNAME);
3249        seenprefix = 1;
3250        if (!as->parms[2].items && !as->parms[3].items) { /* a single entry only */
3251           fprintf(STDERR,"You must provide -server with the -prefix argument\n");
3252           exit(-2);
3253        }
3254     }
3255
3256     if (as->parms[2].items) { /* -server */
3257        afs_int32 aserver;
3258        aserver = GetServer(as->parms[2].items->data);
3259        if (aserver == 0) {
3260           fprintf(STDERR,"vos: server '%s' not found in host table\n",as->parms[2].items->data );
3261           exit(-1);
3262        }
3263        attributes.server = ntohl(aserver);
3264        attributes.Mask |= VLLIST_SERVER;
3265     }
3266     
3267     if (as->parms[3].items) { /* -partition */
3268        if (!as->parms[2].items) {
3269           fprintf(STDERR,"You must provide -server with the -partition argument\n");
3270           exit(-2);
3271        }
3272        apart = volutil_GetPartitionID(as->parms[3].items->data);
3273        if (apart < 0) {
3274           fprintf(STDERR,"vos: could not interpret partition name '%s'\n",
3275                   as->parms[3].items->data);
3276           exit(-1);
3277         }
3278        attributes.partition = apart;
3279        attributes.Mask |= VLLIST_PARTITION;
3280     }
3281
3282     /* Print status line of what we are doing */
3283     fprintf(STDOUT,"Deleting VLDB entries for ");
3284     if (as->parms[2].items) {
3285        fprintf(STDOUT,"server %s ", as->parms[2].items->data);
3286     }
3287     if (as->parms[3].items) {
3288        char pname[10];
3289        MapPartIdIntoName(apart, pname);
3290        fprintf(STDOUT,"partition %s ", pname);
3291     }
3292     if (seenprefix) {
3293        fprintf(STDOUT,"which are prefixed with %s ", prefix);
3294     }
3295     fprintf(STDOUT,"\n");
3296     fflush(STDOUT);
3297
3298     /* Get all the VLDB entries on a server and/or partition */
3299     memset(&arrayEntries, 0, sizeof(arrayEntries));
3300     vcode = VLDB_ListAttributes(&attributes, &nentries, &arrayEntries);
3301     if (vcode) {
3302        fprintf(STDERR,"Could not access the VLDB for attributes\n");
3303        PrintError("",vcode);
3304        exit(-1);
3305     }
3306
3307     /* Process each entry */
3308     for (j=0; j<nentries; j++) {
3309        vllist = &arrayEntries.nbulkentries_val[j];
3310        if (seenprefix) {
3311           /* It only deletes the RW volumes */
3312           if (strncmp(vllist->name, prefix, strlen(prefix))){
3313              if (verbose) {
3314                 fprintf(STDOUT,"Omitting to delete %s due to prefix %s mismatch\n",
3315                         vllist->name, prefix);
3316              }
3317              fflush(STDOUT);
3318              continue;
3319           }
3320        }
3321                 
3322        if (as->parms[4].items) { /* -noexecute */
3323           fprintf(STDOUT,"Would have deleted VLDB entry for %s \n", vllist->name);
3324           fflush(STDOUT);
3325           continue;
3326        }
3327
3328        /* Only matches the RW volume name */
3329        avolid = vllist->volumeId[RWVOL];
3330        vcode = ubik_Call(VL_DeleteEntry, cstruct, 0, avolid, RWVOL);
3331        if (vcode){
3332           fprintf(STDOUT,"Could not delete VDLB entry for  %s\n",vllist->name);
3333           totalFail++;
3334           PrintError("",vcode);
3335           continue;
3336        } else {
3337           totalBack++;
3338           if (verbose)
3339              fprintf(STDOUT,"Deleted VLDB entry for %s \n",vllist->name);
3340        }
3341        fflush(STDOUT);
3342     } /*for*/
3343
3344     fprintf(STDOUT,"----------------------\n");
3345     fprintf(STDOUT,"Total VLDB entries deleted: %lu; failed to delete: %lu\n",
3346             (unsigned long) totalBack, (unsigned long) totalFail);
3347     if (arrayEntries.nbulkentries_val) free(arrayEntries.nbulkentries_val);
3348     return 0;
3349 }
3350
3351
3352 static int CompareVldbEntryByName(p1,p2)
3353 char *p1,*p2;
3354 {
3355     struct nvldbentry *arg1,*arg2;
3356
3357     arg1 = (struct nvldbentry *)p1;
3358     arg2 = (struct nvldbentry *)p2;
3359     return(strcmp(arg1->name,arg2->name));
3360 }
3361
3362 /*
3363 static int CompareVldbEntry(p1,p2)
3364 char *p1,*p2;
3365 {
3366     struct nvldbentry *arg1,*arg2;
3367     int i;
3368     int pos1, pos2;
3369     char comp1[100],comp2[100];
3370     char temp1[20],temp2[20];
3371
3372     arg1 = (struct nvldbentry *)p1;
3373     arg2 = (struct nvldbentry *)p2;
3374     pos1 = -1;
3375     pos2 = -1;
3376
3377     for(i = 0; i < arg1->nServers; i++)
3378         if(arg1->serverFlags[i] & ITSRWVOL) pos1 = i;
3379     for(i = 0; i < arg2->nServers; i++)
3380         if(arg2->serverFlags[i] & ITSRWVOL) pos2 = i;
3381     if(pos1 == -1 || pos2 == -1){
3382         pos1 = 0;
3383         pos2 = 0;
3384     }
3385     sprintf(comp1,"%10u",arg1->serverNumber[pos1]);
3386     sprintf(comp2,"%10u",arg2->serverNumber[pos2]);
3387     sprintf(temp1,"%10u",arg1->serverPartition[pos1]);
3388     sprintf(temp2,"%10u",arg2->serverPartition[pos2]);
3389     strcat(comp1,temp1);
3390     strcat(comp2,temp2);
3391     strcat(comp1,arg1->name);
3392     strcat(comp1,arg2->name);
3393     return(strcmp(comp1,comp2));
3394
3395 }
3396
3397 */      
3398 static ListVLDB(as)
3399     struct cmd_syndesc *as;
3400 {   
3401     afs_int32 apart;
3402     afs_int32 aserver,code;
3403     afs_int32 vcode;
3404     struct VldbListByAttributes attributes;
3405     nbulkentries arrayEntries;
3406     struct nvldbentry *vllist, *tarray=0, *ttarray;
3407     afs_int32 centries, nentries = 0, tarraysize, parraysize;
3408     int j;
3409     char pname[10];
3410     int quiet, sort, lock;
3411     afs_int32 thisindex, nextindex;
3412
3413     aserver = 0;
3414     apart = 0;
3415
3416     attributes.Mask = 0;
3417     lock   = (as->parms[3].items ? 1 : 0);  /* -lock   flag */
3418     quiet  = (as->parms[4].items ? 1 : 0);  /* -quit   flag */
3419     sort   = (as->parms[5].items ? 0 : 1);  /* -nosort flag */
3420
3421     /* If the volume name is given, Use VolumeInfoCmd to look it up
3422      * and not ListAttributes.
3423      */
3424     if (as->parms[0].items) {
3425        if (lock) {
3426           fprintf(STDERR,"vos: illegal use of '-locked' switch, need to specify server and/or partition\n");
3427           exit(1);
3428        }
3429        code = VolumeInfoCmd(as->parms[0].items->data);
3430        if (code) {
3431           PrintError("",code);
3432           exit(1);
3433        }
3434        return 0;
3435     }
3436
3437     /* Server specified */
3438     if (as->parms[1].items) {
3439        aserver = GetServer(as->parms[1].items->data);
3440        if (aserver == 0) {
3441           fprintf(STDERR,"vos: server '%s' not found in host table\n",as->parms[1].items->data );
3442           exit(1);
3443        }
3444        attributes.server = ntohl(aserver);
3445        attributes.Mask |= VLLIST_SERVER;
3446     }
3447     
3448     /* Partition specified */
3449     if (as->parms[2].items) {
3450        apart = volutil_GetPartitionID(as->parms[2].items->data);
3451        if (apart < 0) {
3452           fprintf(STDERR,"vos: could not interpret partition name '%s'\n", as->parms[2].items->data);
3453           exit(1);
3454        }
3455        attributes.partition = apart;
3456        attributes.Mask |= VLLIST_PARTITION;
3457     }
3458
3459     if (lock) {
3460        attributes.Mask |= VLLIST_FLAG;
3461        attributes.flag =  VLOP_ALLOPERS;
3462     }
3463
3464     /* Print header information */
3465     if (!quiet) {
3466        MapPartIdIntoName(apart, pname);
3467        fprintf(STDOUT,"VLDB entries for %s %s%s%s %s\n",
3468                (as->parms[1].items ? "server"                 : "all"    ),
3469                (as->parms[1].items ? as->parms[1].items->data : "servers"),
3470                (as->parms[2].items ? " partition "            : ""),
3471                (as->parms[2].items ? pname                    : ""),
3472                (lock               ? "which are locked:"      : ""));
3473     }
3474
3475     for (thisindex = 0; (thisindex != -1); thisindex = nextindex) {
3476        memset(&arrayEntries, 0, sizeof(arrayEntries));
3477        centries = 0;
3478        nextindex = -1;
3479
3480        vcode = VLDB_ListAttributesN2(&attributes, 0, thisindex,
3481                                      &centries, &arrayEntries, &nextindex);
3482        if (vcode == RXGEN_OPCODE) {
3483           /* Vlserver not running with ListAttributesN2. Fall back */
3484           vcode = VLDB_ListAttributes(&attributes, &centries, &arrayEntries);
3485           nextindex = -1;
3486        }
3487        if (vcode) {
3488           fprintf(STDERR,"Could not access the VLDB for attributes\n");
3489           PrintError("",vcode);
3490           exit(1);
3491        }
3492        nentries += centries;
3493
3494        /* We don't sort, so just print the entries now */
3495        if (!sort) {
3496           for (j = 0; j < centries; j++) {                   /* process each entry */
3497              vllist = &arrayEntries.nbulkentries_val[j];
3498              MapHostToNetwork(vllist);
3499              EnumerateEntry(vllist);
3500
3501              if(vllist->flags & VLOP_ALLOPERS)
3502                 fprintf(STDOUT,"    Volume is currently LOCKED  \n");
3503           }
3504        } 
3505
3506        /* So we sort. First we must collect all the entries and keep
3507         * them in memory.
3508         */
3509        else if (centries > 0) {
3510           if (!tarray) {
3511              /* steal away the first bulk entries array */
3512              tarray = (struct nvldbentry *)arrayEntries.nbulkentries_val;
3513              tarraysize = centries * sizeof(struct nvldbentry);
3514              arrayEntries.nbulkentries_val = 0;
3515           } else {
3516              /* Grow the tarray to keep the extra entries */
3517              parraysize = (centries * sizeof(struct nvldbentry));
3518              ttarray = (struct nvldbentry *) realloc(tarray, tarraysize + parraysize);
3519              if (!ttarray) {
3520                 fprintf(STDERR,"Could not allocate enough space for  the VLDB entries\n");
3521                 goto bypass;
3522              }
3523              tarray = ttarray;
3524              
3525              /* Copy them in */
3526              memcpy(((char *)tarray)+tarraysize, (char *)arrayEntries.nbulkentries_val, parraysize);
3527              tarraysize += parraysize;
3528           }
3529        }
3530
3531        /* Free the bulk array */
3532        if (arrayEntries.nbulkentries_val) {
3533           free(arrayEntries.nbulkentries_val);
3534           arrayEntries.nbulkentries_val = 0;
3535        }
3536     }
3537
3538     /* Here is where we now sort all the entries and print them */
3539     if (sort && (nentries > 0)) {
3540        qsort((char *)tarray, nentries, sizeof(struct nvldbentry), CompareVldbEntryByName);
3541        for (vllist=tarray, j=0; j<nentries; j++, vllist++) {
3542           MapHostToNetwork(vllist);
3543           EnumerateEntry(vllist);
3544
3545           if(vllist->flags & VLOP_ALLOPERS)
3546              fprintf(STDOUT,"    Volume is currently LOCKED  \n");
3547        }
3548     }
3549
3550 bypass:
3551     if (!quiet) fprintf(STDOUT,"\nTotal entries: %lu\n",
3552                         (unsigned long) nentries);
3553     if (tarray) free(tarray);
3554     return 0;
3555 }
3556
3557 static BackSys(as)
3558     register struct cmd_syndesc *as;
3559 {   
3560     afs_int32 apart=0, avolid;
3561     afs_int32 aserver=0, code, aserver1, apart1;
3562     afs_int32 vcode;
3563     struct VldbListByAttributes attributes;
3564     nbulkentries arrayEntries;
3565     register struct nvldbentry *vllist;
3566     afs_int32 nentries;
3567     int j;
3568     char pname[10];
3569     int seenprefix, seenxprefix, exclude, ex, exp, noaction;
3570     afs_int32 totalBack=0;
3571     afs_int32 totalFail=0;
3572     int previdx=-1, error, same;
3573     int comp=0;
3574     char compstr[50];
3575     struct cmd_item *ti;
3576     char *ccode;
3577     int match;
3578
3579     memset(&attributes, 0, sizeof(struct VldbListByAttributes));
3580     attributes.Mask = 0;
3581
3582     seenprefix  = (as->parms[0].items ? 1 : 0);
3583     exclude     = (as->parms[3].items ? 1 : 0);
3584     seenxprefix = (as->parms[4].items ? 1 : 0);
3585     noaction    = (as->parms[5].items ? 1 : 0);
3586
3587     if (as->parms[1].items) {                         /* -server */
3588         aserver = GetServer(as->parms[1].items->data);
3589         if (aserver == 0) {
3590             fprintf(STDERR,"vos: server '%s' not found in host table\n",as->parms[1].items->data );
3591             exit(1);
3592         }
3593         attributes.server  = ntohl(aserver);
3594         attributes.Mask   |= VLLIST_SERVER;
3595     }
3596
3597     if (as->parms[2].items) {                         /* -partition */
3598         apart = volutil_GetPartitionID(as->parms[2].items->data);
3599         if (apart < 0) {
3600             fprintf(STDERR,"vos: could not interpret partition name '%s'\n", as->parms[2].items->data);
3601             exit(1);
3602         }
3603         attributes.partition  = apart;
3604         attributes.Mask      |= VLLIST_PARTITION;
3605     }
3606
3607     /* Check to make sure the prefix and xprefix expressions compile ok */
3608     if (seenprefix) {
3609        for (ti=as->parms[0].items; ti; ti=ti->next) {
3610           if (strncmp(ti->data,"^",1) == 0) {
3611              ccode = (char *)re_comp(ti->data);
3612              if (ccode) {
3613                 fprintf(STDERR,"Unrecognizable -prefix regular expression: '%s': %s\n",
3614                         ti->data, ccode);
3615                 exit(1);        
3616              }
3617           }
3618        }
3619     }
3620     if (seenxprefix) {
3621        for (ti=as->parms[4].items; ti; ti=ti->next) {
3622           if (strncmp(ti->data,"^",1) == 0) {
3623              ccode = (char *)re_comp(ti->data);
3624              if (ccode) {
3625                 fprintf(STDERR,"Unrecognizable -xprefix regular expression: '%s': %s\n",
3626                         ti->data, ccode);
3627                 exit(1);        
3628              }
3629           }
3630        }
3631     }
3632
3633     memset(&arrayEntries, 0, sizeof(arrayEntries)); /* initialize to hint the stub to alloc space */
3634     vcode = VLDB_ListAttributes(&attributes, &nentries, &arrayEntries);
3635     if (vcode) {
3636         fprintf(STDERR,"Could not access the VLDB for attributes\n");
3637         PrintError("",vcode);
3638         exit(1);
3639     }
3640
3641     if (as->parms[1].items || as->parms[2].items || verbose) {
3642         fprintf(STDOUT,"%s up volumes", (noaction?"Would have backed":"Backing"));
3643
3644         if (as->parms[1].items) {
3645             fprintf(STDOUT," on server %s", as->parms[1].items->data);
3646         } else if (as->parms[2].items) {
3647             fprintf(STDOUT," for all servers");
3648         }
3649
3650         if (as->parms[2].items) {
3651             MapPartIdIntoName(apart, pname);
3652             fprintf(STDOUT," partition %s", pname);
3653         }
3654
3655         if (seenprefix || (!seenprefix && seenxprefix)) {
3656             ti  = (seenprefix ? as->parms[0].items : as->parms[4].items);
3657             ex  = (seenprefix ? exclude : !exclude);
3658             exp = (strncmp(ti->data,"^",1) == 0);
3659             fprintf(STDOUT," which %smatch %s '%s'", (ex ? "do not " : ""),
3660                     (exp?"expression":"prefix"), ti->data);
3661             for (ti=ti->next; ti; ti=ti->next) {
3662                exp = (strncmp(ti->data,"^",1) == 0);
3663                printf(" %sor %s '%s'", (ex ? "n" : ""),
3664                       (exp?"expression":"prefix"), ti->data);
3665             }
3666         }
3667
3668         if (seenprefix && seenxprefix) {
3669             ti  = as->parms[4].items;
3670             exp = (strncmp(ti->data,"^",1) == 0);
3671             fprintf(STDOUT," %swhich match %s '%s'",
3672                     (exclude?"adding those ":"removing those "),
3673                     (exp?"expression":"prefix"), ti->data);
3674             for (ti=ti->next; ti; ti=ti->next) {
3675                exp = (strncmp(ti->data,"^",1) == 0);
3676                printf(" or %s '%s'", (exp?"expression":"prefix"), ti->data);
3677             }
3678         }
3679         fprintf(STDOUT," .. ");
3680         if (verbose) fprintf(STDOUT,"\n");
3681         fflush(STDOUT);
3682     }
3683
3684     for (j=0; j<nentries; j++) {        /* process each vldb entry */
3685         vllist = &arrayEntries.nbulkentries_val[j];
3686
3687         if (seenprefix) {
3688            for (ti=as->parms[0].items; ti; ti=ti->next) {
3689               if (strncmp(ti->data,"^",1) == 0) {
3690                  ccode = (char *)re_comp(ti->data);
3691                  if (ccode) {
3692                     fprintf(STDERR,"Error in -prefix regular expression: '%s': %s\n",
3693                             ti->data, ccode);
3694                     exit(1);    
3695                  }
3696                  match = (re_exec(vllist->name) == 1);
3697               } else {
3698                  match = (strncmp(vllist->name,ti->data,strlen(ti->data)) == 0);
3699               }
3700               if (match) break;
3701            }
3702         } else {
3703            match = 1;
3704         }
3705         
3706         /* Without the -exclude flag: If it matches the prefix, then
3707          *    check if we want to exclude any from xprefix.
3708          * With the -exclude flag: If it matches the prefix, then
3709          *    check if we want to add any from xprefix.
3710          */
3711         if (match && seenxprefix) {
3712            for (ti=as->parms[4].items; ti; ti=ti->next) {
3713               if (strncmp(ti->data,"^",1) == 0) {
3714                  ccode = (char *)re_comp(ti->data);
3715                  if (ccode) {
3716                     fprintf(STDERR,"Error in -xprefix regular expression: '%s': %s\n",
3717                             ti->data, ccode);
3718                     exit(1);    
3719                  }
3720                  if (re_exec(vllist->name) == 1) {
3721                     match = 0;
3722                     break;
3723                  }
3724               } else {
3725                  if (strncmp(vllist->name,ti->data,strlen(ti->data)) == 0) {
3726                    match = 0;
3727                    break;
3728                  }
3729               }
3730            }
3731         }
3732
3733         if (exclude) match = !match;     /* -exclude will reverse the match */
3734         if (!match) continue;             /* Skip if no match */
3735
3736         /* Print list of volumes to backup */
3737         if (noaction) {
3738             fprintf(STDOUT,"     %s\n", vllist->name);
3739             continue;
3740         }
3741
3742         if(!(vllist->flags & RW_EXISTS)){
3743             if(verbose) {
3744                 fprintf(STDOUT,"Omitting to backup %s since RW volume does not exist \n", vllist->name);
3745                 fprintf(STDOUT,"\n");
3746             }
3747             fflush(STDOUT);
3748             continue;
3749         }
3750         
3751         avolid = vllist->volumeId[RWVOL];
3752         MapHostToNetwork(vllist);
3753         GetServerAndPart(vllist,RWVOL,&aserver1,&apart1,&previdx);
3754         if(aserver1 == -1 || apart1 == -1){
3755             fprintf(STDOUT,"could not backup %s, invalid VLDB entry\n",vllist->name);
3756             totalFail++;
3757             continue;
3758         }
3759         if (aserver) {
3760             same = VLDB_IsSameAddrs(aserver, aserver1, &error);
3761             if (error) {
3762                 fprintf(STDERR,"Failed to get info about server's %d address(es) from vlserver (err=%d); aborting call!\n", 
3763                         aserver, error);
3764                 totalFail++;
3765                 continue;
3766             }
3767         }
3768         if ((aserver && !same) || (apart && (apart != apart1))) {
3769             if(verbose) {
3770                 fprintf(STDOUT, "Omitting to backup %s since the RW is in a different location\n", vllist->name);
3771             }
3772             continue;
3773         }
3774         if(verbose){
3775             time_t now = time(0);
3776             fprintf(STDOUT,"Creating backup volume for %s on %s",vllist->name, ctime(&now));
3777             fflush(STDOUT);
3778         }
3779
3780         code = UV_BackupVolume(aserver1, apart1, avolid);
3781         if (code) {
3782            fprintf(STDOUT,"Could not backup %s\n",vllist->name);
3783            totalFail++;
3784         }
3785         else {
3786             totalBack++;
3787         }
3788         if (verbose) fprintf(STDOUT,"\n");
3789         fflush(STDOUT);
3790     } /* process each vldb entry */
3791     fprintf(STDOUT,"done\n");
3792     fprintf(STDOUT,"Total volumes backed up: %lu; failed to backup: %lu\n",
3793             (unsigned long) totalBack, (unsigned long) totalFail);
3794     fflush(STDOUT);
3795     if(arrayEntries.nbulkentries_val) free(arrayEntries.nbulkentries_val);
3796     return 0;
3797 }
3798
3799 static UnlockVLDB(as)
3800 register struct cmd_syndesc *as;
3801 {   
3802     afs_int32 apart;
3803     afs_int32 aserver,code;
3804     afs_int32 vcode;
3805     struct VldbListByAttributes attributes;
3806     nbulkentries arrayEntries;
3807     register struct nvldbentry *vllist;
3808     afs_int32 nentries;
3809     int j;
3810     afs_int32 volid;
3811     afs_int32 totalE;
3812     char pname[10];
3813
3814     apart = -1;
3815     totalE = 0;
3816     attributes.Mask = 0;
3817
3818     if(as->parms[0].items) {/* server specified */
3819         aserver = GetServer(as->parms[0].items->data);
3820         if (aserver == 0) {
3821             fprintf(STDERR,"vos: server '%s' not found in host table\n",as->parms[0].items->data );
3822             exit(1);
3823         }
3824         attributes.server = ntohl(aserver);
3825         attributes.Mask |= VLLIST_SERVER;
3826     }
3827     if(as->parms[1].items) {/* partition specified */
3828         apart = volutil_GetPartitionID(as->parms[1].items->data);
3829         if (apart < 0) {
3830             fprintf(STDERR,"vos: could not interpret partition name '%s'\n", as->parms[1].items->data);
3831             exit(1);
3832         }
3833         if (!IsPartValid(apart,aserver,&code)){/*check for validity of the partition */
3834             if(code) PrintError("",code);
3835             else fprintf(STDERR,"vos : partition %s does not exist on the server\n",as->parms[1].items->data);
3836             exit(1);
3837         }
3838         attributes.partition = apart;
3839         attributes.Mask |= VLLIST_PARTITION;
3840     }
3841     attributes.flag = VLOP_ALLOPERS;
3842     attributes.Mask |=  VLLIST_FLAG;
3843     memset(&arrayEntries, 0, sizeof(arrayEntries)); /*initialize to hint the stub  to alloc space */
3844     vcode = VLDB_ListAttributes(&attributes, &nentries, &arrayEntries);
3845     if(vcode) {
3846         fprintf(STDERR,"Could not access the VLDB for attributes\n");
3847         PrintError("",vcode);
3848         exit(1);
3849     }
3850     for(j=0;j<nentries;j++) {   /* process each entry */
3851         vllist = &arrayEntries.nbulkentries_val[j];
3852         volid = vllist->volumeId[RWVOL];
3853         vcode = ubik_Call(VL_ReleaseLock,cstruct, 0, volid,-1, LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP);
3854         if(vcode){
3855             fprintf(STDERR,"Could not unlock entry for volume %s\n",vllist->name);
3856             PrintError("",vcode);
3857             totalE++;
3858         }
3859             
3860     }
3861     MapPartIdIntoName(apart,pname);
3862     if(totalE) fprintf(STDOUT,"Could not lock %lu VLDB entries of %lu locked entries\n", (unsigned long) totalE, (unsigned long) nentries);
3863     else {
3864         if(as->parms[0].items) {
3865             fprintf(STDOUT,"Unlocked all the VLDB entries for volumes on server %s ",as->parms[0].items->data);
3866             if(as->parms[1].items){
3867                 MapPartIdIntoName(apart,pname);
3868                 fprintf(STDOUT,"partition %s\n",pname);
3869             }
3870             else  fprintf(STDOUT,"\n");
3871
3872         }
3873         else if(as->parms[1].items){
3874             MapPartIdIntoName(apart,pname);
3875             fprintf(STDOUT,"Unlocked all the VLDB entries for volumes on partition %s on all servers\n",pname);
3876         }
3877     }
3878     
3879     if(arrayEntries.nbulkentries_val) free(arrayEntries.nbulkentries_val);
3880     return 0;
3881 }
3882
3883 static PartitionInfo(as)
3884 register struct cmd_syndesc *as;
3885 {   
3886     afs_int32 apart;
3887     afs_int32 aserver,code;
3888     char pname[10];
3889     struct diskPartition partition;
3890     struct partList dummyPartList;
3891     int i, cnt;
3892
3893     apart = -1;
3894     aserver = GetServer(as->parms[0].items->data);
3895     if (aserver == 0) {
3896         fprintf(STDERR,"vos: server '%s' not found in host table\n",as->parms[0].items->data );
3897         exit(1);
3898     }
3899     if(as->parms[1].items){
3900         apart = volutil_GetPartitionID(as->parms[1].items->data);
3901         if (apart < 0) {
3902             fprintf(STDERR,"vos: could not interpret partition name '%s'\n", as->parms[1].items->data);
3903             exit(1);
3904         }
3905         dummyPartList.partId[0] = apart;
3906         dummyPartList.partFlags[0] = PARTVALID;
3907         cnt = 1;
3908     }
3909     if(apart != -1) {
3910         if (!IsPartValid(apart,aserver,&code)){/*check for validity of the partition */
3911             if(code) PrintError("",code);
3912             else fprintf(STDERR,"vos : partition %s does not exist on the server\n",as->parms[1].items->data);
3913             exit(1);
3914         }
3915     }
3916     else {
3917         code = UV_ListPartitions(aserver,&dummyPartList, &cnt);
3918         if (code) {
3919             PrintDiagnostics("listpart", code);
3920             exit(1);
3921         }
3922     }
3923     for(i = 0 ; i < cnt ; i++){
3924         if(dummyPartList.partFlags[i] & PARTVALID){
3925             MapPartIdIntoName(dummyPartList.partId[i],pname);
3926             code = UV_PartitionInfo(aserver,pname,&partition);
3927             if(code){
3928                 fprintf(STDERR,"Could not get information on partition %s\n",pname);
3929                 PrintError("",code);
3930                 exit(1);
3931             }
3932             fprintf(STDOUT,"Free space on partition %s: %d K blocks out of total %d\n",pname,partition.free,partition.minFree);
3933         }
3934     }
3935     return 0;
3936 }
3937
3938 static ChangeAddr(as)
3939 register struct cmd_syndesc *as;
3940
3941 {
3942     afs_int32 ip1, ip2, vcode;
3943     int remove=0;
3944
3945     ip1 = GetServer(as->parms[0].items->data);
3946     if (!ip1) {
3947       fprintf(STDERR, "vos: invalid host address\n");
3948       return( EINVAL );
3949     }
3950
3951     if ( ( as->parms[1].items &&  as->parms[2].items) ||
3952          (!as->parms[1].items && !as->parms[2].items) ) {
3953        fprintf(STDERR, "vos: Must specify either '-newaddr <addr>' or '-remove' flag\n");
3954        return(EINVAL);
3955     }
3956
3957     if (as->parms[1].items) {
3958        ip2 = GetServer(as->parms[1].items->data);
3959        if (!ip2) {
3960           fprintf(STDERR, "vos: invalid host address\n");
3961           return( EINVAL );
3962        }
3963     } else {
3964        /* Play a trick here. If we are removing an address, ip1 will be -1
3965         * and ip2 will be the original address. This switch prevents an 
3966         * older revision vlserver from removing the IP address.
3967         */
3968        remove = 1;
3969        ip2 = ip1;
3970        ip1 = 0xffffffff;
3971     }
3972
3973     vcode = ubik_Call_New(VL_ChangeAddr, cstruct, 0, ntohl(ip1), ntohl(ip2) );
3974     if (vcode) {
3975         if (remove) {
3976            fprintf(STDERR,"Could not remove server %s from the VLDB\n",
3977                    as->parms[0].items->data);
3978            if (vcode == VL_NOENT) {
3979               fprintf(STDERR, "vlserver does not support the remove flag or ");
3980            }
3981         } else {
3982            fprintf(STDERR,"Could not change server %s to server %s\n", 
3983                    as->parms[0].items->data, as->parms[1].items->data);
3984         }
3985         PrintError("",vcode);
3986         return( vcode );
3987     }
3988
3989     if (remove) {
3990        fprintf(STDOUT,"Removed server %s from the VLDB\n",
3991                as->parms[0].items->data);
3992     } else {
3993        fprintf(STDOUT,"Changed server %s to server %s\n",
3994                as->parms[0].items->data, as->parms[1].items->data);
3995     }
3996     return 0;
3997 }
3998
3999 static void
4000 print_addrs(const bulkaddrs *addrs, const afsUUID *m_uuid, int nentries, int print, int noresolve)
4001 {
4002   afs_int32 vcode;
4003   afs_int32 i, j;
4004   struct VLCallBack    unused;
4005   afs_int32            *addrp;
4006   bulkaddrs            m_addrs;
4007   ListAddrByAttributes m_attrs;
4008   afs_int32            m_unique, m_nentries, *m_addrp;
4009   afs_int32            base, index;
4010   char buf[1024];
4011
4012   if (print) {
4013       afsUUID_to_string(m_uuid, buf, sizeof(buf));
4014       printf("UUID: %s\n", buf);
4015   }
4016
4017   /* print out the list of all the server */
4018   addrp = (afs_int32 *)addrs->bulkaddrs_val;
4019   for (i=0; i<nentries; i++, addrp++) {
4020      /* If it is a multihomed address, then we will need to 
4021       * get the addresses for this multihomed server from
4022       * the vlserver and print them.
4023       */
4024      if ( ((*addrp & 0xff000000) == 0xff000000) && ((*addrp)&0xffff) ) {
4025         /* Get the list of multihomed fileservers */
4026         base =  (*addrp>>16) & 0xff;
4027         index = (*addrp)     & 0xffff;
4028
4029         if ( (base  >= 0) && (base  <= VL_MAX_ADDREXTBLKS) &&
4030              (index >= 1) && (index <= VL_MHSRV_PERBLK)    ) {
4031            m_attrs.Mask  = VLADDR_INDEX;
4032            m_attrs.index = (base * VL_MHSRV_PERBLK) + index;
4033            m_nentries            = 0;
4034            m_addrs.bulkaddrs_val = 0;
4035            m_addrs.bulkaddrs_len = 0;
4036            vcode = ubik_Call(VL_GetAddrsU, cstruct, 0,
4037                              &m_attrs, &m_uuid, &m_unique, &m_nentries, &m_addrs);
4038            if (vcode) {
4039               fprintf(STDERR,"vos: could not list the multi-homed server addresses\n");
4040               PrintError("",vcode);
4041            }
4042
4043            /* Print the list */
4044            m_addrp = (afs_int32 *)m_addrs.bulkaddrs_val;
4045            for (j=0; j<m_nentries; j++, m_addrp++) {
4046               *m_addrp = htonl(*m_addrp);       
4047               if (noresolve) {
4048                   char hoststr[16];
4049                   printf("%s ", afs_inet_ntoa_r(*m_addrp,hoststr));
4050               } else {
4051                   printf("%s ", hostutil_GetNameByINet(*m_addrp));
4052               }
4053            }
4054            if (j==0) {
4055               printf("<unknown>\n");
4056            } else {
4057               printf("\n");
4058            }
4059
4060            continue;
4061         }
4062      }
4063
4064      /* Otherwise, it is a non-multihomed entry and contains
4065       * the IP address of the server - print it.
4066       */
4067      *addrp = htonl(*addrp);    
4068      if (noresolve) {
4069          char hoststr[16];
4070          printf("%s\n", afs_inet_ntoa_r(*addrp,hoststr));
4071      } else {
4072          printf("%s\n", hostutil_GetNameByINet(*addrp));
4073      }
4074   }
4075
4076   if (print) {
4077       printf("\n");
4078   }
4079   return;
4080 }
4081
4082 static ListAddrs(as)
4083 register struct cmd_syndesc *as;
4084 {
4085   afs_int32 vcode;
4086   afs_int32 i, j, noresolve=0, printuuid=0;
4087   struct VLCallBack    unused;
4088   afs_int32                nentries, *addrp;
4089   bulkaddrs            addrs, m_addrs;
4090   ListAddrByAttributes m_attrs;
4091   afsUUID              m_uuid, askuuid;
4092   afs_int32                m_unique, m_nentries, *m_addrp;
4093   afs_int32                base, index;
4094
4095   memset(&m_attrs, 0, sizeof(struct ListAddrByAttributes));
4096   m_attrs.Mask = VLADDR_INDEX;
4097
4098   memset(&m_addrs, 0, sizeof(bulkaddrs));
4099   memset(&askuuid, 0, sizeof(afsUUID));
4100   if (as->parms[0].items) {
4101       /* -uuid */
4102       afsUUID_from_string(as->parms[0].items->data, &askuuid);
4103       m_attrs.Mask = VLADDR_UUID;
4104       m_attrs.uuid = askuuid;
4105   }
4106   if (as->parms[1].items) {
4107       /* -host */
4108       struct hostent       *he; 
4109       afs_int32 saddr;
4110       he = hostutil_GetHostByName((char*)as->parms[1].items->data);
4111       if (he == NULL) {
4112           fprintf(stderr,
4113                   "Can't get host info for '%s'\n",
4114                   as->parms[1].items->data);
4115           exit(-1);
4116       }
4117       memcpy(&saddr, he->h_addr, 4);
4118       m_attrs.Mask = VLADDR_IPADDR;
4119       m_attrs.ipaddr = ntohl(saddr);
4120   }
4121   if (as->parms[2].items) {
4122       noresolve=1;
4123   }
4124   if (as->parms[3].items) {
4125       printuuid=1;
4126   }
4127
4128   m_addrs.bulkaddrs_val = 0;
4129   m_addrs.bulkaddrs_len = 0;
4130
4131   vcode = ubik_Call_New(VL_GetAddrs, cstruct, 0,
4132                         0, 0, &m_unique, &nentries, &m_addrs);
4133   if (vcode) {
4134     fprintf(STDERR,"vos: could not list the server addresses\n");
4135     PrintError("",vcode);
4136     return( vcode );
4137   }
4138
4139   m_nentries            = 0;
4140   m_addrs.bulkaddrs_val = 0;
4141   m_addrs.bulkaddrs_len = 0;
4142   i=1;
4143   while (1) {
4144       m_attrs.index = i;
4145
4146       vcode = ubik_Call_New(VL_GetAddrsU, cstruct, 0, &m_attrs, &m_uuid, 
4147                         &m_unique, &m_nentries, &m_addrs);
4148       if(vcode == VL_NOENT) {
4149           i++;
4150           nentries++;
4151           continue;
4152       }
4153
4154       if (vcode == VL_INDEXERANGE) {
4155           break;
4156       }
4157
4158       if (vcode) {
4159           fprintf(STDERR,"vos: could not list the server addresses\n");
4160           PrintError("",vcode);
4161           return( vcode );
4162       }
4163
4164       print_addrs(&m_addrs, &m_uuid, m_nentries, printuuid, noresolve);
4165       i++;
4166
4167       if ((as->parms[1].items)||(as->parms[0].items)||(i>nentries))
4168           break;
4169   }
4170     
4171   return 0;
4172 }
4173
4174 static LockEntry(as)
4175 register struct cmd_syndesc *as;
4176
4177 {
4178     afs_int32 avolid,vcode, err;
4179
4180     avolid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);
4181     if (avolid == 0) {
4182         if (err) PrintError("", err);
4183         else fprintf(STDERR, "vos: can't find volume '%s'\n", as->parms[0].items->data);
4184         exit(1);
4185     }
4186     vcode = ubik_Call(VL_SetLock,cstruct, 0, avolid, -1, VLOP_DELETE);
4187     if(vcode){
4188         fprintf(STDERR,"Could not lock VLDB entry for volume %s\n",as->parms[0].items->data);
4189         PrintError("",vcode);
4190         exit(1);
4191     }
4192     fprintf(STDOUT,"Locked VLDB entry for volume %s\n",as->parms[0].items->data);
4193     return 0;
4194 }
4195
4196 static ConvertRO(as)
4197 register struct cmd_syndesc *as;
4198
4199 {
4200     afs_int32 partition = -1;
4201     afs_int32 server, volid, code, i, same;
4202     struct nvldbentry entry, storeEntry;
4203     afs_int32 vcode;
4204     afs_int32 rwindex;
4205     afs_int32 rwserver = 0;
4206     afs_int32 rwpartition;
4207     afs_int32 roindex;
4208     afs_int32 roserver = 0;
4209     afs_int32 ropartition;
4210     int force = 0;
4211     struct rx_connection *aconn;
4212     char c, dc;
4213
4214     server = GetServer(as->parms[0].items->data);
4215     if (!server) {
4216         fprintf(STDERR,"vos: host '%s' not found in host table\n",as->parms[0].items->data );
4217         return ENOENT;
4218     }
4219      partition = volutil_GetPartitionID(as->parms[1].items->data);
4220     if (partition < 0) {
4221         fprintf(STDERR,"vos: could not interpret partition name '%s'\n",as->parms[1].items->data );
4222         return ENOENT;
4223     }
4224     if (!IsPartValid(partition, server, &code)) {
4225         if(code) PrintError("",code);
4226         else fprintf(STDERR,"vos : partition %s does not exist on the server\n",as->parms[1].items->data);
4227         return ENOENT;
4228     }
4229     volid = vsu_GetVolumeID(as->parms[2].items->data, cstruct, &code);
4230     if (volid == 0) {
4231         if (code) PrintError("", code);
4232         else fprintf(STDERR, "Unknown volume ID or name '%s'\n", as->parms[0].items->data);
4233         return -1;
4234     }
4235     if (as->parms[3].items)
4236         force = 1;
4237
4238     vcode = VLDB_GetEntryByID (volid, -1, &entry);
4239     if(vcode) {
4240         fprintf(STDERR,"Could not fetch the entry for volume %lu from VLDB\n",
4241                 (unsigned long) volid);
4242         PrintError("convertROtoRW", code);
4243         return vcode;
4244     }
4245
4246     /* use RO volid even if user specified RW or BK volid */
4247
4248     if (volid != entry.volumeId[ROVOL])
4249         volid = entry.volumeId[ROVOL];
4250
4251     MapHostToNetwork(&entry);
4252     for (i=0; i< entry.nServers; i++) {
4253         if (entry.serverFlags[i] & ITSRWVOL) {
4254             rwindex = i;
4255             rwserver = entry.serverNumber[i];
4256             rwpartition = entry.serverPartition[i];
4257         }
4258         if (entry.serverFlags[i] & ITSROVOL) {
4259             same = VLDB_IsSameAddrs(server, entry.serverNumber[i], &code);
4260             if (code) {
4261                 fprintf(STDERR, "Failed to get info about server's %d address(es) from vlserver (err=%d); aborting call!\n",
4262                                 server, code);
4263                 return ENOENT;
4264             }
4265             if (same) {
4266                 roindex = i;
4267                 roserver = entry.serverNumber[i];
4268                 ropartition = entry.serverPartition[i];
4269                 break;
4270             }
4271         }
4272     }
4273     if (!roserver) {
4274         fprintf(STDERR, "Warning: RO volume didn't exist in vldb!\n");
4275     }
4276     if (ropartition != partition) {
4277         fprintf(STDERR, "Warning: RO volume should be in partition %d instead of %d (vldb)\n", ropartition, partition);
4278     }
4279
4280     if (rwserver) {
4281         fprintf(STDERR,
4282                 "VLDB indicates that a RW volume exists already on %s in partition %s.\n", hostutil_GetNameByINet(rwserver), volutil_PartitionName(rwpartition));
4283         if (!force) {
4284             fprintf(STDERR, "Overwrite this VLDB entry? [y|n] (n)\n");
4285             dc = c = getchar();
4286             while (!(dc==EOF || dc=='\n')) dc=getchar(); /* goto end of line */
4287             if ((c != 'y') && (c != 'Y')) {
4288                fprintf(STDERR, "aborted.\n");
4289                return -1;
4290             }
4291         }
4292     }
4293
4294     vcode = ubik_Call(VL_SetLock, cstruct, 0, entry.volumeId[RWVOL], RWVOL,
4295                                                         VLOP_MOVE);
4296     aconn = UV_Bind(server, AFSCONF_VOLUMEPORT);
4297     code = AFSVolConvertROtoRWvolume(aconn, partition, volid);
4298     if (code) {
4299         fprintf(STDERR,"Converting RO volume %lu to RW volume failed with code %d\n", (unsigned long) volid, code);
4300         PrintError("convertROtoRW ", code);
4301         return -1;
4302     }
4303     entry.serverFlags[roindex] = ITSRWVOL;
4304     entry.flags |= RW_EXISTS;
4305     entry.flags &= ~BACK_EXISTS;
4306     if (rwserver) {
4307         (entry.nServers)--;
4308         if (rwindex != entry.nServers) {
4309             entry.serverNumber[rwindex] = entry.serverNumber[entry.nServers];
4310             entry.serverPartition[rwindex] = entry.serverPartition[entry.nServers];
4311             entry.serverFlags[rwindex] = entry.serverFlags[entry.nServers];
4312             entry.serverNumber[entry.nServers] = 0;
4313             entry.serverPartition[entry.nServers] = 0;
4314             entry.serverFlags[entry.nServers] = 0;
4315         }
4316     }
4317     entry.flags &= ~RO_EXISTS;
4318     for (i=0; i<entry.nServers; i++) {
4319         if (entry.serverFlags[i] & ITSROVOL) {
4320             if (!(entry.serverFlags[i] & (RO_DONTUSE | NEW_REPSITE)))
4321                 entry.flags |= RO_EXISTS;
4322         }
4323     }
4324     MapNetworkToHost(&entry, &storeEntry);
4325     code = VLDB_ReplaceEntry(entry.volumeId[RWVOL], RWVOL, &storeEntry,
4326                        (LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP));
4327     if (code)  {
4328         fprintf(STDERR, "Warning: volume converted, but vldb update failed with code %d!\n", code);
4329     }
4330     vcode = UV_LockRelease(entry.volumeId[RWVOL]);
4331     if (vcode) {
4332         PrintDiagnostics("unlock", vcode);
4333     }
4334     return code;
4335 }
4336
4337 PrintDiagnostics(astring, acode)
4338     char *astring;
4339     afs_int32 acode;
4340 {
4341     if (acode == EACCES) {
4342         fprintf(STDERR,"You are not authorized to perform the 'vos %s' command (%d)\n",
4343                 astring, acode);
4344     }
4345     else {
4346         fprintf(STDERR,"Error in vos %s command.\n", astring);
4347         PrintError("", acode);
4348     }
4349     return 0;
4350 }
4351
4352
4353 static MyBeforeProc(as, arock)
4354 struct cmd_syndesc *as;
4355 char *arock; {
4356     register char *tcell;
4357     register afs_int32 code;
4358     register afs_int32 sauth;
4359
4360     /* Initialize the ubik_client connection */
4361     rx_SetRxDeadTime(90);
4362     cstruct = (struct ubik_client *)0;
4363
4364     sauth = 0;
4365     tcell = NULL;
4366     if (as->parms[12].items)    /* if -cell specified */
4367         tcell = as->parms[12].items->data;
4368     if(as->parms[14].items)     /* -serverauth specified */
4369         sauth = 1;
4370     if(as->parms[16].items)     /* -crypt specified */
4371         vsu_SetCrypt(1);
4372     if ((code = vsu_ClientInit((as->parms[13].items != 0), confdir, tcell, sauth,
4373                                &cstruct, UV_SetSecurity))) {
4374         fprintf(STDERR,"could not initialize VLDB library (code=%lu) \n",
4375                 (unsigned long) code);
4376         exit(1);
4377     }
4378     rxInitDone = 1;
4379     if(as->parms[15].items)     /* -verbose flag set */
4380         verbose = 1;
4381     else
4382         verbose = 0;
4383     return 0;
4384 }
4385
4386 int osi_audit()
4387 {
4388 /* this sucks but it works for now.
4389 */
4390 return 0;
4391 }
4392
4393 #include "AFS_component_version_number.c"
4394
4395 main(argc, argv)
4396 int argc;
4397 char **argv; {
4398   register afs_int32 code;
4399     
4400     register struct cmd_syndesc *ts;
4401
4402 #ifdef  AFS_AIX32_ENV
4403     /*
4404      * The following signal action for AIX is necessary so that in case of a 
4405      * crash (i.e. core is generated) we can include the user's data section 
4406      * in the core dump. Unfortunately, by default, only a partial core is
4407      * generated which, in many cases, isn't too useful.
4408      */
4409     struct sigaction nsa;
4410     
4411     sigemptyset(&nsa.sa_mask);
4412     nsa.sa_handler = SIG_DFL;
4413     nsa.sa_flags = SA_FULLDUMP;
4414     sigaction(SIGSEGV, &nsa, NULL);
4415 #endif
4416
4417     confdir = AFSDIR_CLIENT_ETC_DIRPATH;
4418
4419     cmd_SetBeforeProc(MyBeforeProc,  NULL);
4420
4421     ts = cmd_CreateSyntax("create", CreateVolume, 0, "create a new volume");
4422     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
4423     cmd_AddParm(ts, "-partition", CMD_SINGLE, 0, "partition name");
4424     cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "volume name");
4425     cmd_AddParm(ts, "-maxquota", CMD_SINGLE, CMD_OPTIONAL, "initial quota (KB)");
4426 #ifdef notdef
4427     cmd_AddParm(ts, "-minquota", CMD_SINGLE, CMD_OPTIONAL, "");
4428 #endif
4429     COMMONPARMS;
4430
4431     ts = cmd_CreateSyntax("remove", DeleteVolume, 0, "delete a volume");
4432     cmd_AddParm(ts, "-server", CMD_SINGLE, CMD_OPTIONAL, "machine name");
4433     cmd_AddParm(ts, "-partition", CMD_SINGLE, CMD_OPTIONAL, "partition name");
4434     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
4435
4436     COMMONPARMS;
4437
4438     ts = cmd_CreateSyntax("move", MoveVolume, 0, "move a volume");
4439     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
4440     cmd_AddParm(ts, "-fromserver", CMD_SINGLE, 0, "machine name on source");
4441     cmd_AddParm(ts, "-frompartition", CMD_SINGLE, 0, "partition name on source");
4442     cmd_AddParm(ts, "-toserver", CMD_SINGLE, 0, "machine name on destination");
4443     cmd_AddParm(ts, "-topartition", CMD_SINGLE, 0, "partition name on destination");
4444     COMMONPARMS;
4445
4446     ts = cmd_CreateSyntax("copy", CopyVolume, 0, "copy a volume");
4447     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID on source");
4448     cmd_AddParm(ts, "-fromserver", CMD_SINGLE, 0, "machine name on source");
4449     cmd_AddParm(ts, "-frompartition", CMD_SINGLE, 0, "partition name on source");
4450         cmd_AddParm(ts, "-toname", CMD_SINGLE, 0, "volume name on destination");
4451     cmd_AddParm(ts, "-toserver", CMD_SINGLE, 0, "machine name on destination");
4452     cmd_AddParm(ts, "-topartition", CMD_SINGLE, 0, "partition name on destination");
4453     COMMONPARMS;
4454
4455     ts = cmd_CreateSyntax("backup", BackupVolume, 0, "make backup of a volume");
4456     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
4457     COMMONPARMS;
4458
4459     ts = cmd_CreateSyntax("release", ReleaseVolume, 0, "release a volume");
4460     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
4461     cmd_AddParm(ts, "-force", CMD_FLAG, CMD_OPTIONAL, "force a complete release");
4462     COMMONPARMS;
4463
4464     ts = cmd_CreateSyntax("dump", DumpVolume, 0, "dump a volume");
4465     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
4466     cmd_AddParm(ts, "-time", CMD_SINGLE, CMD_OPTIONAL, "dump from time");
4467     cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_OPTIONAL, "dump file");
4468     cmd_AddParm(ts, "-server", CMD_SINGLE, CMD_OPTIONAL, "server");
4469     cmd_AddParm(ts, "-partition", CMD_SINGLE, CMD_OPTIONAL, "partition");
4470     cmd_AddParm(ts, "-clone", CMD_FLAG, CMD_OPTIONAL, "dump a clone of the volume");
4471     COMMONPARMS;
4472
4473     ts = cmd_CreateSyntax("restore", RestoreVolume, 0, "restore a volume");
4474     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
4475     cmd_AddParm(ts, "-partition", CMD_SINGLE, 0, "partition name");
4476     cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of volume to be restored");
4477     cmd_AddParm(ts, "-file", CMD_SINGLE,CMD_OPTIONAL, "dump file");
4478     cmd_AddParm(ts, "-id", CMD_SINGLE,CMD_OPTIONAL,  "volume ID");
4479     cmd_AddParm(ts, "-overwrite", CMD_SINGLE,CMD_OPTIONAL,  "abort | full | incremental");
4480     cmd_AddParm(ts, "-offline", CMD_FLAG, CMD_OPTIONAL,
4481                 "leave restored volume offline");
4482     cmd_AddParm(ts, "-readonly", CMD_FLAG, CMD_OPTIONAL,
4483                 "make restored volume read-only");
4484     COMMONPARMS;
4485
4486     ts = cmd_CreateSyntax("unlock", LockReleaseCmd, 0, "release lock on VLDB entry for a volume");
4487     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
4488     COMMONPARMS;
4489
4490     ts = cmd_CreateSyntax("changeloc", ChangeLocation, 0, "change an RW volume's location in the VLDB");
4491     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name for new location");
4492     cmd_AddParm(ts, "-partition", CMD_SINGLE, 0, "partition name for new location");
4493     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
4494     COMMONPARMS;
4495
4496     ts = cmd_CreateSyntax("addsite", AddSite, 0, "add a replication site");
4497     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name for new site");
4498     cmd_AddParm(ts, "-partition", CMD_SINGLE, 0, "partition name for new site");
4499     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
4500     COMMONPARMS;
4501
4502     ts = cmd_CreateSyntax("remsite", RemoveSite, 0, "remove a replication site");
4503     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
4504     cmd_AddParm(ts, "-partition", CMD_SINGLE, 0, "partition name");
4505     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
4506     COMMONPARMS;
4507
4508     ts = cmd_CreateSyntax("listpart", ListPartitions, 0, "list partitions");
4509     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
4510     COMMONPARMS;
4511
4512     ts = cmd_CreateSyntax("listvol", ListVolumes, 0, "list volumes on server (bypass VLDB)");
4513     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
4514     cmd_AddParm(ts, "-partition", CMD_SINGLE,CMD_OPTIONAL, "partition name");
4515     cmd_AddParm(ts, "-fast", CMD_FLAG, CMD_OPTIONAL, "minimal listing");
4516     cmd_AddParm(ts, "-long", CMD_FLAG, CMD_OPTIONAL,
4517                 "list all normal volume fields");
4518     cmd_AddParm(ts, "-quiet", CMD_FLAG, CMD_OPTIONAL, "generate minimal information");
4519     cmd_AddParm(ts, "-extended", CMD_FLAG, CMD_OPTIONAL,
4520                 "list extended volume fields");
4521 #ifdef FULL_LISTVOL_SWITCH
4522     cmd_AddParm(ts, "-format", CMD_FLAG, CMD_OPTIONAL, 
4523               "machine readable format");
4524 #endif /* FULL_LISTVOL_SWITCH */
4525     COMMONPARMS;
4526
4527     ts = cmd_CreateSyntax("syncvldb", SyncVldb, 0, "synchronize VLDB with server");
4528     cmd_AddParm(ts, "-server", CMD_SINGLE, CMD_OPTIONAL, "machine name");
4529     cmd_AddParm(ts, "-partition", CMD_SINGLE,CMD_OPTIONAL , "partition name");
4530     cmd_AddParm(ts, "-volume", CMD_SINGLE,CMD_OPTIONAL , "volume name or ID");
4531     COMMONPARMS;
4532
4533     ts = cmd_CreateSyntax("syncserv", SyncServer, 0, "synchronize server with VLDB");
4534     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
4535     cmd_AddParm(ts, "-partition", CMD_SINGLE,CMD_OPTIONAL , "partition name");
4536     COMMONPARMS;
4537
4538     ts = cmd_CreateSyntax("examine", ExamineVolume, 0, "everything about the volume");
4539     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
4540     cmd_AddParm(ts, "-extended", CMD_FLAG, CMD_OPTIONAL,
4541                 "list extended volume fields");
4542 #ifdef FULL_LISTVOL_SWITCH
4543     cmd_AddParm(ts, "-format", CMD_FLAG, CMD_OPTIONAL, 
4544               "machine readable format");
4545 #endif /* FULL_LISTVOL_SWITCH */
4546     COMMONPARMS;
4547     cmd_CreateAlias (ts, "volinfo");
4548
4549     ts = cmd_CreateSyntax("setfields", SetFields, 0, "change volume info fields");
4550     cmd_AddParm(ts, "-id",        CMD_SINGLE, 0, "volume name or ID");
4551     cmd_AddParm(ts, "-maxquota", CMD_SINGLE, CMD_OPTIONAL, "quota (KB)");
4552     cmd_AddParm(ts, "-clearuse",  CMD_FLAG,   CMD_OPTIONAL, "clear dayUse");
4553     COMMONPARMS;
4554
4555     ts = cmd_CreateSyntax("offline", volOffline, 0, (char *) CMD_HIDDEN);
4556     cmd_AddParm(ts, "-server",    CMD_SINGLE, 0, "server name");
4557     cmd_AddParm(ts, "-partition", CMD_SINGLE, 0, "partition name");
4558     cmd_AddParm(ts, "-id",        CMD_SINGLE, 0, "volume name or ID");
4559     cmd_AddParm(ts, "-sleep", CMD_SINGLE, CMD_OPTIONAL, "seconds to sleep");
4560     cmd_AddParm(ts, "-busy",  CMD_FLAG,   CMD_OPTIONAL, "busy volume");
4561     COMMONPARMS;
4562
4563     ts = cmd_CreateSyntax("online", volOnline, 0, (char *) CMD_HIDDEN);
4564     cmd_AddParm(ts, "-server",    CMD_SINGLE, 0, "server name");
4565     cmd_AddParm(ts, "-partition", CMD_SINGLE, 0, "partition name");
4566     cmd_AddParm(ts, "-id",        CMD_SINGLE, 0, "volume name or ID");
4567     COMMONPARMS;
4568
4569     ts = cmd_CreateSyntax("zap", VolumeZap, 0, "delete the volume, don't bother with VLDB");
4570     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
4571     cmd_AddParm(ts, "-partition", CMD_SINGLE, 0, "partition name");
4572     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume ID");
4573     cmd_AddParm(ts, "-force", CMD_FLAG, CMD_OPTIONAL, "force deletion of bad volumes");
4574     cmd_AddParm(ts, "-backup", CMD_FLAG, CMD_OPTIONAL, "also delete backup volume if one is found");
4575     COMMONPARMS;
4576
4577     ts = cmd_CreateSyntax("status", VolserStatus, 0, "report on volser status");
4578     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
4579     COMMONPARMS;
4580
4581     ts = cmd_CreateSyntax("rename", RenameVolume, 0, "rename a volume");
4582     cmd_AddParm(ts, "-oldname", CMD_SINGLE, 0, "old volume name ");
4583     cmd_AddParm(ts, "-newname", CMD_SINGLE, 0, "new volume name ");
4584     COMMONPARMS;
4585
4586     ts = cmd_CreateSyntax("listvldb", ListVLDB, 0, "list volumes in the VLDB");
4587     cmd_AddParm(ts, "-name", CMD_SINGLE,CMD_OPTIONAL,  "volume name or ID");
4588     cmd_AddParm(ts, "-server", CMD_SINGLE,CMD_OPTIONAL,  "machine name");
4589     cmd_AddParm(ts, "-partition", CMD_SINGLE,CMD_OPTIONAL, "partition name");
4590     cmd_AddParm(ts, "-locked", CMD_FLAG, CMD_OPTIONAL, "locked volumes only");
4591     cmd_AddParm(ts, "-quiet", CMD_FLAG, CMD_OPTIONAL, "generate minimal information");
4592     cmd_AddParm(ts, "-nosort", CMD_FLAG, CMD_OPTIONAL, "do not alphabetically sort the volume names");
4593     COMMONPARMS;
4594
4595     ts = cmd_CreateSyntax("backupsys", BackSys, 0, "en masse backups");
4596     cmd_AddParm(ts, "-prefix", CMD_LIST,CMD_OPTIONAL,  "common prefix on volume(s)");
4597     cmd_AddParm(ts, "-server", CMD_SINGLE,CMD_OPTIONAL,  "machine name");
4598     cmd_AddParm(ts, "-partition", CMD_SINGLE,CMD_OPTIONAL, "partition name");
4599     cmd_AddParm(ts, "-exclude", CMD_FLAG, CMD_OPTIONAL, "exclude common prefix volumes");
4600     cmd_AddParm(ts, "-xprefix", CMD_LIST, CMD_OPTIONAL, "negative prefix on volume(s)");
4601     cmd_AddParm(ts, "-dryrun", CMD_FLAG, CMD_OPTIONAL, "no action");
4602     COMMONPARMS;
4603
4604     ts = cmd_CreateSyntax("delentry", DeleteEntry, 0, "delete VLDB entry for a volume");
4605     cmd_AddParm(ts, "-id", CMD_LIST, CMD_OPTIONAL, "volume name or ID");
4606     cmd_AddParm(ts, "-prefix", CMD_SINGLE,CMD_OPTIONAL, "prefix of the volume whose VLDB entry is to be deleted");
4607     cmd_AddParm(ts, "-server", CMD_SINGLE,CMD_OPTIONAL,  "machine name");
4608     cmd_AddParm(ts, "-partition", CMD_SINGLE,CMD_OPTIONAL, "partition name");
4609     cmd_AddParm(ts, "-noexecute", CMD_FLAG,CMD_OPTIONAL|CMD_HIDE, "no execute");
4610     COMMONPARMS;
4611
4612      ts = cmd_CreateSyntax("partinfo", PartitionInfo, 0, "list partition information");
4613     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
4614     cmd_AddParm(ts, "-partition", CMD_SINGLE,CMD_OPTIONAL, "partition name");
4615     COMMONPARMS;
4616
4617     ts = cmd_CreateSyntax("unlockvldb", UnlockVLDB, 0, "unlock all the locked entries in the VLDB");
4618     cmd_AddParm(ts, "-server", CMD_SINGLE,CMD_OPTIONAL,  "machine name");
4619     cmd_AddParm(ts, "-partition", CMD_SINGLE,CMD_OPTIONAL, "partition name");
4620     COMMONPARMS;
4621
4622     ts = cmd_CreateSyntax("lock", LockEntry, 0, "lock VLDB entry for a volume");
4623     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
4624     COMMONPARMS;
4625
4626     ts = cmd_CreateSyntax("changeaddr", ChangeAddr, 0, "change the IP address of a file server");
4627     cmd_AddParm(ts, "-oldaddr", CMD_SINGLE, 0, "original IP address");
4628     cmd_AddParm(ts, "-newaddr", CMD_SINGLE, CMD_OPTIONAL, "new IP address");
4629     cmd_AddParm(ts, "-remove", CMD_FLAG, CMD_OPTIONAL, "remove the IP address from the VLDB");
4630     COMMONPARMS;
4631
4632     ts = cmd_CreateSyntax("listaddrs", ListAddrs, 0, "list the IP address of all file servers registered in the VLDB");
4633     cmd_AddParm(ts, "-uuid", CMD_SINGLE, CMD_OPTIONAL, "uuid of server");
4634     cmd_AddParm(ts, "-host", CMD_SINGLE, CMD_OPTIONAL, "address of host");
4635     cmd_AddParm(ts, "-noresolve", CMD_FLAG, CMD_OPTIONAL, "don't resolve addresses");
4636     cmd_AddParm(ts, "-printuuid", CMD_FLAG, CMD_OPTIONAL, "print uuid of hosts");
4637     COMMONPARMS;
4638
4639     ts = cmd_CreateSyntax("convertROtoRW", ConvertRO, 0, "convert a RO volume into a RW volume (after loss of old RW volume)");
4640     cmd_AddParm(ts, "-server", CMD_SINGLE,0,  "machine name");
4641     cmd_AddParm(ts, "-partition", CMD_SINGLE,0, "partition name");
4642     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
4643     cmd_AddParm(ts, "-force", CMD_FLAG, CMD_OPTIONAL, "don't ask");
4644     COMMONPARMS;
4645
4646     code = cmd_Dispatch(argc, argv);
4647     if (rxInitDone) {
4648         /* Shut down the ubik_client and rx connections */
4649         if (cstruct) {
4650             (void) ubik_ClientDestroy (cstruct);
4651             cstruct = 0;
4652         }
4653         rx_Finalize();
4654     }
4655
4656     exit((code?-1:0));
4657 }