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