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