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