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