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