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