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