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