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