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