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