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