80846fd6edfc9b31c4d0f84a2a20bb43ea42593c
[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 =
693         (partition_get_p) calloc(1, sizeof(partition_get_t));
694
695     /*
696      * Validate arguments
697      */
698
699     if (!IsValidServerHandle(f_server, &tst)) {
700         goto fail_vos_PartitionGetBegin;
701     }
702
703     if (iterationIdP == NULL) {
704         goto fail_vos_PartitionGetBegin;
705     }
706
707     if ((iter == NULL) || (part == NULL)) {
708         tst = ADMNOMEM;
709         goto fail_vos_PartitionGetBegin;
710     }
711
712     /*
713      * Fill in the part structure
714      */
715
716     part->server = serverHandle;
717     if (!UV_ListPartitions
718         (f_server->serv, &part->part_list, &part->total_received, &tst)) {
719         goto fail_vos_PartitionGetBegin;
720     }
721
722     /*
723      * If we didn't receive any partitions, don't spawn a background thread.
724      * Mark the iterator complete.
725      */
726
727     if (part->total_received == 0) {
728         if (!IteratorInit(iter, (void *)part, NULL, NULL, NULL, NULL, &tst)) {
729             goto fail_vos_PartitionGetBegin;
730         }
731         iter->done_iterating = 1;
732         iter->st = ADMITERATORDONE;
733     } else {
734         if (!IteratorInit
735             (iter, (void *)part, GetPartitionInfoRPC,
736              GetPartitionInfoFromCache, NULL, NULL, &tst)) {
737             goto fail_vos_PartitionGetBegin;
738         }
739     }
740     *iterationIdP = (void *)iter;
741     rc = 1;
742
743   fail_vos_PartitionGetBegin:
744
745     if (rc == 0) {
746         if (iter != NULL) {
747             free(iter);
748         }
749         if (part != NULL) {
750             free(part);
751         }
752     }
753
754     if (st != NULL) {
755         *st = tst;
756     }
757     return rc;
758 }
759
760 /*
761  * vos_PartitionGetNext - get the next partition at a server.
762  *
763  * PARAMETERS
764  *
765  * IN iterationId - an iterator previously returned by vos_PartitionGetBegin
766  *
767  * OUT partitionP - a pointer to a vos_partitionEntry_t that upon successful
768  * completion contains the next partition.
769  *
770  * LOCKS
771  * 
772  * The iterator is locked while the next parition is retrieved.
773  *
774  * RETURN CODES
775  *
776  * Returns != 0 upon successful completion.
777  */
778
779 int ADMINAPI
780 vos_PartitionGetNext(const void *iterationId, vos_partitionEntry_p partitionP,
781                      afs_status_p st)
782 {
783     int rc = 0;
784     afs_status_t tst = 0;
785     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
786
787     if (iter == NULL) {
788         tst = ADMITERATORNULL;
789         goto fail_vos_PartitionGetNext;
790     }
791
792     if (partitionP == NULL) {
793         tst = ADMVOSPARTITIONPNULL;
794         goto fail_vos_PartitionGetNext;
795     }
796
797     rc = IteratorNext(iter, (void *)partitionP, &tst);
798
799   fail_vos_PartitionGetNext:
800
801     if (st != NULL) {
802         *st = tst;
803     }
804     return rc;
805 }
806
807 /*
808  * vos_PartitionGetDone - finish using a partition iterator.
809  *
810  * PARAMETERS
811  *
812  * IN iterationId - an iterator previously returned by vos_PartitionGetBegin
813  *
814  * LOCKS
815  * 
816  * The iterator is locked and then destroyed.
817  *
818  * RETURN CODES
819  *
820  * Returns != 0 upon successful completion.
821  */
822
823 int ADMINAPI
824 vos_PartitionGetDone(const void *iterationId, afs_status_p st)
825 {
826     int rc = 0;
827     afs_status_t tst = 0;
828     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
829
830     /*
831      * Validate arguments
832      */
833
834     if (iter == NULL) {
835         tst = ADMITERATORNULL;
836         goto fail_vos_PartitionGetDone;
837     }
838
839     rc = IteratorDone(iter, &tst);
840
841   fail_vos_PartitionGetDone:
842
843     if (st != NULL) {
844         *st = tst;
845     }
846     return rc;
847 }
848
849 /*
850  * vos_ServerOpen - open a handle to an individual server for future
851  * operations
852  *
853  * PARAMETERS
854  *
855  * IN cellHandle - a previously opened cellHandle that corresponds
856  * to the cell where the server lives.
857  *
858  * IN serverName - the machine name of the server
859  *
860  * OUT serverHandleP - a void pointer that upon successful completion 
861  * contains a handle that is used in future operations upon the server.
862  *
863  * LOCKS
864  * 
865  * No locks are obtained or released by this function
866  *
867  * RETURN CODES
868  *
869  * Returns != 0 upon successful completion.
870  */
871
872 int ADMINAPI
873 vos_ServerOpen(const void *cellHandle, const char *serverName,
874                void **serverHandleP, afs_status_p st)
875 {
876     int rc = 0;
877     afs_status_t tst = 0;
878     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
879     file_server_p f_server = (file_server_p) malloc(sizeof(file_server_t));
880     int server_address;
881     struct rx_securityClass *sc[3];
882     int scIndex;
883
884     if (f_server == NULL) {
885         tst = ADMNOMEM;
886         goto fail_vos_ServerOpen;
887     }
888
889     /*
890      * Validate arguments
891      */
892
893     if (!IsValidCellHandle(c_handle, &tst)) {
894         goto fail_vos_ServerOpen;
895     }
896
897     if (!c_handle->tokens->afs_token_set) {
898         tst = ADMVOSCELLHANDLENOAFSTOKENS;
899         goto fail_vos_ServerOpen;
900     }
901
902     if (!util_AdminServerAddressGetFromName
903         (serverName, &server_address, &tst)) {
904         goto fail_vos_ServerOpen;
905     }
906
907     scIndex = c_handle->tokens->sc_index;
908     sc[scIndex] = c_handle->tokens->afs_sc[scIndex];
909     f_server->serv =
910         rx_GetCachedConnection(htonl(server_address),
911                                htons(AFSCONF_VOLUMEPORT), VOLSERVICE_ID,
912                                sc[scIndex], scIndex);
913     if (f_server->serv != NULL) {
914         f_server->begin_magic = BEGIN_MAGIC;
915         f_server->end_magic = END_MAGIC;
916         f_server->is_valid = 1;
917         *serverHandleP = (void *)f_server;
918         rc = 1;
919     } else {
920         tst = ADMVOSSERVERNOCONNECTION;
921         goto fail_vos_ServerOpen;
922     }
923
924   fail_vos_ServerOpen:
925
926     if (st != NULL) {
927         *st = tst;
928     }
929     return rc;
930 }
931
932 /*
933  * vos_ServerClose - close a handle previously obtained from vos_ServerOpen
934  *
935  * PARAMETERS
936  *
937  * IN serverHandle - an existing server handle.
938  *
939  * LOCKS
940  * 
941  * No locks are obtained or released by this function
942  *
943  * RETURN CODES
944  *
945  * Returns != 0 upon successful completion.
946  */
947
948 int ADMINAPI
949 vos_ServerClose(const void *serverHandle, afs_status_p st)
950 {
951     int rc = 0;
952     afs_status_t tst = 0;
953     file_server_p f_server = (file_server_p) serverHandle;
954
955     if (!IsValidServerHandle(f_server, &tst)) {
956         goto fail_vos_ServerClose;
957     }
958
959     rx_ReleaseCachedConnection(f_server->serv);
960     f_server->is_valid = 0;
961     free(f_server);
962     rc = 1;
963
964   fail_vos_ServerClose:
965
966     if (st != NULL) {
967         *st = tst;
968     }
969     return rc;
970 }
971
972 /*
973  * vos_ServerSync - synchronize the vldb and the fileserver at a particular
974  * server.
975  *
976  * PARAMETERS
977  *
978  * IN cellHandle - a previously opened cellHandle that corresponds
979  * to the cell where the server lives.
980  *
981  * IN serverHandle - a handle to the server machine.
982  *
983  * IN callBack - a call back function pointer that may be called to report
984  * status information.  Can be null.
985  *
986  * IN partition - the partition to synchronize.  Can be NULL.
987  *
988  * IN force - force deletion of bad volumes.
989  *
990  * LOCKS
991  * 
992  * No locks are obtained or released by this function
993  *
994  * RETURN CODES
995  *
996  * Returns != 0 upon successful completion.
997  */
998
999 int ADMINAPI
1000 vos_ServerSync(const void *cellHandle, const void *serverHandle,
1001                vos_MessageCallBack_t callBack, const unsigned int *partition,
1002                afs_status_p st)
1003 {
1004     int rc = 0;
1005     afs_status_t tst = 0;
1006     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1007     file_server_p f_server = (file_server_p) serverHandle;
1008     afs_int32 part = 0;
1009     int flags = 0;
1010
1011     /*
1012      * Validate arguments
1013      */
1014
1015     if (!IsValidCellHandle(c_handle, &tst)) {
1016         goto fail_vos_ServerSync;
1017     }
1018
1019     if (!IsValidServerHandle(f_server, &tst)) {
1020         goto fail_vos_ServerSync;
1021     }
1022
1023     if (partition != NULL) {
1024         if (*partition > VOLMAXPARTS) {
1025             tst = ADMVOSPARTITIONTOOLARGE;
1026             goto fail_vos_ServerSync;
1027         }
1028         part = (afs_int32) * partition;
1029         flags = 1;
1030     }
1031
1032     /*
1033      * sync the server
1034      */
1035
1036     rc = UV_SyncServer(c_handle, f_server->serv, part, flags, &tst);
1037
1038   fail_vos_ServerSync:
1039
1040     if (st != NULL) {
1041         *st = tst;
1042     }
1043     return rc;
1044 }
1045
1046 /*
1047  * vos_FileServerAddressChange - change an existing file server address.
1048  *
1049  * PARAMETERS
1050  *
1051  * IN cellHandle - a previously opened cellHandle that corresponds
1052  * to the cell where the address should be changed.
1053  *
1054  * IN callBack - a call back function pointer that may be called to report
1055  * status information.  Can be null.
1056  *
1057  * IN oldAddress - the old server address in host byte order
1058  *
1059  * IN newAddress - the new server address in host byte order
1060  *
1061  * LOCKS
1062  * 
1063  * No locks are obtained or released by this function
1064  *
1065  * RETURN CODES
1066  *
1067  * Returns != 0 upon successful completion.
1068  */
1069
1070 int ADMINAPI
1071 vos_FileServerAddressChange(const void *cellHandle,
1072                             vos_MessageCallBack_t callBack,
1073                             unsigned int oldAddress,
1074                             unsigned int newAddress, afs_status_p st)
1075 {
1076     int rc = 0;
1077     afs_status_t tst = 0;
1078     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1079
1080     /*
1081      * Validate arguments
1082      */
1083
1084     if (!IsValidCellHandle(c_handle, &tst)) {
1085         goto fail_vos_FileServerAddressChange;
1086     }
1087
1088     tst =
1089         ubik_VL_ChangeAddr(c_handle->vos, 0, oldAddress, newAddress);
1090     if (tst) {
1091         goto fail_vos_FileServerAddressChange;
1092     }
1093     rc = 1;
1094
1095   fail_vos_FileServerAddressChange:
1096
1097     if (st != NULL) {
1098         *st = tst;
1099     }
1100     return rc;
1101 }
1102
1103 /*
1104  * vos_FileServerAddressRemove - remove an existing file server address.
1105  *
1106  * PARAMETERS
1107  *
1108  * IN cellHandle - a previously opened cellHandle that corresponds
1109  * to the cell where the address should be removed.
1110  *
1111  * IN callBack - a call back function pointer that may be called to report
1112  * status information.  Can be null.
1113  *
1114  * IN serverAddress - the server address to remove in host byte order.
1115  *
1116  * LOCKS
1117  * 
1118  * No locks are obtained or released by this function
1119  *
1120  * RETURN CODES
1121  *
1122  * Returns != 0 upon successful completion.
1123  */
1124
1125 int ADMINAPI
1126 vos_FileServerAddressRemove(const void *cellHandle,
1127                             vos_MessageCallBack_t callBack,
1128                             unsigned int serverAddress,
1129                             afs_status_p st)
1130 {
1131     int rc = 0;
1132     afs_status_t tst = 0;
1133     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1134     unsigned int dummyAddress = 0xffffffff;
1135
1136     /*
1137      * Validate arguments
1138      */
1139
1140     if (!IsValidCellHandle(c_handle, &tst)) {
1141         goto fail_vos_FileServerAddressRemove;
1142     }
1143
1144     tst =
1145         ubik_VL_ChangeAddr(c_handle->vos, 0, dummyAddress,
1146                       serverAddress);
1147     if (tst) {
1148         goto fail_vos_FileServerAddressRemove;
1149     }
1150     rc = 1;
1151
1152   fail_vos_FileServerAddressRemove:
1153
1154     if (st != NULL) {
1155         *st = tst;
1156     }
1157     return rc;
1158 }
1159
1160 /*
1161  * The iterator functions and data for the server retrieval functions.
1162  *
1163  * These functions are very similar to the FileServerAddressGet
1164  * functions.  The main difference being that instead of returning
1165  * a single address at a time for a server, we fill an array with
1166  * all the addresses of a server.
1167  */
1168
1169 typedef struct server_get {
1170     struct ubik_client *vldb;   /* connection for future rpc's if neccessary */
1171     afs_int32 total_addresses;  /* total number of addresses */
1172     bulkaddrs addresses;        /* the list of addresses */
1173     int address_index;          /* current index into address list */
1174     vos_fileServerEntry_t server[CACHED_ITEMS]; /* the cache of servers */
1175 } server_get_t, *server_get_p;
1176
1177 static int
1178 GetServerRPC(void *rpc_specific, int slot, int *last_item,
1179              int *last_item_contains_data, afs_status_p st)
1180 {
1181     int rc = 0;
1182     afs_status_t tst = 0;
1183     server_get_p serv = (server_get_p) rpc_specific;
1184     afs_uint32 *addrP = &serv->addresses.bulkaddrs_val[serv->address_index];
1185     afs_int32 base, index;
1186     afsUUID m_uuid;
1187     afs_int32 m_unique;
1188     ListAddrByAttributes m_attrs;
1189     afs_int32 total_multi;
1190     bulkaddrs addr_multi;
1191     int i;
1192
1193     /*
1194      * Check to see if this is a multihomed address server
1195      */
1196
1197     if (((*addrP & 0xff000000) == 0xff000000) && ((*addrP) & 0xffff)) {
1198         base = (*addrP >> 16) & 0xff;
1199         index = (*addrP) & 0xffff;
1200
1201         if ((base >= 0) && (base <= VL_MAX_ADDREXTBLKS) && (index >= 1)
1202             && (index <= VL_MHSRV_PERBLK)) {
1203
1204             /*
1205              * This is a multihomed server.  Make an rpc to retrieve
1206              * all its addresses.  Copy the addresses into the cache.
1207              */
1208
1209             m_attrs.Mask = VLADDR_INDEX;
1210             m_attrs.index = (base * VL_MHSRV_PERBLK) + index;
1211             total_multi = 0;
1212             addr_multi.bulkaddrs_val = 0;
1213             addr_multi.bulkaddrs_len = 0;
1214             tst =
1215                 ubik_VL_GetAddrsU(serv->vldb, 0, &m_attrs, &m_uuid,
1216                           &m_unique, &total_multi, &addr_multi);
1217             if (tst) {
1218                 goto fail_GetServerRPC;
1219             }
1220
1221             /*
1222              * Remove any bogus IP addresses which the user may have
1223              * been unable to remove.
1224              */
1225
1226             RemoveBadAddresses(&total_multi, &addr_multi);
1227
1228             /*
1229              * Copy all the addresses into the cache
1230              */
1231
1232             for (i = 0; i < total_multi; i++) {
1233                 serv->server[slot].serverAddress[i] =
1234                     addr_multi.bulkaddrs_val[i];
1235             }
1236
1237             serv->server[slot].count = total_multi;
1238             serv->address_index++;
1239             free(addr_multi.bulkaddrs_val);
1240         }
1241
1242         /*
1243          * The next address is just a plain old address
1244          */
1245
1246     } else {
1247         serv->server[slot].serverAddress[0] = *addrP;
1248         serv->server[slot].count = 1;
1249         serv->address_index++;
1250     }
1251
1252     /*
1253      * See if we've processed all the entries
1254      */
1255
1256
1257     if (serv->address_index == serv->total_addresses) {
1258         *last_item = 1;
1259         *last_item_contains_data = 1;
1260     }
1261     rc = 1;
1262
1263   fail_GetServerRPC:
1264
1265     if (st != NULL) {
1266         *st = tst;
1267     }
1268     return rc;
1269 }
1270
1271 static int
1272 GetServerFromCache(void *rpc_specific, int slot, void *dest, afs_status_p st)
1273 {
1274     int rc = 0;
1275     afs_status_t tst = 0;
1276     server_get_p serv = (server_get_p) rpc_specific;
1277
1278     memcpy(dest, (const void *)&serv->server[slot],
1279            sizeof(vos_fileServerEntry_t));
1280     rc = 1;
1281
1282     if (st != NULL) {
1283         *st = tst;
1284     }
1285     return rc;
1286 }
1287
1288
1289 static int
1290 DestroyServer(void *rpc_specific, afs_status_p st)
1291 {
1292     int rc = 0;
1293     afs_status_t tst = 0;
1294     server_get_p serv = (server_get_p) rpc_specific;
1295
1296     if (serv->addresses.bulkaddrs_val != NULL) {
1297         free(serv->addresses.bulkaddrs_val);
1298     }
1299     rc = 1;
1300
1301     if (st != NULL) {
1302         *st = tst;
1303     }
1304     return rc;
1305 }
1306
1307 /*
1308  * vos_FileServerGetBegin - begin to iterate over the file servers in a cell.
1309  *
1310  * PARAMETERS
1311  *
1312  * IN cellHandle - a previously opened cellHandle that corresponds
1313  * to the cell where the file servers exist.
1314  *
1315  * IN callBack - a call back function pointer that may be called to report
1316  * status information.  Can be null.
1317  *
1318  * OUT iterationIdP - upon successful completion, contains an iterator that
1319  * can be passed to vos_FileServerGetNext.
1320  *
1321  * LOCKS
1322  * 
1323  * No locks are obtained or released by this function
1324  *
1325  * RETURN CODES
1326  *
1327  * Returns != 0 upon successful completion.
1328  */
1329
1330 int ADMINAPI
1331 vos_FileServerGetBegin(const void *cellHandle, vos_MessageCallBack_t callBack,
1332                        void **iterationIdP, afs_status_p st)
1333 {
1334     int rc = 0;
1335     afs_status_t tst = 0;
1336     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1337     afs_admin_iterator_p iter =
1338         (afs_admin_iterator_p) malloc(sizeof(afs_admin_iterator_t));
1339     server_get_p serv = (server_get_p) calloc(1, sizeof(server_get_t));
1340     struct VLCallBack unused;
1341
1342
1343     /*
1344      * Validate arguments
1345      */
1346
1347     if (!IsValidCellHandle(c_handle, &tst)) {
1348         goto fail_vos_FileServerGetBegin;
1349     }
1350
1351     if (iterationIdP == NULL) {
1352         goto fail_vos_FileServerGetBegin;
1353     }
1354
1355     if ((iter == NULL) || (serv == NULL)) {
1356         tst = ADMNOMEM;
1357         goto fail_vos_FileServerGetBegin;
1358     }
1359
1360     /*
1361      * Fill in the serv structure
1362      */
1363
1364     serv->vldb = c_handle->vos;
1365     tst =
1366         ubik_VL_GetAddrs(c_handle->vos, 0, 0, 0, &unused,
1367                       &serv->total_addresses, &serv->addresses);
1368
1369     if (tst) {
1370         goto fail_vos_FileServerGetBegin;
1371     }
1372
1373     /*
1374      * Remove any bogus IP addresses which the user may have
1375      * been unable to remove.
1376      */
1377
1378     RemoveBadAddresses(&serv->total_addresses, &serv->addresses);
1379
1380     if (serv->total_addresses == 0) {
1381         if (!IteratorInit(iter, (void *)serv, NULL, NULL, NULL, NULL, &tst)) {
1382             goto fail_vos_FileServerGetBegin;
1383         }
1384         iter->done_iterating = 1;
1385         iter->st = ADMITERATORDONE;
1386     } else {
1387         if (!IteratorInit
1388             (iter, (void *)serv, GetServerRPC, GetServerFromCache, NULL,
1389              DestroyServer, &tst)) {
1390             goto fail_vos_FileServerGetBegin;
1391         }
1392     }
1393     *iterationIdP = (void *)iter;
1394     rc = 1;
1395
1396   fail_vos_FileServerGetBegin:
1397
1398     if (rc == 0) {
1399         if (iter != NULL) {
1400             free(iter);
1401         }
1402         if (serv != NULL) {
1403             if (serv->addresses.bulkaddrs_val != NULL) {
1404                 free(serv->addresses.bulkaddrs_val);
1405             }
1406             free(serv);
1407         }
1408     }
1409
1410     if (st != NULL) {
1411         *st = tst;
1412     }
1413     return rc;
1414 }
1415
1416 /*
1417  * vos_FileServerGetNext - get information about the next fileserver in the cell.
1418  *
1419  * PARAMETERS
1420  *
1421  * IN iterationId - an iterator previously returned by
1422  * vos_FileServerGetBegin
1423  *
1424  * OUT serverEntryP - a pointer to a vos_fileServerEntry_t that upon successful
1425  * completion contains information about the next server in the cell.
1426  *
1427  * LOCKS
1428  * 
1429  * The iterator is locked while the next server is retrieved.
1430  *
1431  * RETURN CODES
1432  *
1433  * Returns != 0 upon successful completion.
1434  */
1435
1436 int ADMINAPI
1437 vos_FileServerGetNext(void *iterationId, vos_fileServerEntry_p serverEntryP,
1438                       afs_status_p st)
1439 {
1440     int rc = 0;
1441     afs_status_t tst = 0;
1442     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
1443
1444     if (iter == NULL) {
1445         tst = ADMITERATORNULL;
1446         goto fail_vos_FileServerGetNext;
1447     }
1448
1449     if (serverEntryP == NULL) {
1450         tst = ADMVOSSERVERENTRYPNULL;
1451         goto fail_vos_FileServerGetNext;
1452     }
1453
1454     rc = IteratorNext(iter, (void *)serverEntryP, &tst);
1455
1456   fail_vos_FileServerGetNext:
1457
1458     if (st != NULL) {
1459         *st = tst;
1460     }
1461     return rc;
1462 }
1463
1464 /*
1465  * vos_FileServerGetDone - finish using a partition iterator.
1466  *
1467  * PARAMETERS
1468  *
1469  * IN iterationId - an iterator previously returned by vos_FileServerGetBegin
1470  *
1471  * LOCKS
1472  * 
1473  * The iterator is locked and then destroyed.
1474  *
1475  * RETURN CODES
1476  *
1477  * Returns != 0 upon successful completion.
1478  */
1479
1480 int ADMINAPI
1481 vos_FileServerGetDone(void *iterationId, afs_status_p st)
1482 {
1483     int rc = 0;
1484     afs_status_t tst = 0;
1485     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
1486
1487     /*
1488      * Validate arguments
1489      */
1490
1491     if (iter == NULL) {
1492         tst = ADMITERATORNULL;
1493         goto fail_vos_FileServerGetDone;
1494     }
1495
1496     rc = IteratorDone(iter, &tst);
1497
1498   fail_vos_FileServerGetDone:
1499
1500     if (st != NULL) {
1501         *st = tst;
1502     }
1503     return rc;
1504 }
1505
1506 /*
1507  * The iterator functions and data for the transation retrieval functions.
1508  */
1509
1510 typedef struct transaction_get {
1511     afs_int32 total;            /* total number of transactions */
1512     afs_int32 index;            /* index to the current transaction */
1513     transDebugInfo *cur;        /* the current transaction */
1514     vos_serverTransactionStatus_t tran[CACHED_ITEMS];   /* the cache of trans */
1515 } transaction_get_t, *transaction_get_p;
1516
1517 static int
1518 GetTransactionRPC(void *rpc_specific, int slot, int *last_item,
1519                   int *last_item_contains_data, afs_status_p st)
1520 {
1521     int rc = 0;
1522     afs_status_t tst = 0;
1523     transaction_get_p t = (transaction_get_p) rpc_specific;
1524     int index = t->index;
1525
1526     /*
1527      * Copy the next transaction into the cache
1528      */
1529
1530     t->tran[slot].transactionId = t->cur[index].tid;
1531     t->tran[slot].lastActiveTime = t->cur[index].time;
1532     t->tran[slot].creationTime = t->cur[index].creationTime;
1533     t->tran[slot].errorCode = t->cur[index].returnCode;
1534     t->tran[slot].volumeId = t->cur[index].volid;
1535     t->tran[slot].partition = t->cur[index].partition;
1536     strcpy(t->tran[slot].lastProcedureName, t->cur[index].lastProcName);
1537     t->tran[slot].nextReceivePacketSequenceNumber = t->cur[index].readNext;
1538     t->tran[slot].nextSendPacketSequenceNumber = t->cur[index].transmitNext;
1539     t->tran[slot].lastReceiveTime = t->cur[index].lastReceiveTime;
1540     t->tran[slot].lastSendTime = t->cur[index].lastSendTime;
1541
1542     t->tran[slot].volumeAttachMode = VOS_VOLUME_ATTACH_MODE_OK;
1543
1544     switch (t->cur[index].iflags) {
1545     case ITOffline:
1546         t->tran[slot].volumeAttachMode = VOS_VOLUME_ATTACH_MODE_OFFLINE;
1547         break;
1548     case ITBusy:
1549         t->tran[slot].volumeAttachMode = VOS_VOLUME_ATTACH_MODE_BUSY;
1550         break;
1551     case ITReadOnly:
1552         t->tran[slot].volumeAttachMode = VOS_VOLUME_ATTACH_MODE_READONLY;
1553         break;
1554     case ITCreate:
1555         t->tran[slot].volumeAttachMode = VOS_VOLUME_ATTACH_MODE_CREATE;
1556         break;
1557     case ITCreateVolID:
1558         t->tran[slot].volumeAttachMode = VOS_VOLUME_ATTACH_MODE_CREATE_VOLID;
1559         break;
1560     }
1561
1562     t->tran[slot].volumeActiveStatus = VOS_VOLUME_ACTIVE_STATUS_OK;
1563
1564     switch (t->cur[index].vflags) {
1565     case VTDeleteOnSalvage:
1566         t->tran[slot].volumeActiveStatus =
1567             VOS_VOLUME_ACTIVE_STATUS_DELETE_ON_SALVAGE;
1568         break;
1569     case VTOutOfService:
1570         t->tran[slot].volumeActiveStatus =
1571             VOS_VOLUME_ACTIVE_STATUS_OUT_OF_SERVICE;
1572         break;
1573     case VTDeleted:
1574         t->tran[slot].volumeActiveStatus = VOS_VOLUME_ACTIVE_STATUS_DELETED;
1575         break;
1576     }
1577
1578     t->tran[slot].volumeTransactionStatus = VOS_VOLUME_TRANSACTION_STATUS_OK;
1579
1580     if (t->cur[index].tflags) {
1581         t->tran[slot].volumeTransactionStatus =
1582             VOS_VOLUME_TRANSACTION_STATUS_DELETED;
1583     }
1584     t->index++;
1585
1586
1587     /*
1588      * See if we've processed all the entries
1589      */
1590
1591
1592     if (t->index == t->total) {
1593         *last_item = 1;
1594         *last_item_contains_data = 1;
1595     }
1596     rc = 1;
1597
1598     if (st != NULL) {
1599         *st = tst;
1600     }
1601     return rc;
1602 }
1603
1604 static int
1605 GetTransactionFromCache(void *rpc_specific, int slot, void *dest,
1606                         afs_status_p st)
1607 {
1608     int rc = 0;
1609     afs_status_t tst = 0;
1610     transaction_get_p tran = (transaction_get_p) rpc_specific;
1611
1612     memcpy(dest, (const void *)&tran->tran[slot],
1613            sizeof(vos_serverTransactionStatus_p));
1614     rc = 1;
1615
1616     if (st != NULL) {
1617         *st = tst;
1618     }
1619     return rc;
1620 }
1621
1622
1623 static int
1624 DestroyTransaction(void *rpc_specific, afs_status_p st)
1625 {
1626     int rc = 0;
1627     afs_status_t tst = 0;
1628     transaction_get_p tran = (transaction_get_p) rpc_specific;
1629
1630     if (tran->cur != NULL) {
1631         free(tran->cur);
1632     }
1633     rc = 1;
1634
1635     if (st != NULL) {
1636         *st = tst;
1637     }
1638     return rc;
1639 }
1640
1641 /*
1642  * vos_ServerTransactionStatusGetBegin - begin to iterate over the transactions
1643  * at a volume server.
1644  *
1645  * PARAMETERS
1646  *
1647  * IN cellHandle - a previously opened cellHandle that corresponds
1648  * to the cell where the volume server exists.
1649  *
1650  * IN serverHandle - a handle to the server to query.
1651  *
1652  * IN callBack - a call back function pointer that may be called to report
1653  * status information.  Can be null.
1654  *
1655  * OUT iterationIdP - upon successful completion, contains an iterator that
1656  * can be passed to vos_ServerTransactionStatusGetNext.
1657  *
1658  * LOCKS
1659  * 
1660  * No locks are obtained or released by this function
1661  *
1662  * RETURN CODES
1663  *
1664  * Returns != 0 upon successful completion.
1665  */
1666
1667 int ADMINAPI
1668 vos_ServerTransactionStatusGetBegin(const void *cellHandle,
1669                                     const void *serverHandle,
1670                                     vos_MessageCallBack_t callBack,
1671                                     void **iterationIdP, afs_status_p st)
1672 {
1673     int rc = 0;
1674     afs_status_t tst = 0;
1675     file_server_p f_server = (file_server_p) serverHandle;
1676     afs_admin_iterator_p iter =
1677         (afs_admin_iterator_p) malloc(sizeof(afs_admin_iterator_t));
1678     transaction_get_p tran =
1679         (transaction_get_p) calloc(1, sizeof(transaction_get_t));
1680
1681
1682     /*
1683      * Validate arguments
1684      */
1685
1686     if (!IsValidServerHandle(f_server, &tst)) {
1687         goto fail_vos_ServerTransactionStatusGetBegin;
1688     }
1689
1690     if (iterationIdP == NULL) {
1691         goto fail_vos_ServerTransactionStatusGetBegin;
1692     }
1693
1694     if ((iter == NULL) || (tran == NULL)) {
1695         tst = ADMNOMEM;
1696         goto fail_vos_ServerTransactionStatusGetBegin;
1697     }
1698
1699     /*
1700      * Fill in the tran structure
1701      */
1702
1703     if (!UV_VolserStatus(f_server->serv, &tran->cur, &tran->total, &tst)) {
1704         goto fail_vos_ServerTransactionStatusGetBegin;
1705     }
1706
1707     if (tran->total == 0) {
1708         if (!IteratorInit(iter, (void *)tran, NULL, NULL, NULL, NULL, &tst)) {
1709             goto fail_vos_ServerTransactionStatusGetBegin;
1710         }
1711         iter->done_iterating = 1;
1712         iter->st = ADMITERATORDONE;
1713     } else {
1714         if (!IteratorInit
1715             (iter, (void *)tran, GetTransactionRPC, GetTransactionFromCache,
1716              NULL, DestroyTransaction, &tst)) {
1717             goto fail_vos_ServerTransactionStatusGetBegin;
1718         }
1719     }
1720     *iterationIdP = (void *)iter;
1721     rc = 1;
1722
1723   fail_vos_ServerTransactionStatusGetBegin:
1724
1725     if (rc == 0) {
1726         if (iter != NULL) {
1727             free(iter);
1728         }
1729         if (tran != NULL) {
1730             if (tran->cur != NULL) {
1731                 free(tran->cur);
1732             }
1733             free(tran);
1734         }
1735     }
1736
1737     if (st != NULL) {
1738         *st = tst;
1739     }
1740     return rc;
1741 }
1742
1743 /*
1744  * vos_ServerTransactionStatusGetNext - get information about the next 
1745  * active transaction.
1746  *
1747  * PARAMETERS
1748  *
1749  * IN iterationId - an iterator previously returned by
1750  * vos_ServerTransactionStatusGetBegin
1751  *
1752  * OUT serverTransactionStatusP - a pointer to a vos_serverTransactionStatus_p
1753  * that upon successful completion contains information about the
1754  * next transaction.
1755  *
1756  * LOCKS
1757  * 
1758  * The iterator is locked while the next item is retrieved.
1759  *
1760  * RETURN CODES
1761  *
1762  * Returns != 0 upon successful completion.
1763  */
1764
1765 int ADMINAPI
1766 vos_ServerTransactionStatusGetNext(const void *iterationId,
1767                                    vos_serverTransactionStatus_p
1768                                    serverTransactionStatusP, afs_status_p st)
1769 {
1770     int rc = 0;
1771     afs_status_t tst = 0;
1772     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
1773
1774     if (iter == NULL) {
1775         tst = ADMITERATORNULL;
1776         goto fail_vos_ServerTransactionStatusGetNext;
1777     }
1778
1779     if (serverTransactionStatusP == NULL) {
1780         tst = ADMVOSSERVERTRANSACTIONSTATUSPNULL;
1781         goto fail_vos_ServerTransactionStatusGetNext;
1782     }
1783
1784     rc = IteratorNext(iter, (void *)serverTransactionStatusP, &tst);
1785
1786   fail_vos_ServerTransactionStatusGetNext:
1787
1788     if (st != NULL) {
1789         *st = tst;
1790     }
1791     return rc;
1792 }
1793
1794 /*
1795  * vos_ServerTransactionStatusGetDone - finish using a transaction iterator.
1796  *
1797  * PARAMETERS
1798  *
1799  * IN iterationId - an iterator previously returned by
1800  * vos_ServerTransactionStatusGetBegin
1801  *
1802  * LOCKS
1803  * 
1804  * The iterator is locked and then destroyed.
1805  *
1806  * RETURN CODES
1807  *
1808  * Returns != 0 upon successful completion.
1809  */
1810
1811 int ADMINAPI
1812 vos_ServerTransactionStatusGetDone(const void *iterationId, afs_status_p st)
1813 {
1814     int rc = 0;
1815     afs_status_t tst = 0;
1816     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
1817
1818     /*
1819      * Validate arguments
1820      */
1821
1822     if (iter == NULL) {
1823         tst = ADMITERATORNULL;
1824         goto fail_vos_ServerTransactionStatusGetDone;
1825     }
1826
1827     rc = IteratorDone(iter, &tst);
1828
1829   fail_vos_ServerTransactionStatusGetDone:
1830
1831     if (st != NULL) {
1832         *st = tst;
1833     }
1834     return rc;
1835 }
1836
1837 static int
1838 copyVLDBEntry(struct nvldbentry *source, vos_vldbEntry_p dest,
1839               afs_status_p st)
1840 {
1841     int rc = 0;
1842     afs_status_t tst = 0;
1843     int i;
1844
1845     dest->numServers = source->nServers;
1846     for (i = 0; i < VOS_MAX_VOLUME_TYPES; i++) {
1847         dest->volumeId[i] = source->volumeId[i];
1848     }
1849     dest->cloneId = source->cloneId;
1850     dest->status = VOS_VLDB_ENTRY_OK;
1851     if (source->flags & VLOP_ALLOPERS) {
1852         dest->status |= VOS_VLDB_ENTRY_LOCKED;
1853     } else {
1854         if (source->flags & VLOP_MOVE) {
1855             dest->status |= VOS_VLDB_ENTRY_MOVE;
1856         }
1857         if (source->flags & VLOP_RELEASE) {
1858             dest->status |= VOS_VLDB_ENTRY_RELEASE;
1859         }
1860         if (source->flags & VLOP_BACKUP) {
1861             dest->status |= VOS_VLDB_ENTRY_BACKUP;
1862         }
1863         if (source->flags & VLOP_DELETE) {
1864             dest->status |= VOS_VLDB_ENTRY_DELETE;
1865         }
1866         if (source->flags & VLOP_DUMP) {
1867             dest->status |= VOS_VLDB_ENTRY_DUMP;
1868         }
1869     }
1870     if (source->flags & VLF_RWEXISTS) {
1871         dest->status |= VOS_VLDB_ENTRY_RWEXISTS;
1872     }
1873     if (source->flags & VLF_ROEXISTS) {
1874         dest->status |= VOS_VLDB_ENTRY_ROEXISTS;
1875     }
1876     if (source->flags & VLF_BACKEXISTS) {
1877         dest->status |= VOS_VLDB_ENTRY_BACKEXISTS;
1878     }
1879
1880     strncpy(dest->name, source->name, VOS_MAX_VOLUME_NAME_LEN);
1881     dest->name[VOS_MAX_VOLUME_NAME_LEN - 1] = '\0';
1882     for (i = 0; i < VOS_MAX_REPLICA_SITES; i++) {
1883         dest->volumeSites[i].serverAddress = source->serverNumber[i];
1884         dest->volumeSites[i].serverPartition = source->serverPartition[i];
1885         dest->volumeSites[i].serverFlags = 0;
1886
1887         if (source->serverFlags[i] & NEW_REPSITE) {
1888             dest->volumeSites[i].serverFlags |= VOS_VLDB_NEW_REPSITE;
1889         }
1890         if (source->serverFlags[i] & ITSROVOL) {
1891             dest->volumeSites[i].serverFlags |= VOS_VLDB_READ_ONLY;
1892         }
1893         if (source->serverFlags[i] & ITSRWVOL) {
1894             dest->volumeSites[i].serverFlags |= VOS_VLDB_READ_WRITE;
1895         }
1896         if (source->serverFlags[i] & ITSBACKVOL) {
1897             dest->volumeSites[i].serverFlags |= VOS_VLDB_BACKUP;
1898         }
1899         if (source->serverFlags[i] & RO_DONTUSE) {
1900             dest->volumeSites[i].serverFlags |= VOS_VLDB_DONT_USE;
1901         }
1902
1903     }
1904
1905     rc = 1;
1906     if (st != NULL) {
1907         *st = tst;
1908     }
1909     return rc;
1910 }
1911
1912 /*
1913  * vos_VLDBGet- get a volume's vldb entry.
1914  *
1915  * PARAMETERS
1916  *
1917  * IN cellHandle - a previously opened cellHandle that corresponds
1918  * to the cell where the volume entries exist.
1919  *
1920  * IN callBack - a call back function pointer that may be called to report
1921  * status information.  Can be null.
1922  *
1923  * IN volumeId - the id of the volume to retrieve.
1924  *
1925  * IN volumeName - the name of the volume to retrieve.
1926  *
1927  * OUT vldbEntry - upon successful completion, contains the information regarding
1928  * the volume.
1929  *
1930  * LOCKS
1931  * 
1932  * No locks are obtained or released by this function
1933  *
1934  * RETURN CODES
1935  *
1936  * Returns != 0 upon successful completion.
1937  */
1938
1939 int ADMINAPI
1940 vos_VLDBGet(const void *cellHandle, vos_MessageCallBack_t callBack,
1941             const unsigned int *volumeId, char *volumeName,
1942             vos_vldbEntry_p vldbEntry, afs_status_p st)
1943 {
1944     int rc = 0;
1945     afs_status_t tst = 0;
1946     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1947     struct nvldbentry entry;
1948
1949
1950     /*
1951      * Validate arguments
1952      */
1953
1954     if (!IsValidCellHandle(c_handle, &tst)) {
1955         goto fail_vos_VLDBGet;
1956     }
1957
1958     if (vldbEntry == NULL) {
1959         tst = ADMVOSVLDBENTRYNULL;
1960         goto fail_vos_VLDBGet;
1961     }
1962
1963     if (((volumeName == NULL) || (*volumeName == 0)) && (volumeId == NULL)) {
1964         tst = ADMVOSVOLUMENAMEANDVOLUMEIDNULL;
1965         goto fail_vos_VLDBGet;
1966     }
1967
1968     /*
1969      * Retrieve the entry
1970      */
1971
1972     if (!((volumeName == NULL) || (*volumeName == 0))) {
1973         if (!ValidateVolumeName(volumeName, &tst)) {
1974             goto fail_vos_VLDBGet;
1975         }
1976         if (!aVLDB_GetEntryByName(c_handle, volumeName, &entry, &tst)) {
1977             goto fail_vos_VLDBGet;
1978         }
1979     } else {
1980         if (!aVLDB_GetEntryByID(c_handle, *volumeId, -1, &entry, &tst)) {
1981             goto fail_vos_VLDBGet;
1982         }
1983     }
1984
1985     /*
1986      * Copy the entry into our structure
1987      */
1988
1989     if (!copyVLDBEntry(&entry, vldbEntry, &tst)) {
1990         goto fail_vos_VLDBGet;
1991     }
1992     rc = 1;
1993
1994   fail_vos_VLDBGet:
1995
1996     if (st != NULL) {
1997         *st = tst;
1998     }
1999     return rc;
2000 }
2001
2002 /*
2003  * The iterator functions and data for the vldb entry retrieval functions.
2004  */
2005
2006 typedef struct vldb_entry_get {
2007     afs_int32 total;            /* total number of vldb entries */
2008     afs_int32 index;            /* index to the current vldb entry */
2009     nbulkentries entries;       /* the list of entries retrieved */
2010     vos_vldbEntry_t entry[CACHED_ITEMS];        /* the cache of entries */
2011 } vldb_entry_get_t, *vldb_entry_get_p;
2012
2013 static int
2014 GetVLDBEntryRPC(void *rpc_specific, int slot, int *last_item,
2015                 int *last_item_contains_data, afs_status_p st)
2016 {
2017     int rc = 0;
2018     afs_status_t tst = 0;
2019     vldb_entry_get_p entry = (vldb_entry_get_p) rpc_specific;
2020
2021     /*
2022      * Copy the next entry into the cache
2023      */
2024
2025     if (!copyVLDBEntry
2026         (&entry->entries.nbulkentries_val[entry->index], &entry->entry[slot],
2027          &tst)) {
2028         goto fail_GetVLDBEntryRPC;
2029     }
2030     entry->index++;
2031
2032     /*
2033      * See if we've processed all the entries
2034      */
2035
2036
2037     if (entry->index == entry->total) {
2038         *last_item = 1;
2039         *last_item_contains_data = 1;
2040     }
2041     rc = 1;
2042
2043   fail_GetVLDBEntryRPC:
2044
2045     if (st != NULL) {
2046         *st = tst;
2047     }
2048     return rc;
2049 }
2050
2051 static int
2052 GetVLDBEntryFromCache(void *rpc_specific, int slot, void *dest,
2053                       afs_status_p st)
2054 {
2055     int rc = 0;
2056     afs_status_t tst = 0;
2057     vldb_entry_get_p entry = (vldb_entry_get_p) rpc_specific;
2058
2059     memcpy(dest, (const void *)&entry->entry[slot], sizeof(vos_vldbEntry_t));
2060     rc = 1;
2061
2062     if (st != NULL) {
2063         *st = tst;
2064     }
2065     return rc;
2066 }
2067
2068
2069 static int
2070 DestroyVLDBEntry(void *rpc_specific, afs_status_p st)
2071 {
2072     int rc = 0;
2073     afs_status_t tst = 0;
2074     vldb_entry_get_p entry = (vldb_entry_get_p) rpc_specific;
2075
2076     if (entry->entries.nbulkentries_val != NULL) {
2077         free(entry->entries.nbulkentries_val);
2078     }
2079     rc = 1;
2080
2081     if (st != NULL) {
2082         *st = tst;
2083     }
2084     return rc;
2085 }
2086
2087
2088 /*
2089  * vos_VLDBGetBegin - begin to iterate over the VLDB.
2090  *
2091  * PARAMETERS
2092  *
2093  * IN cellHandle - a previously opened cellHandle that corresponds
2094  * to the cell where the volume entries exist.
2095  *
2096  * IN serverHandle - a handle to the server whose entries should be listed.
2097  * Can be null.
2098  *
2099  * IN callBack - a call back function pointer that may be called to report
2100  * status information.  Can be null.
2101  *
2102  * IN partition - the partition whose entries should be listed.
2103  * Can be null.
2104  *
2105  * OUT iterationIdP - upon successful completion, contains an iterator that
2106  * can be passed to vos_VLDBGetNext.
2107  *
2108  * LOCKS
2109  * 
2110  * No locks are obtained or released by this function
2111  *
2112  * RETURN CODES
2113  *
2114  * Returns != 0 upon successful completion.
2115  */
2116
2117 int ADMINAPI
2118 vos_VLDBGetBegin(const void *cellHandle, const void *serverHandle,
2119                  vos_MessageCallBack_t callBack, unsigned int *partition,
2120                  void **iterationIdP, afs_status_p st)
2121 {
2122     int rc = 0;
2123     afs_status_t tst = 0;
2124     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2125     file_server_p f_server = (file_server_p) serverHandle;
2126     afs_admin_iterator_p iter =
2127         (afs_admin_iterator_p) malloc(sizeof(afs_admin_iterator_t));
2128     vldb_entry_get_p entry =
2129         (vldb_entry_get_p) calloc(1, sizeof(vldb_entry_get_t));
2130     struct VldbListByAttributes attr;
2131
2132     attr.Mask = 0;
2133     memset(&attr, 0, sizeof(attr));
2134
2135     /*
2136      * Validate arguments
2137      */
2138
2139     if (!IsValidCellHandle(c_handle, &tst)) {
2140         goto fail_vos_VLDBGetBegin;
2141     }
2142
2143     if ((iter == NULL) || (entry == NULL)) {
2144         tst = ADMNOMEM;
2145         goto fail_vos_VLDBGetBegin;
2146     }
2147
2148     if (f_server != NULL) {
2149         if (!IsValidServerHandle(f_server, &tst)) {
2150             goto fail_vos_VLDBGetBegin;
2151         }
2152         attr.server = ntohl(rx_HostOf(rx_PeerOf(f_server->serv)));
2153         attr.Mask |= VLLIST_SERVER;
2154     }
2155
2156     if (partition != NULL) {
2157         if (*partition > VOLMAXPARTS) {
2158             tst = ADMVOSPARTITIONTOOLARGE;
2159             goto fail_vos_VLDBGetBegin;
2160         }
2161         attr.partition = *partition;
2162         attr.Mask |= VLLIST_PARTITION;
2163     }
2164
2165     if (!VLDB_ListAttributes
2166         (c_handle, &attr, &entry->total, &entry->entries, &tst)) {
2167         goto fail_vos_VLDBGetBegin;
2168     }
2169
2170     if (entry->total <= 0) {
2171         if (!IteratorInit(iter, (void *)entry, NULL, NULL, NULL, NULL, &tst)) {
2172             goto fail_vos_VLDBGetBegin;
2173         }
2174         iter->done_iterating = 1;
2175         iter->st = ADMITERATORDONE;
2176     } else {
2177         if (!IteratorInit
2178             (iter, (void *)entry, GetVLDBEntryRPC, GetVLDBEntryFromCache,
2179              NULL, DestroyVLDBEntry, &tst)) {
2180             goto fail_vos_VLDBGetBegin;
2181         }
2182     }
2183     *iterationIdP = (void *)iter;
2184     rc = 1;
2185
2186   fail_vos_VLDBGetBegin:
2187
2188     if (rc == 0) {
2189         if (iter != NULL) {
2190             free(iter);
2191         }
2192         if (entry->entries.nbulkentries_val != NULL) {
2193             free(entry->entries.nbulkentries_val);
2194         }
2195         if (entry != NULL) {
2196             free(entry);
2197         }
2198     }
2199
2200     if (st != NULL) {
2201         *st = tst;
2202     }
2203     return rc;
2204 }
2205
2206 /*
2207  * vos_VLDBGetNext - get information about the next volume.
2208  *
2209  * PARAMETERS
2210  *
2211  * IN iterationId - an iterator previously returned by
2212  * vos_VLDBGetBegin
2213  *
2214  * OUT vldbEntry - a pointer to a vos_vldbEntry_t
2215  * that upon successful completion contains information about the
2216  * next volume.
2217  *
2218  * LOCKS
2219  * 
2220  * The iterator is locked while the next item is retrieved.
2221  *
2222  * RETURN CODES
2223  *
2224  * Returns != 0 upon successful completion.
2225  */
2226
2227 int ADMINAPI
2228 vos_VLDBGetNext(const void *iterationId, vos_vldbEntry_p vldbEntry,
2229                 afs_status_p st)
2230 {
2231     int rc = 0;
2232     afs_status_t tst = 0;
2233     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
2234
2235     if (iter == NULL) {
2236         tst = ADMITERATORNULL;
2237         goto fail_vos_VLDBGetNext;
2238     }
2239
2240     if (vldbEntry == NULL) {
2241         tst = ADMVOSVLDBENTRYNULL;
2242         goto fail_vos_VLDBGetNext;
2243     }
2244
2245     rc = IteratorNext(iter, (void *)vldbEntry, &tst);
2246
2247   fail_vos_VLDBGetNext:
2248
2249     if (st != NULL) {
2250         *st = tst;
2251     }
2252     return rc;
2253 }
2254
2255 /*
2256  * vos_VLDBGetDone - finish using a volume iterator.
2257  *
2258  * PARAMETERS
2259  *
2260  * IN iterationId - an iterator previously returned by vos_VLDBGetBegin
2261  *
2262  * LOCKS
2263  * 
2264  * The iterator is locked and then destroyed.
2265  *
2266  * RETURN CODES
2267  *
2268  * Returns != 0 upon successful completion.
2269  */
2270
2271 int ADMINAPI
2272 vos_VLDBGetDone(const void *iterationId, afs_status_p st)
2273 {
2274     int rc = 0;
2275     afs_status_t tst = 0;
2276     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
2277
2278     /*
2279      * Validate arguments
2280      */
2281
2282     if (iter == NULL) {
2283         tst = ADMITERATORNULL;
2284         goto fail_vos_VLDBGetDone;
2285     }
2286
2287     rc = IteratorDone(iter, &tst);
2288
2289   fail_vos_VLDBGetDone:
2290
2291     if (st != NULL) {
2292         *st = tst;
2293     }
2294     return rc;
2295 }
2296
2297 /*
2298  * vos_VLDBEntryRemove - remove a vldb entry.
2299  *
2300  * PARAMETERS
2301  *
2302  * IN cellHandle - a previously opened cellHandle that corresponds
2303  * to the cell where the vldb entry exists.
2304  *
2305  * IN serverHandle - a previously opened serverHandle that corresponds
2306  * to the server where the vldb entry exists.  Can be null.
2307  *
2308  * IN callBack - a call back function pointer that may be called to report
2309  * status information.  Can be null.
2310  *
2311  * IN partition - the partition where the vldb entry exists.  Can be null.
2312  *
2313  * IN volumeId - the volume id of the vldb entry to be deleted. Can be null.
2314  *
2315  * LOCKS
2316  * 
2317  * No locks are obtained or released by this function
2318  *
2319  * RETURN CODES
2320  *
2321  * Returns != 0 upon successful completion.
2322  */
2323
2324 int ADMINAPI
2325 vos_VLDBEntryRemove(const void *cellHandle, const void *serverHandle,
2326                     vos_MessageCallBack_t callBack,
2327                     const unsigned int *partition, unsigned int *volumeId,
2328                     afs_status_p st)
2329 {
2330     int rc = 0;
2331     afs_status_t tst = 0;
2332     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2333     file_server_p f_server = (file_server_p) serverHandle;
2334     struct VldbListByAttributes attr;
2335     nbulkentries entries;
2336     afs_int32 nentries;
2337     int i;
2338
2339     memset(&attr, 0, sizeof(attr));
2340     memset(&entries, 0, sizeof(entries));
2341
2342     /*
2343      * Validate arguments
2344      */
2345
2346     if (!IsValidCellHandle(c_handle, &tst)) {
2347         goto fail_vos_VLDBEntryRemove;
2348     }
2349
2350     /*
2351      * If the volume is specified, just delete it
2352      */
2353
2354     if (volumeId != NULL) {
2355         tst = ubik_VL_DeleteEntry(c_handle->vos, 0, *volumeId, -1);
2356         if (tst != 0) {
2357             goto fail_vos_VLDBEntryRemove;
2358         }
2359     }
2360
2361     if (f_server != NULL) {
2362         if (!IsValidServerHandle(f_server, &tst)) {
2363             goto fail_vos_VLDBEntryRemove;
2364         }
2365         attr.server = ntohl(rx_HostOf(rx_PeerOf(f_server->serv)));
2366         attr.Mask |= VLLIST_SERVER;
2367     }
2368
2369     if (partition != NULL) {
2370         if (*partition > VOLMAXPARTS) {
2371             tst = ADMVOSPARTITIONTOOLARGE;
2372             goto fail_vos_VLDBEntryRemove;
2373         }
2374         attr.partition = *partition;
2375         attr.Mask |= VLLIST_PARTITION;
2376     }
2377
2378     if ((f_server == NULL) && (partition == NULL)) {
2379         tst = ADMVOSVLDBDELETEALLNULL;
2380         goto fail_vos_VLDBEntryRemove;
2381     }
2382
2383     if (!VLDB_ListAttributes(c_handle, &attr, &nentries, &entries, &tst)) {
2384         goto fail_vos_VLDBEntryRemove;
2385     }
2386
2387     if (nentries <= 0) {
2388         tst = ADMVOSVLDBNOENTRIES;
2389         goto fail_vos_VLDBEntryRemove;
2390     }
2391
2392     for (i = 0; i < nentries; i++) {
2393         ubik_VL_DeleteEntry(c_handle->vos, 0,
2394                   entries.nbulkentries_val[i].volumeId[RWVOL], -1);
2395     }
2396     rc = 1;
2397
2398   fail_vos_VLDBEntryRemove:
2399
2400     if (entries.nbulkentries_val) {
2401         free(entries.nbulkentries_val);
2402     }
2403
2404     if (st != NULL) {
2405         *st = tst;
2406     }
2407     return rc;
2408 }
2409
2410 /*
2411  * vos_VLDBUnlock - unlock vldb entries en masse.
2412  *
2413  * PARAMETERS
2414  *
2415  * IN cellHandle - a previously opened cellHandle that corresponds
2416  * to the cell where the vldb entries exist.
2417  *
2418  * IN serverHandle - a previously opened serverHandle that corresponds
2419  * to the server where the vldb entries exist.  Can be null.
2420  *
2421  * IN callBack - a call back function pointer that may be called to report
2422  * status information.  Can be null.
2423  *
2424  * IN partition - the partition where the vldb entries exist.  Can be null.
2425  *
2426  * LOCKS
2427  * 
2428  * No locks are obtained or released by this function
2429  *
2430  * RETURN CODES
2431  *
2432  * Returns != 0 upon successful completion.
2433  */
2434
2435 int ADMINAPI
2436 vos_VLDBUnlock(const void *cellHandle, const void *serverHandle,
2437                vos_MessageCallBack_t callBack, const unsigned int *partition,
2438                afs_status_p st)
2439 {
2440     int rc = 0;
2441     afs_status_t tst = 0;
2442     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2443     file_server_p f_server = (file_server_p) serverHandle;
2444     struct VldbListByAttributes attr;
2445     nbulkentries entries;
2446     afs_int32 nentries;
2447     int i;
2448
2449     memset(&attr, 0, sizeof(attr));
2450     memset(&entries, 0, sizeof(entries));
2451
2452     /*
2453      * Validate arguments
2454      */
2455
2456     if (!IsValidCellHandle(c_handle, &tst)) {
2457         goto fail_vos_VLDBUnlock;
2458     }
2459
2460     if (f_server != NULL) {
2461         if (!IsValidServerHandle(f_server, &tst)) {
2462             goto fail_vos_VLDBUnlock;
2463         }
2464         attr.server = ntohl(rx_HostOf(rx_PeerOf(f_server->serv)));
2465         attr.Mask |= VLLIST_SERVER;
2466     }
2467
2468     if (partition != NULL) {
2469         if (*partition > VOLMAXPARTS) {
2470             tst = ADMVOSPARTITIONTOOLARGE;
2471             goto fail_vos_VLDBUnlock;
2472         }
2473         attr.partition = *partition;
2474         attr.Mask |= VLLIST_PARTITION;
2475     }
2476     attr.flag = VLOP_ALLOPERS;
2477     attr.Mask |= VLLIST_FLAG;
2478
2479
2480     if (!VLDB_ListAttributes(c_handle, &attr, &nentries, &entries, &tst)) {
2481         goto fail_vos_VLDBUnlock;
2482     }
2483
2484     if (nentries <= 0) {
2485         tst = ADMVOSVLDBNOENTRIES;
2486         goto fail_vos_VLDBUnlock;
2487     }
2488
2489     for (i = 0; i < nentries; i++) {
2490         vos_VLDBEntryUnlock(cellHandle, 0,
2491                             entries.nbulkentries_val[i].volumeId[RWVOL],
2492                             &tst);
2493     }
2494     rc = 1;
2495
2496   fail_vos_VLDBUnlock:
2497
2498     if (entries.nbulkentries_val) {
2499         free(entries.nbulkentries_val);
2500     }
2501
2502     if (st != NULL) {
2503         *st = tst;
2504     }
2505     return rc;
2506 }
2507
2508
2509 /*
2510  * vos_VLDBEntryLock - lock a vldb entry.
2511  *
2512  * PARAMETERS
2513  *
2514  * IN cellHandle - a previously opened cellHandle that corresponds
2515  * to the cell where the vldb entry exists.
2516  *
2517  * IN callBack - a call back function pointer that may be called to report
2518  * status information.  Can be null.
2519  *
2520  * IN volumeId - the volume id of the vldb entry to be deleted.
2521  *
2522  * LOCKS
2523  * 
2524  * No locks are obtained or released by this function
2525  *
2526  * RETURN CODES
2527  *
2528  * Returns != 0 upon successful completion.
2529  */
2530
2531 int ADMINAPI
2532 vos_VLDBEntryLock(const void *cellHandle, vos_MessageCallBack_t callBack,
2533                   unsigned int volumeId, afs_status_p st)
2534 {
2535     int rc = 0;
2536     afs_status_t tst = 0;
2537     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2538
2539     /*
2540      * Validate arguments
2541      */
2542
2543     if (!IsValidCellHandle(c_handle, &tst)) {
2544         goto fail_vos_VLDBEntryLock;
2545     }
2546
2547     tst = ubik_VL_SetLock(c_handle->vos, 0, volumeId, -1, VLOP_DELETE);
2548     if (tst != 0) {
2549         goto fail_vos_VLDBEntryLock;
2550     }
2551     rc = 1;
2552
2553   fail_vos_VLDBEntryLock:
2554
2555     if (st != NULL) {
2556         *st = tst;
2557     }
2558     return rc;
2559 }
2560
2561 /*
2562  * vos_VLDBEntryUnlock - unlock a vldb entry.
2563  *
2564  * PARAMETERS
2565  *
2566  * IN cellHandle - a previously opened cellHandle that corresponds
2567  * to the cell where the vldb entry exists.
2568  *
2569  * IN callBack - a call back function pointer that may be called to report
2570  * status information.  Can be null.
2571  *
2572  * IN volumeId - the volume id of the vldb entry to be unlocked.
2573  *
2574  * LOCKS
2575  * 
2576  * No locks are obtained or released by this function
2577  *
2578  * RETURN CODES
2579  *
2580  * Returns != 0 upon successful completion.
2581  */
2582
2583 int ADMINAPI
2584 vos_VLDBEntryUnlock(const void *cellHandle, vos_MessageCallBack_t callBack,
2585                     unsigned int volumeId, afs_status_p st)
2586 {
2587     int rc = 0;
2588     afs_status_t tst = 0;
2589     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2590
2591     /*
2592      * Validate arguments
2593      */
2594
2595     if (!IsValidCellHandle(c_handle, &tst)) {
2596         goto fail_vos_VLDBEntryUnlock;
2597     }
2598
2599
2600     tst =
2601         ubik_VL_ReleaseLock(c_handle->vos, 0, volumeId, -1,
2602                   LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP);
2603     if (tst != 0) {
2604         goto fail_vos_VLDBEntryUnlock;
2605     }
2606     rc = 1;
2607
2608   fail_vos_VLDBEntryUnlock:
2609
2610     if (st != NULL) {
2611         *st = tst;
2612     }
2613     return rc;
2614 }
2615
2616 /*
2617  * vos_VLDBReadOnlySiteCreate - create a readonly site for a volume.
2618  *
2619  * PARAMETERS
2620  *
2621  * IN cellHandle - a previously opened cellHandle that corresponds
2622  * to the cell where the volume exists.
2623  *
2624  * IN serverHandle - a previously opened serverHandle that corresponds
2625  * to the server where the new volume should be created.
2626  *
2627  * IN callBack - a call back function pointer that may be called to report
2628  * status information.  Can be null.
2629  *
2630  * IN partition - the partition where then new volume should be created.
2631  *
2632  * IN volumeId - the volume id of the volume to be replicated.
2633  *
2634  * LOCKS
2635  * 
2636  * No locks are obtained or released by this function
2637  *
2638  * RETURN CODES
2639  *
2640  * Returns != 0 upon successful completion.
2641  */
2642
2643 int ADMINAPI
2644 vos_VLDBReadOnlySiteCreate(const void *cellHandle, const void *serverHandle,
2645                            vos_MessageCallBack_t callBack,
2646                            unsigned int partition, unsigned int volumeId,
2647                            afs_status_p st)
2648 {
2649     int rc = 0;
2650     afs_status_t tst = 0;
2651     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2652     file_server_p f_server = (file_server_p) serverHandle;
2653
2654     /*
2655      * Validate arguments
2656      */
2657
2658     if (!IsValidCellHandle(c_handle, &tst)) {
2659         goto fail_vos_VLDBReadOnlySiteCreate;
2660     }
2661
2662     if (!IsValidServerHandle(f_server, &tst)) {
2663         goto fail_vos_VLDBReadOnlySiteCreate;
2664     }
2665
2666     if (partition > VOLMAXPARTS) {
2667         tst = ADMVOSPARTITIONTOOLARGE;
2668         goto fail_vos_VLDBReadOnlySiteCreate;
2669     }
2670
2671     if (!UV_AddSite
2672         (c_handle, ntohl(rx_HostOf(rx_PeerOf(f_server->serv))), partition,
2673          volumeId, &tst)) {
2674         goto fail_vos_VLDBReadOnlySiteCreate;
2675     }
2676     rc = 1;
2677
2678   fail_vos_VLDBReadOnlySiteCreate:
2679
2680     if (st != NULL) {
2681         *st = tst;
2682     }
2683     return rc;
2684 }
2685
2686 /*
2687  * vos_VLDBReadOnlySiteDelete - delete a replication site for a volume.
2688  *
2689  * PARAMETERS
2690  *
2691  *
2692  * IN cellHandle - a previously opened cellHandle that corresponds
2693  * to the cell where the volume exists.
2694  *
2695  * IN serverHandle - a previously opened serverHandle that corresponds
2696  * to the server where the volume should be deleted.
2697  *
2698  * IN callBack - a call back function pointer that may be called to report
2699  * status information.  Can be null.
2700  *
2701  * IN partition - the partition where then volume should be deleted.
2702  *
2703  * IN volumeId - the volume id of the volume to be deleted.
2704  *
2705  * LOCKS
2706  * 
2707  * No locks are obtained or released by this function
2708  *
2709  * RETURN CODES
2710  *
2711  * Returns != 0 upon successful completion.
2712  */
2713
2714 int ADMINAPI
2715 vos_VLDBReadOnlySiteDelete(const void *cellHandle, const void *serverHandle,
2716                            vos_MessageCallBack_t callBack,
2717                            unsigned int partition, unsigned int volumeId,
2718                            afs_status_p st)
2719 {
2720     int rc = 0;
2721     afs_status_t tst = 0;
2722     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2723     file_server_p f_server = (file_server_p) serverHandle;
2724
2725     /*
2726      * Validate arguments
2727      */
2728
2729     if (!IsValidCellHandle(c_handle, &tst)) {
2730         goto fail_vos_VLDBReadOnlySiteDelete;
2731     }
2732
2733     if (!IsValidServerHandle(f_server, &tst)) {
2734         goto fail_vos_VLDBReadOnlySiteDelete;
2735     }
2736
2737     if (partition > VOLMAXPARTS) {
2738         tst = ADMVOSPARTITIONTOOLARGE;
2739         goto fail_vos_VLDBReadOnlySiteDelete;
2740     }
2741
2742     if (!UV_RemoveSite
2743         (c_handle, ntohl(rx_HostOf(rx_PeerOf(f_server->serv))), partition,
2744          volumeId, &tst)) {
2745         goto fail_vos_VLDBReadOnlySiteDelete;
2746     }
2747     rc = 1;
2748
2749   fail_vos_VLDBReadOnlySiteDelete:
2750
2751     if (st != NULL) {
2752         *st = tst;
2753     }
2754     return rc;
2755 }
2756
2757 /*
2758  * vos_VLDBSync - synchronize the vldb with the fileserver.
2759  *
2760  * PARAMETERS
2761  *
2762  * IN cellHandle - a previously opened cellHandle that corresponds
2763  * to the cell where the sync should occur.
2764  *
2765  * IN serverHandle - a previously opened serverHandle that corresponds
2766  * to the server where the sync should occur.
2767  *
2768  * IN callBack - a call back function pointer that may be called to report
2769  * status information.  Can be null.
2770  *
2771  * IN partition - the partition where the sync should occur.  Can be null.
2772  *
2773  * IN force - force deletion of bad volumes.
2774  *
2775  * LOCKS
2776  * 
2777  * No locks are obtained or released by this function
2778  *
2779  * RETURN CODES
2780  *
2781  * Returns != 0 upon successful completion.
2782  */
2783
2784 int ADMINAPI
2785 vos_VLDBSync(const void *cellHandle, const void *serverHandle,
2786              vos_MessageCallBack_t callBack, const unsigned int *partition,
2787              vos_force_t force, afs_status_p st)
2788 {
2789     int rc = 0;
2790     afs_status_t tst = 0;
2791     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2792     file_server_p f_server = (file_server_p) serverHandle;
2793     afs_int32 part = 0;
2794     int flags = 0;
2795     int force_flag = 0;
2796
2797     /*
2798      * Validate arguments
2799      */
2800
2801     if (!IsValidCellHandle(c_handle, &tst)) {
2802         goto fail_vos_VLDBSync;
2803     }
2804
2805     if (!IsValidServerHandle(f_server, &tst)) {
2806         goto fail_vos_VLDBSync;
2807     }
2808
2809     if (partition != NULL) {
2810         if (*partition > VOLMAXPARTS) {
2811             tst = ADMVOSPARTITIONTOOLARGE;
2812             goto fail_vos_VLDBSync;
2813         }
2814         part = (afs_int32) * partition;
2815         flags = 1;
2816     }
2817
2818     if (force == VOS_FORCE) {
2819         force_flag = 1;
2820     }
2821
2822     /*
2823      * sync the vldb
2824      */
2825
2826     rc = UV_SyncVldb(c_handle, f_server->serv, part, flags, force_flag, &tst);
2827
2828   fail_vos_VLDBSync:
2829
2830     if (st != NULL) {
2831         *st = tst;
2832     }
2833     return rc;
2834 }
2835
2836 /*
2837  * vos_VolumeCreate - create a new partition.
2838  *
2839  * PARAMETERS
2840  *
2841  * IN cellHandle - a previously opened cellHandle that corresponds
2842  * to the cell where the server lives.
2843  *
2844  * IN serverHandle - a previously open vos server handle that holds
2845  * the partition where the volume should be create.
2846  *
2847  * IN callBack - a call back function pointer that may be called to report
2848  * status information.  Can be null.
2849  *
2850  * IN partition - the integer that represents the partition that will 
2851  * house the new volume.
2852  *
2853  * IN volumeName - the name of the new volume.
2854  *
2855  * IN quota - the quota of the new volume.
2856  *
2857  * OUT volumeId - the volume id of the newly created volume.
2858  *
2859  * LOCKS
2860  * 
2861  * No locks are obtained or released by this function
2862  *
2863  * RETURN CODES
2864  *
2865  * Returns != 0 upon successful completion.
2866  */
2867
2868 int ADMINAPI
2869 vos_VolumeCreate(const void *cellHandle, const void *serverHandle,
2870                  vos_MessageCallBack_t callBack, unsigned int partition,
2871                  char *volumeName, unsigned int quota,
2872                  unsigned int *volumeId, afs_status_p st)
2873 {
2874     int rc = 0;
2875     afs_status_t tst = 0;
2876     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2877     file_server_p f_server = (file_server_p) serverHandle;
2878     vos_partitionEntry_t pinfo;
2879     struct nvldbentry vinfo;
2880
2881     /*
2882      * Validate arguments
2883      */
2884
2885     if (!IsValidCellHandle(c_handle, &tst)) {
2886         goto fail_vos_VolumeCreate;
2887     }
2888
2889     if (!IsValidServerHandle(f_server, &tst)) {
2890         goto fail_vos_VolumeCreate;
2891     }
2892
2893     if (partition > VOLMAXPARTS) {
2894         tst = ADMVOSPARTITIONTOOLARGE;
2895         goto fail_vos_VolumeCreate;
2896     }
2897
2898     if (!ValidateVolumeName(volumeName, &tst)) {
2899         goto fail_vos_VolumeCreate;
2900     }
2901
2902     if (volumeId == NULL) {
2903         tst = ADMVOSVOLUMEID;
2904         goto fail_vos_VolumeCreate;
2905     }
2906
2907     /*
2908      * Check that partition is valid at the server
2909      */
2910
2911     if (!vos_PartitionGet
2912         (cellHandle, serverHandle, 0, partition, &pinfo, &tst)) {
2913         goto fail_vos_VolumeCreate;
2914     }
2915
2916     /*
2917      * Check that the volume doesn't already exist
2918      */
2919
2920     if (aVLDB_GetEntryByName(c_handle, volumeName, &vinfo, &tst)) {
2921         tst = ADMVOSVOLUMENAMEDUP;
2922         goto fail_vos_VolumeCreate;
2923     }
2924
2925     /*
2926      * Create the new volume
2927      */
2928
2929     rc = UV_CreateVolume(c_handle, f_server->serv, partition, volumeName,
2930                          quota, volumeId, &tst);
2931
2932   fail_vos_VolumeCreate:
2933
2934     if (st != NULL) {
2935         *st = tst;
2936     }
2937     return rc;
2938 }
2939
2940 /*
2941  * vos_VolumeDelete - remove a volume.
2942  *
2943  * PARAMETERS
2944  *
2945  * IN cellHandle - a previously opened cellHandle that corresponds
2946  * to the cell where the volume exists.
2947  *
2948  * IN serverHandle - a previously opened serverHandle that corresponds
2949  * to the server where the volume exists.
2950  *
2951  * IN callBack - a call back function pointer that may be called to report
2952  * status information.  Can be null.
2953  *
2954  * IN partition - the partition where the volume exists.
2955  *
2956  * IN volumeId - the volume id of the volume to be deleted.
2957  *
2958  * LOCKS
2959  * 
2960  * No locks are obtained or released by this function
2961  *
2962  * RETURN CODES
2963  *
2964  * Returns != 0 upon successful completion.
2965  */
2966
2967 int ADMINAPI
2968 vos_VolumeDelete(const void *cellHandle, const void *serverHandle,
2969                  vos_MessageCallBack_t callBack, unsigned int partition,
2970                  unsigned int volumeId, afs_status_p st)
2971 {
2972     int rc = 0;
2973     afs_status_t tst = 0;
2974     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2975     file_server_p f_server = (file_server_p) serverHandle;
2976     vos_partitionEntry_t pinfo;
2977
2978     /*
2979      * Validate arguments
2980      */
2981
2982     if (!IsValidCellHandle(c_handle, &tst)) {
2983         goto fail_vos_VolumeDelete;
2984     }
2985
2986     if (!IsValidServerHandle(f_server, &tst)) {
2987         goto fail_vos_VolumeDelete;
2988     }
2989
2990     if (partition > VOLMAXPARTS) {
2991         tst = ADMVOSPARTITIONTOOLARGE;
2992         goto fail_vos_VolumeDelete;
2993     }
2994
2995     /*
2996      * Check that partition is valid at the server
2997      */
2998
2999     if (!vos_PartitionGet
3000         (cellHandle, serverHandle, 0, partition, &pinfo, &tst)) {
3001         goto fail_vos_VolumeDelete;
3002     }
3003
3004     rc = UV_DeleteVolume(c_handle, f_server->serv, partition, volumeId, &tst);
3005
3006   fail_vos_VolumeDelete:
3007
3008     if (st != NULL) {
3009         *st = tst;
3010     }
3011     return rc;
3012 }
3013
3014 /*
3015  * vos_VolumeRename - rename a volume.
3016  *
3017  * PARAMETERS
3018  *
3019  * IN cellHandle - a previously opened cellHandle that corresponds
3020  * to the cell where the volume exists.
3021  *
3022  * IN serverHandle - a previously opened serverHandle that corresponds
3023  * to the server where the vldb entry exists.  Can be null.
3024  *
3025  * IN callBack - a call back function pointer that may be called to report
3026  * status information.  Can be null.
3027  *
3028  * IN readWriteVolumeId - the volume id of the volume to be renamed.
3029  *
3030  * IN newVolumeName - the new name.
3031  *
3032  * LOCKS
3033  * 
3034  * No locks are obtained or released by this function
3035  *
3036  * RETURN CODES
3037  *
3038  * Returns != 0 upon successful completion.
3039  */
3040
3041 int ADMINAPI
3042 vos_VolumeRename(const void *cellHandle, vos_MessageCallBack_t callBack,
3043                  unsigned int readWriteVolumeId, char *newVolumeName,
3044                  afs_status_p st)
3045 {
3046     int rc = 0;
3047     afs_status_t tst = 0;
3048     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
3049     struct nvldbentry entry;
3050
3051     /*
3052      * Validate arguments
3053      */
3054
3055     if (!IsValidCellHandle(c_handle, &tst)) {
3056         goto fail_vos_VolumeRename;
3057     }
3058
3059     if ((newVolumeName == NULL) || (*newVolumeName == 0)) {
3060         tst = ADMVOSNEWVOLUMENAMENULL;
3061         goto fail_vos_VolumeRename;
3062     }
3063
3064     /*
3065      * Retrieve the entry
3066      */
3067
3068     if (!aVLDB_GetEntryByID(c_handle, readWriteVolumeId, -1, &entry, &tst)) {
3069         goto fail_vos_VolumeRename;
3070     }
3071
3072     rc = UV_RenameVolume(c_handle, &entry, newVolumeName, &tst);
3073
3074   fail_vos_VolumeRename:
3075
3076     if (st != NULL) {
3077         *st = tst;
3078     }
3079     return rc;
3080 }
3081
3082 /*
3083  * vos_VolumeDump - dump a volume
3084  *
3085  * PARAMETERS
3086  *
3087  * IN cellHandle - a previously opened cellHandle that corresponds
3088  * to the cell where the volume exists.
3089  *
3090  * IN serverHandle - a previously opened serverHandle that corresponds
3091  * to the server where the volume exists.  Can be null.
3092  *
3093  * IN callBack - a call back function pointer that may be called to report
3094  * status information.  Can be null.
3095  *
3096  * IN volumeId - the volume id of the volume to be dumped.
3097  *
3098  * IN startTime - files with modification times >= this time will be dumped.
3099  *
3100  * IN dumpFile - the file to dump the volume to.
3101  *
3102  * LOCKS
3103  * 
3104  * No locks are obtained or released by this function
3105  *
3106  * RETURN CODES
3107  *
3108  * Returns != 0 upon successful completion.
3109  */
3110
3111 int ADMINAPI
3112 vos_VolumeDump(const void *cellHandle, const void *serverHandle,
3113                vos_MessageCallBack_t callBack, unsigned int *partition,
3114                unsigned int volumeId, unsigned int startTime,
3115                const char *dumpFile, afs_status_p st)
3116 {
3117     int rc = 0;
3118     afs_status_t tst = 0;
3119     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
3120     file_server_p f_server = (file_server_p) serverHandle;
3121     afs_int32 server, part, voltype;
3122     struct nvldbentry entry;
3123
3124     /*
3125      * Validate arguments
3126      */
3127
3128     if (!IsValidCellHandle(c_handle, &tst)) {
3129         goto fail_vos_VolumeDump;
3130     }
3131
3132     if (serverHandle != NULL) {
3133         if (!IsValidServerHandle(f_server, &tst)) {
3134             goto fail_vos_VolumeDump;
3135         }
3136     }
3137
3138     /*
3139      * You must specify both the serverHandle and the partition
3140      */
3141
3142     if (serverHandle || partition) {
3143         if (!serverHandle || !partition) {
3144             tst = ADMVOSSERVERANDPARTITION;
3145             goto fail_vos_VolumeDump;
3146         } else {
3147             if (*partition > VOLMAXPARTS) {
3148                 tst = ADMVOSPARTITIONTOOLARGE;
3149                 goto fail_vos_VolumeDump;
3150             }
3151             server = ntohl(rx_HostOf(rx_PeerOf(f_server->serv)));
3152             part = *partition;
3153         }
3154     } else {
3155         if (!GetVolumeInfo
3156             (c_handle, volumeId, &entry, &server, &part, &voltype, &tst)) {
3157             goto fail_vos_VolumeDump;
3158         }
3159     }
3160
3161     if ((dumpFile == NULL) || (*dumpFile == 0)) {
3162         tst = ADMVOSDUMPFILENULL;
3163         goto fail_vos_VolumeDump;
3164     }
3165
3166     rc = UV_DumpVolume(c_handle, volumeId, server, part, startTime, dumpFile,
3167                        &tst);
3168
3169   fail_vos_VolumeDump:
3170
3171     if (st != NULL) {
3172         *st = tst;
3173     }
3174     return rc;
3175 }
3176
3177 /*
3178  * vos_VolumeRestore - restore a volume from a dump
3179  *
3180  * PARAMETERS
3181  *
3182  * IN cellHandle - a previously opened cellHandle that corresponds
3183  * to the cell where the volume exists.
3184  *
3185  * IN serverHandle - a previously opened serverHandle that corresponds
3186  * to the server where the volume exists.
3187  *
3188  * IN callBack - a call back function pointer that may be called to report
3189  * status information.  Can be null.
3190  *
3191  * IN partition - the partition where the volume exists.
3192  *
3193  * IN volumeId - the volume id of the volume to be restored.
3194  *
3195  * IN volumeName - the volume name of the volume to be restored.
3196  *
3197  * IN dumpFile - the file from which to restore the volume.
3198  *
3199  * IN dumpType - the type of dump to perform.
3200  *
3201  * LOCKS
3202  * 
3203  * No locks are obtained or released by this function
3204  *
3205  * RETURN CODES
3206  *
3207  * Returns != 0 upon successful completion.
3208  */
3209
3210 int ADMINAPI
3211 vos_VolumeRestore(const void *cellHandle, const void *serverHandle,
3212                   vos_MessageCallBack_t callBack, unsigned int partition,
3213                   unsigned int *volumeId, char *volumeName,
3214                   const char *dumpFile, vos_volumeRestoreType_t dumpType,
3215                   afs_status_p st)
3216 {
3217     int rc = 0;
3218     afs_status_t tst = 0;
3219     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
3220     file_server_p f_server = (file_server_p) serverHandle;
3221     struct nvldbentry entry;
3222     afs_int32 volid, server;
3223     int fd;
3224     struct stat status;
3225     int restoreflags = 0;
3226     afs_int32 Oserver, Opart, Otype;
3227     struct nvldbentry Oentry;
3228     int equal;
3229
3230     /*
3231      * Validate arguments
3232      */
3233
3234     if (!IsValidCellHandle(c_handle, &tst)) {
3235         goto fail_vos_VolumeRestore;
3236     }
3237
3238     if (serverHandle != NULL) {
3239         if (!IsValidServerHandle(f_server, &tst)) {
3240             goto fail_vos_VolumeRestore;
3241         }
3242     }
3243
3244     /*
3245      * Must pass volumeName
3246      */
3247
3248     if ((volumeName == NULL) || (*volumeName == 0)) {
3249         tst = ADMVOSVOLUMENAMENULL;
3250         goto fail_vos_VolumeRestore;
3251     }
3252
3253     if (!ValidateVolumeName(volumeName, &tst)) {
3254         goto fail_vos_VolumeRestore;
3255     }
3256
3257     /*
3258      * If volumeId is passed, it must be a valid volume id
3259      */
3260
3261     if (volumeId != NULL) {
3262         if (!aVLDB_GetEntryByID(c_handle, *volumeId, -1, &entry, &tst)) {
3263             goto fail_vos_VolumeRestore;
3264         }
3265         volid = *volumeId;
3266     } else {
3267         volid = 0;
3268     }
3269
3270     server = ntohl(rx_HostOf(rx_PeerOf(f_server->serv)));
3271
3272     if (partition > VOLMAXPARTS) {
3273         tst = ADMVOSPARTITIONTOOLARGE;
3274         goto fail_vos_VolumeRestore;
3275     }
3276
3277     /*
3278      * Check that dumpFile exists and can be accessed
3279      */
3280
3281     fd = open(dumpFile, 0);
3282     if ((fd < 0) || (fstat(fd, &status) < 0)) {
3283         close(fd);
3284         tst = ADMVOSDUMPFILEOPENFAIL;
3285         goto fail_vos_VolumeRestore;
3286     } else {
3287         close(fd);
3288     }
3289
3290     if (!aVLDB_GetEntryByName(c_handle, volumeName, &entry, &tst)) {
3291         restoreflags = RV_FULLRST;
3292     } else if (Lp_GetRwIndex(c_handle, &entry, 0) == -1) {
3293         restoreflags = RV_FULLRST;
3294         if (volid == 0) {
3295             volid = entry.volumeId[RWVOL];
3296         } else if ((entry.volumeId[RWVOL] != 0)
3297                    && (entry.volumeId[RWVOL] != volid)) {
3298             volid = entry.volumeId[RWVOL];
3299         }
3300     } else {
3301
3302         if (volid == 0) {
3303             volid = entry.volumeId[RWVOL];
3304         } else if ((entry.volumeId[RWVOL] != 0)
3305                    && (entry.volumeId[RWVOL] != volid)) {
3306             volid = entry.volumeId[RWVOL];
3307         }
3308
3309         /*
3310          * If the vldb says the same volume exists somewhere else
3311          * the caller must specify a full restore, not an incremental
3312          */
3313
3314         if (dumpType == VOS_RESTORE_FULL) {
3315             restoreflags = RV_FULLRST;
3316         } else {
3317
3318             /*
3319              * Check to see if the volume exists where the caller said
3320              */
3321             if (!GetVolumeInfo
3322                 (c_handle, volid, &Oentry, &Oserver, &Opart, &Otype, &tst)) {
3323                 goto fail_vos_VolumeRestore;
3324             }
3325             if (!VLDB_IsSameAddrs(c_handle, Oserver, server, &equal, &tst)) {
3326                 goto fail_vos_VolumeRestore;
3327             }
3328
3329             if (!equal) {
3330                 tst = ADMVOSRESTOREVOLEXIST;
3331                 goto fail_vos_VolumeRestore;
3332             }
3333         }
3334     }
3335
3336     rc = UV_RestoreVolume(c_handle, server, partition, volid, volumeName,
3337                           restoreflags, dumpFile, &tst);
3338
3339   fail_vos_VolumeRestore:
3340
3341     if (st != NULL) {
3342         *st = tst;
3343     }
3344     return rc;
3345 }
3346
3347 /*
3348  * vos_VolumeOnline - bring a volume online.
3349  *
3350  * PARAMETERS
3351  *
3352  * IN serverHandle - a previously opened serverHandle that corresponds
3353  * to the server where the volume exists.
3354  *
3355  * IN callBack - a call back function pointer that may be called to report
3356  * status information.  Can be null.
3357  *
3358  * IN partition - the partition where the volume exists.
3359  *
3360  * IN volumeId - the volume id of the volume to be brought online.
3361  *
3362  * LOCKS
3363  * 
3364  * No locks are obtained or released by this function
3365  *
3366  * RETURN CODES
3367  *
3368  * Returns != 0 upon successful completion.
3369  */
3370
3371 int ADMINAPI
3372 vos_VolumeOnline(const void *serverHandle, vos_MessageCallBack_t callBack,
3373                  unsigned int partition, unsigned int volumeId,
3374                  unsigned int sleepTime, vos_volumeOnlineType_t volumeStatus,
3375                  afs_status_p st)
3376 {
3377     int rc = 0;
3378     afs_status_t tst = 0;
3379     file_server_p f_server = (file_server_p) serverHandle;
3380     int up = ITOffline;
3381
3382     /*
3383      * Validate arguments
3384      */
3385
3386     if (!IsValidServerHandle(f_server, &tst)) {
3387         goto fail_vos_VolumeOnline;
3388     }
3389
3390     if (partition > VOLMAXPARTS) {
3391         tst = ADMVOSPARTITIONIDTOOLARGE;
3392         goto fail_vos_VolumeOnline;
3393     }
3394
3395     if (volumeStatus == VOS_ONLINE_BUSY) {
3396         up = ITBusy;
3397     }
3398
3399     rc = UV_SetVolume(f_server->serv, partition, volumeId, up, 0, sleepTime,
3400                       &tst);
3401
3402   fail_vos_VolumeOnline:
3403
3404     if (st != NULL) {
3405         *st = tst;
3406     }
3407     return rc;
3408 }
3409
3410 /*
3411  * vos_VolumeOffline - take a volume offline.
3412  *
3413  * PARAMETERS
3414  *
3415  * IN serverHandle - a previously opened serverHandle that corresponds
3416  * to the server where the volume exists.
3417  *
3418  * IN callBack - a call back function pointer that may be called to report
3419  * status information.  Can be null.
3420  *
3421  * IN partition - the partition where the volume exists.
3422  *
3423  * IN volumeId - the volume id of the volume to be taken offline.
3424  *
3425  * LOCKS
3426  * 
3427  * No locks are obtained or released by this function
3428  *
3429  * RETURN CODES
3430  *
3431  * Returns != 0 upon successful completion.
3432  */
3433
3434 int ADMINAPI
3435 vos_VolumeOffline(const void *serverHandle, vos_MessageCallBack_t callBack,
3436                   unsigned int partition, unsigned int volumeId,
3437                   afs_status_p st)
3438 {
3439     int rc = 0;
3440     afs_status_t tst = 0;
3441     file_server_p f_server = (file_server_p) serverHandle;
3442
3443     /*
3444      * Validate arguments
3445      */
3446
3447     if (!IsValidServerHandle(f_server, &tst)) {
3448         goto fail_vos_VolumeOffline;
3449     }
3450
3451     if (partition > VOLMAXPARTS) {
3452         tst = ADMVOSPARTITIONIDTOOLARGE;
3453         goto fail_vos_VolumeOffline;
3454     }
3455
3456     rc = UV_SetVolume(f_server->serv, partition, volumeId, ITOffline,
3457                       VTOutOfService, 0, &tst);
3458
3459   fail_vos_VolumeOffline:
3460
3461     if (st != NULL) {
3462         *st = tst;
3463     }
3464     return rc;
3465 }
3466
3467 /*
3468  * copyvolintXInfo - copy a struct volintXInfo to a vos_volumeEntry_p.
3469  *
3470  * PARAMETERS
3471  *
3472  * IN source - the volintXInfo structure to copy.
3473  *
3474  * OUT dest - the vos_volumeEntry_t to fill
3475  *
3476  * LOCKS
3477  * 
3478  * No locks are obtained or released by this function
3479  *
3480  * RETURN CODES
3481  *
3482  * Returns != 0 upon successful completion.
3483  */
3484
3485 static int
3486 copyvolintXInfo(struct volintXInfo *source, vos_volumeEntry_p dest,
3487                 afs_status_p st)
3488 {
3489     int rc = 0;
3490     afs_status_t tst = 0;
3491     int i;
3492
3493     /*
3494      * If the volume is not marked OK, all the other fields are invalid
3495      * We take the extra step of blanking out dest here to prevent the
3496      * user from seeing stale data from a previous call
3497      */
3498
3499     memset(dest, 0, sizeof(*dest));
3500
3501     switch (source->status) {
3502     case VOK:
3503         dest->status = VOS_OK;
3504         break;
3505     case VSALVAGE:
3506         dest->status = VOS_SALVAGE;
3507         break;
3508     case VNOVNODE:
3509         dest->status = VOS_NO_VNODE;
3510         break;
3511     case VNOVOL:
3512         dest->status = VOS_NO_VOL;
3513         break;
3514     case VVOLEXISTS:
3515         dest->status = VOS_VOL_EXISTS;
3516         break;
3517     case VNOSERVICE:
3518         dest->status = VOS_NO_SERVICE;
3519         break;
3520     case VOFFLINE:
3521         dest->status = VOS_OFFLINE;
3522         break;
3523     case VONLINE:
3524         dest->status = VOS_ONLINE;
3525         break;
3526     case VDISKFULL:
3527         dest->status = VOS_DISK_FULL;
3528         break;
3529     case VOVERQUOTA:
3530         dest->status = VOS_OVER_QUOTA;
3531         break;
3532     case VBUSY:
3533         dest->status = VOS_BUSY;
3534         break;
3535     case VMOVED:
3536         dest->status = VOS_MOVED;
3537         break;
3538     }
3539
3540     /*
3541      * Check to see if the entry is marked ok before copying all the
3542      * fields
3543      */
3544
3545     if (dest->status == VOS_OK) {
3546         strncpy(dest->name, source->name, VOS_MAX_VOLUME_NAME_LEN);
3547         dest->name[VOS_MAX_VOLUME_NAME_LEN - 1] = '\0';
3548         dest->id = source->volid;
3549         if (source->type == 0) {
3550             dest->type = VOS_READ_WRITE_VOLUME;
3551         } else if (source->type == 1) {
3552             dest->type = VOS_READ_ONLY_VOLUME;
3553         } else if (source->type == 2) {
3554             dest->type = VOS_BACKUP_VOLUME;
3555         }
3556         dest->backupId = source->backupID;
3557         dest->readWriteId = source->parentID;
3558         dest->readOnlyId = source->cloneID;
3559         dest->copyCreationDate = source->copyDate;
3560         dest->creationDate = source->creationDate;
3561         dest->lastAccessDate = source->accessDate;
3562         dest->lastUpdateDate = source->updateDate;
3563         dest->lastBackupDate = source->backupDate;
3564         dest->accessesSinceMidnight = source->dayUse;
3565         dest->fileCount = source->filecount;
3566         dest->maxQuota = source->maxquota;
3567         dest->currentSize = source->size;
3568         if (source->inUse == 1) {
3569             dest->volumeDisposition = VOS_ONLINE;
3570         } else {
3571             dest->volumeDisposition = VOS_OFFLINE;
3572         }
3573
3574         for (i = 0; i < VOS_VOLUME_READ_WRITE_STATS_NUMBER; i++) {
3575             dest->readStats[i] = source->stat_reads[i];
3576             dest->writeStats[i] = source->stat_writes[i];
3577         }
3578
3579         for (i = 0; i < VOS_VOLUME_TIME_STATS_NUMBER; i++) {
3580             dest->fileAuthorWriteSameNetwork[i] =
3581                 source->stat_fileSameAuthor[i];
3582             dest->fileAuthorWriteDifferentNetwork[i] =
3583                 source->stat_fileDiffAuthor[i];
3584             dest->dirAuthorWriteSameNetwork[i] =
3585                 source->stat_dirSameAuthor[i];
3586             dest->dirAuthorWriteDifferentNetwork[i] =
3587                 source->stat_dirDiffAuthor[i];
3588         }
3589     }
3590
3591     rc = 1;
3592
3593     if (st != NULL) {
3594         *st = tst;
3595     }
3596     return rc;
3597 }
3598
3599 /*
3600  * vos_VolumeGet - get information about a particular volume.
3601  *
3602  * PARAMETERS
3603  *
3604  * IN cellHandle - a previously opened cellHandle that corresponds
3605  * to the cell where the volume exists.
3606  *
3607  * IN serverHandle - a previously opened serverHandle that corresponds
3608  * to the server where the volume exists.
3609  *
3610  * IN callBack - a call back function pointer that may be called to report
3611  * status information.  Can be null.
3612  *
3613  * IN partition - the partition where the volume exists.
3614  *
3615  * IN volumeId - the volume id of the volume to be retrieved.
3616  *
3617  * OUT volumeP - upon successful completion, contains the information about the 
3618  * specified volume.
3619  *
3620  * LOCKS
3621  * 
3622  * No locks are obtained or released by this function
3623  *
3624  * RETURN CODES
3625  *
3626  * Returns != 0 upon successful completion.
3627  */
3628
3629 int ADMINAPI
3630 vos_VolumeGet(const void *cellHandle, const void *serverHandle,
3631               vos_MessageCallBack_t callBack, unsigned int partition,
3632               unsigned int volumeId, vos_volumeEntry_p volumeP,
3633               afs_status_p st)
3634 {
3635     int rc = 0;
3636     afs_status_t tst = 0;
3637     file_server_p f_server = (file_server_p) serverHandle;
3638     struct volintXInfo *info = NULL;
3639
3640     /*
3641      * Validate arguments
3642      */
3643
3644     if (!IsValidServerHandle(f_server, &tst)) {
3645         goto fail_vos_VolumeGet;
3646     }
3647
3648     if (partition > VOLMAXPARTS) {
3649         tst = ADMVOSPARTITIONIDTOOLARGE;
3650         goto fail_vos_VolumeGet;
3651     }
3652
3653     if (volumeP == NULL) {
3654         tst = ADMVOSVOLUMEPNULL;
3655         goto fail_vos_VolumeGet;
3656     }
3657
3658     /*
3659      * Retrieve the information for the volume
3660      */
3661
3662     if (!UV_XListOneVolume(f_server->serv, partition, volumeId, &info, &tst)) {
3663         goto fail_vos_VolumeGet;
3664     }
3665
3666     /*
3667      * Copy the volume info to our structure
3668      */
3669
3670     if (!copyvolintXInfo(info, volumeP, &tst)) {
3671         goto fail_vos_VolumeGet;
3672     }
3673     rc = 1;
3674
3675   fail_vos_VolumeGet:
3676
3677     if (info != NULL) {
3678         free(info);
3679     }
3680
3681     if (st != NULL) {
3682         *st = tst;
3683     }
3684     return rc;
3685 }
3686
3687 /*
3688  * The iterator functions and data for the volume retrieval functions.
3689  */
3690
3691 typedef struct volume_get {
3692     struct volintXInfo *vollist;
3693     afs_int32 total;            /* total number of volumes at this partition */
3694     afs_int32 index;            /* index to the current volume */
3695     vos_volumeEntry_t entry[CACHED_ITEMS];      /* the cache of entries */
3696 } volume_get_t, *volume_get_p;
3697
3698 static int
3699 GetVolumeRPC(void *rpc_specific, int slot, int *last_item,
3700              int *last_item_contains_data, afs_status_p st)
3701 {
3702     int rc = 0;
3703     afs_status_t tst = 0;
3704     volume_get_p entry = (volume_get_p) rpc_specific;
3705
3706     /*
3707      * Copy the next entry into the cache
3708      */
3709
3710     if (!copyvolintXInfo
3711         (&entry->vollist[entry->index], &entry->entry[slot], &tst)) {
3712         goto fail_GetVolumeRPC;
3713     }
3714     entry->index++;
3715
3716     /*
3717      * See if we've processed all the entries
3718      */
3719
3720
3721     if (entry->index == entry->total) {
3722         *last_item = 1;
3723         *last_item_contains_data = 1;
3724     }
3725     rc = 1;
3726
3727   fail_GetVolumeRPC:
3728
3729     if (st != NULL) {
3730         *st = tst;
3731     }
3732     return rc;
3733 }
3734
3735 static int
3736 GetVolumeFromCache(void *rpc_specific, int slot, void *dest, afs_status_p st)
3737 {
3738     int rc = 0;
3739     afs_status_t tst = 0;
3740     volume_get_p entry = (volume_get_p) rpc_specific;
3741
3742     memcpy(dest, (const void *)&entry->entry[slot],
3743            sizeof(vos_volumeEntry_t));
3744     rc = 1;
3745
3746     if (st != NULL) {
3747         *st = tst;
3748     }
3749     return rc;
3750 }
3751
3752
3753 static int
3754 DestroyVolume(void *rpc_specific, afs_status_p st)
3755 {
3756     int rc = 0;
3757     afs_status_t tst = 0;
3758     volume_get_p entry = (volume_get_p) rpc_specific;
3759
3760     if (entry->vollist != NULL) {
3761         free(entry->vollist);
3762     }
3763     rc = 1;
3764
3765     if (st != NULL) {
3766         *st = tst;
3767     }
3768     return rc;
3769 }
3770
3771
3772 /*
3773  * vos_VolumeGetBegin - begin to iterator over the list of volumes at a server.
3774  *
3775  * PARAMETERS
3776  *
3777  * IN cellHandle - a previously opened cellHandle that corresponds
3778  * to the cell where the volumes exist.
3779  *
3780  * IN serverHandle - a handle to the server where the volumes exist.
3781  *
3782  * IN callBack - a call back function pointer that may be called to report
3783  * status information.  Can be null.
3784  *
3785  * IN partition - the partition whose volumes should be listed.  Can be null.
3786  *
3787  * OUT iterationIdP - upon successful completion, contains an iterator that
3788  * can be passed to vos_VolumeGetBegin.
3789  *
3790  * LOCKS
3791  * 
3792  * No locks are obtained or released by this function
3793  *
3794  * RETURN CODES
3795  *
3796  * Returns != 0 upon successful completion.
3797  */
3798
3799 int ADMINAPI
3800 vos_VolumeGetBegin(const void *cellHandle, const void *serverHandle,
3801                    vos_MessageCallBack_t callBack, unsigned int partition,
3802                    void **iterationIdP, afs_status_p st)
3803 {
3804     int rc = 0;
3805     afs_status_t tst = 0;
3806     file_server_p f_server = (file_server_p) serverHandle;
3807     afs_admin_iterator_p iter =
3808         (afs_admin_iterator_p) malloc(sizeof(afs_admin_iterator_t));
3809     volume_get_p entry = (volume_get_p) calloc(1, sizeof(volume_get_t));
3810
3811     /*
3812      * Validate arguments
3813      */
3814
3815     if (!IsValidServerHandle(f_server, &tst)) {
3816         goto fail_vos_VolumeGetBegin;
3817     }
3818
3819     if (partition > VOLMAXPARTS) {
3820         tst = ADMVOSPARTITIONIDTOOLARGE;
3821         goto fail_vos_VolumeGetBegin;
3822     }
3823
3824     if ((iter == NULL) || (entry == NULL)) {
3825         tst = ADMNOMEM;
3826         goto fail_vos_VolumeGetBegin;
3827     }
3828
3829     /*
3830      * Get a list of all the volumes contained in the partition at the
3831      * server
3832      */
3833
3834     if (!UV_XListVolumes
3835         (f_server->serv, partition, 1, &entry->vollist, &entry->total,
3836          &tst)) {
3837         goto fail_vos_VolumeGetBegin;
3838     }
3839
3840     if (entry->total == 0) {
3841         if (!IteratorInit(iter, (void *)entry, NULL, NULL, NULL, NULL, &tst)) {
3842             goto fail_vos_VolumeGetBegin;
3843         }
3844         iter->done_iterating = 1;
3845         iter->st = ADMITERATORDONE;
3846     } else {
3847         if (!IteratorInit
3848             (iter, (void *)entry, GetVolumeRPC, GetVolumeFromCache, NULL,
3849              DestroyVolume, &tst)) {
3850             goto fail_vos_VolumeGetBegin;
3851         }
3852     }
3853     *iterationIdP = (void *)iter;
3854     rc = 1;
3855
3856   fail_vos_VolumeGetBegin:
3857
3858     if (rc == 0) {
3859         if (iter != NULL) {
3860             free(iter);
3861         }
3862         if (entry != NULL) {
3863             free(entry);
3864         }
3865     }
3866
3867     if (st != NULL) {
3868         *st = tst;
3869     }
3870     return rc;
3871 }
3872
3873 /*
3874  * vos_VolumeGetNext - get information about the next volume.
3875  *
3876  * PARAMETERS
3877  *
3878  * IN iterationId - an iterator previously returned by
3879  * vos_VolumeGetBegin
3880  *
3881  * OUT volumeP - a pointer to a vos_volumeEntry_t
3882  * that upon successful completion contains information about the
3883  * next volume.
3884  *
3885  * LOCKS
3886  * 
3887  * The iterator is locked while the next item is retrieved.
3888  *
3889  * RETURN CODES
3890  *
3891  * Returns != 0 upon successful completion.
3892  */
3893
3894 int ADMINAPI
3895 vos_VolumeGetNext(const void *iterationId, vos_volumeEntry_p volumeP,
3896                   afs_status_p st)
3897 {
3898     int rc = 0;
3899     afs_status_t tst = 0;
3900     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
3901
3902     if (iter == NULL) {
3903         tst = ADMITERATORNULL;
3904         goto fail_vos_VolumeGetNext;
3905     }
3906
3907     if (volumeP == NULL) {
3908         tst = ADMVOSVOLUMEPNULL;
3909         goto fail_vos_VolumeGetNext;
3910     }
3911
3912     rc = IteratorNext(iter, (void *)volumeP, &tst);
3913
3914   fail_vos_VolumeGetNext:
3915
3916     if (st != NULL) {
3917         *st = tst;
3918     }
3919     return rc;
3920 }
3921
3922 /*
3923  * vos_VolumeGetDone - finish using a volume iterator.
3924  *
3925  * PARAMETERS
3926  *
3927  * IN iterationId - an iterator previously returned by vos_VolumeGetBegin
3928  *
3929  * LOCKS
3930  * 
3931  * The iterator is locked and then destroyed.
3932  *
3933  * RETURN CODES
3934  *
3935  * Returns != 0 upon successful completion.
3936  */
3937
3938 int ADMINAPI
3939 vos_VolumeGetDone(const void *iterationId, afs_status_p st)
3940 {
3941     int rc = 0;
3942     afs_status_t tst = 0;
3943     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
3944
3945     /*
3946      * Validate arguments
3947      */
3948
3949     if (iter == NULL) {
3950         tst = ADMITERATORNULL;
3951         goto fail_vos_VolumeGetDone;
3952     }
3953
3954     rc = IteratorDone(iter, &tst);
3955
3956   fail_vos_VolumeGetDone:
3957
3958     if (st != NULL) {
3959         *st = tst;
3960     }
3961     return rc;
3962 }
3963
3964 /*
3965  * vos_VolumeMove - move a volume from one server to another.
3966  *
3967  * PARAMETERS
3968  *
3969  * IN cellHandle - a previously opened cellHandle that corresponds
3970  * to the cell where the volume exists.
3971  *
3972  * IN callBack - a call back function pointer that may be called to report
3973  * status information.  Can be null.
3974  *
3975  * IN volumeId - the volume id of the volume to be moved.
3976  *
3977  * IN fromServer - a previously opened serverHandle that corresponds
3978  * to the server where the volume currently resides.
3979  *
3980  * IN fromPartition - the partition where the volume currently resides.
3981  *
3982  * IN toServer - a previously opened serverHandle that corresponds
3983  * to the server where the volume will be moved.
3984  *
3985  * IN toPartition - the partition where the volume will be moved.
3986  *
3987  * LOCKS
3988  * 
3989  * No locks are obtained or released by this function
3990  *
3991  * RETURN CODES
3992  *
3993  * Returns != 0 upon successful completion.
3994  */
3995
3996 int ADMINAPI
3997 vos_VolumeMove(const void *cellHandle, vos_MessageCallBack_t callBack,
3998                unsigned int volumeId, const void *fromServer,
3999                unsigned int fromPartition, const void *toServer,
4000                unsigned int toPartition, afs_status_p st)
4001 {
4002     int rc = 0;
4003     afs_status_t tst = 0;
4004     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
4005     file_server_p from_server = (file_server_p) fromServer;
4006     file_server_p to_server = (file_server_p) toServer;
4007     afs_int32 from_server_addr =
4008         ntohl(rx_HostOf(rx_PeerOf(from_server->serv)));
4009     afs_int32 to_server_addr = ntohl(rx_HostOf(rx_PeerOf(to_server->serv)));
4010     afs_int32 from_partition = fromPartition;
4011     afs_int32 to_partition = toPartition;
4012
4013     /*
4014      * Validate arguments
4015      */
4016
4017     if (!IsValidCellHandle(c_handle, &tst)) {
4018         goto fail_vos_VolumeMove;
4019     }
4020
4021     if (!IsValidServerHandle(from_server, &tst)) {
4022         goto fail_vos_VolumeMove;
4023     }
4024
4025     if (!IsValidServerHandle(to_server, &tst)) {
4026         goto fail_vos_VolumeMove;
4027     }
4028
4029     if (fromPartition > VOLMAXPARTS) {
4030         tst = ADMVOSPARTITIONIDTOOLARGE;
4031         goto fail_vos_VolumeMove;
4032     }
4033
4034     if (toPartition > VOLMAXPARTS) {
4035         tst = ADMVOSPARTITIONIDTOOLARGE;
4036         goto fail_vos_VolumeMove;
4037     }
4038
4039     /*
4040      * Move the volume
4041      */
4042
4043     rc = UV_MoveVolume(c_handle, volumeId, from_server_addr, from_partition,
4044                        to_server_addr, to_partition, &tst);
4045
4046   fail_vos_VolumeMove:
4047
4048     if (st != NULL) {
4049         *st = tst;
4050     }
4051     return rc;
4052 }
4053
4054 /*
4055  * vos_VolumeRelease - release a volume.
4056  *
4057  * PARAMETERS
4058  *
4059  * IN cellHandle - a previously opened cellHandle that corresponds
4060  * to the cell where the volume exists.
4061  *
4062  * IN callBack - a call back function pointer that may be called to report
4063  * status information.  Can be null.
4064  *
4065  * IN volumeId - the volume to be released.
4066  *
4067  * IN force - force a complete release.
4068  *
4069  * LOCKS
4070  * 
4071  * No locks are obtained or released by this function
4072  *
4073  * RETURN CODES
4074  *
4075  * Returns != 0 upon successful completion.
4076  */
4077
4078 int ADMINAPI
4079 vos_VolumeRelease(const void *cellHandle, vos_MessageCallBack_t callBack,
4080                   unsigned int volumeId, vos_force_t force, afs_status_p st)
4081 {
4082     int rc = 0;
4083     afs_status_t tst = 0;
4084     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
4085     afs_int32 server, part, forc = 0, voltype, volume;
4086     struct nvldbentry entry;
4087
4088     /*
4089      * Validate arguments
4090      */
4091
4092     if (!IsValidCellHandle(c_handle, &tst)) {
4093         goto fail_vos_VolumeRelease;
4094     }
4095
4096     if (!GetVolumeInfo
4097         (c_handle, volumeId, &entry, &server, &part, &voltype, &tst)) {
4098         goto fail_vos_VolumeRelease;
4099     }
4100
4101     if (force == VOS_FORCE) {
4102         forc = 1;
4103     }
4104
4105     volume = volumeId;
4106     rc = UV_ReleaseVolume(c_handle, volume, server, part, forc, &tst);
4107
4108   fail_vos_VolumeRelease:
4109
4110     if (st != NULL) {
4111         *st = tst;
4112     }
4113     return rc;
4114 }
4115
4116 /*
4117  * vos_VolumeZap - forcibly delete a volume.
4118  *
4119  * PARAMETERS
4120  *
4121  * IN cellHandle - a previously opened cellHandle that corresponds
4122  * to the cell where the volume exists.
4123  *
4124  * IN serverHandle - a previously opened serverHandle that corresponds
4125  * to the server where the volume exists.
4126  *
4127  * IN callBack - a call back function pointer that may be called to report
4128  * status information.  Can be null.
4129  *
4130  * IN partition - the partition where the volume exists.
4131  *
4132  * IN volumeId - the volume id of the vldb entry to be deleted.
4133  *
4134  * IN force - force the deletion of bad volumes.
4135  *
4136  * LOCKS
4137  * 
4138  * No locks are obtained or released by this function
4139  *
4140  * RETURN CODES
4141  *
4142  * Returns != 0 upon successful completion.
4143  */
4144
4145 int ADMINAPI
4146 vos_VolumeZap(const void *cellHandle, const void *serverHandle,
4147               vos_MessageCallBack_t callBack, unsigned int partition,
4148               unsigned int volumeId, vos_force_t force, afs_status_p st)
4149 {
4150     int rc = 0;
4151     afs_status_t tst = 0;
4152     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
4153     file_server_p f_server = (file_server_p) serverHandle;
4154
4155     /*
4156      * Verify that the cellHandle is capable of making vos rpc's
4157      */
4158
4159     if (!IsValidCellHandle(c_handle, &tst)) {
4160         goto fail_vos_VolumeZap;
4161     }
4162
4163     if (!IsValidServerHandle(f_server, &tst)) {
4164         goto fail_vos_VolumeZap;
4165     }
4166
4167     if (force == VOS_FORCE) {
4168         rc = UV_NukeVolume(c_handle, f_server->serv, partition, volumeId,
4169                            &tst);
4170     } else {
4171         rc = UV_VolumeZap(c_handle, f_server->serv, partition, volumeId,
4172                           &tst);
4173     }
4174
4175   fail_vos_VolumeZap:
4176
4177     if (st != NULL) {
4178         *st = tst;
4179     }
4180     return rc;
4181 }
4182
4183 /*
4184  * vos_PartitionNameToId - translate a string representing a partition
4185  * to a number.
4186  *
4187  * PARAMETERS
4188  *
4189  * IN partitionName - a string representing a partition.  Must be of
4190  * the form /vicep..
4191  *
4192  * OUT partitionId - a number containing the partition id upon successful 
4193  * completion.
4194  *
4195  * LOCKS
4196  * 
4197  * No locks are obtained or released by this function
4198  *
4199  * RETURN CODES
4200  *
4201  * Returns != 0 upon successful completion.
4202  */
4203
4204 int ADMINAPI
4205 vos_PartitionNameToId(const char *partitionName, unsigned int *partitionId,
4206                       afs_status_p st)
4207 {
4208     int rc = 0;
4209     afs_status_t tst = 0;
4210     size_t partition_name_len;
4211     int i;
4212
4213     /* 
4214      * Validate arguments
4215      */
4216
4217     if (partitionName == NULL) {
4218         tst = ADMVOSPARTITIONNAMENULL;
4219         goto fail_vos_PartitionNameToId;
4220     }
4221
4222     if (partitionId == NULL) {
4223         tst = ADMVOSPARTITIONIDNULL;
4224         goto fail_vos_PartitionNameToId;
4225     }
4226
4227     /*
4228      * Check that string begins with /vicep
4229      */
4230
4231     if (strncmp(partitionName, VICE_PARTITION_PREFIX, VICE_PREFIX_SIZE)) {
4232         tst = ADMVOSPARTITIONNAMEINVALID;
4233         goto fail_vos_PartitionNameToId;
4234     }
4235
4236     /*
4237      * Check that the string is either one or two characters
4238      * longer than VICE_PREFIX_SIZE
4239      */
4240
4241     partition_name_len = strlen(partitionName);
4242
4243     if (partition_name_len == VICE_PREFIX_SIZE) {
4244         tst = ADMVOSPARTITIONNAMETOOSHORT;
4245         goto fail_vos_PartitionNameToId;
4246     }
4247
4248     if (partition_name_len > (VICE_PREFIX_SIZE + 2)) {
4249         tst = ADMVOSPARTITIONNAMETOOLONG;
4250         goto fail_vos_PartitionNameToId;
4251     }
4252
4253     /*
4254      * Check that all characters past the prefix are lower case
4255      */
4256
4257     for (i = VICE_PREFIX_SIZE; i < partition_name_len; i++) {
4258         if (!islower(partitionName[i])) {
4259             tst = ADMVOSPARTITIONNAMENOTLOWER;
4260             goto fail_vos_PartitionNameToId;
4261         }
4262     }
4263
4264     /*
4265      * Convert the name to a number
4266      */
4267
4268     if (partitionName[VICE_PREFIX_SIZE + 1] == 0) {
4269         *partitionId = partitionName[VICE_PREFIX_SIZE] - 'a';
4270     } else {
4271         *partitionId =
4272             (partitionName[VICE_PREFIX_SIZE] - 'a') * 26 +
4273             (partitionName[VICE_PREFIX_SIZE + 1] - 'a') + 26;
4274     }
4275
4276     if (*partitionId > VOLMAXPARTS) {
4277         tst = ADMVOSPARTITIONIDTOOLARGE;
4278         goto fail_vos_PartitionNameToId;
4279     }
4280     rc = 1;
4281
4282   fail_vos_PartitionNameToId:
4283
4284     if (st != NULL) {
4285         *st = tst;
4286     }
4287     return rc;
4288 }
4289
4290 /*
4291  * vos_PartitionIdToName - translate a number representing a partition
4292  * to a character string.
4293  *
4294  * PARAMETERS
4295  *
4296  * IN partitionId - an integer representing the partition.
4297  *
4298  * OUT partitionName - a string containing the converted partition ID
4299  * upon successful completion.
4300  *
4301  * LOCKS
4302  * 
4303  * No locks are obtained or released by this function
4304  *
4305  * RETURN CODES
4306  *
4307  * Returns != 0 upon successful completion.
4308  */
4309
4310 int ADMINAPI
4311 vos_PartitionIdToName(unsigned int partitionId, char *partitionName,
4312                       afs_status_p st)
4313 {
4314     int rc = 0;
4315     afs_status_t tst = 0;
4316
4317     if (partitionId > VOLMAXPARTS) {
4318         tst = ADMVOSPARTITIONIDTOOLARGE;
4319         goto fail_vos_PartitionIdToName;
4320     }
4321
4322     if (partitionName == NULL) {
4323         tst = ADMVOSPARTITIONNAMENULL;
4324         goto fail_vos_PartitionIdToName;
4325     }
4326
4327     if (partitionId < 26) {
4328         strcpy(partitionName, VICE_PARTITION_PREFIX);
4329         partitionName[6] = partitionId + 'a';
4330         partitionName[7] = '\0';
4331     } else {
4332         strcpy(partitionName, VICE_PARTITION_PREFIX);
4333         partitionId -= 26;
4334         partitionName[6] = 'a' + (partitionId / 26);
4335         partitionName[7] = 'a' + (partitionId % 26);
4336         partitionName[8] = '\0';
4337     }
4338     rc = 1;
4339
4340   fail_vos_PartitionIdToName:
4341
4342     if (st != NULL) {
4343         *st = tst;
4344     }
4345     return rc;
4346 }
4347
4348 /*
4349  * vos_VolumeQuotaChange - change the quota of a volume.
4350  *
4351  * PARAMETERS
4352  *
4353  * IN cellHandle - a previously opened cellHandle that corresponds
4354  * to the cell where the volume exists.
4355  *
4356  * IN serverHandle - a previously opened serverHandle that corresponds
4357  * to the server where the volume exists.
4358  *
4359  * IN callBack - a call back function pointer that may be called to report
4360  * status information.  Can be null.
4361  *
4362  * IN partition - the partition where the volume exists.
4363  *
4364  * IN volumeId - the volume id of the volume to be modified.
4365  *
4366  * IN volumeQuota - the new volume quota.
4367  *
4368  * LOCKS
4369  * 
4370  * No locks are obtained or released by this function
4371  *
4372  * RETURN CODES
4373  *
4374  * Returns != 0 upon successful completion.
4375  */
4376
4377 int ADMINAPI
4378 vos_VolumeQuotaChange(const void *cellHandle, const void *serverHandle,
4379                       vos_MessageCallBack_t callBack, unsigned int partition,
4380                       unsigned int volumeId, unsigned int volumeQuota,
4381                       afs_status_p st)
4382 {
4383     int rc = 0;
4384     afs_status_t tst = 0;
4385     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
4386     file_server_p f_server = (file_server_p) serverHandle;
4387     int ttid = 0;
4388     int rcode = 0;
4389     struct volintInfo tstatus;
4390     int active_trans = 0;
4391
4392     /*
4393      * Verify that the cellHandle is capable of making vos rpc's
4394      */
4395
4396     if (!IsValidCellHandle(c_handle, &tst)) {
4397         goto fail_vos_VolumeQuotaChange;
4398     }
4399
4400     if (!IsValidServerHandle(f_server, &tst)) {
4401         goto fail_vos_VolumeQuotaChange;
4402     }
4403
4404     memset((void *)&tstatus, 0, sizeof(tstatus));
4405     tstatus.dayUse = -1;
4406     tstatus.spare2 = -1;
4407     tstatus.maxquota = volumeQuota;
4408
4409
4410     tst =
4411         AFSVolTransCreate(f_server->serv, volumeId, partition, ITBusy, &ttid);
4412     if (tst) {
4413         goto fail_vos_VolumeQuotaChange;
4414     }
4415     active_trans = 1;
4416
4417     tst = AFSVolSetInfo(f_server->serv, ttid, &tstatus);
4418     if (tst) {
4419         goto fail_vos_VolumeQuotaChange;
4420     }
4421     rc = 1;
4422
4423   fail_vos_VolumeQuotaChange:
4424
4425     if (active_trans) {
4426         afs_status_t tst2 = 0;
4427         tst2 = AFSVolEndTrans(f_server->serv, ttid, &rcode);
4428         if (tst2) {
4429             if (tst == 0) {
4430                 tst = tst2;
4431                 rc = 0;
4432             }
4433         }
4434         if (rcode) {
4435             if (tst == 0) {
4436                 tst = rcode;
4437                 rc = 0;
4438             }
4439         }
4440     }
4441
4442     if (st != NULL) {
4443         *st = tst;
4444     }
4445     return rc;
4446 }
4447 /*
4448  * vos_VolumeGet2 - get information about a particular volume.
4449  *
4450  * PARAMETERS
4451  *
4452  * IN cellHandle - a previously opened cellHandle that corresponds
4453  * to the cell where the volume exists.
4454  *
4455  * IN serverHandle - a previously opened serverHandle that corresponds
4456  * to the server where the volume exists.
4457  *
4458  * IN callBack - a call back function pointer that may be called to report
4459  * status information.  Can be null.
4460  *
4461  * IN partition - the partition where the volume exists.
4462  *
4463  * IN volumeId - the volume id of the volume to be retrieved.
4464  *
4465  * OUT pinfo - upon successful completion, contains the information about the 
4466  * specified volume.
4467  *
4468  * LOCKS
4469  * 
4470  * No locks are obtained or released by this function
4471  *
4472  * RETURN CODES
4473  *
4474  * Returns != 0 upon successful completion.
4475  */
4476
4477 int ADMINAPI
4478 vos_VolumeGet2(const void *cellHandle, const void *serverHandle,
4479               vos_MessageCallBack_t callBack, unsigned int partition,
4480               unsigned int volumeId, volintInfo* pinfo,
4481               afs_status_p st)
4482 {
4483     int rc = 0;
4484     afs_status_t tst = 0;
4485     file_server_p f_server = (file_server_p) serverHandle;
4486     volintInfo *pinfo_=0;
4487
4488     /*
4489      * Validate arguments
4490      */
4491
4492     if (!IsValidServerHandle(f_server, &tst)) {
4493         goto fail_vos_VolumeGet2;
4494     }
4495
4496     if (partition > VOLMAXPARTS) {
4497         tst = ADMVOSPARTITIONIDTOOLARGE;
4498         goto fail_vos_VolumeGet2;
4499     }
4500
4501     if (pinfo == NULL) {
4502         tst = ADMVOSVOLUMEPNULL;
4503         goto fail_vos_VolumeGet2;
4504     }
4505
4506     /*
4507      * Retrieve the information for the volume
4508      */
4509
4510     if (!UV_ListOneVolume(f_server->serv, partition, volumeId, &pinfo_,&tst)) {
4511         goto fail_vos_VolumeGet2;
4512     }
4513
4514
4515     rc = 1;
4516
4517   fail_vos_VolumeGet2:
4518
4519     if (pinfo_ != NULL) {
4520      memcpy(pinfo,pinfo_,sizeof(volintInfo));
4521         free(pinfo_);
4522     }
4523
4524     if (st != NULL) {
4525         *st = tst;
4526     }
4527     return rc;
4528 }
4529
4530 /*
4531  * vos_ClearVolUpdateCounter - reset volUpdateCounter of a volume to zero
4532  *
4533  * PARAMETERS
4534  *
4535  * IN cellHandle - a previously opened cellHandle that corresponds
4536  * to the cell where the volume exists.
4537  *
4538  * IN serverHandle - a previously opened serverHandle that corresponds
4539  * to the server where the volume exists.
4540  *
4541  * IN partition - the partition where the volume exists.
4542  *
4543  * IN volumeId - the volume id of the volume to be retrieved.
4544  *
4545  * LOCKS
4546  * 
4547  * No locks are obtained or released by this function
4548  *
4549  * RETURN CODES
4550  *
4551  * Returns != 0 upon successful completion.
4552  */
4553
4554 int ADMINAPI
4555 vos_ClearVolUpdateCounter(const void *cellHandle,
4556                                   const void *serverHandle,
4557                                   unsigned int partition,
4558                                   unsigned int volumeId,
4559                       &nbs