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