Squash pthreaded vos warnings
[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 name/address and return the address in HOST BYTE order
205  */
206 afs_int32
207 GetServer(char *aname)
208 {
209     register struct hostent *th;
210     afs_int32 addr;
211     int b1, b2, b3, b4;
212     register afs_int32 code;
213     char hostname[MAXHOSTCHARS];
214
215     code = sscanf(aname, "%d.%d.%d.%d", &b1, &b2, &b3, &b4);
216     if (code == 4) {
217         addr = (b1 << 24) | (b2 << 16) | (b3 << 8) | b4;
218         addr = ntohl(addr);     /* convert to host order */
219     } else {
220         th = gethostbyname(aname);
221         if (!th)
222             return 0;
223         memcpy(&addr, th->h_addr, sizeof(addr));
224     }
225
226     if (addr == htonl(0x7f000001)) {    /* local host */
227         code = gethostname(hostname, MAXHOSTCHARS);
228         if (code)
229             return 0;
230         th = gethostbyname(hostname);   /* returns host byte order */
231         if (!th)
232             return 0;
233         memcpy(&addr, th->h_addr, sizeof(addr));
234     }
235
236     return (addr);
237 }
238
239 afs_int32
240 GetVolumeType(char *aname)
241 {
242
243     if (!strcmp(aname, "ro"))
244         return (ROVOL);
245     else if (!strcmp(aname, "rw"))
246         return (RWVOL);
247     else if (!strcmp(aname, "bk"))
248         return (BACKVOL);
249     else
250         return (-1);
251 }
252
253 int
254 IsPartValid(afs_int32 partId, afs_int32 server, afs_int32 *code)
255 {
256     struct partList dummyPartList;
257     int i, success, cnt;
258
259     success = 0;
260     *code = 0;
261
262     *code = UV_ListPartitions(server, &dummyPartList, &cnt);
263     if (*code)
264         return success;
265     for (i = 0; i < cnt; i++) {
266         if (dummyPartList.partFlags[i] & PARTVALID)
267             if (dummyPartList.partId[i] == partId)
268                 success = 1;
269     }
270     return success;
271 }
272
273
274
275  /*sends the contents of file associated with <fd> and <blksize>  to Rx Stream 
276   * associated  with <call> */
277 int 
278 SendFile(usd_handle_t ufd, register struct rx_call *call, long blksize)
279 {
280     char *buffer = (char *)0;
281     afs_int32 error = 0;
282     int done = 0;
283     afs_uint32 nbytes;
284
285     buffer = (char *)malloc(blksize);
286     if (!buffer) {
287         fprintf(STDERR, "malloc failed\n");
288         return -1;
289     }
290
291     while (!error && !done) {
292 #ifndef AFS_NT40_ENV            /* NT csn't select on non-socket fd's */
293         fd_set in;
294         FD_ZERO(&in);
295         FD_SET((intptr_t)(ufd->handle), &in);
296         /* don't timeout if read blocks */
297 #if defined(AFS_PTHREAD_ENV)
298         select(((intptr_t)(ufd->handle)) + 1, &in, 0, 0, 0);
299 #else
300         IOMGR_Select(((intptr_t)(ufd->handle)) + 1, &in, 0, 0, 0);
301 #endif
302 #endif
303         error = USD_READ(ufd, buffer, blksize, &nbytes);
304         if (error) {
305             fprintf(STDERR, "File system read failed: %s\n",
306                     afs_error_message(error));
307             break;
308         }
309         if (nbytes == 0) {
310             done = 1;
311             break;
312         }
313         if (rx_Write(call, buffer, nbytes) != nbytes) {
314             error = -1;
315             break;
316         }
317     }
318     if (buffer)
319         free(buffer);
320     return error;
321 }
322
323 /* function invoked by UV_RestoreVolume, reads the data from rx_trx_stream and
324  * writes it out to the volume. */
325 afs_int32
326 WriteData(struct rx_call *call, void *rock)
327 {
328     char *filename = (char *) rock;
329     usd_handle_t ufd;
330     long blksize;
331     afs_int32 error, code;
332     int ufdIsOpen = 0;
333     afs_hyper_t filesize, currOffset; 
334     afs_uint32 buffer;          
335     afs_uint32 got;             
336
337     error = 0;
338
339     if (!filename || !*filename) {
340         usd_StandardInput(&ufd);
341         blksize = 4096;
342         ufdIsOpen = 1;
343     } else {
344         code = usd_Open(filename, USD_OPEN_RDONLY, 0, &ufd);
345         if (code == 0) {
346             ufdIsOpen = 1;
347             code = USD_IOCTL(ufd, USD_IOCTL_GETBLKSIZE, &blksize);
348         }
349         if (code) {
350             fprintf(STDERR, "Could not access file '%s': %s\n", filename,
351                     afs_error_message(code));
352             error = VOLSERBADOP;
353             goto wfail;
354         }
355         /* test if we have a valid dump */
356         hset64(filesize, 0, 0);
357         USD_SEEK(ufd, filesize, SEEK_END, &currOffset);
358         hset64(filesize, hgethi(currOffset), hgetlo(currOffset)-sizeof(afs_uint32));
359         USD_SEEK(ufd, filesize, SEEK_SET, &currOffset);
360         USD_READ(ufd, (char *)&buffer, sizeof(afs_uint32), &got);
361         if ((got != sizeof(afs_uint32)) || (ntohl(buffer) != DUMPENDMAGIC)) {
362             fprintf(STDERR, "Signature missing from end of file '%s'\n", filename);
363             error = VOLSERBADOP;
364             goto wfail;
365         }
366         /* rewind, we are done */
367         hset64(filesize, 0, 0);
368         USD_SEEK(ufd, filesize, SEEK_SET, &currOffset);
369     }
370     code = SendFile(ufd, call, blksize);
371     if (code) {
372         error = code;
373         goto wfail;
374     }
375   wfail:
376     if (ufdIsOpen) {
377         code = USD_CLOSE(ufd);
378         if (code) {
379             fprintf(STDERR, "Could not close dump file %s\n",
380                     (filename && *filename) ? filename : "STDOUT");
381             if (!error)
382                 error = code;
383         }
384     }
385     return error;
386 }
387
388 /* Receive data from <call> stream into file associated
389  * with <fd> <blksize>
390  */
391 int
392 ReceiveFile(usd_handle_t ufd, struct rx_call *call, long blksize)
393 {
394     char *buffer = NULL;
395     afs_int32 bytesread;
396     afs_uint32 bytesleft, w;
397     afs_int32 error = 0;
398
399     buffer = (char *)malloc(blksize);
400     if (!buffer) {
401         fprintf(STDERR, "memory allocation failed\n");
402         ERROR_EXIT(-1);
403     }
404
405     while ((bytesread = rx_Read(call, buffer, blksize)) > 0) {
406         for (bytesleft = bytesread; bytesleft; bytesleft -= w) {
407 #ifndef AFS_NT40_ENV            /* NT csn't select on non-socket fd's */
408             fd_set out;
409             FD_ZERO(&out);
410             FD_SET((intptr_t)(ufd->handle), &out);
411             /* don't timeout if write blocks */
412 #if defined(AFS_PTHREAD_ENV)
413             select(((intptr_t)(ufd->handle)) + 1, &out, 0, 0, 0);
414 #else
415             IOMGR_Select(((intptr_t)(ufd->handle)) + 1, 0, &out, 0, 0);
416 #endif
417 #endif
418             error =
419                 USD_WRITE(ufd, &buffer[bytesread - bytesleft], bytesleft, &w);
420             if (error) {
421                 fprintf(STDERR, "File system write failed: %s\n",
422                         afs_error_message(error));
423                 ERROR_EXIT(-1);
424             }
425         }
426     }
427
428   error_exit:
429     if (buffer)
430         free(buffer);
431     return (error);
432 }
433
434 afs_int32
435 DumpFunction(struct rx_call *call, void *rock)
436 {
437     char *filename = (char *)rock;
438     usd_handle_t ufd;           /* default is to stdout */
439     afs_int32 error = 0, code;
440     afs_hyper_t size;
441     long blksize;
442     int ufdIsOpen = 0;
443
444     /* Open the output file */
445     if (!filename || !*filename) {
446         usd_StandardOutput(&ufd);
447         blksize = 4096;
448         ufdIsOpen = 1;
449     } else {
450         code =
451             usd_Open(filename, USD_OPEN_CREATE | USD_OPEN_RDWR, 0666, &ufd);
452         if (code == 0) {
453             ufdIsOpen = 1;
454             hzero(size);
455             code = USD_IOCTL(ufd, USD_IOCTL_SETSIZE, &size);
456         }
457         if (code == 0) {
458             code = USD_IOCTL(ufd, USD_IOCTL_GETBLKSIZE, &blksize);
459         }
460         if (code) {
461             fprintf(STDERR, "Could not create file '%s': %s\n", filename,
462                     afs_error_message(code));
463             ERROR_EXIT(VOLSERBADOP);
464         }
465     }
466
467     code = ReceiveFile(ufd, call, blksize);
468     if (code)
469         ERROR_EXIT(code);
470
471   error_exit:
472     /* Close the output file */
473     if (ufdIsOpen) {
474         code = USD_CLOSE(ufd);
475         if (code) {
476             fprintf(STDERR, "Could not close dump file %s\n",
477                     (filename && *filename) ? filename : "STDIN");
478             if (!error)
479                 error = code;
480         }
481     }
482
483     return (error);
484 }
485
486 static void
487 DisplayFormat(volintInfo *pntr, afs_int32 server, afs_int32 part,
488               int *totalOK, int *totalNotOK, int *totalBusy, int fast,
489               int longlist, int disp)
490 {
491     char pname[10];
492     time_t t;
493
494     if (fast) {
495         fprintf(STDOUT, "%-10lu\n", (unsigned long)pntr->volid);
496     } else if (longlist) {
497         if (pntr->status == VOK) {
498             fprintf(STDOUT, "%-32s ", pntr->name);
499             fprintf(STDOUT, "%10lu ", (unsigned long)pntr->volid);
500             if (pntr->type == 0)
501                 fprintf(STDOUT, "RW ");
502             if (pntr->type == 1)
503                 fprintf(STDOUT, "RO ");
504             if (pntr->type == 2)
505                 fprintf(STDOUT, "BK ");
506             fprintf(STDOUT, "%10d K  ", pntr->size);
507             if (pntr->inUse == 1) {
508                 fprintf(STDOUT, "On-line");
509                 *totalOK += 1;
510             } else {
511                 fprintf(STDOUT, "Off-line");
512                 *totalNotOK += 1;
513             }
514             if (pntr->needsSalvaged == 1)
515                 fprintf(STDOUT, "**needs salvage**");
516             fprintf(STDOUT, "\n");
517             MapPartIdIntoName(part, pname);
518             fprintf(STDOUT, "    %s %s \n", hostutil_GetNameByINet(server),
519                     pname);
520             fprintf(STDOUT, "    RWrite %10lu ROnly %10lu Backup %10lu \n",
521                     (unsigned long)pntr->parentID,
522                     (unsigned long)pntr->cloneID,
523                     (unsigned long)pntr->backupID);
524             fprintf(STDOUT, "    MaxQuota %10d K \n", pntr->maxquota);
525             t = pntr->creationDate;
526             fprintf(STDOUT, "    Creation    %s",
527                     ctime(&t));
528             t = pntr->copyDate;
529             fprintf(STDOUT, "    Copy        %s",
530                     ctime(&t));
531
532             t = pntr->backupDate;
533             if (!t)
534                 fprintf(STDOUT, "    Backup      Never\n");
535             else
536                 fprintf(STDOUT, "    Backup      %s",
537                         ctime(&t));
538
539             t = pntr->accessDate;
540             if (t)
541                 fprintf(STDOUT, "    Last Access %s",
542                         ctime(&t));
543
544             t = pntr->updateDate;
545             if (!t)
546                 fprintf(STDOUT, "    Last Update Never\n");
547             else
548                 fprintf(STDOUT, "    Last Update %s",
549                         ctime(&t));
550             fprintf(STDOUT,
551                     "    %d accesses in the past day (i.e., vnode references)\n",
552                     pntr->dayUse);
553         } else if (pntr->status == VBUSY) {
554             *totalBusy += 1;
555             qPut(&busyHead, pntr->volid);
556             if (disp)
557                 fprintf(STDOUT, "**** Volume %lu is busy ****\n",
558                         (unsigned long)pntr->volid);
559         } else {
560             *totalNotOK += 1;
561             qPut(&notokHead, pntr->volid);
562             if (disp)
563                 fprintf(STDOUT, "**** Could not attach volume %lu ****\n",
564                         (unsigned long)pntr->volid);
565         }
566         fprintf(STDOUT, "\n");
567     } else {                    /* default listing */
568         if (pntr->status == VOK) {
569             fprintf(STDOUT, "%-32s ", pntr->name);
570             fprintf(STDOUT, "%10lu ", (unsigned long)pntr->volid);
571             if (pntr->type == 0)
572                 fprintf(STDOUT, "RW ");
573             if (pntr->type == 1)
574                 fprintf(STDOUT, "RO ");
575             if (pntr->type == 2)
576                 fprintf(STDOUT, "BK ");
577             fprintf(STDOUT, "%10d K ", pntr->size);
578             if (pntr->inUse == 1) {
579                 fprintf(STDOUT, "On-line");
580                 *totalOK += 1;
581             } else {
582                 fprintf(STDOUT, "Off-line");
583                 *totalNotOK += 1;
584             }
585             if (pntr->needsSalvaged == 1)
586                 fprintf(STDOUT, "**needs salvage**");
587             fprintf(STDOUT, "\n");
588         } else if (pntr->status == VBUSY) {
589             *totalBusy += 1;
590             qPut(&busyHead, pntr->volid);
591             if (disp)
592                 fprintf(STDOUT, "**** Volume %lu is busy ****\n",
593                         (unsigned long)pntr->volid);
594         } else {
595             *totalNotOK += 1;
596             qPut(&notokHead, pntr->volid);
597             if (disp)
598                 fprintf(STDOUT, "**** Could not attach volume %lu ****\n",
599                         (unsigned long)pntr->volid);
600         }
601     }
602 }
603
604 /*------------------------------------------------------------------------
605  * PRIVATE XDisplayFormat
606  *
607  * Description:
608  *      Display the contents of one extended volume info structure.
609  *
610  * Arguments:
611  *      a_xInfoP        : Ptr to extended volume info struct to print.
612  *      a_servID        : Server ID to print.
613  *      a_partID        : Partition ID to print.
614  *      a_totalOKP      : Ptr to total-OK counter.
615  *      a_totalNotOKP   : Ptr to total-screwed counter.
616  *      a_totalBusyP    : Ptr to total-busy counter.
617  *      a_fast          : Fast listing?
618  *      a_int32         : Int32 listing?
619  *      a_showProblems  : Show volume problems?
620  *
621  * Returns:
622  *      Nothing.
623  *
624  * Environment:
625  *      Nothing interesting.
626  *
627  * Side Effects:
628  *      As advertised.
629  *------------------------------------------------------------------------*/
630
631 static void
632 XDisplayFormat(volintXInfo *a_xInfoP, afs_int32 a_servID, afs_int32 a_partID,
633                int *a_totalOKP, int *a_totalNotOKP, int *a_totalBusyP,
634                int a_fast, int a_int32, int a_showProblems)
635 {                               /*XDisplayFormat */
636     time_t t;
637     char pname[10];
638
639     if (a_fast) {
640         /*
641          * Short & sweet.
642          */
643         fprintf(STDOUT, "%-10lu\n", (unsigned long)a_xInfoP->volid);
644     } else if (a_int32) {
645         /*
646          * Fully-detailed listing.
647          */
648         if (a_xInfoP->status == VOK) {
649             /*
650              * Volume's status is OK - all the fields are valid.
651              */
652             fprintf(STDOUT, "%-32s ", a_xInfoP->name);
653             fprintf(STDOUT, "%10lu ", (unsigned long)a_xInfoP->volid);
654             if (a_xInfoP->type == 0)
655                 fprintf(STDOUT, "RW ");
656             if (a_xInfoP->type == 1)
657                 fprintf(STDOUT, "RO ");
658             if (a_xInfoP->type == 2)
659                 fprintf(STDOUT, "BK ");
660             fprintf(STDOUT, "%10d K used ", a_xInfoP->size);
661             fprintf(STDOUT, "%d files ", a_xInfoP->filecount);
662             if (a_xInfoP->inUse == 1) {
663                 fprintf(STDOUT, "On-line");
664                 (*a_totalOKP)++;
665             } else {
666                 fprintf(STDOUT, "Off-line");
667                 (*a_totalNotOKP)++;
668             }
669             fprintf(STDOUT, "\n");
670             MapPartIdIntoName(a_partID, pname);
671             fprintf(STDOUT, "    %s %s \n", hostutil_GetNameByINet(a_servID),
672                     pname);
673             fprintf(STDOUT, "    RWrite %10lu ROnly %10lu Backup %10lu \n",
674                     (unsigned long)a_xInfoP->parentID,
675                     (unsigned long)a_xInfoP->cloneID,
676                     (unsigned long)a_xInfoP->backupID);
677             fprintf(STDOUT, "    MaxQuota %10d K \n", a_xInfoP->maxquota);
678
679             t = a_xInfoP->creationDate;
680             fprintf(STDOUT, "    Creation    %s",
681                     ctime(&t));
682
683             t = a_xInfoP->copyDate;
684             fprintf(STDOUT, "    Copy        %s",
685                     ctime(&t));
686
687             t = a_xInfoP->backupDate;
688             if (!t)
689                 fprintf(STDOUT, "    Backup      Never\n");
690             else
691                 fprintf(STDOUT, "    Backup      %s",
692                         ctime(&t));
693
694             t = a_xInfoP->accessDate;
695             if (t)
696                 fprintf(STDOUT, "    Last Access %s",
697                         ctime(&t));
698
699             t = a_xInfoP->updateDate;
700             if (!t)
701                 fprintf(STDOUT, "    Last Update Never\n");
702             else
703                 fprintf(STDOUT, "    Last Update %s",
704                         ctime(&t));
705             fprintf(STDOUT,
706                     "    %d accesses in the past day (i.e., vnode references)\n",
707                     a_xInfoP->dayUse);
708
709             /*
710              * Print all the read/write and authorship stats.
711              */
712             fprintf(STDOUT, "\n                      Raw Read/Write Stats\n");
713             fprintf(STDOUT,
714                     "          |-------------------------------------------|\n");
715             fprintf(STDOUT,
716                     "          |    Same Network     |    Diff Network     |\n");
717             fprintf(STDOUT,
718                     "          |----------|----------|----------|----------|\n");
719             fprintf(STDOUT,
720                     "          |  Total   |   Auth   |   Total  |   Auth   |\n");
721             fprintf(STDOUT,
722                     "          |----------|----------|----------|----------|\n");
723             fprintf(STDOUT, "Reads     | %8d | %8d | %8d | %8d |\n",
724                     a_xInfoP->stat_reads[VOLINT_STATS_SAME_NET],
725                     a_xInfoP->stat_reads[VOLINT_STATS_SAME_NET_AUTH],
726                     a_xInfoP->stat_reads[VOLINT_STATS_DIFF_NET],
727                     a_xInfoP->stat_reads[VOLINT_STATS_DIFF_NET_AUTH]);
728             fprintf(STDOUT, "Writes    | %8d | %8d | %8d | %8d |\n",
729                     a_xInfoP->stat_writes[VOLINT_STATS_SAME_NET],
730                     a_xInfoP->stat_writes[VOLINT_STATS_SAME_NET_AUTH],
731                     a_xInfoP->stat_writes[VOLINT_STATS_DIFF_NET],
732                     a_xInfoP->stat_writes[VOLINT_STATS_DIFF_NET_AUTH]);
733             fprintf(STDOUT,
734                     "          |-------------------------------------------|\n\n");
735
736             fprintf(STDOUT,
737                     "                   Writes Affecting Authorship\n");
738             fprintf(STDOUT,
739                     "          |-------------------------------------------|\n");
740             fprintf(STDOUT,
741                     "          |   File Authorship   | Directory Authorship|\n");
742             fprintf(STDOUT,
743                     "          |----------|----------|----------|----------|\n");
744             fprintf(STDOUT,
745                     "          |   Same   |   Diff   |    Same  |   Diff   |\n");
746             fprintf(STDOUT,
747                     "          |----------|----------|----------|----------|\n");
748             fprintf(STDOUT, "0-60 sec  | %8d | %8d | %8d | %8d |\n",
749                     a_xInfoP->stat_fileSameAuthor[VOLINT_STATS_TIME_IDX_0],
750                     a_xInfoP->stat_fileDiffAuthor[VOLINT_STATS_TIME_IDX_0],
751                     a_xInfoP->stat_dirSameAuthor[VOLINT_STATS_TIME_IDX_0],
752                     a_xInfoP->stat_dirDiffAuthor[VOLINT_STATS_TIME_IDX_0]);
753             fprintf(STDOUT, "1-10 min  | %8d | %8d | %8d | %8d |\n",
754                     a_xInfoP->stat_fileSameAuthor[VOLINT_STATS_TIME_IDX_1],
755                     a_xInfoP->stat_fileDiffAuthor[VOLINT_STATS_TIME_IDX_1],
756                     a_xInfoP->stat_dirSameAuthor[VOLINT_STATS_TIME_IDX_1],
757                     a_xInfoP->stat_dirDiffAuthor[VOLINT_STATS_TIME_IDX_1]);
758             fprintf(STDOUT, "10min-1hr | %8d | %8d | %8d | %8d |\n",
759                     a_xInfoP->stat_fileSameAuthor[VOLINT_STATS_TIME_IDX_2],
760                     a_xInfoP->stat_fileDiffAuthor[VOLINT_STATS_TIME_IDX_2],
761                     a_xInfoP->stat_dirSameAuthor[VOLINT_STATS_TIME_IDX_2],
762                     a_xInfoP->stat_dirDiffAuthor[VOLINT_STATS_TIME_IDX_2]);
763             fprintf(STDOUT, "1hr-1day  | %8d | %8d | %8d | %8d |\n",
764                     a_xInfoP->stat_fileSameAuthor[VOLINT_STATS_TIME_IDX_3],
765                     a_xInfoP->stat_fileDiffAuthor[VOLINT_STATS_TIME_IDX_3],
766                     a_xInfoP->stat_dirSameAuthor[VOLINT_STATS_TIME_IDX_3],
767                     a_xInfoP->stat_dirDiffAuthor[VOLINT_STATS_TIME_IDX_3]);
768             fprintf(STDOUT, "1day-1wk  | %8d | %8d | %8d | %8d |\n",
769                     a_xInfoP->stat_fileSameAuthor[VOLINT_STATS_TIME_IDX_4],
770                     a_xInfoP->stat_fileDiffAuthor[VOLINT_STATS_TIME_IDX_4],
771                     a_xInfoP->stat_dirSameAuthor[VOLINT_STATS_TIME_IDX_4],
772                     a_xInfoP->stat_dirDiffAuthor[VOLINT_STATS_TIME_IDX_4]);
773             fprintf(STDOUT, "> 1wk     | %8d | %8d | %8d | %8d |\n",
774                     a_xInfoP->stat_fileSameAuthor[VOLINT_STATS_TIME_IDX_5],
775                     a_xInfoP->stat_fileDiffAuthor[VOLINT_STATS_TIME_IDX_5],
776                     a_xInfoP->stat_dirSameAuthor[VOLINT_STATS_TIME_IDX_5],
777                     a_xInfoP->stat_dirDiffAuthor[VOLINT_STATS_TIME_IDX_5]);
778             fprintf(STDOUT,
779                     "          |-------------------------------------------|\n");
780         } /*Volume status OK */
781         else if (a_xInfoP->status == VBUSY) {
782             (*a_totalBusyP)++;
783             qPut(&busyHead, a_xInfoP->volid);
784             if (a_showProblems)
785                 fprintf(STDOUT, "**** Volume %lu is busy ****\n",
786                         (unsigned long)a_xInfoP->volid);
787         } /*Busy volume */
788         else {
789             (*a_totalNotOKP)++;
790             qPut(&notokHead, a_xInfoP->volid);
791             if (a_showProblems)
792                 fprintf(STDOUT, "**** Could not attach volume %lu ****\n",
793                         (unsigned long)a_xInfoP->volid);
794         }                       /*Screwed volume */
795         fprintf(STDOUT, "\n");
796     } /*Long listing */
797     else {
798         /*
799          * Default listing.
800          */
801         if (a_xInfoP->status == VOK) {
802             fprintf(STDOUT, "%-32s ", a_xInfoP->name);
803             fprintf(STDOUT, "%10lu ", (unsigned long)a_xInfoP->volid);
804             if (a_xInfoP->type == 0)
805                 fprintf(STDOUT, "RW ");
806             if (a_xInfoP->type == 1)
807                 fprintf(STDOUT, "RO ");
808             if (a_xInfoP->type == 2)
809                 fprintf(STDOUT, "BK ");
810             fprintf(STDOUT, "%10d K ", a_xInfoP->size);
811             if (a_xInfoP->inUse == 1) {
812                 fprintf(STDOUT, "On-line");
813                 (*a_totalOKP)++;
814             } else {
815                 fprintf(STDOUT, "Off-line");
816                 (*a_totalNotOKP)++;
817             }
818             fprintf(STDOUT, "\n");
819         } /*Volume OK */
820         else if (a_xInfoP->status == VBUSY) {
821             (*a_totalBusyP)++;
822             qPut(&busyHead, a_xInfoP->volid);
823             if (a_showProblems)
824                 fprintf(STDOUT, "**** Volume %lu is busy ****\n",
825                         (unsigned long)a_xInfoP->volid);
826         } /*Busy volume */
827         else {
828             (*a_totalNotOKP)++;
829             qPut(&notokHead, a_xInfoP->volid);
830             if (a_showProblems)
831                 fprintf(STDOUT, "**** Could not attach volume %lu ****\n",
832                         (unsigned long)a_xInfoP->volid);
833         }                       /*Screwed volume */
834     }                           /*Default listing */
835 }                               /*XDisplayFormat */
836
837 /*------------------------------------------------------------------------
838  * PRIVATE XDisplayFormat2
839  *
840  * Description:
841  *      Display the formated contents of one extended volume info structure.
842  *
843  * Arguments:
844  *      a_xInfoP        : Ptr to extended volume info struct to print.
845  *      a_servID        : Server ID to print.
846  *      a_partID        : Partition ID to print.
847  *      a_totalOKP      : Ptr to total-OK counter.
848  *      a_totalNotOKP   : Ptr to total-screwed counter.
849  *      a_totalBusyP    : Ptr to total-busy counter.
850  *      a_fast          : Fast listing?
851  *      a_int32         : Int32 listing?
852  *      a_showProblems  : Show volume problems?
853  *
854  * Returns:
855  *      Nothing.
856  *
857  * Environment:
858  *      Nothing interesting.
859  *
860  * Side Effects:
861  *      As advertised.
862  *------------------------------------------------------------------------*/
863
864 static void
865 XDisplayFormat2(volintXInfo *a_xInfoP, afs_int32 a_servID, afs_int32 a_partID,
866                 int *a_totalOKP, int *a_totalNotOKP, int *a_totalBusyP,
867                 int a_fast, int a_int32, int a_showProblems)
868 {                               /*XDisplayFormat */
869     time_t t;
870     if (a_fast) {
871         /*
872          * Short & sweet.
873          */
874         fprintf(STDOUT, "vold_id\t%-10lu\n", (unsigned long)a_xInfoP->volid);
875     } else if (a_int32) {
876         /*
877          * Fully-detailed listing.
878          */
879         if (a_xInfoP->status == VOK) {
880             /*
881              * Volume's status is OK - all the fields are valid.
882              */
883
884                 static long server_cache = -1, partition_cache = -1;
885                 static char hostname[256], address[32], pname[16];
886                 int i,ai[] = {VOLINT_STATS_TIME_IDX_0,VOLINT_STATS_TIME_IDX_1,VOLINT_STATS_TIME_IDX_2,
887                               VOLINT_STATS_TIME_IDX_3,VOLINT_STATS_TIME_IDX_4,VOLINT_STATS_TIME_IDX_5};
888
889                 if (a_servID != server_cache) {
890                         struct in_addr s;
891
892                         s.s_addr = a_servID;
893                         strcpy(hostname, hostutil_GetNameByINet(a_servID));
894                         strcpy(address, inet_ntoa(s));
895                         server_cache = a_servID;
896                 }
897                 if (a_partID != partition_cache) {
898                         MapPartIdIntoName(a_partID, pname);
899                         partition_cache = a_partID;
900                 }
901
902                 fprintf(STDOUT, "name\t\t%s\n", a_xInfoP->name);
903                 fprintf(STDOUT, "id\t\t%lu\n", afs_printable_uint32_lu(a_xInfoP->volid));
904                 fprintf(STDOUT, "serv\t\t%s\t%s\n", address, hostname);
905                 fprintf(STDOUT, "part\t\t%s\n", pname);
906                 fprintf(STDOUT, "status\t\tOK\n");
907                 fprintf(STDOUT, "backupID\t%lu\n", 
908                         afs_printable_uint32_lu(a_xInfoP->backupID));
909                 fprintf(STDOUT, "parentID\t%lu\n", 
910                         afs_printable_uint32_lu(a_xInfoP->parentID));
911                 fprintf(STDOUT, "cloneID\t\t%lu\n", 
912                         afs_printable_uint32_lu(a_xInfoP->cloneID));
913                 fprintf(STDOUT, "inUse\t\t%s\n", a_xInfoP->inUse ? "Y" : "N");
914                 switch (a_xInfoP->type) {
915                 case 0:
916                         fprintf(STDOUT, "type\t\tRW\n");
917                         break;
918                 case 1:
919                         fprintf(STDOUT, "type\t\tRO\n");
920                         break;
921                 case 2:
922                         fprintf(STDOUT, "type\t\tBK\n");
923                         break;
924                 default:
925                         fprintf(STDOUT, "type\t\t?\n");
926                         break;
927                 }
928                 t = a_xInfoP->creationDate;
929                 fprintf(STDOUT, "creationDate\t%-9lu\t%s", 
930                         afs_printable_uint32_lu(a_xInfoP->creationDate),
931                         ctime(&t));
932
933                 t = a_xInfoP->accessDate;
934                 fprintf(STDOUT, "accessDate\t%-9lu\t%s", 
935                         afs_printable_uint32_lu(a_xInfoP->accessDate),
936                         ctime(&t));
937
938                 t = a_xInfoP->updateDate;
939                 fprintf(STDOUT, "updateDate\t%-9lu\t%s", 
940                         afs_printable_uint32_lu(a_xInfoP->updateDate),
941                         ctime(&t));
942
943                 t = a_xInfoP->backupDate;
944                 fprintf(STDOUT, "backupDate\t%-9lu\t%s", 
945                         afs_printable_uint32_lu(a_xInfoP->backupDate),
946                         ctime(&t));
947
948                 t = a_xInfoP->copyDate;
949                 fprintf(STDOUT, "copyDate\t%-9lu\t%s", 
950                         afs_printable_uint32_lu(a_xInfoP->copyDate),
951                         ctime(&t));
952                 
953                 fprintf(STDOUT, "diskused\t%u\n", a_xInfoP->size);
954                 fprintf(STDOUT, "maxquota\t%u\n", a_xInfoP->maxquota);
955
956                 fprintf(STDOUT, "filecount\t%u\n", a_xInfoP->filecount);
957                 fprintf(STDOUT, "dayUse\t\t%u\n", a_xInfoP->dayUse);
958
959
960
961                 fprintf(STDOUT,"reads_same_net\t%8d\n",a_xInfoP->stat_reads[VOLINT_STATS_SAME_NET]);
962                 fprintf(STDOUT,"reads_same_net_auth\t%8d\n",a_xInfoP->stat_reads[VOLINT_STATS_SAME_NET_AUTH]);
963                 fprintf(STDOUT,"reads_diff_net\t%8d\n",a_xInfoP->stat_reads[VOLINT_STATS_DIFF_NET]);
964                 fprintf(STDOUT,"reads_diff_net_auth\t%8d\n",a_xInfoP->stat_reads[VOLINT_STATS_DIFF_NET_AUTH]);
965
966                 fprintf(STDOUT,"writes_same_net\t%8d\n",a_xInfoP->stat_writes[VOLINT_STATS_SAME_NET]);
967                 fprintf(STDOUT,"writes_same_net_auth\t%8d\n",a_xInfoP->stat_writes[VOLINT_STATS_SAME_NET_AUTH]);
968                 fprintf(STDOUT,"writes_diff_net\t%8d\n",a_xInfoP->stat_writes[VOLINT_STATS_DIFF_NET]);
969                 fprintf(STDOUT,"writes_diff_net_auth\t%8d\n",a_xInfoP->stat_writes[VOLINT_STATS_DIFF_NET_AUTH]);
970
971                 for(i=0;i<5;i++)
972                 {
973                         fprintf(STDOUT,"file_same_author_idx_%d\t%8d\n",i+1,a_xInfoP->stat_fileSameAuthor[ai[i]]);
974                         fprintf(STDOUT,"file_diff_author_idx_%d\t%8d\n",i+1,a_xInfoP->stat_fileDiffAuthor[ai[i]]);
975                         fprintf(STDOUT,"dir_same_author_idx_%d\t%8d\n",i+1,a_xInfoP->stat_dirSameAuthor[ai[i]]);
976                         fprintf(STDOUT,"dir_dif_author_idx_%d\t%8d\n",i+1,a_xInfoP->stat_dirDiffAuthor[ai[i]]);
977                 }
978
979         } /*Volume status OK */
980         else if (a_xInfoP->status == VBUSY) {
981             (*a_totalBusyP)++;
982             qPut(&busyHead, a_xInfoP->volid);
983             if (a_showProblems)
984                 fprintf(STDOUT, "BUSY_VOL\t%lu\n",
985                         (unsigned long)a_xInfoP->volid);
986         } /*Busy volume */
987         else {
988             (*a_totalNotOKP)++;
989             qPut(&notokHead, a_xInfoP->volid);
990             if (a_showProblems)
991                 fprintf(STDOUT, "COULD_NOT_ATTACH\t%lu\n",
992                         (unsigned long)a_xInfoP->volid);
993         }                       /*Screwed volume */
994     } /*Long listing */
995     else {
996         /*
997          * Default listing.
998          */
999         if (a_xInfoP->status == VOK) {
1000             fprintf(STDOUT, "name\t%-32s\n", a_xInfoP->name);
1001             fprintf(STDOUT, "volID\t%10lu\n", (unsigned long)a_xInfoP->volid);
1002             if (a_xInfoP->type == 0)
1003                 fprintf(STDOUT, "type\tRW\n");
1004             if (a_xInfoP->type == 1)
1005                 fprintf(STDOUT, "type\tRO\n");
1006             if (a_xInfoP->type == 2)
1007                 fprintf(STDOUT, "type\tBK\n");
1008             fprintf(STDOUT, "size\t%10dK\n", a_xInfoP->size);
1009
1010             fprintf(STDOUT, "inUse\t%d\n",a_xInfoP->inUse);
1011             if (a_xInfoP->inUse == 1)
1012                 (*a_totalOKP)++;
1013             else
1014                 (*a_totalNotOKP)++;
1015
1016         } /*Volume OK */
1017         else if (a_xInfoP->status == VBUSY) {
1018             (*a_totalBusyP)++;
1019             qPut(&busyHead, a_xInfoP->volid);
1020             if (a_showProblems)
1021                 fprintf(STDOUT, "VOLUME_BUSY\t%lu\n",
1022                         (unsigned long)a_xInfoP->volid);
1023         } /*Busy volume */
1024         else {
1025             (*a_totalNotOKP)++;
1026             qPut(&notokHead, a_xInfoP->volid);
1027             if (a_showProblems)
1028                 fprintf(STDOUT, "COULD_NOT_ATTACH_VOLUME\t%lu\n",
1029                         (unsigned long)a_xInfoP->volid);
1030         }                       /*Screwed volume */
1031     }                           /*Default listing */
1032 }                               /*XDisplayFormat */
1033
1034 static void
1035 DisplayFormat2(long server, long partition, volintInfo *pntr)
1036 {
1037     static long server_cache = -1, partition_cache = -1;
1038     static char hostname[256], address[32], pname[16];
1039     time_t t;
1040
1041     if (server != server_cache) {
1042         struct in_addr s;
1043
1044         s.s_addr = server;
1045         strcpy(hostname, hostutil_GetNameByINet(server));
1046         strcpy(address, inet_ntoa(s));
1047         server_cache = server;
1048     }
1049     if (partition != partition_cache) {
1050         MapPartIdIntoName(partition, pname);
1051         partition_cache = partition;
1052     }
1053
1054     if (pntr->status == VOK)
1055         fprintf(STDOUT, "name\t\t%s\n", pntr->name);
1056
1057     fprintf(STDOUT, "id\t\t%lu\n", 
1058             afs_printable_uint32_lu(pntr->volid));
1059     fprintf(STDOUT, "serv\t\t%s\t%s\n", address, hostname);
1060     fprintf(STDOUT, "part\t\t%s\n", pname);
1061     switch (pntr->status) {
1062     case VOK:
1063         fprintf(STDOUT, "status\t\tOK\n");
1064         break;
1065     case VBUSY:
1066         fprintf(STDOUT, "status\t\tBUSY\n");
1067         return;
1068     default:
1069         fprintf(STDOUT, "status\t\tUNATTACHABLE\n");
1070         return;
1071     }
1072     fprintf(STDOUT, "backupID\t%lu\n", 
1073             afs_printable_uint32_lu(pntr->backupID));
1074     fprintf(STDOUT, "parentID\t%lu\n", 
1075             afs_printable_uint32_lu(pntr->parentID));
1076     fprintf(STDOUT, "cloneID\t\t%lu\n", 
1077             afs_printable_uint32_lu(pntr->cloneID));
1078     fprintf(STDOUT, "inUse\t\t%s\n", pntr->inUse ? "Y" : "N");
1079     fprintf(STDOUT, "needsSalvaged\t%s\n", pntr->needsSalvaged ? "Y" : "N");
1080     /* 0xD3 is from afs/volume.h since I had trouble including the file */
1081     fprintf(STDOUT, "destroyMe\t%s\n", pntr->destroyMe == 0xD3 ? "Y" : "N");
1082     switch (pntr->type) {
1083     case 0:
1084         fprintf(STDOUT, "type\t\tRW\n");
1085         break;
1086     case 1:
1087         fprintf(STDOUT, "type\t\tRO\n");
1088         break;
1089     case 2:
1090         fprintf(STDOUT, "type\t\tBK\n");
1091         break;
1092     default:
1093         fprintf(STDOUT, "type\t\t?\n");
1094         break;
1095     }
1096     t = pntr->creationDate;
1097     fprintf(STDOUT, "creationDate\t%-9lu\t%s", 
1098             afs_printable_uint32_lu(pntr->creationDate),
1099             ctime(&t));
1100
1101     t = pntr->accessDate;
1102     fprintf(STDOUT, "accessDate\t%-9lu\t%s", 
1103             afs_printable_uint32_lu(pntr->accessDate),
1104             ctime(&t));
1105
1106     t = pntr->updateDate;
1107     fprintf(STDOUT, "updateDate\t%-9lu\t%s", 
1108             afs_printable_uint32_lu(pntr->updateDate),
1109             ctime(&t));
1110
1111     t = pntr->backupDate;
1112     fprintf(STDOUT, "backupDate\t%-9lu\t%s", 
1113             afs_printable_uint32_lu(pntr->backupDate),
1114             ctime(&t));
1115
1116     t = pntr->copyDate;
1117     fprintf(STDOUT, "copyDate\t%-9lu\t%s", 
1118             afs_printable_uint32_lu(pntr->copyDate),
1119             ctime(&t));
1120
1121     fprintf(STDOUT, "flags\t\t%#lx\t(Optional)\n", 
1122             afs_printable_uint32_lu(pntr->flags));
1123     fprintf(STDOUT, "diskused\t%u\n", pntr->size);
1124     fprintf(STDOUT, "maxquota\t%u\n", pntr->maxquota);
1125     fprintf(STDOUT, "minquota\t%lu\t(Optional)\n", 
1126             afs_printable_uint32_lu(pntr->spare0));
1127     fprintf(STDOUT, "filecount\t%u\n", pntr->filecount);
1128     fprintf(STDOUT, "dayUse\t\t%u\n", pntr->dayUse);
1129     fprintf(STDOUT, "weekUse\t\t%lu\t(Optional)\n",
1130             afs_printable_uint32_lu(pntr->spare1));
1131     fprintf(STDOUT, "spare2\t\t%lu\t(Optional)\n", 
1132             afs_printable_uint32_lu(pntr->spare2));
1133     fprintf(STDOUT, "spare3\t\t%lu\t(Optional)\n", 
1134             afs_printable_uint32_lu(pntr->spare3));
1135     return;
1136 }
1137
1138 static void
1139 DisplayVolumes2(long server, long partition, volintInfo *pntr, long count)
1140 {
1141     long i;
1142
1143     for (i = 0; i < count; i++) {
1144         fprintf(STDOUT, "BEGIN_OF_ENTRY\n");
1145         DisplayFormat2(server, partition, pntr);
1146         fprintf(STDOUT, "END_OF_ENTRY\n\n");
1147         pntr++;
1148     }
1149     return;
1150 }
1151
1152 static void
1153 DisplayVolumes(afs_int32 server, afs_int32 part, volintInfo *pntr,
1154                afs_int32 count, afs_int32 longlist, afs_int32 fast,
1155                int quiet)
1156 {
1157     int totalOK, totalNotOK, totalBusy, i;
1158     afs_uint32 volid = 0;
1159
1160     totalOK = 0;
1161     totalNotOK = 0;
1162     totalBusy = 0;
1163     qInit(&busyHead);
1164     qInit(&notokHead);
1165     for (i = 0; i < count; i++) {
1166         DisplayFormat(pntr, server, part, &totalOK, &totalNotOK, &totalBusy,
1167                       fast, longlist, 0);
1168         pntr++;
1169     }
1170     if (totalBusy) {
1171         while (busyHead.count) {
1172             qGet(&busyHead, &volid);
1173             fprintf(STDOUT, "**** Volume %lu is busy ****\n",
1174                     (unsigned long)volid);
1175         }
1176     }
1177     if (totalNotOK) {
1178         while (notokHead.count) {
1179             qGet(&notokHead, &volid);
1180             fprintf(STDOUT, "**** Could not attach volume %lu ****\n",
1181                     (unsigned long)volid);
1182         }
1183     }
1184     if (!quiet) {
1185         fprintf(STDOUT, "\n");
1186         if (!fast) {
1187             fprintf(STDOUT,
1188                     "Total volumes onLine %d ; Total volumes offLine %d ; Total busy %d\n\n",
1189                     totalOK, totalNotOK, totalBusy);
1190         }
1191     }
1192 }
1193 /*------------------------------------------------------------------------
1194  * PRIVATE XDisplayVolumes
1195  *
1196  * Description:
1197  *      Display extended volume information.
1198  *
1199  * Arguments:
1200  *      a_servID : Pointer to the Rx call we're performing.
1201  *      a_partID : Partition for which we want the extended list.
1202  *      a_xInfoP : Ptr to extended volume info.
1203  *      a_count  : Number of volume records contained above.
1204  *      a_int32   : Int32 listing generated?
1205  *      a_fast   : Fast listing generated?
1206  *      a_quiet  : Quiet listing generated?
1207  *
1208  * Returns:
1209  *      Nothing.
1210  *
1211  * Environment:
1212  *      Nothing interesting.
1213  *
1214  * Side Effects:
1215  *      As advertised.
1216  *------------------------------------------------------------------------*/
1217
1218 static void
1219 XDisplayVolumes(afs_int32 a_servID, afs_int32 a_partID, volintXInfo *a_xInfoP,
1220                 afs_int32 a_count, afs_int32 a_int32, afs_int32 a_fast,
1221                 int a_quiet)
1222 {                               /*XDisplayVolumes */
1223
1224     int totalOK;                /*Total OK volumes */
1225     int totalNotOK;             /*Total screwed volumes */
1226     int totalBusy;              /*Total busy volumes */
1227     int i;                      /*Loop variable */
1228     afs_uint32 volid = 0;       /*Current volume ID */
1229
1230     /*
1231      * Initialize counters and (global!!) queues.
1232      */
1233     totalOK = 0;
1234     totalNotOK = 0;
1235     totalBusy = 0;
1236     qInit(&busyHead);
1237     qInit(&notokHead);
1238
1239     /*
1240      * Display each volume in the list.
1241      */
1242     for (i = 0; i < a_count; i++) {
1243         XDisplayFormat(a_xInfoP, a_servID, a_partID, &totalOK, &totalNotOK,
1244                        &totalBusy, a_fast, a_int32, 0);
1245         a_xInfoP++;
1246     }
1247
1248     /*
1249      * If any volumes were found to be busy or screwed, display them.
1250      */
1251     if (totalBusy) {
1252         while (busyHead.count) {
1253             qGet(&busyHead, &volid);
1254             fprintf(STDOUT, "**** Volume %lu is busy ****\n",
1255                     (unsigned long)volid);
1256         }
1257     }
1258     if (totalNotOK) {
1259         while (notokHead.count) {
1260             qGet(&notokHead, &volid);
1261             fprintf(STDOUT, "**** Could not attach volume %lu ****\n",
1262                     (unsigned long)volid);
1263         }
1264     }
1265
1266     if (!a_quiet) {
1267         fprintf(STDOUT, "\n");
1268         if (!a_fast) {
1269             fprintf(STDOUT,
1270                     "Total volumes: %d on-line, %d off-line, %d  busyd\n\n",
1271                     totalOK, totalNotOK, totalBusy);
1272         }
1273     }
1274
1275 }                               /*XDisplayVolumes */
1276
1277 /*------------------------------------------------------------------------
1278  * PRIVATE XDisplayVolumes2
1279  *
1280  * Description:
1281  *      Display extended formated volume information.
1282  *
1283  * Arguments:
1284  *      a_servID : Pointer to the Rx call we're performing.
1285  *      a_partID : Partition for which we want the extended list.
1286  *      a_xInfoP : Ptr to extended volume info.
1287  *      a_count  : Number of volume records contained above.
1288  *      a_int32   : Int32 listing generated?
1289  *      a_fast   : Fast listing generated?
1290  *      a_quiet  : Quiet listing generated?
1291  *
1292  * Returns:
1293  *      Nothing.
1294  *
1295  * Environment:
1296  *      Nothing interesting.
1297  *
1298  * Side Effects:
1299  *      As advertised.
1300  *------------------------------------------------------------------------*/
1301
1302 static void
1303 XDisplayVolumes2(afs_int32 a_servID, afs_int32 a_partID, volintXInfo *a_xInfoP,
1304                  afs_int32 a_count, afs_int32 a_int32, afs_int32 a_fast,
1305                  int a_quiet)
1306 {                               /*XDisplayVolumes */
1307
1308     int totalOK;                /*Total OK volumes */
1309     int totalNotOK;             /*Total screwed volumes */
1310     int totalBusy;              /*Total busy volumes */
1311     int i;                      /*Loop variable */
1312     afs_uint32 volid = 0;       /*Current volume ID */
1313
1314     /*
1315      * Initialize counters and (global!!) queues.
1316      */
1317     totalOK = 0;
1318     totalNotOK = 0;
1319     totalBusy = 0;
1320     qInit(&busyHead);
1321     qInit(&notokHead);
1322
1323     /*
1324      * Display each volume in the list.
1325      */
1326     for (i = 0; i < a_count; i++) {
1327         fprintf(STDOUT, "BEGIN_OF_ENTRY\n");
1328         XDisplayFormat2(a_xInfoP, a_servID, a_partID, &totalOK, &totalNotOK,
1329                        &totalBusy, a_fast, a_int32, 0);
1330         fprintf(STDOUT, "END_OF_ENTRY\n");
1331         a_xInfoP++;
1332     }
1333
1334     /*
1335      * If any volumes were found to be busy or screwed, display them.
1336      */
1337     if (totalBusy) {
1338         while (busyHead.count) {
1339             qGet(&busyHead, &volid);
1340             fprintf(STDOUT, "BUSY_VOL\t%lu\n",
1341                     (unsigned long)volid);
1342         }
1343     }
1344     if (totalNotOK) {
1345         while (notokHead.count) {
1346             qGet(&notokHead, &volid);
1347             fprintf(STDOUT, "COULD_NOT_ATTACH\t%lu\n",
1348                     (unsigned long)volid);
1349         }
1350     }
1351
1352     if (!a_quiet) {
1353         fprintf(STDOUT, "\n");
1354         if (!a_fast) {
1355             fprintf(STDOUT,
1356                     "VOLUMES_ONLINE\t%d\nVOLUMES_OFFLINE\t%d\nVOLUMES_BUSY\t%d\n",
1357                     totalOK, totalNotOK, totalBusy);
1358         }
1359     }
1360
1361 }                               /*XDisplayVolumes2 */
1362
1363
1364 /* set <server> and <part> to the correct values depending on 
1365  * <voltype> and <entry> */
1366 static void
1367 GetServerAndPart(struct nvldbentry *entry, int voltype, afs_int32 *server,
1368                  afs_int32 *part, int *previdx)
1369 {
1370     int i, istart, vtype;
1371
1372     *server = -1;
1373     *part = -1;
1374
1375     /* Doesn't check for non-existance of backup volume */
1376     if ((voltype == RWVOL) || (voltype == BACKVOL)) {
1377         vtype = ITSRWVOL;
1378         istart = 0;             /* seach the entire entry */
1379     } else {
1380         vtype = ITSROVOL;
1381         /* Seach from beginning of entry or pick up where we left off */
1382         istart = ((*previdx < 0) ? 0 : *previdx + 1);
1383     }
1384
1385     for (i = istart; i < entry->nServers; i++) {
1386         if (entry->serverFlags[i] & vtype) {
1387             *server = entry->serverNumber[i];
1388             *part = entry->serverPartition[i];
1389             *previdx = i;
1390             return;
1391         }
1392     }
1393
1394     /* Didn't find any, return -1 */
1395     *previdx = -1;
1396     return;
1397 }
1398
1399 static void
1400 PostVolumeStats(struct nvldbentry *entry)
1401 {
1402     SubEnumerateEntry(entry);
1403     /* Check for VLOP_ALLOPERS */
1404     if (entry->flags & VLOP_ALLOPERS)
1405         fprintf(STDOUT, "    Volume is currently LOCKED  \n");
1406     return;
1407 }
1408
1409 /*------------------------------------------------------------------------
1410  * PRIVATE XVolumeStats
1411  *
1412  * Description:
1413  *      Display extended volume information.
1414  *
1415  * Arguments:
1416  *      a_xInfoP  : Ptr to extended volume info.
1417  *      a_entryP  : Ptr to the volume's VLDB entry.
1418  *      a_srvID   : Server ID.
1419  *      a_partID  : Partition ID.
1420  *      a_volType : Type of volume to print.
1421  *
1422  * Returns:
1423  *      Nothing.
1424  *
1425  * Environment:
1426  *      Nothing interesting.
1427  *
1428  * Side Effects:
1429  *      As advertised.
1430  *------------------------------------------------------------------------*/
1431
1432 static void
1433 XVolumeStats(volintXInfo *a_xInfoP, struct nvldbentry *a_entryP,
1434              afs_int32 a_srvID, afs_int32 a_partID, int a_volType)
1435 {                               /*XVolumeStats */
1436
1437     int totalOK, totalNotOK, totalBusy; /*Dummies - we don't really count here */
1438
1439     XDisplayFormat(a_xInfoP,    /*Ptr to extended volume info */
1440                    a_srvID,     /*Server ID to print */
1441                    a_partID,    /*Partition ID to print */
1442                    &totalOK,    /*Ptr to total-OK counter */
1443                    &totalNotOK, /*Ptr to total-screwed counter */
1444                    &totalBusy,  /*Ptr to total-busy counter */
1445                    0,           /*Don't do a fast listing */
1446                    1,           /*Do a long listing */
1447                    1);          /*Show volume problems */
1448     return;
1449
1450 }                               /*XVolumeStats */
1451
1452 static void
1453 VolumeStats_int(volintInfo *pntr, struct nvldbentry *entry, afs_int32 server, 
1454              afs_int32 part, int voltype)
1455 {
1456     int totalOK, totalNotOK, totalBusy;
1457
1458     DisplayFormat(pntr, server, part, &totalOK, &totalNotOK, &totalBusy, 0, 1,
1459                   1);
1460     return;
1461 }
1462
1463 /* command to forcibly remove a volume */
1464 static int
1465 NukeVolume(register struct cmd_syndesc *as)
1466 {
1467     register afs_int32 code;
1468     afs_uint32 volID;
1469     afs_int32  err;
1470     afs_int32 partID;
1471     afs_int32 server;
1472     register char *tp;
1473
1474     server = GetServer(tp = as->parms[0].items->data);
1475     if (!server) {
1476         fprintf(STDERR, "vos: server '%s' not found in host table\n", tp);
1477         return 1;
1478     }
1479
1480     partID = volutil_GetPartitionID(tp = as->parms[1].items->data);
1481     if (partID == -1) {
1482         fprintf(STDERR, "vos: could not parse '%s' as a partition name", tp);
1483         return 1;
1484     }
1485
1486     volID = vsu_GetVolumeID(tp = as->parms[2].items->data, cstruct, &err);
1487     if (volID == 0) {
1488         if (err)
1489             PrintError("", err);
1490         else
1491             fprintf(STDERR,
1492                     "vos: could not parse '%s' as a numeric volume ID", tp);
1493         return 1;
1494     }
1495
1496     fprintf(STDOUT,
1497             "vos: forcibly removing all traces of volume %d, please wait...",
1498             volID);
1499     fflush(STDOUT);
1500     code = UV_NukeVolume(server, partID, volID);
1501     if (code == 0)
1502         fprintf(STDOUT, "done.\n");
1503     else
1504         fprintf(STDOUT, "failed with code %d.\n", code);
1505     return code;
1506 }
1507
1508
1509 /*------------------------------------------------------------------------
1510  * PRIVATE ExamineVolume
1511  *
1512  * Description:
1513  *      Routine used to examine a single volume, contacting the VLDB as
1514  *      well as the Volume Server.
1515  *
1516  * Arguments:
1517  *      as : Ptr to parsed command line arguments.
1518  *
1519  * Returns:
1520  *      0 for a successful operation,
1521  *      Otherwise, one of the ubik or VolServer error values.
1522  *
1523  * Environment:
1524  *      Nothing interesting.
1525  *
1526  * Side Effects:
1527  *      As advertised.
1528  *------------------------------------------------------------------------
1529  */
1530 static int
1531 ExamineVolume(register struct cmd_syndesc *as, void *arock)
1532 {
1533     struct nvldbentry entry;
1534     afs_int32 vcode = 0;
1535     volintInfo *pntr = (volintInfo *) 0;
1536     volintXInfo *xInfoP = (volintXInfo *) 0;
1537     afs_uint32 volid;
1538     afs_int32 code, err, error = 0;
1539     int voltype, foundserv = 0, foundentry = 0;
1540     afs_int32 aserver, apart;
1541     int previdx = -1;
1542     int wantExtendedInfo;       /*Do we want extended vol info? */
1543
1544     wantExtendedInfo = (as->parms[1].items ? 1 : 0);    /* -extended */
1545
1546     volid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);   /* -id */
1547     if (volid == 0) {
1548         if (err)
1549             PrintError("", err);
1550         else
1551             fprintf(STDERR, "Unknown volume ID or name '%s'\n",
1552                     as->parms[0].items->data);
1553         return -1;
1554     }
1555
1556     if (verbose) {
1557         fprintf(STDOUT, "Fetching VLDB entry for %lu .. ",
1558                 (unsigned long)volid);
1559         fflush(STDOUT);
1560     }
1561     vcode = VLDB_GetEntryByID(volid, -1, &entry);
1562     if (vcode) {
1563         fprintf(STDERR,
1564                 "Could not fetch the entry for volume number %lu from VLDB \n",
1565                 (unsigned long)volid);
1566         return (vcode);
1567     }
1568     if (verbose)
1569         fprintf(STDOUT, "done\n");
1570     MapHostToNetwork(&entry);
1571
1572     if (entry.volumeId[RWVOL] == volid)
1573         voltype = RWVOL;
1574     else if (entry.volumeId[BACKVOL] == volid)
1575         voltype = BACKVOL;
1576     else                        /* (entry.volumeId[ROVOL] == volid) */
1577         voltype = ROVOL;
1578
1579     do {                        /* do {...} while (voltype == ROVOL) */
1580         /* Get the entry for the volume. If its a RW vol, get the RW entry.
1581          * It its a BK vol, get the RW entry (even if VLDB may say the BK doen't exist).
1582          * If its a RO vol, get the next RO entry.
1583          */
1584         GetServerAndPart(&entry, ((voltype == ROVOL) ? ROVOL : RWVOL),
1585                          &aserver, &apart, &previdx);
1586         if (previdx == -1) {    /* searched all entries */
1587             if (!foundentry) {
1588                 fprintf(STDERR, "Volume %s does not exist in VLDB\n\n",
1589                         as->parms[0].items->data);
1590                 error = ENOENT;
1591             }
1592             break;
1593         }
1594         foundentry = 1;
1595
1596         /* Get information about the volume from the server */
1597         if (verbose) {
1598             fprintf(STDOUT, "Getting volume listing from the server %s .. ",
1599                     hostutil_GetNameByINet(aserver));
1600             fflush(STDOUT);
1601         }
1602         if (wantExtendedInfo)
1603             code = UV_XListOneVolume(aserver, apart, volid, &xInfoP);
1604         else
1605             code = UV_ListOneVolume(aserver, apart, volid, &pntr);
1606         if (verbose)
1607             fprintf(STDOUT, "done\n");
1608
1609         if (code) {
1610             error = code;
1611             if (code == ENODEV) {
1612                 if ((voltype == BACKVOL) && !(entry.flags & BACK_EXISTS)) {
1613                     /* The VLDB says there is no backup volume and its not on disk */
1614                     fprintf(STDERR, "Volume %s does not exist\n",
1615                             as->parms[0].items->data);
1616                     error = ENOENT;
1617                 } else {
1618                     fprintf(STDERR,
1619                             "Volume does not exist on server %s as indicated by the VLDB\n",
1620                             hostutil_GetNameByINet(aserver));
1621                 }
1622             } else {
1623                 PrintDiagnostics("examine", code);
1624             }
1625             fprintf(STDOUT, "\n");
1626         } else {
1627             foundserv = 1;
1628             if (wantExtendedInfo)
1629                 XVolumeStats(xInfoP, &entry, aserver, apart, voltype);
1630             else if (as->parms[2].items) {
1631                 DisplayFormat2(aserver, apart, pntr);
1632                 EnumerateEntry(&entry);
1633             } else
1634                 VolumeStats_int(pntr, &entry, aserver, apart, voltype);
1635
1636             if ((voltype == BACKVOL) && !(entry.flags & BACK_EXISTS)) {
1637                 /* The VLDB says there is no backup volume yet we found one on disk */
1638                 fprintf(STDERR, "Volume %s does not exist in VLDB\n",
1639                         as->parms[0].items->data);
1640                 error = ENOENT;
1641             }
1642         }
1643
1644         if (pntr)
1645             free(pntr);
1646         if (xInfoP)
1647             free(xInfoP);
1648     } while (voltype == ROVOL);
1649
1650     if (!foundserv) {
1651         fprintf(STDERR, "Dump only information from VLDB\n\n");
1652         fprintf(STDOUT, "%s \n", entry.name);   /* PostVolumeStats doesn't print name */
1653     }
1654     PostVolumeStats(&entry);
1655
1656     return (error);
1657 }
1658
1659 /*------------------------------------------------------------------------
1660  * PRIVATE SetFields
1661  *
1662  * Description:
1663  *      Routine used to change the status of a single volume.
1664  *
1665  * Arguments:
1666  *      as : Ptr to parsed command line arguments.
1667  *
1668  * Returns:
1669  *      0 for a successful operation,
1670  *      Otherwise, one of the ubik or VolServer error values.
1671  *
1672  * Environment:
1673  *      Nothing interesting.
1674  *
1675  * Side Effects:
1676  *      As advertised.
1677  *------------------------------------------------------------------------
1678  */
1679 static int
1680 SetFields(register struct cmd_syndesc *as, void *arock)
1681 {
1682     struct nvldbentry entry;
1683     volintInfo info;
1684     afs_uint32 volid;
1685     afs_int32 code, err;
1686     afs_int32 aserver, apart;
1687     int previdx = -1;
1688
1689     volid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);   /* -id */
1690     if (volid == 0) {
1691         if (err)
1692             PrintError("", err);
1693         else
1694             fprintf(STDERR, "Unknown volume ID or name '%s'\n",
1695                     as->parms[0].items->data);
1696         return -1;
1697     }
1698
1699     code = VLDB_GetEntryByID(volid, RWVOL, &entry);
1700     if (code) {
1701         fprintf(STDERR,
1702                 "Could not fetch the entry for volume number %lu from VLDB \n",
1703                 (unsigned long)volid);
1704         return (code);
1705     }
1706     MapHostToNetwork(&entry);
1707
1708     GetServerAndPart(&entry, RWVOL, &aserver, &apart, &previdx);
1709     if (previdx == -1) {
1710         fprintf(STDERR, "Volume %s does not exist in VLDB\n\n",
1711                 as->parms[0].items->data);
1712         return (ENOENT);
1713     }
1714
1715     init_volintInfo(&info);
1716     info.volid = volid;
1717     info.type = RWVOL;
1718
1719     if (as->parms[1].items) {
1720         /* -max <quota> */
1721         code = util_GetHumanInt32(as->parms[1].items->data, &info.maxquota);
1722         if (code) {
1723             fprintf(STDERR, "invalid quota value\n");
1724             return code;
1725         }
1726     }
1727     if (as->parms[2].items) {
1728         /* -clearuse */
1729         info.dayUse = 0;
1730     }
1731     if (as->parms[3].items) {
1732         /* -clearVolUpCounter */
1733         info.spare2 = 0;
1734     }
1735     code = UV_SetVolumeInfo(aserver, apart, volid, &info);
1736     if (code)
1737         fprintf(STDERR,
1738                 "Could not update volume info fields for volume number %lu\n",
1739                 (unsigned long)volid);
1740     return (code);
1741 }
1742
1743 /*------------------------------------------------------------------------
1744  * PRIVATE volOnline
1745  *
1746  * Description:
1747  *      Brings a volume online.
1748  *
1749  * Arguments:
1750  *      as : Ptr to parsed command line arguments.
1751  *
1752  * Returns:
1753  *      0 for a successful operation,
1754  *
1755  * Environment:
1756  *      Nothing interesting.
1757  *
1758  * Side Effects:
1759  *      As advertised.
1760  *------------------------------------------------------------------------
1761  */
1762 static int
1763 volOnline(register struct cmd_syndesc *as, void *arock)
1764 {
1765     afs_int32 server, partition;
1766     afs_uint32 volid;
1767     afs_int32 code, err = 0;
1768
1769     server = GetServer(as->parms[0].items->data);
1770     if (server == 0) {
1771         fprintf(STDERR, "vos: server '%s' not found in host table\n",
1772                 as->parms[0].items->data);
1773         return -1;
1774     }
1775
1776     partition = volutil_GetPartitionID(as->parms[1].items->data);
1777     if (partition < 0) {
1778         fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
1779                 as->parms[1].items->data);
1780         return ENOENT;
1781     }
1782
1783     volid = vsu_GetVolumeID(as->parms[2].items->data, cstruct, &err);   /* -id */
1784     if (!volid) {
1785         if (err)
1786             PrintError("", err);
1787         else
1788             fprintf(STDERR, "Unknown volume ID or name '%s'\n",
1789                     as->parms[0].items->data);
1790         return -1;
1791     }
1792
1793     code = UV_SetVolume(server, partition, volid, ITOffline, 0 /*online */ ,
1794                         0 /*sleep */ );
1795     if (code) {
1796         fprintf(STDERR, "Failed to set volume. Code = %d\n", code);
1797         return -1;
1798     }
1799
1800     return 0;
1801 }
1802
1803 /*------------------------------------------------------------------------
1804  * PRIVATE volOffline
1805  *
1806  * Description:
1807  *      Brings a volume offline.
1808  *
1809  * Arguments:
1810  *      as : Ptr to parsed command line arguments.
1811  *
1812  * Returns:
1813  *      0 for a successful operation,
1814  *
1815  * Environment:
1816  *      Nothing interesting.
1817  *
1818  * Side Effects:
1819  *      As advertised.
1820  *------------------------------------------------------------------------
1821  */
1822 static int
1823 volOffline(register struct cmd_syndesc *as, void *arock)
1824 {
1825     afs_int32 server, partition;
1826     afs_uint32 volid;
1827     afs_int32 code, err = 0;
1828     afs_int32 transflag, sleeptime, transdone;
1829
1830     server = GetServer(as->parms[0].items->data);
1831     if (server == 0) {
1832         fprintf(STDERR, "vos: server '%s' not found in host table\n",
1833                 as->parms[0].items->data);
1834         return -1;
1835     }
1836
1837     partition = volutil_GetPartitionID(as->parms[1].items->data);
1838     if (partition < 0) {
1839         fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
1840                 as->parms[1].items->data);
1841         return ENOENT;
1842     }
1843
1844     volid = vsu_GetVolumeID(as->parms[2].items->data, cstruct, &err);   /* -id */
1845     if (!volid) {
1846         if (err)
1847             PrintError("", err);
1848         else
1849             fprintf(STDERR, "Unknown volume ID or name '%s'\n",
1850                     as->parms[0].items->data);
1851         return -1;
1852     }
1853
1854     transflag = (as->parms[4].items ? ITBusy : ITOffline);
1855     sleeptime = (as->parms[3].items ? atol(as->parms[3].items->data) : 0);
1856     transdone = (sleeptime ? 0 /*online */ : VTOutOfService);
1857     if (as->parms[4].items && !as->parms[3].items) {
1858         fprintf(STDERR, "-sleep option must be used with -busy flag\n");
1859         return -1;
1860     }
1861
1862     code =
1863         UV_SetVolume(server, partition, volid, transflag, transdone,
1864                      sleeptime);
1865     if (code) {
1866         fprintf(STDERR, "Failed to set volume. Code = %d\n", code);
1867         return -1;
1868     }
1869
1870     return 0;
1871 }
1872
1873 static int
1874 CreateVolume(register struct cmd_syndesc *as, void *arock)
1875 {
1876     afs_int32 pnum;
1877     char part[10];
1878     afs_uint32 volid = 0, rovolid = 0, bkvolid = 0;
1879     afs_uint32 *arovolid;
1880     afs_int32 code;
1881     struct nvldbentry entry;
1882     afs_int32 vcode;
1883     afs_int32 quota;
1884
1885     arovolid = &rovolid;
1886
1887     quota = 5000;
1888     tserver = GetServer(as->parms[0].items->data);
1889     if (!tserver) {
1890         fprintf(STDERR, "vos: host '%s' not found in host table\n",
1891                 as->parms[0].items->data);
1892         return ENOENT;
1893     }
1894     pnum = volutil_GetPartitionID(as->parms[1].items->data);
1895     if (pnum < 0) {
1896         fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
1897                 as->parms[1].items->data);
1898         return ENOENT;
1899     }
1900     if (!IsPartValid(pnum, tserver, &code)) {   /*check for validity of the partition */
1901         if (code)
1902             PrintError("", code);
1903         else
1904             fprintf(STDERR,
1905                     "vos : partition %s does not exist on the server\n",
1906                     as->parms[1].items->data);
1907         return ENOENT;
1908     }
1909     if (!ISNAMEVALID(as->parms[2].items->data)) {
1910         fprintf(STDERR,
1911                 "vos: the name of the root volume %s exceeds the size limit of %d\n",
1912                 as->parms[2].items->data, VOLSER_OLDMAXVOLNAME - 10);
1913         return E2BIG;
1914     }
1915     if (!VolNameOK(as->parms[2].items->data)) {
1916         fprintf(STDERR,
1917                 "Illegal volume name %s, should not end in .readonly or .backup\n",
1918                 as->parms[2].items->data);
1919         return EINVAL;
1920     }
1921     if (IsNumeric(as->parms[2].items->data)) {
1922         fprintf(STDERR, "Illegal volume name %s, should not be a number\n",
1923                 as->parms[2].items->data);
1924         return EINVAL;
1925     }
1926     vcode = VLDB_GetEntryByName(as->parms[2].items->data, &entry);
1927     if (!vcode) {
1928         fprintf(STDERR, "Volume %s already exists\n",
1929                 as->parms[2].items->data);
1930         PrintDiagnostics("create", code);
1931         return EEXIST;
1932     }
1933
1934     if (as->parms[3].items) {
1935         code = util_GetHumanInt32(as->parms[3].items->data, &quota);
1936         if (code) {
1937             fprintf(STDERR, "vos: bad integer specified for quota.\n");
1938             return code;
1939         }
1940     }
1941
1942     if (as->parms[4].items) {
1943         if (!IsNumeric(as->parms[4].items->data)) {
1944             fprintf(STDERR, "vos: Given volume ID %s should be numeric.\n",
1945                     as->parms[4].items->data);
1946             return EINVAL;
1947         }
1948
1949         code = util_GetUInt32(as->parms[4].items->data, &volid);
1950         if (code) {
1951             fprintf(STDERR, "vos: bad integer specified for volume ID.\n");
1952             return code;
1953         }
1954     }
1955
1956     if (as->parms[5].items) {
1957         if (!IsNumeric(as->parms[5].items->data)) {
1958             fprintf(STDERR, "vos: Given RO volume ID %s should be numeric.\n",
1959                     as->parms[5].items->data);
1960             return EINVAL;
1961         }
1962
1963         code = util_GetUInt32(as->parms[5].items->data, &rovolid);
1964         if (code) {
1965             fprintf(STDERR, "vos: bad integer specified for volume ID.\n");
1966             return code;
1967         }
1968
1969         if (rovolid == 0) {
1970             arovolid = NULL;
1971         }
1972     }
1973
1974     code =
1975         UV_CreateVolume3(tserver, pnum, as->parms[2].items->data, quota, 0,
1976                          0, 0, 0, &volid, arovolid, &bkvolid);
1977     if (code) {
1978         PrintDiagnostics("create", code);
1979         return code;
1980     }
1981     MapPartIdIntoName(pnum, part);
1982     fprintf(STDOUT, "Volume %lu created on partition %s of %s\n",
1983             (unsigned long)volid, part, as->parms[0].items->data);
1984
1985     return 0;
1986 }
1987
1988 #if 0
1989 static afs_int32
1990 DeleteAll(struct nvldbentry *entry)
1991 {
1992     int i;
1993     afs_int32 error, code, curserver, curpart;
1994     afs_uint32 volid;
1995
1996     MapHostToNetwork(entry);
1997     error = 0;
1998     for (i = 0; i < entry->nServers; i++) {
1999         curserver = entry->serverNumber[i];
2000         curpart = entry->serverPartition[i];
2001         if (entry->serverFlags[i] & ITSROVOL) {
2002             volid = entry->volumeId[ROVOL];
2003         } else {
2004             volid = entry->volumeId[RWVOL];
2005         }
2006         code = UV_DeleteVolume(curserver, curpart, volid);
2007         if (code && !error)
2008             error = code;
2009     }
2010     return error;
2011 }
2012 #endif
2013
2014 static int
2015 DeleteVolume(struct cmd_syndesc *as, void *arock)
2016 {
2017     afs_int32 err, code = 0;
2018     afs_int32 server = 0, partition = -1;
2019     afs_uint32 volid;
2020     char pname[10];
2021     afs_int32 idx, j;
2022
2023     if (as->parms[0].items) {
2024         server = GetServer(as->parms[0].items->data);
2025         if (!server) {
2026             fprintf(STDERR, "vos: server '%s' not found in host table\n",
2027                     as->parms[0].items->data);
2028             return ENOENT;
2029         }
2030     }
2031
2032     if (as->parms[1].items) {
2033         partition = volutil_GetPartitionID(as->parms[1].items->data);
2034         if (partition < 0) {
2035             fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
2036                     as->parms[1].items->data);
2037             return EINVAL;
2038         }
2039
2040         /* Check for validity of the partition */
2041         if (!IsPartValid(partition, server, &code)) {
2042             if (code) {
2043                 PrintError("", code);
2044             } else {
2045                 fprintf(STDERR,
2046                         "vos : partition %s does not exist on the server\n",
2047                         as->parms[1].items->data);
2048             }
2049             return ENOENT;
2050         }
2051     }
2052
2053     volid = vsu_GetVolumeID(as->parms[2].items->data, cstruct, &err);
2054     if (volid == 0) {
2055         fprintf(STDERR, "Can't find volume name '%s' in VLDB\n",
2056                 as->parms[2].items->data);
2057         if (err)
2058             PrintError("", err);
2059         return ENOENT;
2060     }
2061
2062     /* If the server or partition option are not complete, try to fill
2063      * them in from the VLDB entry.
2064      */
2065     if ((partition == -1) || !server) {
2066         struct nvldbentry entry;
2067
2068         code = VLDB_GetEntryByID(volid, -1, &entry);
2069         if (code) {
2070             fprintf(STDERR,
2071                     "Could not fetch the entry for volume %lu from VLDB\n",
2072                     (unsigned long)volid);
2073             PrintError("", code);
2074             return (code);
2075         }
2076
2077         if (((volid == entry.volumeId[RWVOL]) && (entry.flags & RW_EXISTS))
2078             || ((volid == entry.volumeId[BACKVOL])
2079                 && (entry.flags & BACK_EXISTS))) {
2080             idx = Lp_GetRwIndex(&entry);
2081             if ((idx == -1) || (server && (server != entry.serverNumber[idx]))
2082                 || ((partition != -1)
2083                     && (partition != entry.serverPartition[idx]))) {
2084                 fprintf(STDERR, "VLDB: Volume '%s' no match\n",
2085                         as->parms[2].items->data);
2086                 return ENOENT;
2087             }
2088         } else if ((volid == entry.volumeId[ROVOL])
2089                    && (entry.flags & RO_EXISTS)) {
2090             for (idx = -1, j = 0; j < entry.nServers; j++) {
2091                 if (entry.serverFlags[j] != ITSROVOL)
2092                     continue;
2093
2094                 if (((server == 0) || (server == entry.serverNumber[j]))
2095                     && ((partition == -1)
2096                         || (partition == entry.serverPartition[j]))) {
2097                     if (idx != -1) {
2098                         fprintf(STDERR,
2099                                 "VLDB: Volume '%s' matches more than one RO\n",
2100                                 as->parms[2].items->data);
2101                         return ENOENT;
2102                     }
2103                     idx = j;
2104                 }
2105             }
2106             if (idx == -1) {
2107                 fprintf(STDERR, "VLDB: Volume '%s' no match\n",
2108                         as->parms[2].items->data);
2109                 return ENOENT;
2110             }
2111         } else {
2112             fprintf(STDERR, "VLDB: Volume '%s' no match\n",
2113                     as->parms[2].items->data);
2114             return ENOENT;
2115         }
2116
2117         server = htonl(entry.serverNumber[idx]);
2118         partition = entry.serverPartition[idx];
2119     }
2120
2121
2122     code = UV_DeleteVolume(server, partition, volid);
2123     if (code) {
2124         PrintDiagnostics("remove", code);
2125         return code;
2126     }
2127
2128     MapPartIdIntoName(partition, pname);
2129     fprintf(STDOUT, "Volume %lu on partition %s server %s deleted\n",
2130             (unsigned long)volid, pname, hostutil_GetNameByINet(server));
2131     return 0;
2132 }
2133
2134 #define TESTM   0               /* set for move space tests, clear for production */
2135 static int
2136 MoveVolume(register struct cmd_syndesc *as, void *arock)
2137 {
2138
2139     afs_uint32 volid;
2140     afs_int32 fromserver, toserver, frompart, topart;
2141     afs_int32 flags, code, err;
2142     char fromPartName[10], toPartName[10];
2143
2144     struct diskPartition64 partition;   /* for space check */
2145     volintInfo *p;
2146
2147     volid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);
2148     if (volid == 0) {
2149         if (err)
2150             PrintError("", err);
2151         else
2152             fprintf(STDERR, "vos: can't find volume ID or name '%s'\n",
2153                     as->parms[0].items->data);
2154         return ENOENT;
2155     }
2156     fromserver = GetServer(as->parms[1].items->data);
2157     if (fromserver == 0) {
2158         fprintf(STDERR, "vos: server '%s' not found in host table\n",
2159                 as->parms[1].items->data);
2160         return ENOENT;
2161     }
2162     toserver = GetServer(as->parms[3].items->data);
2163     if (toserver == 0) {
2164         fprintf(STDERR, "vos: server '%s' not found in host table\n",
2165                 as->parms[3].items->data);
2166         return ENOENT;
2167     }
2168     frompart = volutil_GetPartitionID(as->parms[2].items->data);
2169     if (frompart < 0) {
2170         fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
2171                 as->parms[2].items->data);
2172         return EINVAL;
2173     }
2174     if (!IsPartValid(frompart, fromserver, &code)) {    /*check for validity of the partition */
2175         if (code)
2176             PrintError("", code);
2177         else
2178             fprintf(STDERR,
2179                     "vos : partition %s does not exist on the server\n",
2180                     as->parms[2].items->data);
2181         return ENOENT;
2182     }
2183     topart = volutil_GetPartitionID(as->parms[4].items->data);
2184     if (topart < 0) {
2185         fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
2186                 as->parms[4].items->data);
2187         return EINVAL;
2188     }
2189     if (!IsPartValid(topart, toserver, &code)) {        /*check for validity of the partition */
2190         if (code)
2191             PrintError("", code);
2192         else
2193             fprintf(STDERR,
2194                     "vos : partition %s does not exist on the server\n",
2195                     as->parms[4].items->data);
2196         return ENOENT;
2197     }
2198
2199     flags = 0;
2200     if (as->parms[5].items) flags |= RV_NOCLONE;
2201
2202     /*
2203      * check source partition for space to clone volume
2204      */
2205
2206     MapPartIdIntoName(topart, toPartName);
2207     MapPartIdIntoName(frompart, fromPartName);
2208
2209     /*
2210      * check target partition for space to move volume
2211      */
2212
2213     code = UV_PartitionInfo64(toserver, toPartName, &partition);
2214     if (code) {
2215         fprintf(STDERR, "vos: cannot access partition %s\n", toPartName);
2216         exit(1);
2217     }
2218     if (TESTM)
2219         fprintf(STDOUT, "target partition %s free space %" AFS_INT64_FMT "\n", toPartName,
2220                 partition.free);
2221
2222     p = (volintInfo *) 0;
2223     code = UV_ListOneVolume(fromserver, frompart, volid, &p);
2224     if (code) {
2225         fprintf(STDERR, "vos:cannot access volume %lu\n",
2226                 (unsigned long)volid);
2227         exit(1);
2228     }
2229     if (TESTM)
2230         fprintf(STDOUT, "volume %lu size %d\n", (unsigned long)volid,
2231                 p->size);
2232     if (partition.free <= p->size) {
2233         fprintf(STDERR,
2234                 "vos: no space on target partition %s to move volume %lu\n",
2235                 toPartName, (unsigned long)volid);
2236         free(p);
2237         exit(1);
2238     }
2239     free(p);
2240
2241     if (TESTM) {
2242         fprintf(STDOUT, "size test - don't do move\n");
2243         exit(0);
2244     }
2245
2246     /* successful move still not guaranteed but shoot for it */
2247
2248     code =
2249         UV_MoveVolume2(volid, fromserver, frompart, toserver, topart, flags);
2250     if (code) {
2251         PrintDiagnostics("move", code);
2252         return code;
2253     }
2254     MapPartIdIntoName(topart, toPartName);
2255     MapPartIdIntoName(frompart, fromPartName);
2256     fprintf(STDOUT, "Volume %lu moved from %s %s to %s %s \n",
2257             (unsigned long)volid, as->parms[1].items->data, fromPartName,
2258             as->parms[3].items->data, toPartName);
2259
2260     return 0;
2261 }
2262
2263 static int
2264 CopyVolume(register struct cmd_syndesc *as, void *arock)
2265 {
2266     afs_uint32 volid;
2267     afs_int32 fromserver, toserver, frompart, topart, code, err, flags;
2268     char fromPartName[10], toPartName[10], *tovolume;
2269     struct nvldbentry entry;
2270     struct diskPartition64 partition;   /* for space check */
2271     volintInfo *p;
2272
2273     volid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);
2274     if (volid == 0) {
2275         if (err)
2276             PrintError("", err);
2277         else
2278             fprintf(STDERR, "vos: can't find volume ID or name '%s'\n",
2279                     as->parms[0].items->data);
2280         return ENOENT;
2281     }
2282     fromserver = GetServer(as->parms[1].items->data);
2283     if (fromserver == 0) {
2284         fprintf(STDERR, "vos: server '%s' not found in host table\n",
2285                 as->parms[1].items->data);
2286         return ENOENT;
2287     }
2288
2289     toserver = GetServer(as->parms[4].items->data);
2290     if (toserver == 0) {
2291         fprintf(STDERR, "vos: server '%s' not found in host table\n",
2292                 as->parms[4].items->data);
2293         return ENOENT;
2294     }
2295
2296     tovolume = as->parms[3].items->data;
2297     if (!ISNAMEVALID(tovolume)) {
2298         fprintf(STDERR,
2299                 "vos: the name of the root volume %s exceeds the size limit of %d\n",
2300                 tovolume, VOLSER_OLDMAXVOLNAME - 10);
2301         return E2BIG;
2302     }
2303     if (!VolNameOK(tovolume)) {
2304         fprintf(STDERR,
2305                 "Illegal volume name %s, should not end in .readonly or .backup\n",
2306                 tovolume);
2307         return EINVAL;
2308     }
2309     if (IsNumeric(tovolume)) {
2310         fprintf(STDERR, "Illegal volume name %s, should not be a number\n",
2311                 tovolume);
2312         return EINVAL;
2313     }
2314     code = VLDB_GetEntryByName(tovolume, &entry);
2315     if (!code) {
2316         fprintf(STDERR, "Volume %s already exists\n", tovolume);
2317         PrintDiagnostics("copy", code);
2318         return EEXIST;
2319     }
2320
2321     frompart = volutil_GetPartitionID(as->parms[2].items->data);
2322     if (frompart < 0) {
2323         fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
2324                 as->parms[2].items->data);
2325         return EINVAL;
2326     }
2327     if (!IsPartValid(frompart, fromserver, &code)) {    /*check for validity of the partition */
2328         if (code)
2329             PrintError("", code);
2330         else
2331             fprintf(STDERR,
2332                     "vos : partition %s does not exist on the server\n",
2333                     as->parms[2].items->data);
2334         return ENOENT;
2335     }
2336
2337     topart = volutil_GetPartitionID(as->parms[5].items->data);
2338     if (topart < 0) {
2339         fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
2340                 as->parms[5].items->data);
2341         return EINVAL;
2342     }
2343     if (!IsPartValid(topart, toserver, &code)) {        /*check for validity of the partition */
2344         if (code)
2345             PrintError("", code);
2346         else
2347             fprintf(STDERR,
2348                     "vos : partition %s does not exist on the server\n",
2349                     as->parms[5].items->data);
2350         return ENOENT;
2351     }
2352
2353     flags = 0;
2354     if (as->parms[6].items) flags |= RV_OFFLINE;
2355     if (as->parms[7].items) flags |= RV_RDONLY;
2356     if (as->parms[8].items) flags |= RV_NOCLONE;
2357
2358     MapPartIdIntoName(topart, toPartName);
2359     MapPartIdIntoName(frompart, fromPartName);
2360
2361     /*
2362      * check target partition for space to move volume
2363      */
2364
2365     code = UV_PartitionInfo64(toserver, toPartName, &partition);
2366     if (code) {
2367         fprintf(STDERR, "vos: cannot access partition %s\n", toPartName);
2368         exit(1);
2369     }
2370     if (TESTM)
2371         fprintf(STDOUT, "target partition %s free space %" AFS_INT64_FMT "\n", toPartName,
2372                 partition.free);
2373
2374     p = (volintInfo *) 0;
2375     code = UV_ListOneVolume(fromserver, frompart, volid, &p);
2376     if (code) {
2377         fprintf(STDERR, "vos:cannot access volume %lu\n",
2378                 (unsigned long)volid);
2379         exit(1);
2380     }
2381
2382     if (partition.free <= p->size) {
2383         fprintf(STDERR,
2384                 "vos: no space on target partition %s to copy volume %lu\n",
2385                 toPartName, (unsigned long)volid);
2386         free(p);
2387         exit(1);
2388     }
2389     free(p);
2390
2391     /* successful copy still not guaranteed but shoot for it */
2392
2393     code =
2394         UV_CopyVolume2(volid, fromserver, frompart, tovolume, toserver,
2395                        topart, 0, flags);
2396     if (code) {
2397         PrintDiagnostics("copy", code);
2398         return code;
2399     }
2400     MapPartIdIntoName(topart, toPartName);
2401     MapPartIdIntoName(frompart, fromPartName);
2402     fprintf(STDOUT, "Volume %lu copied from %s %s to %s on %s %s \n",
2403             (unsigned long)volid, as->parms[1].items->data, fromPartName,
2404             tovolume, as->parms[4].items->data, toPartName);
2405
2406     return 0;
2407 }
2408
2409
2410 static int
2411 ShadowVolume(register struct cmd_syndesc *as, void *arock)
2412 {
2413     afs_uint32 volid, tovolid;
2414     afs_int32 fromserver, toserver, frompart, topart;
2415     afs_int32 code, err, flags;
2416     char fromPartName[10], toPartName[10], toVolName[32], *tovolume;
2417     struct diskPartition64 partition;   /* for space check */
2418     volintInfo *p, *q;
2419
2420     p = (volintInfo *) 0;
2421     q = (volintInfo *) 0;
2422
2423     volid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);
2424     if (volid == 0) {
2425         if (err)
2426             PrintError("", err);
2427         else
2428             fprintf(STDERR, "vos: can't find volume ID or name '%s'\n",
2429                     as->parms[0].items->data);
2430         return ENOENT;
2431     }
2432     fromserver = GetServer(as->parms[1].items->data);
2433     if (fromserver == 0) {
2434         fprintf(STDERR, "vos: server '%s' not found in host table\n",
2435                 as->parms[1].items->data);
2436         return ENOENT;
2437     }
2438
2439     toserver = GetServer(as->parms[3].items->data);
2440     if (toserver == 0) {
2441         fprintf(STDERR, "vos: server '%s' not found in host table\n",
2442                 as->parms[3].items->data);
2443         return ENOENT;
2444     }
2445
2446     frompart = volutil_GetPartitionID(as->parms[2].items->data);
2447     if (frompart < 0) {
2448         fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
2449                 as->parms[2].items->data);
2450         return EINVAL;
2451     }
2452     if (!IsPartValid(frompart, fromserver, &code)) {    /*check for validity of the partition */
2453         if (code)
2454             PrintError("", code);
2455         else
2456             fprintf(STDERR,
2457                     "vos : partition %s does not exist on the server\n",
2458                     as->parms[2].items->data);
2459         return ENOENT;
2460     }
2461
2462     topart = volutil_GetPartitionID(as->parms[4].items->data);
2463     if (topart < 0) {
2464         fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
2465                 as->parms[4].items->data);
2466         return EINVAL;
2467     }
2468     if (!IsPartValid(topart, toserver, &code)) {        /*check for validity of the partition */
2469         if (code)
2470             PrintError("", code);
2471         else
2472             fprintf(STDERR,
2473                     "vos : partition %s does not exist on the server\n",
2474                     as->parms[4].items->data);
2475         return ENOENT;
2476     }
2477
2478     if (as->parms[5].items) {
2479         tovolume = as->parms[5].items->data;
2480         if (!ISNAMEVALID(tovolume)) {
2481             fprintf(STDERR,
2482                 "vos: the name of the root volume %s exceeds the size limit of %d\n",
2483                 tovolume, VOLSER_OLDMAXVOLNAME - 10);
2484             return E2BIG;
2485         }
2486         if (!VolNameOK(tovolume)) {
2487             fprintf(STDERR,
2488                 "Illegal volume name %s, should not end in .readonly or .backup\n",
2489                 tovolume);
2490             return EINVAL;
2491         }
2492         if (IsNumeric(tovolume)) {
2493             fprintf(STDERR,
2494                 "Illegal volume name %s, should not be a number\n",
2495                 tovolume);
2496             return EINVAL;
2497         }
2498     } else {
2499         /* use actual name of source volume */
2500         code = UV_ListOneVolume(fromserver, frompart, volid, &p);
2501         if (code) {
2502             fprintf(STDERR, "vos:cannot access volume %lu\n",
2503                 (unsigned long)volid);
2504             exit(1);
2505         }
2506         strcpy(toVolName, p->name);
2507         tovolume = toVolName;
2508         /* save p for size checks later */
2509     }
2510
2511     if (as->parms[6].items) {
2512         tovolid = vsu_GetVolumeID(as->parms[6].items->data, cstruct, &err);
2513         if (tovolid == 0) {
2514             if (err)
2515                 PrintError("", err);
2516             else
2517                 fprintf(STDERR, "vos: can't find volume ID or name '%s'\n",
2518                         as->parms[6].items->data);
2519             if (p)
2520                 free(p);
2521             return ENOENT;
2522         }
2523     } else {
2524         tovolid = vsu_GetVolumeID(tovolume, cstruct, &err);
2525         if (tovolid == 0) {
2526             if (err)
2527                 PrintError("", err);
2528             else
2529                 fprintf(STDERR, "vos: can't find volume ID or name '%s'\n",
2530                         tovolume);
2531             if (p)
2532                 free(p);
2533             return ENOENT;
2534         }
2535     }
2536
2537     flags = RV_NOVLDB;
2538     if (as->parms[7].items) flags |= RV_OFFLINE;
2539     if (as->parms[8].items) flags |= RV_RDONLY;
2540     if (as->parms[9].items) flags |= RV_NOCLONE;
2541     if (as->parms[10].items) flags |= RV_CPINCR;
2542
2543     MapPartIdIntoName(topart, toPartName);
2544     MapPartIdIntoName(frompart, fromPartName);
2545
2546     /*
2547      * check target partition for space to move volume
2548      */
2549
2550     code = UV_PartitionInfo64(toserver, toPartName, &partition);
2551     if (code) {
2552         fprintf(STDERR, "vos: cannot access partition %s\n", toPartName);
2553         exit(1);
2554     }
2555     if (TESTM)
2556         fprintf(STDOUT, "target partition %s free space %" AFS_INT64_FMT "\n", toPartName,
2557                 partition.free);
2558
2559     /* Don't do this again if we did it above */
2560     if (!p) {
2561         code = UV_ListOneVolume(fromserver, frompart, volid, &p);
2562         if (code) {
2563             fprintf(STDERR, "vos:cannot access volume %lu\n",
2564                 (unsigned long)volid);
2565             exit(1);
2566         }
2567     }
2568
2569     /* OK if this fails */
2570     code = UV_ListOneVolume(toserver, topart, tovolid, &q);
2571
2572     /* Treat existing volume size as "free" */
2573     if (q)
2574         p->size = (q->size < p->size) ? p->size - q->size : 0;
2575
2576     if (partition.free <= p->size) {
2577         fprintf(STDERR,
2578                 "vos: no space on target partition %s to copy volume %lu\n",
2579                 toPartName, (unsigned long)volid);
2580         free(p);
2581         if (q) free(q);
2582         exit(1);
2583     }
2584     free(p);
2585     if (q) free(q);
2586
2587     /* successful copy still not guaranteed but shoot for it */
2588
2589     code =
2590         UV_CopyVolume2(volid, fromserver, frompart, tovolume, toserver,
2591                        topart, tovolid, flags);
2592     if (code) {
2593         PrintDiagnostics("shadow", code);
2594         return code;
2595     }
2596     MapPartIdIntoName(topart, toPartName);
2597     MapPartIdIntoName(frompart, fromPartName);
2598     fprintf(STDOUT, "Volume %lu shadowed from %s %s to %s %s \n",
2599             (unsigned long)volid, as->parms[1].items->data, fromPartName,
2600             as->parms[3].items->data, toPartName);
2601
2602     return 0;
2603 }
2604
2605
2606 static int
2607 CloneVolume(register struct cmd_syndesc *as, void *arock)
2608 {
2609     afs_uint32 volid, cloneid;
2610     afs_int32 server, part, voltype;
2611     char partName[10], *volname;
2612     afs_int32 code, err, flags;
2613     struct nvldbentry entry;
2614
2615     volid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);
2616     if (volid == 0) {
2617         if (err)
2618             PrintError("", err);
2619         else
2620             fprintf(STDERR, "vos: can't find volume ID or name '%s'\n",
2621                     as->parms[0].items->data);
2622         return ENOENT;
2623     }
2624
2625     if (as->parms[1].items || as->parms[2].items) {
2626         if (!as->parms[1].items || !as->parms[2].items) {
2627             fprintf(STDERR,
2628                     "Must specify both -server and -partition options\n");
2629             return -1;
2630         }
2631         server = GetServer(as->parms[1].items->data);
2632         if (server == 0) {
2633             fprintf(STDERR, "vos: server '%s' not found in host table\n",
2634                     as->parms[1].items->data);
2635             return ENOENT;
2636         }
2637         part = volutil_GetPartitionID(as->parms[2].items->data);
2638         if (part < 0) {
2639             fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
2640                     as->parms[2].items->data);
2641             return EINVAL;
2642         }
2643         if (!IsPartValid(part, server, &code)) {        /*check for validity of the partition */
2644             if (code)
2645                 PrintError("", code);
2646             else
2647                 fprintf(STDERR,
2648                     "vos : partition %s does not exist on the server\n",
2649                     as->parms[2].items->data);
2650             return ENOENT;
2651         }
2652     } else {
2653         code = GetVolumeInfo(volid, &server, &part, &voltype, &entry);
2654         if (code)
2655             return code;
2656     }
2657
2658     volname = 0;
2659     if (as->parms[3].items) {
2660         volname = as->parms[3].items->data;
2661         if (strlen(volname) > VOLSER_OLDMAXVOLNAME - 1) {
2662             fprintf(STDERR,
2663                 "vos: the name of the root volume %s exceeds the size limit of %d\n",
2664                 volname, VOLSER_OLDMAXVOLNAME - 1);
2665             return E2BIG;
2666         }
2667 #if 0
2668         /* 
2669          * In order that you be able to make clones of RO or BK, this
2670          * check must be omitted.
2671          */
2672         if (!VolNameOK(volname)) {
2673             fprintf(STDERR,
2674                 "Illegal volume name %s, should not end in .readonly or .backup\n",
2675                 volname);
2676             return EINVAL;
2677         }
2678 #endif
2679         if (IsNumeric(volname)) {
2680             fprintf(STDERR,
2681                 "Illegal volume name %s, should not be a number\n",
2682                 volname);
2683             return EINVAL;
2684         }
2685     }
2686
2687     cloneid = 0;
2688     if (as->parms[4].items) {
2689         cloneid = vsu_GetVolumeID(as->parms[4].items->data, cstruct, &err);
2690         if (cloneid == 0) {
2691             if (err)
2692                 PrintError("", err);
2693             else
2694                 fprintf(STDERR, "vos: can't find volume ID or name '%s'\n",
2695                         as->parms[4].items->data);
2696             return ENOENT;
2697         }
2698     }
2699
2700     flags = 0;
2701     if (as->parms[5].items) flags |= RV_OFFLINE;
2702     if (as->parms[6].items) flags |= RV_RDONLY;
2703
2704
2705     code = 
2706         UV_CloneVolume(server, part, volid, cloneid, volname, flags);
2707
2708     if (code) {
2709         PrintDiagnostics("clone", code);
2710         return code;
2711     }
2712     MapPartIdIntoName(part, partName);
2713     fprintf(STDOUT, "Created clone for volume %s\n",
2714             as->parms[0].items->data);
2715
2716     return 0;
2717 }
2718
2719
2720 static int
2721 BackupVolume(register struct cmd_syndesc *as, void *arock)
2722 {
2723     afs_uint32 avolid;
2724     afs_int32 aserver, apart, vtype, code, err;
2725     struct nvldbentry entry;
2726
2727     afs_uint32 buvolid;
2728     afs_int32 buserver, bupart, butype;
2729     struct nvldbentry buentry;
2730
2731     avolid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);
2732     if (avolid == 0) {
2733         if (err)
2734             PrintError("", err);
2735         else
2736             fprintf(STDERR, "vos: can't find volume ID or name '%s'\n",
2737                     as->parms[0].items->data);
2738         return ENOENT;
2739     }
2740     code = GetVolumeInfo(avolid, &aserver, &apart, &vtype, &entry);
2741     if (code)
2742         exit(1);
2743
2744     /* verify this is a readwrite volume */
2745
2746     if (vtype != RWVOL) {
2747         fprintf(STDERR, "%s not RW volume\n", as->parms[0].items->data);
2748         exit(1);
2749     }
2750
2751     /* is there a backup volume already? */
2752
2753     if (entry.flags & BACK_EXISTS) {
2754         /* yep, where is it? */
2755
2756         buvolid = entry.volumeId[BACKVOL];
2757         code = GetVolumeInfo(buvolid, &buserver, &bupart, &butype, &buentry);
2758         if (code)
2759             exit(1);
2760
2761         /* is it local? */
2762         code = VLDB_IsSameAddrs(buserver, aserver, &err);
2763         if (err) {
2764             fprintf(STDERR,
2765                     "Failed to get info about server's %d address(es) from vlserver; aborting call!\n",
2766                     buserver);
2767             exit(1);
2768         }
2769         if (!code) {
2770             fprintf(STDERR,
2771                     "FATAL ERROR: backup volume %lu exists on server %lu\n",
2772                     (unsigned long)buvolid, (unsigned long)buserver);
2773             exit(1);
2774         }
2775     }
2776
2777     /* nope, carry on */
2778
2779     code = UV_BackupVolume(aserver, apart, avolid);
2780
2781     if (code) {
2782         PrintDiagnostics("backup", code);
2783         return code;
2784     }
2785     fprintf(STDOUT, "Created backup volume for %s \n",
2786             as->parms[0].items->data);
2787     return 0;
2788 }
2789
2790 static int
2791 ReleaseVolume(register struct cmd_syndesc *as, void *arock)
2792 {
2793
2794     struct nvldbentry entry;
2795     afs_uint32 avolid;
2796     afs_int32 aserver, apart, vtype, code, err;
2797     int force = 0;
2798
2799     if (as->parms[1].items)
2800         force = 1;
2801     avolid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);
2802     if (avolid == 0) {
2803         if (err)
2804             PrintError("", err);
2805         else
2806             fprintf(STDERR, "vos: can't find volume '%s'\n",
2807                     as->parms[0].items->data);
2808         return ENOENT;
2809     }
2810     code = GetVolumeInfo(avolid, &aserver, &apart, &vtype, &entry);
2811     if (code)
2812         return code;
2813
2814     if (vtype != RWVOL) {
2815         fprintf(STDERR, "%s not a RW volume\n", as->parms[0].items->data);
2816         return (ENOENT);
2817     }
2818
2819     if (!ISNAMEVALID(entry.name)) {
2820         fprintf(STDERR,
2821                 "Volume name %s is too long, rename before releasing\n",
2822                 entry.name);
2823         return E2BIG;
2824     }
2825
2826     code = UV_ReleaseVolume(avolid, aserver, apart, force);
2827     if (code) {
2828         PrintDiagnostics("release", code);
2829         return code;
2830     }
2831     fprintf(STDOUT, "Released volume %s successfully\n",
2832             as->parms[0].items->data);
2833     return 0;
2834 }
2835
2836 static int
2837 DumpVolumeCmd(register struct cmd_syndesc *as, void *arock)
2838 {
2839     afs_uint32 avolid;
2840     afs_int32 aserver, apart, voltype, fromdate = 0, code, err, i, flags;
2841     char filename[MAXPATHLEN];
2842     struct nvldbentry entry;
2843
2844     rx_SetRxDeadTime(60 * 10);
2845     for (i = 0; i < MAXSERVERS; i++) {
2846         struct rx_connection *rxConn = ubik_GetRPCConn(cstruct, i);
2847         if (rxConn == 0)
2848             break;
2849         rx_SetConnDeadTime(rxConn, rx_connDeadTime);
2850         if (rxConn->service)
2851             rxConn->service->connDeadTime = rx_connDeadTime;
2852     }
2853
2854     avolid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);
2855     if (avolid == 0) {
2856         if (err)
2857             PrintError("", err);
2858         else
2859             fprintf(STDERR, "vos: can't find volume '%s'\n",
2860                     as->parms[0].items->data);
2861         return ENOENT;
2862     }
2863
2864     if (as->parms[3].items || as->parms[4].items) {
2865         if (!as->parms[3].items || !as->parms[4].items) {
2866             fprintf(STDERR,
2867                     "Must specify both -server and -partition options\n");
2868             return -1;
2869         }
2870         aserver = GetServer(as->parms[3].items->data);
2871         if (aserver == 0) {
2872             fprintf(STDERR, "Invalid server name\n");
2873             return -1;
2874         }
2875         apart = volutil_GetPartitionID(as->parms[4].items->data);
2876         if (apart < 0) {
2877             fprintf(STDERR, "Invalid partition name\n");
2878             return -1;
2879         }
2880     } else {
2881         code = GetVolumeInfo(avolid, &aserver, &apart, &voltype, &entry);
2882         if (code)
2883             return code;
2884     }
2885
2886     if (as->parms[1].items && strcmp(as->parms[1].items->data, "0")) {
2887         code = ktime_DateToInt32(as->parms[1].items->data, &fromdate);
2888         if (code) {
2889             fprintf(STDERR, "vos: failed to parse date '%s' (error=%d))\n",
2890                     as->parms[1].items->data, code);
2891             return code;
2892         }
2893     }
2894     if (as->parms[2].items) {
2895         strcpy(filename, as->parms[2].items->data);
2896     } else {
2897         strcpy(filename, "");
2898     }
2899
2900     flags = as->parms[6].items ? VOLDUMPV2_OMITDIRS : 0;
2901 retry_dump:
2902     if (as->parms[5].items) {
2903         code =
2904             UV_DumpClonedVolume(avolid, aserver, apart, fromdate,
2905                                 DumpFunction, filename, flags);
2906     } else {
2907         code =
2908             UV_DumpVolume(avolid, aserver, apart, fromdate, DumpFunction,
2909                           filename, flags);
2910     }
2911     if ((code == RXGEN_OPCODE) && (as->parms[6].items)) {
2912         flags &= ~VOLDUMPV2_OMITDIRS;
2913         goto retry_dump;
2914     }
2915     if (code) {
2916         PrintDiagnostics("dump", code);
2917         return code;
2918     }
2919     if (strcmp(filename, ""))
2920         fprintf(STDERR, "Dumped volume %s in file %s\n",
2921                 as->parms[0].items->data, filename);
2922     else
2923         fprintf(STDERR, "Dumped volume %s in stdout \n",
2924                 as->parms[0].items->data);
2925     return 0;
2926 }
2927
2928 #define ASK   0
2929 #define ABORT 1
2930 #define FULL  2
2931 #define INC   3
2932
2933 #define TS_DUMP 1
2934 #define TS_KEEP 2
2935 #define TS_NEW  3
2936
2937 static int
2938 RestoreVolumeCmd(register struct cmd_syndesc *as, void *arock)
2939 {
2940     afs_uint32 avolid, aparentid;
2941     afs_int32 aserver, apart, code, vcode, err;
2942     afs_int32 aoverwrite = ASK;
2943     afs_int32 acreation = 0, alastupdate = 0;
2944     int restoreflags = 0;
2945     int readonly = 0, offline = 0, voltype = RWVOL;
2946     char prompt;
2947     char afilename[MAXPATHLEN], avolname[VOLSER_MAXVOLNAME + 1], apartName[10];
2948     char volname[VOLSER_MAXVOLNAME + 1];
2949     struct nvldbentry entry;
2950
2951     prompt = 'n';
2952
2953     aparentid = 0;
2954     if (as->parms[4].items) {
2955         avolid = vsu_GetVolumeID(as->parms[4].items->data, cstruct, &err);
2956         if (avolid == 0) {
2957             if (err)
2958                 PrintError("", err);
2959             else
2960                 fprintf(STDERR, "vos: can't find volume '%s'\n",
2961                         as->parms[4].items->data);
2962             exit(1);
2963         }
2964     } else
2965         avolid = 0;
2966
2967     if (as->parms[5].items) {
2968         if ((strcmp(as->parms[5].items->data, "a") == 0)
2969             || (strcmp(as->parms[5].items->data, "abort") == 0)) {
2970             aoverwrite = ABORT;
2971         } else if ((strcmp(as->parms[5].items->data, "f") == 0)
2972                    || (strcmp(as->parms[5].items->data, "full") == 0)) {
2973             aoverwrite = FULL;
2974         } else if ((strcmp(as->parms[5].items->data, "i") == 0)
2975                    || (strcmp(as->parms[5].items->data, "inc") == 0)
2976                    || (strcmp(as->parms[5].items->data, "increment") == 0)
2977                    || (strcmp(as->parms[5].items->data, "incremental") == 0)) {
2978             aoverwrite = INC;
2979         } else {
2980             fprintf(STDERR, "vos: %s is not a valid argument to -overwrite\n",
2981                     as->parms[5].items->data);
2982             exit(1);
2983         }
2984     }
2985     if (as->parms[6].items)
2986         offline = 1;
2987     if (as->parms[7].items) {
2988         readonly = 1;
2989         voltype = ROVOL;
2990     }
2991
2992     if (as->parms[8].items) {
2993         if ((strcmp(as->parms[8].items->data, "d") == 0)
2994             || (strcmp(as->parms[8].items->data, "dump") == 0)) {
2995             acreation = TS_DUMP;
2996         } else if ((strcmp(as->parms[8].items->data, "k") == 0)
2997             || (strcmp(as->parms[8].items->data, "keep") == 0)) {
2998             acreation = TS_KEEP;
2999         } else if ((strcmp(as->parms[8].items->data, "n") == 0)
3000             || (strcmp(as->parms[8].items->data, "new") == 0)) {
3001             acreation = TS_NEW;
3002         } else {
3003             fprintf(STDERR, "vos: %s is not a valid argument to -creation\n",
3004                     as->parms[8].items->data);
3005             exit(1);
3006         }
3007     }
3008
3009     if (as->parms[9].items) {
3010         if ((strcmp(as->parms[9].items->data, "d") == 0)
3011             || (strcmp(as->parms[9].items->data, "dump") == 0)) {
3012             alastupdate = TS_DUMP;
3013         } else if ((strcmp(as->parms[9].items->data, "k") == 0)
3014             || (strcmp(as->parms[9].items->data, "keep") == 0)) {
3015             alastupdate = TS_KEEP;
3016         } else if ((strcmp(as->parms[9].items->data, "n") == 0)
3017             || (strcmp(as->parms[9].items->data, "new") == 0)) {
3018             alastupdate = TS_NEW;
3019         } else {
3020             fprintf(STDERR, "vos: %s is not a valid argument to -lastupdate\n",
3021                     as->parms[9].items->data);
3022             exit(1);
3023         }
3024     }
3025
3026     aserver = GetServer(as->parms[0].items->data);
3027     if (aserver == 0) {
3028         fprintf(STDERR, "vos: server '%s' not found in host table\n",
3029                 as->parms[0].items->data);
3030         exit(1);
3031     }
3032     apart = volutil_GetPartitionID(as->parms[1].items->data);
3033     if (apart < 0) {
3034         fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
3035                 as->parms[1].items->data);
3036         exit(1);
3037     }
3038     if (!IsPartValid(apart, aserver, &code)) {  /*check for validity of the partition */
3039         if (code)
3040             PrintError("", code);
3041         else
3042             fprintf(STDERR,
3043                     "vos : partition %s does not exist on the server\n",
3044                     as->parms[1].items->data);
3045         exit(1);
3046     }
3047     strcpy(avolname, as->parms[2].items->data);
3048     if (!ISNAMEVALID(avolname)) {
3049         fprintf(STDERR,
3050                 "vos: the name of the volume %s exceeds the size limit\n",
3051                 avolname);
3052         exit(1);
3053     }
3054     if (!VolNameOK(avolname)) {
3055         fprintf(STDERR,
3056                 "Illegal volume name %s, should not end in .readonly or .backup\n",
3057                 avolname);
3058         exit(1);
3059     }
3060     if (as->parms[3].items) {
3061         strcpy(afilename, as->parms[3].items->data);
3062         if (!FileExists(afilename)) {
3063             fprintf(STDERR, "Can't access file %s\n", afilename);
3064             exit(1);
3065         }
3066     } else {
3067         strcpy(afilename, "");
3068     }
3069
3070     /* Check if volume exists or not */
3071
3072     vsu_ExtractName(volname, avolname);
3073     vcode = VLDB_GetEntryByName(volname, &entry);
3074     if (vcode) {                /* no volume - do a full restore */
3075         restoreflags = RV_FULLRST;
3076         if ((aoverwrite == INC) || (aoverwrite == ABORT))
3077             fprintf(STDERR,
3078                     "Volume does not exist; Will perform a full restore\n");
3079     }
3080
3081     else if ((!readonly && Lp_GetRwIndex(&entry) == -1) /* RW volume does not exist - do a full */
3082              ||(readonly && !Lp_ROMatch(0, 0, &entry))) {       /* RO volume does not exist - do a full */
3083         restoreflags = RV_FULLRST;
3084         if ((aoverwrite == INC) || (aoverwrite == ABORT))
3085             fprintf(STDERR,
3086                     "%s Volume does not exist; Will perform a full restore\n",
3087                     readonly ? "RO" : "RW");
3088
3089         if (avolid == 0) {
3090             avolid = entry.volumeId[voltype];
3091         } else if (entry.volumeId[voltype] != 0
3092                    && entry.volumeId[voltype] != avolid) {
3093             avolid = entry.volumeId[voltype];
3094         }
3095         aparentid = entry.volumeId[RWVOL];
3096     }
3097
3098     else {                      /* volume exists - do we do a full incremental or abort */
3099         int Oserver, Opart, Otype, vol_elsewhere = 0;
3100         struct nvldbentry Oentry;
3101         int c, dc;
3102
3103         if (avolid == 0) {
3104             avolid = entry.volumeId[voltype];
3105         } else if (entry.volumeId[voltype] != 0
3106                    && entry.volumeId[voltype] != avolid) {
3107             avolid = entry.volumeId[voltype];
3108         }
3109         aparentid = entry.volumeId[RWVOL];
3110
3111         /* A file name was specified  - check if volume is on another partition */
3112         vcode = GetVolumeInfo(avolid, &Oserver, &Opart, &Otype, &Oentry);
3113         if (vcode)
3114             exit(1);
3115
3116         vcode = VLDB_IsSameAddrs(Oserver, aserver, &err);
3117         if (err) {
3118             fprintf(STDERR,
3119                     "Failed to get info about server's %d address(es) from vlserver (err=%d); aborting call!\n",
3120                     Oserver, err);
3121             exit(1);
3122         }
3123         if (!vcode || (Opart != apart))
3124             vol_elsewhere = 1;
3125
3126         if (aoverwrite == ASK) {
3127             if (strcmp(afilename, "") == 0) {   /* The file is from standard in */
3128                 fprintf(STDERR,
3129                         "Volume exists and no -overwrite option specified; Aborting restore command\n");
3130                 exit(1);
3131             }
3132
3133             /* Ask what to do */
3134             if (vol_elsewhere) {
3135                 fprintf(STDERR,
3136                         "The volume %s %u already exists on a different server/part\n",
3137                         volname, entry.volumeId[voltype]);
3138                 fprintf(STDERR,
3139                         "Do you want to do a full restore or abort? [fa](a): ");
3140             } else {
3141                 fprintf(STDERR,
3142                         "The volume %s %u already exists in the VLDB\n",
3143                         volname, entry.volumeId[voltype]);
3144                 fprintf(STDERR,
3145                         "Do you want to do a full/incremental restore or abort? [fia](a): ");
3146             }
3147             dc = c = getchar();
3148             while (!(dc == EOF || dc == '\n'))
3149                 dc = getchar(); /* goto end of line */
3150             if ((c == 'f') || (c == 'F'))
3151                 aoverwrite = FULL;
3152             else if ((c == 'i') || (c == 'I'))
3153                 aoverwrite = INC;
3154             else
3155                 aoverwrite = ABORT;
3156         }
3157
3158         if (aoverwrite == ABORT) {
3159             fprintf(STDERR, "Volume exists; Aborting restore command\n");
3160             exit(1);
3161         } else if (aoverwrite == FULL) {
3162             restoreflags = RV_FULLRST;
3163             fprintf(STDERR,
3164                     "Volume exists; Will delete and perform full restore\n");
3165         } else if (aoverwrite == INC) {
3166             restoreflags = 0;
3167             if (vol_elsewhere) {
3168                 fprintf(STDERR,
3169                         "%s volume %lu already exists on a different server/part; not allowed\n",
3170                         readonly ? "RO" : "RW", (unsigned long)avolid);
3171                 exit(1);
3172             }
3173         }
3174     }
3175     if (offline)
3176         restoreflags |= RV_OFFLINE;
3177     if (readonly)
3178         restoreflags |= RV_RDONLY;
3179
3180     switch (acreation) {
3181         case TS_DUMP:
3182             restoreflags |= RV_CRDUMP;
3183             break;
3184         case TS_KEEP:
3185             restoreflags |= RV_CRKEEP;
3186             break;
3187         case TS_NEW:
3188             restoreflags |= RV_CRNEW;
3189             break;
3190         default:
3191             if (aoverwrite == FULL)
3192                 restoreflags |= RV_CRNEW;
3193             else
3194                 restoreflags |= RV_CRKEEP;
3195     }
3196
3197     switch (alastupdate) {
3198         case TS_DUMP:
3199             restoreflags |= RV_LUDUMP;
3200             break;
3201         case TS_KEEP:
3202             restoreflags |= RV_LUKEEP;
3203             break;
3204         case TS_NEW:
3205             restoreflags |= RV_LUNEW;
3206             break;
3207         default:
3208             restoreflags |= RV_LUDUMP;
3209     }
3210     if (as->parms[10].items) {
3211         restoreflags |= RV_NODEL;
3212     }
3213     
3214
3215     code =
3216         UV_RestoreVolume2(aserver, apart, avolid, aparentid,
3217                           avolname, restoreflags, WriteData, afilename);
3218     if (code) {
3219         PrintDiagnostics("restore", code);
3220         exit(1);
3221     }
3222     MapPartIdIntoName(apart, apartName);
3223
3224     /*
3225      * patch typo here - originally "parms[1]", should be "parms[0]"
3226      */
3227
3228     fprintf(STDOUT, "Restored volume %s on %s %s\n", avolname,
3229             as->parms[0].items->data, apartName);
3230     return 0;
3231 }
3232
3233 static int
3234 LockReleaseCmd(register struct cmd_syndesc *as, void *arock)
3235 {
3236     afs_uint32 avolid;
3237     afs_int32 code, err;
3238
3239     avolid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);
3240     if (avolid == 0) {
3241         if (err)
3242             PrintError("", err);
3243         else
3244             fprintf(STDERR, "vos: can't find volume '%s'\n",
3245                     as->parms[0].items->data);
3246         exit(1);
3247     }
3248
3249     code = UV_LockRelease(avolid);
3250     if (code) {
3251         PrintDiagnostics("unlock", code);
3252         exit(1);
3253     }
3254     fprintf(STDOUT, "Released lock on vldb entry for volume %s\n",
3255             as->parms[0].items->data);
3256     return 0;
3257 }
3258
3259 static int
3260 AddSite(register struct cmd_syndesc *as, void *arock)
3261 {
3262     afs_uint32 avolid;
3263     afs_int32 aserver, apart, code, err, arovolid, valid = 0;
3264     char apartName[10], avolname[VOLSER_MAXVOLNAME + 1];
3265
3266     vsu_ExtractName(avolname, as->parms[2].items->data);;
3267     avolid = vsu_GetVolumeID(avolname, cstruct, &err);
3268     if (avolid == 0) {
3269         if (err)
3270             PrintError("", err);
3271         else
3272             fprintf(STDERR, "vos: can't find volume '%s'\n",
3273                     as->parms[2].items->data);
3274         exit(1);
3275     }
3276     arovolid = 0;
3277     if (as->parms[3].items) {
3278         vsu_ExtractName(avolname, as->parms[3].items->data);
3279         arovolid = vsu_GetVolumeID(avolname, cstruct, &err);
3280         if (!arovolid) {
3281             fprintf(STDERR, "vos: invalid ro volume id '%s'\n",
3282                     as->parms[3].items->data);
3283             exit(1);
3284         }
3285     }
3286     aserver = GetServer(as->parms[0].items->data);
3287     if (aserver == 0) {
3288         fprintf(STDERR, "vos: server '%s' not found in host table\n",
3289                 as->parms[0].items->data);
3290         exit(1);
3291     }
3292     apart = volutil_GetPartitionID(as->parms[1].items->data);
3293     if (apart < 0) {
3294         fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
3295                 as->parms[1].items->data);
3296         exit(1);
3297     }
3298     if (!IsPartValid(apart, aserver, &code)) {  /*check for validity of the partition */
3299         if (code)
3300             PrintError("", code);
3301         else
3302             fprintf(STDERR,
3303                     "vos : partition %s does not exist on the server\n",
3304                     as->parms[1].items->data);
3305         exit(1);
3306     }
3307     if (as->parms[4].items) {
3308         valid = 1;
3309     }
3310     code = UV_AddSite2(aserver, apart, avolid, arovolid, valid);
3311     if (code) {
3312         PrintDiagnostics("addsite", code);
3313         exit(1);
3314     }
3315     MapPartIdIntoName(apart, apartName);
3316     fprintf(STDOUT, "Added replication site %s %s for volume %s\n",
3317             as->parms[0].items->data, apartName, as->parms[2].items->data);
3318     return 0;
3319 }
3320
3321 static int
3322 RemoveSite(register struct cmd_syndesc *as, void *arock)
3323 {
3324
3325     afs_uint32 avolid;
3326     afs_int32 aserver, apart, code, err;
3327     char apartName[10], avolname[VOLSER_MAXVOLNAME + 1];
3328
3329     vsu_ExtractName(avolname, as->parms[2].items->data);
3330     avolid = vsu_GetVolumeID(avolname, cstruct, &err);
3331     if (avolid == 0) {
3332         if (err)
3333             PrintError("", err);
3334         else
3335             fprintf(STDERR, "vos: can't find volume '%s'\n",
3336                     as->parms[2].items->data);
3337         exit(1);
3338     }
3339     aserver = GetServer(as->parms[0].items->data);
3340     if (aserver == 0) {
3341         fprintf(STDERR, "vos: server '%s' not found in host table\n",
3342                 as->parms[0].items->data);
3343         exit(1);
3344     }
3345     apart = volutil_GetPartitionID(as->parms[1].items->data);
3346     if (apart < 0) {
3347         fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
3348                 as->parms[1].items->data);
3349         exit(1);
3350     }
3351 /*
3352  *skip the partition validity check, since it is possible that the partition
3353  *has since been decomissioned.
3354  */
3355 /*
3356         if (!IsPartValid(apart,aserver,&code)){
3357             if(code) PrintError("",code);
3358             else fprintf(STDERR,"vos : partition %s does not exist on the server\n",as->parms[1].items->data);
3359             exit(1);
3360         }
3361 */
3362     code = UV_RemoveSite(aserver, apart, avolid);
3363     if (code) {
3364         PrintDiagnostics("remsite", code);
3365         exit(1);
3366     }
3367     MapPartIdIntoName(apart, apartName);
3368     fprintf(STDOUT, "Removed replication site %s %s for volume %s\n",
3369             as->parms[0].items->data, apartName, as->parms[2].items->data);
3370     return 0;
3371 }
3372
3373 static int
3374 ChangeLocation(register struct cmd_syndesc *as, void *arock)
3375 {
3376     afs_uint32 avolid;
3377     afs_int32 aserver, apart, code, err;
3378     char apartName[10];
3379
3380     avolid = vsu_GetVolumeID(as->parms[2].items->data, cstruct, &err);
3381     if (avolid == 0) {
3382         if (err)
3383             PrintError("", err);
3384         else
3385             fprintf(STDERR, "vos: can't find volume '%s'\n",
3386                     as->parms[2].items->data);
3387         exit(1);
3388     }
3389     aserver = GetServer(as->parms[0].items->data);
3390     if (aserver == 0) {
3391         fprintf(STDERR, "vos: server '%s' not found in host table\n",
3392                 as->parms[0].items->data);
3393         exit(1);
3394     }
3395     apart = volutil_GetPartitionID(as->parms[1].items->data);
3396     if (apart < 0) {
3397         fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
3398                 as->parms[1].items->data);
3399         exit(1);
3400     }
3401     if (!IsPartValid(apart, aserver, &code)) {  /*check for validity of the partition */
3402         if (code)
3403             PrintError("", code);
3404         else
3405             fprintf(STDERR,
3406                     "vos : partition %s does not exist on the server\n",
3407                     as->parms[1].items->data);
3408         exit(1);
3409     }
3410     code = UV_ChangeLocation(aserver, apart, avolid);
3411     if (code) {
3412         PrintDiagnostics("addsite", code);
3413         exit(1);
3414     }
3415     MapPartIdIntoName(apart, apartName);
3416     fprintf(STDOUT, "Changed location to %s %s for volume %s\n",
3417             as->parms[0].items->data, apartName, as->parms[2].items->data);
3418     return 0;
3419 }
3420
3421 static int
3422 ListPartitions(register struct cmd_syndesc *as, void *arock)
3423 {
3424     afs_int32 aserver, code;
3425     struct partList dummyPartList;
3426     int i;
3427     char pname[10];
3428     int total, cnt;
3429
3430     aserver = GetServer(as->parms[0].items->data);
3431     if (aserver == 0) {
3432         fprintf(STDERR, "vos: server '%s' not found in host table\n",
3433                 as->parms[0].items->data);
3434         exit(1);
3435     }
3436
3437
3438     code = UV_ListPartitions(aserver, &dummyPartList, &cnt);
3439     if (code) {
3440         PrintDiagnostics("listpart", code);
3441         exit(1);
3442     }
3443     total = 0;
3444     fprintf(STDOUT, "The partitions on the server are:\n");
3445     for (i = 0; i < cnt; i++) {
3446         if (dummyPartList.partFlags[i] & PARTVALID) {
3447             memset(pname, 0, sizeof(pname));
3448             MapPartIdIntoName(dummyPartList.partId[i], pname);
3449             fprintf(STDOUT, " %10s ", pname);
3450             total++;
3451             if ((i % 5) == 0 && (i != 0))
3452                 fprintf(STDOUT, "\n");
3453         }
3454     }
3455     fprintf(STDOUT, "\n");
3456     fprintf(STDOUT, "Total: %d\n", total);
3457     return 0;
3458
3459 }
3460
3461 static int
3462 CompareVolName(const void *p1, const void *p2)
3463 {
3464     volintInfo *arg1, *arg2;
3465
3466     arg1 = (volintInfo *) p1;
3467     arg2 = (volintInfo *) p2;
3468     return (strcmp(arg1->name, arg2->name));
3469
3470 }
3471
3472 /*------------------------------------------------------------------------
3473  * PRIVATE XCompareVolName
3474  *
3475  * Description:
3476  *      Comparison routine for volume names coming from an extended
3477  *      volume listing.
3478  *
3479  * Arguments:
3480  *      a_obj1P : Char ptr to first extended vol info object
3481  *      a_obj1P : Char ptr to second extended vol info object
3482  *
3483  * Returns:
3484  *      The value of strcmp() on the volume names within the passed
3485  *      objects (i,e., -1, 0, or 1).
3486  *
3487  * Environment:
3488  *      Passed to qsort() as the designated comparison routine.
3489  *
3490  * Side Effects:
3491  *      As advertised.
3492  *------------------------------------------------------------------------*/
3493
3494 static int
3495 XCompareVolName(const void *a_obj1P, const void *a_obj2P)
3496 {                               /*XCompareVolName */
3497
3498     return (strcmp
3499             (((struct volintXInfo *)(a_obj1P))->name,
3500              ((struct volintXInfo *)(a_obj2P))->name));
3501
3502 }                               /*XCompareVolName */
3503
3504 static int
3505 CompareVolID(const void *p1, const void *p2)
3506 {
3507     volintInfo *arg1, *arg2;
3508
3509     arg1 = (volintInfo *) p1;
3510     arg2 = (volintInfo *) p2;
3511     if (arg1->volid == arg2->volid)
3512         return 0;
3513     if (arg1->volid > arg2->volid)
3514         return 1;
3515     else
3516         return -1;
3517
3518 }
3519
3520 /*------------------------------------------------------------------------
3521  * PRIVATE XCompareVolID
3522  *
3523  * Description:
3524  *      Comparison routine for volume IDs coming from an extended
3525  *      volume listing.
3526  *
3527  * Arguments:
3528  *      a_obj1P : Char ptr to first extended vol info object
3529  *      a_obj1P : Char ptr to second extended vol info object
3530  *
3531  * Returns:
3532  *      The value of strcmp() on the volume names within the passed
3533  *      objects (i,e., -1, 0, or 1).
3534  *
3535  * Environment:
3536  *      Passed to qsort() as the designated comparison routine.
3537  *
3538  * Side Effects:
3539  *      As advertised.
3540  *------------------------------------------------------------------------*/
3541
3542 static int
3543 XCompareVolID(const void *a_obj1P, const void *a_obj2P)
3544 {                               /*XCompareVolID */
3545
3546     afs_int32 id1, id2;         /*Volume IDs we're comparing */
3547
3548     id1 = ((struct volintXInfo *)(a_obj1P))->volid;
3549     id2 = ((struct volintXInfo *)(a_obj2P))->volid;
3550     if (id1 == id2)
3551         return (0);
3552     else if (id1 > id2)
3553         return (1);
3554     else
3555         return (-1);
3556
3557 }                               /*XCompareVolID */
3558
3559 /*------------------------------------------------------------------------
3560  * PRIVATE ListVolumes
3561  *
3562  * Description:
3563  *      Routine used to list volumes, contacting the Volume Server
3564  *      directly, bypassing the VLDB.
3565  *
3566  * Arguments:
3567  *      as : Ptr to parsed command line arguments.
3568  *
3569  * Returns:
3570  *      0                       Successful operation
3571  *
3572  * Environment:
3573  *      Nothing interesting.
3574  *
3575  * Side Effects:
3576  *      As advertised.
3577  *------------------------------------------------------------------------*/
3578
3579 static int
3580 ListVolumes(register struct cmd_syndesc *as, void *arock)
3581 {
3582     afs_int32 apart, int32list, fast;
3583     afs_int32 aserver, code;
3584     volintInfo *pntr;
3585     volintInfo *oldpntr = NULL;
3586     afs_int32 count;
3587     int i;
3588     char *base;
3589     volintXInfo *xInfoP;
3590     volintXInfo *origxInfoP = NULL; /*Ptr to current/orig extended vol info */
3591     int wantExtendedInfo;       /*Do we want extended vol info? */
3592
3593     char pname[10];
3594     struct partList dummyPartList;
3595     int all;
3596     int quiet, cnt;
3597
3598     apart = -1;
3599     fast = 0;
3600     int32list = 0;
3601
3602     if (as->parms[3].items)
3603         int32list = 1;
3604     if (as->parms[4].items)
3605         quiet = 1;
3606     else
3607         quiet = 0;
3608     if (as->parms[2].items)
3609         fast = 1;
3610     if (fast)
3611         all = 0;
3612     else
3613         all = 1;
3614     if (as->parms[5].items) {
3615         /*
3616          * We can't coexist with the fast flag.
3617          */
3618         if (fast) {
3619             fprintf(STDERR,
3620                     "vos: Can't use the -fast and -extended flags together\n");
3621             exit(1);
3622         }
3623
3624         /*
3625          * We need to turn on ``long'' listings to get the full effect.
3626          */
3627         wantExtendedInfo = 1;
3628         int32list = 1;
3629     } else
3630         wantExtendedInfo = 0;
3631     if (as->parms[1].items) {
3632         apart = volutil_GetPartitionID(as->parms[1].items->data);
3633         if (apart < 0) {
3634             fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
3635                     as->parms[1].items->data);
3636             exit(1);
3637         }
3638         dummyPartList.partId[0] = apart;
3639         dummyPartList.partFlags[0] = PARTVALID;
3640         cnt = 1;
3641     }
3642     aserver = GetServer(as->parms[0].items->data);
3643     if (aserver == 0) {
3644         fprintf(STDERR, "vos: server '%s' not found in host table\n",
3645                 as->parms[0].items->data);
3646         exit(1);
3647     }
3648
3649     if (apart != -1) {
3650         if (!IsPartValid(apart, aserver, &code)) {      /*check for validity of the partition */
3651             if (code)
3652                 PrintError("", code);
3653             else
3654                 fprintf(STDERR,
3655                         "vos : partition %s does not exist on the server\n",
3656                         as->parms[1].items->data);
3657             exit(1);
3658         }
3659     } else {
3660         code = UV_ListPartitions(aserver, &dummyPartList, &cnt);
3661         if (code) {
3662             PrintDiagnostics("listvol", code);