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