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