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