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