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