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