Don't cast the return from calloc()
[openafs.git] / src / libadmin / vos / afs_vosAdmin.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 #include <afs/stds.h>
13
14 #include <roken.h>
15
16 #include <ctype.h>
17
18 #include <afs/vlserver.h>
19 #include <afs/volser.h>
20 #include <afs/volint.h>
21
22 #include "afs_vosAdmin.h"
23 #include "../adminutil/afs_AdminInternal.h"
24
25 /* File descriptors are HANDLE's on NT. The following typedef helps catch
26  * type errors. Duplicated from vol/ihandle.h
27  */
28 #ifdef AFS_NT40_ENV
29 typedef HANDLE FD_t;
30 #else
31 typedef int FD_t;
32 #endif
33 #define INVALID_FD ((FD_t)-1)
34
35 #include <afs/partition.h>
36 #include <rx/rx.h>
37 #include <rx/rxstat.h>
38 #include <afs/afs_utilAdmin.h>
39 #include "vosutils.h"
40 #include "vsprocs.h"
41 #include "lockprocs.h"
42
43 typedef struct file_server {
44     int begin_magic;
45     int is_valid;
46     struct rx_connection *serv;
47     int end_magic;
48 } file_server_t, *file_server_p;
49
50 /*
51  * IsValidServerHandle - test a server handle for validity.
52  *
53  * PARAMETERS
54  *
55  * IN serverHandle - the serverHandle to be validated.
56  *
57  * LOCKS
58  * 
59  * No locks are obtained or released by this function
60  *
61  * RETURN CODES
62  *
63  * Returns != 0 upon successful completion.
64  */
65
66 static int
67 IsValidServerHandle(file_server_p serverHandle, afs_status_p st)
68 {
69     int rc = 0;
70     afs_status_t tst = 0;
71
72     if (serverHandle == NULL) {
73         tst = ADMVOSSERVERHANDLENULL;
74         goto fail_IsValidServerHandle;
75     }
76
77     if (serverHandle->is_valid != 1) {
78         tst = ADMVOSSERVERHANDLEINVALID;
79         goto fail_IsValidServerHandle;
80     }
81
82     if ((serverHandle->begin_magic != BEGIN_MAGIC)
83         || (serverHandle->end_magic != END_MAGIC)) {
84         tst = ADMVOSSERVERHANDLEBADMAGIC;
85         goto fail_IsValidServerHandle;
86     }
87     rc = 1;
88
89   fail_IsValidServerHandle:
90
91     if (st != NULL) {
92         *st = tst;
93     }
94
95     return rc;
96 }
97
98 /*
99  * IsValidCellHandle - verify that a cell handle can be used to make vos 
100  * requests.
101  *
102  * PARAMETERS
103  *
104  * IN cellHandle - the cellHandle to be validated.
105  *
106  * LOCKS
107  * 
108  * No locks are obtained or released by this function
109  *
110  * RETURN CODES
111  *
112  * Returns != 0 upon successful completion.
113  */
114
115 static int
116 IsValidCellHandle(afs_cell_handle_p cellHandle, afs_status_p st)
117 {
118     int rc = 0;
119     afs_status_t tst = 0;
120
121     if (!CellHandleIsValid((void *)cellHandle, &tst)) {
122         goto fail_IsValidCellHandle;
123     }
124
125     if (cellHandle->vos_valid == 0) {
126         tst = ADMVOSCELLHANDLEINVALIDVOS;
127         goto fail_IsValidCellHandle;
128     }
129     rc = 1;
130
131   fail_IsValidCellHandle:
132
133     if (st != NULL) {
134         *st = tst;
135     }
136     return rc;
137 }
138
139 /* set <server> and <part> to the correct values depending on
140  * <voltype> and <entry> */
141 static void
142 GetServerAndPart(struct nvldbentry *entry, int voltype, afs_int32 * server,
143                  afs_int32 * part, int *previdx)
144 {
145     int i, istart, vtype;
146
147     *server = -1;
148     *part = -1;
149
150     /* Doesn't check for non-existance of backup volume */
151     if ((voltype == RWVOL) || (voltype == BACKVOL)) {
152         vtype = ITSRWVOL;
153         istart = 0;             /* seach the entire entry */
154     } else {
155         vtype = ITSROVOL;
156         /* Seach from beginning of entry or pick up where we left off */
157         istart = ((*previdx < 0) ? 0 : *previdx + 1);
158     }
159
160     for (i = istart; i < entry->nServers; i++) {
161         if (entry->serverFlags[i] & vtype) {
162             *server = entry->serverNumber[i];
163             *part = entry->serverPartition[i];
164             *previdx = i;
165             return;
166         }
167     }
168
169     /* Didn't find any, return -1 */
170     *previdx = -1;
171     return;
172 }
173
174 /*
175  * vos_BackupVolumeCreate - create a backup volume for a volume.
176  *
177  * PARAMETERS
178  *
179  * IN cellHandle - a previously opened cellHandle that corresponds
180  * to the cell where volume exists.
181  *
182  * IN callBack - a call back function pointer that may be called to report
183  * status information.  Can be null.
184  *
185  * IN volumeId - the volume to create the back up for.
186  *
187  * LOCKS
188  * 
189  * No locks are obtained or released by this function
190  *
191  * RETURN CODES
192  *
193  * Returns != 0 upon successful completion.
194  */
195
196 int ADMINAPI
197 vos_BackupVolumeCreate(const void *cellHandle, vos_MessageCallBack_t callBack,
198                        unsigned int volumeId, afs_status_p st)
199 {
200     int rc = 0;
201     afs_status_t tst = 0;
202     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
203     struct nvldbentry rw_vol_entry;
204     afs_int32 rw_server;
205     afs_int32 rw_partition;
206     afs_int32 rw_vol_type;
207     struct nvldbentry bk_vol_entry;
208     afs_int32 bk_server;
209     afs_int32 bk_partition;
210     afs_int32 bk_vol_type;
211     int equal;
212
213     /*
214      * Validate arguments
215      */
216
217     if (!IsValidCellHandle(c_handle, &tst)) {
218         goto fail_vos_BackupVolumeCreate;
219     }
220
221     /*
222      * Get the volume information and verify that we've been passed
223      * a read write volume id
224      */
225
226     if (!GetVolumeInfo
227         (c_handle, volumeId, &rw_vol_entry, &rw_server, &rw_partition,
228          &rw_vol_type, &tst)) {
229         goto fail_vos_BackupVolumeCreate;
230     }
231
232     if (rw_vol_type != RWVOL) {
233         tst = ADMVOSMUSTBERWVOL;
234         goto fail_vos_BackupVolumeCreate;
235     }
236
237     /*
238      * Check to see that if a backup volume exists, it exists on the
239      * same server as volumeId
240      */
241
242     if (rw_vol_entry.flags & BACK_EXISTS) {
243         if (!GetVolumeInfo
244             (c_handle, rw_vol_entry.volumeId[BACKVOL], &bk_vol_entry,
245              &bk_server, &bk_partition, &bk_vol_type, &tst)) {
246             goto fail_vos_BackupVolumeCreate;
247         }
248         if (!VLDB_IsSameAddrs(c_handle, bk_server, rw_server, &equal, &tst)) {
249             goto fail_vos_BackupVolumeCreate;
250         }
251         if (!equal) {
252             tst = ADMVOSBACKUPVOLWRONGSERVER;
253             goto fail_vos_BackupVolumeCreate;
254         }
255     }
256
257     /*
258      * Create the new backup volume
259      */
260
261     rc = UV_BackupVolume(c_handle, rw_server, rw_partition, volumeId, &tst);
262
263   fail_vos_BackupVolumeCreate:
264
265     if (st != NULL) {
266         *st = tst;
267     }
268     return rc;
269 }
270
271 /*
272  * vos_BackupVolumeCreateMultiple - create backup volumes en masse.
273  *
274  * PARAMETERS
275  *
276  * IN cellHandle - a previously opened cellHandle that corresponds
277  * to the cell where the volumes exist.
278  *
279  * IN serverHandle - the server where the backups are to be created.  Can be
280  * null.
281  *
282  * IN callBack - a call back function pointer that may be called to report
283  * status information.  Can be null.
284  *
285  * IN partition - the partition where the backups are to be created.  Can be
286  * null.
287  *
288  * IN volumePrefix - all volumes with this prefix will have backup volumes
289  * created. Can be null.
290  *
291  * IN excludePrefix - exclude the volumes that match volumePrefix.
292  *
293  * LOCKS
294  * 
295  * No locks are obtained or released by this function
296  *
297  * RETURN CODES
298  *
299  * Returns != 0 upon successful completion.
300  */
301
302 int ADMINAPI
303 vos_BackupVolumeCreateMultiple(const void *cellHandle,
304                                const void *serverHandle,
305                                vos_MessageCallBack_t callBack,
306                                const unsigned int *partition,
307                                const char *volumePrefix,
308                                vos_exclude_t excludePrefix, afs_status_p st)
309 {
310     int rc = 0;
311     afs_status_t tst = 0;
312     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
313     file_server_p f_server = (file_server_p) serverHandle;
314     struct VldbListByAttributes attr;
315     int exclude = 0;
316     int prefix = 0;
317     size_t prefix_len = 0;
318     nbulkentries arrayEntries;
319     afs_int32 nentries = 0;
320     struct nvldbentry *entry;
321     int i;
322     afs_int32 rw_volid, rw_server, rw_partition;
323     int previdx;
324     int equal = 0;
325     char backbuf[1024];
326
327     memset((void *)&attr, 0, sizeof(attr));
328
329     /*
330      * Validate arguments
331      *
332      * The only required argument to this function is the cellHandle.
333      * If the excludePrefix is set to VOS_EXCLUDE, volumePrefix must
334      * be non-null.
335      */
336
337     if (!IsValidCellHandle(c_handle, &tst)) {
338         goto fail_vos_BackupVolumeCreateMultiple;
339     }
340
341     if ((excludePrefix == VOS_EXCLUDE)
342         && ((volumePrefix == NULL) || (*volumePrefix == 0))) {
343         tst = ADMVOSEXCLUDEREQUIRESPREFIX;
344         goto fail_vos_BackupVolumeCreateMultiple;
345     }
346
347     if (f_server != NULL) {
348         if (!IsValidServerHandle(f_server, &tst)) {
349             goto fail_vos_BackupVolumeCreateMultiple;
350         }
351         attr.server = ntohl(rx_HostOf(rx_PeerOf(f_server->serv)));
352         attr.Mask |= VLLIST_SERVER;
353     }
354
355     if (partition != NULL) {
356         if (*partition > VOLMAXPARTS) {
357             tst = ADMVOSPARTITIONTOOLARGE;
358             goto fail_vos_BackupVolumeCreateMultiple;
359         }
360         attr.partition = *partition;
361         attr.Mask |= VLLIST_PARTITION;
362     }
363
364     if (excludePrefix == VOS_EXCLUDE) {
365         exclude = 1;
366     }
367
368     if ((volumePrefix != NULL) && (*volumePrefix != 0)) {
369         prefix = 1;
370         prefix_len = strlen(volumePrefix);
371     }
372
373     memset((void *)&arrayEntries, 0, sizeof(arrayEntries));
374
375     /*
376      * Get a list of all the volumes in the cell
377      */
378
379     if (!VLDB_ListAttributes(c_handle, &attr, &nentries, &arrayEntries, &tst)) {
380         goto fail_vos_BackupVolumeCreateMultiple;
381     }
382
383     /*
384      * Cycle through the list of volumes and see if we should create a backup
385      * for each individual volume
386      */
387
388     for (i = 0; i < nentries; i++) {
389         entry = &arrayEntries.nbulkentries_val[i];
390
391         /*
392          * Skip entries that don't have a RW volume
393          */
394
395         if (!(entry->flags & RW_EXISTS)) {
396             if (callBack != NULL) {
397                 const char *messageText;
398                 if (util_AdminErrorCodeTranslate
399                     (ADMVOSVOLUMENOREADWRITE, 0, &messageText, &tst)) {
400                     sprintf(backbuf, "%s %s", messageText, entry->name);
401                     (**callBack) (VOS_VERBOSE_MESSAGE, backbuf);
402                 }
403             }
404             continue;
405         }
406
407         /*
408          * See if we should skip this entry because of the prefix/exclude
409          * combination we've been passed
410          */
411
412         if (prefix) {
413             if (exclude) {
414                 if (!strncmp(entry->name, volumePrefix, prefix_len)) {
415                     continue;
416                 }
417             } else {
418                 if (strncmp(entry->name, volumePrefix, prefix_len)) {
419                     continue;
420                 }
421             }
422         }
423
424         rw_volid = entry->volumeId[RWVOL];
425         GetServerAndPart(entry, RWVOL, &rw_server, &rw_partition, &previdx);
426
427         if ((rw_server == -1) || (rw_partition == -1)) {
428             if (callBack != NULL) {
429                 const char *messageText;
430                 if (util_AdminErrorCodeTranslate
431                     (ADMVOSVLDBBADENTRY, 0, &messageText, &tst)) {
432                     sprintf(backbuf, "%s %s", messageText, entry->name);
433                     (**callBack) (VOS_ERROR_MESSAGE, backbuf);
434                 }
435             }
436             continue;
437         }
438
439         /*
440          * Check that the RW volume is on the same server that we were
441          * passed
442          */
443
444         if (serverHandle != NULL) {
445             if (!VLDB_IsSameAddrs
446                 (c_handle, ntohl(rx_HostOf(rx_PeerOf(f_server->serv))),
447                  rw_server, &equal, &tst)) {
448                 if (callBack != NULL) {
449                     const char *messageText;
450                     if (util_AdminErrorCodeTranslate
451                         (ADMVOSVLDBBADSERVER, 0, &messageText, &tst)) {
452                         sprintf(backbuf, "%s %x %d", messageText,
453                                 ntohl(rx_HostOf(rx_PeerOf(f_server->serv))),
454                                 tst);
455                         (**callBack) (VOS_ERROR_MESSAGE, backbuf);
456                     }
457                 }
458                 continue;
459             }
460             if (!equal) {
461                 if (callBack != NULL) {
462                     const char *messageText;
463                     if (util_AdminErrorCodeTranslate
464                         (ADMVOSVLDBDIFFERENTADDR, 0, &messageText, &tst)) {
465                         sprintf(backbuf, "%s %s", messageText, entry->name);
466                         (**callBack) (VOS_ERROR_MESSAGE, backbuf);
467                     }
468                 }
469                 continue;
470             }
471         }
472
473         /*
474          * Check that the RW volume is on the same partition we were
475          * passed
476          */
477
478         if (partition != NULL) {
479             if (*partition != rw_partition) {
480                 continue;
481             }
482         }
483
484         /*
485          * Backup the volume
486          */
487
488         rc = UV_BackupVolume(c_handle, rw_server, rw_partition, rw_volid,
489                              &tst);
490     }
491
492   fail_vos_BackupVolumeCreateMultiple:
493
494     if (arrayEntries.nbulkentries_val) {
495         free(arrayEntries.nbulkentries_val);
496     }
497
498     if (st != NULL) {
499         *st = tst;
500     }
501     return rc;
502 }
503
504 /*
505  * vos_PartitionGet - get information about a single partition.
506  *
507  * PARAMETERS
508  *
509  * IN cellHandle - a previously opened cellHandle that corresponds
510  * to the cell where the server lives.
511  *
512  * IN serverHandle - a previously open vos server handle that holds
513  * the partition of interest.
514  *
515  * IN callBack - a call back function pointer that may be called to report
516  * status information.  Can be null.
517  *
518  * IN partition - the integer that represents the partition of interest.
519  *
520  * OUT partitionP - a pointer to a vos_partitionEntry_t that upon successful 
521  * completion contains information regarding the partition.
522  *
523  * LOCKS
524  * 
525  * No locks are obtained or released by this function
526  *
527  * RETURN CODES
528  *
529  * Returns != 0 upon successful completion.
530  */
531
532 int ADMINAPI
533 vos_PartitionGet(const void *cellHandle, const void *serverHandle,
534                  vos_MessageCallBack_t callBack, unsigned int partition,
535                  vos_partitionEntry_p partitionP, afs_status_p st)
536 {
537     int rc = 0;
538     afs_status_t tst = 0;
539     struct diskPartition part_info;
540     file_server_p f_server = (file_server_p) serverHandle;
541     char partitionName[10];     /* this rpc requires a character partition name */
542
543     /*
544      * Validate arguments
545      */
546
547     if (!IsValidServerHandle(f_server, &tst)) {
548         goto fail_vos_PartitionGet;
549     }
550
551     if (partitionP == NULL) {
552         tst = ADMVOSPARTITIONPNULL;
553         goto fail_vos_PartitionGet;
554     }
555
556     if (!vos_PartitionIdToName(partition, partitionName, &tst)) {
557         goto fail_vos_PartitionGet;
558     }
559
560     tst = AFSVolPartitionInfo(f_server->serv, partitionName, &part_info);
561     if (tst) {
562         goto fail_vos_PartitionGet;
563     }
564     strncpy(partitionP->name, part_info.name, VOS_MAX_PARTITION_NAME_LEN);
565     partitionP->name[VOS_MAX_PARTITION_NAME_LEN-1] = '\0';
566     strncpy(partitionP->deviceName, part_info.devName, VOS_MAX_PARTITION_NAME_LEN);
567     partitionP->deviceName[VOS_MAX_PARTITION_NAME_LEN-1] = '\0';
568     partitionP->lockFileDescriptor = part_info.lock_fd;
569     partitionP->totalSpace = part_info.minFree;
570     partitionP->totalFreeSpace = part_info.free;
571     rc = 1;
572
573   fail_vos_PartitionGet:
574
575     if (st != NULL) {
576         *st = tst;
577     }
578     return rc;
579 }
580
581 /*
582  * The iterator functions and data for the partition retrieval functions.
583  */
584
585 typedef struct partition_get {
586     afs_int32 total_received;   /* the total number of valid partiions retrieved */
587     int number_processed;       /* the number of valid paritions we've handed out */
588     int index;                  /* the current index into the part_list array */
589     struct partList part_list;  /* the list of partitions */
590     vos_partitionEntry_t partition[CACHED_ITEMS];       /* the cache of partitions */
591     const void *server;         /* the server where the parititions exist */
592 } partition_get_t, *partition_get_p;
593
594 static int
595 GetPartitionInfoRPC(void *rpc_specific, int slot, int *last_item,
596                     int *last_item_contains_data, afs_status_p st)
597 {
598     int rc = 0;
599     afs_status_t tst = 0;
600     partition_get_p part = (partition_get_p) rpc_specific;
601     vos_partitionEntry_p ptr = (vos_partitionEntry_p) & part->partition[slot];
602
603     /*
604      * Skip partition entries that are not valid
605      */
606
607     while (!(part->part_list.partFlags[part->index] & PARTVALID)) {
608         part->index++;
609     }
610
611     /*
612      * Get information for the next partition
613      */
614
615     if (!vos_PartitionGet
616         (0, part->server, 0,
617          (unsigned int)part->part_list.partId[part->index], ptr, &tst)) {
618         goto fail_GetPartitionInfoRPC;
619     }
620
621     part->index++;
622     part->number_processed++;
623
624     if (part->number_processed == part->total_received) {
625         *last_item = 1;
626         *last_item_contains_data = 1;
627     }
628     rc = 1;
629
630   fail_GetPartitionInfoRPC:
631
632     if (st != NULL) {
633         *st = tst;
634     }
635     return rc;
636 }
637
638 static int
639 GetPartitionInfoFromCache(void *rpc_specific, int slot, void *dest,
640                           afs_status_p st)
641 {
642     int rc = 0;
643     afs_status_t tst = 0;
644     partition_get_p part = (partition_get_p) rpc_specific;
645
646     memcpy(dest, (const void *)&part->partition[slot],
647            sizeof(vos_partitionEntry_t));
648     rc = 1;
649
650     if (st != NULL) {
651         *st = tst;
652     }
653     return rc;
654 }
655
656 /*
657  * vos_PartitionGetBegin - begin to iterate over the partitions at a 
658  * particular server.
659  *
660  * PARAMETERS
661  *
662  * IN cellHandle - a previously opened cellHandle that corresponds
663  * to the cell where the server exists.
664  *
665  * IN serverHandle - the server that houses the partitions of interest.
666  *
667  * IN callBack - a call back function pointer that may be called to report
668  * status information.  Can be null.
669  *
670  * OUT iterationIdP - upon successful completion, contains an iterator that can
671  * be passed to vos_PartitionGetNext.
672  *
673  * LOCKS
674  * 
675  * No locks are obtained or released by this function
676  *
677  * RETURN CODES
678  *
679  * Returns != 0 upon successful completion.
680  */
681
682 int ADMINAPI
683 vos_PartitionGetBegin(const void *cellHandle, const void *serverHandle,
684                       vos_MessageCallBack_t callBack, void **iterationIdP,
685                       afs_status_p st)
686 {
687     int rc = 0;
688     afs_status_t tst = 0;
689     file_server_p f_server = (file_server_p) serverHandle;
690     afs_admin_iterator_p iter =
691         (afs_admin_iterator_p) malloc(sizeof(afs_admin_iterator_t));
692     partition_get_p part = calloc(1, sizeof(partition_get_t));
693
694     /*
695      * Validate arguments
696      */
697
698     if (!IsValidServerHandle(f_server, &tst)) {
699         goto fail_vos_PartitionGetBegin;
700     }
701
702     if (iterationIdP == NULL) {
703         goto fail_vos_PartitionGetBegin;
704     }
705
706     if ((iter == NULL) || (part == NULL)) {
707         tst = ADMNOMEM;
708         goto fail_vos_PartitionGetBegin;
709     }
710
711     /*
712      * Fill in the part structure
713      */
714
715     part->server = serverHandle;
716     if (!UV_ListPartitions
717         (f_server->serv, &part->part_list, &part->total_received, &tst)) {
718         goto fail_vos_PartitionGetBegin;
719     }
720
721     /*
722      * If we didn't receive any partitions, don't spawn a background thread.
723      * Mark the iterator complete.
724      */
725
726     if (part->total_received == 0) {
727         if (!IteratorInit(iter, (void *)part, NULL, NULL, NULL, NULL, &tst)) {
728             goto fail_vos_PartitionGetBegin;
729         }
730         iter->done_iterating = 1;
731         iter->st = ADMITERATORDONE;
732     } else {
733         if (!IteratorInit
734             (iter, (void *)part, GetPartitionInfoRPC,
735              GetPartitionInfoFromCache, NULL, NULL, &tst)) {
736             goto fail_vos_PartitionGetBegin;
737         }
738     }
739     *iterationIdP = (void *)iter;
740     rc = 1;
741
742   fail_vos_PartitionGetBegin:
743
744     if (rc == 0) {
745         if (iter != NULL) {
746             free(iter);
747         }
748         if (part != NULL) {
749             free(part);
750         }
751     }
752
753     if (st != NULL) {
754         *st = tst;
755     }
756     return rc;
757 }
758
759 /*
760  * vos_PartitionGetNext - get the next partition at a server.
761  *
762  * PARAMETERS
763  *
764  * IN iterationId - an iterator previously returned by vos_PartitionGetBegin
765  *
766  * OUT partitionP - a pointer to a vos_partitionEntry_t that upon successful
767  * completion contains the next partition.
768  *
769  * LOCKS
770  * 
771  * The iterator is locked while the next parition is retrieved.
772  *
773  * RETURN CODES
774  *
775  * Returns != 0 upon successful completion.
776  */
777
778 int ADMINAPI
779 vos_PartitionGetNext(const void *iterationId, vos_partitionEntry_p partitionP,
780                      afs_status_p st)
781 {
782     int rc = 0;
783     afs_status_t tst = 0;
784     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
785
786     if (iter == NULL) {
787         tst = ADMITERATORNULL;
788         goto fail_vos_PartitionGetNext;
789     }
790
791     if (partitionP == NULL) {
792         tst = ADMVOSPARTITIONPNULL;
793         goto fail_vos_PartitionGetNext;
794     }
795
796     rc = IteratorNext(iter, (void *)partitionP, &tst);
797
798   fail_vos_PartitionGetNext:
799
800     if (st != NULL) {
801         *st = tst;
802     }
803     return rc;
804 }
805
806 /*
807  * vos_PartitionGetDone - finish using a partition iterator.
808  *
809  * PARAMETERS
810  *
811  * IN iterationId - an iterator previously returned by vos_PartitionGetBegin
812  *
813  * LOCKS
814  * 
815  * The iterator is locked and then destroyed.
816  *
817  * RETURN CODES
818  *
819  * Returns != 0 upon successful completion.
820  */
821
822 int ADMINAPI
823 vos_PartitionGetDone(const void *iterationId, afs_status_p st)
824 {
825     int rc = 0;
826     afs_status_t tst = 0;
827     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
828
829     /*
830      * Validate arguments
831      */
832
833     if (iter == NULL) {
834         tst = ADMITERATORNULL;
835         goto fail_vos_PartitionGetDone;
836     }
837
838     rc = IteratorDone(iter, &tst);
839
840   fail_vos_PartitionGetDone:
841
842     if (st != NULL) {
843         *st = tst;
844     }
845     return rc;
846 }
847
848 /*
849  * vos_ServerOpen - open a handle to an individual server for future
850  * operations
851  *
852  * PARAMETERS
853  *
854  * IN cellHandle - a previously opened cellHandle that corresponds
855  * to the cell where the server lives.
856  *
857  * IN serverName - the machine name of the server
858  *
859  * OUT serverHandleP - a void pointer that upon successful completion 
860  * contains a handle that is used in future operations upon the server.
861  *
862  * LOCKS
863  * 
864  * No locks are obtained or released by this function
865  *
866  * RETURN CODES
867  *
868  * Returns != 0 upon successful completion.
869  */
870
871 int ADMINAPI
872 vos_ServerOpen(const void *cellHandle, const char *serverName,
873                void **serverHandleP, afs_status_p st)
874 {
875     int rc = 0;
876     afs_status_t tst = 0;
877     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
878     file_server_p f_server = (file_server_p) malloc(sizeof(file_server_t));
879     int server_address;
880     struct rx_securityClass *sc[3];
881     int scIndex;
882
883     if (f_server == NULL) {
884         tst = ADMNOMEM;
885         goto fail_vos_ServerOpen;
886     }
887
888     /*
889      * Validate arguments
890      */
891
892     if (!IsValidCellHandle(c_handle, &tst)) {
893         goto fail_vos_ServerOpen;
894     }
895
896     if (!c_handle->tokens->afs_token_set) {
897         tst = ADMVOSCELLHANDLENOAFSTOKENS;
898         goto fail_vos_ServerOpen;
899     }
900
901     if (!util_AdminServerAddressGetFromName
902         (serverName, &server_address, &tst)) {
903         goto fail_vos_ServerOpen;
904     }
905
906     scIndex = c_handle->tokens->sc_index;
907     sc[scIndex] = c_handle->tokens->afs_sc[scIndex];
908     f_server->serv =
909         rx_GetCachedConnection(htonl(server_address),
910                                htons(AFSCONF_VOLUMEPORT), VOLSERVICE_ID,
911                                sc[scIndex], scIndex);
912     if (f_server->serv != NULL) {
913         f_server->begin_magic = BEGIN_MAGIC;
914         f_server->end_magic = END_MAGIC;
915         f_server->is_valid = 1;
916         *serverHandleP = (void *)f_server;
917         rc = 1;
918     } else {
919         tst = ADMVOSSERVERNOCONNECTION;
920         goto fail_vos_ServerOpen;
921     }
922
923   fail_vos_ServerOpen:
924
925     if (st != NULL) {
926         *st = tst;
927     }
928     return rc;
929 }
930
931 /*
932  * vos_ServerClose - close a handle previously obtained from vos_ServerOpen
933  *
934  * PARAMETERS
935  *
936  * IN serverHandle - an existing server handle.
937  *
938  * LOCKS
939  * 
940  * No locks are obtained or released by this function
941  *
942  * RETURN CODES
943  *
944  * Returns != 0 upon successful completion.
945  */
946
947 int ADMINAPI
948 vos_ServerClose(const void *serverHandle, afs_status_p st)
949 {
950     int rc = 0;
951     afs_status_t tst = 0;
952     file_server_p f_server = (file_server_p) serverHandle;
953
954     if (!IsValidServerHandle(f_server, &tst)) {
955         goto fail_vos_ServerClose;
956     }
957
958     rx_ReleaseCachedConnection(f_server->serv);
959     f_server->is_valid = 0;
960     free(f_server);
961     rc = 1;
962
963   fail_vos_ServerClose:
964
965     if (st != NULL) {
966         *st = tst;
967     }
968     return rc;
969 }
970
971 /*
972  * vos_ServerSync - synchronize the vldb and the fileserver at a particular
973  * server.
974  *
975  * PARAMETERS
976  *
977  * IN cellHandle - a previously opened cellHandle that corresponds
978  * to the cell where the server lives.
979  *
980  * IN serverHandle - a handle to the server machine.
981  *
982  * IN callBack - a call back function pointer that may be called to report
983  * status information.  Can be null.
984  *
985  * IN partition - the partition to synchronize.  Can be NULL.
986  *
987  * IN force - force deletion of bad volumes.
988  *
989  * LOCKS
990  * 
991  * No locks are obtained or released by this function
992  *
993  * RETURN CODES
994  *
995  * Returns != 0 upon successful completion.
996  */
997
998 int ADMINAPI
999 vos_ServerSync(const void *cellHandle, const void *serverHandle,
1000                vos_MessageCallBack_t callBack, const unsigned int *partition,
1001                afs_status_p st)
1002 {
1003     int rc = 0;
1004     afs_status_t tst = 0;
1005     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1006     file_server_p f_server = (file_server_p) serverHandle;
1007     afs_int32 part = 0;
1008     int flags = 0;
1009
1010     /*
1011      * Validate arguments
1012      */
1013
1014     if (!IsValidCellHandle(c_handle, &tst)) {
1015         goto fail_vos_ServerSync;
1016     }
1017
1018     if (!IsValidServerHandle(f_server, &tst)) {
1019         goto fail_vos_ServerSync;
1020     }
1021
1022     if (partition != NULL) {
1023         if (*partition > VOLMAXPARTS) {
1024             tst = ADMVOSPARTITIONTOOLARGE;
1025             goto fail_vos_ServerSync;
1026         }
1027         part = (afs_int32) * partition;
1028         flags = 1;
1029     }
1030
1031     /*
1032      * sync the server
1033      */
1034
1035     rc = UV_SyncServer(c_handle, f_server->serv, part, flags, &tst);
1036
1037   fail_vos_ServerSync:
1038
1039     if (st != NULL) {
1040         *st = tst;
1041     }
1042     return rc;
1043 }
1044
1045 /*
1046  * vos_FileServerAddressChange - change an existing file server address.
1047  *
1048  * PARAMETERS
1049  *
1050  * IN cellHandle - a previously opened cellHandle that corresponds
1051  * to the cell where the address should be changed.
1052  *
1053  * IN callBack - a call back function pointer that may be called to report
1054  * status information.  Can be null.
1055  *
1056  * IN oldAddress - the old server address in host byte order
1057  *
1058  * IN newAddress - the new server address in host byte order
1059  *
1060  * LOCKS
1061  * 
1062  * No locks are obtained or released by this function
1063  *
1064  * RETURN CODES
1065  *
1066  * Returns != 0 upon successful completion.
1067  */
1068
1069 int ADMINAPI
1070 vos_FileServerAddressChange(const void *cellHandle,
1071                             vos_MessageCallBack_t callBack,
1072                             unsigned int oldAddress,
1073                             unsigned int newAddress, afs_status_p st)
1074 {
1075     int rc = 0;
1076     afs_status_t tst = 0;
1077     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1078
1079     /*
1080      * Validate arguments
1081      */
1082
1083     if (!IsValidCellHandle(c_handle, &tst)) {
1084         goto fail_vos_FileServerAddressChange;
1085     }
1086
1087     tst =
1088         ubik_VL_ChangeAddr(c_handle->vos, 0, oldAddress, newAddress);
1089     if (tst) {
1090         goto fail_vos_FileServerAddressChange;
1091     }
1092     rc = 1;
1093
1094   fail_vos_FileServerAddressChange:
1095
1096     if (st != NULL) {
1097         *st = tst;
1098     }
1099     return rc;
1100 }
1101
1102 /*
1103  * vos_FileServerAddressRemove - remove an existing file server address.
1104  *
1105  * PARAMETERS
1106  *
1107  * IN cellHandle - a previously opened cellHandle that corresponds
1108  * to the cell where the address should be removed.
1109  *
1110  * IN callBack - a call back function pointer that may be called to report
1111  * status information.  Can be null.
1112  *
1113  * IN serverAddress - the server address to remove in host byte order.
1114  *
1115  * LOCKS
1116  * 
1117  * No locks are obtained or released by this function
1118  *
1119  * RETURN CODES
1120  *
1121  * Returns != 0 upon successful completion.
1122  */
1123
1124 int ADMINAPI
1125 vos_FileServerAddressRemove(const void *cellHandle,
1126                             vos_MessageCallBack_t callBack,
1127                             unsigned int serverAddress,
1128                             afs_status_p st)
1129 {
1130     int rc = 0;
1131     afs_status_t tst = 0;
1132     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1133     unsigned int dummyAddress = 0xffffffff;
1134
1135     /*
1136      * Validate arguments
1137      */
1138
1139     if (!IsValidCellHandle(c_handle, &tst)) {
1140         goto fail_vos_FileServerAddressRemove;
1141     }
1142
1143     tst =
1144         ubik_VL_ChangeAddr(c_handle->vos, 0, dummyAddress,
1145                       serverAddress);
1146     if (tst) {
1147         goto fail_vos_FileServerAddressRemove;
1148     }
1149     rc = 1;
1150
1151   fail_vos_FileServerAddressRemove:
1152
1153     if (st != NULL) {
1154         *st = tst;
1155     }
1156     return rc;
1157 }
1158
1159 /*
1160  * The iterator functions and data for the server retrieval functions.
1161  *
1162  * These functions are very similar to the FileServerAddressGet
1163  * functions.  The main difference being that instead of returning
1164  * a single address at a time for a server, we fill an array with
1165  * all the addresses of a server.
1166  */
1167
1168 typedef struct server_get {
1169     struct ubik_client *vldb;   /* connection for future rpc's if neccessary */
1170     afs_int32 total_addresses;  /* total number of addresses */
1171     bulkaddrs addresses;        /* the list of addresses */
1172     int address_index;          /* current index into address list */
1173     vos_fileServerEntry_t server[CACHED_ITEMS]; /* the cache of servers */
1174 } server_get_t, *server_get_p;
1175
1176 static int
1177 GetServerRPC(void *rpc_specific, int slot, int *last_item,
1178              int *last_item_contains_data, afs_status_p st)
1179 {
1180     int rc = 0;
1181     afs_status_t tst = 0;
1182     server_get_p serv = (server_get_p) rpc_specific;
1183     afs_uint32 *addrP = &serv->addresses.bulkaddrs_val[serv->address_index];
1184     afs_int32 base, index;
1185     afsUUID m_uuid;
1186     afs_int32 m_unique;
1187     ListAddrByAttributes m_attrs;
1188     afs_int32 total_multi;
1189     bulkaddrs addr_multi;
1190     int i;
1191
1192     /*
1193      * Check to see if this is a multihomed address server
1194      */
1195
1196     if (((*addrP & 0xff000000) == 0xff000000) && ((*addrP) & 0xffff)) {
1197         base = (*addrP >> 16) & 0xff;
1198         index = (*addrP) & 0xffff;
1199
1200         if ((base >= 0) && (base <= VL_MAX_ADDREXTBLKS) && (index >= 1)
1201             && (index <= VL_MHSRV_PERBLK)) {
1202
1203             /*
1204              * This is a multihomed server.  Make an rpc to retrieve
1205              * all its addresses.  Copy the addresses into the cache.
1206              */
1207
1208             m_attrs.Mask = VLADDR_INDEX;
1209             m_attrs.index = (base * VL_MHSRV_PERBLK) + index;
1210             total_multi = 0;
1211             addr_multi.bulkaddrs_val = 0;
1212             addr_multi.bulkaddrs_len = 0;
1213             tst =
1214                 ubik_VL_GetAddrsU(serv->vldb, 0, &m_attrs, &m_uuid,
1215                           &m_unique, &total_multi, &addr_multi);
1216             if (tst) {
1217                 goto fail_GetServerRPC;
1218             }
1219
1220             /*
1221              * Remove any bogus IP addresses which the user may have
1222              * been unable to remove.
1223              */
1224
1225             RemoveBadAddresses(&total_multi, &addr_multi);
1226
1227             /*
1228              * Copy all the addresses into the cache
1229              */
1230
1231             for (i = 0; i < total_multi; i++) {
1232                 serv->server[slot].serverAddress[i] =
1233                     addr_multi.bulkaddrs_val[i];
1234             }
1235
1236             serv->server[slot].count = total_multi;
1237             serv->address_index++;
1238             free(addr_multi.bulkaddrs_val);
1239         }
1240
1241         /*
1242          * The next address is just a plain old address
1243          */
1244
1245     } else {
1246         serv->server[slot].serverAddress[0] = *addrP;
1247         serv->server[slot].count = 1;
1248         serv->address_index++;
1249     }
1250
1251     /*
1252      * See if we've processed all the entries
1253      */
1254
1255
1256     if (serv->address_index == serv->total_addresses) {
1257         *last_item = 1;
1258         *last_item_contains_data = 1;
1259     }
1260     rc = 1;
1261
1262   fail_GetServerRPC:
1263
1264     if (st != NULL) {
1265         *st = tst;
1266     }
1267     return rc;
1268 }
1269
1270 static int
1271 GetServerFromCache(void *rpc_specific, int slot, void *dest, afs_status_p st)
1272 {
1273     int rc = 0;
1274     afs_status_t tst = 0;
1275     server_get_p serv = (server_get_p) rpc_specific;
1276
1277     memcpy(dest, (const void *)&serv->server[slot],
1278            sizeof(vos_fileServerEntry_t));
1279     rc = 1;
1280
1281     if (st != NULL) {
1282         *st = tst;
1283     }
1284     return rc;
1285 }
1286
1287
1288 static int
1289 DestroyServer(void *rpc_specific, afs_status_p st)
1290 {
1291     int rc = 0;
1292     afs_status_t tst = 0;
1293     server_get_p serv = (server_get_p) rpc_specific;
1294
1295     if (serv->addresses.bulkaddrs_val != NULL) {
1296         free(serv->addresses.bulkaddrs_val);
1297     }
1298     rc = 1;
1299
1300     if (st != NULL) {
1301         *st = tst;
1302     }
1303     return rc;
1304 }
1305
1306 /*
1307  * vos_FileServerGetBegin - begin to iterate over the file servers in a cell.
1308  *
1309  * PARAMETERS
1310  *
1311  * IN cellHandle - a previously opened cellHandle that corresponds
1312  * to the cell where the file servers exist.
1313  *
1314  * IN callBack - a call back function pointer that may be called to report
1315  * status information.  Can be null.
1316  *
1317  * OUT iterationIdP - upon successful completion, contains an iterator that
1318  * can be passed to vos_FileServerGetNext.
1319  *
1320  * LOCKS
1321  * 
1322  * No locks are obtained or released by this function
1323  *
1324  * RETURN CODES
1325  *
1326  * Returns != 0 upon successful completion.
1327  */
1328
1329 int ADMINAPI
1330 vos_FileServerGetBegin(const void *cellHandle, vos_MessageCallBack_t callBack,
1331                        void **iterationIdP, afs_status_p st)
1332 {
1333     int rc = 0;
1334     afs_status_t tst = 0;
1335     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1336     afs_admin_iterator_p iter =
1337         (afs_admin_iterator_p) malloc(sizeof(afs_admin_iterator_t));
1338     server_get_p serv = calloc(1, sizeof(server_get_t));
1339     struct VLCallBack unused;
1340
1341
1342     /*
1343      * Validate arguments
1344      */
1345
1346     if (!IsValidCellHandle(c_handle, &tst)) {
1347         goto fail_vos_FileServerGetBegin;
1348     }
1349
1350     if (iterationIdP == NULL) {
1351         goto fail_vos_FileServerGetBegin;
1352     }
1353
1354     if ((iter == NULL) || (serv == NULL)) {
1355         tst = ADMNOMEM;
1356         goto fail_vos_FileServerGetBegin;
1357     }
1358
1359     /*
1360      * Fill in the serv structure
1361      */
1362
1363     serv->vldb = c_handle->vos;
1364     tst =
1365         ubik_VL_GetAddrs(c_handle->vos, 0, 0, 0, &unused,
1366                       &serv->total_addresses, &serv->addresses);
1367
1368     if (tst) {
1369         goto fail_vos_FileServerGetBegin;
1370     }
1371
1372     /*
1373      * Remove any bogus IP addresses which the user may have
1374      * been unable to remove.
1375      */
1376
1377     RemoveBadAddresses(&serv->total_addresses, &serv->addresses);
1378
1379     if (serv->total_addresses == 0) {
1380         if (!IteratorInit(iter, (void *)serv, NULL, NULL, NULL, NULL, &tst)) {
1381             goto fail_vos_FileServerGetBegin;
1382         }
1383         iter->done_iterating = 1;
1384         iter->st = ADMITERATORDONE;
1385     } else {
1386         if (!IteratorInit
1387             (iter, (void *)serv, GetServerRPC, GetServerFromCache, NULL,
1388              DestroyServer, &tst)) {
1389             goto fail_vos_FileServerGetBegin;
1390         }
1391     }
1392     *iterationIdP = (void *)iter;
1393     rc = 1;
1394
1395   fail_vos_FileServerGetBegin:
1396
1397     if (rc == 0) {
1398         if (iter != NULL) {
1399             free(iter);
1400         }
1401         if (serv != NULL) {
1402             if (serv->addresses.bulkaddrs_val != NULL) {
1403                 free(serv->addresses.bulkaddrs_val);
1404             }
1405             free(serv);
1406         }
1407     }
1408
1409     if (st != NULL) {
1410         *st = tst;
1411     }
1412     return rc;
1413 }
1414
1415 /*
1416  * vos_FileServerGetNext - get information about the next fileserver in the cell.
1417  *
1418  * PARAMETERS
1419  *
1420  * IN iterationId - an iterator previously returned by
1421  * vos_FileServerGetBegin
1422  *
1423  * OUT serverEntryP - a pointer to a vos_fileServerEntry_t that upon successful
1424  * completion contains information about the next server in the cell.
1425  *
1426  * LOCKS
1427  * 
1428  * The iterator is locked while the next server is retrieved.
1429  *
1430  * RETURN CODES
1431  *
1432  * Returns != 0 upon successful completion.
1433  */
1434
1435 int ADMINAPI
1436 vos_FileServerGetNext(void *iterationId, vos_fileServerEntry_p serverEntryP,
1437                       afs_status_p st)
1438 {
1439     int rc = 0;
1440     afs_status_t tst = 0;
1441     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
1442
1443     if (iter == NULL) {
1444         tst = ADMITERATORNULL;
1445         goto fail_vos_FileServerGetNext;
1446     }
1447
1448     if (serverEntryP == NULL) {
1449         tst = ADMVOSSERVERENTRYPNULL;
1450         goto fail_vos_FileServerGetNext;
1451     }
1452
1453     rc = IteratorNext(iter, (void *)serverEntryP, &tst);
1454
1455   fail_vos_FileServerGetNext:
1456
1457     if (st != NULL) {
1458         *st = tst;
1459     }
1460     return rc;
1461 }
1462
1463 /*
1464  * vos_FileServerGetDone - finish using a partition iterator.
1465  *
1466  * PARAMETERS
1467  *
1468  * IN iterationId - an iterator previously returned by vos_FileServerGetBegin
1469  *
1470  * LOCKS
1471  * 
1472  * The iterator is locked and then destroyed.
1473  *
1474  * RETURN CODES
1475  *
1476  * Returns != 0 upon successful completion.
1477  */
1478
1479 int ADMINAPI
1480 vos_FileServerGetDone(void *iterationId, afs_status_p st)
1481 {
1482     int rc = 0;
1483     afs_status_t tst = 0;
1484     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
1485
1486     /*
1487      * Validate arguments
1488      */
1489
1490     if (iter == NULL) {
1491         tst = ADMITERATORNULL;
1492         goto fail_vos_FileServerGetDone;
1493     }
1494
1495     rc = IteratorDone(iter, &tst);
1496
1497   fail_vos_FileServerGetDone:
1498
1499     if (st != NULL) {
1500         *st = tst;
1501     }
1502     return rc;
1503 }
1504
1505 /*
1506  * The iterator functions and data for the transation retrieval functions.
1507  */
1508
1509 typedef struct transaction_get {
1510     afs_int32 total;            /* total number of transactions */
1511     afs_int32 index;            /* index to the current transaction */
1512     transDebugInfo *cur;        /* the current transaction */
1513     vos_serverTransactionStatus_t tran[CACHED_ITEMS];   /* the cache of trans */
1514 } transaction_get_t, *transaction_get_p;
1515
1516 static int
1517 GetTransactionRPC(void *rpc_specific, int slot, int *last_item,
1518                   int *last_item_contains_data, afs_status_p st)
1519 {
1520     int rc = 0;
1521     afs_status_t tst = 0;
1522     transaction_get_p t = (transaction_get_p) rpc_specific;
1523     int index = t->index;
1524
1525     /*
1526      * Copy the next transaction into the cache
1527      */
1528
1529     t->tran[slot].transactionId = t->cur[index].tid;
1530     t->tran[slot].lastActiveTime = t->cur[index].time;
1531     t->tran[slot].creationTime = t->cur[index].creationTime;
1532     t->tran[slot].errorCode = t->cur[index].returnCode;
1533     t->tran[slot].volumeId = t->cur[index].volid;
1534     t->tran[slot].partition = t->cur[index].partition;
1535     strcpy(t->tran[slot].lastProcedureName, t->cur[index].lastProcName);
1536     t->tran[slot].nextReceivePacketSequenceNumber = t->cur[index].readNext;
1537     t->tran[slot].nextSendPacketSequenceNumber = t->cur[index].transmitNext;
1538     t->tran[slot].lastReceiveTime = t->cur[index].lastReceiveTime;
1539     t->tran[slot].lastSendTime = t->cur[index].lastSendTime;
1540
1541     t->tran[slot].volumeAttachMode = VOS_VOLUME_ATTACH_MODE_OK;
1542
1543     switch (t->cur[index].iflags) {
1544     case ITOffline:
1545         t->tran[slot].volumeAttachMode = VOS_VOLUME_ATTACH_MODE_OFFLINE;
1546         break;
1547     case ITBusy:
1548         t->tran[slot].volumeAttachMode = VOS_VOLUME_ATTACH_MODE_BUSY;
1549         break;
1550     case ITReadOnly:
1551         t->tran[slot].volumeAttachMode = VOS_VOLUME_ATTACH_MODE_READONLY;
1552         break;
1553     case ITCreate:
1554         t->tran[slot].volumeAttachMode = VOS_VOLUME_ATTACH_MODE_CREATE;
1555         break;
1556     case ITCreateVolID:
1557         t->tran[slot].volumeAttachMode = VOS_VOLUME_ATTACH_MODE_CREATE_VOLID;
1558         break;
1559     }
1560
1561     t->tran[slot].volumeActiveStatus = VOS_VOLUME_ACTIVE_STATUS_OK;
1562
1563     switch (t->cur[index].vflags) {
1564     case VTDeleteOnSalvage:
1565         t->tran[slot].volumeActiveStatus =
1566             VOS_VOLUME_ACTIVE_STATUS_DELETE_ON_SALVAGE;
1567         break;
1568     case VTOutOfService:
1569         t->tran[slot].volumeActiveStatus =
1570             VOS_VOLUME_ACTIVE_STATUS_OUT_OF_SERVICE;
1571         break;
1572     case VTDeleted:
1573         t->tran[slot].volumeActiveStatus = VOS_VOLUME_ACTIVE_STATUS_DELETED;
1574         break;
1575     }
1576
1577     t->tran[slot].volumeTransactionStatus = VOS_VOLUME_TRANSACTION_STATUS_OK;
1578
1579     if (t->cur[index].tflags) {
1580         t->tran[slot].volumeTransactionStatus =
1581             VOS_VOLUME_TRANSACTION_STATUS_DELETED;
1582     }
1583     t->index++;
1584
1585
1586     /*
1587      * See if we've processed all the entries
1588      */
1589
1590
1591     if (t->index == t->total) {
1592         *last_item = 1;
1593         *last_item_contains_data = 1;
1594     }
1595     rc = 1;
1596
1597     if (st != NULL) {
1598         *st = tst;
1599     }
1600     return rc;
1601 }
1602
1603 static int
1604 GetTransactionFromCache(void *rpc_specific, int slot, void *dest,
1605                         afs_status_p st)
1606 {
1607     int rc = 0;
1608     afs_status_t tst = 0;
1609     transaction_get_p tran = (transaction_get_p) rpc_specific;
1610
1611     memcpy(dest, (const void *)&tran->tran[slot],
1612            sizeof(vos_serverTransactionStatus_p));
1613     rc = 1;
1614
1615     if (st != NULL) {
1616         *st = tst;
1617     }
1618     return rc;
1619 }
1620
1621
1622 static int
1623 DestroyTransaction(void *rpc_specific, afs_status_p st)
1624 {
1625     int rc = 0;
1626     afs_status_t tst = 0;
1627     transaction_get_p tran = (transaction_get_p) rpc_specific;
1628
1629     if (tran->cur != NULL) {
1630         free(tran->cur);
1631     }
1632     rc = 1;
1633
1634     if (st != NULL) {
1635         *st = tst;
1636     }
1637     return rc;
1638 }
1639
1640 /*
1641  * vos_ServerTransactionStatusGetBegin - begin to iterate over the transactions
1642  * at a volume server.
1643  *
1644  * PARAMETERS
1645  *
1646  * IN cellHandle - a previously opened cellHandle that corresponds
1647  * to the cell where the volume server exists.
1648  *
1649  * IN serverHandle - a handle to the server to query.
1650  *
1651  * IN callBack - a call back function pointer that may be called to report
1652  * status information.  Can be null.
1653  *
1654  * OUT iterationIdP - upon successful completion, contains an iterator that
1655  * can be passed to vos_ServerTransactionStatusGetNext.
1656  *
1657  * LOCKS
1658  * 
1659  * No locks are obtained or released by this function
1660  *
1661  * RETURN CODES
1662  *
1663  * Returns != 0 upon successful completion.
1664  */
1665
1666 int ADMINAPI
1667 vos_ServerTransactionStatusGetBegin(const void *cellHandle,
1668                                     const void *serverHandle,
1669                                     vos_MessageCallBack_t callBack,
1670                                     void **iterationIdP, afs_status_p st)
1671 {
1672     int rc = 0;
1673     afs_status_t tst = 0;
1674     file_server_p f_server = (file_server_p) serverHandle;
1675     afs_admin_iterator_p iter =
1676         (afs_admin_iterator_p) malloc(sizeof(afs_admin_iterator_t));
1677     transaction_get_p tran = calloc(1, sizeof(transaction_get_t));
1678
1679
1680     /*
1681      * Validate arguments
1682      */
1683
1684     if (!IsValidServerHandle(f_server, &tst)) {
1685         goto fail_vos_ServerTransactionStatusGetBegin;
1686     }
1687
1688     if (iterationIdP == NULL) {
1689         goto fail_vos_ServerTransactionStatusGetBegin;
1690     }
1691
1692     if ((iter == NULL) || (tran == NULL)) {
1693         tst = ADMNOMEM;
1694         goto fail_vos_ServerTransactionStatusGetBegin;
1695     }
1696
1697     /*
1698      * Fill in the tran structure
1699      */
1700
1701     if (!UV_VolserStatus(f_server->serv, &tran->cur, &tran->total, &tst)) {
1702         goto fail_vos_ServerTransactionStatusGetBegin;
1703     }
1704
1705     if (tran->total == 0) {
1706         if (!IteratorInit(iter, (void *)tran, NULL, NULL, NULL, NULL, &tst)) {
1707             goto fail_vos_ServerTransactionStatusGetBegin;
1708         }
1709         iter->done_iterating = 1;
1710         iter->st = ADMITERATORDONE;
1711     } else {
1712         if (!IteratorInit
1713             (iter, (void *)tran, GetTransactionRPC, GetTransactionFromCache,
1714              NULL, DestroyTransaction, &tst)) {
1715             goto fail_vos_ServerTransactionStatusGetBegin;
1716         }
1717     }
1718     *iterationIdP = (void *)iter;
1719     rc = 1;
1720
1721   fail_vos_ServerTransactionStatusGetBegin:
1722
1723     if (rc == 0) {
1724         if (iter != NULL) {
1725             free(iter);
1726         }
1727         if (tran != NULL) {
1728             if (tran->cur != NULL) {
1729                 free(tran->cur);
1730             }
1731             free(tran);
1732         }
1733     }
1734
1735     if (st != NULL) {
1736         *st = tst;
1737     }
1738     return rc;
1739 }
1740
1741 /*
1742  * vos_ServerTransactionStatusGetNext - get information about the next 
1743  * active transaction.
1744  *
1745  * PARAMETERS
1746  *
1747  * IN iterationId - an iterator previously returned by
1748  * vos_ServerTransactionStatusGetBegin
1749  *
1750  * OUT serverTransactionStatusP - a pointer to a vos_serverTransactionStatus_p
1751  * that upon successful completion contains information about the
1752  * next transaction.
1753  *
1754  * LOCKS
1755  * 
1756  * The iterator is locked while the next item is retrieved.
1757  *
1758  * RETURN CODES
1759  *
1760  * Returns != 0 upon successful completion.
1761  */
1762
1763 int ADMINAPI
1764 vos_ServerTransactionStatusGetNext(const void *iterationId,
1765                                    vos_serverTransactionStatus_p
1766                                    serverTransactionStatusP, afs_status_p st)
1767 {
1768     int rc = 0;
1769     afs_status_t tst = 0;
1770     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
1771
1772     if (iter == NULL) {
1773         tst = ADMITERATORNULL;
1774         goto fail_vos_ServerTransactionStatusGetNext;
1775     }
1776
1777     if (serverTransactionStatusP == NULL) {
1778         tst = ADMVOSSERVERTRANSACTIONSTATUSPNULL;
1779         goto fail_vos_ServerTransactionStatusGetNext;
1780     }
1781
1782     rc = IteratorNext(iter, (void *)serverTransactionStatusP, &tst);
1783
1784   fail_vos_ServerTransactionStatusGetNext:
1785
1786     if (st != NULL) {
1787         *st = tst;
1788     }
1789     return rc;
1790 }
1791
1792 /*
1793  * vos_ServerTransactionStatusGetDone - finish using a transaction iterator.
1794  *
1795  * PARAMETERS
1796  *
1797  * IN iterationId - an iterator previously returned by
1798  * vos_ServerTransactionStatusGetBegin
1799  *
1800  * LOCKS
1801  * 
1802  * The iterator is locked and then destroyed.
1803  *
1804  * RETURN CODES
1805  *
1806  * Returns != 0 upon successful completion.
1807  */
1808
1809 int ADMINAPI
1810 vos_ServerTransactionStatusGetDone(const void *iterationId, afs_status_p st)
1811 {
1812     int rc = 0;
1813     afs_status_t tst = 0;
1814     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
1815
1816     /*
1817      * Validate arguments
1818      */
1819
1820     if (iter == NULL) {
1821         tst = ADMITERATORNULL;
1822         goto fail_vos_ServerTransactionStatusGetDone;
1823     }
1824
1825     rc = IteratorDone(iter, &tst);
1826
1827   fail_vos_ServerTransactionStatusGetDone:
1828
1829     if (st != NULL) {
1830         *st = tst;
1831     }
1832     return rc;
1833 }
1834
1835 static int
1836 copyVLDBEntry(struct nvldbentry *source, vos_vldbEntry_p dest,
1837               afs_status_p st)
1838 {
1839     int rc = 0;
1840     afs_status_t tst = 0;
1841     int i;
1842
1843     dest->numServers = source->nServers;
1844     for (i = 0; i < VOS_MAX_VOLUME_TYPES; i++) {
1845         dest->volumeId[i] = source->volumeId[i];
1846     }
1847     dest->cloneId = source->cloneId;
1848     dest->status = VOS_VLDB_ENTRY_OK;
1849     if (source->flags & VLOP_ALLOPERS) {
1850         dest->status |= VOS_VLDB_ENTRY_LOCKED;
1851     } else {
1852         if (source->flags & VLOP_MOVE) {
1853             dest->status |= VOS_VLDB_ENTRY_MOVE;
1854         }
1855         if (source->flags & VLOP_RELEASE) {
1856             dest->status |= VOS_VLDB_ENTRY_RELEASE;
1857         }
1858         if (source->flags & VLOP_BACKUP) {
1859             dest->status |= VOS_VLDB_ENTRY_BACKUP;
1860         }
1861         if (source->flags & VLOP_DELETE) {
1862             dest->status |= VOS_VLDB_ENTRY_DELETE;
1863         }
1864         if (source->flags & VLOP_DUMP) {
1865             dest->status |= VOS_VLDB_ENTRY_DUMP;
1866         }
1867     }
1868     if (source->flags & VLF_RWEXISTS) {
1869         dest->status |= VOS_VLDB_ENTRY_RWEXISTS;
1870     }
1871     if (source->flags & VLF_ROEXISTS) {
1872         dest->status |= VOS_VLDB_ENTRY_ROEXISTS;
1873     }
1874     if (source->flags & VLF_BACKEXISTS) {
1875         dest->status |= VOS_VLDB_ENTRY_BACKEXISTS;
1876     }
1877
1878     strncpy(dest->name, source->name, VOS_MAX_VOLUME_NAME_LEN);
1879     dest->name[VOS_MAX_VOLUME_NAME_LEN - 1] = '\0';
1880     for (i = 0; i < VOS_MAX_REPLICA_SITES; i++) {
1881         dest->volumeSites[i].serverAddress = source->serverNumber[i];
1882         dest->volumeSites[i].serverPartition = source->serverPartition[i];
1883         dest->volumeSites[i].serverFlags = 0;
1884
1885         if (source->serverFlags[i] & NEW_REPSITE) {
1886             dest->volumeSites[i].serverFlags |= VOS_VLDB_NEW_REPSITE;
1887         }
1888         if (source->serverFlags[i] & ITSROVOL) {
1889             dest->volumeSites[i].serverFlags |= VOS_VLDB_READ_ONLY;
1890         }
1891         if (source->serverFlags[i] & ITSRWVOL) {
1892             dest->volumeSites[i].serverFlags |= VOS_VLDB_READ_WRITE;
1893         }
1894         if (source->serverFlags[i] & ITSBACKVOL) {
1895             dest->volumeSites[i].serverFlags |= VOS_VLDB_BACKUP;
1896         }
1897         if (source->serverFlags[i] & RO_DONTUSE) {
1898             dest->volumeSites[i].serverFlags |= VOS_VLDB_DONT_USE;
1899         }
1900
1901     }
1902
1903     rc = 1;
1904     if (st != NULL) {
1905         *st = tst;
1906     }
1907     return rc;
1908 }
1909
1910 /*
1911  * vos_VLDBGet- get a volume's vldb entry.
1912  *
1913  * PARAMETERS
1914  *
1915  * IN cellHandle - a previously opened cellHandle that corresponds
1916  * to the cell where the volume entries exist.
1917  *
1918  * IN callBack - a call back function pointer that may be called to report
1919  * status information.  Can be null.
1920  *
1921  * IN volumeId - the id of the volume to retrieve.
1922  *
1923  * IN volumeName - the name of the volume to retrieve.
1924  *
1925  * OUT vldbEntry - upon successful completion, contains the information regarding
1926  * the volume.
1927  *
1928  * LOCKS
1929  * 
1930  * No locks are obtained or released by this function
1931  *
1932  * RETURN CODES
1933  *
1934  * Returns != 0 upon successful completion.
1935  */
1936
1937 int ADMINAPI
1938 vos_VLDBGet(const void *cellHandle, vos_MessageCallBack_t callBack,
1939             const unsigned int *volumeId, char *volumeName,
1940             vos_vldbEntry_p vldbEntry, afs_status_p st)
1941 {
1942     int rc = 0;
1943     afs_status_t tst = 0;
1944     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1945     struct nvldbentry entry;
1946
1947
1948     /*
1949      * Validate arguments
1950      */
1951
1952     if (!IsValidCellHandle(c_handle, &tst)) {
1953         goto fail_vos_VLDBGet;
1954     }
1955
1956     if (vldbEntry == NULL) {
1957         tst = ADMVOSVLDBENTRYNULL;
1958         goto fail_vos_VLDBGet;
1959     }
1960
1961     if (((volumeName == NULL) || (*volumeName == 0)) && (volumeId == NULL)) {
1962         tst = ADMVOSVOLUMENAMEANDVOLUMEIDNULL;
1963         goto fail_vos_VLDBGet;
1964     }
1965
1966     /*
1967      * Retrieve the entry
1968      */
1969
1970     if (!((volumeName == NULL) || (*volumeName == 0))) {
1971         if (!ValidateVolumeName(volumeName, &tst)) {
1972             goto fail_vos_VLDBGet;
1973         }
1974         if (!aVLDB_GetEntryByName(c_handle, volumeName, &entry, &tst)) {
1975             goto fail_vos_VLDBGet;
1976         }
1977     } else {
1978         if (!aVLDB_GetEntryByID(c_handle, *volumeId, -1, &entry, &tst)) {
1979             goto fail_vos_VLDBGet;
1980         }
1981     }
1982
1983     /*
1984      * Copy the entry into our structure
1985      */
1986
1987     if (!copyVLDBEntry(&entry, vldbEntry, &tst)) {
1988         goto fail_vos_VLDBGet;
1989     }
1990     rc = 1;
1991
1992   fail_vos_VLDBGet:
1993
1994     if (st != NULL) {
1995         *st = tst;
1996     }
1997     return rc;
1998 }
1999
2000 /*
2001  * The iterator functions and data for the vldb entry retrieval functions.
2002  */
2003
2004 typedef struct vldb_entry_get {
2005     afs_int32 total;            /* total number of vldb entries */
2006     afs_int32 index;            /* index to the current vldb entry */
2007     nbulkentries entries;       /* the list of entries retrieved */
2008     vos_vldbEntry_t entry[CACHED_ITEMS];        /* the cache of entries */
2009 } vldb_entry_get_t, *vldb_entry_get_p;
2010
2011 static int
2012 GetVLDBEntryRPC(void *rpc_specific, int slot, int *last_item,
2013                 int *last_item_contains_data, afs_status_p st)
2014 {
2015     int rc = 0;
2016     afs_status_t tst = 0;
2017     vldb_entry_get_p entry = (vldb_entry_get_p) rpc_specific;
2018
2019     /*
2020      * Copy the next entry into the cache
2021      */
2022
2023     if (!copyVLDBEntry
2024         (&entry->entries.nbulkentries_val[entry->index], &entry->entry[slot],
2025          &tst)) {
2026         goto fail_GetVLDBEntryRPC;
2027     }
2028     entry->index++;
2029
2030     /*
2031      * See if we've processed all the entries
2032      */
2033
2034
2035     if (entry->index == entry->total) {
2036         *last_item = 1;
2037         *last_item_contains_data = 1;
2038     }
2039     rc = 1;
2040
2041   fail_GetVLDBEntryRPC:
2042
2043     if (st != NULL) {
2044         *st = tst;
2045     }
2046     return rc;
2047 }
2048
2049 static int
2050 GetVLDBEntryFromCache(void *rpc_specific, int slot, void *dest,
2051                       afs_status_p st)
2052 {
2053     int rc = 0;
2054     afs_status_t tst = 0;
2055     vldb_entry_get_p entry = (vldb_entry_get_p) rpc_specific;
2056
2057     memcpy(dest, (const void *)&entry->entry[slot], sizeof(vos_vldbEntry_t));
2058     rc = 1;
2059
2060     if (st != NULL) {
2061         *st = tst;
2062     }
2063     return rc;
2064 }
2065
2066
2067 static int
2068 DestroyVLDBEntry(void *rpc_specific, afs_status_p st)
2069 {
2070     int rc = 0;
2071     afs_status_t tst = 0;
2072     vldb_entry_get_p entry = (vldb_entry_get_p) rpc_specific;
2073
2074     if (entry->entries.nbulkentries_val != NULL) {
2075         free(entry->entries.nbulkentries_val);
2076     }
2077     rc = 1;
2078
2079     if (st != NULL) {
2080         *st = tst;
2081     }
2082     return rc;
2083 }
2084
2085
2086 /*
2087  * vos_VLDBGetBegin - begin to iterate over the VLDB.
2088  *
2089  * PARAMETERS
2090  *
2091  * IN cellHandle - a previously opened cellHandle that corresponds
2092  * to the cell where the volume entries exist.
2093  *
2094  * IN serverHandle - a handle to the server whose entries should be listed.
2095  * Can be null.
2096  *
2097  * IN callBack - a call back function pointer that may be called to report
2098  * status information.  Can be null.
2099  *
2100  * IN partition - the partition whose entries should be listed.
2101  * Can be null.
2102  *
2103  * OUT iterationIdP - upon successful completion, contains an iterator that
2104  * can be passed to vos_VLDBGetNext.
2105  *
2106  * LOCKS
2107  * 
2108  * No locks are obtained or released by this function
2109  *
2110  * RETURN CODES
2111  *
2112  * Returns != 0 upon successful completion.
2113  */
2114
2115 int ADMINAPI
2116 vos_VLDBGetBegin(const void *cellHandle, const void *serverHandle,
2117                  vos_MessageCallBack_t callBack, unsigned int *partition,
2118                  void **iterationIdP, afs_status_p st)
2119 {
2120     int rc = 0;
2121     afs_status_t tst = 0;
2122     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2123     file_server_p f_server = (file_server_p) serverHandle;
2124     afs_admin_iterator_p iter =
2125         (afs_admin_iterator_p) malloc(sizeof(afs_admin_iterator_t));
2126     vldb_entry_get_p entry = calloc(1, sizeof(vldb_entry_get_t));
2127     struct VldbListByAttributes attr;
2128
2129     attr.Mask = 0;
2130     memset(&attr, 0, sizeof(attr));
2131
2132     /*
2133      * Validate arguments
2134      */
2135
2136     if (!IsValidCellHandle(c_handle, &tst)) {
2137         goto fail_vos_VLDBGetBegin;
2138     }
2139
2140     if ((iter == NULL) || (entry == NULL)) {
2141         tst = ADMNOMEM;
2142         goto fail_vos_VLDBGetBegin;
2143     }
2144
2145     if (f_server != NULL) {
2146         if (!IsValidServerHandle(f_server, &tst)) {
2147             goto fail_vos_VLDBGetBegin;
2148         }
2149         attr.server = ntohl(rx_HostOf(rx_PeerOf(f_server->serv)));
2150         attr.Mask |= VLLIST_SERVER;
2151     }
2152
2153     if (partition != NULL) {
2154         if (*partition > VOLMAXPARTS) {
2155             tst = ADMVOSPARTITIONTOOLARGE;
2156             goto fail_vos_VLDBGetBegin;
2157         }
2158         attr.partition = *partition;
2159         attr.Mask |= VLLIST_PARTITION;
2160     }
2161
2162     if (!VLDB_ListAttributes
2163         (c_handle, &attr, &entry->total, &entry->entries, &tst)) {
2164         goto fail_vos_VLDBGetBegin;
2165     }
2166
2167     if (entry->total <= 0) {
2168         if (!IteratorInit(iter, (void *)entry, NULL, NULL, NULL, NULL, &tst)) {
2169             goto fail_vos_VLDBGetBegin;
2170         }
2171         iter->done_iterating = 1;
2172         iter->st = ADMITERATORDONE;
2173     } else {
2174         if (!IteratorInit
2175             (iter, (void *)entry, GetVLDBEntryRPC, GetVLDBEntryFromCache,
2176              NULL, DestroyVLDBEntry, &tst)) {
2177             goto fail_vos_VLDBGetBegin;
2178         }
2179     }
2180     *iterationIdP = (void *)iter;
2181     rc = 1;
2182
2183   fail_vos_VLDBGetBegin:
2184
2185     if (rc == 0) {
2186         if (iter != NULL) {
2187             free(iter);
2188         }
2189         if (entry->entries.nbulkentries_val != NULL) {
2190             free(entry->entries.nbulkentries_val);
2191         }
2192         if (entry != NULL) {
2193             free(entry);
2194         }
2195     }
2196
2197     if (st != NULL) {
2198         *st = tst;
2199     }
2200     return rc;
2201 }
2202
2203 /*
2204  * vos_VLDBGetNext - get information about the next volume.
2205  *
2206  * PARAMETERS
2207  *
2208  * IN iterationId - an iterator previously returned by
2209  * vos_VLDBGetBegin
2210  *
2211  * OUT vldbEntry - a pointer to a vos_vldbEntry_t
2212  * that upon successful completion contains information about the
2213  * next volume.
2214  *
2215  * LOCKS
2216  * 
2217  * The iterator is locked while the next item is retrieved.
2218  *
2219  * RETURN CODES
2220  *
2221  * Returns != 0 upon successful completion.
2222  */
2223
2224 int ADMINAPI
2225 vos_VLDBGetNext(const void *iterationId, vos_vldbEntry_p vldbEntry,
2226                 afs_status_p st)
2227 {
2228     int rc = 0;
2229     afs_status_t tst = 0;
2230     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
2231
2232     if (iter == NULL) {
2233         tst = ADMITERATORNULL;
2234         goto fail_vos_VLDBGetNext;
2235     }
2236
2237     if (vldbEntry == NULL) {
2238         tst = ADMVOSVLDBENTRYNULL;
2239         goto fail_vos_VLDBGetNext;
2240     }
2241
2242     rc = IteratorNext(iter, (void *)vldbEntry, &tst);
2243
2244   fail_vos_VLDBGetNext:
2245
2246     if (st != NULL) {
2247         *st = tst;
2248     }
2249     return rc;
2250 }
2251
2252 /*
2253  * vos_VLDBGetDone - finish using a volume iterator.
2254  *
2255  * PARAMETERS
2256  *
2257  * IN iterationId - an iterator previously returned by vos_VLDBGetBegin
2258  *
2259  * LOCKS
2260  * 
2261  * The iterator is locked and then destroyed.
2262  *
2263  * RETURN CODES
2264  *
2265  * Returns != 0 upon successful completion.
2266  */
2267
2268 int ADMINAPI
2269 vos_VLDBGetDone(const void *iterationId, afs_status_p st)
2270 {
2271     int rc = 0;
2272     afs_status_t tst = 0;
2273     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
2274
2275     /*
2276      * Validate arguments
2277      */
2278
2279     if (iter == NULL) {
2280         tst = ADMITERATORNULL;
2281         goto fail_vos_VLDBGetDone;
2282     }
2283
2284     rc = IteratorDone(iter, &tst);
2285
2286   fail_vos_VLDBGetDone:
2287
2288     if (st != NULL) {
2289         *st = tst;
2290     }
2291     return rc;
2292 }
2293
2294 /*
2295  * vos_VLDBEntryRemove - remove a vldb entry.
2296  *
2297  * PARAMETERS
2298  *
2299  * IN cellHandle - a previously opened cellHandle that corresponds
2300  * to the cell where the vldb entry exists.
2301  *
2302  * IN serverHandle - a previously opened serverHandle that corresponds
2303  * to the server where the vldb entry exists.  Can be null.
2304  *
2305  * IN callBack - a call back function pointer that may be called to report
2306  * status information.  Can be null.
2307  *
2308  * IN partition - the partition where the vldb entry exists.  Can be null.
2309  *
2310  * IN volumeId - the volume id of the vldb entry to be deleted. Can be null.
2311  *
2312  * LOCKS
2313  * 
2314  * No locks are obtained or released by this function
2315  *
2316  * RETURN CODES
2317  *
2318  * Returns != 0 upon successful completion.
2319  */
2320
2321 int ADMINAPI
2322 vos_VLDBEntryRemove(const void *cellHandle, const void *serverHandle,
2323                     vos_MessageCallBack_t callBack,
2324                     const unsigned int *partition, unsigned int *volumeId,
2325                     afs_status_p st)
2326 {
2327     int rc = 0;
2328     afs_status_t tst = 0;
2329     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2330     file_server_p f_server = (file_server_p) serverHandle;
2331     struct VldbListByAttributes attr;
2332     nbulkentries entries;
2333     afs_int32 nentries;
2334     int i;
2335
2336     memset(&attr, 0, sizeof(attr));
2337     memset(&entries, 0, sizeof(entries));
2338
2339     /*
2340      * Validate arguments
2341      */
2342
2343     if (!IsValidCellHandle(c_handle, &tst)) {
2344         goto fail_vos_VLDBEntryRemove;
2345     }
2346
2347     /*
2348      * If the volume is specified, just delete it
2349      */
2350
2351     if (volumeId != NULL) {
2352         tst = ubik_VL_DeleteEntry(c_handle->vos, 0, *volumeId, -1);
2353         if (tst != 0) {
2354             goto fail_vos_VLDBEntryRemove;
2355         }
2356     }
2357
2358     if (f_server != NULL) {
2359         if (!IsValidServerHandle(f_server, &tst)) {
2360             goto fail_vos_VLDBEntryRemove;
2361         }
2362         attr.server = ntohl(rx_HostOf(rx_PeerOf(f_server->serv)));
2363         attr.Mask |= VLLIST_SERVER;
2364     }
2365
2366     if (partition != NULL) {
2367         if (*partition > VOLMAXPARTS) {
2368             tst = ADMVOSPARTITIONTOOLARGE;
2369             goto fail_vos_VLDBEntryRemove;
2370         }
2371         attr.partition = *partition;
2372         attr.Mask |= VLLIST_PARTITION;
2373     }
2374
2375     if ((f_server == NULL) && (partition == NULL)) {
2376         tst = ADMVOSVLDBDELETEALLNULL;
2377         goto fail_vos_VLDBEntryRemove;
2378     }
2379
2380     if (!VLDB_ListAttributes(c_handle, &attr, &nentries, &entries, &tst)) {
2381         goto fail_vos_VLDBEntryRemove;
2382     }
2383
2384     if (nentries <= 0) {
2385         tst = ADMVOSVLDBNOENTRIES;
2386         goto fail_vos_VLDBEntryRemove;
2387     }
2388
2389     for (i = 0; i < nentries; i++) {
2390         ubik_VL_DeleteEntry(c_handle->vos, 0,
2391                   entries.nbulkentries_val[i].volumeId[RWVOL], -1);
2392     }
2393     rc = 1;
2394
2395   fail_vos_VLDBEntryRemove:
2396
2397     if (entries.nbulkentries_val) {
2398         free(entries.nbulkentries_val);
2399     }
2400
2401     if (st != NULL) {
2402         *st = tst;
2403     }
2404     return rc;
2405 }
2406
2407 /*
2408  * vos_VLDBUnlock - unlock vldb entries en masse.
2409  *
2410  * PARAMETERS
2411  *
2412  * IN cellHandle - a previously opened cellHandle that corresponds
2413  * to the cell where the vldb entries exist.
2414  *
2415  * IN serverHandle - a previously opened serverHandle that corresponds
2416  * to the server where the vldb entries exist.  Can be null.
2417  *
2418  * IN callBack - a call back function pointer that may be called to report
2419  * status information.  Can be null.
2420  *
2421  * IN partition - the partition where the vldb entries exist.  Can be null.
2422  *
2423  * LOCKS
2424  * 
2425  * No locks are obtained or released by this function
2426  *
2427  * RETURN CODES
2428  *
2429  * Returns != 0 upon successful completion.
2430  */
2431
2432 int ADMINAPI
2433 vos_VLDBUnlock(const void *cellHandle, const void *serverHandle,
2434                vos_MessageCallBack_t callBack, const unsigned int *partition,
2435                afs_status_p st)
2436 {
2437     int rc = 0;
2438     afs_status_t tst = 0;
2439     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2440     file_server_p f_server = (file_server_p) serverHandle;
2441     struct VldbListByAttributes attr;
2442     nbulkentries entries;
2443     afs_int32 nentries;
2444     int i;
2445
2446     memset(&attr, 0, sizeof(attr));
2447     memset(&entries, 0, sizeof(entries));
2448
2449     /*
2450      * Validate arguments
2451      */
2452
2453     if (!IsValidCellHandle(c_handle, &tst)) {
2454         goto fail_vos_VLDBUnlock;
2455     }
2456
2457     if (f_server != NULL) {
2458         if (!IsValidServerHandle(f_server, &tst)) {
2459             goto fail_vos_VLDBUnlock;
2460         }
2461         attr.server = ntohl(rx_HostOf(rx_PeerOf(f_server->serv)));
2462         attr.Mask |= VLLIST_SERVER;
2463     }
2464
2465     if (partition != NULL) {
2466         if (*partition > VOLMAXPARTS) {
2467             tst = ADMVOSPARTITIONTOOLARGE;
2468             goto fail_vos_VLDBUnlock;
2469         }
2470         attr.partition = *partition;
2471         attr.Mask |= VLLIST_PARTITION;
2472     }
2473     attr.flag = VLOP_ALLOPERS;
2474     attr.Mask |= VLLIST_FLAG;
2475
2476
2477     if (!VLDB_ListAttributes(c_handle, &attr, &nentries, &entries, &tst)) {
2478         goto fail_vos_VLDBUnlock;
2479     }
2480
2481     if (nentries <= 0) {
2482         tst = ADMVOSVLDBNOENTRIES;
2483         goto fail_vos_VLDBUnlock;
2484     }
2485
2486     for (i = 0; i < nentries; i++) {
2487         vos_VLDBEntryUnlock(cellHandle, 0,
2488                             entries.nbulkentries_val[i].volumeId[RWVOL],
2489                             &tst);
2490     }
2491     rc = 1;
2492
2493   fail_vos_VLDBUnlock:
2494
2495     if (entries.nbulkentries_val) {
2496         free(entries.nbulkentries_val);
2497     }
2498
2499     if (st != NULL) {
2500         *st = tst;
2501     }
2502     return rc;
2503 }
2504
2505
2506 /*
2507  * vos_VLDBEntryLock - lock a vldb entry.
2508  *
2509  * PARAMETERS
2510  *
2511  * IN cellHandle - a previously opened cellHandle that corresponds
2512  * to the cell where the vldb entry exists.
2513  *
2514  * IN callBack - a call back function pointer that may be called to report
2515  * status information.  Can be null.
2516  *
2517  * IN volumeId - the volume id of the vldb entry to be deleted.
2518  *
2519  * LOCKS
2520  * 
2521  * No locks are obtained or released by this function
2522  *
2523  * RETURN CODES
2524  *
2525  * Returns != 0 upon successful completion.
2526  */
2527
2528 int ADMINAPI
2529 vos_VLDBEntryLock(const void *cellHandle, vos_MessageCallBack_t callBack,
2530                   unsigned int volumeId, afs_status_p st)
2531 {
2532     int rc = 0;
2533     afs_status_t tst = 0;
2534     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2535
2536     /*
2537      * Validate arguments
2538      */
2539
2540     if (!IsValidCellHandle(c_handle, &tst)) {
2541         goto fail_vos_VLDBEntryLock;
2542     }
2543
2544     tst = ubik_VL_SetLock(c_handle->vos, 0, volumeId, -1, VLOP_DELETE);
2545     if (tst != 0) {
2546         goto fail_vos_VLDBEntryLock;
2547     }
2548     rc = 1;
2549
2550   fail_vos_VLDBEntryLock:
2551
2552     if (st != NULL) {
2553         *st = tst;
2554     }
2555     return rc;
2556 }
2557
2558 /*
2559  * vos_VLDBEntryUnlock - unlock a vldb entry.
2560  *
2561  * PARAMETERS
2562  *
2563  * IN cellHandle - a previously opened cellHandle that corresponds
2564  * to the cell where the vldb entry exists.
2565  *
2566  * IN callBack - a call back function pointer that may be called to report
2567  * status information.  Can be null.
2568  *
2569  * IN volumeId - the volume id of the vldb entry to be unlocked.
2570  *
2571  * LOCKS
2572  * 
2573  * No locks are obtained or released by this function
2574  *
2575  * RETURN CODES
2576  *
2577  * Returns != 0 upon successful completion.
2578  */
2579
2580 int ADMINAPI
2581 vos_VLDBEntryUnlock(const void *cellHandle, vos_MessageCallBack_t callBack,
2582                     unsigned int volumeId, afs_status_p st)
2583 {
2584     int rc = 0;
2585     afs_status_t tst = 0;
2586     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2587
2588     /*
2589      * Validate arguments
2590      */
2591
2592     if (!IsValidCellHandle(c_handle, &tst)) {
2593         goto fail_vos_VLDBEntryUnlock;
2594     }
2595
2596
2597     tst =
2598         ubik_VL_ReleaseLock(c_handle->vos, 0, volumeId, -1,
2599                   LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP);
2600     if (tst != 0) {
2601         goto fail_vos_VLDBEntryUnlock;
2602     }
2603     rc = 1;
2604
2605   fail_vos_VLDBEntryUnlock:
2606
2607     if (st != NULL) {
2608         *st = tst;
2609     }
2610     return rc;
2611 }
2612
2613 /*
2614  * vos_VLDBReadOnlySiteCreate - create a readonly site for a volume.
2615  *
2616  * PARAMETERS
2617  *
2618  * IN cellHandle - a previously opened cellHandle that corresponds
2619  * to the cell where the volume exists.
2620  *
2621  * IN serverHandle - a previously opened serverHandle that corresponds
2622  * to the server where the new volume should be created.
2623  *
2624  * IN callBack - a call back function pointer that may be called to report
2625  * status information.  Can be null.
2626  *
2627  * IN partition - the partition where then new volume should be created.
2628  *
2629  * IN volumeId - the volume id of the volume to be replicated.
2630  *
2631  * LOCKS
2632  * 
2633  * No locks are obtained or released by this function
2634  *
2635  * RETURN CODES
2636  *
2637  * Returns != 0 upon successful completion.
2638  */
2639
2640 int ADMINAPI
2641 vos_VLDBReadOnlySiteCreate(const void *cellHandle, const void *serverHandle,
2642                            vos_MessageCallBack_t callBack,
2643                            unsigned int partition, unsigned int volumeId,
2644                            afs_status_p st)
2645 {
2646     int rc = 0;
2647     afs_status_t tst = 0;
2648     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2649     file_server_p f_server = (file_server_p) serverHandle;
2650
2651     /*
2652      * Validate arguments
2653      */
2654
2655     if (!IsValidCellHandle(c_handle, &tst)) {
2656         goto fail_vos_VLDBReadOnlySiteCreate;
2657     }
2658
2659     if (!IsValidServerHandle(f_server, &tst)) {
2660         goto fail_vos_VLDBReadOnlySiteCreate;
2661     }
2662
2663     if (partition > VOLMAXPARTS) {
2664         tst = ADMVOSPARTITIONTOOLARGE;
2665         goto fail_vos_VLDBReadOnlySiteCreate;
2666     }
2667
2668     if (!UV_AddSite
2669         (c_handle, ntohl(rx_HostOf(rx_PeerOf(f_server->serv))), partition,
2670          volumeId, &tst)) {
2671         goto fail_vos_VLDBReadOnlySiteCreate;
2672     }
2673     rc = 1;
2674
2675   fail_vos_VLDBReadOnlySiteCreate:
2676
2677     if (st != NULL) {
2678         *st = tst;
2679     }
2680     return rc;
2681 }
2682
2683 /*
2684  * vos_VLDBReadOnlySiteDelete - delete a replication site for a volume.
2685  *
2686  * PARAMETERS
2687  *
2688  *
2689  * IN cellHandle - a previously opened cellHandle that corresponds
2690  * to the cell where the volume exists.
2691  *
2692  * IN serverHandle - a previously opened serverHandle that corresponds
2693  * to the server where the volume should be deleted.
2694  *
2695  * IN callBack - a call back function pointer that may be called to report
2696  * status information.  Can be null.
2697  *
2698  * IN partition - the partition where then volume should be deleted.
2699  *
2700  * IN volumeId - the volume id of the volume to be deleted.
2701  *
2702  * LOCKS
2703  * 
2704  * No locks are obtained or released by this function
2705  *
2706  * RETURN CODES
2707  *
2708  * Returns != 0 upon successful completion.
2709  */
2710
2711 int ADMINAPI
2712 vos_VLDBReadOnlySiteDelete(const void *cellHandle, const void *serverHandle,
2713                            vos_MessageCallBack_t callBack,
2714                            unsigned int partition, unsigned int volumeId,
2715                            afs_status_p st)
2716 {
2717     int rc = 0;
2718     afs_status_t tst = 0;
2719     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2720     file_server_p f_server = (file_server_p) serverHandle;
2721
2722     /*
2723      * Validate arguments
2724      */
2725
2726     if (!IsValidCellHandle(c_handle, &tst)) {
2727         goto fail_vos_VLDBReadOnlySiteDelete;
2728     }
2729
2730     if (!IsValidServerHandle(f_server, &tst)) {
2731         goto fail_vos_VLDBReadOnlySiteDelete;
2732     }
2733
2734     if (partition > VOLMAXPARTS) {
2735         tst = ADMVOSPARTITIONTOOLARGE;
2736         goto fail_vos_VLDBReadOnlySiteDelete;
2737     }
2738
2739     if (!UV_RemoveSite
2740         (c_handle, ntohl(rx_HostOf(rx_PeerOf(f_server->serv))), partition,
2741          volumeId, &tst)) {
2742         goto fail_vos_VLDBReadOnlySiteDelete;
2743     }
2744     rc = 1;
2745
2746   fail_vos_VLDBReadOnlySiteDelete:
2747
2748     if (st != NULL) {
2749         *st = tst;
2750     }
2751     return rc;
2752 }
2753
2754 /*
2755  * vos_VLDBSync - synchronize the vldb with the fileserver.
2756  *
2757  * PARAMETERS
2758  *
2759  * IN cellHandle - a previously opened cellHandle that corresponds
2760  * to the cell where the sync should occur.
2761  *
2762  * IN serverHandle - a previously opened serverHandle that corresponds
2763  * to the server where the sync should occur.
2764  *
2765  * IN callBack - a call back function pointer that may be called to report
2766  * status information.  Can be null.
2767  *
2768  * IN partition - the partition where the sync should occur.  Can be null.
2769  *
2770  * IN force - force deletion of bad volumes.
2771  *
2772  * LOCKS
2773  * 
2774  * No locks are obtained or released by this function
2775  *
2776  * RETURN CODES
2777  *
2778  * Returns != 0 upon successful completion.
2779  */
2780
2781 int ADMINAPI
2782 vos_VLDBSync(const void *cellHandle, const void *serverHandle,
2783              vos_MessageCallBack_t callBack, const unsigned int *partition,
2784              vos_force_t force, afs_status_p st)
2785 {
2786     int rc = 0;
2787     afs_status_t tst = 0;
2788     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2789     file_server_p f_server = (file_server_p) serverHandle;
2790     afs_int32 part = 0;
2791     int flags = 0;
2792     int force_flag = 0;
2793
2794     /*
2795      * Validate arguments
2796      */
2797
2798     if (!IsValidCellHandle(c_handle, &tst)) {
2799         goto fail_vos_VLDBSync;
2800     }
2801
2802     if (!IsValidServerHandle(f_server, &tst)) {
2803         goto fail_vos_VLDBSync;
2804     }
2805
2806     if (partition != NULL) {
2807         if (*partition > VOLMAXPARTS) {
2808             tst = ADMVOSPARTITIONTOOLARGE;
2809             goto fail_vos_VLDBSync;
2810         }
2811         part = (afs_int32) * partition;
2812         flags = 1;
2813     }
2814
2815     if (force == VOS_FORCE) {
2816         force_flag = 1;
2817     }
2818
2819     /*
2820      * sync the vldb
2821      */
2822
2823     rc = UV_SyncVldb(c_handle, f_server->serv, part, flags, force_flag, &tst);
2824
2825   fail_vos_VLDBSync:
2826
2827     if (st != NULL) {
2828         *st = tst;
2829     }
2830     return rc;
2831 }
2832
2833 /*
2834  * vos_VolumeCreate - create a new partition.
2835  *
2836  * PARAMETERS
2837  *
2838  * IN cellHandle - a previously opened cellHandle that corresponds
2839  * to the cell where the server lives.
2840  *
2841  * IN serverHandle - a previously open vos server handle that holds
2842  * the partition where the volume should be create.
2843  *
2844  * IN callBack - a call back function pointer that may be called to report
2845  * status information.  Can be null.
2846  *
2847  * IN partition - the integer that represents the partition that will 
2848  * house the new volume.
2849  *
2850  * IN volumeName - the name of the new volume.
2851  *
2852  * IN quota - the quota of the new volume.
2853  *
2854  * OUT volumeId - the volume id of the newly created volume.
2855  *
2856  * LOCKS
2857  * 
2858  * No locks are obtained or released by this function
2859  *
2860  * RETURN CODES
2861  *
2862  * Returns != 0 upon successful completion.
2863  */
2864
2865 int ADMINAPI
2866 vos_VolumeCreate(const void *cellHandle, const void *serverHandle,
2867                  vos_MessageCallBack_t callBack, unsigned int partition,
2868                  char *volumeName, unsigned int quota,
2869                  unsigned int *volumeId, afs_status_p st)
2870 {
2871     int rc = 0;
2872     afs_status_t tst = 0;
2873     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2874     file_server_p f_server = (file_server_p) serverHandle;
2875     vos_partitionEntry_t pinfo;
2876     struct nvldbentry vinfo;
2877
2878     /*
2879      * Validate arguments
2880      */
2881
2882     if (!IsValidCellHandle(c_handle, &tst)) {
2883         goto fail_vos_VolumeCreate;
2884     }
2885
2886     if (!IsValidServerHandle(f_server, &tst)) {
2887         goto fail_vos_VolumeCreate;
2888     }
2889
2890     if (partition > VOLMAXPARTS) {
2891         tst = ADMVOSPARTITIONTOOLARGE;
2892         goto fail_vos_VolumeCreate;
2893     }
2894
2895     if (!ValidateVolumeName(volumeName, &tst)) {
2896         goto fail_vos_VolumeCreate;
2897     }
2898
2899     if (volumeId == NULL) {
2900         tst = ADMVOSVOLUMEID;
2901         goto fail_vos_VolumeCreate;
2902     }
2903
2904     /*
2905      * Check that partition is valid at the server
2906      */
2907
2908     if (!vos_PartitionGet
2909         (cellHandle, serverHandle, 0, partition, &pinfo, &tst)) {
2910         goto fail_vos_VolumeCreate;
2911     }
2912
2913     /*
2914      * Check that the volume doesn't already exist
2915      */
2916
2917     if (aVLDB_GetEntryByName(c_handle, volumeName, &vinfo, &tst)) {
2918         tst = ADMVOSVOLUMENAMEDUP;
2919         goto fail_vos_VolumeCreate;
2920     }
2921
2922     /*
2923      * Create the new volume
2924      */
2925
2926     rc = UV_CreateVolume(c_handle, f_server->serv, partition, volumeName,
2927                          quota, volumeId, &tst);
2928
2929   fail_vos_VolumeCreate:
2930
2931     if (st != NULL) {
2932         *st = tst;
2933     }
2934     return rc;
2935 }
2936
2937 /*
2938  * vos_VolumeDelete - remove a volume.
2939  *
2940  * PARAMETERS
2941  *
2942  * IN cellHandle - a previously opened cellHandle that corresponds
2943  * to the cell where the volume exists.
2944  *
2945  * IN serverHandle - a previously opened serverHandle that corresponds
2946  * to the server where the volume exists.
2947  *
2948  * IN callBack - a call back function pointer that may be called to report
2949  * status information.  Can be null.
2950  *
2951  * IN partition - the partition where the volume exists.
2952  *
2953  * IN volumeId - the volume id of the volume to be deleted.
2954  *
2955  * LOCKS
2956  * 
2957  * No locks are obtained or released by this function
2958  *
2959  * RETURN CODES
2960  *
2961  * Returns != 0 upon successful completion.
2962  */
2963
2964 int ADMINAPI
2965 vos_VolumeDelete(const void *cellHandle, const void *serverHandle,
2966                  vos_MessageCallBack_t callBack, unsigned int partition,
2967                  unsigned int volumeId, afs_status_p st)
2968 {
2969     int rc = 0;
2970     afs_status_t tst = 0;
2971     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2972     file_server_p f_server = (file_server_p) serverHandle;
2973     vos_partitionEntry_t pinfo;
2974
2975     /*
2976      * Validate arguments
2977      */
2978
2979     if (!IsValidCellHandle(c_handle, &tst)) {
2980         goto fail_vos_VolumeDelete;
2981     }
2982
2983     if (!IsValidServerHandle(f_server, &tst)) {
2984         goto fail_vos_VolumeDelete;
2985     }
2986
2987     if (partition > VOLMAXPARTS) {
2988         tst = ADMVOSPARTITIONTOOLARGE;
2989         goto fail_vos_VolumeDelete;
2990     }
2991
2992     /*
2993      * Check that partition is valid at the server
2994      */
2995
2996     if (!vos_PartitionGet
2997         (cellHandle, serverHandle, 0, partition, &pinfo, &tst)) {
2998         goto fail_vos_VolumeDelete;
2999     }
3000
3001     rc = UV_DeleteVolume(c_handle, f_server->serv, partition, volumeId, &tst);
3002
3003   fail_vos_VolumeDelete:
3004
3005     if (st != NULL) {
3006         *st = tst;
3007     }
3008     return rc;
3009 }
3010
3011 /*
3012  * vos_VolumeRename - rename a volume.
3013  *
3014  * PARAMETERS
3015  *
3016  * IN cellHandle - a previously opened cellHandle that corresponds
3017  * to the cell where the volume exists.
3018  *
3019  * IN serverHandle - a previously opened serverHandle that corresponds
3020  * to the server where the vldb entry exists.  Can be null.
3021  *
3022  * IN callBack - a call back function pointer that may be called to report
3023  * status information.  Can be null.
3024  *
3025  * IN readWriteVolumeId - the volume id of the volume to be renamed.
3026  *
3027  * IN newVolumeName - the new name.
3028  *
3029  * LOCKS
3030  * 
3031  * No locks are obtained or released by this function
3032  *
3033  * RETURN CODES
3034  *
3035  * Returns != 0 upon successful completion.
3036  */
3037
3038 int ADMINAPI
3039 vos_VolumeRename(const void *cellHandle, vos_MessageCallBack_t callBack,
3040                  unsigned int readWriteVolumeId, char *newVolumeName,
3041                  afs_status_p st)
3042 {
3043     int rc = 0;
3044     afs_status_t tst = 0;
3045     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
3046     struct nvldbentry entry;
3047
3048     /*
3049      * Validate arguments
3050      */
3051
3052     if (!IsValidCellHandle(c_handle, &tst)) {
3053         goto fail_vos_VolumeRename;
3054     }
3055
3056     if ((newVolumeName == NULL) || (*newVolumeName == 0)) {
3057         tst = ADMVOSNEWVOLUMENAMENULL;
3058         goto fail_vos_VolumeRename;
3059     }
3060
3061     /*
3062      * Retrieve the entry
3063      */
3064
3065     if (!aVLDB_GetEntryByID(c_handle, readWriteVolumeId, -1, &entry, &tst)) {
3066         goto fail_vos_VolumeRename;
3067     }
3068
3069     rc = UV_RenameVolume(c_handle, &entry, newVolumeName, &tst);
3070
3071   fail_vos_VolumeRename:
3072
3073     if (st != NULL) {
3074         *st = tst;
3075     }
3076     return rc;
3077 }
3078
3079 /*
3080  * vos_VolumeDump - dump a volume
3081  *
3082  * PARAMETERS
3083  *
3084  * IN cellHandle - a previously opened cellHandle that corresponds
3085  * to the cell where the volume exists.
3086  *
3087  * IN serverHandle - a previously opened serverHandle that corresponds
3088  * to the server where the volume exists.  Can be null.
3089  *
3090  * IN callBack - a call back function pointer that may be called to report
3091  * status information.  Can be null.
3092  *
3093  * IN volumeId - the volume id of the volume to be dumped.
3094  *
3095  * IN startTime - files with modification times >= this time will be dumped.
3096  *
3097  * IN dumpFile - the file to dump the volume to.
3098  *
3099  * LOCKS
3100  * 
3101  * No locks are obtained or released by this function
3102  *
3103  * RETURN CODES
3104  *
3105  * Returns != 0 upon successful completion.
3106  */
3107
3108 int ADMINAPI
3109 vos_VolumeDump(const void *cellHandle, const void *serverHandle,
3110                vos_MessageCallBack_t callBack, unsigned int *partition,
3111                unsigned int volumeId, unsigned int startTime,
3112                const char *dumpFile, afs_status_p st)
3113 {
3114     int rc = 0;
3115     afs_status_t tst = 0;
3116     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
3117     file_server_p f_server = (file_server_p) serverHandle;
3118     afs_int32 server, part, voltype;
3119     struct nvldbentry entry;
3120
3121     /*
3122      * Validate arguments
3123      */
3124
3125     if (!IsValidCellHandle(c_handle, &tst)) {
3126         goto fail_vos_VolumeDump;
3127     }
3128
3129     if (serverHandle != NULL) {
3130         if (!IsValidServerHandle(f_server, &tst)) {
3131             goto fail_vos_VolumeDump;
3132         }
3133     }
3134
3135     /*
3136      * You must specify both the serverHandle and the partition
3137      */
3138
3139     if (serverHandle || partition) {
3140         if (!serverHandle || !partition) {
3141             tst = ADMVOSSERVERANDPARTITION;
3142             goto fail_vos_VolumeDump;
3143         } else {
3144             if (*partition > VOLMAXPARTS) {
3145                 tst = ADMVOSPARTITIONTOOLARGE;
3146                 goto fail_vos_VolumeDump;
3147             }
3148             server = ntohl(rx_HostOf(rx_PeerOf(f_server->serv)));
3149             part = *partition;
3150         }
3151     } else {
3152         if (!GetVolumeInfo
3153             (c_handle, volumeId, &entry, &server, &part, &voltype, &tst)) {
3154             goto fail_vos_VolumeDump;
3155         }
3156     }
3157
3158     if ((dumpFile == NULL) || (*dumpFile == 0)) {
3159         tst = ADMVOSDUMPFILENULL;
3160         goto fail_vos_VolumeDump;
3161     }
3162
3163     rc = UV_DumpVolume(c_handle, volumeId, server, part, startTime, dumpFile,
3164                        &tst);
3165
3166   fail_vos_VolumeDump:
3167
3168     if (st != NULL) {
3169         *st = tst;
3170     }
3171     return rc;
3172 }
3173
3174 /*
3175  * vos_VolumeRestore - restore a volume from a dump
3176  *
3177  * PARAMETERS
3178  *
3179  * IN cellHandle - a previously opened cellHandle that corresponds
3180  * to the cell where the volume exists.
3181  *
3182  * IN serverHandle - a previously opened serverHandle that corresponds
3183  * to the server where the volume exists.
3184  *
3185  * IN callBack - a call back function pointer that may be called to report
3186  * status information.  Can be null.
3187  *
3188  * IN partition - the partition where the volume exists.
3189  *
3190  * IN volumeId - the volume id of the volume to be restored.
3191  *
3192  * IN volumeName - the volume name of the volume to be restored.
3193  *
3194  * IN dumpFile - the file from which to restore the volume.
3195  *
3196  * IN dumpType - the type of dump to perform.
3197  *
3198  * LOCKS
3199  * 
3200  * No locks are obtained or released by this function
3201  *
3202  * RETURN CODES
3203  *
3204  * Returns != 0 upon successful completion.
3205  */
3206
3207 int ADMINAPI
3208 vos_VolumeRestore(const void *cellHandle, const void *serverHandle,
3209                   vos_MessageCallBack_t callBack, unsigned int partition,
3210                   unsigned int *volumeId, char *volumeName,
3211                   const char *dumpFile, vos_volumeRestoreType_t dumpType,
3212                   afs_status_p st)
3213 {
3214     int rc = 0;
3215     afs_status_t tst = 0;
3216     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
3217     file_server_p f_server = (file_server_p) serverHandle;
3218     struct nvldbentry entry;
3219     afs_int32 volid, server;
3220     int fd;
3221     struct stat status;
3222     int restoreflags = 0;
3223     afs_int32 Oserver, Opart, Otype;
3224     struct nvldbentry Oentry;
3225     int equal;
3226
3227     /*
3228      * Validate arguments
3229      */
3230
3231     if (!IsValidCellHandle(c_handle, &tst)) {
3232         goto fail_vos_VolumeRestore;
3233     }
3234
3235     if (serverHandle != NULL) {
3236         if (!IsValidServerHandle(f_server, &tst)) {
3237             goto fail_vos_VolumeRestore;
3238         }
3239     }
3240
3241     /*
3242      * Must pass volumeName
3243      */
3244
3245     if ((volumeName == NULL) || (*volumeName == 0)) {
3246         tst = ADMVOSVOLUMENAMENULL;
3247         goto fail_vos_VolumeRestore;
3248     }
3249
3250     if (!ValidateVolumeName(volumeName, &tst)) {
3251         goto fail_vos_VolumeRestore;
3252     }
3253
3254     /*
3255      * If volumeId is passed, it must be a valid volume id
3256      */
3257
3258     if (volumeId != NULL) {
3259         if (!aVLDB_GetEntryByID(c_handle, *volumeId, -1, &entry, &tst)) {
3260             goto fail_vos_VolumeRestore;
3261         }
3262         volid = *volumeId;
3263     } else {
3264         volid = 0;
3265     }
3266
3267     server = ntohl(rx_HostOf(rx_PeerOf(f_server->serv)));
3268
3269     if (partition > VOLMAXPARTS) {
3270         tst = ADMVOSPARTITIONTOOLARGE;
3271         goto fail_vos_VolumeRestore;
3272     }
3273
3274     /*
3275      * Check that dumpFile exists and can be accessed
3276      */
3277
3278     fd = open(dumpFile, 0);
3279     if ((fd < 0) || (fstat(fd, &status) < 0)) {
3280         close(fd);
3281         tst = ADMVOSDUMPFILEOPENFAIL;
3282         goto fail_vos_VolumeRestore;
3283     } else {
3284         close(fd);
3285     }
3286
3287     if (!aVLDB_GetEntryByName(c_handle, volumeName, &entry, &tst)) {
3288         restoreflags = RV_FULLRST;
3289     } else if (Lp_GetRwIndex(c_handle, &entry, 0) == -1) {
3290         restoreflags = RV_FULLRST;
3291         if (volid == 0) {
3292             volid = entry.volumeId[RWVOL];
3293         } else if ((entry.volumeId[RWVOL] != 0)
3294                    && (entry.volumeId[RWVOL] != volid)) {
3295             volid = entry.volumeId[RWVOL];
3296         }
3297     } else {
3298
3299         if (volid == 0) {
3300             volid = entry.volumeId[RWVOL];
3301         } else if ((entry.volumeId[RWVOL] != 0)
3302                    && (entry.volumeId[RWVOL] != volid)) {
3303             volid = entry.volumeId[RWVOL];
3304         }
3305
3306         /*
3307          * If the vldb says the same volume exists somewhere else
3308          * the caller must specify a full restore, not an incremental
3309          */
3310
3311         if (dumpType == VOS_RESTORE_FULL) {
3312             restoreflags = RV_FULLRST;
3313         } else {
3314
3315             /*
3316              * Check to see if the volume exists where the caller said
3317              */
3318             if (!GetVolumeInfo
3319                 (c_handle, volid, &Oentry, &Oserver, &Opart, &Otype, &tst)) {
3320                 goto fail_vos_VolumeRestore;
3321             }
3322             if (!VLDB_IsSameAddrs(c_handle, Oserver, server, &equal, &tst)) {
3323                 goto fail_vos_VolumeRestore;
3324             }
3325
3326             if (!equal) {
3327                 tst = ADMVOSRESTOREVOLEXIST;
3328                 goto fail_vos_VolumeRestore;
3329             }
3330         }
3331     }
3332
3333     rc = UV_RestoreVolume(c_handle, server, partition, volid, volumeName,
3334                           restoreflags, dumpFile, &tst);
3335
3336   fail_vos_VolumeRestore:
3337
3338     if (st != NULL) {
3339         *st = tst;
3340     }
3341     return rc;
3342 }
3343
3344 /*
3345  * vos_VolumeOnline - bring a volume online.
3346  *
3347  * PARAMETERS
3348  *
3349  * IN serverHandle - a previously opened serverHandle that corresponds
3350  * to the server where the volume exists.
3351  *
3352  * IN callBack - a call back function pointer that may be called to report
3353  * status information.  Can be null.
3354  *
3355  * IN partition - the partition where the volume exists.
3356  *
3357  * IN volumeId - the volume id of the volume to be brought online.
3358  *
3359  * LOCKS
3360  * 
3361  * No locks are obtained or released by this function
3362  *
3363  * RETURN CODES
3364  *
3365  * Returns != 0 upon successful completion.
3366  */
3367
3368 int ADMINAPI
3369 vos_VolumeOnline(const void *serverHandle, vos_MessageCallBack_t callBack,
3370                  unsigned int partition, unsigned int volumeId,
3371                  unsigned int sleepTime, vos_volumeOnlineType_t volumeStatus,
3372                  afs_status_p st)
3373 {
3374     int rc = 0;
3375     afs_status_t tst = 0;
3376     file_server_p f_server = (file_server_p) serverHandle;
3377     int up = ITOffline;
3378
3379     /*
3380      * Validate arguments
3381      */
3382
3383     if (!IsValidServerHandle(f_server, &tst)) {
3384         goto fail_vos_VolumeOnline;
3385     }
3386
3387     if (partition > VOLMAXPARTS) {
3388         tst = ADMVOSPARTITIONIDTOOLARGE;
3389         goto fail_vos_VolumeOnline;
3390     }
3391
3392     if (volumeStatus == VOS_ONLINE_BUSY) {
3393         up = ITBusy;
3394     }
3395
3396     rc = UV_SetVolume(f_server->serv, partition, volumeId, up, 0, sleepTime,
3397                       &tst);
3398
3399   fail_vos_VolumeOnline:
3400
3401     if (st != NULL) {
3402         *st = tst;
3403     }
3404     return rc;
3405 }
3406
3407 /*
3408  * vos_VolumeOffline - take a volume offline.
3409  *
3410  * PARAMETERS
3411  *
3412  * IN serverHandle - a previously opened serverHandle that corresponds
3413  * to the server where the volume exists.
3414  *
3415  * IN callBack - a call back function pointer that may be called to report
3416  * status information.  Can be null.
3417  *
3418  * IN partition - the partition where the volume exists.
3419  *
3420  * IN volumeId - the volume id of the volume to be taken offline.
3421  *
3422  * LOCKS
3423  * 
3424  * No locks are obtained or released by this function
3425  *
3426  * RETURN CODES
3427  *
3428  * Returns != 0 upon successful completion.
3429  */
3430
3431 int ADMINAPI
3432 vos_VolumeOffline(const void *serverHandle, vos_MessageCallBack_t callBack,
3433                   unsigned int partition, unsigned int volumeId,
3434                   afs_status_p st)
3435 {
3436     int rc = 0;
3437     afs_status_t tst = 0;
3438     file_server_p f_server = (file_server_p) serverHandle;
3439
3440     /*
3441      * Validate arguments
3442      */
3443
3444     if (!IsValidServerHandle(f_server, &tst)) {
3445         goto fail_vos_VolumeOffline;
3446     }
3447
3448     if (partition > VOLMAXPARTS) {
3449         tst = ADMVOSPARTITIONIDTOOLARGE;
3450         goto fail_vos_VolumeOffline;
3451     }
3452
3453     rc = UV_SetVolume(f_server->serv, partition, volumeId, ITOffline,
3454                       VTOutOfService, 0, &tst);
3455
3456   fail_vos_VolumeOffline:
3457
3458     if (st != NULL) {
3459         *st = tst;
3460     }
3461     return rc;
3462 }
3463
3464 /*
3465  * copyvolintXInfo - copy a struct volintXInfo to a vos_volumeEntry_p.
3466  *
3467  * PARAMETERS
3468  *
3469  * IN source - the volintXInfo structure to copy.
3470  *
3471  * OUT dest - the vos_volumeEntry_t to fill
3472  *
3473  * LOCKS
3474  * 
3475  * No locks are obtained or released by this function
3476  *
3477  * RETURN CODES
3478  *
3479  * Returns != 0 upon successful completion.
3480  */
3481
3482 static int
3483 copyvolintXInfo(struct volintXInfo *source, vos_volumeEntry_p dest,
3484                 afs_status_p st)
3485 {
3486     int rc = 0;
3487     afs_status_t tst = 0;
3488     int i;
3489
3490     /*
3491      * If the volume is not marked OK, all the other fields are invalid
3492      * We take the extra step of blanking out dest here to prevent the
3493      * user from seeing stale data from a previous call
3494      */
3495
3496     memset(dest, 0, sizeof(*dest));
3497
3498     switch (source->status) {
3499     case VOK:
3500         dest->status = VOS_OK;
3501         break;
3502     case VSALVAGE:
3503         dest->status = VOS_SALVAGE;
3504         break;
3505     case VNOVNODE:
3506         dest->status = VOS_NO_VNODE;
3507         break;
3508     case VNOVOL:
3509         dest->status = VOS_NO_VOL;
3510         break;
3511     case VVOLEXISTS:
3512         dest->status = VOS_VOL_EXISTS;
3513         break;
3514     case VNOSERVICE:
3515         dest->status = VOS_NO_SERVICE;
3516         break;
3517     case VOFFLINE:
3518         dest->status = VOS_OFFLINE;
3519         break;
3520     case VONLINE:
3521         dest->status = VOS_ONLINE;
3522         break;
3523     case VDISKFULL:
3524         dest->status = VOS_DISK_FULL;
3525         break;
3526     case VOVERQUOTA:
3527         dest->status = VOS_OVER_QUOTA;
3528         break;
3529     case VBUSY:
3530         dest->status = VOS_BUSY;
3531         break;
3532     case VMOVED:
3533         dest->status = VOS_MOVED;
3534         break;
3535     }
3536
3537     /*
3538      * Check to see if the entry is marked ok before copying all the
3539      * fields
3540      */
3541
3542     if (dest->status == VOS_OK) {
3543         strncpy(dest->name, source->name, VOS_MAX_VOLUME_NAME_LEN);
3544         dest->name[VOS_MAX_VOLUME_NAME_LEN - 1] = '\0';
3545         dest->id = source->volid;
3546         if (source->type == 0) {
3547             dest->type = VOS_READ_WRITE_VOLUME;
3548         } else if (source->type == 1) {
3549             dest->type = VOS_READ_ONLY_VOLUME;
3550         } else if (source->type == 2) {
3551             dest->type = VOS_BACKUP_VOLUME;
3552         }
3553         dest->backupId = source->backupID;
3554         dest->readWriteId = source->parentID;
3555         dest->readOnlyId = source->cloneID;
3556         dest->copyCreationDate = source->copyDate;
3557         dest->creationDate = source->creationDate;
3558         dest->lastAccessDate = source->accessDate;
3559         dest->lastUpdateDate = source->updateDate;
3560         dest->lastBackupDate = source->backupDate;
3561         dest->accessesSinceMidnight = source->dayUse;
3562         dest->fileCount = source->filecount;
3563         dest->maxQuota = source->maxquota;
3564         dest->currentSize = source->size;
3565         if (source->inUse == 1) {
3566             dest->volumeDisposition = VOS_ONLINE;
3567         } else {
3568             dest->volumeDisposition = VOS_OFFLINE;
3569         }
3570
3571         for (i = 0; i < VOS_VOLUME_READ_WRITE_STATS_NUMBER; i++) {
3572             dest->readStats[i] = source->stat_reads[i];
3573             dest->writeStats[i] = source->stat_writes[i];
3574         }
3575
3576         for (i = 0; i < VOS_VOLUME_TIME_STATS_NUMBER; i++) {
3577             dest->fileAuthorWriteSameNetwork[i] =
3578                 source->stat_fileSameAuthor[i];
3579             dest->fileAuthorWriteDifferentNetwork[i] =
3580                 source->stat_fileDiffAuthor[i];
3581             dest->dirAuthorWriteSameNetwork[i] =
3582                 source->stat_dirSameAuthor[i];
3583             dest->dirAuthorWriteDifferentNetwork[i] =
3584                 source->stat_dirDiffAuthor[i];
3585         }
3586     }
3587
3588     rc = 1;
3589
3590     if (st != NULL) {
3591         *st = tst;
3592     }
3593     return rc;
3594 }
3595
3596 /*
3597  * vos_VolumeGet - get information about a particular volume.
3598  *
3599  * PARAMETERS
3600  *
3601  * IN cellHandle - a previously opened cellHandle that corresponds
3602  * to the cell where the volume exists.
3603  *
3604  * IN serverHandle - a previously opened serverHandle that corresponds
3605  * to the server where the volume exists.
3606  *
3607  * IN callBack - a call back function pointer that may be called to report
3608  * status information.  Can be null.
3609  *
3610  * IN partition - the partition where the volume exists.
3611  *
3612  * IN volumeId - the volume id of the volume to be retrieved.
3613  *
3614  * OUT volumeP - upon successful completion, contains the information about the 
3615  * specified volume.
3616  *
3617  * LOCKS
3618  * 
3619  * No locks are obtained or released by this function
3620  *
3621  * RETURN CODES
3622  *
3623  * Returns != 0 upon successful completion.
3624  */
3625
3626 int ADMINAPI
3627 vos_VolumeGet(const void *cellHandle, const void *serverHandle,
3628               vos_MessageCallBack_t callBack, unsigned int partition,
3629               unsigned int volumeId, vos_volumeEntry_p volumeP,
3630               afs_status_p st)
3631 {
3632     int rc = 0;
3633     afs_status_t tst = 0;
3634     file_server_p f_server = (file_server_p) serverHandle;
3635     struct volintXInfo *info = NULL;
3636
3637     /*
3638      * Validate arguments
3639      */
3640
3641     if (!IsValidServerHandle(f_server, &tst)) {
3642         goto fail_vos_VolumeGet;
3643     }
3644
3645     if (partition > VOLMAXPARTS) {
3646         tst = ADMVOSPARTITIONIDTOOLARGE;
3647         goto fail_vos_VolumeGet;
3648     }
3649
3650     if (volumeP == NULL) {
3651         tst = ADMVOSVOLUMEPNULL;
3652         goto fail_vos_VolumeGet;
3653     }
3654
3655     /*
3656      * Retrieve the information for the volume
3657      */
3658
3659     if (!UV_XListOneVolume(f_server->serv, partition, volumeId, &info, &tst)) {
3660         goto fail_vos_VolumeGet;
3661     }
3662
3663     /*
3664      * Copy the volume info to our structure
3665      */
3666
3667     if (!copyvolintXInfo(info, volumeP, &tst)) {
3668         goto fail_vos_VolumeGet;
3669     }
3670     rc = 1;
3671
3672   fail_vos_VolumeGet:
3673
3674     if (info != NULL) {
3675         free(info);
3676     }
3677
3678     if (st != NULL) {
3679         *st = tst;
3680     }
3681     return rc;
3682 }
3683
3684 /*
3685  * The iterator functions and data for the volume retrieval functions.
3686  */
3687
3688 typedef struct volume_get {
3689     struct volintXInfo *vollist;
3690     afs_int32 total;            /* total number of volumes at this partition */
3691     afs_int32 index;            /* index to the current volume */
3692     vos_volumeEntry_t entry[CACHED_ITEMS];      /* the cache of entries */
3693 } volume_get_t, *volume_get_p;
3694
3695 static int
3696 GetVolumeRPC(void *rpc_specific, int slot, int *last_item,
3697              int *last_item_contains_data, afs_status_p st)
3698 {
3699     int rc = 0;
3700     afs_status_t tst = 0;
3701     volume_get_p entry = (volume_get_p) rpc_specific;
3702
3703     /*
3704      * Copy the next entry into the cache
3705      */
3706
3707     if (!copyvolintXInfo
3708         (&entry->vollist[entry->index], &entry->entry[slot], &tst)) {
3709         goto fail_GetVolumeRPC;
3710     }
3711     entry->index++;
3712
3713     /*
3714      * See if we've processed all the entries
3715      */
3716
3717
3718     if (entry->index == entry->total) {
3719         *last_item = 1;
3720         *last_item_contains_data = 1;
3721     }
3722     rc = 1;
3723
3724   fail_GetVolumeRPC:
3725
3726     if (st != NULL) {
3727         *st = tst;
3728     }
3729     return rc;
3730 }
3731
3732 static int
3733 GetVolumeFromCache(void *rpc_specific, int slot, void *dest, afs_status_p st)
3734 {
3735     int rc = 0;
3736     afs_status_t tst = 0;
3737     volume_get_p entry = (volume_get_p) rpc_specific;
3738
3739     memcpy(dest, (const void *)&entry->entry[slot],
3740            sizeof(vos_volumeEntry_t));
3741     rc = 1;
3742
3743     if (st != NULL) {
3744         *st = tst;
3745     }
3746     return rc;
3747 }
3748
3749
3750 static int
3751 DestroyVolume(void *rpc_specific, afs_status_p st)
3752 {
3753     int rc = 0;
3754     afs_status_t tst = 0;
3755     volume_get_p entry = (volume_get_p) rpc_specific;
3756
3757     if (entry->vollist != NULL) {
3758         free(entry->vollist);
3759     }
3760     rc = 1;
3761
3762     if (st != NULL) {
3763         *st = tst;
3764     }
3765     return rc;
3766 }
3767
3768
3769 /*
3770  * vos_VolumeGetBegin - begin to iterator over the list of volumes at a server.
3771  *
3772  * PARAMETERS
3773  *
3774  * IN cellHandle - a previously opened cellHandle that corresponds
3775  * to the cell where the volumes exist.
3776  *
3777  * IN serverHandle - a handle to the server where the volumes exist.
3778  *
3779  * IN callBack - a call back function pointer that may be called to report
3780  * status information.  Can be null.
3781  *
3782  * IN partition - the partition whose volumes should be listed.  Can be null.
3783  *
3784  * OUT iterationIdP - upon successful completion, contains an iterator that
3785  * can be passed to vos_VolumeGetBegin.
3786  *
3787  * LOCKS
3788  * 
3789  * No locks are obtained or released by this function
3790  *
3791  * RETURN CODES
3792  *
3793  * Returns != 0 upon successful completion.
3794  */
3795
3796 int ADMINAPI
3797 vos_VolumeGetBegin(const void *cellHandle, const void *serverHandle,
3798                    vos_MessageCallBack_t callBack, unsigned int partition,
3799                    void **iterationIdP, afs_status_p st)
3800 {
3801     int rc = 0;
3802     afs_status_t tst = 0;
3803     file_server_p f_server = (file_server_p) serverHandle;
3804     afs_admin_iterator_p iter =
3805         (afs_admin_iterator_p) malloc(sizeof(afs_admin_iterator_t));
3806     volume_get_p entry = calloc(1, sizeof(volume_get_t));
3807
3808     /*
3809      * Validate arguments
3810      */
3811
3812     if (!IsValidServerHandle(f_server, &tst)) {
3813         goto fail_vos_VolumeGetBegin;