Consolidate loopback address tests
[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 #ifdef IGNORE_SOME_GCC_WARNINGS
14 # pragma GCC diagnostic warning "-Wimplicit-function-declaration"
15 #endif
16
17 #include <sys/types.h>
18 #include <string.h>
19 #ifdef HAVE_STDINT_H
20 # include <stdint.h>
21 #endif
22 #ifdef AFS_NT40_ENV
23 #include <fcntl.h>
24 #include <io.h>
25 #include <winsock2.h>
26 #include <WINNT/afsreg.h>
27 #else
28 #include <sys/time.h>
29 #include <sys/file.h>
30 #include <netdb.h>
31 #include <netinet/in.h>
32 #include <arpa/inet.h>
33 #endif
34 #include <sys/stat.h>
35 #ifdef AFS_AIX_ENV
36 #include <sys/statfs.h>
37 #endif
38 #include <errno.h>
39
40 #include <lock.h>
41 #include <afs/stds.h>
42 #include <rx/xdr.h>
43 #include <rx/rx.h>
44 #include <rx/rx_globals.h>
45 #include <afs/nfs.h>
46 #include <afs/vlserver.h>
47 #include <afs/cellconfig.h>
48 #include <afs/keys.h>
49 #include <afs/afsutil.h>
50 #include <ubik.h>
51 #include <afs/afsint.h>
52 #include <afs/cmd.h>
53 #include <afs/usd.h>
54 #include "volser.h"
55 #include "volint.h"
56 #include <afs/ihandle.h>
57 #include <afs/vnode.h>
58 #include <afs/volume.h>
59 #include <afs/com_err.h>
60 #include "dump.h"
61 #include "lockdata.h"
62
63 #ifdef  AFS_AIX32_ENV
64 #include <signal.h>
65 #endif
66 #include "volser_internal.h"
67 #include "volser_prototypes.h"
68 #include "vsutils_prototypes.h"
69 #include "lockprocs_prototypes.h"
70
71 #ifdef HAVE_POSIX_REGEX
72 #include <regex.h>
73 #endif
74
75 /* Local Prototypes */
76 int PrintDiagnostics(char *astring, afs_int32 acode);
77 int GetVolumeInfo(afs_uint32 volid, afs_uint32 *server, afs_int32 *part,
78                   afs_int32 *voltype, struct nvldbentry *rentry);
79
80 struct tqElem {
81     afs_uint32 volid;
82     struct tqElem *next;
83 };
84
85 struct tqHead {
86     afs_int32 count;
87     struct tqElem *next;
88 };
89
90 #define COMMONPARMS     cmd_Seek(ts, 12);\
91 cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");\
92 cmd_AddParm(ts, "-noauth", CMD_FLAG, CMD_OPTIONAL, "don't authenticate");\
93 cmd_AddParm(ts, "-localauth",CMD_FLAG,CMD_OPTIONAL,"use server tickets");\
94 cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, "verbose");\
95 cmd_AddParm(ts, "-encrypt", CMD_FLAG, CMD_OPTIONAL, "encrypt commands");\
96 cmd_AddParm(ts, "-noresolve", CMD_FLAG, CMD_OPTIONAL, "don't resolve addresses"); \
97
98 #define ERROR_EXIT(code) {error=(code); goto error_exit;}
99
100 int rxInitDone = 0;
101 struct rx_connection *tconn;
102 afs_uint32 tserver;
103 extern struct ubik_client *cstruct;
104 const char *confdir;
105
106 static struct tqHead busyHead, notokHead;
107
108 static void
109 qInit(struct tqHead *ahead)
110 {
111     memset(ahead, 0, sizeof(struct tqHead));
112     return;
113 }
114
115
116 static void
117 qPut(struct tqHead *ahead, afs_uint32 volid)
118 {
119     struct tqElem *elem;
120
121     elem = (struct tqElem *)malloc(sizeof(struct tqElem));
122     elem->next = ahead->next;
123     elem->volid = volid;
124     ahead->next = elem;
125     ahead->count++;
126     return;
127 }
128
129 static void
130 qGet(struct tqHead *ahead, afs_uint32 *volid)
131 {
132     struct tqElem *tmp;
133
134     if (ahead->count <= 0)
135         return;
136     *volid = ahead->next->volid;
137     tmp = ahead->next;
138     ahead->next = tmp->next;
139     ahead->count--;
140     free(tmp);
141     return;
142 }
143
144 /* returns 1 if <filename> exists else 0 */
145 static int
146 FileExists(char *filename)
147 {
148     usd_handle_t ufd;
149     int code;
150     afs_hyper_t size;
151
152     code = usd_Open(filename, USD_OPEN_RDONLY, 0, &ufd);
153     if (code) {
154         return 0;
155     }
156     code = USD_IOCTL(ufd, USD_IOCTL_GETSIZE, &size);
157     USD_CLOSE(ufd);
158     if (code) {
159         return 0;
160     }
161     return 1;
162 }
163
164 /* returns 1 if <name> doesnot end in .readonly or .backup, else 0 */
165 static int
166 VolNameOK(char *name)
167 {
168     int total;
169
170
171     total = strlen(name);
172     if (!strcmp(&name[total - 9], ".readonly")) {
173         return 0;
174     } else if (!strcmp(&name[total - 7], ".backup")) {
175         return 0;
176     } else {
177         return 1;
178     }
179 }
180
181 /* return 1 if name is a number else 0 */
182 static int
183 IsNumeric(char *name)
184 {
185     int result, len, i;
186     char *ptr;
187
188     result = 1;
189     ptr = name;
190     len = strlen(name);
191     for (i = 0; i < len; i++) {
192         if (*ptr < '0' || *ptr > '9') {
193             result = 0;
194             break;
195         }
196         ptr++;
197
198     }
199     return result;
200 }
201
202
203 /*
204  * Parse a server dotted address and return the address in network byte order
205  */
206 afs_uint32
207 GetServerNoresolve(char *aname)
208 {
209     int b1, b2, b3, b4;
210     afs_uint32 addr;
211     afs_int32 code;
212
213     code = sscanf(aname, "%d.%d.%d.%d", &b1, &b2, &b3, &b4);
214     if (code == 4) {
215         addr = (b1 << 24) | (b2 << 16) | (b3 << 8) | b4;
216         addr = htonl(addr);     /* convert to network byte order */
217         return addr;
218     } else
219         return 0;
220 }
221 /*
222  * Parse a server name/address and return the address in network byte order
223  */
224 afs_uint32
225 GetServer(char *aname)
226 {
227     register struct hostent *th;
228     afs_uint32 addr; /* in network byte order */
229     register afs_int32 code;
230     char hostname[MAXHOSTCHARS];
231
232     if ((addr = GetServerNoresolve(aname)) == 0) {
233         th = gethostbyname(aname);
234         if (!th)
235             return 0;
236         memcpy(&addr, th->h_addr, sizeof(addr));
237     }
238
239     if (rx_IsLoopbackAddr(ntohl(addr))) {       /* local host */
240         code = gethostname(hostname, MAXHOSTCHARS);
241         if (code)
242             return 0;
243         th = gethostbyname(hostname);
244         if (!th)
245             return 0;
246         memcpy(&addr, th->h_addr, sizeof(addr));
247     }
248
249     return (addr);
250 }
251
252 afs_int32
253 GetVolumeType(char *aname)
254 {
255
256     if (!strcmp(aname, "ro"))
257         return (ROVOL);
258     else if (!strcmp(aname, "rw"))
259         return (RWVOL);
260     else if (!strcmp(aname, "bk"))
261         return (BACKVOL);
262     else
263         return (-1);
264 }
265
266 int
267 IsPartValid(afs_int32 partId, afs_uint32 server, afs_int32 *code)
268 {
269     struct partList dummyPartList;
270     int i, success, cnt;
271
272     success = 0;
273     *code = 0;
274
275     *code = UV_ListPartitions(server, &dummyPartList, &cnt);
276     if (*code)
277         return success;
278     for (i = 0; i < cnt; i++) {
279         if (dummyPartList.partFlags[i] & PARTVALID)
280             if (dummyPartList.partId[i] == partId)
281                 success = 1;
282     }
283     return success;
284 }
285
286
287
288  /*sends the contents of file associated with <fd> and <blksize>  to Rx Stream 
289   * associated  with <call> */
290 int 
291 SendFile(usd_handle_t ufd, register struct rx_call *call, long blksize)
292 {
293     char *buffer = (char *)0;
294     afs_int32 error = 0;
295     int done = 0;
296     afs_uint32 nbytes;
297
298     buffer = (char *)malloc(blksize);
299     if (!buffer) {
300         fprintf(STDERR, "malloc failed\n");
301         return -1;
302     }
303
304     while (!error && !done) {
305 #ifndef AFS_NT40_ENV            /* NT csn't select on non-socket fd's */
306         fd_set in;
307         FD_ZERO(&in);
308         FD_SET((intptr_t)(ufd->handle), &in);
309         /* don't timeout if read blocks */
310 #if defined(AFS_PTHREAD_ENV)
311         select(((intptr_t)(ufd->handle)) + 1, &in, 0, 0, 0);
312 #else
313         IOMGR_Select(((intptr_t)(ufd->handle)) + 1, &in, 0, 0, 0);
314 #endif
315 #endif
316         error = USD_READ(ufd, buffer, blksize, &nbytes);
317         if (error) {
318             fprintf(STDERR, "File system read failed: %s\n",
319                     afs_error_message(error));
320             break;
321         }
322         if (nbytes == 0) {
323             done = 1;
324             break;
325         }
326         if (rx_Write(call, buffer, nbytes) != nbytes) {
327             error = -1;
328             break;
329         }
330     }
331     if (buffer)
332         free(buffer);
333     return error;
334 }
335
336 /* function invoked by UV_RestoreVolume, reads the data from rx_trx_stream and
337  * writes it out to the volume. */
338 afs_int32
339 WriteData(struct rx_call *call, void *rock)
340 {
341     char *filename = (char *) rock;
342     usd_handle_t ufd;
343     long blksize;
344     afs_int32 error, code;
345     int ufdIsOpen = 0;
346     afs_hyper_t filesize, currOffset; 
347     afs_uint32 buffer;          
348     afs_uint32 got;             
349
350     error = 0;
351
352     if (!filename || !*filename) {
353         usd_StandardInput(&ufd);
354         blksize = 4096;
355         ufdIsOpen = 1;
356     } else {
357         code = usd_Open(filename, USD_OPEN_RDONLY, 0, &ufd);
358         if (code == 0) {
359             ufdIsOpen = 1;
360             code = USD_IOCTL(ufd, USD_IOCTL_GETBLKSIZE, &blksize);
361         }
362         if (code) {
363             fprintf(STDERR, "Could not access file '%s': %s\n", filename,
364                     afs_error_message(code));
365             error = VOLSERBADOP;
366             goto wfail;
367         }
368         /* test if we have a valid dump */
369         hset64(filesize, 0, 0);
370         USD_SEEK(ufd, filesize, SEEK_END, &currOffset);
371         hset64(filesize, hgethi(currOffset), hgetlo(currOffset)-sizeof(afs_uint32));
372         USD_SEEK(ufd, filesize, SEEK_SET, &currOffset);
373         USD_READ(ufd, (char *)&buffer, sizeof(afs_uint32), &got);
374         if ((got != sizeof(afs_uint32)) || (ntohl(buffer) != DUMPENDMAGIC)) {
375             fprintf(STDERR, "Signature missing from end of file '%s'\n", filename);
376             error = VOLSERBADOP;
377             goto wfail;
378         }
379         /* rewind, we are done */
380         hset64(filesize, 0, 0);
381         USD_SEEK(ufd, filesize, SEEK_SET, &currOffset);
382     }
383     code = SendFile(ufd, call, blksize);
384     if (code) {
385         error = code;
386         goto wfail;
387     }
388   wfail:
389     if (ufdIsOpen) {
390         code = USD_CLOSE(ufd);
391         if (code) {
392             fprintf(STDERR, "Could not close dump file %s\n",
393                     (filename && *filename) ? filename : "STDOUT");
394             if (!error)
395                 error = code;
396         }
397     }
398     return error;
399 }
400
401 /* Receive data from <call> stream into file associated
402  * with <fd> <blksize>
403  */
404 int
405 ReceiveFile(usd_handle_t ufd, struct rx_call *call, long blksize)
406 {
407     char *buffer = NULL;
408     afs_int32 bytesread;
409     afs_uint32 bytesleft, w;
410     afs_int32 error = 0;
411
412     buffer = (char *)malloc(blksize);
413     if (!buffer) {
414         fprintf(STDERR, "memory allocation failed\n");
415         ERROR_EXIT(-1);
416     }
417
418     while ((bytesread = rx_Read(call, buffer, blksize)) > 0) {
419         for (bytesleft = bytesread; bytesleft; bytesleft -= w) {
420 #ifndef AFS_NT40_ENV            /* NT csn't select on non-socket fd's */
421             fd_set out;
422             FD_ZERO(&out);
423             FD_SET((intptr_t)(ufd->handle), &out);
424             /* don't timeout if write blocks */
425 #if defined(AFS_PTHREAD_ENV)
426             select(((intptr_t)(ufd->handle)) + 1, &out, 0, 0, 0);
427 #else
428             IOMGR_Select(((intptr_t)(ufd->handle)) + 1, 0, &out, 0, 0);
429 #endif
430 #endif
431             error =
432                 USD_WRITE(ufd, &buffer[bytesread - bytesleft], bytesleft, &w);
433             if (error) {
434                 fprintf(STDERR, "File system write failed: %s\n",
435                         afs_error_message(error));
436                 ERROR_EXIT(-1);
437             }
438         }
439     }
440
441   error_exit:
442     if (buffer)
443         free(buffer);
444     return (error);
445 }
446
447 afs_int32
448 DumpFunction(struct rx_call *call, void *rock)
449 {
450     char *filename = (char *)rock;
451     usd_handle_t ufd;           /* default is to stdout */
452     afs_int32 error = 0, code;
453     afs_hyper_t size;
454     long blksize;
455     int ufdIsOpen = 0;
456
457     /* Open the output file */
458     if (!filename || !*filename) {
459         usd_StandardOutput(&ufd);
460         blksize = 4096;
461         ufdIsOpen = 1;
462     } else {
463         code =
464             usd_Open(filename, USD_OPEN_CREATE | USD_OPEN_RDWR, 0666, &ufd);
465         if (code == 0) {
466             ufdIsOpen = 1;
467             hzero(size);
468             code = USD_IOCTL(ufd, USD_IOCTL_SETSIZE, &size);
469         }
470         if (code == 0) {
471             code = USD_IOCTL(ufd, USD_IOCTL_GETBLKSIZE, &blksize);
472         }
473         if (code) {
474             fprintf(STDERR, "Could not create file '%s': %s\n", filename,
475                     afs_error_message(code));
476             ERROR_EXIT(VOLSERBADOP);
477         }
478     }
479
480     code = ReceiveFile(ufd, call, blksize);
481     if (code)
482         ERROR_EXIT(code);
483
484   error_exit:
485     /* Close the output file */
486     if (ufdIsOpen) {
487         code = USD_CLOSE(ufd);
488         if (code) {
489             fprintf(STDERR, "Could not close dump file %s\n",
490                     (filename && *filename) ? filename : "STDIN");
491             if (!error)
492                 error = code;
493         }
494     }
495
496     return (error);
497 }
498
499 static void
500 DisplayFormat(volintInfo *pntr, afs_uint32 server, afs_int32 part,
501               int *totalOK, int *totalNotOK, int *totalBusy, int fast,
502               int longlist, int disp)
503 {
504     char pname[10];
505     time_t t;
506
507     if (fast) {
508         fprintf(STDOUT, "%-10lu\n", (unsigned long)pntr->volid);
509     } else if (longlist) {
510         if (pntr->status == VOK) {
511             fprintf(STDOUT, "%-32s ", pntr->name);
512             fprintf(STDOUT, "%10lu ", (unsigned long)pntr->volid);
513             if (pntr->type == 0)
514                 fprintf(STDOUT, "RW ");
515             if (pntr->type == 1)
516                 fprintf(STDOUT, "RO ");
517             if (pntr->type == 2)
518                 fprintf(STDOUT, "BK ");
519             fprintf(STDOUT, "%10d K  ", pntr->size);
520             if (pntr->inUse == 1) {
521                 fprintf(STDOUT, "On-line");
522                 *totalOK += 1;
523             } else {
524                 fprintf(STDOUT, "Off-line");
525                 *totalNotOK += 1;
526             }
527             if (pntr->needsSalvaged == 1)
528                 fprintf(STDOUT, "**needs salvage**");
529             fprintf(STDOUT, "\n");
530             MapPartIdIntoName(part, pname);
531             fprintf(STDOUT, "    %s %s \n", hostutil_GetNameByINet(server),
532                     pname);
533             fprintf(STDOUT, "    RWrite %10lu ROnly %10lu Backup %10lu \n",
534                     (unsigned long)pntr->parentID,
535                     (unsigned long)pntr->cloneID,
536                     (unsigned long)pntr->backupID);
537             fprintf(STDOUT, "    MaxQuota %10d K \n", pntr->maxquota);
538             t = pntr->creationDate;
539             fprintf(STDOUT, "    Creation    %s",
540                     ctime(&t));
541             t = pntr->copyDate;
542             fprintf(STDOUT, "    Copy        %s",
543                     ctime(&t));
544
545             t = pntr->backupDate;
546             if (!t)
547                 fprintf(STDOUT, "    Backup      Never\n");
548             else
549                 fprintf(STDOUT, "    Backup      %s",
550                         ctime(&t));
551
552             t = pntr->accessDate;
553             if (t)
554                 fprintf(STDOUT, "    Last Access %s",
555                         ctime(&t));
556
557             t = pntr->updateDate;
558             if (!t)
559                 fprintf(STDOUT, "    Last Update Never\n");
560             else
561                 fprintf(STDOUT, "    Last Update %s",
562                         ctime(&t));
563             fprintf(STDOUT,
564                     "    %d accesses in the past day (i.e., vnode references)\n",
565                     pntr->dayUse);
566         } else if (pntr->status == VBUSY) {
567             *totalBusy += 1;
568             qPut(&busyHead, pntr->volid);
569             if (disp)
570                 fprintf(STDOUT, "**** Volume %lu is busy ****\n",
571                         (unsigned long)pntr->volid);
572         } else {
573             *totalNotOK += 1;
574             qPut(&notokHead, pntr->volid);
575             if (disp)
576                 fprintf(STDOUT, "**** Could not attach volume %lu ****\n",
577                         (unsigned long)pntr->volid);
578         }
579         fprintf(STDOUT, "\n");
580     } else {                    /* default listing */
581         if (pntr->status == VOK) {
582             fprintf(STDOUT, "%-32s ", pntr->name);
583             fprintf(STDOUT, "%10lu ", (unsigned long)pntr->volid);
584             if (pntr->type == 0)
585                 fprintf(STDOUT, "RW ");
586             if (pntr->type == 1)
587                 fprintf(STDOUT, "RO ");
588             if (pntr->type == 2)
589                 fprintf(STDOUT, "BK ");
590             fprintf(STDOUT, "%10d K ", pntr->size);
591             if (pntr->inUse == 1) {
592                 fprintf(STDOUT, "On-line");
593                 *totalOK += 1;
594             } else {
595                 fprintf(STDOUT, "Off-line");
596                 *totalNotOK += 1;
597             }
598             if (pntr->needsSalvaged == 1)
599                 fprintf(STDOUT, "**needs salvage**");
600             fprintf(STDOUT, "\n");
601         } else if (pntr->status == VBUSY) {
602             *totalBusy += 1;
603             qPut(&busyHead, pntr->volid);
604             if (disp)
605                 fprintf(STDOUT, "**** Volume %lu is busy ****\n",
606                         (unsigned long)pntr->volid);
607         } else {
608             *totalNotOK += 1;
609             qPut(&notokHead, pntr->volid);
610             if (disp)
611                 fprintf(STDOUT, "**** Could not attach volume %lu ****\n",
612                         (unsigned long)pntr->volid);
613         }
614     }
615 }
616
617 /*------------------------------------------------------------------------
618  * PRIVATE XDisplayFormat
619  *
620  * Description:
621  *      Display the contents of one extended volume info structure.
622  *
623  * Arguments:
624  *      a_xInfoP        : Ptr to extended volume info struct to print.
625  *      a_servID        : Server ID to print.
626  *      a_partID        : Partition ID to print.
627  *      a_totalOKP      : Ptr to total-OK counter.
628  *      a_totalNotOKP   : Ptr to total-screwed counter.
629  *      a_totalBusyP    : Ptr to total-busy counter.
630  *      a_fast          : Fast listing?
631  *      a_int32         : Int32 listing?
632  *      a_showProblems  : Show volume problems?
633  *
634  * Returns:
635  *      Nothing.
636  *
637  * Environment:
638  *      Nothing interesting.
639  *
640  * Side Effects:
641  *      As advertised.
642  *------------------------------------------------------------------------*/
643
644 static void
645 XDisplayFormat(volintXInfo *a_xInfoP, afs_uint32 a_servID, afs_int32 a_partID,
646                int *a_totalOKP, int *a_totalNotOKP, int *a_totalBusyP,
647                int a_fast, int a_int32, int a_showProblems)
648 {                               /*XDisplayFormat */
649     time_t t;
650     char pname[10];
651
652     if (a_fast) {
653         /*
654          * Short & sweet.
655          */
656         fprintf(STDOUT, "%-10lu\n", (unsigned long)a_xInfoP->volid);
657     } else if (a_int32) {
658         /*
659          * Fully-detailed listing.
660          */
661         if (a_xInfoP->status == VOK) {
662             /*
663              * Volume's status is OK - all the fields are valid.
664              */
665             fprintf(STDOUT, "%-32s ", a_xInfoP->name);
666             fprintf(STDOUT, "%10lu ", (unsigned long)a_xInfoP->volid);
667             if (a_xInfoP->type == 0)
668                 fprintf(STDOUT, "RW ");
669             if (a_xInfoP->type == 1)
670                 fprintf(STDOUT, "RO ");
671             if (a_xInfoP->type == 2)
672                 fprintf(STDOUT, "BK ");
673             fprintf(STDOUT, "%10d K used ", a_xInfoP->size);
674             fprintf(STDOUT, "%d files ", a_xInfoP->filecount);
675             if (a_xInfoP->inUse == 1) {
676                 fprintf(STDOUT, "On-line");
677                 (*a_totalOKP)++;
678             } else {
679                 fprintf(STDOUT, "Off-line");
680                 (*a_totalNotOKP)++;
681             }
682             fprintf(STDOUT, "\n");
683             MapPartIdIntoName(a_partID, pname);
684             fprintf(STDOUT, "    %s %s \n", hostutil_GetNameByINet(a_servID),
685                     pname);
686             fprintf(STDOUT, "    RWrite %10lu ROnly %10lu Backup %10lu \n",
687                     (unsigned long)a_xInfoP->parentID,
688                     (unsigned long)a_xInfoP->cloneID,
689                     (unsigned long)a_xInfoP->backupID);
690             fprintf(STDOUT, "    MaxQuota %10d K \n", a_xInfoP->maxquota);
691
692             t = a_xInfoP->creationDate;
693             fprintf(STDOUT, "    Creation    %s",
694                     ctime(&t));
695
696             t = a_xInfoP->copyDate;
697             fprintf(STDOUT, "    Copy        %s",
698                     ctime(&t));
699
700             t = a_xInfoP->backupDate;
701             if (!t)
702                 fprintf(STDOUT, "    Backup      Never\n");
703             else
704                 fprintf(STDOUT, "    Backup      %s",
705                         ctime(&t));
706
707             t = a_xInfoP->accessDate;
708             if (t)
709                 fprintf(STDOUT, "    Last Access %s",
710                         ctime(&t));
711
712             t = a_xInfoP->updateDate;
713             if (!t)
714                 fprintf(STDOUT, "    Last Update Never\n");
715             else
716                 fprintf(STDOUT, "    Last Update %s",
717                         ctime(&t));
718             fprintf(STDOUT,
719                     "    %d accesses in the past day (i.e., vnode references)\n",
720                     a_xInfoP->dayUse);
721
722             /*
723              * Print all the read/write and authorship stats.
724              */
725             fprintf(STDOUT, "\n                      Raw Read/Write Stats\n");
726             fprintf(STDOUT,
727                     "          |-------------------------------------------|\n");
728             fprintf(STDOUT,
729                     "          |    Same Network     |    Diff Network     |\n");
730             fprintf(STDOUT,
731                     "          |----------|----------|----------|----------|\n");
732             fprintf(STDOUT,
733                     "          |  Total   |   Auth   |   Total  |   Auth   |\n");
734             fprintf(STDOUT,
735                     "          |----------|----------|----------|----------|\n");
736             fprintf(STDOUT, "Reads     | %8d | %8d | %8d | %8d |\n",
737                     a_xInfoP->stat_reads[VOLINT_STATS_SAME_NET],
738                     a_xInfoP->stat_reads[VOLINT_STATS_SAME_NET_AUTH],
739                     a_xInfoP->stat_reads[VOLINT_STATS_DIFF_NET],
740                     a_xInfoP->stat_reads[VOLINT_STATS_DIFF_NET_AUTH]);
741             fprintf(STDOUT, "Writes    | %8d | %8d | %8d | %8d |\n",
742                     a_xInfoP->stat_writes[VOLINT_STATS_SAME_NET],
743                     a_xInfoP->stat_writes[VOLINT_STATS_SAME_NET_AUTH],
744                     a_xInfoP->stat_writes[VOLINT_STATS_DIFF_NET],
745                     a_xInfoP->stat_writes[VOLINT_STATS_DIFF_NET_AUTH]);
746             fprintf(STDOUT,
747                     "          |-------------------------------------------|\n\n");
748
749             fprintf(STDOUT,
750                     "                   Writes Affecting Authorship\n");
751             fprintf(STDOUT,
752                     "          |-------------------------------------------|\n");
753             fprintf(STDOUT,
754                     "          |   File Authorship   | Directory Authorship|\n");
755             fprintf(STDOUT,
756                     "          |----------|----------|----------|----------|\n");
757             fprintf(STDOUT,
758                     "          |   Same   |   Diff   |    Same  |   Diff   |\n");
759             fprintf(STDOUT,
760                     "          |----------|----------|----------|----------|\n");
761             fprintf(STDOUT, "0-60 sec  | %8d | %8d | %8d | %8d |\n",
762                     a_xInfoP->stat_fileSameAuthor[VOLINT_STATS_TIME_IDX_0],
763                     a_xInfoP->stat_fileDiffAuthor[VOLINT_STATS_TIME_IDX_0],
764                     a_xInfoP->stat_dirSameAuthor[VOLINT_STATS_TIME_IDX_0],
765                     a_xInfoP->stat_dirDiffAuthor[VOLINT_STATS_TIME_IDX_0]);
766             fprintf(STDOUT, "1-10 min  | %8d | %8d | %8d | %8d |\n",
767                     a_xInfoP->stat_fileSameAuthor[VOLINT_STATS_TIME_IDX_1],
768                     a_xInfoP->stat_fileDiffAuthor[VOLINT_STATS_TIME_IDX_1],
769                     a_xInfoP->stat_dirSameAuthor[VOLINT_STATS_TIME_IDX_1],
770                     a_xInfoP->stat_dirDiffAuthor[VOLINT_STATS_TIME_IDX_1]);
771             fprintf(STDOUT, "10min-1hr | %8d | %8d | %8d | %8d |\n",
772                     a_xInfoP->stat_fileSameAuthor[VOLINT_STATS_TIME_IDX_2],
773                     a_xInfoP->stat_fileDiffAuthor[VOLINT_STATS_TIME_IDX_2],
774                     a_xInfoP->stat_dirSameAuthor[VOLINT_STATS_TIME_IDX_2],
775                     a_xInfoP->stat_dirDiffAuthor[VOLINT_STATS_TIME_IDX_2]);
776             fprintf(STDOUT, "1hr-1day  | %8d | %8d | %8d | %8d |\n",
777                     a_xInfoP->stat_fileSameAuthor[VOLINT_STATS_TIME_IDX_3],
778                     a_xInfoP->stat_fileDiffAuthor[VOLINT_STATS_TIME_IDX_3],
779                     a_xInfoP->stat_dirSameAuthor[VOLINT_STATS_TIME_IDX_3],
780                     a_xInfoP->stat_dirDiffAuthor[VOLINT_STATS_TIME_IDX_3]);
781             fprintf(STDOUT, "1day-1wk  | %8d | %8d | %8d | %8d |\n",
782                     a_xInfoP->stat_fileSameAuthor[VOLINT_STATS_TIME_IDX_4],
783                     a_xInfoP->stat_fileDiffAuthor[VOLINT_STATS_TIME_IDX_4],
784                     a_xInfoP->stat_dirSameAuthor[VOLINT_STATS_TIME_IDX_4],
785                     a_xInfoP->stat_dirDiffAuthor[VOLINT_STATS_TIME_IDX_4]);
786             fprintf(STDOUT, "> 1wk     | %8d | %8d | %8d | %8d |\n",
787                     a_xInfoP->stat_fileSameAuthor[VOLINT_STATS_TIME_IDX_5],
788                     a_xInfoP->stat_fileDiffAuthor[VOLINT_STATS_TIME_IDX_5],
789                     a_xInfoP->stat_dirSameAuthor[VOLINT_STATS_TIME_IDX_5],
790                     a_xInfoP->stat_dirDiffAuthor[VOLINT_STATS_TIME_IDX_5]);
791             fprintf(STDOUT,
792                     "          |-------------------------------------------|\n");
793         } /*Volume status OK */
794         else if (a_xInfoP->status == VBUSY) {
795             (*a_totalBusyP)++;
796             qPut(&busyHead, a_xInfoP->volid);
797             if (a_showProblems)
798                 fprintf(STDOUT, "**** Volume %lu is busy ****\n",
799                         (unsigned long)a_xInfoP->volid);
800         } /*Busy volume */
801         else {
802             (*a_totalNotOKP)++;
803             qPut(&notokHead, a_xInfoP->volid);
804             if (a_showProblems)
805                 fprintf(STDOUT, "**** Could not attach volume %lu ****\n",
806                         (unsigned long)a_xInfoP->volid);
807         }                       /*Screwed volume */
808         fprintf(STDOUT, "\n");
809     } /*Long listing */
810     else {
811         /*
812          * Default listing.
813          */
814         if (a_xInfoP->status == VOK) {
815             fprintf(STDOUT, "%-32s ", a_xInfoP->name);
816             fprintf(STDOUT, "%10lu ", (unsigned long)a_xInfoP->volid);
817             if (a_xInfoP->type == 0)
818                 fprintf(STDOUT, "RW ");
819             if (a_xInfoP->type == 1)
820                 fprintf(STDOUT, "RO ");
821             if (a_xInfoP->type == 2)
822                 fprintf(STDOUT, "BK ");
823             fprintf(STDOUT, "%10d K ", a_xInfoP->size);
824             if (a_xInfoP->inUse == 1) {
825                 fprintf(STDOUT, "On-line");
826                 (*a_totalOKP)++;
827             } else {
828                 fprintf(STDOUT, "Off-line");
829                 (*a_totalNotOKP)++;
830             }
831             fprintf(STDOUT, "\n");
832         } /*Volume OK */
833         else if (a_xInfoP->status == VBUSY) {
834             (*a_totalBusyP)++;
835             qPut(&busyHead, a_xInfoP->volid);
836             if (a_showProblems)
837                 fprintf(STDOUT, "**** Volume %lu is busy ****\n",
838                         (unsigned long)a_xInfoP->volid);
839         } /*Busy volume */
840         else {
841             (*a_totalNotOKP)++;
842             qPut(&notokHead, a_xInfoP->volid);
843             if (a_showProblems)
844                 fprintf(STDOUT, "**** Could not attach volume %lu ****\n",
845                         (unsigned long)a_xInfoP->volid);
846         }                       /*Screwed volume */
847     }                           /*Default listing */
848 }                               /*XDisplayFormat */
849
850 /*------------------------------------------------------------------------
851  * PRIVATE XDisplayFormat2
852  *
853  * Description:
854  *      Display the formated contents of one extended volume info structure.
855  *
856  * Arguments:
857  *      a_xInfoP        : Ptr to extended volume info struct to print.
858  *      a_servID        : Server ID to print.
859  *      a_partID        : Partition ID to print.
860  *      a_totalOKP      : Ptr to total-OK counter.
861  *      a_totalNotOKP   : Ptr to total-screwed counter.
862  *      a_totalBusyP    : Ptr to total-busy counter.
863  *      a_fast          : Fast listing?
864  *      a_int32         : Int32 listing?
865  *      a_showProblems  : Show volume problems?
866  *
867  * Returns:
868  *      Nothing.
869  *
870  * Environment:
871  *      Nothing interesting.
872  *
873  * Side Effects:
874  *      As advertised.
875  *------------------------------------------------------------------------*/
876
877 static void
878 XDisplayFormat2(volintXInfo *a_xInfoP, afs_uint32 a_servID, afs_int32 a_partID,
879                 int *a_totalOKP, int *a_totalNotOKP, int *a_totalBusyP,
880                 int a_fast, int a_int32, int a_showProblems)
881 {                               /*XDisplayFormat */
882     time_t t;
883     if (a_fast) {
884         /*
885          * Short & sweet.
886          */
887         fprintf(STDOUT, "vold_id\t%-10lu\n", (unsigned long)a_xInfoP->volid);
888     } else if (a_int32) {
889         /*
890          * Fully-detailed listing.
891          */
892         if (a_xInfoP->status == VOK) {
893             /*
894              * Volume's status is OK - all the fields are valid.
895              */
896
897                 static long server_cache = -1, partition_cache = -1;
898                 static char hostname[256], address[32], pname[16];
899                 int i,ai[] = {VOLINT_STATS_TIME_IDX_0,VOLINT_STATS_TIME_IDX_1,VOLINT_STATS_TIME_IDX_2,
900                               VOLINT_STATS_TIME_IDX_3,VOLINT_STATS_TIME_IDX_4,VOLINT_STATS_TIME_IDX_5};
901
902                 if (a_servID != server_cache) {
903                         struct in_addr s;
904
905                         s.s_addr = a_servID;
906                         strcpy(hostname, hostutil_GetNameByINet(a_servID));
907                         strcpy(address, inet_ntoa(s));
908                         server_cache = a_servID;
909                 }
910                 if (a_partID != partition_cache) {
911                         MapPartIdIntoName(a_partID, pname);
912                         partition_cache = a_partID;
913                 }
914
915                 fprintf(STDOUT, "name\t\t%s\n", a_xInfoP->name);
916                 fprintf(STDOUT, "id\t\t%lu\n", afs_printable_uint32_lu(a_xInfoP->volid));
917                 fprintf(STDOUT, "serv\t\t%s\t%s\n", address, hostname);
918                 fprintf(STDOUT, "part\t\t%s\n", pname);
919                 fprintf(STDOUT, "status\t\tOK\n");
920                 fprintf(STDOUT, "backupID\t%lu\n", 
921                         afs_printable_uint32_lu(a_xInfoP->backupID));
922                 fprintf(STDOUT, "parentID\t%lu\n", 
923                         afs_printable_uint32_lu(a_xInfoP->parentID));
924                 fprintf(STDOUT, "cloneID\t\t%lu\n", 
925                         afs_printable_uint32_lu(a_xInfoP->cloneID));
926                 fprintf(STDOUT, "inUse\t\t%s\n", a_xInfoP->inUse ? "Y" : "N");
927                 switch (a_xInfoP->type) {
928                 case 0:
929                         fprintf(STDOUT, "type\t\tRW\n");
930                         break;
931                 case 1:
932                         fprintf(STDOUT, "type\t\tRO\n");
933                         break;
934                 case 2:
935                         fprintf(STDOUT, "type\t\tBK\n");
936                         break;
937                 default:
938                         fprintf(STDOUT, "type\t\t?\n");
939                         break;
940                 }
941                 t = a_xInfoP->creationDate;
942                 fprintf(STDOUT, "creationDate\t%-9lu\t%s", 
943                         afs_printable_uint32_lu(a_xInfoP->creationDate),
944                         ctime(&t));
945
946                 t = a_xInfoP->accessDate;
947                 fprintf(STDOUT, "accessDate\t%-9lu\t%s", 
948                         afs_printable_uint32_lu(a_xInfoP->accessDate),
949                         ctime(&t));
950
951                 t = a_xInfoP->updateDate;
952                 fprintf(STDOUT, "updateDate\t%-9lu\t%s", 
953                         afs_printable_uint32_lu(a_xInfoP->updateDate),
954                         ctime(&t));
955
956                 t = a_xInfoP->backupDate;
957                 fprintf(STDOUT, "backupDate\t%-9lu\t%s", 
958                         afs_printable_uint32_lu(a_xInfoP->backupDate),
959                         ctime(&t));
960
961                 t = a_xInfoP->copyDate;
962                 fprintf(STDOUT, "copyDate\t%-9lu\t%s", 
963                         afs_printable_uint32_lu(a_xInfoP->copyDate),
964                         ctime(&t));
965                 
966                 fprintf(STDOUT, "diskused\t%u\n", a_xInfoP->size);
967                 fprintf(STDOUT, "maxquota\t%u\n", a_xInfoP->maxquota);
968
969                 fprintf(STDOUT, "filecount\t%u\n", a_xInfoP->filecount);
970                 fprintf(STDOUT, "dayUse\t\t%u\n", a_xInfoP->dayUse);
971
972
973
974                 fprintf(STDOUT,"reads_same_net\t%8d\n",a_xInfoP->stat_reads[VOLINT_STATS_SAME_NET]);
975                 fprintf(STDOUT,"reads_same_net_auth\t%8d\n",a_xInfoP->stat_reads[VOLINT_STATS_SAME_NET_AUTH]);
976                 fprintf(STDOUT,"reads_diff_net\t%8d\n",a_xInfoP->stat_reads[VOLINT_STATS_DIFF_NET]);
977                 fprintf(STDOUT,"reads_diff_net_auth\t%8d\n",a_xInfoP->stat_reads[VOLINT_STATS_DIFF_NET_AUTH]);
978
979                 fprintf(STDOUT,"writes_same_net\t%8d\n",a_xInfoP->stat_writes[VOLINT_STATS_SAME_NET]);
980                 fprintf(STDOUT,"writes_same_net_auth\t%8d\n",a_xInfoP->stat_writes[VOLINT_STATS_SAME_NET_AUTH]);
981                 fprintf(STDOUT,"writes_diff_net\t%8d\n",a_xInfoP->stat_writes[VOLINT_STATS_DIFF_NET]);
982                 fprintf(STDOUT,"writes_diff_net_auth\t%8d\n",a_xInfoP->stat_writes[VOLINT_STATS_DIFF_NET_AUTH]);
983
984                 for(i=0;i<5;i++)
985                 {
986                         fprintf(STDOUT,"file_same_author_idx_%d\t%8d\n",i+1,a_xInfoP->stat_fileSameAuthor[ai[i]]);
987                         fprintf(STDOUT,"file_diff_author_idx_%d\t%8d\n",i+1,a_xInfoP->stat_fileDiffAuthor[ai[i]]);
988                         fprintf(STDOUT,"dir_same_author_idx_%d\t%8d\n",i+1,a_xInfoP->stat_dirSameAuthor[ai[i]]);
989                         fprintf(STDOUT,"dir_dif_author_idx_%d\t%8d\n",i+1,a_xInfoP->stat_dirDiffAuthor[ai[i]]);
990                 }
991
992         } /*Volume status OK */
993         else if (a_xInfoP->status == VBUSY) {
994             (*a_totalBusyP)++;
995             qPut(&busyHead, a_xInfoP->volid);
996             if (a_showProblems)
997                 fprintf(STDOUT, "BUSY_VOL\t%lu\n",
998                         (unsigned long)a_xInfoP->volid);
999         } /*Busy volume */
1000         else {
1001             (*a_totalNotOKP)++;
1002             qPut(&notokHead, a_xInfoP->volid);
1003             if (a_showProblems)
1004                 fprintf(STDOUT, "COULD_NOT_ATTACH\t%lu\n",
1005                         (unsigned long)a_xInfoP->volid);
1006         }                       /*Screwed volume */
1007     } /*Long listing */
1008     else {
1009         /*
1010          * Default listing.
1011          */
1012         if (a_xInfoP->status == VOK) {
1013             fprintf(STDOUT, "name\t%-32s\n", a_xInfoP->name);
1014             fprintf(STDOUT, "volID\t%10lu\n", (unsigned long)a_xInfoP->volid);
1015             if (a_xInfoP->type == 0)
1016                 fprintf(STDOUT, "type\tRW\n");
1017             if (a_xInfoP->type == 1)
1018                 fprintf(STDOUT, "type\tRO\n");
1019             if (a_xInfoP->type == 2)
1020                 fprintf(STDOUT, "type\tBK\n");
1021             fprintf(STDOUT, "size\t%10dK\n", a_xInfoP->size);
1022
1023             fprintf(STDOUT, "inUse\t%d\n",a_xInfoP->inUse);
1024             if (a_xInfoP->inUse == 1)
1025                 (*a_totalOKP)++;
1026             else
1027                 (*a_totalNotOKP)++;
1028
1029         } /*Volume OK */
1030         else if (a_xInfoP->status == VBUSY) {
1031             (*a_totalBusyP)++;
1032             qPut(&busyHead, a_xInfoP->volid);
1033             if (a_showProblems)
1034                 fprintf(STDOUT, "VOLUME_BUSY\t%lu\n",
1035                         (unsigned long)a_xInfoP->volid);
1036         } /*Busy volume */
1037         else {
1038             (*a_totalNotOKP)++;
1039             qPut(&notokHead, a_xInfoP->volid);
1040             if (a_showProblems)
1041                 fprintf(STDOUT, "COULD_NOT_ATTACH_VOLUME\t%lu\n",
1042                         (unsigned long)a_xInfoP->volid);
1043         }                       /*Screwed volume */
1044     }                           /*Default listing */
1045 }                               /*XDisplayFormat */
1046
1047 static void
1048 DisplayFormat2(long server, long partition, volintInfo *pntr)
1049 {
1050     static long server_cache = -1, partition_cache = -1;
1051     static char hostname[256], address[32], pname[16];
1052     time_t t;
1053
1054     if (server != server_cache) {
1055         struct in_addr s;
1056
1057         s.s_addr = server;
1058         strcpy(hostname, hostutil_GetNameByINet(server));
1059         strcpy(address, inet_ntoa(s));
1060         server_cache = server;
1061     }
1062     if (partition != partition_cache) {
1063         MapPartIdIntoName(partition, pname);
1064         partition_cache = partition;
1065     }
1066
1067     if (pntr->status == VOK)
1068         fprintf(STDOUT, "name\t\t%s\n", pntr->name);
1069
1070     fprintf(STDOUT, "id\t\t%lu\n", 
1071             afs_printable_uint32_lu(pntr->volid));
1072     fprintf(STDOUT, "serv\t\t%s\t%s\n", address, hostname);
1073     fprintf(STDOUT, "part\t\t%s\n", pname);
1074     switch (pntr->status) {
1075     case VOK:
1076         fprintf(STDOUT, "status\t\tOK\n");
1077         break;
1078     case VBUSY:
1079         fprintf(STDOUT, "status\t\tBUSY\n");
1080         return;
1081     default:
1082         fprintf(STDOUT, "status\t\tUNATTACHABLE\n");
1083         return;
1084     }
1085     fprintf(STDOUT, "backupID\t%lu\n", 
1086             afs_printable_uint32_lu(pntr->backupID));
1087     fprintf(STDOUT, "parentID\t%lu\n", 
1088             afs_printable_uint32_lu(pntr->parentID));
1089     fprintf(STDOUT, "cloneID\t\t%lu\n", 
1090             afs_printable_uint32_lu(pntr->cloneID));
1091     fprintf(STDOUT, "inUse\t\t%s\n", pntr->inUse ? "Y" : "N");
1092     fprintf(STDOUT, "needsSalvaged\t%s\n", pntr->needsSalvaged ? "Y" : "N");
1093     /* 0xD3 is from afs/volume.h since I had trouble including the file */
1094     fprintf(STDOUT, "destroyMe\t%s\n", pntr->destroyMe == 0xD3 ? "Y" : "N");
1095     switch (pntr->type) {
1096     case 0:
1097         fprintf(STDOUT, "type\t\tRW\n");
1098         break;
1099     case 1:
1100         fprintf(STDOUT, "type\t\tRO\n");
1101         break;
1102     case 2:
1103         fprintf(STDOUT, "type\t\tBK\n");
1104         break;
1105     default:
1106         fprintf(STDOUT, "type\t\t?\n");
1107         break;
1108     }
1109     t = pntr->creationDate;
1110     fprintf(STDOUT, "creationDate\t%-9lu\t%s", 
1111             afs_printable_uint32_lu(pntr->creationDate),
1112             ctime(&t));
1113
1114     t = pntr->accessDate;
1115     fprintf(STDOUT, "accessDate\t%-9lu\t%s", 
1116             afs_printable_uint32_lu(pntr->accessDate),
1117             ctime(&t));
1118
1119     t = pntr->updateDate;
1120     fprintf(STDOUT, "updateDate\t%-9lu\t%s", 
1121             afs_printable_uint32_lu(pntr->updateDate),
1122             ctime(&t));
1123
1124     t = pntr->backupDate;
1125     fprintf(STDOUT, "backupDate\t%-9lu\t%s", 
1126             afs_printable_uint32_lu(pntr->backupDate),
1127             ctime(&t));
1128
1129     t = pntr->copyDate;
1130     fprintf(STDOUT, "copyDate\t%-9lu\t%s", 
1131             afs_printable_uint32_lu(pntr->copyDate),
1132             ctime(&t));
1133
1134     fprintf(STDOUT, "flags\t\t%#lx\t(Optional)\n", 
1135             afs_printable_uint32_lu(pntr->flags));
1136     fprintf(STDOUT, "diskused\t%u\n", pntr->size);
1137     fprintf(STDOUT, "maxquota\t%u\n", pntr->maxquota);
1138     fprintf(STDOUT, "minquota\t%lu\t(Optional)\n", 
1139             afs_printable_uint32_lu(pntr->spare0));
1140     fprintf(STDOUT, "filecount\t%u\n", pntr->filecount);
1141     fprintf(STDOUT, "dayUse\t\t%u\n", pntr->dayUse);
1142     fprintf(STDOUT, "weekUse\t\t%lu\t(Optional)\n",
1143             afs_printable_uint32_lu(pntr->spare1));
1144     fprintf(STDOUT, "spare2\t\t%lu\t(Optional)\n", 
1145             afs_printable_uint32_lu(pntr->spare2));
1146     fprintf(STDOUT, "spare3\t\t%lu\t(Optional)\n", 
1147             afs_printable_uint32_lu(pntr->spare3));
1148     return;
1149 }
1150
1151 static void
1152 DisplayVolumes2(long server, long partition, volintInfo *pntr, long count)
1153 {
1154     long i;
1155
1156     for (i = 0; i < count; i++) {
1157         fprintf(STDOUT, "BEGIN_OF_ENTRY\n");
1158         DisplayFormat2(server, partition, pntr);
1159         fprintf(STDOUT, "END_OF_ENTRY\n\n");
1160         pntr++;
1161     }
1162     return;
1163 }
1164
1165 static void
1166 DisplayVolumes(afs_uint32 server, afs_int32 part, volintInfo *pntr,
1167                afs_int32 count, afs_int32 longlist, afs_int32 fast,
1168                int quiet)
1169 {
1170     int totalOK, totalNotOK, totalBusy, i;
1171     afs_uint32 volid = 0;
1172
1173     totalOK = 0;
1174     totalNotOK = 0;
1175     totalBusy = 0;
1176     qInit(&busyHead);
1177     qInit(&notokHead);
1178     for (i = 0; i < count; i++) {
1179         DisplayFormat(pntr, server, part, &totalOK, &totalNotOK, &totalBusy,
1180                       fast, longlist, 0);
1181         pntr++;
1182     }
1183     if (totalBusy) {
1184         while (busyHead.count) {
1185             qGet(&busyHead, &volid);
1186             fprintf(STDOUT, "**** Volume %lu is busy ****\n",
1187                     (unsigned long)volid);
1188         }
1189     }
1190     if (totalNotOK) {
1191         while (notokHead.count) {
1192             qGet(&notokHead, &volid);
1193             fprintf(STDOUT, "**** Could not attach volume %lu ****\n",
1194                     (unsigned long)volid);
1195         }
1196     }
1197     if (!quiet) {
1198         fprintf(STDOUT, "\n");
1199         if (!fast) {
1200             fprintf(STDOUT,
1201                     "Total volumes onLine %d ; Total volumes offLine %d ; Total busy %d\n\n",
1202                     totalOK, totalNotOK, totalBusy);
1203         }
1204     }
1205 }
1206 /*------------------------------------------------------------------------
1207  * PRIVATE XDisplayVolumes
1208  *
1209  * Description:
1210  *      Display extended volume information.
1211  *
1212  * Arguments:
1213  *      a_servID : Pointer to the Rx call we're performing.
1214  *      a_partID : Partition for which we want the extended list.
1215  *      a_xInfoP : Ptr to extended volume info.
1216  *      a_count  : Number of volume records contained above.
1217  *      a_int32   : Int32 listing generated?
1218  *      a_fast   : Fast listing generated?
1219  *      a_quiet  : Quiet listing generated?
1220  *
1221  * Returns:
1222  *      Nothing.
1223  *
1224  * Environment:
1225  *      Nothing interesting.
1226  *
1227  * Side Effects:
1228  *      As advertised.
1229  *------------------------------------------------------------------------*/
1230
1231 static void
1232 XDisplayVolumes(afs_uint32 a_servID, afs_int32 a_partID, volintXInfo *a_xInfoP,
1233                 afs_int32 a_count, afs_int32 a_int32, afs_int32 a_fast,
1234                 int a_quiet)
1235 {                               /*XDisplayVolumes */
1236
1237     int totalOK;                /*Total OK volumes */
1238     int totalNotOK;             /*Total screwed volumes */
1239     int totalBusy;              /*Total busy volumes */
1240     int i;                      /*Loop variable */
1241     afs_uint32 volid = 0;       /*Current volume ID */
1242
1243     /*
1244      * Initialize counters and (global!!) queues.
1245      */
1246     totalOK = 0;
1247     totalNotOK = 0;
1248     totalBusy = 0;
1249     qInit(&busyHead);
1250     qInit(&notokHead);
1251
1252     /*
1253      * Display each volume in the list.
1254      */
1255     for (i = 0; i < a_count; i++) {
1256         XDisplayFormat(a_xInfoP, a_servID, a_partID, &totalOK, &totalNotOK,
1257                        &totalBusy, a_fast, a_int32, 0);
1258         a_xInfoP++;
1259     }
1260
1261     /*
1262      * If any volumes were found to be busy or screwed, display them.
1263      */
1264     if (totalBusy) {
1265         while (busyHead.count) {
1266             qGet(&busyHead, &volid);
1267             fprintf(STDOUT, "**** Volume %lu is busy ****\n",
1268                     (unsigned long)volid);
1269         }
1270     }
1271     if (totalNotOK) {
1272         while (notokHead.count) {
1273             qGet(&notokHead, &volid);
1274             fprintf(STDOUT, "**** Could not attach volume %lu ****\n",
1275                     (unsigned long)volid);
1276         }
1277     }
1278
1279     if (!a_quiet) {
1280         fprintf(STDOUT, "\n");
1281         if (!a_fast) {
1282             fprintf(STDOUT,
1283                     "Total volumes: %d on-line, %d off-line, %d  busyd\n\n",
1284                     totalOK, totalNotOK, totalBusy);
1285         }
1286     }
1287
1288 }                               /*XDisplayVolumes */
1289
1290 /*------------------------------------------------------------------------
1291  * PRIVATE XDisplayVolumes2
1292  *
1293  * Description:
1294  *      Display extended formated volume information.
1295  *
1296  * Arguments:
1297  *      a_servID : Pointer to the Rx call we're performing.
1298  *      a_partID : Partition for which we want the extended list.
1299  *      a_xInfoP : Ptr to extended volume info.
1300  *      a_count  : Number of volume records contained above.
1301  *      a_int32   : Int32 listing generated?
1302  *      a_fast   : Fast listing generated?
1303  *      a_quiet  : Quiet listing generated?
1304  *
1305  * Returns:
1306  *      Nothing.
1307  *
1308  * Environment:
1309  *      Nothing interesting.
1310  *
1311  * Side Effects:
1312  *      As advertised.
1313  *------------------------------------------------------------------------*/
1314
1315 static void
1316 XDisplayVolumes2(afs_uint32 a_servID, afs_int32 a_partID, volintXInfo *a_xInfoP,
1317                  afs_int32 a_count, afs_int32 a_int32, afs_int32 a_fast,
1318                  int a_quiet)
1319 {                               /*XDisplayVolumes */
1320
1321     int totalOK;                /*Total OK volumes */
1322     int totalNotOK;             /*Total screwed volumes */
1323     int totalBusy;              /*Total busy volumes */
1324     int i;                      /*Loop variable */
1325     afs_uint32 volid = 0;       /*Current volume ID */
1326
1327     /*
1328      * Initialize counters and (global!!) queues.
1329      */
1330     totalOK = 0;
1331     totalNotOK = 0;
1332     totalBusy = 0;
1333     qInit(&busyHead);
1334     qInit(&notokHead);
1335
1336     /*
1337      * Display each volume in the list.
1338      */
1339     for (i = 0; i < a_count; i++) {
1340         fprintf(STDOUT, "BEGIN_OF_ENTRY\n");
1341         XDisplayFormat2(a_xInfoP, a_servID, a_partID, &totalOK, &totalNotOK,
1342                        &totalBusy, a_fast, a_int32, 0);
1343         fprintf(STDOUT, "END_OF_ENTRY\n");
1344         a_xInfoP++;
1345     }
1346
1347     /*
1348      * If any volumes were found to be busy or screwed, display them.
1349      */
1350     if (totalBusy) {
1351         while (busyHead.count) {
1352             qGet(&busyHead, &volid);
1353             fprintf(STDOUT, "BUSY_VOL\t%lu\n",
1354                     (unsigned long)volid);
1355         }
1356     }
1357     if (totalNotOK) {
1358         while (notokHead.count) {
1359             qGet(&notokHead, &volid);
1360             fprintf(STDOUT, "COULD_NOT_ATTACH\t%lu\n",
1361                     (unsigned long)volid);
1362         }
1363     }
1364
1365     if (!a_quiet) {
1366         fprintf(STDOUT, "\n");
1367         if (!a_fast) {
1368             fprintf(STDOUT,
1369                     "VOLUMES_ONLINE\t%d\nVOLUMES_OFFLINE\t%d\nVOLUMES_BUSY\t%d\n",
1370                     totalOK, totalNotOK, totalBusy);
1371         }
1372     }
1373
1374 }                               /*XDisplayVolumes2 */
1375
1376
1377 /* set <server> and <part> to the correct values depending on 
1378  * <voltype> and <entry> */
1379 static void
1380 GetServerAndPart(struct nvldbentry *entry, int voltype, afs_uint32 *server,
1381                  afs_int32 *part, int *previdx)
1382 {
1383     int i, istart, vtype;
1384
1385     *server = -1;
1386     *part = -1;
1387
1388     /* Doesn't check for non-existance of backup volume */
1389     if ((voltype == RWVOL) || (voltype == BACKVOL)) {
1390         vtype = ITSRWVOL;
1391         istart = 0;             /* seach the entire entry */
1392     } else {
1393         vtype = ITSROVOL;
1394         /* Seach from beginning of entry or pick up where we left off */
1395         istart = ((*previdx < 0) ? 0 : *previdx + 1);
1396     }
1397
1398     for (i = istart; i < entry->nServers; i++) {
1399         if (entry->serverFlags[i] & vtype) {
1400             *server = entry->serverNumber[i];
1401             *part = entry->serverPartition[i];
1402             *previdx = i;
1403             return;
1404         }
1405     }
1406
1407     /* Didn't find any, return -1 */
1408     *previdx = -1;
1409     return;
1410 }
1411
1412 static void
1413 PrintLocked(afs_int32 aflags)
1414 {
1415     afs_int32 flags = aflags & VLOP_ALLOPERS;
1416
1417     if (flags) {
1418         fprintf(STDOUT, "    Volume is currently LOCKED  \n");
1419
1420         if (flags & VLOP_MOVE) {
1421             fprintf(STDOUT, "    Volume is locked for a move operation\n");
1422         }
1423         if (flags & VLOP_RELEASE) {
1424             fprintf(STDOUT, "    Volume is locked for a release operation\n");
1425         }
1426         if (flags & VLOP_BACKUP) {
1427             fprintf(STDOUT, "    Volume is locked for a backup operation\n");
1428         }
1429         if (flags & VLOP_DELETE) {
1430             fprintf(STDOUT, "    Volume is locked for a delete/misc operation\n");
1431         }
1432         if (flags & VLOP_DUMP) {
1433             fprintf(STDOUT, "    Volume is locked for a dump/restore operation\n");
1434         }
1435     }
1436 }
1437
1438 static void
1439 PostVolumeStats(struct nvldbentry *entry)
1440 {
1441     SubEnumerateEntry(entry);
1442     /* Check for VLOP_ALLOPERS */
1443     PrintLocked(entry->flags);
1444     return;
1445 }
1446
1447 /*------------------------------------------------------------------------
1448  * PRIVATE XVolumeStats
1449  *
1450  * Description:
1451  *      Display extended volume information.
1452  *
1453  * Arguments:
1454  *      a_xInfoP  : Ptr to extended volume info.
1455  *      a_entryP  : Ptr to the volume's VLDB entry.
1456  *      a_srvID   : Server ID.
1457  *      a_partID  : Partition ID.
1458  *      a_volType : Type of volume to print.
1459  *
1460  * Returns:
1461  *      Nothing.
1462  *
1463  * Environment:
1464  *      Nothing interesting.
1465  *
1466  * Side Effects:
1467  *      As advertised.
1468  *------------------------------------------------------------------------*/
1469
1470 static void
1471 XVolumeStats(volintXInfo *a_xInfoP, struct nvldbentry *a_entryP,
1472              afs_int32 a_srvID, afs_int32 a_partID, int a_volType)
1473 {                               /*XVolumeStats */
1474
1475     int totalOK, totalNotOK, totalBusy; /*Dummies - we don't really count here */
1476
1477     XDisplayFormat(a_xInfoP,    /*Ptr to extended volume info */
1478                    a_srvID,     /*Server ID to print */
1479                    a_partID,    /*Partition ID to print */
1480                    &totalOK,    /*Ptr to total-OK counter */
1481                    &totalNotOK, /*Ptr to total-screwed counter */
1482                    &totalBusy,  /*Ptr to total-busy counter */
1483                    0,           /*Don't do a fast listing */
1484                    1,           /*Do a long listing */
1485                    1);          /*Show volume problems */
1486     return;
1487
1488 }                               /*XVolumeStats */
1489
1490 static void
1491 VolumeStats_int(volintInfo *pntr, struct nvldbentry *entry, afs_uint32 server,
1492              afs_int32 part, int voltype)
1493 {
1494     int totalOK, totalNotOK, totalBusy;
1495
1496     DisplayFormat(pntr, server, part, &totalOK, &totalNotOK, &totalBusy, 0, 1,
1497                   1);
1498     return;
1499 }
1500
1501 /* command to forcibly remove a volume */
1502 static int
1503 NukeVolume(register struct cmd_syndesc *as)
1504 {
1505     register afs_int32 code;
1506     afs_uint32 volID;
1507     afs_int32  err;
1508     afs_int32 partID;
1509     afs_uint32 server;
1510     register char *tp;
1511
1512     server = GetServer(tp = as->parms[0].items->data);
1513     if (!server) {
1514         fprintf(STDERR, "vos: server '%s' not found in host table\n", tp);
1515         return 1;
1516     }
1517
1518     partID = volutil_GetPartitionID(tp = as->parms[1].items->data);
1519     if (partID == -1) {
1520         fprintf(STDERR, "vos: could not parse '%s' as a partition name", tp);
1521         return 1;
1522     }
1523
1524     volID = vsu_GetVolumeID(tp = as->parms[2].items->data, cstruct, &err);
1525     if (volID == 0) {
1526         if (err)
1527             PrintError("", err);
1528         else
1529             fprintf(STDERR,
1530                     "vos: could not parse '%s' as a numeric volume ID", tp);
1531         return 1;
1532     }
1533
1534     fprintf(STDOUT,
1535             "vos: forcibly removing all traces of volume %d, please wait...",
1536             volID);
1537     fflush(STDOUT);
1538     code = UV_NukeVolume(server, partID, volID);
1539     if (code == 0)
1540         fprintf(STDOUT, "done.\n");
1541     else
1542         fprintf(STDOUT, "failed with code %d.\n", code);
1543     return code;
1544 }
1545
1546
1547 /*------------------------------------------------------------------------
1548  * PRIVATE ExamineVolume
1549  *
1550  * Description:
1551  *      Routine used to examine a single volume, contacting the VLDB as
1552  *      well as the Volume Server.
1553  *
1554  * Arguments:
1555  *      as : Ptr to parsed command line arguments.
1556  *
1557  * Returns:
1558  *      0 for a successful operation,
1559  *      Otherwise, one of the ubik or VolServer error values.
1560  *
1561  * Environment:
1562  *      Nothing interesting.
1563  *
1564  * Side Effects:
1565  *      As advertised.
1566  *------------------------------------------------------------------------
1567  */
1568 static int
1569 ExamineVolume(register struct cmd_syndesc *as, void *arock)
1570 {
1571     struct nvldbentry entry;
1572     afs_int32 vcode = 0;
1573     volintInfo *pntr = (volintInfo *) 0;
1574     volintXInfo *xInfoP = (volintXInfo *) 0;
1575     afs_uint32 volid;
1576     afs_int32 code, err, error = 0;
1577     int voltype, foundserv = 0, foundentry = 0;
1578     afs_uint32 aserver;
1579     afs_int32 apart;
1580     int previdx = -1;
1581     int wantExtendedInfo;       /*Do we want extended vol info? */
1582     int isSubEnum=0;            /* Keep track whether sub enumerate called. */
1583     wantExtendedInfo = (as->parms[1].items ? 1 : 0);    /* -extended */
1584
1585     volid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);   /* -id */
1586     if (volid == 0) {
1587         if (err)
1588             PrintError("", err);
1589         else
1590             fprintf(STDERR, "Unknown volume ID or name '%s'\n",
1591                     as->parms[0].items->data);
1592         return -1;
1593     }
1594
1595     if (verbose) {
1596         fprintf(STDOUT, "Fetching VLDB entry for %lu .. ",
1597                 (unsigned long)volid);
1598         fflush(STDOUT);
1599     }
1600     vcode = VLDB_GetEntryByID(volid, -1, &entry);
1601     if (vcode) {
1602         fprintf(STDERR,
1603                 "Could not fetch the entry for volume number %lu from VLDB \n",
1604                 (unsigned long)volid);
1605         return (vcode);
1606     }
1607     if (verbose)
1608         fprintf(STDOUT, "done\n");
1609     MapHostToNetwork(&entry);
1610
1611     if (entry.volumeId[RWVOL] == volid)
1612         voltype = RWVOL;
1613     else if (entry.volumeId[BACKVOL] == volid)
1614         voltype = BACKVOL;
1615     else                        /* (entry.volumeId[ROVOL] == volid) */
1616         voltype = ROVOL;
1617
1618     do {                        /* do {...} while (voltype == ROVOL) */
1619         /* Get the entry for the volume. If its a RW vol, get the RW entry.
1620          * It its a BK vol, get the RW entry (even if VLDB may say the BK doen't exist).
1621          * If its a RO vol, get the next RO entry.
1622          */
1623         GetServerAndPart(&entry, ((voltype == ROVOL) ? ROVOL : RWVOL),
1624                          &aserver, &apart, &previdx);
1625         if (previdx == -1) {    /* searched all entries */
1626             if (!foundentry) {
1627                 fprintf(STDERR, "Volume %s does not exist in VLDB\n\n",
1628                         as->parms[0].items->data);
1629                 error = ENOENT;
1630             }
1631             break;
1632         }
1633         foundentry = 1;
1634
1635         /* Get information about the volume from the server */
1636         if (verbose) {
1637             fprintf(STDOUT, "Getting volume listing from the server %s .. ",
1638                     hostutil_GetNameByINet(aserver));
1639             fflush(STDOUT);
1640         }
1641         if (wantExtendedInfo)
1642             code = UV_XListOneVolume(aserver, apart, volid, &xInfoP);
1643         else
1644             code = UV_ListOneVolume(aserver, apart, volid, &pntr);
1645         if (verbose)
1646             fprintf(STDOUT, "done\n");
1647
1648         if (code) {
1649             error = code;
1650             if (code == ENODEV) {
1651                 if ((voltype == BACKVOL) && !(entry.flags & BACK_EXISTS)) {
1652                     /* The VLDB says there is no backup volume and its not on disk */
1653                     fprintf(STDERR, "Volume %s does not exist\n",
1654                             as->parms[0].items->data);
1655                     error = ENOENT;
1656                 } else {
1657                     fprintf(STDERR,
1658                             "Volume does not exist on server %s as indicated by the VLDB\n",
1659                             hostutil_GetNameByINet(aserver));
1660                 }
1661             } else {
1662                 PrintDiagnostics("examine", code);
1663             }
1664             fprintf(STDOUT, "\n");
1665         } else {
1666             foundserv = 1;
1667             if (wantExtendedInfo)
1668                 XVolumeStats(xInfoP, &entry, aserver, apart, voltype);
1669             else if (as->parms[2].items) {
1670                 DisplayFormat2(aserver, apart, pntr);
1671                 EnumerateEntry(&entry);
1672                 isSubEnum = 1;
1673             } else
1674                 VolumeStats_int(pntr, &entry, aserver, apart, voltype);
1675
1676             if ((voltype == BACKVOL) && !(entry.flags & BACK_EXISTS)) {
1677                 /* The VLDB says there is no backup volume yet we found one on disk */
1678                 fprintf(STDERR, "Volume %s does not exist in VLDB\n",
1679                         as->parms[0].items->data);
1680                 error = ENOENT;
1681             }
1682         }
1683
1684         if (pntr)
1685             free(pntr);
1686         if (xInfoP)
1687             free(xInfoP);
1688     } while (voltype == ROVOL);
1689
1690     if (!foundserv) {
1691         fprintf(STDERR, "Dump only information from VLDB\n\n");
1692         fprintf(STDOUT, "%s \n", entry.name);   /* PostVolumeStats doesn't print name */
1693     }
1694
1695     if (!isSubEnum)
1696         PostVolumeStats(&entry);
1697
1698     return (error);
1699 }
1700
1701 /*------------------------------------------------------------------------
1702  * PRIVATE SetFields
1703  *
1704  * Description:
1705  *      Routine used to change the status of a single volume.
1706  *
1707  * Arguments:
1708  *      as : Ptr to parsed command line arguments.
1709  *
1710  * Returns:
1711  *      0 for a successful operation,
1712  *      Otherwise, one of the ubik or VolServer error values.
1713  *
1714  * Environment:
1715  *      Nothing interesting.
1716  *
1717  * Side Effects:
1718  *      As advertised.
1719  *------------------------------------------------------------------------
1720  */
1721 static int
1722 SetFields(register struct cmd_syndesc *as, void *arock)
1723 {
1724     struct nvldbentry entry;
1725     volintInfo info;
1726     afs_uint32 volid;
1727     afs_int32 code, err;
1728     afs_uint32 aserver;
1729     afs_int32 apart;
1730     int previdx = -1;
1731
1732     volid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);   /* -id */
1733     if (volid == 0) {
1734         if (err)
1735             PrintError("", err);
1736         else
1737             fprintf(STDERR, "Unknown volume ID or name '%s'\n",
1738                     as->parms[0].items->data);
1739         return -1;
1740     }
1741
1742     code = VLDB_GetEntryByID(volid, RWVOL, &entry);
1743     if (code) {
1744         fprintf(STDERR,
1745                 "Could not fetch the entry for volume number %lu from VLDB \n",
1746                 (unsigned long)volid);
1747         return (code);
1748     }
1749     MapHostToNetwork(&entry);
1750
1751     GetServerAndPart(&entry, RWVOL, &aserver, &apart, &previdx);
1752     if (previdx == -1) {
1753         fprintf(STDERR, "Volume %s does not exist in VLDB\n\n",
1754                 as->parms[0].items->data);
1755         return (ENOENT);
1756     }
1757
1758     init_volintInfo(&info);
1759     info.volid = volid;
1760     info.type = RWVOL;
1761
1762     if (as->parms[1].items) {
1763         /* -max <quota> */
1764         code = util_GetHumanInt32(as->parms[1].items->data, &info.maxquota);
1765         if (code) {
1766             fprintf(STDERR, "invalid quota value\n");
1767             return code;
1768         }
1769     }
1770     if (as->parms[2].items) {
1771         /* -clearuse */
1772         info.dayUse = 0;
1773     }
1774     if (as->parms[3].items) {
1775         /* -clearVolUpCounter */
1776         info.spare2 = 0;
1777     }
1778     code = UV_SetVolumeInfo(aserver, apart, volid, &info);
1779     if (code)
1780         fprintf(STDERR,
1781                 "Could not update volume info fields for volume number %lu\n",
1782                 (unsigned long)volid);
1783     return (code);
1784 }
1785
1786 /*------------------------------------------------------------------------
1787  * PRIVATE volOnline
1788  *
1789  * Description:
1790  *      Brings a volume online.
1791  *
1792  * Arguments:
1793  *      as : Ptr to parsed command line arguments.
1794  *
1795  * Returns:
1796  *      0 for a successful operation,
1797  *
1798  * Environment:
1799  *      Nothing interesting.
1800  *
1801  * Side Effects:
1802  *      As advertised.
1803  *------------------------------------------------------------------------
1804  */
1805 static int
1806 volOnline(register struct cmd_syndesc *as, void *arock)
1807 {
1808     afs_uint32 server;
1809     afs_int32 partition;
1810     afs_uint32 volid;
1811     afs_int32 code, err = 0;
1812
1813     server = GetServer(as->parms[0].items->data);
1814     if (server == 0) {
1815         fprintf(STDERR, "vos: server '%s' not found in host table\n",
1816                 as->parms[0].items->data);
1817         return -1;
1818     }
1819
1820     partition = volutil_GetPartitionID(as->parms[1].items->data);
1821     if (partition < 0) {
1822         fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
1823                 as->parms[1].items->data);
1824         return ENOENT;
1825     }
1826
1827     volid = vsu_GetVolumeID(as->parms[2].items->data, cstruct, &err);   /* -id */
1828     if (!volid) {
1829         if (err)
1830             PrintError("", err);
1831         else
1832             fprintf(STDERR, "Unknown volume ID or name '%s'\n",
1833                     as->parms[0].items->data);
1834         return -1;
1835     }
1836
1837     code = UV_SetVolume(server, partition, volid, ITOffline, 0 /*online */ ,
1838                         0 /*sleep */ );
1839     if (code) {
1840         fprintf(STDERR, "Failed to set volume. Code = %d\n", code);
1841         return -1;
1842     }
1843
1844     return 0;
1845 }
1846
1847 /*------------------------------------------------------------------------
1848  * PRIVATE volOffline
1849  *
1850  * Description:
1851  *      Brings a volume offline.
1852  *
1853  * Arguments:
1854  *      as : Ptr to parsed command line arguments.
1855  *
1856  * Returns:
1857  *      0 for a successful operation,
1858  *
1859  * Environment:
1860  *      Nothing interesting.
1861  *
1862  * Side Effects:
1863  *      As advertised.
1864  *------------------------------------------------------------------------
1865  */
1866 static int
1867 volOffline(register struct cmd_syndesc *as, void *arock)
1868 {
1869     afs_uint32 server;
1870     afs_int32 partition;
1871     afs_uint32 volid;
1872     afs_int32 code, err = 0;
1873     afs_int32 transflag, sleeptime, transdone;
1874
1875     server = GetServer(as->parms[0].items->data);
1876     if (server == 0) {
1877         fprintf(STDERR, "vos: server '%s' not found in host table\n",
1878                 as->parms[0].items->data);
1879         return -1;
1880     }
1881
1882     partition = volutil_GetPartitionID(as->parms[1].items->data);
1883     if (partition < 0) {
1884         fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
1885                 as->parms[1].items->data);
1886         return ENOENT;
1887     }
1888
1889     volid = vsu_GetVolumeID(as->parms[2].items->data, cstruct, &err);   /* -id */
1890     if (!volid) {
1891         if (err)
1892             PrintError("", err);
1893         else
1894             fprintf(STDERR, "Unknown volume ID or name '%s'\n",
1895                     as->parms[0].items->data);
1896         return -1;
1897     }
1898
1899     transflag = (as->parms[4].items ? ITBusy : ITOffline);
1900     sleeptime = (as->parms[3].items ? atol(as->parms[3].items->data) : 0);
1901     transdone = (sleeptime ? 0 /*online */ : VTOutOfService);
1902     if (as->parms[4].items && !as->parms[3].items) {
1903         fprintf(STDERR, "-sleep option must be used with -busy flag\n");
1904         return -1;
1905     }
1906
1907     code =
1908         UV_SetVolume(server, partition, volid, transflag, transdone,
1909                      sleeptime);
1910     if (code) {
1911         fprintf(STDERR, "Failed to set volume. Code = %d\n", code);
1912         return -1;
1913     }
1914
1915     return 0;
1916 }
1917
1918 static int
1919 CreateVolume(register struct cmd_syndesc *as, void *arock)
1920 {
1921     afs_int32 pnum;
1922     char part[10];
1923     afs_uint32 volid = 0, rovolid = 0, bkvolid = 0;
1924     afs_uint32 *arovolid;
1925     afs_int32 code;
1926     struct nvldbentry entry;
1927     afs_int32 vcode;
1928     afs_int32 quota;
1929
1930     arovolid = &rovolid;
1931
1932     quota = 5000;
1933     tserver = GetServer(as->parms[0].items->data);
1934     if (!tserver) {
1935         fprintf(STDERR, "vos: host '%s' not found in host table\n",
1936                 as->parms[0].items->data);
1937         return ENOENT;
1938     }
1939     pnum = volutil_GetPartitionID(as->parms[1].items->data);
1940     if (pnum < 0) {
1941         fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
1942                 as->parms[1].items->data);
1943         return ENOENT;
1944     }
1945     if (!IsPartValid(pnum, tserver, &code)) {   /*check for validity of the partition */
1946         if (code)
1947             PrintError("", code);
1948         else
1949             fprintf(STDERR,
1950                     "vos : partition %s does not exist on the server\n",
1951                     as->parms[1].items->data);
1952         return ENOENT;
1953     }
1954     if (!ISNAMEVALID(as->parms[2].items->data)) {
1955         fprintf(STDERR,
1956                 "vos: the name of the root volume %s exceeds the size limit of %d\n",
1957                 as->parms[2].items->data, VOLSER_OLDMAXVOLNAME - 10);
1958         return E2BIG;
1959     }
1960     if (!VolNameOK(as->parms[2].items->data)) {
1961         fprintf(STDERR,
1962                 "Illegal volume name %s, should not end in .readonly or .backup\n",
1963                 as->parms[2].items->data);
1964         return EINVAL;
1965     }
1966     if (IsNumeric(as->parms[2].items->data)) {
1967         fprintf(STDERR, "Illegal volume name %s, should not be a number\n",
1968                 as->parms[2].items->data);
1969         return EINVAL;
1970     }
1971     vcode = VLDB_GetEntryByName(as->parms[2].items->data, &entry);
1972     if (!vcode) {
1973         fprintf(STDERR, "Volume %s already exists\n",
1974                 as->parms[2].items->data);
1975         PrintDiagnostics("create", code);
1976         return EEXIST;
1977     }
1978
1979     if (as->parms[3].items) {
1980         code = util_GetHumanInt32(as->parms[3].items->data, &quota);
1981         if (code) {
1982             fprintf(STDERR, "vos: bad integer specified for quota.\n");
1983             return code;
1984         }
1985     }
1986
1987     if (as->parms[4].items) {
1988         if (!IsNumeric(as->parms[4].items->data)) {
1989             fprintf(STDERR, "vos: Given volume ID %s should be numeric.\n",
1990                     as->parms[4].items->data);
1991             return EINVAL;
1992         }
1993
1994         code = util_GetUInt32(as->parms[4].items->data, &volid);
1995         if (code) {
1996             fprintf(STDERR, "vos: bad integer specified for volume ID.\n");
1997             return code;
1998         }
1999     }
2000
2001     if (as->parms[5].items) {
2002         if (!IsNumeric(as->parms[5].items->data)) {
2003             fprintf(STDERR, "vos: Given RO volume ID %s should be numeric.\n",
2004                     as->parms[5].items->data);
2005             return EINVAL;
2006         }
2007
2008         code = util_GetUInt32(as->parms[5].items->data, &rovolid);
2009         if (code) {
2010             fprintf(STDERR, "vos: bad integer specified for volume ID.\n");
2011             return code;
2012         }
2013
2014         if (rovolid == 0) {
2015             arovolid = NULL;
2016         }
2017     }
2018
2019     code =
2020         UV_CreateVolume3(tserver, pnum, as->parms[2].items->data, quota, 0,
2021                          0, 0, 0, &volid, arovolid, &bkvolid);
2022     if (code) {
2023         PrintDiagnostics("create", code);
2024         return code;
2025     }
2026     MapPartIdIntoName(pnum, part);
2027     fprintf(STDOUT, "Volume %lu created on partition %s of %s\n",
2028             (unsigned long)volid, part, as->parms[0].items->data);
2029
2030     return 0;
2031 }
2032
2033 #if 0
2034 static afs_int32
2035 DeleteAll(struct nvldbentry *entry)
2036 {
2037     int i;
2038     afs_int32 error, code, curserver, curpart;
2039     afs_uint32 volid;
2040
2041     MapHostToNetwork(entry);
2042     error = 0;
2043     for (i = 0; i < entry->nServers; i++) {
2044         curserver = entry->serverNumber[i];
2045         curpart = entry->serverPartition[i];
2046         if (entry->serverFlags[i] & ITSROVOL) {
2047             volid = entry->volumeId[ROVOL];
2048         } else {
2049             volid = entry->volumeId[RWVOL];
2050         }
2051         code = UV_DeleteVolume(curserver, curpart, volid);
2052         if (code && !error)
2053             error = code;
2054     }
2055     return error;
2056 }
2057 #endif
2058
2059 static int
2060 DeleteVolume(struct cmd_syndesc *as, void *arock)
2061 {
2062     afs_int32 err, code = 0;
2063     afs_uint32 server = 0;
2064     afs_int32 partition = -1;
2065     afs_uint32 volid;
2066     char pname[10];
2067     afs_int32 idx, j;
2068
2069     if (as->parms[0].items) {
2070         server = GetServer(as->parms[0].items->data);
2071         if (!server) {
2072             fprintf(STDERR, "vos: server '%s' not found in host table\n",
2073                     as->parms[0].items->data);
2074             return ENOENT;
2075         }
2076     }
2077
2078     if (as->parms[1].items) {
2079         partition = volutil_GetPartitionID(as->parms[1].items->data);
2080         if (partition < 0) {
2081             fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
2082                     as->parms[1].items->data);
2083             return EINVAL;
2084         }
2085
2086         /* Check for validity of the partition */
2087         if (!IsPartValid(partition, server, &code)) {
2088             if (code) {
2089                 PrintError("", code);
2090             } else {
2091                 fprintf(STDERR,
2092                         "vos : partition %s does not exist on the server\n",
2093                         as->parms[1].items->data);
2094             }
2095             return ENOENT;
2096         }
2097     }
2098
2099     volid = vsu_GetVolumeID(as->parms[2].items->data, cstruct, &err);
2100     if (volid == 0) {
2101         fprintf(STDERR, "Can't find volume name '%s' in VLDB\n",
2102                 as->parms[2].items->data);
2103         if (err)
2104             PrintError("", err);
2105         return ENOENT;
2106     }
2107
2108     /* If the server or partition option are not complete, try to fill
2109      * them in from the VLDB entry.
2110      */
2111     if ((partition == -1) || !server) {
2112         struct nvldbentry entry;
2113
2114         code = VLDB_GetEntryByID(volid, -1, &entry);
2115         if (code) {
2116             fprintf(STDERR,
2117                     "Could not fetch the entry for volume %lu from VLDB\n",
2118                     (unsigned long)volid);
2119             PrintError("", code);
2120             return (code);
2121         }
2122
2123         if (((volid == entry.volumeId[RWVOL]) && (entry.flags & RW_EXISTS))
2124             || ((volid == entry.volumeId[BACKVOL])
2125                 && (entry.flags & BACK_EXISTS))) {
2126             idx = Lp_GetRwIndex(&entry);
2127             if ((idx == -1) || (server && (server != entry.serverNumber[idx]))
2128                 || ((partition != -1)
2129                     && (partition != entry.serverPartition[idx]))) {
2130                 fprintf(STDERR, "VLDB: Volume '%s' no match\n",
2131                         as->parms[2].items->data);
2132                 return ENOENT;
2133             }
2134         } else if ((volid == entry.volumeId[ROVOL])
2135                    && (entry.flags & RO_EXISTS)) {
2136             for (idx = -1, j = 0; j < entry.nServers; j++) {
2137                 if (entry.serverFlags[j] != ITSROVOL)
2138                     continue;
2139
2140                 if (((server == 0) || (server == entry.serverNumber[j]))
2141                     && ((partition == -1)
2142                         || (partition == entry.serverPartition[j]))) {
2143                     if (idx != -1) {
2144                         fprintf(STDERR,
2145                                 "VLDB: Volume '%s' matches more than one RO\n",
2146                                 as->parms[2].items->data);
2147                         return ENOENT;
2148                     }
2149                     idx = j;
2150                 }
2151             }
2152             if (idx == -1) {
2153                 fprintf(STDERR, "VLDB: Volume '%s' no match\n",
2154                         as->parms[2].items->data);
2155                 return ENOENT;
2156             }
2157         } else {
2158             fprintf(STDERR, "VLDB: Volume '%s' no match\n",
2159                     as->parms[2].items->data);
2160             return ENOENT;
2161         }
2162
2163         server = htonl(entry.serverNumber[idx]);
2164         partition = entry.serverPartition[idx];
2165     }
2166
2167
2168     code = UV_DeleteVolume(server, partition, volid);
2169     if (code) {
2170         PrintDiagnostics("remove", code);
2171         return code;
2172     }
2173
2174     MapPartIdIntoName(partition, pname);
2175     fprintf(STDOUT, "Volume %lu on partition %s server %s deleted\n",
2176             (unsigned long)volid, pname, hostutil_GetNameByINet(server));
2177     return 0;
2178 }
2179
2180 #define TESTM   0               /* set for move space tests, clear for production */
2181 static int
2182 MoveVolume(register struct cmd_syndesc *as, void *arock)
2183 {
2184
2185     afs_uint32 volid;
2186     afs_uint32 fromserver, toserver;
2187     afs_int32 frompart, topart;
2188     afs_int32 flags, code, err;
2189     char fromPartName[10], toPartName[10];
2190
2191     struct diskPartition64 partition;   /* for space check */
2192     volintInfo *p;
2193
2194     volid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);
2195     if (volid == 0) {
2196         if (err)
2197             PrintError("", err);
2198         else
2199             fprintf(STDERR, "vos: can't find volume ID or name '%s'\n",
2200                     as->parms[0].items->data);
2201         return ENOENT;
2202     }
2203     fromserver = GetServer(as->parms[1].items->data);
2204     if (fromserver == 0) {
2205         fprintf(STDERR, "vos: server '%s' not found in host table\n",
2206                 as->parms[1].items->data);
2207         return ENOENT;
2208     }
2209     toserver = GetServer(as->parms[3].items->data);
2210     if (toserver == 0) {
2211         fprintf(STDERR, "vos: server '%s' not found in host table\n",
2212                 as->parms[3].items->data);
2213         return ENOENT;
2214     }
2215     frompart = volutil_GetPartitionID(as->parms[2].items->data);
2216     if (frompart < 0) {
2217         fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
2218                 as->parms[2].items->data);
2219         return EINVAL;
2220     }
2221     if (!IsPartValid(frompart, fromserver, &code)) {    /*check for validity of the partition */
2222         if (code)
2223             PrintError("", code);
2224         else
2225             fprintf(STDERR,
2226                     "vos : partition %s does not exist on the server\n",
2227                     as->parms[2].items->data);
2228         return ENOENT;
2229     }
2230     topart = volutil_GetPartitionID(as->parms[4].items->data);
2231     if (topart < 0) {
2232         fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
2233                 as->parms[4].items->data);
2234         return EINVAL;
2235     }
2236     if (!IsPartValid(topart, toserver, &code)) {        /*check for validity of the partition */
2237         if (code)
2238             PrintError("", code);
2239         else
2240             fprintf(STDERR,
2241                     "vos : partition %s does not exist on the server\n",
2242                     as->parms[4].items->data);
2243         return ENOENT;
2244     }
2245
2246     flags = 0;
2247     if (as->parms[5].items) flags |= RV_NOCLONE;
2248
2249     /*
2250      * check source partition for space to clone volume
2251      */
2252
2253     MapPartIdIntoName(topart, toPartName);
2254     MapPartIdIntoName(frompart, fromPartName);
2255
2256     /*
2257      * check target partition for space to move volume
2258      */
2259
2260     code = UV_PartitionInfo64(toserver, toPartName, &partition);
2261     if (code) {
2262         fprintf(STDERR, "vos: cannot access partition %s\n", toPartName);
2263         exit(1);
2264     }
2265     if (TESTM)
2266         fprintf(STDOUT, "target partition %s free space %" AFS_INT64_FMT "\n", toPartName,
2267                 partition.free);
2268
2269     p = (volintInfo *) 0;
2270     code = UV_ListOneVolume(fromserver, frompart, volid, &p);
2271     if (code) {
2272         fprintf(STDERR, "vos:cannot access volume %lu\n",
2273                 (unsigned long)volid);
2274         exit(1);
2275     }
2276     if (TESTM)
2277         fprintf(STDOUT, "volume %lu size %d\n", (unsigned long)volid,
2278                 p->size);
2279     if (partition.free <= p->size) {
2280         fprintf(STDERR,
2281                 "vos: no space on target partition %s to move volume %lu\n",
2282                 toPartName, (unsigned long)volid);
2283         free(p);
2284         exit(1);
2285     }
2286     free(p);
2287
2288     if (TESTM) {
2289         fprintf(STDOUT, "size test - don't do move\n");
2290         exit(0);
2291     }
2292
2293     /* successful move still not guaranteed but shoot for it */
2294
2295     code =
2296         UV_MoveVolume2(volid, fromserver, frompart, toserver, topart, flags);
2297     if (code) {
2298         PrintDiagnostics("move", code);
2299         return code;
2300     }
2301     MapPartIdIntoName(topart, toPartName);
2302     MapPartIdIntoName(frompart, fromPartName);
2303     fprintf(STDOUT, "Volume %lu moved from %s %s to %s %s \n",
2304             (unsigned long)volid, as->parms[1].items->data, fromPartName,
2305             as->parms[3].items->data, toPartName);
2306
2307     return 0;
2308 }
2309
2310 static int
2311 CopyVolume(register struct cmd_syndesc *as, void *arock)
2312 {
2313     afs_uint32 volid;
2314     afs_uint32 fromserver, toserver;
2315     afs_int32 frompart, topart, code, err, flags;
2316     char fromPartName[10], toPartName[10], *tovolume;
2317     struct nvldbentry entry;
2318     struct diskPartition64 partition;   /* for space check */
2319     volintInfo *p;
2320
2321     volid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);
2322     if (volid == 0) {
2323         if (err)
2324             PrintError("", err);
2325         else
2326             fprintf(STDERR, "vos: can't find volume ID or name '%s'\n",
2327                     as->parms[0].items->data);
2328         return ENOENT;
2329     }
2330     fromserver = GetServer(as->parms[1].items->data);
2331     if (fromserver == 0) {
2332         fprintf(STDERR, "vos: server '%s' not found in host table\n",
2333                 as->parms[1].items->data);
2334         return ENOENT;
2335     }
2336
2337     toserver = GetServer(as->parms[4].items->data);
2338     if (toserver == 0) {
2339         fprintf(STDERR, "vos: server '%s' not found in host table\n",
2340                 as->parms[4].items->data);
2341         return ENOENT;
2342     }
2343
2344     tovolume = as->parms[3].items->data;
2345     if (!ISNAMEVALID(tovolume)) {
2346         fprintf(STDERR,
2347                 "vos: the name of the root volume %s exceeds the size limit of %d\n",
2348                 tovolume, VOLSER_OLDMAXVOLNAME - 10);
2349         return E2BIG;
2350     }
2351     if (!VolNameOK(tovolume)) {
2352         fprintf(STDERR,
2353                 "Illegal volume name %s, should not end in .readonly or .backup\n",
2354                 tovolume);
2355         return EINVAL;
2356     }
2357     if (IsNumeric(tovolume)) {
2358         fprintf(STDERR, "Illegal volume name %s, should not be a number\n",
2359                 tovolume);
2360         return EINVAL;
2361     }
2362     code = VLDB_GetEntryByName(tovolume, &entry);
2363     if (!code) {
2364         fprintf(STDERR, "Volume %s already exists\n", tovolume);
2365         PrintDiagnostics("copy", code);
2366         return EEXIST;
2367     }
2368
2369     frompart = volutil_GetPartitionID(as->parms[2].items->data);
2370     if (frompart < 0) {
2371         fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
2372                 as->parms[2].items->data);
2373         return EINVAL;
2374     }
2375     if (!IsPartValid(frompart, fromserver, &code)) {    /*check for validity of the partition */
2376         if (code)
2377             PrintError("", code);
2378         else
2379             fprintf(STDERR,
2380                     "vos : partition %s does not exist on the server\n",
2381                     as->parms[2].items->data);
2382         return ENOENT;
2383     }
2384
2385     topart = volutil_GetPartitionID(as->parms[5].items->data);
2386     if (topart < 0) {
2387         fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
2388                 as->parms[5].items->data);
2389         return EINVAL;
2390     }
2391     if (!IsPartValid(topart, toserver, &code)) {        /*check for validity of the partition */
2392         if (code)
2393             PrintError("", code);
2394         else
2395             fprintf(STDERR,
2396                     "vos : partition %s does not exist on the server\n",
2397                     as->parms[5].items->data);
2398         return ENOENT;
2399     }
2400
2401     flags = 0;
2402     if (as->parms[6].items) flags |= RV_OFFLINE;
2403     if (as->parms[7].items) flags |= RV_RDONLY;
2404     if (as->parms[8].items) flags |= RV_NOCLONE;
2405
2406     MapPartIdIntoName(topart, toPartName);
2407     MapPartIdIntoName(frompart, fromPartName);
2408
2409     /*
2410      * check target partition for space to move volume
2411      */
2412
2413     code = UV_PartitionInfo64(toserver, toPartName, &partition);
2414     if (code) {
2415         fprintf(STDERR, "vos: cannot access partition %s\n", toPartName);
2416         exit(1);
2417     }
2418     if (TESTM)
2419         fprintf(STDOUT, "target partition %s free space %" AFS_INT64_FMT "\n", toPartName,
2420                 partition.free);
2421
2422     p = (volintInfo *) 0;
2423     code = UV_ListOneVolume(fromserver, frompart, volid, &p);
2424     if (code) {
2425         fprintf(STDERR, "vos:cannot access volume %lu\n",
2426                 (unsigned long)volid);
2427         exit(1);
2428     }
2429
2430     if (partition.free <= p->size) {
2431         fprintf(STDERR,
2432                 "vos: no space on target partition %s to copy volume %lu\n",
2433                 toPartName, (unsigned long)volid);
2434         free(p);
2435         exit(1);
2436     }
2437     free(p);
2438
2439     /* successful copy still not guaranteed but shoot for it */
2440
2441     code =
2442         UV_CopyVolume2(volid, fromserver, frompart, tovolume, toserver,
2443                        topart, 0, flags);
2444     if (code) {
2445         PrintDiagnostics("copy", code);
2446         return code;
2447     }
2448     MapPartIdIntoName(topart, toPartName);
2449     MapPartIdIntoName(frompart, fromPartName);
2450     fprintf(STDOUT, "Volume %lu copied from %s %s to %s on %s %s \n",
2451             (unsigned long)volid, as->parms[1].items->data, fromPartName,
2452             tovolume, as->parms[4].items->data, toPartName);
2453
2454     return 0;
2455 }
2456
2457
2458 static int
2459 ShadowVolume(register struct cmd_syndesc *as, void *arock)
2460 {
2461     afs_uint32 volid, tovolid;
2462     afs_uint32 fromserver, toserver;
2463     afs_int32 frompart, topart;
2464     afs_int32 code, err, flags;
2465     char fromPartName[10], toPartName[10], toVolName[32], *tovolume;
2466     struct diskPartition64 partition;   /* for space check */
2467     volintInfo *p, *q;
2468
2469     p = (volintInfo *) 0;
2470     q = (volintInfo *) 0;
2471
2472     volid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);
2473     if (volid == 0) {
2474         if (err)
2475             PrintError("", err);
2476         else
2477             fprintf(STDERR, "vos: can't find volume ID or name '%s'\n",
2478                     as->parms[0].items->data);
2479         return ENOENT;
2480     }
2481     fromserver = GetServer(as->parms[1].items->data);
2482     if (fromserver == 0) {
2483         fprintf(STDERR, "vos: server '%s' not found in host table\n",
2484                 as->parms[1].items->data);
2485         return ENOENT;
2486     }
2487
2488     toserver = GetServer(as->parms[3].items->data);
2489     if (toserver == 0) {
2490         fprintf(STDERR, "vos: server '%s' not found in host table\n",
2491                 as->parms[3].items->data);
2492         return ENOENT;
2493     }
2494
2495     frompart = volutil_GetPartitionID(as->parms[2].items->data);
2496     if (frompart < 0) {
2497         fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
2498                 as->parms[2].items->data);
2499         return EINVAL;
2500     }
2501     if (!IsPartValid(frompart, fromserver, &code)) {    /*check for validity of the partition */
2502         if (code)
2503             PrintError("", code);
2504         else
2505             fprintf(STDERR,
2506                     "vos : partition %s does not exist on the server\n",
2507                     as->parms[2].items->data);
2508         return ENOENT;
2509     }
2510
2511     topart = volutil_GetPartitionID(as->parms[4].items->data);
2512     if (topart < 0) {
2513         fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
2514                 as->parms[4].items->data);
2515         return EINVAL;
2516     }
2517     if (!IsPartValid(topart, toserver, &code)) {        /*check for validity of the partition */
2518         if (code)
2519             PrintError("", code);
2520         else
2521             fprintf(STDERR,
2522                     "vos : partition %s does not exist on the server\n",
2523                     as->parms[4].items->data);
2524         return ENOENT;
2525     }
2526
2527     if (as->parms[5].items) {
2528         tovolume = as->parms[5].items->data;
2529         if (!ISNAMEVALID(tovolume)) {
2530             fprintf(STDERR,
2531                 "vos: the name of the root volume %s exceeds the size limit of %d\n",
2532                 tovolume, VOLSER_OLDMAXVOLNAME - 10);
2533             return E2BIG;
2534         }
2535         if (!VolNameOK(tovolume)) {
2536             fprintf(STDERR,
2537                 "Illegal volume name %s, should not end in .readonly or .backup\n",
2538                 tovolume);
2539             return EINVAL;
2540         }
2541         if (IsNumeric(tovolume)) {
2542             fprintf(STDERR,
2543                 "Illegal volume name %s, should not be a number\n",
2544                 tovolume);
2545             return EINVAL;
2546         }
2547     } else {
2548         /* use actual name of source volume */
2549         code = UV_ListOneVolume(fromserver, frompart, volid, &p);
2550         if (code) {
2551             fprintf(STDERR, "vos:cannot access volume %lu\n",
2552                 (unsigned long)volid);
2553             exit(1);
2554         }
2555         strcpy(toVolName, p->name);
2556         tovolume = toVolName;
2557         /* save p for size checks later */
2558     }
2559
2560     if (as->parms[6].items) {
2561         tovolid = vsu_GetVolumeID(as->parms[6].items->data, cstruct, &err);
2562         if (tovolid == 0) {
2563             if (err)
2564                 PrintError("", err);
2565             else
2566                 fprintf(STDERR, "vos: can't find volume ID or name '%s'\n",
2567                         as->parms[6].items->data);
2568             if (p)
2569                 free(p);
2570             return ENOENT;
2571         }
2572     } else {
2573         tovolid = vsu_GetVolumeID(tovolume, cstruct, &err);
2574         if (tovolid == 0) {
2575             if (err)
2576                 PrintError("", err);
2577             else
2578                 fprintf(STDERR, "vos: can't find volume ID or name '%s'\n",
2579                         tovolume);
2580             if (p)
2581                 free(p);
2582             return ENOENT;
2583         }
2584     }
2585
2586     flags = RV_NOVLDB;
2587     if (as->parms[7].items) flags |= RV_OFFLINE;
2588     if (as->parms[8].items) flags |= RV_RDONLY;
2589     if (as->parms[9].items) flags |= RV_NOCLONE;
2590     if (as->parms[10].items) flags |= RV_CPINCR;
2591
2592     MapPartIdIntoName(topart, toPartName);
2593     MapPartIdIntoName(frompart, fromPartName);
2594
2595     /*
2596      * check target partition for space to move volume
2597      */
2598
2599     code = UV_PartitionInfo64(toserver, toPartName, &partition);
2600     if (code) {
2601         fprintf(STDERR, "vos: cannot access partition %s\n", toPartName);
2602         exit(1);
2603     }
2604     if (TESTM)
2605         fprintf(STDOUT, "target partition %s free space %" AFS_INT64_FMT "\n", toPartName,
2606                 partition.free);
2607
2608     /* Don't do this again if we did it above */
2609     if (!p) {
2610         code = UV_ListOneVolume(fromserver, frompart, volid, &p);
2611         if (code) {
2612             fprintf(STDERR, "vos:cannot access volume %lu\n",
2613                 (unsigned long)volid);
2614             exit(1);
2615         }
2616     }
2617
2618     /* OK if this fails */
2619     code = UV_ListOneVolume(toserver, topart, tovolid, &q);
2620
2621     /* Treat existing volume size as "free" */
2622     if (q)
2623         p->size = (q->size < p->size) ? p->size - q->size : 0;
2624
2625     if (partition.free <= p->size) {
2626         fprintf(STDERR,
2627                 "vos: no space on target partition %s to copy volume %lu\n",
2628                 toPartName, (unsigned long)volid);
2629         free(p);
2630         if (q) free(q);
2631         exit(1);
2632     }
2633     free(p);
2634     if (q) free(q);
2635
2636     /* successful copy still not guaranteed but shoot for it */
2637
2638     code =
2639         UV_CopyVolume2(volid, fromserver, frompart, tovolume, toserver,
2640                        topart, tovolid, flags);
2641     if (code) {
2642         PrintDiagnostics("shadow", code);
2643         return code;
2644     }
2645     MapPartIdIntoName(topart, toPartName);
2646     MapPartIdIntoName(frompart, fromPartName);
2647     fprintf(STDOUT, "Volume %lu shadowed from %s %s to %s %s \n",
2648             (unsigned long)volid, as->parms[1].items->data, fromPartName,
2649             as->parms[3].items->data, toPartName);
2650
2651     return 0;
2652 }
2653
2654
2655 static int
2656 CloneVolume(register struct cmd_syndesc *as, void *arock)
2657 {
2658     afs_uint32 volid, cloneid;
2659     afs_uint32 server;
2660     afs_int32 part, voltype;
2661     char partName[10], *volname;
2662     afs_int32 code, err, flags;
2663     struct nvldbentry entry;
2664
2665     volid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);
2666     if (volid == 0) {
2667         if (err)
2668             PrintError("", err);
2669         else
2670             fprintf(STDERR, "vos: can't find volume ID or name '%s'\n",
2671                     as->parms[0].items->data);
2672         return ENOENT;
2673     }
2674
2675     if (as->parms[1].items || as->parms[2].items) {
2676         if (!as->parms[1].items || !as->parms[2].items) {
2677             fprintf(STDERR,
2678                     "Must specify both -server and -partition options\n");
2679             return -1;
2680         }
2681         server = GetServer(as->parms[1].items->data);
2682         if (server == 0) {
2683             fprintf(STDERR, "vos: server '%s' not found in host table\n",
2684                     as->parms[1].items->data);
2685             return ENOENT;
2686         }
2687         part = volutil_GetPartitionID(as->parms[2].items->data);
2688         if (part < 0) {
2689             fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
2690                     as->parms[2].items->data);
2691             return EINVAL;
2692         }
2693         if (!IsPartValid(part, server, &code)) {        /*check for validity of the partition */
2694             if (code)
2695                 PrintError("", code);
2696             else
2697                 fprintf(STDERR,
2698                     "vos : partition %s does not exist on the server\n",
2699                     as->parms[2].items->data);
2700             return ENOENT;
2701         }
2702     } else {
2703         code = GetVolumeInfo(volid, &server, &part, &voltype, &entry);
2704         if (code)
2705             return code;
2706     }
2707
2708     volname = 0;
2709     if (as->parms[3].items) {
2710         volname = as->parms[3].items->data;
2711         if (strlen(volname) > VOLSER_OLDMAXVOLNAME - 1) {
2712             fprintf(STDERR,
2713                 "vos: the name of the root volume %s exceeds the size limit of %d\n",
2714                 volname, VOLSER_OLDMAXVOLNAME - 1);
2715             return E2BIG;
2716         }
2717 #if 0
2718         /* 
2719          * In order that you be able to make clones of RO or BK, this
2720          * check must be omitted.
2721          */
2722         if (!VolNameOK(volname)) {
2723             fprintf(STDERR,
2724                 "Illegal volume name %s, should not end in .readonly or .backup\n",
2725                 volname);
2726             return EINVAL;
2727         }
2728 #endif
2729         if (IsNumeric(volname)) {
2730             fprintf(STDERR,
2731                 "Illegal volume name %s, should not be a number\n",
2732                 volname);
2733             return EINVAL;
2734         }
2735     }
2736
2737     cloneid = 0;
2738     if (as->parms[4].items) {
2739         cloneid = vsu_GetVolumeID(as->parms[4].items->data, cstruct, &err);
2740         if (cloneid == 0) {
2741             if (err)
2742                 PrintError("", err);
2743             else
2744                 fprintf(STDERR, "vos: can't find volume ID or name '%s'\n",
2745                         as->parms[4].items->data);
2746             return ENOENT;
2747         }
2748     }
2749
2750     flags = 0;
2751     if (as->parms[5].items) flags |= RV_OFFLINE;
2752     if (as->parms[6].items) flags |= RV_RDONLY;
2753
2754
2755     code = 
2756         UV_CloneVolume(server, part, volid, cloneid, volname, flags);
2757
2758     if (code) {
2759         PrintDiagnostics("clone", code);
2760         return code;
2761     }
2762     MapPartIdIntoName(part, partName);
2763     fprintf(STDOUT, "Created clone for volume %s\n",
2764             as->parms[0].items->data);
2765
2766     return 0;
2767 }
2768
2769
2770 static int
2771 BackupVolume(register struct cmd_syndesc *as, void *arock)
2772 {
2773     afs_uint32 avolid;
2774     afs_uint32 aserver;
2775     afs_int32 apart, vtype, code, err;
2776     struct nvldbentry entry;
2777
2778     afs_uint32 buvolid;
2779     afs_uint32 buserver;
2780     afs_int32 bupart, butype;
2781     struct nvldbentry buentry;
2782
2783     avolid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);
2784     if (avolid == 0) {
2785         if (err)
2786             PrintError("", err);
2787         else
2788             fprintf(STDERR, "vos: can't find volume ID or name '%s'\n",
2789                     as->parms[0].items->data);
2790         return ENOENT;
2791     }
2792     code = GetVolumeInfo(avolid, &aserver, &apart, &vtype, &entry);
2793     if (code)
2794         exit(1);
2795
2796     /* verify this is a readwrite volume */
2797
2798     if (vtype != RWVOL) {
2799         fprintf(STDERR, "%s not RW volume\n", as->parms[0].items->data);
2800         exit(1);
2801     }
2802
2803     /* is there a backup volume already? */
2804
2805     if (entry.flags & BACK_EXISTS) {
2806         /* yep, where is it? */
2807
2808         buvolid = entry.volumeId[BACKVOL];
2809         code = GetVolumeInfo(buvolid, &buserver, &bupart, &butype, &buentry);
2810         if (code)
2811             exit(1);
2812
2813         /* is it local? */
2814         code = VLDB_IsSameAddrs(buserver, aserver, &err);
2815         if (err) {
2816             fprintf(STDERR,
2817                     "Failed to get info about server's %d address(es) from vlserver; aborting call!\n",
2818                     buserver);
2819             exit(1);
2820         }
2821         if (!code) {
2822             fprintf(STDERR,
2823                     "FATAL ERROR: backup volume %lu exists on server %lu\n",
2824                     (unsigned long)buvolid, (unsigned long)buserver);
2825             exit(1);
2826         }
2827     }
2828
2829     /* nope, carry on */
2830
2831     code = UV_BackupVolume(aserver, apart, avolid);
2832
2833     if (code) {
2834         PrintDiagnostics("backup", code);
2835         return code;
2836     }
2837     fprintf(STDOUT, "Created backup volume for %s \n",
2838             as->parms[0].items->data);
2839     return 0;
2840 }
2841
2842 static int
2843 ReleaseVolume(register struct cmd_syndesc *as, void *arock)
2844 {
2845
2846     struct nvldbentry entry;
2847     afs_uint32 avolid;
2848     afs_uint32 aserver;
2849     afs_int32 apart, vtype, code, err;
2850     int force = 0;
2851
2852     if (as->parms[1].items)
2853         force = 1;
2854     avolid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);
2855     if (avolid == 0) {
2856         if (err)
2857             PrintError("", err);
2858         else
2859             fprintf(STDERR, "vos: can't find volume '%s'\n",
2860                     as->parms[0].items->data);
2861         return ENOENT;
2862     }
2863     code = GetVolumeInfo(avolid, &aserver, &apart, &vtype, &entry);
2864     if (code)
2865         return code;
2866
2867     if (vtype != RWVOL) {
2868         fprintf(STDERR, "%s not a RW volume\n", as->parms[0].items->data);
2869         return (ENOENT);
2870     }
2871
2872     if (!ISNAMEVALID(entry.name)) {
2873         fprintf(STDERR,
2874                 "Volume name %s is too long, rename before releasing\n",
2875                 entry.name);
2876         return E2BIG;
2877     }
2878
2879     code = UV_ReleaseVolume(avolid, aserver, apart, force);
2880     if (code) {
2881         PrintDiagnostics("release", code);
2882         return code;
2883     }
2884     fprintf(STDOUT, "Released volume %s successfully\n",
2885             as->parms[0].items->data);
2886     return 0;
2887 }
2888
2889 static int
2890 DumpVolumeCmd(register struct cmd_syndesc *as, void *arock)
2891 {
2892     afs_uint32 avolid;
2893     afs_uint32 aserver;
2894     afs_int32 apart, voltype, fromdate = 0, code, err, i, flags;
2895     char filename[MAXPATHLEN];
2896     struct nvldbentry entry;
2897
2898     rx_SetRxDeadTime(60 * 10);
2899     for (i = 0; i < MAXSERVERS; i++) {
2900         struct rx_connection *rxConn = ubik_GetRPCConn(cstruct, i);
2901         if (rxConn == 0)
2902             break;
2903         rx_SetConnDeadTime(rxConn, rx_connDeadTime);
2904         if (rxConn->service)
2905             rxConn->service->connDeadTime = rx_connDeadTime;
2906     }
2907
2908     avolid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);
2909     if (avolid == 0) {
2910         if (err)
2911             PrintError("", err);
2912         else
2913             fprintf(STDERR, "vos: can't find volume '%s'\n",
2914                     as->parms[0].items->data);
2915         return ENOENT;
2916     }
2917
2918     if (as->parms[3].items || as->parms[4].items) {
2919         if (!as->parms[3].items || !as->parms[4].items) {
2920             fprintf(STDERR,
2921                     "Must specify both -server and -partition options\n");
2922             return -1;
2923         }
2924         aserver = GetServer(as->parms[3].items->data);
2925         if (aserver == 0) {
2926             fprintf(STDERR, "Invalid server name\n");
2927             return -1;
2928         }
2929         apart = volutil_GetPartitionID(as->parms[4].items->data);
2930         if (apart < 0) {
2931             fprintf(STDERR, "Invalid partition name\n");
2932             return -1;
2933         }
2934     } else {
2935         code = GetVolumeInfo(avolid, &aserver, &apart, &voltype, &entry);
2936         if (code)
2937             return code;
2938     }
2939
2940     if (as->parms[1].items && strcmp(as->parms[1].items->data, "0")) {
2941         code = ktime_DateToInt32(as->parms[1].items->data, &fromdate);
2942         if (code) {
2943             fprintf(STDERR, "vos: failed to parse date '%s' (error=%d))\n",
2944                     as->parms[1].items->data, code);
2945             return code;
2946         }
2947     }
2948     if (as->parms[2].items) {
2949         strcpy(filename, as->parms[2].items->data);
2950     } else {
2951         strcpy(filename, "");
2952     }
2953
2954     flags = as->parms[6].items ? VOLDUMPV2_OMITDIRS : 0;
2955 retry_dump:
2956     if (as->parms[5].items) {
2957         code =
2958             UV_DumpClonedVolume(avolid, aserver, apart, fromdate,
2959                                 DumpFunction, filename, flags);
2960     } else {
2961         code =
2962             UV_DumpVolume(avolid, aserver, apart, fromdate, DumpFunction,
2963                           filename, flags);
2964     }
2965     if ((code == RXGEN_OPCODE) && (as->parms[6].items)) {
2966         flags &= ~VOLDUMPV2_OMITDIRS;
2967         goto retry_dump;
2968     }
2969     if (code) {
2970         PrintDiagnostics("dump", code);
2971         return code;
2972     }
2973     if (strcmp(filename, ""))
2974         fprintf(STDERR, "Dumped volume %s in file %s\n",
2975                 as->parms[0].items->data, filename);
2976     else
2977         fprintf(STDERR, "Dumped volume %s in stdout \n",
2978                 as->parms[0].items->data);
2979     return 0;
2980 }
2981
2982 #define ASK   0
2983 #define ABORT 1
2984 #define FULL  2
2985 #define INC   3
2986
2987 #define TS_DUMP 1
2988 #define TS_KEEP 2
2989 #define TS_NEW  3
2990
2991 static int
2992 RestoreVolumeCmd(register struct cmd_syndesc *as, void *arock)
2993 {
2994     afs_uint32 avolid, aparentid;
2995     afs_uint32 aserver;
2996     afs_int32 apart, code, vcode, err;
2997     afs_int32 aoverwrite = ASK;
2998     afs_int32 acreation = 0, alastupdate = 0;
2999     int restoreflags = 0;
3000     int readonly = 0, offline = 0, voltype = RWVOL;
3001     char prompt;
3002     char afilename[MAXPATHLEN], avolname[VOLSER_MAXVOLNAME + 1], apartName[10];
3003     char volname[VOLSER_MAXVOLNAME + 1];
3004     struct nvldbentry entry;
3005
3006     prompt = 'n';
3007
3008     aparentid = 0;
3009     if (as->parms[4].items) {
3010         avolid = vsu_GetVolumeID(as->parms[4].items->data, cstruct, &err);
3011         if (avolid == 0) {
3012             if (err)
3013                 PrintError("", err);
3014             else
3015                 fprintf(STDERR, "vos: can't find volume '%s'\n",
3016                         as->parms[4].items->data);
3017             exit(1);
3018         }
3019     } else
3020         avolid = 0;
3021
3022     if (as->parms[5].items) {
3023         if ((strcmp(as->parms[5].items->data, "a") == 0)
3024             || (strcmp(as->parms[5].items->data, "abort") == 0)) {
3025             aoverwrite = ABORT;
3026         } else if ((strcmp(as->parms[5].items->data, "f") == 0)
3027                    || (strcmp(as->parms[5].items->data, "full") == 0)) {
3028             aoverwrite = FULL;
3029         } else if ((strcmp(as->parms[5].items->data, "i") == 0)
3030                    || (strcmp(as->parms[5].items->data, "inc") == 0)
3031                    || (strcmp(as->parms[5].items->data, "increment") == 0)
3032                    || (strcmp(as->parms[5].items->data, "incremental") == 0)) {
3033             aoverwrite = INC;
3034         } else {
3035             fprintf(STDERR, "vos: %s is not a valid argument to -overwrite\n",
3036                     as->parms[5].items->data);
3037             exit(1);
3038         }
3039     }
3040     if (as->parms[6].items)
3041         offline = 1;
3042     if (as->parms[7].items) {
3043         readonly = 1;
3044         voltype = ROVOL;
3045     }
3046
3047     if (as->parms[8].items) {
3048         if ((strcmp(as->parms[8].items->data, "d") == 0)
3049             || (strcmp(as->parms[8].items->data, "dump") == 0)) {
3050             acreation = TS_DUMP;
3051         } else if ((strcmp(as->parms[8].items->data, "k") == 0)
3052             || (strcmp(as->parms[8].items->data, "keep") == 0)) {
3053             acreation = TS_KEEP;
3054         } else if ((strcmp(as->parms[8].items->data, "n") == 0)
3055             || (strcmp(as->parms[8].items->data, "new") == 0)) {
3056             acreation = TS_NEW;
3057         } else {
3058             fprintf(STDERR, "vos: %s is not a valid argument to -creation\n",
3059                     as->parms[8].items->data);
3060             exit(1);
3061         }
3062     }
3063
3064     if (as->parms[9].items) {
3065         if ((strcmp(as->parms[9].items->data, "d") == 0)
3066             || (strcmp(as->parms[9].items->data, "dump") == 0)) {
3067             alastupdate = TS_DUMP;
3068         } else if ((strcmp(as->parms[9].items->data, "k") == 0)
3069             || (strcmp(as->parms[9].items->data, "keep") == 0)) {
3070             alastupdate = TS_KEEP;
3071         } else if ((strcmp(as->parms[9].items->data, "n") == 0)
3072             || (strcmp(as->parms[9].items->data, "new") == 0)) {
3073             alastupdate = TS_NEW;
3074         } else {
3075             fprintf(STDERR, "vos: %s is not a valid argument to -lastupdate\n",
3076                     as->parms[9].items->data);
3077             exit(1);
3078         }
3079     }
3080
3081     aserver = GetServer(as->parms[0].items->data);
3082     if (aserver == 0) {
3083         fprintf(STDERR, "vos: server '%s' not found in host table\n",
3084                 as->parms[0].items->data);
3085         exit(1);
3086     }
3087     apart = volutil_GetPartitionID(as->parms[1].items->data);
3088     if (apart < 0) {
3089         fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
3090                 as->parms[1].items->data);
3091         exit(1);
3092     }
3093     if (!IsPartValid(apart, aserver, &code)) {  /*check for validity of the partition */
3094         if (code)
3095             PrintError("", code);
3096         else
3097             fprintf(STDERR,
3098                     "vos : partition %s does not exist on the server\n",
3099                     as->parms[1].items->data);
3100         exit(1);
3101     }
3102     strcpy(avolname, as->parms[2].items->data);
3103     if (!ISNAMEVALID(avolname)) {
3104         fprintf(STDERR,
3105                 "vos: the name of the volume %s exceeds the size limit\n",
3106                 avolname);
3107         exit(1);
3108     }
3109     if (!VolNameOK(avolname)) {
3110         fprintf(STDERR,
3111                 "Illegal volume name %s, should not end in .readonly or .backup\n",
3112                 avolname);
3113         exit(1);
3114     }
3115     if (as->parms[3].items) {
3116         strcpy(afilename, as->parms[3].items->data);
3117         if (!FileExists(afilename)) {
3118             fprintf(STDERR, "Can't access file %s\n", afilename);
3119             exit(1);
3120         }
3121     } else {
3122         strcpy(afilename, "");
3123     }
3124
3125     /* Check if volume exists or not */
3126
3127     vsu_ExtractName(volname, avolname);
3128     vcode = VLDB_GetEntryByName(volname, &entry);
3129     if (vcode) {                /* no volume - do a full restore */
3130         restoreflags = RV_FULLRST;
3131         if ((aoverwrite == INC) || (aoverwrite == ABORT))
3132             fprintf(STDERR,
3133                     "Volume does not exist; Will perform a full restore\n");
3134     }
3135
3136     else if ((!readonly && Lp_GetRwIndex(&entry) == -1) /* RW volume does not exist - do a full */
3137              ||(readonly && !Lp_ROMatch(0, 0, &entry))) {       /* RO volume does not exist - do a full */
3138         restoreflags = RV_FULLRST;
3139         if ((aoverwrite == INC) || (aoverwrite == ABORT))
3140             fprintf(STDERR,
3141                     "%s Volume does not exist; Will perform a full restore\n",
3142                     readonly ? "RO" : "RW");
3143
3144         if (avolid == 0) {
3145             avolid = entry.volumeId[voltype];
3146         } else if (entry.volumeId[voltype] != 0
3147                    && entry.volumeId[voltype] != avolid) {
3148             avolid = entry.volumeId[voltype];
3149         }
3150         aparentid = entry.volumeId[RWVOL];
3151     }
3152
3153     else {                      /* volume exists - do we do a full incremental or abort */
3154         afs_uint32 Oserver;
3155         afs_int32 Opart, Otype, vol_elsewhere = 0;
3156         struct nvldbentry Oentry;
3157         int c, dc;
3158
3159         if (avolid == 0) {
3160             avolid = entry.volumeId[voltype];
3161         } else if (entry.volumeId[voltype] != 0
3162                    && entry.volumeId[voltype] != avolid) {
3163             avolid = entry.volumeId[voltype];
3164         }
3165         aparentid = entry.volumeId[RWVOL];
3166
3167         /* A file name was specified  - check if volume is on another partition */
3168         vcode = GetVolumeInfo(avolid, &Oserver, &Opart, &Otype, &Oentry);
3169         if (vcode)
3170             exit(1);
3171
3172         vcode = VLDB_IsSameAddrs(Oserver, aserver, &err);
3173         if (err) {
3174             fprintf(STDERR,
3175                     "Failed to get info about server's %d address(es) from vlserver (err=%d); aborting call!\n",
3176                     Oserver, err);
3177             exit(1);
3178         }
3179         if (!vcode || (Opart != apart))
3180             vol_elsewhere = 1;
3181
3182         if (aoverwrite == ASK) {
3183             if (strcmp(afilename, "") == 0) {   /* The file is from standard in */
3184                 fprintf(STDERR,
3185                         "Volume exists and no -overwrite option specified; Aborting restore command\n");
3186                 exit(1);
3187             }
3188
3189             /* Ask what to do */
3190             if (vol_elsewhere) {
3191                 fprintf(STDERR,
3192                         "The volume %s %u already exists on a different server/part\n",
3193                         volname, entry.volumeId[voltype]);
3194                 fprintf(STDERR,
3195                         "Do you want to do a full restore or abort? [fa](a): ");
3196             } else {
3197                 fprintf(STDERR,
3198                         "The volume %s %u already exists in the VLDB\n",
3199                         volname, entry.volumeId[voltype]);
3200                 fprintf(STDERR,
3201                         "Do you want to do a full/incremental restore or abort? [fia](a): ");
3202             }
3203             dc = c = getchar();
3204             while (!(dc == EOF || dc == '\n'))
3205                 dc = getchar(); /* goto end of line */
3206             if ((c == 'f') || (c == 'F'))
3207                 aoverwrite = FULL;
3208             else if ((c == 'i') || (c == 'I'))
3209                 aoverwrite = INC;
3210             else
3211                 aoverwrite = ABORT;
3212         }
3213
3214         if (aoverwrite == ABORT) {
3215             fprintf(STDERR, "Volume exists; Aborting restore command\n");
3216             exit(1);
3217         } else if (aoverwrite == FULL) {
3218             restoreflags = RV_FULLRST;
3219             fprintf(STDERR,
3220                     "Volume exists; Will delete and perform full restore\n");
3221         } else if (aoverwrite == INC) {
3222             restoreflags = 0;
3223             if (vol_elsewhere) {
3224                 fprintf(STDERR,
3225                         "%s volume %lu already exists on a different server/part; not allowed\n",
3226                         readonly ? "RO" : "RW", (unsigned long)avolid);
3227                 exit(1);
3228             }
3229         }
3230     }
3231     if (offline)
3232         restoreflags |= RV_OFFLINE;
3233     if (readonly)
3234         restoreflags |= RV_RDONLY;
3235
3236     switch (acreation) {
3237         case TS_DUMP:
3238             restoreflags |= RV_CRDUMP;
3239             break;
3240         case TS_KEEP:
3241             restoreflags |= RV_CRKEEP;
3242             break;
3243         case TS_NEW:
3244             restoreflags |= RV_CRNEW;
3245             break;
3246         default:
3247             if (aoverwrite == FULL)
3248                 restoreflags |= RV_CRNEW;
3249             else
3250                 restoreflags |= RV_CRKEEP;
3251     }
3252
3253     switch (alastupdate) {
3254         case TS_DUMP:
3255             restoreflags |= RV_LUDUMP;
3256             break;
3257         case TS_KEEP:
3258             restoreflags |= RV_LUKEEP;
3259             break;
3260         case TS_NEW:
3261             restoreflags |= RV_LUNEW;
3262             break;
3263         default:
3264             restoreflags |= RV_LUDUMP;
3265     }
3266     if (as->parms[10].items) {
3267         restoreflags |= RV_NODEL;
3268     }
3269     
3270
3271     code =
3272         UV_RestoreVolume2(aserver, apart, avolid, aparentid,
3273                           avolname, restoreflags, WriteData, afilename);
3274     if (code) {
3275         PrintDiagnostics("restore", code);
3276         exit(1);
3277     }
3278     MapPartIdIntoName(apart, apartName);
3279
3280     /*
3281      * patch typo here - originally "parms[1]", should be "parms[0]"
3282      */
3283
3284     fprintf(STDOUT, "Restored volume %s on %s %s\n", avolname,
3285             as->parms[0].items->data, apartName);
3286     return 0;
3287 }
3288
3289 static int
3290 LockReleaseCmd(register struct cmd_syndesc *as, void *arock)
3291 {
3292     afs_uint32 avolid;
3293     afs_int32 code, err;
3294
3295     avolid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);
3296     if (avolid == 0) {
3297         if (err)
3298             PrintError("", err);
3299         else
3300             fprintf(STDERR, "vos: can't find volume '%s'\n",
3301                     as->parms[0].items->data);
3302         exit(1);
3303     }
3304
3305     code = UV_LockRelease(avolid);
3306     if (code) {
3307         PrintDiagnostics("unlock", code);
3308         exit(1);
3309     }
3310     fprintf(STDOUT, "Released lock on vldb entry for volume %s\n",
3311             as->parms[0].items->data);
3312     return 0;
3313 }
3314
3315 static int
3316 AddSite(register struct cmd_syndesc *as, void *arock)
3317 {
3318     afs_uint32 avolid;
3319     afs_uint32 aserver;
3320     afs_int32 apart, code, err, arovolid, valid = 0;
3321     char apartName[10], avolname[VOLSER_MAXVOLNAME + 1];
3322
3323     vsu_ExtractName(avolname, as->parms[2].items->data);;
3324     avolid = vsu_GetVolumeID(avolname, cstruct, &err);
3325     if (avolid == 0) {
3326         if (err)
3327             PrintError("", err);
3328         else
3329             fprintf(STDERR, "vos: can't find volume '%s'\n",
3330                     as->parms[2].items->data);
3331         exit(1);
3332     }
3333     arovolid = 0;
3334     if (as->parms[3].items) {
3335         vsu_ExtractName(avolname, as->parms[3].items->data);
3336         arovolid = vsu_GetVolumeID(avolname, cstruct, &err);
3337         if (!arovolid) {
3338             fprintf(STDERR, "vos: invalid ro volume id '%s'\n",
3339                     as->parms[3].items->data);
3340             exit(1);
3341         }
3342     }
3343     aserver = GetServer(as->parms[0].items->data);
3344     if (aserver == 0) {
3345         fprintf(STDERR, "vos: server '%s' not found in host table\n",
3346                 as->parms[0].items->data);
3347         exit(1);
3348     }
3349     apart = volutil_GetPartitionID(as->parms[1].items->data);
3350     if (apart < 0) {
3351         fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
3352                 as->parms[1].items->data);
3353         exit(1);
3354     }
3355     if (!IsPartValid(apart, aserver, &code)) {  /*check for validity of the partition */
3356         if (code)
3357             PrintError("", code);
3358         else
3359             fprintf(STDERR,
3360                     "vos : partition %s does not exist on the server\n",
3361                     as->parms[1].items->data);
3362         exit(1);
3363     }
3364     if (as->parms[4].items) {
3365         valid = 1;
3366     }
3367     code = UV_AddSite2(aserver, apart, avolid, arovolid, valid);
3368     if (code) {
3369         PrintDiagnostics("addsite", code);
3370         exit(1);
3371     }
3372     MapPartIdIntoName(apart, apartName);
3373     fprintf(STDOUT, "Added replication site %s %s for volume %s\n",
3374             as->parms[0].items->data, apartName, as->parms[2].items->data);
3375     return 0;
3376 }
3377
3378 static int
3379 RemoveSite(register struct cmd_syndesc *as, void *arock)
3380 {
3381
3382     afs_uint32 avolid;
3383     afs_uint32 aserver;
3384     afs_int32 apart, code, err;
3385     char apartName[10], avolname[VOLSER_MAXVOLNAME + 1];
3386
3387     vsu_ExtractName(avolname, as->parms[2].items->data);
3388     avolid = vsu_GetVolumeID(avolname, cstruct, &err);
3389     if (avolid == 0) {
3390         if (err)
3391             PrintError("", err);
3392         else
3393             fprintf(STDERR, "vos: can't find volume '%s'\n",
3394                     as->parms[2].items->data);
3395         exit(1);
3396     }
3397     aserver = GetServer(as->parms[0].items->data);
3398     if (aserver == 0) {
3399         fprintf(STDERR, "vos: server '%s' not found in host table\n",
3400                 as->parms[0].items->data);
3401         exit(1);
3402     }
3403     apart = volutil_GetPartitionID(as->parms[1].items->data);
3404     if (apart < 0) {
3405         fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
3406                 as->parms[1].items->data);
3407         exit(1);
3408     }
3409 /*
3410  *skip the partition validity check, since it is possible that the partition
3411  *has since been decomissioned.
3412  */
3413 /*
3414         if (!IsPartValid(apart,aserver,&code)){
3415             if(code) PrintError("",code);
3416             else fprintf(STDERR,"vos : partition %s does not exist on the server\n",as->parms[1].items->data);
3417             exit(1);
3418         }
3419 */
3420     code = UV_RemoveSite(aserver, apart, avolid);
3421     if (code) {
3422         PrintDiagnostics("remsite", code);
3423         exit(1);
3424     }
3425     MapPartIdIntoName(apart, apartName);
3426     fprintf(STDOUT, "Removed replication site %s %s for volume %s\n",
3427             as->parms[0].items->data, apartName, as->parms[2].items->data);
3428     return 0;
3429 }
3430
3431 static int
3432 ChangeLocation(register struct cmd_syndesc *as, void *arock)
3433 {
3434     afs_uint32 avolid;
3435     afs_uint32 aserver;
3436     afs_int32 apart, code, err;
3437     char apartName[10];
3438
3439     avolid = vsu_GetVolumeID(as->parms[2].items->data, cstruct, &err);
3440     if (avolid == 0) {
3441         if (err)
3442             PrintError("", err);
3443         else
3444             fprintf(STDERR, "vos: can't find volume '%s'\n",
3445                     as->parms[2].items->data);
3446         exit(1);
3447     }
3448     aserver = GetServer(as->parms[0].items->data);
3449     if (aserver == 0) {
3450         fprintf(STDERR, "vos: server '%s' not found in host table\n",
3451                 as->parms[0].items->data);
3452         exit(1);
3453     }
3454     apart = volutil_GetPartitionID(as->parms[1].items->data);
3455     if (apart < 0) {
3456         fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
3457                 as->parms[1].items->data);
3458         exit(1);
3459     }
3460     if (!IsPartValid(apart, aserver, &code)) {  /*check for validity of the partition */
3461         if (code)
3462             PrintError("", code);
3463         else
3464             fprintf(STDERR,
3465                     "vos : partition %s does not exist on the server\n",
3466                     as->parms[1].items->data);
3467         exit(1);
3468     }
3469     code = UV_ChangeLocation(aserver, apart, avolid);
3470     if (code) {
3471         PrintDiagnostics("addsite", code);
3472         exit(1);
3473     }
3474     MapPartIdIntoName(apart, apartName);
3475     fprintf(STDOUT, "Changed location to %s %s for volume %s\n",
3476             as->parms[0].items->data, apartName, as->parms[2].items->data);
3477     return 0;
3478 }
3479
3480 static int
3481 ListPartitions(register struct cmd_syndesc *as, void *arock)
3482 {
3483     afs_uint32 aserver;
3484     afs_int32 code;
3485     struct partList dummyPartList;
3486     int i;
3487     char pname[10];
3488     int total, cnt;
3489
3490     aserver = GetServer(as->parms[0].items->data);
3491     if (aserver == 0) {
3492         fprintf(STDERR, "vos: server '%s' not found in host table\n",
3493                 as->parms[0].items->data);
3494         exit(1);
3495     }
3496
3497
3498     code = UV_ListPartitions(aserver, &dummyPartList, &cnt);
3499     if (code) {
3500         PrintDiagnostics("listpart", code);
3501         exit(1);
3502     }
3503     total = 0;
3504     fprintf(STDOUT, "The partitions on the server are:\n");
3505     for (i = 0; i < cnt; i++) {
3506         if (dummyPartList.partFlags[i] & PARTVALID) {
3507             memset(pname, 0, sizeof(pname));
3508             MapPartIdIntoName(dummyPartList.partId[i], pname);
3509             fprintf(STDOUT, " %10s ", pname);
3510             total++;
3511             if ((i % 5) == 0 && (i != 0))
3512                 fprintf(STDOUT, "\n");
3513         }
3514     }
3515     fprintf(STDOUT, "\n");
3516     fprintf(STDOUT, "Total: %d\n", total);
3517     return 0;
3518
3519 }
3520
3521 static int
3522 CompareVolName(const void *p1, const void *p2)
3523 {
3524     volintInfo *arg1, *arg2;
3525
3526     arg1 = (volintInfo *) p1;
3527     arg2 = (volintInfo *) p2;
3528     return (strcmp(arg1->name, arg2->name));
3529
3530 }
3531
3532 /*------------------------------------------------------------------------
3533  * PRIVATE XCompareVolName
3534  *
3535  * Description:
3536  *      Comparison routine for volume names coming from an extended
3537  *      volume listing.
3538  *
3539  * Arguments:
3540  *      a_obj1P : Char ptr to first extended vol info object
3541  *      a_obj1P : Char ptr to second extended vol info object
3542  *
3543  * Returns:
3544  *      The value of strcmp() on the volume names within the passed
3545  *      objects (i,e., -1, 0, or 1).
3546  *
3547  * Environment:
3548  *      Passed to qsort() as the designated comparison routine.
3549  *
3550  * Side Effects:
3551  *      As advertised.
3552  *------------------------------------------------------------------------*/
3553
3554 static int
3555 XCompareVolName(const void *a_obj1P, const void *a_obj2P)
3556 {                               /*XCompareVolName */
3557
3558     return (strcmp
3559             (((struct volintXInfo *)(a_obj1P))->name,
3560              ((struct volintXInfo *)(a_obj2P))->name));
3561
3562 }                               /*XCompareVolName */
3563
3564 static int
3565 CompareVolID(const void *p1, const void *p2)
3566 {
3567     volintInfo *arg1, *arg2;
3568
3569     arg1 = (volintInfo *) p1;
3570     arg2 = (volintInfo *) p2;
3571     if (arg1->volid == arg2->volid)
3572         return 0;
3573     if (arg1->volid > arg2->volid)
3574         return 1;
3575     else
3576         return -1;
3577
3578 }
3579
3580 /*------------------------------------------------------------------------
3581  * PRIVATE XCompareVolID
3582  *
3583  * Description:
3584  *      Comparison routine for volume IDs coming from an extended
3585  *      volume listing.
3586  *
3587  * Arguments:
3588  *      a_obj1P : Char ptr to first extended vol info object
3589  *      a_obj1P : Char ptr to second extended vol info object
3590  *
3591  * Returns:
3592  *      The value of strcmp() on the volume names within the passed
3593  *      objects (i,e., -1, 0, or 1).
3594  *
3595  * Environment:
3596  *      Passed to qsort() as the designated comparison routine.
3597  *
3598  * Side Effects:
3599  *      As advertised.
3600  *------------------------------------------------------------------------*/
3601
3602 static int
3603 XCompareVolID(const void *a_obj1P, const void *a_obj2P)
3604 {                               /*XCompareVolID */
3605
3606     afs_int32 id1, id2;         /*Volume IDs we're comparing */
3607
3608     id1 = ((struct volintXInfo *)(a_obj1P))->volid;
3609     id2 = ((struct volintXInfo *)(a_obj2P))->volid;
3610     if (id1 == id2)
3611         return (0);
3612     else if (id1 > id2)
3613         return (1);
3614     else
3615         return (-1);
3616
3617 }                               /*XCompareVolID */
3618
3619 /*------------------------------------------------------------------------
3620  * PRIVATE ListVolumes
3621  *
3622  * Description:
3623  *      Routine used to list volumes, contacting the Volume Server
3624  *      directly, bypassing the VLDB.
3625  *
3626  * Arguments:
3627  *      as : Ptr to parsed command line arguments.
3628  *
3629  * Returns:
3630  *      0                       Successful operation
3631  *
3632  * Environment:
3633  *      Nothing interesting.
3634  *
3635  * Side Effects:
3636  *      As advertised.
3637  *------------------------------------------------------------------------*/
3638
3639 static int
3640 ListVolumes(register struct cmd_syndesc *as, void *arock)
3641 {
3642     afs_int32 apart, int32list, fast;
3643     afs_uint32 aserver;
3644     afs_int32 code;
3645     volintInfo *pntr;
3646     volintInfo *oldpntr = NULL;
3647     afs_int32 count;
3648     int i;
3649     char *base;
3650     volintXInfo *xInfoP;
3651     volintXInfo *origxInfoP = NULL; /*Ptr to current/orig extended vol info */
3652     int wantExtendedInfo;       /*Do we want extended vol info? */
3653
3654     char pname[10];
3655     struct partList dummyPartList;
3656     int all;
3657     int quiet, cnt;
3658
3659     apart = -1;
3660     fast = 0;
3661     int32list = 0;
3662
3663     if (as->parms[3].items)
3664         int32list = 1;
3665     if (as->parms[4].items)
3666         quiet = 1;
3667     else
3668         quiet = 0;
3669     if (as->parms[2].items)
3670         fast = 1;
3671     if (fast)
3672         all = 0;
3673     else
3674         all = 1;
3675     if (as->parms[5].items) {
3676         /*
3677          * We can't coexist with the fast flag.
3678          */
3679         if (fast) {
3680             fprintf(STDERR,
3681                     "vos: Can't use the -fast and -extended flags together\n");
3682             exit(1);
3683         }
3684
3685         /*
3686          * We need to turn on ``long'' listings to get the full effect.
3687          */
3688         wantExtendedInfo = 1;
3689         int32list = 1;
3690     } else
3691         wantExtendedInfo = 0;
3692     if (as->parms[1].items) {
3693         apart = volutil_GetPartitionID(as->parms[1].items->data);
3694         if (apart < 0) {
3695             fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
3696                     as->parms[1].items->data);
3697             exit(1);
3698         }
3699         dummyPartList.partId[0] = apart;
3700         dummyPartList.partFlags[0] = PARTVALID;
3701         cnt = 1;
3702     }
3703     aserver = GetServer(as->parms[0].items->data);
3704     if (aserver == 0) {
3705         fprintf(STDERR, "vos: server '%s' not found in host table\n",
3706                 as->parms[0].items->data);
3707         exit(1);
3708     }
3709
3710     if (apart != -1) {
3711         if (!IsPartValid(apart, aserver, &code)) {      /*check for validity of the partition */
3712             if (code)
3713                 PrintError("", code);
3714             else
3715                 fprintf(STDERR,
3716                         "vos : partition %s does not exist on the server\n",
3717                         as->parms[1].items->data);
3718             exit(1);
3719         }
3720     } else {
3721         code = UV_ListPartitions(aserver, &dummyPartList, &cnt);
3722         if (code) {
3723             PrintDiagnostics("listvol", code);
3724             exit(1);
3725         }
3726     }
3727     for (i = 0; i < cnt; i++) {
3728         if (dummyPartList.partFlags[i] & PARTVALID) {
3729             if (wantExtendedInfo)
3730                 code =
3731                     UV_XListVolumes(aserver, dummyPartList.partId[i], all,
3732                                     &xInfoP, &count);
3733             else
3734                 code =
3735                     UV_ListVolumes(aserver, dummyPartList.partId[i], all,
3736                                    &pntr, &count);
3737             if (code) {
3738                 PrintDiagnostics("listvol", code);
3739                 if (pntr)
3740                     free(pntr);
3741                 exit(1);
3742             }
3743             if (wantExtendedInfo) {
3744                 origxInfoP = xInfoP;
3745                 base = (char *)xInfoP;
3746             } else {
3747                 oldpntr = pntr;
3748                 base = (char *)pntr;
3749             }
3750
3751             if (!fast) {
3752                 if (wantExtendedInfo)
3753                     qsort(base, count, sizeof(volintXInfo), XCompareVolName);
3754                 else
3755                     qsort(base, count, sizeof(volintInfo), CompareVolName);
3756             } else {
3757                 if (wantExtendedInfo)
3758                     qsort(base, count, sizeof(volintXInfo), XCompareVolID);
3759                 else
3760                     qsort(base, count, sizeof(volintInfo), CompareVolID);
3761             }
3762             MapPartIdIntoName(dummyPartList.partId[i], pname);
3763             if (!quiet)
3764                 fprintf(STDOUT,
3765                         "Total number of volumes on server %s partition %s: %lu \n",
3766                         as->parms[0].items->data, pname,
3767                         (unsigned long)count);
3768             if (wantExtendedInfo) {
3769                 if (as->parms[6].items)
3770                     XDisplayVolumes2(aserver, dummyPartList.partId[i], origxInfoP,
3771                                 count, int32list, fast, quiet);
3772                 else
3773                     XDisplayVolumes(aserver, dummyPartList.partId[i], origxInfoP,
3774                                 count, int32list, fast, quiet);
3775                 if (xInfoP)
3776                     free(xInfoP);
3777                 xInfoP = (volintXInfo *) 0;
3778             } else {
3779                 if (as->parms[6].items)
3780                     DisplayVolumes2(aserver, dummyPartList.partId[i], oldpntr,
3781                                     count);
3782                 else
3783                     DisplayVolumes(aserver, dummyPartList.partId[i], oldpntr,
3784                                    count, int32list, fast, quiet);
3785                 if (pntr)
3786                     free(pntr);
3787                 pntr = (volintInfo *) 0;
3788             }
3789         }
3790     }
3791     return 0;
3792 }
3793
3794 static int
3795 SyncVldb(register struct cmd_syndesc *as, void *arock)
3796 {
3797     afs_int32 pnum = 0, code;   /* part name */
3798     char part[10];
3799     int flags = 0;
3800     char *volname = 0;
3801
3802     tserver = 0;
3803     if (as->parms[0].items) {
3804         tserver = GetServer(as->parms[0].items->data);
3805         if (!tserver) {
3806             fprintf(STDERR, "vos: host '%s' not found in host table\n",
3807                     as->parms[0].items->data);
3808             exit(1);
3809         }
3810     }
3811
3812     if (as->parms[1].items) {
3813         pnum = volutil_GetPartitionID(as->parms[1].items->data);
3814         if (pnum < 0) {
3815             fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
3816                     as->parms[1].items->data);
3817             exit(1);
3818         }
3819         if (!IsPartValid(pnum, tserver, &code)) {       /*check for validity of the partition */
3820             if (code)
3821                 PrintError("", code);
3822             else
3823                 fprintf(STDERR,
3824                         "vos: partition %s does not exist on the server\n",
3825                         as->parms[1].items->data);
3826             exit(1);
3827         }
3828         flags = 1;
3829
3830         if (!tserver) {
3831             fprintf(STDERR,
3832                     "The -partition option requires a -server option\n");
3833             exit(1);
3834         }
3835     }
3836
3837     if (as->parms[3].items) {
3838         flags |= 2; /* don't update */
3839     }
3840
3841     if (as->parms[2].items) {
3842         /* Synchronize an individual volume */
3843         volname = as->parms[2].items->data;
3844         code = UV_SyncVolume(tserver, pnum, volname, flags);
3845     } else {
3846         if (!tserver) {
3847             fprintf(STDERR,
3848                     "Without a -volume option, the -server option is required\n");
3849             exit(1);
3850         }
3851         code = UV_SyncVldb(tserver, pnum, flags, 0 /*unused */ );
3852     }
3853
3854     if (code) {
3855         PrintDiagnostics("syncvldb", code);
3856         exit(1);
3857     }
3858
3859     /* Print a summary of what we did */
3860     if (volname)
3861         fprintf(STDOUT, "VLDB volume %s synchronized", volname);
3862     else
3863         fprintf(STDOUT, "VLDB synchronized");
3864     if (tserver) {
3865         fprintf(STDOUT, " with state of server %s", as->parms[0].items->data);
3866     }
3867     if (flags & 1) {
3868         MapPartIdIntoName(pnum, part);
3869         fprintf(STDOUT, " partition %s\n", part);
3870     }
3871     fprintf(STDOUT, "\n");
3872
3873     return 0;
3874 }
3875
3876 static int
3877 SyncServer(register struct cmd_syndesc *as, void *arock)
3878 {
3879     afs_int32 pnum, code;       /* part name */
3880     char part[10];
3881
3882     int flags = 0;
3883
3884     tserver = GetServer(as->parms[0].items->data);
3885     if (!tserver) {
3886         fprintf(STDERR, "vos: host '%s' not found in host table\n",
3887                 as->parms[0].items->data);
3888         exit(1);
3889     }
3890     if (as->parms[1].items) {
3891         pnum = volutil_GetPartitionID(as->parms[1].items->data);
3892         if (pnum < 0) {
3893             fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
3894                     as->parms[1].items->data);
3895             exit(1);
3896         }
3897         if (!IsPartValid(pnum, tserver, &code)) {       /*check for validity of the partition */
3898             if (code)
3899                 PrintError("", code);
3900             else
3901                 fprintf(STDERR,
3902                         "vos : partition %s does not exist on the server\n",
3903                         as->parms[1].items->data);
3904             exit(1);
3905         }
3906         flags = 1;
3907     } else {
3908         pnum = -1;
3909     }
3910
3911     if (as->parms[2].items) {
3912         flags |= 2; /* don't update */
3913     }
3914     code = UV_SyncServer(tserver, pnum, flags, 0 /*unused */ );
3915     if (code) {
3916         PrintDiagnostics("syncserv", code);
3917         exit(1);
3918     }
3919     if (flags & 1) {
3920         MapPartIdIntoName(pnum, part);
3921         fprintf(STDOUT, "Server %s partition %s synchronized with VLDB\n",
3922                 as->parms[0].items->data, part);
3923     } else
3924         fprintf(STDOUT, "Server %s synchronized with VLDB\n",
3925                 as->parms[0].items->data);
3926     return 0;
3927
3928 }
3929
3930 static int
3931 VolumeInfoCmd(char *name)
3932 {
3933     struct nvldbentry entry;
3934     afs_int32 vcode;
3935
3936     /* The vlserver will handle names with the .readonly
3937      * and .backup extension as well as volume ids.
3938      */
3939     vcode = VLDB_GetEntryByName(name, &entry);
3940     if (vcode) {
3941         PrintError("", vcode);
3942         exit(1);
3943     }
3944     MapHostToNetwork(&entry);
3945     EnumerateEntry(&entry);
3946
3947     /* Defect #3027: grubby check to handle locked volume.
3948      * If VLOP_ALLOPERS is set, the entry is locked.
3949      * Leave this routine as is, but put in correct check.
3950      */
3951     PrintLocked(entry.flags);
3952
3953     return 0;
3954 }
3955
3956 static int
3957 VolumeZap(register struct cmd_syndesc *as, void *arock)
3958 {
3959     struct nvldbentry entry;
3960     afs_uint32 volid, zapbackupid = 0, backupid = 0;
3961     afs_int32 code, server, part, err;
3962
3963     if (as->parms[3].items) {
3964         /* force flag is on, use the other version */
3965         return NukeVolume(as);
3966     }
3967
3968     if (as->parms[4].items) {
3969         zapbackupid = 1;
3970     }
3971
3972     volid = vsu_GetVolumeID(as->parms[2].items->data, cstruct, &err);
3973     if (volid == 0) {
3974         if (err)
3975             PrintError("", err);
3976         else
3977             fprintf(STDERR, "vos: can't find volume '%s'\n",
3978                     as->parms[2].items->data);
3979         exit(1);
3980     }
3981     part = volutil_GetPartitionID(as->parms[1].items->data);
3982     if (part < 0) {
3983         fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
3984                 as->parms[1].items->data);
3985         exit(1);
3986     }
3987     server = GetServer(as->parms[0].items->data);
3988     if (!server) {
3989         fprintf(STDERR, "vos: host '%s' not found in host table\n",
3990                 as->parms[0].items->data);
3991         exit(1);
3992     }
3993     if (!IsPartValid(part, server, &code)) {    /*check for validity of the partition */
3994         if (code)
3995             PrintError("", code);
3996         else
3997             fprintf(STDERR,
3998                     "vos : partition %s does not exist on the server\n",
3999                     as->parms[1].items->data);
4000         exit(1);
4001     }
4002     code = VLDB_GetEntryByID(volid, -1, &entry);
4003     if (!code) {
4004         if (volid == entry.volumeId[RWVOL])
4005             backupid = entry.volumeId[BACKVOL];
4006         fprintf(STDERR,
4007                 "Warning: Entry for volume number %lu exists in VLDB (but we're zapping it anyway!)\n",
4008                 (unsigned long)volid);
4009     }
4010     if (zapbackupid) {
4011         volintInfo *pntr = (volintInfo *) 0;
4012
4013         if (!backupid) {
4014             code = UV_ListOneVolume(server, part, volid, &pntr);
4015             if (!code) {
4016                 if (volid == pntr->parentID)
4017                     backupid = pntr->backupID;
4018                 if (pntr)
4019                     free(pntr);
4020             }
4021         }
4022         if (backupid) {
4023             code = UV_VolumeZap(server, part, backupid);
4024             if (code) {
4025                 PrintDiagnostics("zap", code);
4026                 exit(1);
4027             }
4028             fprintf(STDOUT, "Backup Volume %lu deleted\n",
4029                     (unsigned long)backupid);
4030         }
4031     }
4032     code = UV_VolumeZap(server, part, volid);
4033     if (code) {
4034         PrintDiagnostics("zap", code);
4035         exit(1);
4036     }
4037     fprintf(STDOUT, "Volume %lu deleted\n", (unsigned long)volid);
4038
4039     return 0;
4040 }
4041
4042 static int
4043 VolserStatus(register struct cmd_syndesc *as, void *arock)
4044 {
4045     afs_uint32 server;
4046     afs_int32 code;
4047     transDebugInfo *pntr, *oldpntr;
4048     afs_int32 count;
4049     int i;
4050     char pname[10];
4051     time_t t;
4052
4053     server = GetServer(as->parms[0].items->data);
4054     if (!server) {
4055         fprintf(STDERR, "vos: host '%s' not found in host table\n",
4056                 as->parms[0].items->data);
4057         exit(1);
4058     }
4059     code = UV_VolserStatus(server, &pntr, &count);
4060     if (code) {
4061         PrintDiagnostics("status", code);
4062         exit(1);
4063     }
4064     oldpntr = pntr;
4065     if (count == 0)
4066         fprintf(STDOUT, "No active transactions on %s\n",
4067                 as->parms[0].items->data);
4068     else {
4069         fprintf(STDOUT, "Total transactions: %d\n", count);
4070     }
4071     for (i = 0; i < count; i++) {
4072         /*print out the relevant info */
4073         fprintf(STDOUT, "--------------------------------------\n");
4074         t = pntr->time;
4075         fprintf(STDOUT, "transaction: %lu  created: %s",
4076                 (unsigned long)pntr->tid, ctime(&t));
4077         if (pntr->returnCode) {
4078             fprintf(STDOUT, "returnCode: %lu\n",
4079                     (unsigned long)pntr->returnCode);
4080         }
4081         if (pntr->iflags) {
4082             fprintf(STDOUT, "attachFlags:  ");
4083             switch (pntr->iflags) {
4084             case ITOffline:
4085                 fprintf(STDOUT, "offline ");
4086                 break;
4087             case ITBusy:
4088                 fprintf(STDOUT, "busy ");
4089                 break;
4090             case ITReadOnly:
4091                 fprintf(STDOUT, "readonly ");
4092                 break;
4093             case ITCreate:
4094                 fprintf(STDOUT, "create ");
4095                 break;
4096             case ITCreateVolID:
4097                 fprintf(STDOUT, "create volid ");
4098                 break;
4099             }
4100             fprintf(STDOUT, "\n");
4101         }
4102         if (pntr->vflags) {
4103             fprintf(STDOUT, "volumeStatus: ");
4104             switch (pntr->vflags) {
4105             case VTDeleteOnSalvage:
4106                 fprintf(STDOUT, "deleteOnSalvage ");
4107             case VTOutOfService:
4108                 fprintf(STDOUT, "outOfService ");
4109             case VTDeleted:
4110                 fprintf(STDOUT, "deleted ");
4111             }
4112             fprintf(STDOUT, "\n");
4113         }
4114         if (pntr->tflags) {
4115             fprintf(STDOUT, "transactionFlags: ");
4116             fprintf(STDOUT, "delete\n");
4117         }
4118         MapPartIdIntoName(pntr->partition, pname);
4119         fprintf(STDOUT, "volume: %lu  partition: %s  procedure: %s\n",
4120                 (unsigned long)pntr->volid, pname, pntr->lastProcName);
4121         if (pntr->callValid) {
4122             fprintf(STDOUT,
4123                     "packetRead: %lu  lastReceiveTime: %d  packetSend: %lu  lastSendTime: %d\n",
4124                     (unsigned long)pntr->readNext, pntr->lastReceiveTime,
4125                     (unsigned long)pntr->transmitNext, pntr->lastSendTime);
4126         }
4127         pntr++;
4128         fprintf(STDOUT, "--------------------------------------\n");
4129         fprintf(STDOUT, "\n");
4130     }
4131     if (oldpntr)
4132         free(oldpntr);
4133     return 0;
4134 }
4135
4136 static int
4137 RenameVolume(register struct cmd_syndesc *as, void *arock)
4138 {
4139     afs_int32 code1, code2, code;
4140     struct nvldbentry entry;
4141
4142     code1 = VLDB_GetEntryByName(as->parms[0].items->data, &entry);
4143     if (code1) {
4144         fprintf(STDERR, "vos: Could not find entry for volume %s\n",
4145                 as->parms[0].items->data);
4146         exit(1);
4147     }
4148     code2 = VLDB_GetEntryByName(as->parms[1].items->data, &entry);
4149     if ((!code1) && (!code2)) { /*the newname already exists */
4150         fprintf(STDERR, "vos: volume %s already exists\n",
4151                 as->parms[1].items->data);
4152         exit(1);
4153     }
4154
4155     if (code1 && code2) {
4156         fprintf(STDERR, "vos: Could not find entry for volume %s or %s\n",
4157                 as->parms[0].items->data, as->parms[1].items->data);
4158         exit(1);
4159     }
4160     if (!VolNameOK(as->parms[0].items->data)) {
4161         fprintf(STDERR,
4162                 "Illegal volume name %s, should not end in .readonly or .backup\n",
4163                 as->parms[0].items->data);
4164         exit(1);
4165     }
4166     if (!ISNAMEVALID(as->parms[1].items->data)) {
4167         fprintf(STDERR,
4168                 "vos: the new volume name %s exceeds the size limit of %d\n",
4169                 as->parms[1].items->data, VOLSER_OLDMAXVOLNAME - 10);
4170         exit(1);
4171     }
4172     if (!VolNameOK(as->parms[1].items->data)) {
4173         fprintf(STDERR,
4174                 "Illegal volume name %s, should not end in .readonly or .backup\n",
4175                 as->parms[1].items->data);
4176         exit(1);
4177     }
4178     if (IsNumeric(as->parms[1].items->data)) {
4179         fprintf(STDERR, "Illegal volume name %s, should not be a number\n",
4180                 as->parms[1].items->data);
4181         exit(1);
4182     }
4183     MapHostToNetwork(&entry);
4184     code =
4185         UV_RenameVolume(&entry, as->parms[0].items->data,
4186                         as->parms[1].items->data);
4187     if (code) {
4188         PrintDiagnostics("rename", code);
4189         exit(1);
4190     }
4191     fprintf(STDOUT, "Renamed volume %s to %s\n", as->parms[0].items->data,
4192             as->parms[1].items->data);
4193     return 0;
4194 }
4195
4196 int
4197 GetVolumeInfo(afs_uint32 volid, afs_uint32 *server, afs_int32 *part, afs_int32 *voltype,
4198               struct nvldbentry *rentry)
4199 {
4200     afs_int32 vcode;
4201     int i, index = -1;
4202
4203     vcode = VLDB_GetEntryByID(volid, -1, rentry);
4204     if (vcode) {
4205         fprintf(STDERR,
4206                 "Could not fetch the entry for volume %lu from VLDB \n",
4207                 (unsigned long)volid);
4208         PrintError("", vcode);
4209         return (vcode);
4210     }
4211     MapHostToNetwork(rentry);
4212     if (volid == rentry->volumeId[ROVOL]) {
4213         *voltype = ROVOL;
4214         for (i = 0; i < rentry->nServers; i++) {
4215             if ((index == -1) && (rentry->serverFlags[i] & ITSROVOL)
4216                 && !(rentry->serverFlags[i] & RO_DONTUSE))
4217                 index = i;
4218         }
4219         if (index == -1) {
4220             fprintf(STDERR,
4221                     "RO volume is not found in VLDB entry for volume %lu\n",
4222                     (unsigned long)volid);
4223             return -1;
4224         }
4225
4226         *server = rentry->serverNumber[index];
4227         *part = rentry->serverPartition[index];
4228         return 0;
4229     }
4230
4231     index = Lp_GetRwIndex(rentry);
4232     if (index == -1) {
4233         fprintf(STDERR,
4234                 "RW Volume is not found in VLDB entry for volume %lu\n",
4235                 (unsigned long)volid);
4236         return -1;
4237     }
4238     if (volid == rentry->volumeId[RWVOL]) {
4239         *voltype = RWVOL;
4240         *server = rentry->serverNumber[index];
4241         *part = rentry->serverPartition[index];
4242         return 0;
4243     }
4244     if (volid == rentry->volumeId[BACKVOL]) {
4245         *voltype = BACKVOL;
4246         *server = rentry->serverNumber[index];
4247         *part = rentry->serverPartition[index];
4248         return 0;
4249     }
4250     fprintf(STDERR,
4251             "unexpected volume type for volume %lu\n",
4252             (unsigned long)volid);
4253     return -1;
4254 }
4255
4256 static int
4257 DeleteEntry(register struct cmd_syndesc *as, void *arock)
4258 {
4259     afs_int32 apart = 0;
4260     afs_uint32 avolid;
4261     afs_int32 vcode;
4262     struct VldbListByAttributes attributes;
4263     nbulkentries arrayEntries;
4264     register struct nvldbentry *vllist;
4265     struct cmd_item *itp;
4266     afs_int32 nentries;
4267     int j;
4268     char prefix[VOLSER_MAXVOLNAME + 1];
4269     int seenprefix = 0;
4270     afs_int32 totalBack = 0, totalFail = 0, err;
4271
4272     if (as->parms[0].items) {   /* -id */
4273         if (as->parms[1].items || as->parms[2].items || as->parms[3].items) {
4274             fprintf(STDERR,
4275                     "You cannot use -server, -partition, or -prefix with the -id argument\n");
4276             exit(-2);
4277         }
4278         for (itp = as->parms[0].items; itp; itp = itp->next) {
4279             avolid = vsu_GetVolumeID(itp->data, cstruct, &err);
4280             if (avolid == 0) {
4281                 if (err)
4282                     PrintError("", err);
4283                 else
4284                     fprintf(STDERR, "vos: can't find volume '%s'\n",
4285                             itp->data);
4286                 continue;
4287             }
4288             if (as->parms[4].items) {   /* -noexecute */
4289                 fprintf(STDOUT, "Would have deleted VLDB entry for %s \n",
4290                         itp->data);
4291                 fflush(STDOUT);
4292                 continue;
4293             }
4294             vcode = ubik_VL_DeleteEntry(cstruct, 0, avolid, RWVOL);
4295             if (vcode) {
4296                 fprintf(STDERR, "Could not delete entry for volume %s\n",
4297                         itp->data);
4298                 fprintf(STDERR,
4299                         "You must specify a RW volume name or ID "
4300                         "(the entire VLDB entry will be deleted)\n");
4301                 PrintError("", vcode);
4302                 totalFail++;
4303                 continue;
4304             }
4305             totalBack++;
4306         }
4307         fprintf(STDOUT, "Deleted %d VLDB entries\n", totalBack);
4308         return (totalFail);
4309     }
4310
4311     if (!as->parms[1].items && !as->parms[2].items && !as->parms[3].items) {
4312         fprintf(STDERR, "You must specify an option\n");
4313         exit(-2);
4314     }
4315
4316     /* Zero out search attributes */
4317     memset(&attributes, 0, sizeof(struct VldbListByAttributes));
4318
4319     if (as->parms[1].items) {   /* -prefix */
4320         strncpy(prefix, as->parms[1].items->data, VOLSER_MAXVOLNAME);
4321         seenprefix = 1;
4322         if (!as->parms[2].items && !as->parms[3].items) {       /* a single entry only */
4323             fprintf(STDERR,
4324                     "You must provide -server with the -prefix argument\n");
4325             exit(-2);
4326         }
4327     }
4328
4329     if (as->parms[2].items) {   /* -server */
4330         afs_uint32 aserver;
4331         aserver = GetServer(as->parms[2].items->data);
4332         if (aserver == 0) {
4333             fprintf(STDERR, "vos: server '%s' not found in host table\n",
4334                     as->parms[2].items->data);
4335             exit(-1);
4336         }
4337         attributes.server = ntohl(aserver);
4338         attributes.Mask |= VLLIST_SERVER;
4339     }
4340
4341     if (as->parms[3].items) {   /* -partition */
4342         if (!as->parms[2].items) {
4343             fprintf(STDERR,
4344                     "You must provide -server with the -partition argument\n");
4345             exit(-2);
4346         }
4347         apart = volutil_GetPartitionID(as->parms[3].items->data);
4348         if (apart < 0) {
4349             fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
4350                     as->parms[3].items->data);
4351             exit(-1);
4352         }
4353         attributes.partition = apart;
4354         attributes.Mask |= VLLIST_PARTITION;
4355     }
4356
4357     /* Print status line of what we are doing */
4358     fprintf(STDOUT, "Deleting VLDB entries for ");
4359     if (as->parms[2].items) {
4360         fprintf(STDOUT, "server %s ", as->parms[2].items->data);
4361     }
4362     if (as->parms[3].items) {
4363         char pname[10];
4364         MapPartIdIntoName(apart, pname);
4365         fprintf(STDOUT, "partition %s ", pname);
4366     }
4367     if (seenprefix) {
4368         fprintf(STDOUT, "which are prefixed with %s ", prefix);
4369     }
4370     fprintf(STDOUT, "\n");
4371     fflush(STDOUT);
4372
4373     /* Get all the VLDB entries on a server and/or partition */
4374     memset(&arrayEntries, 0, sizeof(arrayEntries));
4375     vcode = VLDB_ListAttributes(&attributes, &nentries, &arrayEntries);
4376     if (vcode) {
4377         fprintf(STDERR, "Could not access the VLDB for attributes\n");
4378         PrintError("", vcode);
4379         exit(-1);
4380     }
4381
4382     /* Process each entry */
4383     for (j = 0; j < nentries; j++) {
4384         vllist = &arrayEntries.nbulkentries_val[j];
4385         if (seenprefix) {
4386             /* It only deletes the RW volumes */
4387             if (strncmp(vllist->name, prefix, strlen(prefix))) {
4388                 if (verbose) {
4389                     fprintf(STDOUT,
4390                             "Omitting to delete %s due to prefix %s mismatch\n",
4391                             vllist->name, prefix);
4392                 }
4393                 fflush(STDOUT);
4394                 continue;
4395             }
4396         }
4397
4398         if (as->parms[4].items) {       /* -noexecute */
4399             fprintf(STDOUT, "Would have deleted VLDB entry for %s \n",
4400                     vllist->name);
4401             fflush(STDOUT);
4402             continue;
4403         }
4404
4405         /* Only matches the RW volume name */
4406         avolid = vllist->volumeId[RWVOL];
4407         vcode = ubik_VL_DeleteEntry(cstruct, 0, avolid, RWVOL);
4408         if (vcode) {
4409             fprintf(STDOUT, "Could not delete VDLB entry for  %s\n",
4410                     vllist->name);
4411             totalFail++;
4412             PrintError("", vcode);
4413             continue;
4414         } else {
4415             totalBack++;
4416             if (verbose)
4417                 fprintf(STDOUT, "Deleted VLDB entry for %s \n", vllist->name);
4418         }
4419         fflush(STDOUT);
4420     }                           /*for */
4421
4422     fprintf(STDOUT, "----------------------\n");
4423     fprintf(STDOUT,
4424             "Total VLDB entries deleted: %lu; failed to delete: %lu\n",
4425             (unsigned long)totalBack, (unsigned long)totalFail);
4426     if (arrayEntries.nbulkentries_val)
4427         free(arrayEntries.nbulkentries_val);
4428     return 0;
4429 }
4430
4431
4432 static int
4433 CompareVldbEntryByName(const void *p1, const void *p2)
4434 {
4435     struct nvldbentry *arg1, *arg2;
4436
4437     arg1 = (struct nvldbentry *)p1;
4438     arg2 = (struct nvldbentry *)p2;
4439     return (strcmp(arg1->name, arg2->name));
4440 }
4441
4442 /*
4443 static int CompareVldbEntry(char *p1, char *p2)
4444 {
4445     struct nvldbentry *arg1,*arg2;
4446     int i;
4447     int pos1, pos2;
4448     char comp1[100],comp2[100];
4449     char temp1[20],temp2[20];
4450
4451     arg1 = (struct nvldbentry *)p1;
4452     arg2 = (struct nvldbentry *)p2;
4453     pos1 = -1;
4454     pos2 = -1;
4455
4456     for(i = 0; i < arg1->nServers; i++)
4457         if(arg1->serverFlags[i] & ITSRWVOL) pos1 = i;
4458     for(i = 0; i < arg2->nServers; i++)
4459         if(arg2->serverFlags[i] & ITSRWVOL) pos2 = i;
4460     if(pos1 == -1 || pos2 == -1){
4461         pos1 = 0;
4462         pos2 = 0;
4463     }
4464     sprintf(comp1,"%10u",arg1->serverNumber[pos1]);
4465     sprintf(comp2,"%10u",arg2->serverNumber[pos2]);
4466     sprintf(temp1,"%10u",arg1->serverPartition[pos1]);
4467     sprintf(temp2,"%10u",arg2->serverPartition[pos2]);
4468     strcat(comp1,temp1);
4469     strcat(comp2,temp2);
4470     strcat(comp1,arg1->name);
4471     strcat(comp1,arg2->name);
4472     return(strcmp(comp1,comp2));
4473
4474 }
4475
4476 */
4477 static int
4478 ListVLDB(struct cmd_syndesc *as, void *arock)
4479 {
4480     afs_int32 apart;
4481     afs_uint32 aserver;
4482     afs_int32 code;
4483     afs_int32 vcode;
4484     struct VldbListByAttributes attributes;
4485     nbulkentries arrayEntries;
4486     struct nvldbentry *vllist, *tarray = 0, *ttarray;
4487     afs_int32 centries, nentries = 0;
4488     afs_int32 tarraysize = 0;
4489     afs_int32 parraysize;
4490     int j;
4491     char pname[10];
4492     int quiet, sort, lock;
4493     afs_int32 thisindex, nextindex;
4494
4495     aserver = 0;
4496     apart = 0;
4497
4498     attributes.Mask = 0;
4499     lock = (as->parms[3].items ? 1 : 0);        /* -lock   flag */
4500     quiet = (as->parms[4].items ? 1 : 0);       /* -quit   flag */
4501     sort = (as->parms[5].items ? 0 : 1);        /* -nosort flag */
4502
4503     /* If the volume name is given, Use VolumeInfoCmd to look it up
4504      * and not ListAttributes.
4505      */
4506     if (as->parms[0].items) {
4507         if (lock) {
4508             fprintf(STDERR,
4509                     "vos: illegal use of '-locked' switch, need to specify server and/or partition\n");
4510             exit(1);
4511         }
4512         code = VolumeInfoCmd(as->parms[0].items->data);
4513         if (code) {
4514             PrintError("", code);
4515             exit(1);
4516         }
4517         return 0;
4518     }
4519
4520     /* Server specified */
4521     if (as->parms[1].items) {
4522         aserver = GetServer(as->parms[1].items->data);
4523         if (aserver == 0) {
4524             fprintf(STDERR, "vos: server '%s' not found in host table\n",
4525                     as->parms[1].items->data);
4526             exit(1);
4527         }
4528         attributes.server = ntohl(aserver);
4529         attributes.Mask |= VLLIST_SERVER;
4530     }
4531
4532     /* Partition specified */
4533     if (as->parms[2].items) {
4534         apart = volutil_GetPartitionID(as->parms[2].items->data);
4535         if (apart < 0) {
4536             fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
4537                     as->parms[2].items->data);
4538             exit(1);
4539         }
4540         attributes.partition = apart;
4541         attributes.Mask |= VLLIST_PARTITION;
4542     }
4543
4544     if (lock) {
4545         attributes.Mask |= VLLIST_FLAG;
4546         attributes.flag = VLOP_ALLOPERS;
4547     }
4548
4549     /* Print header information */
4550     if (!quiet) {
4551         MapPartIdIntoName(apart, pname);
4552         fprintf(STDOUT, "VLDB entries for %s %s%s%s %s\n",
4553                 (as->parms[1].items ? "server" : "all"),
4554                 (as->parms[1].items ? as->parms[1].items->data : "servers"),
4555                 (as->parms[2].items ? " partition " : ""),
4556                 (as->parms[2].items ? pname : ""),
4557                 (lock ? "which are locked:" : ""));
4558     }
4559
4560     for (thisindex = 0; (thisindex != -1); thisindex = nextindex) {
4561         memset(&arrayEntries, 0, sizeof(arrayEntries));
4562         centries = 0;
4563         nextindex = -1;
4564
4565         vcode =
4566             VLDB_ListAttributesN2(&attributes, 0, thisindex, &centries,
4567                                   &arrayEntries, &nextindex);
4568         if (vcode == RXGEN_OPCODE) {
4569             /* Vlserver not running with ListAttributesN2. Fall back */
4570             vcode =
4571                 VLDB_ListAttributes(&attributes, &centries, &arrayEntries);
4572             nextindex = -1;
4573         }
4574         if (vcode) {
4575             fprintf(STDERR, "Could not access the VLDB for attributes\n");
4576             PrintError("", vcode);
4577             exit(1);
4578         }
4579         nentries += centries;
4580
4581         /* We don't sort, so just print the entries now */
4582         if (!sort) {
4583             for (j = 0; j < centries; j++) {    /* process each entry */
4584                 vllist = &arrayEntries.nbulkentries_val[j];
4585                 MapHostToNetwork(vllist);
4586                 EnumerateEntry(vllist);
4587
4588                 PrintLocked(vllist->flags);
4589             }
4590         }
4591
4592         /* So we sort. First we must collect all the entries and keep
4593          * them in memory.
4594          */
4595         else if (centries > 0) {
4596             if (!tarray) {
4597                 /* steal away the first bulk entries array */
4598                 tarray = (struct nvldbentry *)arrayEntries.nbulkentries_val;
4599                 tarraysize = centries * sizeof(struct nvldbentry);
4600                 arrayEntries.nbulkentries_val = 0;
4601             } else {
4602                 /* Grow the tarray to keep the extra entries */
4603                 parraysize = (centries * sizeof(struct nvldbentry));
4604                 ttarray =
4605                     (struct nvldbentry *)realloc(tarray,
4606                                                  tarraysize + parraysize);
4607                 if (!ttarray) {
4608                     fprintf(STDERR,
4609                             "Could not allocate enough space for  the VLDB entries\n");
4610                     goto bypass;
4611                 }
4612                 tarray = ttarray;
4613
4614                 /* Copy them in */
4615                 memcpy(((char *)tarray) + tarraysize,
4616                        (char *)arrayEntries.nbulkentries_val, parraysize);
4617                 tarraysize += parraysize;
4618             }
4619         }
4620
4621         /* Free the bulk array */
4622         if (arrayEntries.nbulkentries_val) {
4623             free(arrayEntries.nbulkentries_val);
4624             arrayEntries.nbulkentries_val = 0;
4625         }
4626     }
4627
4628     /* Here is where we now sort all the entries and print them */
4629     if (sort && (nentries > 0)) {
4630         qsort((char *)tarray, nentries, sizeof(struct nvldbentry),
4631               CompareVldbEntryByName);
4632         for (vllist = tarray, j = 0; j < nentries; j++, vllist++) {
4633             MapHostToNetwork(vllist);
4634             EnumerateEntry(vllist);
4635
4636             PrintLocked(vllist->flags);
4637         }
4638     }
4639
4640   bypass:
4641     if (!quiet)
4642         fprintf(STDOUT, "\nTotal entries: %lu\n", (unsigned long)nentries);
4643     if (tarray)
4644         free(tarray);
4645     return 0;
4646 }
4647
4648 static int
4649 BackSys(register struct cmd_syndesc *as, void *arock)
4650 {
4651     afs_uint32 avolid;
4652     afs_int32 apart = 0;
4653     afs_uint32 aserver = 0, aserver1;
4654     afs_int32 code, apart1;
4655     afs_int32 vcode;
4656     struct VldbListByAttributes attributes;
4657     nbulkentries arrayEntries;
4658     register struct nvldbentry *vllist;
4659     afs_int32 nentries;
4660     int j;
4661     char pname[10];
4662     int seenprefix, seenxprefix, exclude, ex, exp, noaction;
4663     afs_int32 totalBack = 0;
4664     afs_int32 totalFail = 0;
4665     int previdx = -1;
4666     int error;
4667     int same = 0;
4668     struct cmd_item *ti;
4669     int match = 0;
4670 #ifndef HAVE_POSIX_REGEX
4671     char *ccode;
4672 #endif
4673
4674     memset(&attributes, 0, sizeof(struct VldbListByAttributes));
4675     attributes.Mask = 0;
4676
4677     seenprefix = (as->parms[0].items ? 1 : 0);
4678     exclude = (as->parms[3].items ? 1 : 0);
4679     seenxprefix = (as->parms[4].items ? 1 : 0);
4680     noaction = (as->parms[5].items ? 1 : 0);
4681
4682     if (as->parms[1].items) {   /* -server */
4683         aserver = GetServer(as->parms[1].items->data);
4684         if (aserver == 0) {
4685             fprintf(STDERR, "vos: server '%s' not found in host table\n",
4686                     as->parms[1].items->data);
4687             exit(1);
4688         }
4689         attributes.server = ntohl(aserver);
4690         attributes.Mask |= VLLIST_SERVER;
4691     }
4692
4693     if (as->parms[2].items) {   /* -partition */
4694         apart = volutil_GetPartitionID(as->parms[2].items->data);
4695         if (apart < 0) {
4696             fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
4697                     as->parms[2].items->data);
4698             exit(1);
4699         }
4700         attributes.partition = apart;
4701         attributes.Mask |= VLLIST_PARTITION;
4702     }
4703
4704     /* Check to make sure the prefix and xprefix expressions compile ok */
4705     if (seenprefix) {
4706         for (ti = as->parms[0].items; ti; ti = ti->next) {
4707             if (strncmp(ti->data, "^", 1) == 0) {
4708 #ifdef HAVE_POSIX_REGEX
4709                 regex_t re;
4710                 char errbuf[256];
4711
4712                 code = regcomp(&re, ti->data, REG_NOSUB);
4713                 if (code != 0) {
4714                     regerror(code, &re, errbuf, sizeof errbuf);
4715                     fprintf(STDERR,
4716                             "Unrecognizable -prefix regular expression: '%s': %s\n",
4717                             ti->data, errbuf);
4718                     exit(1);
4719                 }
4720                 regfree(&re);
4721 #else
4722                 ccode = (char *)re_comp(ti->data);
4723                 if (ccode) {
4724                     fprintf(STDERR,
4725                             "Unrecognizable -prefix regular expression: '%s': %s\n",
4726                             ti->data, ccode);
4727                     exit(1);
4728                 }
4729 #endif
4730             }
4731         }
4732     }
4733     if (seenxprefix) {
4734         for (ti = as->parms[4].items; ti; ti = ti->next) {
4735             if (strncmp(ti->data, "^", 1) == 0) {
4736 #ifdef HAVE_POSIX_REGEX
4737                 regex_t re;
4738                 char errbuf[256];
4739
4740                 code = regcomp(&re, ti->data, REG_NOSUB);
4741                 if (code != 0) {
4742                     regerror(code, &re, errbuf, sizeof errbuf);
4743                     fprintf(STDERR,
4744                             "Unrecognizable -xprefix regular expression: '%s': %s\n",
4745                             ti->data, errbuf);
4746                     exit(1);
4747                 }
4748                 regfree(&re);
4749 #else
4750                 ccode = (char *)re_comp(ti->data);
4751                 if (ccode) {
4752                     fprintf(STDERR,
4753                             "Unrecognizable -xprefix regular expression: '%s': %s\n",
4754                             ti->data, ccode);
4755                     exit(1);
4756                 }
4757 #endif
4758             }
4759         }
4760     }
4761
4762     memset(&arrayEntries, 0, sizeof(arrayEntries));     /* initialize to hint the stub to alloc space */
4763     vcode = VLDB_ListAttributes(&attributes, &nentries, &arrayEntries);
4764     if (vcode) {
4765         fprintf(STDERR, "Could not access the VLDB for attributes\n");
4766         PrintError("", vcode);
4767         exit(1);
4768     }
4769
4770     if (as->parms[1].items || as->parms[2].items || verbose) {
4771         fprintf(STDOUT, "%s up volumes",
4772                 (noaction ? "Would have backed" : "Backing"));
4773
4774         if (as->parms[1].items) {
4775             fprintf(STDOUT, " on server %s", as->parms[1].items->data);
4776         } else if (as->parms[2].items) {
4777             fprintf(STDOUT, " for all servers");
4778         }
4779
4780         if (as->parms[2].items) {
4781             MapPartIdIntoName(apart, pname);
4782             fprintf(STDOUT, " partition %s", pname);
4783         }
4784
4785         if (seenprefix || (!seenprefix && seenxprefix)) {
4786             ti = (seenprefix ? as->parms[0].items : as->parms[4].items);
4787             ex = (seenprefix ? exclude : !exclude);
4788             exp = (strncmp(ti->data, "^", 1) == 0);
4789             fprintf(STDOUT, " which %smatch %s '%s'", (ex ? "do not " : ""),
4790                     (exp ? "expression" : "prefix"), ti->data);
4791             for (ti = ti->next; ti; ti = ti->next) {
4792                 exp = (strncmp(ti->data, "^", 1) == 0);
4793                 printf(" %sor %s '%s'", (ex ? "n" : ""),
4794                        (exp ? "expression" : "prefix"), ti->data);
4795             }
4796         }
4797
4798         if (seenprefix && seenxprefix) {
4799             ti = as->parms[4].items;
4800             exp = (strncmp(ti->data, "^", 1) == 0);
4801             fprintf(STDOUT, " %swhich match %s '%s'",
4802                     (exclude ? "adding those " : "removing those "),
4803                     (exp ? "expression" : "prefix"), ti->data);
4804             for (ti = ti->next; ti; ti = ti->next) {
4805                 exp = (strncmp(ti->data, "^", 1) == 0);
4806                 printf(" or %s '%s'", (exp ? "expression" : "prefix"),
4807                        ti->data);
4808             }
4809         }
4810         fprintf(STDOUT, " .. ");
4811         if (verbose)
4812             fprintf(STDOUT, "\n");
4813         fflush(STDOUT);
4814     }
4815
4816     for (j = 0; j < nentries; j++) {    /* process each vldb entry */
4817         vllist = &arrayEntries.nbulkentries_val[j];
4818
4819         if (seenprefix) {
4820             for (ti = as->parms[0].items; ti; ti = ti->next) {
4821                 if (strncmp(ti->data, "^", 1) == 0) {
4822 #ifdef HAVE_POSIX_REGEX
4823                     regex_t re;
4824                     char errbuf[256];
4825
4826                     /* XXX -- should just do the compile once! */
4827                     code = regcomp(&re, ti->data, REG_NOSUB);
4828                     if (code != 0) {
4829                         regerror(code, &re, errbuf, sizeof errbuf);
4830                         fprintf(STDERR,
4831                                 "Error in -prefix regular expression: '%s': %s\n",
4832                                 ti->data, errbuf);
4833                         exit(1);
4834                     }
4835                     match = (regexec(&re, vllist->name, 0, NULL, 0) == 0);
4836                     regfree(&re);
4837 #else
4838                     ccode = (char *)re_comp(ti->data);
4839                     if (ccode) {
4840                         fprintf(STDERR,
4841                                 "Error in -prefix regular expression: '%s': %s\n",
4842                                 ti->data, ccode);
4843                         exit(1);
4844                     }
4845                     match = (re_exec(vllist->name) == 1);
4846 #endif
4847                 } else {
4848                     match =
4849                         (strncmp(vllist->name, ti->data, strlen(ti->data)) ==
4850                          0);
4851                 }
4852                 if (match)
4853                     break;
4854             }
4855         } else {
4856             match = 1;
4857         }
4858
4859         /* Without the -exclude flag: If it matches the prefix, then
4860          *    check if we want to exclude any from xprefix.
4861          * With the -exclude flag: If it matches the prefix, then
4862          *    check if we want to add any from xprefix.
4863          */
4864         if (match && seenxprefix) {
4865             for (ti = as->parms[4].items; ti; ti = ti->next) {
4866                 if (strncmp(ti->data, "^", 1) == 0) {
4867 #ifdef HAVE_POSIX_REGEX
4868                     regex_t re;
4869                     char errbuf[256];
4870
4871                     /* XXX -- should just do the compile once! */
4872                     code = regcomp(&re, ti->data, REG_NOSUB);
4873                     if (code != 0) {
4874                         regerror(code, &re, errbuf, sizeof errbuf);
4875                         fprintf(STDERR,
4876                                 "Error in -xprefix regular expression: '%s': %s\n",
4877                                 ti->data, errbuf);
4878                         exit(1);
4879                     }
4880                     if (regexec(&re, vllist->name, 0, NULL, 0) == 0)
4881                             match = 0;
4882                     regfree(&re);
4883 #else
4884                     ccode = (char *)re_comp(ti->data);
4885                     if (ccode) {
4886                         fprintf(STDERR,
4887                                 "Error in -xprefix regular expression: '%s': %s\n",
4888                                 ti->data, ccode);
4889                         exit(1);
4890                     }
4891                     if (re_exec(vllist->name) == 1) {
4892                         match = 0;
4893                         break;
4894                     }
4895 #endif
4896                 } else {
4897                     if (strncmp(vllist->name, ti->data, strlen(ti->data)) ==
4898                         0) {
4899                         match = 0;
4900                         break;
4901                     }
4902                 }
4903             }
4904         }
4905
4906         if (exclude)
4907             match = !match;     /* -exclude will reverse the match */
4908         if (!match)
4909             continue;           /* Skip if no match */
4910
4911         /* Print list of volumes to backup */
4912         if (noaction) {
4913             fprintf(STDOUT, "     %s\n", vllist->name);
4914             continue;
4915         }
4916
4917         if (!(vllist->flags & RW_EXISTS)) {
4918             if (verbose) {
4919                 fprintf(STDOUT,
4920                         "Omitting to backup %s since RW volume does not exist \n",
4921                         vllist->name);
4922                 fprintf(STDOUT, "\n");
4923             }
4924             fflush(STDOUT);
4925             continue;
4926         }
4927
4928         avolid = vllist->volumeId[RWVOL];
4929         MapHostToNetwork(vllist);
4930         GetServerAndPart(vllist, RWVOL, &aserver1, &apart1, &previdx);
4931         if (aserver1 == -1 || apart1 == -1) {
4932             fprintf(STDOUT, "could not backup %s, invalid VLDB entry\n",
4933                     vllist->name);
4934             totalFail++;
4935             continue;
4936         }
4937         if (aserver) {
4938             same = VLDB_IsSameAddrs(aserver, aserver1, &error);
4939             if (error) {
4940                 fprintf(STDERR,
4941                         "Failed to get info about server's %d address(es) from vlserver (err=%d); aborting call!\n",
4942                         aserver, error);
4943                 totalFail++;
4944                 continue;
4945             }
4946         }
4947         if ((aserver && !same) || (apart && (apart != apart1))) {
4948             if (verbose) {
4949                 fprintf(STDOUT,
4950                         "Omitting to backup %s since the RW is in a different location\n",
4951                         vllist->name);
4952             }
4953             continue;
4954         }
4955         if (verbose) {
4956             time_t now = time(0);
4957             fprintf(STDOUT, "Creating backup volume for %s on %s",
4958                     vllist->name, ctime(&now));
4959             fflush(STDOUT);
4960         }
4961
4962         code = UV_BackupVolume(aserver1, apart1, avolid);
4963         if (code) {
4964             fprintf(STDOUT, "Could not backup %s\n", vllist->name);
4965             totalFail++;
4966         } else {
4967             totalBack++;
4968         }
4969         if (verbose)
4970             fprintf(STDOUT, "\n");
4971         fflush(STDOUT);
4972     }                           /* process each vldb entry */
4973     fprintf(STDOUT, "done\n");
4974     fprintf(STDOUT, "Total volumes backed up: %lu; failed to backup: %lu\n",
4975             (unsigned long)totalBack, (unsigned long)totalFail);
4976     fflush(STDOUT);
4977     if (arrayEntries.nbulkentries_val)
4978         free(arrayEntries.nbulkentries_val);
4979     return 0;
4980 }
4981
4982 static int
4983 UnlockVLDB(register struct cmd_syndesc *as, void *arock)
4984 {
4985     afs_int32 apart;
4986     afs_uint32 aserver = 0;
4987     afs_int32 code;
4988     afs_int32 vcode;
4989     struct VldbListByAttributes attributes;
4990     nbulkentries arrayEntries;
4991     register struct nvldbentry *vllist;
4992     afs_int32 nentries;
4993     int j;
4994     afs_uint32 volid;
4995     afs_int32 totalE;
4996     char pname[10];
4997
4998     apart = -1;
4999     totalE = 0;
5000     attributes.Mask = 0;
5001
5002     if (as->parms[0].items) {   /* server specified */
5003         aserver = GetServer(as->parms[0].items->data);
5004         if (aserver == 0) {
5005             fprintf(STDERR, "vos: server '%s' not found in host table\n",
5006                     as->parms[0].items->data);
5007             exit(1);
5008         }
5009         attributes.server = ntohl(aserver);
5010         attributes.Mask |= VLLIST_SERVER;
5011     }
5012     if (as->parms[1].items) {   /* partition specified */
5013         apart = volutil_GetPartitionID(as->parms[1].items->data);
5014         if (apart < 0) {
5015             fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
5016                     as->parms[1].items->data);
5017             exit(1);
5018         }
5019         if (!IsPartValid(apart, aserver, &code)) {      /*check for validity of the partition */
5020             if (code)
5021                 PrintError("", code);
5022             else
5023                 fprintf(STDERR,
5024                         "vos : partition %s does not exist on the server\n",
5025                         as->parms[1].items->data);
5026             exit(1);
5027         }
5028         attributes.partition = apart;
5029         attributes.Mask |= VLLIST_PARTITION;
5030     }
5031     attributes.flag = VLOP_ALLOPERS;
5032     attributes.Mask |= VLLIST_FLAG;
5033     memset(&arrayEntries, 0, sizeof(arrayEntries));     /*initialize to hint the stub  to alloc space */
5034     vcode = VLDB_ListAttributes(&attributes, &nentries, &arrayEntries);
5035     if (vcode) {
5036         fprintf(STDERR, "Could not access the VLDB for attributes\n");
5037         PrintError("", vcode);
5038         exit(1);
5039     }
5040     for (j = 0; j < nentries; j++) {    /* process each entry */
5041         vllist = &arrayEntries.nbulkentries_val[j];
5042         volid = vllist->volumeId[RWVOL];
5043         vcode =
5044             ubik_VL_ReleaseLock(cstruct, 0, volid, -1,
5045                                 LOCKREL_OPCODE | LOCKREL_AFSID | 
5046                                 LOCKREL_TIMESTAMP);
5047         if (vcode) {
5048             fprintf(STDERR, "Could not unlock entry for volume %s\n",
5049                     vllist->name);
5050             PrintError("", vcode);
5051             totalE++;
5052         }
5053
5054     }
5055     MapPartIdIntoName(apart, pname);
5056     if (totalE)
5057         fprintf(STDOUT,
5058                 "Could not lock %lu VLDB entries of %lu locked entries\n",
5059                 (unsigned long)totalE, (unsigned long)nentries);
5060     else {
5061         if (as->parms[0].items) {
5062             fprintf(STDOUT,
5063                     "Unlocked all the VLDB entries for volumes on server %s ",
5064                     as->parms[0].items->data);
5065             if (as->parms[1].items) {
5066                 MapPartIdIntoName(apart, pname);
5067                 fprintf(STDOUT, "partition %s\n", pname);
5068             } else
5069                 fprintf(STDOUT, "\n");
5070
5071         } else if (as->parms[1].items) {
5072             MapPartIdIntoName(apart, pname);
5073             fprintf(STDOUT,
5074                     "Unlocked all the VLDB entries for volumes on partition %s on all servers\n",
5075                     pname);
5076         }
5077     }
5078
5079     if (arrayEntries.nbulkentries_val)
5080         free(arrayEntries.nbulkentries_val);
5081     return 0;
5082 }
5083
5084 static char *
5085 PrintInt64Size(afs_uint64 in)
5086 {
5087     register afs_uint32 hi, lo;
5088     register char * units;
5089     static char output[16];
5090
5091     SplitInt64(in,hi,lo);
5092
5093     if (hi == 0) {
5094         units = "KB";
5095     } else if (!(hi & 0xFFFFFC00)) {
5096         units = "MB";
5097         lo = (hi << 22) | (lo >> 10);
5098     } else if (!(hi & 0xFFF00000)) {
5099         units = "GB";
5100         lo = (hi << 12) | (lo >> 20);
5101     } else if (!(hi & 0xC0000000)) {
5102         units = "TB";
5103         lo = (hi << 2) | (lo >> 30);
5104     } else {
5105         units = "PB";
5106         lo = (hi >> 8);
5107     }
5108     sprintf(output,"%u %s", lo, units);
5109     return output;
5110 }
5111
5112 static int
5113 PartitionInfo(register struct cmd_syndesc *as, void *arock)
5114 {
5115     afs_int32 apart;
5116     afs_uint32 aserver;
5117     afs_int32 code;
5118     char pname[10];
5119     struct diskPartition64 partition;
5120     struct partList dummyPartList;
5121     int i, cnt;
5122     int printSummary=0, sumPartitions=0;
5123     afs_uint64 sumFree, sumStorage;
5124
5125     ZeroInt64(sumFree);
5126     ZeroInt64(sumStorage);
5127     apart = -1;
5128     aserver = GetServer(as->parms[0].items->data);
5129     if (aserver == 0) {
5130         fprintf(STDERR, "vos: server '%s' not found in host table\n",
5131                 as->parms[0].items->data);
5132         exit(1);
5133     }
5134     if (as->parms[1].items) {
5135         apart = volutil_GetPartitionID(as->parms[1].items->data);
5136         if (apart < 0) {
5137             fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
5138                     as->parms[1].items->data);
5139             exit(1);
5140         }
5141         dummyPartList.partId[0] = apart;
5142         dummyPartList.partFlags[0] = PARTVALID;
5143         cnt = 1;
5144     }
5145     if (as->parms[2].items) {
5146         printSummary = 1;
5147     }
5148     if (apart != -1) {
5149         if (!IsPartValid(apart, aserver, &code)) {      /*check for validity of the partition */
5150             if (code)
5151                 PrintError("", code);
5152             else
5153                 fprintf(STDERR,
5154                         "vos : partition %s does not exist on the server\n",
5155                         as->parms[1].items->data);
5156             exit(1);
5157         }
5158     } else {
5159         code = UV_ListPartitions(aserver, &dummyPartList, &cnt);
5160         if (code) {
5161             PrintDiagnostics("listpart", code);
5162             exit(1);
5163         }
5164     }
5165     for (i = 0; i < cnt; i++) {
5166         if (dummyPartList.partFlags[i] & PARTVALID) {
5167             MapPartIdIntoName(dummyPartList.partId[i], pname);
5168             code = UV_PartitionInfo64(aserver, pname, &partition);
5169             if (code) {
5170                 fprintf(STDERR, "Could not get information on partition %s\n",
5171                         pname);
5172                 PrintError("", code);
5173                 exit(1);
5174             }
5175             fprintf(STDOUT,
5176                     "Free space on partition %s: %" AFS_INT64_FMT " K blocks out of total %" AFS_INT64_FMT "\n",
5177                     pname, partition.free, partition.minFree);
5178             sumPartitions++;
5179             AddUInt64(sumFree,partition.free,&sumFree);
5180             AddUInt64(sumStorage,partition.minFree,&sumStorage);
5181         }
5182     }
5183     if (printSummary) {
5184         fprintf(STDOUT,
5185                 "Summary: %s free out of ",
5186                 PrintInt64Size(sumFree));
5187         fprintf(STDOUT,
5188                 "%s on %d partitions\n",
5189                 PrintInt64Size(sumStorage), 
5190                 sumPartitions);
5191     }
5192     return 0;
5193 }
5194
5195 static int
5196 ChangeAddr(register struct cmd_syndesc *as, void *arock)
5197 {
5198     afs_int32 ip1, ip2, vcode;
5199     int remove = 0;
5200
5201     if (noresolve)
5202         ip1 = GetServerNoresolve(as->parms[0].items->data);
5203     else
5204         ip1 = GetServer(as->parms[0].items->data);
5205     if (!ip1) {
5206         fprintf(STDERR, "vos: invalid host address\n");
5207         return (EINVAL);
5208     }
5209
5210     if ((as->parms[1].items && as->parms[2].items)
5211         || (!as->parms[1].items && !as->parms[2].items)) {
5212         fprintf(STDERR,
5213                 "vos: Must specify either '-newaddr <addr>' or '-remove' flag\n");
5214         return (EINVAL);
5215     }
5216
5217     if (as->parms[1].items) {
5218         if (noresolve)
5219             ip2 = GetServerNoresolve(as->parms[1].items->data);
5220         else
5221             ip2 = GetServer(as->parms[1].items->data);
5222         if (!ip2) {
5223             fprintf(STDERR, "vos: invalid host address\n");
5224             return (EINVAL);
5225         }
5226     } else {
5227         /* Play a trick here. If we are removing an address, ip1 will be -1
5228          * and ip2 will be the original address. This switch prevents an 
5229          * older revision vlserver from removing the IP address.
5230          */
5231         remove = 1;
5232         ip2 = ip1;
5233         ip1 = 0xffffffff;
5234     }
5235
5236     vcode = ubik_VL_ChangeAddr(cstruct, UBIK_CALL_NEW, ntohl(ip1), ntohl(ip2));
5237     if (vcode) {
5238         char hoststr1[16], hoststr2[16];
5239         if (remove) {
5240             afs_inet_ntoa_r(ip2, hoststr2);
5241             fprintf(STDERR, "Could not remove server %s from the VLDB\n",
5242                     hoststr2);
5243             if (vcode == VL_NOENT) {
5244                 fprintf(STDERR,
5245                         "vlserver does not support the remove flag or ");
5246             }
5247         } else {
5248             afs_inet_ntoa_r(ip1, hoststr1);
5249             afs_inet_ntoa_r(ip2, hoststr2);
5250             fprintf(STDERR, "Could not change server %s to server %s\n",
5251                     hoststr1, hoststr2);
5252         }
5253         PrintError("", vcode);
5254         return (vcode);
5255     }
5256
5257     if (remove) {
5258         fprintf(STDOUT, "Removed server %s from the VLDB\n",
5259                 as->parms[0].items->data);
5260     } else {
5261         fprintf(STDOUT, "Changed server %s to server %s\n",
5262                 as->parms[0].items->data, as->parms[1].items->data);
5263     }
5264     return 0;
5265 }
5266
5267 static void
5268 print_addrs(const bulkaddrs * addrs, afsUUID * m_uuid, int nentries,
5269             int print)
5270 {
5271     afs_int32 vcode, m_uniq=0;
5272     afs_int32 i, j;
5273     afs_uint32 *addrp;
5274     bulkaddrs m_addrs;
5275     ListAddrByAttributes m_attrs;
5276     afs_int32 m_nentries;
5277     afs_uint32 *m_addrp;
5278     afs_int32 base, index;
5279     char buf[1024];
5280
5281     if (print) {
5282         afsUUID_to_string(m_uuid, buf, sizeof(buf));
5283         printf("UUID: %s\n", buf);
5284     }
5285
5286     /* print out the list of all the server */
5287     addrp = (afs_uint32 *) addrs->bulkaddrs_val;
5288     for (i = 0; i < nentries; i++, addrp++) {
5289         /* If it is a multihomed address, then we will need to 
5290          * get the addresses for this multihomed server from
5291          * the vlserver and print them.
5292          */
5293         if (((*addrp & 0xff000000) == 0xff000000) && ((*addrp) & 0xffff)) {
5294             /* Get the list of multihomed fileservers */
5295             base = (*addrp >> 16) & 0xff;
5296             index = (*addrp) & 0xffff;
5297
5298             if ((base >= 0) && (base <= VL_MAX_ADDREXTBLKS) && (index >= 1)
5299                 && (index <= VL_MHSRV_PERBLK)) {
5300                 m_attrs.Mask = VLADDR_INDEX;
5301                 m_attrs.index = (base * VL_MHSRV_PERBLK) + index;
5302                 m_nentries = 0;
5303                 m_addrs.bulkaddrs_val = 0;
5304                 m_addrs.bulkaddrs_len = 0;
5305                 vcode =
5306                     ubik_VL_GetAddrsU(cstruct, 0, &m_attrs, m_uuid,
5307                                       &m_uniq, &m_nentries,
5308                                       &m_addrs);
5309                 if (vcode) {
5310                     fprintf(STDERR,
5311                             "vos: could not list the multi-homed server addresses\n");
5312                     PrintError("", vcode);
5313                 }
5314
5315                 /* Print the list */
5316                 m_addrp = (afs_uint32 *) m_addrs.bulkaddrs_val;
5317                 for (j = 0; j < m_nentries; j++, m_addrp++) {
5318                     *m_addrp = htonl(*m_addrp);
5319                     if (noresolve) {
5320                         char hoststr[16];
5321                         printf("%s ", afs_inet_ntoa_r(*m_addrp, hoststr));
5322                     } else {
5323                         printf("%s ", hostutil_GetNameByINet(*m_addrp));
5324                     }
5325                 }
5326                 if (j == 0) {
5327                     printf("<unknown>\n");
5328                 } else {
5329                     printf("\n");
5330                 }
5331
5332                 continue;
5333             }
5334         }
5335
5336         /* Otherwise, it is a non-multihomed entry and contains
5337          * the IP address of the server - print it.
5338          */
5339         *addrp = htonl(*addrp);
5340         if (noresolve) {
5341             char hoststr[16];
5342             printf("%s\n", afs_inet_ntoa_r(*addrp, hoststr));
5343         } else {
5344             printf("%s\n", hostutil_GetNameByINet(*addrp));
5345         }
5346     }
5347
5348     if (print) {
5349         printf("\n");
5350     }
5351     return;
5352 }
5353
5354 static int
5355 ListAddrs(register struct cmd_syndesc *as, void *arock)
5356 {
5357     afs_int32 vcode, m_uniq=0;
5358     afs_int32 i, printuuid = 0;
5359     struct VLCallBack vlcb;
5360     afs_int32 nentries;
5361     bulkaddrs m_addrs;
5362     ListAddrByAttributes m_attrs;
5363     afsUUID m_uuid, askuuid;
5364     afs_int32 m_nentries;
5365
5366     memset(&m_attrs, 0, sizeof(struct ListAddrByAttributes));
5367     m_attrs.Mask = VLADDR_INDEX;
5368
5369     memset(&m_addrs, 0, sizeof(bulkaddrs));
5370     memset(&askuuid, 0, sizeof(afsUUID));
5371     if (as->parms[0].items) {
5372         /* -uuid */
5373         if (afsUUID_from_string(as->parms[0].items->data, &askuuid) < 0) {
5374             fprintf(STDERR, "vos: invalid UUID '%s'\n", 
5375                     as->parms[0].items->data);
5376             exit(-1);
5377         }
5378         m_attrs.Mask = VLADDR_UUID;
5379         m_attrs.uuid = askuuid;
5380     }
5381     if (as->parms[1].items) {
5382         /* -host */
5383         struct hostent *he;
5384         afs_uint32 saddr;
5385         he = hostutil_GetHostByName((char *)as->parms[1].items->data);
5386         if (he == NULL) {
5387             fprintf(STDERR, "vos: Can't get host info for '%s'\n",
5388                     as->parms[1].items->data);
5389             exit(-1);
5390         }
5391         memcpy(&saddr, he->h_addr, 4);
5392         m_attrs.Mask = VLADDR_IPADDR;
5393         m_attrs.ipaddr = ntohl(saddr);
5394     }
5395     if (as->parms[2].items) {
5396         printuuid = 1;
5397     }
5398
5399     m_addrs.bulkaddrs_val = 0;
5400     m_addrs.bulkaddrs_len = 0;
5401
5402     vcode =
5403         ubik_VL_GetAddrs(cstruct, UBIK_CALL_NEW, 0, 0, &vlcb, &nentries,
5404                          &m_addrs);
5405     if (vcode) {
5406         fprintf(STDERR, "vos: could not list the server addresses\n");
5407         PrintError("", vcode);
5408         return (vcode);
5409     }
5410
5411     m_nentries = 0;
5412     m_addrs.bulkaddrs_val = 0;
5413     m_addrs.bulkaddrs_len = 0;
5414     i = 1;
5415     while (1) {
5416         m_attrs.index = i;
5417
5418         vcode =
5419             ubik_VL_GetAddrsU(cstruct, UBIK_CALL_NEW, &m_attrs, &m_uuid,
5420                               &m_uniq, &m_nentries, &m_addrs);
5421
5422         if (vcode == VL_NOENT) {
5423             if (m_attrs.Mask == VLADDR_UUID) {
5424                 fprintf(STDERR, "vos: no entry for UUID '%s' found in VLDB\n",
5425                         as->parms[0].items->data);
5426                 exit(-1);
5427             } else if (m_attrs.Mask == VLADDR_IPADDR) {
5428                 fprintf(STDERR, "vos: no entry for host '%s' [0x%08x] found in VLDB\n",
5429                         as->parms[1].items->data, m_attrs.ipaddr);
5430                 exit(-1);
5431             } else {
5432                 i++;
5433                 nentries++;
5434                 continue;
5435             }
5436         }
5437
5438         if (vcode == VL_INDEXERANGE) {
5439             break;
5440         }
5441
5442         if (vcode) {
5443             fprintf(STDERR, "vos: could not list the server addresses\n");
5444             PrintError("", vcode);
5445             return (vcode);
5446         }
5447
5448         print_addrs(&m_addrs, &m_uuid, m_nentries, printuuid);
5449         i++;
5450
5451         if ((as->parms[1].items) || (as->parms[0].items) || (i > nentries))
5452             break;
5453     }
5454
5455     return 0;
5456 }
5457
5458
5459 static int
5460 SetAddrs(register struct cmd_syndesc *as, void *arock)
5461 {
5462     afs_int32 vcode;
5463     bulkaddrs m_addrs;
5464     afsUUID askuuid;
5465     afs_uint32 FS_HostAddrs_HBO[ADDRSPERSITE];
5466
5467     memset(&m_addrs, 0, sizeof(bulkaddrs));
5468     memset(&askuuid, 0, sizeof(afsUUID));
5469     if (as->parms[0].items) {
5470         /* -uuid */
5471         if (afsUUID_from_string(as->parms[0].items->data, &askuuid) < 0) {
5472             fprintf(STDERR, "vos: invalid UUID '%s'\n",
5473                     as->parms[0].items->data);
5474             exit(-1);
5475         }
5476     }
5477     if (as->parms[1].items) {
5478         /* -host */
5479         struct cmd_item *ti;
5480         afs_uint32 saddr;
5481         int i = 0;
5482
5483         for (ti = as->parms[1].items; ti && i < ADDRSPERSITE; ti = ti->next) {
5484
5485             if (noresolve)
5486                 saddr = GetServerNoresolve(ti->data);
5487             else
5488                 saddr = GetServer(ti->data);
5489
5490             if (!saddr) {
5491                 fprintf(STDERR, "vos: Can't get host info for '%s'\n",
5492                         ti->data);
5493                 exit(-1);
5494             }
5495             /* Convert it to host byte order */
5496             FS_HostAddrs_HBO[i] = ntohl(saddr);
5497             i++;
5498         }
5499         m_addrs.bulkaddrs_len = i;
5500         m_addrs.bulkaddrs_val = FS_HostAddrs_HBO;
5501     }
5502
5503     vcode = ubik_VL_RegisterAddrs(cstruct, 0, &askuuid, 0, &m_addrs);
5504
5505     if (vcode) {
5506         if (vcode == VL_MULTIPADDR) {
5507             fprintf(STDERR, "vos: VL_RegisterAddrs rpc failed; The IP address exists on a different server; repair it\n");
5508             PrintError("", vcode);
5509             return vcode;
5510         } else if (vcode == RXGEN_OPCODE) {
5511             fprintf(STDERR, "vlserver doesn't support VL_RegisterAddrs rpc; ignored\n");
5512             PrintError("", vcode);
5513             return vcode;
5514         }
5515     }
5516     if (verbose) {
5517         fprintf(STDOUT, "vos: Changed UUID with addresses:\n");
5518         print_addrs(&m_addrs, &askuuid, m_addrs.bulkaddrs_len, 1);
5519     }
5520     return 0;
5521 }
5522
5523 static int
5524 LockEntry(register struct cmd_syndesc *as, void *arock)
5525 {
5526     afs_uint32 avolid;
5527     afs_int32 vcode, err;
5528
5529     avolid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);
5530     if (avolid == 0) {
5531         if (err)
5532             PrintError("", err);
5533         else
5534             fprintf(STDERR, "vos: can't find volume '%s'\n",
5535                     as->parms[0].items->data);
5536         exit(1);
5537     }
5538     vcode = ubik_VL_SetLock(cstruct, 0, avolid, -1, VLOP_DELETE);
5539     if (vcode) {
5540         fprintf(STDERR, "Could not lock VLDB entry for volume %s\n",
5541                 as->parms[0].items->data);
5542         PrintError("", vcode);
5543         exit(1);
5544     }
5545     fprintf(STDOUT, "Locked VLDB entry for volume %s\n",
5546             as->parms[0].items->data);
5547     return 0;
5548 }
5549
5550 static int
5551 ConvertRO(register struct cmd_syndesc *as, void *arock)
5552 {
5553     afs_int32 partition = -1;
5554     afs_uint32 volid;
5555     afs_uint32 server;
5556     afs_int32 code, i, same;
5557     struct nvldbentry entry, storeEntry;
5558     afs_int32 vcode;
5559     afs_int32 rwindex = 0;
5560     afs_uint32 rwserver = 0;
5561     afs_int32 rwpartition = 0;
5562     afs_int32 roindex = 0;
5563     afs_uint32 roserver = 0;
5564     afs_int32 ropartition = 0;
5565     int force = 0;
5566     struct rx_connection *aconn;
5567     char c, dc;
5568
5569     server = GetServer(as->parms[0].items->data);
5570     if (!server) {
5571         fprintf(STDERR, "vos: host '%s' not found in host table\n",
5572                 as->parms[0].items->data);
5573         return ENOENT;
5574     }
5575     partition = volutil_GetPartitionID(as->parms[1].items->data);
5576     if (partition < 0) {
5577         fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
5578                 as->parms[1].items->data);
5579         return ENOENT;
5580     }
5581     if (!IsPartValid(partition, server, &code)) {
5582         if (code)
5583             PrintError("", code);
5584         else
5585             fprintf(STDERR,
5586                     "vos : partition %s does not exist on the server\n",
5587                     as->parms[1].items->data);
5588         return ENOENT;
5589     }
5590     volid = vsu_GetVolumeID(as->parms[2].items->data, cstruct, &code);
5591     if (volid == 0) {
5592         if (code)
5593             PrintError("", code);
5594         else
5595             fprintf(STDERR, "Unknown volume ID or name '%s'\n",
5596                     as->parms[0].items->data);
5597         return -1;
5598     }
5599     if (as->parms[3].items)
5600         force = 1;
5601
5602     vcode = VLDB_GetEntryByID(volid, -1, &entry);
5603     if (vcode) {
5604         fprintf(STDERR,
5605                 "Could not fetch the entry for volume %lu from VLDB\n",
5606                 (unsigned long)volid);
5607         PrintError("convertROtoRW", code);
5608         return vcode;
5609     }
5610
5611     /* use RO volid even if user specified RW or BK volid */
5612
5613     if (volid != entry.volumeId[ROVOL])
5614         volid = entry.volumeId[ROVOL];
5615
5616     MapHostToNetwork(&entry);
5617     for (i = 0; i < entry.nServers; i++) {
5618         if (entry.serverFlags[i] & ITSRWVOL) {
5619             rwindex = i;
5620             rwserver = entry.serverNumber[i];
5621             rwpartition = entry.serverPartition[i];
5622         }
5623         if (entry.serverFlags[i] & ITSROVOL) {
5624             same = VLDB_IsSameAddrs(server, entry.serverNumber[i], &code);
5625             if (code) {
5626                 fprintf(STDERR,
5627                         "Failed to get info about server's %d address(es) from vlserver (err=%d); aborting call!\n",
5628                         server, code);
5629                 return ENOENT;
5630             }
5631             if (same) {
5632                 roindex = i;
5633                 roserver = entry.serverNumber[i];
5634                 ropartition = entry.serverPartition[i];
5635                 break;
5636             }
5637         }
5638     }
5639     if (!roserver) {
5640         fprintf(STDERR, "Warning: RO volume didn't exist in vldb!\n");
5641     }
5642     if (ropartition != partition) {
5643         fprintf(STDERR,
5644                 "Warning: RO volume should be in partition %d instead of %d (vldb)\n",
5645                 ropartition, partition);
5646     }
5647
5648     if (rwserver) {
5649         fprintf(STDERR,
5650                 "VLDB indicates that a RW volume exists already on %s in partition %s.\n",
5651                 hostutil_GetNameByINet(rwserver),
5652                 volutil_PartitionName(rwpartition));
5653         if (!force) {
5654             fprintf(STDERR, "Overwrite this VLDB entry? [y|n] (n)\n");
5655             dc = c = getchar();
5656             while (!(dc == EOF || dc == '\n'))
5657                 dc = getchar(); /* goto end of line */
5658             if ((c != 'y') && (c != 'Y')) {
5659                 fprintf(STDERR, "aborted.\n");
5660                 return -1;
5661             }
5662         }
5663     }
5664
5665     vcode =
5666         ubik_VL_SetLock(cstruct, 0, entry.volumeId[RWVOL], RWVOL,
5667                   VLOP_MOVE);
5668     aconn = UV_Bind(server, AFSCONF_VOLUMEPORT);
5669     code = AFSVolConvertROtoRWvolume(aconn, partition, volid);
5670     if (code) {
5671         fprintf(STDERR,
5672                 "Converting RO volume %lu to RW volume failed with code %d\n",
5673                 (unsigned long)volid, code);
5674         PrintError("convertROtoRW ", code);
5675         return -1;
5676     }
5677     entry.serverFlags[roindex] = ITSRWVOL;
5678     entry.flags |= RW_EXISTS;
5679     entry.flags &= ~BACK_EXISTS;
5680     if (rwserver) {
5681         (entry.nServers)--;
5682         if (rwindex != entry.nServers) {
5683             entry.serverNumber[rwindex] = entry.serverNumber[entry.nServers];
5684             entry.serverPartition[rwindex] =
5685                 entry.serverPartition[entry.nServers];
5686             entry.serverFlags[rwindex] = entry.serverFlags[entry.nServers];
5687             entry.serverNumber[entry.nServers] = 0;
5688             entry.serverPartition[entry.nServers] = 0;
5689             entry.serverFlags[entry.nServers] = 0;
5690         }
5691     }
5692     entry.flags &= ~RO_EXISTS;
5693     for (i = 0; i < entry.nServers; i++) {
5694         if (entry.serverFlags[i] & ITSROVOL) {
5695             if (!(entry.serverFlags[i] & (RO_DONTUSE | NEW_REPSITE)))
5696                 entry.flags |= RO_EXISTS;
5697         }
5698     }
5699     MapNetworkToHost(&entry, &storeEntry);
5700     code =
5701         VLDB_ReplaceEntry(entry.volumeId[RWVOL], RWVOL, &storeEntry,
5702                           (LOCKREL_OPCODE | LOCKREL_AFSID |
5703                            LOCKREL_TIMESTAMP));
5704     if (code) {
5705         fprintf(STDERR,
5706                 "Warning: volume converted, but vldb update failed with code %d!\n",
5707                 code);
5708     }
5709     vcode = UV_LockRelease(entry.volumeId[RWVOL]);
5710     if (vcode) {
5711         PrintDiagnostics("unlock", vcode);
5712     }
5713     return code;
5714 }
5715
5716 static int
5717 Sizes(register struct cmd_syndesc *as, void *arock)
5718 {
5719     afs_uint32 avolid;
5720     afs_uint32 aserver;
5721     afs_int32 apart, voltype, fromdate = 0, code, err, i;
5722     struct nvldbentry entry;
5723     volintSize vol_size;
5724
5725     rx_SetRxDeadTime(60 * 10);
5726     for (i = 0; i < MAXSERVERS; i++) {
5727         struct rx_connection *rxConn = ubik_GetRPCConn(cstruct, i);
5728         if (rxConn == 0)
5729             break;
5730         rx_SetConnDeadTime(rxConn, rx_connDeadTime);
5731         if (rxConn->service)
5732             rxConn->service->connDeadTime = rx_connDeadTime;
5733     }
5734
5735     avolid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);
5736     if (avolid == 0) {
5737         if (err)
5738             PrintError("", err);
5739         else
5740             fprintf(STDERR, "vos: can't find volume '%s'\n",
5741                     as->parms[0].items->data);
5742         return ENOENT;
5743     }
5744
5745     if (as->parms[1].items || as->parms[2].items) {
5746         if (!as->parms[1].items || !as->parms[2].items) {
5747             fprintf(STDERR,
5748                     "Must specify both -server and -partition options\n");
5749             return -1;
5750         }
5751         aserver = GetServer(as->parms[2].items->data);
5752         if (aserver == 0) {
5753             fprintf(STDERR, "Invalid server name\n");
5754             return -1;
5755         }
5756         apart = volutil_GetPartitionID(as->parms[1].items->data);
5757         if (apart < 0) {
5758             fprintf(STDERR, "Invalid partition name\n");
5759             return -1;
5760         }
5761     } else {
5762         code = GetVolumeInfo(avolid, &aserver, &apart, &voltype, &entry);
5763         if (code)
5764             return code;
5765     }
5766
5767     fromdate = 0;
5768
5769     if (as->parms[4].items && strcmp(as->parms[4].items->data, "0")) {
5770         code = ktime_DateToInt32(as->parms[4].items->data, &fromdate);
5771         if (code) {
5772             fprintf(STDERR, "vos: failed to parse date '%s' (error=%d))\n",
5773                     as->parms[4].items->data, code);
5774             return code;
5775         }
5776     }
5777
5778     fprintf(STDOUT, "Volume: %s\n", as->parms[0].items->data);
5779
5780     if (as->parms[3].items) {   /* do the dump estimate */
5781 #ifdef AFS_64BIT_ENV
5782         vol_size.dump_size = 0;
5783 #else
5784    FillInt64(vol_size.dump_size,0, 1);
5785 #endif
5786         code = UV_GetSize(avolid, aserver, apart, fromdate, &vol_size);
5787         if (code) {
5788             PrintDiagnostics("size", code);
5789             return code;
5790         }
5791         /* presumably the size info is now gathered in pntr */
5792         /* now we display it */
5793
5794         fprintf(STDOUT, "dump_size: %llu\n", vol_size.dump_size);
5795     }
5796
5797     /* Display info */
5798
5799     return 0;
5800 }
5801
5802 static int
5803 EndTrans(register struct cmd_syndesc *as, void *arock)
5804 {
5805     afs_uint32 server;
5806     afs_int32 code, tid, rcode;
5807     struct rx_connection *aconn;
5808
5809     server = GetServer(as->parms[0].items->data);
5810     if (!server) {
5811         fprintf(STDERR, "vos: host '%s' not found in host table\n",
5812                 as->parms[0].items->data);
5813         return EINVAL;
5814     }
5815
5816     code = util_GetInt32(as->parms[1].items->data, &tid);
5817     if (code) {
5818         fprintf(STDERR, "vos: bad integer specified for transaction ID.\n");
5819         return code;
5820     }
5821
5822     aconn = UV_Bind(server, AFSCONF_VOLUMEPORT);
5823     code = AFSVolEndTrans(aconn, tid, &rcode);
5824     if (!code) {
5825         code = rcode;
5826     }
5827
5828     if (code) {
5829         PrintDiagnostics("endtrans", code);
5830         return 1;
5831     }
5832
5833     return 0;
5834 }
5835
5836 int
5837 PrintDiagnostics(char *astring, afs_int32 acode)
5838 {
5839     if (acode == EACCES) {
5840         fprintf(STDERR,
5841                 "You are not authorized to perform the 'vos %s' command (%d)\n",
5842                 astring, acode);
5843     } else {
5844         fprintf(STDERR, "Error in vos %s command.\n", astring);
5845         PrintError("", acode);
5846     }
5847     return 0;
5848 }
5849
5850
5851 #ifdef AFS_NT40_ENV
5852 static DWORD
5853 win32_enableCrypt(void)
5854 {
5855     HKEY parmKey;
5856     DWORD dummyLen;
5857     DWORD cryptall = 0;
5858     DWORD code;
5859
5860     /* Look up configuration parameters in Registry */
5861     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
5862                         0, (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &parmKey);
5863     if (code != ERROR_SUCCESS) {
5864         dummyLen = sizeof(cryptall);
5865         RegQueryValueEx(parmKey, "SecurityLevel", NULL, NULL,
5866                         (BYTE *) &cryptall, &dummyLen);
5867     }
5868     RegCloseKey (parmKey);
5869
5870     return cryptall;
5871 }
5872 #endif /* AFS_NT40_ENV */
5873
5874 static int
5875 MyBeforeProc(struct cmd_syndesc *as, void *arock)
5876 {
5877     register char *tcell;
5878     register afs_int32 code;
5879     register afs_int32 sauth;
5880
5881     /* Initialize the ubik_client connection */
5882     rx_SetRxDeadTime(90);
5883     cstruct = (struct ubik_client *)0;
5884
5885     sauth = 0;
5886     tcell = NULL;
5887     if (as->parms[12].items)    /* if -cell specified */
5888         tcell = as->parms[12].items->data;
5889     if (as->parms[14].items)    /* -serverauth specified */
5890         sauth = 1;
5891     if (as->parms[16].items     /* -encrypt specified */
5892 #ifdef AFS_NT40_ENV
5893         || win32_enableCrypt()
5894 #endif /* AFS_NT40_ENV */
5895          )
5896         vsu_SetCrypt(1);
5897     if ((code =
5898          vsu_ClientInit((as->parms[13].items != 0), confdir, tcell, sauth,
5899                         &cstruct, UV_SetSecurity))) {
5900         fprintf(STDERR, "could not initialize VLDB library (code=%lu) \n",
5901                 (unsigned long)code);
5902         exit(1);
5903     }
5904     rxInitDone = 1;
5905     if (as->parms[15].items)    /* -verbose flag set */
5906         verbose = 1;
5907     else
5908         verbose = 0;
5909     if (as->parms[17].items)    /* -noresolve flag set */
5910         noresolve = 1;
5911     else
5912         noresolve = 0;
5913     return 0;
5914 }
5915
5916 int
5917 osi_audit(void)
5918 {
5919 /* this sucks but it works for now.
5920 */
5921     return 0;
5922 }
5923
5924 #include "AFS_component_version_number.c"
5925
5926 int
5927 main(int argc, char **argv)
5928 {
5929     register afs_int32 code;
5930
5931     register struct cmd_syndesc *ts;
5932
5933 #ifdef  AFS_AIX32_ENV
5934     /*
5935      * The following signal action for AIX is necessary so that in case of a 
5936      * crash (i.e. core is generated) we can include the user's data section 
5937      * in the core dump. Unfortunately, by default, only a partial core is
5938      * generated which, in many cases, isn't too useful.
5939      */
5940     struct sigaction nsa;
5941
5942     sigemptyset(&nsa.sa_mask);
5943     nsa.sa_handler = SIG_DFL;
5944     nsa.sa_flags = SA_FULLDUMP;
5945     sigaction(SIGSEGV, &nsa, NULL);
5946 #endif
5947
5948     confdir = AFSDIR_CLIENT_ETC_DIRPATH;
5949
5950     cmd_SetBeforeProc(MyBeforeProc, NULL);
5951
5952     ts = cmd_CreateSyntax("create", CreateVolume, NULL, "create a new volume");
5953     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
5954     cmd_AddParm(ts, "-partition", CMD_SINGLE, 0, "partition name");
5955     cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "volume name");
5956     cmd_AddParm(ts, "-maxquota", CMD_SINGLE, CMD_OPTIONAL,
5957                 "initial quota (KB)");
5958     cmd_AddParm(ts, "-id", CMD_SINGLE, CMD_OPTIONAL, "volume ID");
5959     cmd_AddParm(ts, "-roid", CMD_SINGLE, CMD_OPTIONAL, "readonly volume ID");
5960 #ifdef notdef
5961     cmd_AddParm(ts, "-minquota", CMD_SINGLE, CMD_OPTIONAL, "");
5962 #endif
5963     COMMONPARMS;
5964
5965     ts = cmd_CreateSyntax("remove", DeleteVolume, NULL, "delete a volume");
5966     cmd_AddParm(ts, "-server", CMD_SINGLE, CMD_OPTIONAL, "machine name");
5967     cmd_AddParm(ts, "-partition", CMD_SINGLE, CMD_OPTIONAL, "partition name");
5968     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
5969
5970     COMMONPARMS;
5971
5972     ts = cmd_CreateSyntax("move", MoveVolume, NULL, "move a volume");
5973     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
5974     cmd_AddParm(ts, "-fromserver", CMD_SINGLE, 0, "machine name on source");
5975     cmd_AddParm(ts, "-frompartition", CMD_SINGLE, 0,
5976                 "partition name on source");
5977     cmd_AddParm(ts, "-toserver", CMD_SINGLE, 0,
5978                 "machine name on destination");
5979     cmd_AddParm(ts, "-topartition", CMD_SINGLE, 0,
5980                 "partition name on destination");
5981     cmd_AddParm(ts, "-live", CMD_FLAG, CMD_OPTIONAL,
5982                 "copy live volume without cloning");
5983     COMMONPARMS;
5984
5985     ts = cmd_CreateSyntax("copy", CopyVolume, NULL, "copy a volume");
5986     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID on source");
5987     cmd_AddParm(ts, "-fromserver", CMD_SINGLE, 0, "machine name on source");
5988     cmd_AddParm(ts, "-frompartition", CMD_SINGLE, 0,
5989                 "partition name on source");
5990     cmd_AddParm(ts, "-toname", CMD_SINGLE, 0, "volume name on destination");
5991     cmd_AddParm(ts, "-toserver", CMD_SINGLE, 0,
5992                 "machine name on destination");
5993     cmd_AddParm(ts, "-topartition", CMD_SINGLE, 0,
5994                 "partition name on destination");
5995     cmd_AddParm(ts, "-offline", CMD_FLAG, CMD_OPTIONAL,
5996                 "leave new volume offline");
5997     cmd_AddParm(ts, "-readonly", CMD_FLAG, CMD_OPTIONAL,
5998                 "make new volume read-only");
5999     cmd_AddParm(ts, "-live", CMD_FLAG, CMD_OPTIONAL,
6000                 "copy live volume without cloning");
6001     COMMONPARMS;
6002
6003     ts = cmd_CreateSyntax("shadow", ShadowVolume, NULL,
6004                           "make or update a shadow volume");
6005     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID on source");
6006     cmd_AddParm(ts, "-fromserver", CMD_SINGLE, 0, "machine name on source");
6007     cmd_AddParm(ts, "-frompartition", CMD_SINGLE, 0,
6008                 "partition name on source");
6009     cmd_AddParm(ts, "-toserver", CMD_SINGLE, 0,
6010                 "machine name on destination");
6011     cmd_AddParm(ts, "-topartition", CMD_SINGLE, 0,
6012                 "partition name on destination");
6013     cmd_AddParm(ts, "-toname", CMD_SINGLE, CMD_OPTIONAL,
6014                 "volume name on destination");
6015     cmd_AddParm(ts, "-toid", CMD_SINGLE, CMD_OPTIONAL,
6016                 "volume ID on destination");
6017     cmd_AddParm(ts, "-offline", CMD_FLAG, CMD_OPTIONAL,
6018                 "leave shadow volume offline");
6019     cmd_AddParm(ts, "-readonly", CMD_FLAG, CMD_OPTIONAL,
6020                 "make shadow volume read-only");
6021     cmd_AddParm(ts, "-live", CMD_FLAG, CMD_OPTIONAL,
6022                 "copy live volume without cloning");
6023     cmd_AddParm(ts, "-incremental", CMD_FLAG, CMD_OPTIONAL,
6024                 "do incremental update if target exists");
6025     COMMONPARMS;
6026
6027     ts = cmd_CreateSyntax("backup", BackupVolume, NULL,
6028                           "make backup of a volume");
6029     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
6030     COMMONPARMS;
6031
6032     ts = cmd_CreateSyntax("clone", CloneVolume, NULL,
6033                           "make clone of a volume");
6034     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
6035     cmd_AddParm(ts, "-server", CMD_SINGLE, CMD_OPTIONAL, "server");
6036     cmd_AddParm(ts, "-partition", CMD_SINGLE, CMD_OPTIONAL, "partition");
6037     cmd_AddParm(ts, "-toname", CMD_SINGLE, CMD_OPTIONAL,
6038                 "volume name on destination");
6039     cmd_AddParm(ts, "-toid", CMD_SINGLE, CMD_OPTIONAL,
6040                 "volume ID on destination");
6041     cmd_AddParm(ts, "-offline", CMD_FLAG, CMD_OPTIONAL,
6042                 "leave clone volume offline");
6043     cmd_AddParm(ts, "-readonly", CMD_FLAG, CMD_OPTIONAL,
6044                 "make clone volume read-only, not readwrite");
6045     COMMONPARMS;
6046
6047     ts = cmd_CreateSyntax("release", ReleaseVolume, NULL, "release a volume");
6048     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
6049     cmd_AddParm(ts, "-force", CMD_FLAG, CMD_OPTIONAL,
6050                 "force a complete release");
6051     COMMONPARMS;
6052
6053     ts = cmd_CreateSyntax("dump", DumpVolumeCmd, NULL, "dump a volume");
6054     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
6055     cmd_AddParm(ts, "-time", CMD_SINGLE, CMD_OPTIONAL, "dump from time");
6056     cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_OPTIONAL, "dump file");
6057     cmd_AddParm(ts, "-server", CMD_SINGLE, CMD_OPTIONAL, "server");
6058     cmd_AddParm(ts, "-partition", CMD_SINGLE, CMD_OPTIONAL, "partition");
6059     cmd_AddParm(ts, "-clone", CMD_FLAG, CMD_OPTIONAL,
6060                 "dump a clone of the volume");
6061     cmd_AddParm(ts, "-omitdirs", CMD_FLAG, CMD_OPTIONAL,
6062                 "omit unchanged directories from an incremental dump");
6063     COMMONPARMS;
6064
6065     ts = cmd_CreateSyntax("restore", RestoreVolumeCmd, NULL,
6066                           "restore a volume");
6067     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
6068     cmd_AddParm(ts, "-partition", CMD_SINGLE, 0, "partition name");
6069     cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of volume to be restored");
6070     cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_OPTIONAL, "dump file");
6071     cmd_AddParm(ts, "-id", CMD_SINGLE, CMD_OPTIONAL, "volume ID");
6072     cmd_AddParm(ts, "-overwrite", CMD_SINGLE, CMD_OPTIONAL,
6073                 "abort | full | incremental");
6074     cmd_AddParm(ts, "-offline", CMD_FLAG, CMD_OPTIONAL,
6075                 "leave restored volume offline");
6076     cmd_AddParm(ts, "-readonly", CMD_FLAG, CMD_OPTIONAL,
6077                 "make restored volume read-only");
6078     cmd_AddParm(ts, "-creation", CMD_SINGLE, CMD_OPTIONAL,
6079                 "dump | keep | new");
6080     cmd_AddParm(ts, "-lastupdate", CMD_SINGLE, CMD_OPTIONAL,
6081                 "dump | keep | new");
6082     cmd_AddParm(ts, "-nodelete", CMD_FLAG, CMD_OPTIONAL,
6083                 "do not delete old site when restoring to a new site");
6084     COMMONPARMS;
6085
6086     ts = cmd_CreateSyntax("unlock", LockReleaseCmd, NULL,
6087                           "release lock on VLDB entry for a volume");
6088     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
6089     COMMONPARMS;
6090
6091     ts = cmd_CreateSyntax("changeloc", ChangeLocation, NULL,
6092                           "change an RW volume's location in the VLDB");
6093     cmd_AddParm(ts, "-server", CMD_SINGLE, 0,
6094                 "machine name for new location");
6095     cmd_AddParm(ts, "-partition", CMD_SINGLE, 0,
6096                 "partition name for new location");
6097     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
6098     COMMONPARMS;
6099
6100     ts = cmd_CreateSyntax("addsite", AddSite, NULL, "add a replication site");
6101     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name for new site");
6102     cmd_AddParm(ts, "-partition", CMD_SINGLE, 0,
6103                 "partition name for new site");
6104     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
6105     cmd_AddParm(ts, "-roid", CMD_SINGLE, CMD_OPTIONAL, "volume name or ID for RO");
6106     cmd_AddParm(ts, "-valid", CMD_FLAG, CMD_OPTIONAL, "publish as an up-to-date site in VLDB");
6107     COMMONPARMS;
6108
6109     ts = cmd_CreateSyntax("remsite", RemoveSite, NULL,
6110                           "remove a replication site");
6111     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
6112     cmd_AddParm(ts, "-partition", CMD_SINGLE, 0, "partition name");
6113     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
6114     COMMONPARMS;
6115
6116     ts = cmd_CreateSyntax("listpart", ListPartitions, NULL, "list partitions");
6117     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
6118     COMMONPARMS;
6119
6120     ts = cmd_CreateSyntax("listvol", ListVolumes, NULL,
6121                           "list volumes on server (bypass VLDB)");
6122     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
6123     cmd_AddParm(ts, "-partition", CMD_SINGLE, CMD_OPTIONAL, "partition name");
6124     cmd_AddParm(ts, "-fast", CMD_FLAG, CMD_OPTIONAL, "minimal listing");
6125     cmd_AddParm(ts, "-long", CMD_FLAG, CMD_OPTIONAL,
6126                 "list all normal volume fields");
6127     cmd_AddParm(ts, "-quiet", CMD_FLAG, CMD_OPTIONAL,
6128                 "generate minimal information");
6129     cmd_AddParm(ts, "-extended", CMD_FLAG, CMD_OPTIONAL,
6130                 "list extended volume fields");
6131     cmd_AddParm(ts, "-format", CMD_FLAG, CMD_OPTIONAL,
6132                 "machine readable format");
6133     COMMONPARMS;
6134
6135     ts = cmd_CreateSyntax("syncvldb", SyncVldb, NULL,
6136                           "synchronize VLDB with server");
6137     cmd_AddParm(ts, "-server", CMD_SINGLE, CMD_OPTIONAL, "machine name");
6138     cmd_AddParm(ts, "-partition", CMD_SINGLE, CMD_OPTIONAL, "partition name");
6139     cmd_AddParm(ts, "-volume", CMD_SINGLE, CMD_OPTIONAL, "volume name or ID");
6140     cmd_AddParm(ts, "-dryrun", CMD_FLAG, CMD_OPTIONAL, "report without updating");
6141     COMMONPARMS;
6142
6143     ts = cmd_CreateSyntax("syncserv", SyncServer, NULL,
6144                           "synchronize server with VLDB");
6145     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
6146     cmd_AddParm(ts, "-partition", CMD_SINGLE, CMD_OPTIONAL, "partition name");
6147     cmd_AddParm(ts, "-dryrun", CMD_FLAG, CMD_OPTIONAL, "report without updating");
6148     COMMONPARMS;
6149
6150     ts = cmd_CreateSyntax("examine", ExamineVolume, NULL,
6151                           "everything about the volume");
6152     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
6153     cmd_AddParm(ts, "-extended", CMD_FLAG, CMD_OPTIONAL,
6154                 "list extended volume fields");
6155     cmd_AddParm(ts, "-format", CMD_FLAG, CMD_OPTIONAL,
6156                 "machine readable format");
6157     COMMONPARMS;
6158     cmd_CreateAlias(ts, "volinfo");
6159
6160     ts = cmd_CreateSyntax("setfields", SetFields, NULL,
6161                           "change volume info fields");
6162     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
6163     cmd_AddParm(ts, "-maxquota", CMD_SINGLE, CMD_OPTIONAL, "quota (KB)");
6164     cmd_AddParm(ts, "-clearuse", CMD_FLAG, CMD_OPTIONAL, "clear dayUse");
6165     cmd_AddParm(ts, "-clearVolUpCounter", CMD_FLAG, CMD_OPTIONAL, "clear volUpdateCounter");
6166     COMMONPARMS;
6167
6168     ts = cmd_CreateSyntax("offline", volOffline, NULL, "force the volume status to offline");
6169     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "server name");
6170     cmd_AddParm(ts, "-partition", CMD_SINGLE, 0, "partition name");
6171     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
6172     cmd_AddParm(ts, "-sleep", CMD_SINGLE, CMD_OPTIONAL, "seconds to sleep");
6173     cmd_AddParm(ts, "-busy", CMD_FLAG, CMD_OPTIONAL, "busy volume");
6174     COMMONPARMS;
6175
6176     ts = cmd_CreateSyntax("online", volOnline, NULL, "force the volume status to online");
6177     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "server name");
6178     cmd_AddParm(ts, "-partition", CMD_SINGLE, 0, "partition name");
6179     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
6180     COMMONPARMS;
6181
6182     ts = cmd_CreateSyntax("zap", VolumeZap, NULL,
6183                           "delete the volume, don't bother with VLDB");
6184     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
6185     cmd_AddParm(ts, "-partition", CMD_SINGLE, 0, "partition name");
6186     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume ID");
6187     cmd_AddParm(ts, "-force", CMD_FLAG, CMD_OPTIONAL,
6188                 "force deletion of bad volumes");
6189     cmd_AddParm(ts, "-backup", CMD_FLAG, CMD_OPTIONAL,
6190                 "also delete backup volume if one is found");
6191     COMMONPARMS;
6192
6193     ts = cmd_CreateSyntax("status", VolserStatus, NULL,
6194                           "report on volser status");
6195     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
6196     COMMONPARMS;
6197
6198     ts = cmd_CreateSyntax("rename", RenameVolume, NULL, "rename a volume");
6199     cmd_AddParm(ts, "-oldname", CMD_SINGLE, 0, "old volume name ");
6200     cmd_AddParm(ts, "-newname", CMD_SINGLE, 0, "new volume name ");
6201     COMMONPARMS;
6202
6203     ts = cmd_CreateSyntax("listvldb", ListVLDB, NULL,
6204                           "list volumes in the VLDB");
6205     cmd_AddParm(ts, "-name", CMD_SINGLE, CMD_OPTIONAL, "volume name or ID");
6206     cmd_AddParm(ts, "-server", CMD_SINGLE, CMD_OPTIONAL, "machine name");
6207     cmd_AddParm(ts, "-partition", CMD_SINGLE, CMD_OPTIONAL, "partition name");
6208     cmd_AddParm(ts, "-locked", CMD_FLAG, CMD_OPTIONAL, "locked volumes only");
6209     cmd_AddParm(ts, "-quiet", CMD_FLAG, CMD_OPTIONAL,
6210                 "generate minimal information");
6211     cmd_AddParm(ts, "-nosort", CMD_FLAG, CMD_OPTIONAL,
6212                 "do not alphabetically sort the volume names");
6213     COMMONPARMS;
6214
6215     ts = cmd_CreateSyntax("backupsys", BackSys, NULL, "en masse backups");
6216     cmd_AddParm(ts, "-prefix", CMD_LIST, CMD_OPTIONAL,
6217                 "common prefix on volume(s)");
6218     cmd_AddParm(ts, "-server", CMD_SINGLE, CMD_OPTIONAL, "machine name");
6219     cmd_AddParm(ts, "-partition", CMD_SINGLE, CMD_OPTIONAL, "partition name");
6220     cmd_AddParm(ts, "-exclude", CMD_FLAG, CMD_OPTIONAL,
6221                 "exclude common prefix volumes");
6222     cmd_AddParm(ts, "-xprefix", CMD_LIST, CMD_OPTIONAL,
6223                 "negative prefix on volume(s)");
6224     cmd_AddParm(ts, "-dryrun", CMD_FLAG, CMD_OPTIONAL, "no action");
6225     COMMONPARMS;
6226
6227     ts = cmd_CreateSyntax("delentry", DeleteEntry, NULL,
6228                           "delete VLDB entry for a volume");
6229     cmd_AddParm(ts, "-id", CMD_LIST, CMD_OPTIONAL, "volume name or ID");
6230     cmd_AddParm(ts, "-prefix", CMD_SINGLE, CMD_OPTIONAL,
6231                 "prefix of the volume whose VLDB entry is to be deleted");
6232     cmd_AddParm(ts, "-server", CMD_SINGLE, CMD_OPTIONAL, "machine name");
6233     cmd_AddParm(ts, "-partition", CMD_SINGLE, CMD_OPTIONAL, "partition name");
6234     cmd_AddParm(ts, "-noexecute", CMD_FLAG, CMD_OPTIONAL,
6235                 "no execute");
6236     COMMONPARMS;
6237
6238     ts = cmd_CreateSyntax("partinfo", PartitionInfo, NULL,
6239                           "list partition information");
6240     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
6241     cmd_AddParm(ts, "-partition", CMD_SINGLE, CMD_OPTIONAL, "partition name");
6242     cmd_AddParm(ts, "-summary", CMD_FLAG, CMD_OPTIONAL,
6243                 "print storage summary");
6244     COMMONPARMS;
6245
6246     ts = cmd_CreateSyntax("unlockvldb", UnlockVLDB, NULL,
6247                           "unlock all the locked entries in the VLDB");
6248     cmd_AddParm(ts, "-server", CMD_SINGLE, CMD_OPTIONAL, "machine name");
6249     cmd_AddParm(ts, "-partition", CMD_SINGLE, CMD_OPTIONAL, "partition name");
6250     COMMONPARMS;
6251
6252     ts = cmd_CreateSyntax("lock", LockEntry, NULL,
6253                           "lock VLDB entry for a volume");
6254     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
6255     COMMONPARMS;
6256
6257     ts = cmd_CreateSyntax("changeaddr", ChangeAddr, NULL,
6258                           "change the IP address of a file server");
6259     cmd_AddParm(ts, "-oldaddr", CMD_SINGLE, 0, "original IP address");
6260     cmd_AddParm(ts, "-newaddr", CMD_SINGLE, CMD_OPTIONAL, "new IP address");
6261     cmd_AddParm(ts, "-remove", CMD_FLAG, CMD_OPTIONAL,
6262                 "remove the IP address from the VLDB");
6263     COMMONPARMS;
6264
6265     ts = cmd_CreateSyntax("listaddrs", ListAddrs, NULL,
6266                           "list the IP address of all file servers registered in the VLDB");
6267     cmd_AddParm(ts, "-uuid", CMD_SINGLE, CMD_OPTIONAL, "uuid of server");
6268     cmd_AddParm(ts, "-host", CMD_SINGLE, CMD_OPTIONAL, "address of host");
6269     cmd_AddParm(ts, "-printuuid", CMD_FLAG, CMD_OPTIONAL,
6270                 "print uuid of hosts");
6271     COMMONPARMS;
6272
6273     ts = cmd_CreateSyntax("convertROtoRW", ConvertRO, NULL,
6274                           "convert a RO volume into a RW volume (after loss of old RW volume)");
6275     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
6276     cmd_AddParm(ts, "-partition", CMD_SINGLE, 0, "partition name");
6277     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
6278     cmd_AddParm(ts, "-force", CMD_FLAG, CMD_OPTIONAL, "don't ask");
6279     COMMONPARMS;
6280
6281     ts = cmd_CreateSyntax("size", Sizes, NULL,
6282                           "obtain various sizes of the volume.");
6283     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
6284     cmd_AddParm(ts, "-partition", CMD_SINGLE, CMD_OPTIONAL, "partition name");
6285     cmd_AddParm(ts, "-server", CMD_SINGLE, CMD_OPTIONAL, "machine name");
6286     cmd_AddParm(ts, "-dump", CMD_FLAG, CMD_OPTIONAL,
6287                 "Obtain the size of the dump");
6288     cmd_AddParm(ts, "-time", CMD_SINGLE, CMD_OPTIONAL, "dump from time");
6289     COMMONPARMS;
6290
6291     ts = cmd_CreateSyntax("endtrans", EndTrans, NULL,
6292                           "end a volserver transaction");
6293     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
6294     cmd_AddParm(ts, "-transaction", CMD_SINGLE, 0,
6295                 "transaction ID");
6296     COMMONPARMS;
6297
6298     ts = cmd_CreateSyntax("setaddrs", SetAddrs, NULL,
6299                           "set the list of IP address for a given UUID in the VLDB");
6300     cmd_AddParm(ts, "-uuid", CMD_SINGLE, 0, "uuid of server");
6301     cmd_AddParm(ts, "-host", CMD_LIST, 0, "address of host");
6302
6303     COMMONPARMS;
6304     code = cmd_Dispatch(argc, argv);
6305     if (rxInitDone) {
6306         /* Shut down the ubik_client and rx connections */
6307         if (cstruct) {
6308             (void)ubik_ClientDestroy(cstruct);
6309             cstruct = 0;
6310         }
6311         rx_Finalize();
6312     }
6313
6314     exit((code ? -1 : 0));
6315 }