OPENAFS-SA-2016-002 ListAddrByAttributes 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     memset(&m_attrs, 0, sizeof(m_attrs));
1192     /*
1193      * Check to see if this is a multihomed address server
1194      */
1195
1196     if (((*addrP & 0xff000000) == 0xff000000) && ((*addrP) & 0xffff)) {
1197         base = (*addrP >> 16) & 0xff;
1198         index = (*addrP) & 0xffff;
1199
1200         if ((base >= 0) && (base <= VL_MAX_ADDREXTBLKS) && (index >= 1)
1201             && (index <= VL_MHSRV_PERBLK)) {
1202
1203             /*
1204              * This is a multihomed server.  Make an rpc to retrieve
1205              * all its addresses.  Copy the addresses into the cache.
1206              */
1207
1208             m_attrs.Mask = VLADDR_INDEX;
1209             m_attrs.index = (base * VL_MHSRV_PERBLK) + index;
1210             total_multi = 0;
1211             addr_multi.bulkaddrs_val = 0;
1212             addr_multi.bulkaddrs_len = 0;
1213             tst =
1214                 ubik_VL_GetAddrsU(serv->vldb, 0, &m_attrs, &m_uuid,
1215                           &m_unique, &total_multi, &addr_multi);
1216             if (tst) {
1217                 goto fail_GetServerRPC;
1218             }
1219
1220             /*
1221              * Remove any bogus IP addresses which the user may have
1222              * been unable to remove.
1223              */
1224
1225             RemoveBadAddresses(&total_multi, &addr_multi);
1226
1227             /*
1228              * Copy all the addresses into the cache
1229              */
1230
1231             for (i = 0; i < total_multi; i++) {
1232                 serv->server[slot].serverAddress[i] =
1233                     addr_multi.bulkaddrs_val[i];
1234             }
1235
1236             serv->server[slot].count = total_multi;
1237             serv->address_index++;
1238             free(addr_multi.bulkaddrs_val);
1239         }
1240
1241         /*
1242          * The next address is just a plain old address
1243          */
1244
1245     } else {
1246         serv->server[slot].serverAddress[0] = *addrP;
1247         serv->server[slot].count = 1;
1248         serv->address_index++;
1249     }
1250
1251     /*
1252      * See if we've processed all the entries
1253      */
1254
1255
1256     if (serv->address_index == serv->total_addresses) {
1257         *last_item = 1;
1258         *last_item_contains_data = 1;
1259     }
1260     rc = 1;
1261
1262   fail_GetServerRPC:
1263
1264     if (st != NULL) {
1265         *st = tst;
1266     }
1267     return rc;
1268 }
1269
1270 static int
1271 GetServerFromCache(void *rpc_specific, int slot, void *dest, afs_status_p st)
1272 {
1273     int rc = 0;
1274     afs_status_t tst = 0;
1275     server_get_p serv = (server_get_p) rpc_specific;
1276
1277     memcpy(dest, (const void *)&serv->server[slot],
1278            sizeof(vos_fileServerEntry_t));
1279     rc = 1;
1280
1281     if (st != NULL) {
1282         *st = tst;
1283     }
1284     return rc;
1285 }
1286
1287
1288 static int
1289 DestroyServer(void *rpc_specific, afs_status_p st)
1290 {
1291     int rc = 0;
1292     afs_status_t tst = 0;
1293     server_get_p serv = (server_get_p) rpc_specific;
1294
1295     if (serv->addresses.bulkaddrs_val != NULL) {
1296         free(serv->addresses.bulkaddrs_val);
1297     }
1298     rc = 1;
1299
1300     if (st != NULL) {
1301         *st = tst;
1302     }
1303     return rc;
1304 }
1305
1306 /*
1307  * vos_FileServerGetBegin - begin to iterate over the file servers in a cell.
1308  *
1309  * PARAMETERS
1310  *
1311  * IN cellHandle - a previously opened cellHandle that corresponds
1312  * to the cell where the file servers exist.
1313  *
1314  * IN callBack - a call back function pointer that may be called to report
1315  * status information.  Can be null.
1316  *
1317  * OUT iterationIdP - upon successful completion, contains an iterator that
1318  * can be passed to vos_FileServerGetNext.
1319  *
1320  * LOCKS
1321  * 
1322  * No locks are obtained or released by this function
1323  *
1324  * RETURN CODES
1325  *
1326  * Returns != 0 upon successful completion.
1327  */
1328
1329 int ADMINAPI
1330 vos_FileServerGetBegin(const void *cellHandle, vos_MessageCallBack_t callBack,
1331                        void **iterationIdP, afs_status_p st)
1332 {
1333     int rc = 0;
1334     afs_status_t tst = 0;
1335     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1336     afs_admin_iterator_p iter = malloc(sizeof(afs_admin_iterator_t));
1337     server_get_p serv = calloc(1, sizeof(server_get_t));
1338     struct VLCallBack unused;
1339
1340
1341     /*
1342      * Validate arguments
1343      */
1344
1345     if (!IsValidCellHandle(c_handle, &tst)) {
1346         goto fail_vos_FileServerGetBegin;
1347     }
1348
1349     if (iterationIdP == NULL) {
1350         goto fail_vos_FileServerGetBegin;
1351     }
1352
1353     if ((iter == NULL) || (serv == NULL)) {
1354         tst = ADMNOMEM;
1355         goto fail_vos_FileServerGetBegin;
1356     }
1357
1358     /*
1359      * Fill in the serv structure
1360      */
1361
1362     serv->vldb = c_handle->vos;
1363     tst =
1364         ubik_VL_GetAddrs(c_handle->vos, 0, 0, 0, &unused,
1365                       &serv->total_addresses, &serv->addresses);
1366
1367     if (tst) {
1368         goto fail_vos_FileServerGetBegin;
1369     }
1370
1371     /*
1372      * Remove any bogus IP addresses which the user may have
1373      * been unable to remove.
1374      */
1375
1376     RemoveBadAddresses(&serv->total_addresses, &serv->addresses);
1377
1378     if (serv->total_addresses == 0) {
1379         if (!IteratorInit(iter, (void *)serv, NULL, NULL, NULL, NULL, &tst)) {
1380             goto fail_vos_FileServerGetBegin;
1381         }
1382         iter->done_iterating = 1;
1383         iter->st = ADMITERATORDONE;
1384     } else {
1385         if (!IteratorInit
1386             (iter, (void *)serv, GetServerRPC, GetServerFromCache, NULL,
1387              DestroyServer, &tst)) {
1388             goto fail_vos_FileServerGetBegin;
1389         }
1390     }
1391     *iterationIdP = (void *)iter;
1392     rc = 1;
1393
1394   fail_vos_FileServerGetBegin:
1395
1396     if (rc == 0) {
1397         if (iter != NULL) {
1398             free(iter);
1399         }
1400         if (serv != NULL) {
1401             if (serv->addresses.bulkaddrs_val != NULL) {
1402                 free(serv->addresses.bulkaddrs_val);
1403             }
1404             free(serv);
1405         }
1406     }
1407
1408     if (st != NULL) {
1409         *st = tst;
1410     }
1411     return rc;
1412 }
1413
1414 /*
1415  * vos_FileServerGetNext - get information about the next fileserver in the cell.
1416  *
1417  * PARAMETERS
1418  *
1419  * IN iterationId - an iterator previously returned by
1420  * vos_FileServerGetBegin
1421  *
1422  * OUT serverEntryP - a pointer to a vos_fileServerEntry_t that upon successful
1423  * completion contains information about the next server in the cell.
1424  *
1425  * LOCKS
1426  * 
1427  * The iterator is locked while the next server is retrieved.
1428  *
1429  * RETURN CODES
1430  *
1431  * Returns != 0 upon successful completion.
1432  */
1433
1434 int ADMINAPI
1435 vos_FileServerGetNext(void *iterationId, vos_fileServerEntry_p serverEntryP,
1436                       afs_status_p st)
1437 {
1438     int rc = 0;
1439     afs_status_t tst = 0;
1440     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
1441
1442     if (iter == NULL) {
1443         tst = ADMITERATORNULL;
1444         goto fail_vos_FileServerGetNext;
1445     }
1446
1447     if (serverEntryP == NULL) {
1448         tst = ADMVOSSERVERENTRYPNULL;
1449         goto fail_vos_FileServerGetNext;
1450     }
1451
1452     rc = IteratorNext(iter, (void *)serverEntryP, &tst);
1453
1454   fail_vos_FileServerGetNext:
1455
1456     if (st != NULL) {
1457         *st = tst;
1458     }
1459     return rc;
1460 }
1461
1462 /*
1463  * vos_FileServerGetDone - finish using a partition iterator.
1464  *
1465  * PARAMETERS
1466  *
1467  * IN iterationId - an iterator previously returned by vos_FileServerGetBegin
1468  *
1469  * LOCKS
1470  * 
1471  * The iterator is locked and then destroyed.
1472  *
1473  * RETURN CODES
1474  *
1475  * Returns != 0 upon successful completion.
1476  */
1477
1478 int ADMINAPI
1479 vos_FileServerGetDone(void *iterationId, afs_status_p st)
1480 {
1481     int rc = 0;
1482     afs_status_t tst = 0;
1483     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
1484
1485     /*
1486      * Validate arguments
1487      */
1488
1489     if (iter == NULL) {
1490         tst = ADMITERATORNULL;
1491         goto fail_vos_FileServerGetDone;
1492     }
1493
1494     rc = IteratorDone(iter, &tst);
1495
1496   fail_vos_FileServerGetDone:
1497
1498     if (st != NULL) {
1499         *st = tst;
1500     }
1501     return rc;
1502 }
1503
1504 /*
1505  * The iterator functions and data for the transation retrieval functions.
1506  */
1507
1508 typedef struct transaction_get {
1509     afs_int32 total;            /* total number of transactions */
1510     afs_int32 index;            /* index to the current transaction */
1511     transDebugInfo *cur;        /* the current transaction */
1512     vos_serverTransactionStatus_t tran[CACHED_ITEMS];   /* the cache of trans */
1513 } transaction_get_t, *transaction_get_p;
1514
1515 static int
1516 GetTransactionRPC(void *rpc_specific, int slot, int *last_item,
1517                   int *last_item_contains_data, afs_status_p st)
1518 {
1519     int rc = 0;
1520     afs_status_t tst = 0;
1521     transaction_get_p t = (transaction_get_p) rpc_specific;
1522     int index = t->index;
1523
1524     /*
1525      * Copy the next transaction into the cache
1526      */
1527
1528     t->tran[slot].transactionId = t->cur[index].tid;
1529     t->tran[slot].lastActiveTime = t->cur[index].time;
1530     t->tran[slot].creationTime = t->cur[index].creationTime;
1531     t->tran[slot].errorCode = t->cur[index].returnCode;
1532     t->tran[slot].volumeId = t->cur[index].volid;
1533     t->tran[slot].partition = t->cur[index].partition;
1534     strcpy(t->tran[slot].lastProcedureName, t->cur[index].lastProcName);
1535     t->tran[slot].nextReceivePacketSequenceNumber = t->cur[index].readNext;
1536     t->tran[slot].nextSendPacketSequenceNumber = t->cur[index].transmitNext;
1537     t->tran[slot].lastReceiveTime = t->cur[index].lastReceiveTime;
1538     t->tran[slot].lastSendTime = t->cur[index].lastSendTime;
1539
1540     t->tran[slot].volumeAttachMode = VOS_VOLUME_ATTACH_MODE_OK;
1541
1542     switch (t->cur[index].iflags) {
1543     case ITOffline:
1544         t->tran[slot].volumeAttachMode = VOS_VOLUME_ATTACH_MODE_OFFLINE;
1545         break;
1546     case ITBusy:
1547         t->tran[slot].volumeAttachMode = VOS_VOLUME_ATTACH_MODE_BUSY;
1548         break;
1549     case ITReadOnly:
1550         t->tran[slot].volumeAttachMode = VOS_VOLUME_ATTACH_MODE_READONLY;
1551         break;
1552     case ITCreate:
1553         t->tran[slot].volumeAttachMode = VOS_VOLUME_ATTACH_MODE_CREATE;
1554         break;
1555     case ITCreateVolID:
1556         t->tran[slot].volumeAttachMode = VOS_VOLUME_ATTACH_MODE_CREATE_VOLID;
1557         break;
1558     }
1559
1560     t->tran[slot].volumeActiveStatus = VOS_VOLUME_ACTIVE_STATUS_OK;
1561
1562     switch (t->cur[index].vflags) {
1563     case VTDeleteOnSalvage:
1564         t->tran[slot].volumeActiveStatus =
1565             VOS_VOLUME_ACTIVE_STATUS_DELETE_ON_SALVAGE;
1566         break;
1567     case VTOutOfService:
1568         t->tran[slot].volumeActiveStatus =
1569             VOS_VOLUME_ACTIVE_STATUS_OUT_OF_SERVICE;
1570         break;
1571     case VTDeleted:
1572         t->tran[slot].volumeActiveStatus = VOS_VOLUME_ACTIVE_STATUS_DELETED;
1573         break;
1574     }
1575
1576     t->tran[slot].volumeTransactionStatus = VOS_VOLUME_TRANSACTION_STATUS_OK;
1577
1578     if (t->cur[index].tflags) {
1579         t->tran[slot].volumeTransactionStatus =
1580             VOS_VOLUME_TRANSACTION_STATUS_DELETED;
1581     }
1582     t->index++;
1583
1584
1585     /*
1586      * See if we've processed all the entries
1587      */
1588
1589
1590     if (t->index == t->total) {
1591         *last_item = 1;
1592         *last_item_contains_data = 1;
1593     }
1594     rc = 1;
1595
1596     if (st != NULL) {
1597         *st = tst;
1598     }
1599     return rc;
1600 }
1601
1602 static int
1603 GetTransactionFromCache(void *rpc_specific, int slot, void *dest,
1604                         afs_status_p st)
1605 {
1606     int rc = 0;
1607     afs_status_t tst = 0;
1608     transaction_get_p tran = (transaction_get_p) rpc_specific;
1609
1610     memcpy(dest, (const void *)&tran->tran[slot],
1611            sizeof(vos_serverTransactionStatus_p));
1612     rc = 1;
1613
1614     if (st != NULL) {
1615         *st = tst;
1616     }
1617     return rc;
1618 }
1619
1620
1621 static int
1622 DestroyTransaction(void *rpc_specific, afs_status_p st)
1623 {
1624     int rc = 0;
1625     afs_status_t tst = 0;
1626     transaction_get_p tran = (transaction_get_p) rpc_specific;
1627
1628     if (tran->cur != NULL) {
1629         free(tran->cur);
1630     }
1631     rc = 1;
1632
1633     if (st != NULL) {
1634         *st = tst;
1635     }
1636     return rc;
1637 }
1638
1639 /*
1640  * vos_ServerTransactionStatusGetBegin - begin to iterate over the transactions
1641  * at a volume server.
1642  *
1643  * PARAMETERS
1644  *
1645  * IN cellHandle - a previously opened cellHandle that corresponds
1646  * to the cell where the volume server exists.
1647  *
1648  * IN serverHandle - a handle to the server to query.
1649  *
1650  * IN callBack - a call back function pointer that may be called to report
1651  * status information.  Can be null.
1652  *
1653  * OUT iterationIdP - upon successful completion, contains an iterator that
1654  * can be passed to vos_ServerTransactionStatusGetNext.
1655  *
1656  * LOCKS
1657  * 
1658  * No locks are obtained or released by this function
1659  *
1660  * RETURN CODES
1661  *
1662  * Returns != 0 upon successful completion.
1663  */
1664
1665 int ADMINAPI
1666 vos_ServerTransactionStatusGetBegin(const void *cellHandle,
1667                                     const void *serverHandle,
1668                                     vos_MessageCallBack_t callBack,
1669                                     void **iterationIdP, afs_status_p st)
1670 {
1671     int rc = 0;
1672     afs_status_t tst = 0;
1673     file_server_p f_server = (file_server_p) serverHandle;
1674     afs_admin_iterator_p iter = malloc(sizeof(afs_admin_iterator_t));
1675     transaction_get_p tran = calloc(1, sizeof(transaction_get_t));
1676
1677
1678     /*
1679      * Validate arguments
1680      */
1681
1682     if (!IsValidServerHandle(f_server, &tst)) {
1683         goto fail_vos_ServerTransactionStatusGetBegin;
1684     }
1685
1686     if (iterationIdP == NULL) {
1687         goto fail_vos_ServerTransactionStatusGetBegin;
1688     }
1689
1690     if ((iter == NULL) || (tran == NULL)) {
1691         tst = ADMNOMEM;
1692         goto fail_vos_ServerTransactionStatusGetBegin;
1693     }
1694
1695     /*
1696      * Fill in the tran structure
1697      */
1698
1699     if (!UV_VolserStatus(f_server->serv, &tran->cur, &tran->total, &tst)) {
1700         goto fail_vos_ServerTransactionStatusGetBegin;
1701     }
1702
1703     if (tran->total == 0) {
1704         if (!IteratorInit(iter, (void *)tran, NULL, NULL, NULL, NULL, &tst)) {
1705             goto fail_vos_ServerTransactionStatusGetBegin;
1706         }
1707         iter->done_iterating = 1;
1708         iter->st = ADMITERATORDONE;
1709     } else {
1710         if (!IteratorInit
1711             (iter, (void *)tran, GetTransactionRPC, GetTransactionFromCache,
1712              NULL, DestroyTransaction, &tst)) {
1713             goto fail_vos_ServerTransactionStatusGetBegin;
1714         }
1715     }
1716     *iterationIdP = (void *)iter;
1717     rc = 1;
1718
1719   fail_vos_ServerTransactionStatusGetBegin:
1720
1721     if (rc == 0) {
1722         if (iter != NULL) {
1723             free(iter);
1724         }
1725         if (tran != NULL) {
1726             if (tran->cur != NULL) {
1727                 free(tran->cur);
1728             }
1729             free(tran);
1730         }
1731     }
1732
1733     if (st != NULL) {
1734         *st = tst;
1735     }
1736     return rc;
1737 }
1738
1739 /*
1740  * vos_ServerTransactionStatusGetNext - get information about the next 
1741  * active transaction.
1742  *
1743  * PARAMETERS
1744  *
1745  * IN iterationId - an iterator previously returned by
1746  * vos_ServerTransactionStatusGetBegin
1747  *
1748  * OUT serverTransactionStatusP - a pointer to a vos_serverTransactionStatus_p
1749  * that upon successful completion contains information about the
1750  * next transaction.
1751  *
1752  * LOCKS
1753  * 
1754  * The iterator is locked while the next item is retrieved.
1755  *
1756  * RETURN CODES
1757  *
1758  * Returns != 0 upon successful completion.
1759  */
1760
1761 int ADMINAPI
1762 vos_ServerTransactionStatusGetNext(const void *iterationId,
1763                                    vos_serverTransactionStatus_p
1764                                    serverTransactionStatusP, afs_status_p st)
1765 {
1766     int rc = 0;
1767     afs_status_t tst = 0;
1768     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
1769
1770     if (iter == NULL) {
1771         tst = ADMITERATORNULL;
1772         goto fail_vos_ServerTransactionStatusGetNext;
1773     }
1774
1775     if (serverTransactionStatusP == NULL) {
1776         tst = ADMVOSSERVERTRANSACTIONSTATUSPNULL;
1777         goto fail_vos_ServerTransactionStatusGetNext;
1778     }
1779
1780     rc = IteratorNext(iter, (void *)serverTransactionStatusP, &tst);
1781
1782   fail_vos_ServerTransactionStatusGetNext:
1783
1784     if (st != NULL) {
1785         *st = tst;
1786     }
1787     return rc;
1788 }
1789
1790 /*
1791  * vos_ServerTransactionStatusGetDone - finish using a transaction iterator.
1792  *
1793  * PARAMETERS
1794  *
1795  * IN iterationId - an iterator previously returned by
1796  * vos_ServerTransactionStatusGetBegin
1797  *
1798  * LOCKS
1799  * 
1800  * The iterator is locked and then destroyed.
1801  *
1802  * RETURN CODES
1803  *
1804  * Returns != 0 upon successful completion.
1805  */
1806
1807 int ADMINAPI
1808 vos_ServerTransactionStatusGetDone(const void *iterationId, afs_status_p st)
1809 {
1810     int rc = 0;
1811     afs_status_t tst = 0;
1812     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
1813
1814     /*
1815      * Validate arguments
1816      */
1817
1818     if (iter == NULL) {
1819         tst = ADMITERATORNULL;
1820         goto fail_vos_ServerTransactionStatusGetDone;
1821     }
1822
1823     rc = IteratorDone(iter, &tst);
1824
1825   fail_vos_ServerTransactionStatusGetDone:
1826
1827     if (st != NULL) {
1828         *st = tst;
1829     }
1830     return rc;
1831 }
1832
1833 static int
1834 copyVLDBEntry(struct nvldbentry *source, vos_vldbEntry_p dest,
1835               afs_status_p st)
1836 {
1837     int rc = 0;
1838     afs_status_t tst = 0;
1839     int i;
1840
1841     dest->numServers = source->nServers;
1842     for (i = 0; i < VOS_MAX_VOLUME_TYPES; i++) {
1843         dest->volumeId[i] = source->volumeId[i];
1844     }
1845     dest->cloneId = source->cloneId;
1846     dest->status = VOS_VLDB_ENTRY_OK;
1847     if (source->flags & VLOP_ALLOPERS) {
1848         dest->status |= VOS_VLDB_ENTRY_LOCKED;
1849     } else {
1850         if (source->flags & VLOP_MOVE) {
1851             dest->status |= VOS_VLDB_ENTRY_MOVE;
1852         }
1853         if (source->flags & VLOP_RELEASE) {
1854             dest->status |= VOS_VLDB_ENTRY_RELEASE;
1855         }
1856         if (source->flags & VLOP_BACKUP) {
1857             dest->status |= VOS_VLDB_ENTRY_BACKUP;
1858         }
1859         if (source->flags & VLOP_DELETE) {
1860             dest->status |= VOS_VLDB_ENTRY_DELETE;
1861         }
1862         if (source->flags & VLOP_DUMP) {
1863             dest->status |= VOS_VLDB_ENTRY_DUMP;
1864         }
1865     }
1866     if (source->flags & VLF_RWEXISTS) {
1867         dest->status |= VOS_VLDB_ENTRY_RWEXISTS;
1868     }
1869     if (source->flags & VLF_ROEXISTS) {
1870         dest->status |= VOS_VLDB_ENTRY_ROEXISTS;
1871     }
1872     if (source->flags & VLF_BACKEXISTS) {
1873         dest->status |= VOS_VLDB_ENTRY_BACKEXISTS;
1874     }
1875
1876     strncpy(dest->name, source->name, VOS_MAX_VOLUME_NAME_LEN);
1877     dest->name[VOS_MAX_VOLUME_NAME_LEN - 1] = '\0';
1878     for (i = 0; i < VOS_MAX_REPLICA_SITES; i++) {
1879         dest->volumeSites[i].serverAddress = source->serverNumber[i];
1880         dest->volumeSites[i].serverPartition = source->serverPartition[i];
1881         dest->volumeSites[i].serverFlags = 0;
1882
1883         if (source->serverFlags[i] & VLSF_NEWREPSITE) {
1884             dest->volumeSites[i].serverFlags |= VOS_VLDB_NEW_REPSITE;
1885         }
1886         if (source->serverFlags[i] & VLSF_ROVOL) {
1887             dest->volumeSites[i].serverFlags |= VOS_VLDB_READ_ONLY;
1888         }
1889         if (source->serverFlags[i] & VLSF_RWVOL) {
1890             dest->volumeSites[i].serverFlags |= VOS_VLDB_READ_WRITE;
1891         }
1892         if (source->serverFlags[i] & VLSF_BACKVOL) {
1893             dest->volumeSites[i].serverFlags |= VOS_VLDB_BACKUP;
1894         }
1895         if (source->serverFlags[i] & VLSF_DONTUSE) {
1896             dest->volumeSites[i].serverFlags |= VOS_VLDB_DONT_USE;
1897         }
1898
1899     }
1900
1901     rc = 1;
1902     if (st != NULL) {
1903         *st = tst;
1904     }
1905     return rc;
1906 }
1907
1908 /*
1909  * vos_VLDBGet- get a volume's vldb entry.
1910  *
1911  * PARAMETERS
1912  *
1913  * IN cellHandle - a previously opened cellHandle that corresponds
1914  * to the cell where the volume entries exist.
1915  *
1916  * IN callBack - a call back function pointer that may be called to report
1917  * status information.  Can be null.
1918  *
1919  * IN volumeId - the id of the volume to retrieve.
1920  *
1921  * IN volumeName - the name of the volume to retrieve.
1922  *
1923  * OUT vldbEntry - upon successful completion, contains the information regarding
1924  * the volume.
1925  *
1926  * LOCKS
1927  * 
1928  * No locks are obtained or released by this function
1929  *
1930  * RETURN CODES
1931  *
1932  * Returns != 0 upon successful completion.
1933  */
1934
1935 int ADMINAPI
1936 vos_VLDBGet(const void *cellHandle, vos_MessageCallBack_t callBack,
1937             const unsigned int *volumeId, char *volumeName,
1938             vos_vldbEntry_p vldbEntry, afs_status_p st)
1939 {
1940     int rc = 0;
1941     afs_status_t tst = 0;
1942     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1943     struct nvldbentry entry;
1944
1945
1946     /*
1947      * Validate arguments
1948      */
1949
1950     if (!IsValidCellHandle(c_handle, &tst)) {
1951         goto fail_vos_VLDBGet;
1952     }
1953
1954     if (vldbEntry == NULL) {
1955         tst = ADMVOSVLDBENTRYNULL;
1956         goto fail_vos_VLDBGet;
1957     }
1958
1959     if (((volumeName == NULL) || (*volumeName == 0)) && (volumeId == NULL)) {
1960         tst = ADMVOSVOLUMENAMEANDVOLUMEIDNULL;
1961         goto fail_vos_VLDBGet;
1962     }
1963
1964     /*
1965      * Retrieve the entry
1966      */
1967
1968     if (!((volumeName == NULL) || (*volumeName == 0))) {
1969         if (!ValidateVolumeName(volumeName, &tst)) {
1970             goto fail_vos_VLDBGet;
1971         }
1972         if (!aVLDB_GetEntryByName(c_handle, volumeName, &entry, &tst)) {
1973             goto fail_vos_VLDBGet;
1974         }
1975     } else {
1976         if (!aVLDB_GetEntryByID(c_handle, *volumeId, -1, &entry, &tst)) {
1977             goto fail_vos_VLDBGet;
1978         }
1979     }
1980
1981     /*
1982      * Copy the entry into our structure
1983      */
1984
1985     if (!copyVLDBEntry(&entry, vldbEntry, &tst)) {
1986         goto fail_vos_VLDBGet;
1987     }
1988     rc = 1;
1989
1990   fail_vos_VLDBGet:
1991
1992     if (st != NULL) {
1993         *st = tst;
1994     }
1995     return rc;
1996 }
1997
1998 /*
1999  * The iterator functions and data for the vldb entry retrieval functions.
2000  */
2001
2002 typedef struct vldb_entry_get {
2003     afs_int32 total;            /* total number of vldb entries */
2004     afs_int32 index;            /* index to the current vldb entry */
2005     nbulkentries entries;       /* the list of entries retrieved */
2006     vos_vldbEntry_t entry[CACHED_ITEMS];        /* the cache of entries */
2007 } vldb_entry_get_t, *vldb_entry_get_p;
2008
2009 static int
2010 GetVLDBEntryRPC(void *rpc_specific, int slot, int *last_item,
2011                 int *last_item_contains_data, afs_status_p st)
2012 {
2013     int rc = 0;
2014     afs_status_t tst = 0;
2015     vldb_entry_get_p entry = (vldb_entry_get_p) rpc_specific;
2016
2017     /*
2018      * Copy the next entry into the cache
2019      */
2020
2021     if (!copyVLDBEntry
2022         (&entry->entries.nbulkentries_val[entry->index], &entry->entry[slot],
2023          &tst)) {
2024         goto fail_GetVLDBEntryRPC;
2025     }
2026     entry->index++;
2027
2028     /*
2029      * See if we've processed all the entries
2030      */
2031
2032
2033     if (entry->index == entry->total) {
2034         *last_item = 1;
2035         *last_item_contains_data = 1;
2036     }
2037     rc = 1;
2038
2039   fail_GetVLDBEntryRPC:
2040
2041     if (st != NULL) {
2042         *st = tst;
2043     }
2044     return rc;
2045 }
2046
2047 static int
2048 GetVLDBEntryFromCache(void *rpc_specific, int slot, void *dest,
2049                       afs_status_p st)
2050 {
2051     int rc = 0;
2052     afs_status_t tst = 0;
2053     vldb_entry_get_p entry = (vldb_entry_get_p) rpc_specific;
2054
2055     memcpy(dest, (const void *)&entry->entry[slot], sizeof(vos_vldbEntry_t));
2056     rc = 1;
2057
2058     if (st != NULL) {
2059         *st = tst;
2060     }
2061     return rc;
2062 }
2063
2064
2065 static int
2066 DestroyVLDBEntry(void *rpc_specific, afs_status_p st)
2067 {
2068     int rc = 0;
2069     afs_status_t tst = 0;
2070     vldb_entry_get_p entry = (vldb_entry_get_p) rpc_specific;
2071
2072     if (entry->entries.nbulkentries_val != NULL) {
2073         free(entry->entries.nbulkentries_val);
2074     }
2075     rc = 1;
2076
2077     if (st != NULL) {
2078         *st = tst;
2079     }
2080     return rc;
2081 }
2082
2083
2084 /*
2085  * vos_VLDBGetBegin - begin to iterate over the VLDB.
2086  *
2087  * PARAMETERS
2088  *
2089  * IN cellHandle - a previously opened cellHandle that corresponds
2090  * to the cell where the volume entries exist.
2091  *
2092  * IN serverHandle - a handle to the server whose entries should be listed.
2093  * Can be null.
2094  *
2095  * IN callBack - a call back function pointer that may be called to report
2096  * status information.  Can be null.
2097  *
2098  * IN partition - the partition whose entries should be listed.
2099  * Can be null.
2100  *
2101  * OUT iterationIdP - upon successful completion, contains an iterator that
2102  * can be passed to vos_VLDBGetNext.
2103  *
2104  * LOCKS
2105  * 
2106  * No locks are obtained or released by this function
2107  *
2108  * RETURN CODES
2109  *
2110  * Returns != 0 upon successful completion.
2111  */
2112
2113 int ADMINAPI
2114 vos_VLDBGetBegin(const void *cellHandle, const void *serverHandle,
2115                  vos_MessageCallBack_t callBack, unsigned int *partition,
2116                  void **iterationIdP, afs_status_p st)
2117 {
2118     int rc = 0;
2119     afs_status_t tst = 0;
2120     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2121     file_server_p f_server = (file_server_p) serverHandle;
2122     afs_admin_iterator_p iter = malloc(sizeof(afs_admin_iterator_t));
2123     vldb_entry_get_p entry = calloc(1, sizeof(vldb_entry_get_t));
2124     struct VldbListByAttributes attr;
2125
2126     attr.Mask = 0;
2127     memset(&attr, 0, sizeof(attr));
2128
2129     /*
2130      * Validate arguments
2131      */
2132
2133     if (!IsValidCellHandle(c_handle, &tst)) {
2134         goto fail_vos_VLDBGetBegin;
2135     }
2136
2137     if ((iter == NULL) || (entry == NULL)) {
2138         tst = ADMNOMEM;
2139         goto fail_vos_VLDBGetBegin;
2140     }
2141
2142     if (f_server != NULL) {
2143         if (!IsValidServerHandle(f_server, &tst)) {
2144             goto fail_vos_VLDBGetBegin;
2145         }
2146         attr.server = ntohl(rx_HostOf(rx_PeerOf(f_server->serv)));
2147         attr.Mask |= VLLIST_SERVER;
2148     }
2149
2150     if (partition != NULL) {
2151         if (*partition > VOLMAXPARTS) {
2152             tst = ADMVOSPARTITIONTOOLARGE;
2153             goto fail_vos_VLDBGetBegin;
2154         }
2155         attr.partition = *partition;
2156         attr.Mask |= VLLIST_PARTITION;
2157     }
2158
2159     if (!VLDB_ListAttributes
2160         (c_handle, &attr, &entry->total, &entry->entries, &tst)) {
2161         goto fail_vos_VLDBGetBegin;
2162     }
2163
2164     if (entry->total <= 0) {
2165         if (!IteratorInit(iter, (void *)entry, NULL, NULL, NULL, NULL, &tst)) {
2166             goto fail_vos_VLDBGetBegin;
2167         }
2168         iter->done_iterating = 1;
2169         iter->st = ADMITERATORDONE;
2170     } else {
2171         if (!IteratorInit
2172             (iter, (void *)entry, GetVLDBEntryRPC, GetVLDBEntryFromCache,
2173              NULL, DestroyVLDBEntry, &tst)) {
2174             goto fail_vos_VLDBGetBegin;
2175         }
2176     }
2177     *iterationIdP = (void *)iter;
2178     rc = 1;
2179
2180   fail_vos_VLDBGetBegin:
2181
2182     if (rc == 0) {
2183         if (iter != NULL) {
2184             free(iter);
2185         }
2186         if (entry->entries.nbulkentries_val != NULL) {
2187             free(entry->entries.nbulkentries_val);
2188         }
2189         if (entry != NULL) {
2190             free(entry);
2191         }
2192     }
2193
2194     if (st != NULL) {
2195         *st = tst;
2196     }
2197     return rc;
2198 }
2199
2200 /*
2201  * vos_VLDBGetNext - get information about the next volume.
2202  *
2203  * PARAMETERS
2204  *
2205  * IN iterationId - an iterator previously returned by
2206  * vos_VLDBGetBegin
2207  *
2208  * OUT vldbEntry - a pointer to a vos_vldbEntry_t
2209  * that upon successful completion contains information about the
2210  * next volume.
2211  *
2212  * LOCKS
2213  * 
2214  * The iterator is locked while the next item is retrieved.
2215  *
2216  * RETURN CODES
2217  *
2218  * Returns != 0 upon successful completion.
2219  */
2220
2221 int ADMINAPI
2222 vos_VLDBGetNext(const void *iterationId, vos_vldbEntry_p vldbEntry,
2223                 afs_status_p st)
2224 {
2225     int rc = 0;
2226     afs_status_t tst = 0;
2227     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
2228
2229     if (iter == NULL) {
2230         tst = ADMITERATORNULL;
2231         goto fail_vos_VLDBGetNext;
2232     }
2233
2234     if (vldbEntry == NULL) {
2235         tst = ADMVOSVLDBENTRYNULL;
2236         goto fail_vos_VLDBGetNext;
2237     }
2238
2239     rc = IteratorNext(iter, (void *)vldbEntry, &tst);
2240
2241   fail_vos_VLDBGetNext:
2242
2243     if (st != NULL) {
2244         *st = tst;
2245     }
2246     return rc;
2247 }
2248
2249 /*
2250  * vos_VLDBGetDone - finish using a volume iterator.
2251  *
2252  * PARAMETERS
2253  *
2254  * IN iterationId - an iterator previously returned by vos_VLDBGetBegin
2255  *
2256  * LOCKS
2257  * 
2258  * The iterator is locked and then destroyed.
2259  *
2260  * RETURN CODES
2261  *
2262  * Returns != 0 upon successful completion.
2263  */
2264
2265 int ADMINAPI
2266 vos_VLDBGetDone(const void *iterationId, afs_status_p st)
2267 {
2268     int rc = 0;
2269     afs_status_t tst = 0;
2270     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
2271
2272     /*
2273      * Validate arguments
2274      */
2275
2276     if (iter == NULL) {
2277         tst = ADMITERATORNULL;
2278         goto fail_vos_VLDBGetDone;
2279     }
2280
2281     rc = IteratorDone(iter, &tst);
2282
2283   fail_vos_VLDBGetDone:
2284
2285     if (st != NULL) {
2286         *st = tst;
2287     }
2288     return rc;
2289 }
2290
2291 /*
2292  * vos_VLDBEntryRemove - remove a vldb entry.
2293  *
2294  * PARAMETERS
2295  *
2296  * IN cellHandle - a previously opened cellHandle that corresponds
2297  * to the cell where the vldb entry exists.
2298  *
2299  * IN serverHandle - a previously opened serverHandle that corresponds
2300  * to the server where the vldb entry exists.  Can be null.
2301  *
2302  * IN callBack - a call back function pointer that may be called to report
2303  * status information.  Can be null.
2304  *
2305  * IN partition - the partition where the vldb entry exists.  Can be null.
2306  *
2307  * IN volumeId - the volume id of the vldb entry to be deleted. Can be null.
2308  *
2309  * LOCKS
2310  * 
2311  * No locks are obtained or released by this function
2312  *
2313  * RETURN CODES
2314  *
2315  * Returns != 0 upon successful completion.
2316  */
2317
2318 int ADMINAPI
2319 vos_VLDBEntryRemove(const void *cellHandle, const void *serverHandle,
2320                     vos_MessageCallBack_t callBack,
2321                     const unsigned int *partition, unsigned int *volumeId,
2322                     afs_status_p st)
2323 {
2324     int rc = 0;
2325     afs_status_t tst = 0;
2326     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2327     file_server_p f_server = (file_server_p) serverHandle;
2328     struct VldbListByAttributes attr;
2329     nbulkentries entries;
2330     afs_int32 nentries;
2331     int i;
2332
2333     memset(&attr, 0, sizeof(attr));
2334     memset(&entries, 0, sizeof(entries));
2335
2336     /*
2337      * Validate arguments
2338      */
2339
2340     if (!IsValidCellHandle(c_handle, &tst)) {
2341         goto fail_vos_VLDBEntryRemove;
2342     }
2343
2344     /*
2345      * If the volume is specified, just delete it
2346      */
2347
2348     if (volumeId != NULL) {
2349         tst = ubik_VL_DeleteEntry(c_handle->vos, 0, *volumeId, -1);
2350         if (tst != 0) {
2351             goto fail_vos_VLDBEntryRemove;
2352         }
2353     }
2354
2355     if (f_server != NULL) {
2356         if (!IsValidServerHandle(f_server, &tst)) {
2357             goto fail_vos_VLDBEntryRemove;
2358         }
2359         attr.server = ntohl(rx_HostOf(rx_PeerOf(f_server->serv)));
2360         attr.Mask |= VLLIST_SERVER;
2361     }
2362
2363     if (partition != NULL) {
2364         if (*partition > VOLMAXPARTS) {
2365             tst = ADMVOSPARTITIONTOOLARGE;
2366             goto fail_vos_VLDBEntryRemove;
2367         }
2368         attr.partition = *partition;
2369         attr.Mask |= VLLIST_PARTITION;
2370     }
2371
2372     if ((f_server == NULL) && (partition == NULL)) {
2373         tst = ADMVOSVLDBDELETEALLNULL;
2374         goto fail_vos_VLDBEntryRemove;
2375     }
2376
2377     if (!VLDB_ListAttributes(c_handle, &attr, &nentries, &entries, &tst)) {
2378         goto fail_vos_VLDBEntryRemove;
2379     }
2380
2381     if (nentries <= 0) {
2382         tst = ADMVOSVLDBNOENTRIES;
2383         goto fail_vos_VLDBEntryRemove;
2384     }
2385
2386     for (i = 0; i < nentries; i++) {
2387         ubik_VL_DeleteEntry(c_handle->vos, 0,
2388                   entries.nbulkentries_val[i].volumeId[RWVOL], -1);
2389     }
2390     rc = 1;
2391
2392   fail_vos_VLDBEntryRemove:
2393
2394     if (entries.nbulkentries_val) {
2395         free(entries.nbulkentries_val);
2396     }
2397
2398     if (st != NULL) {
2399         *st = tst;
2400     }
2401     return rc;
2402 }
2403
2404 /*
2405  * vos_VLDBUnlock - unlock vldb entries en masse.
2406  *
2407  * PARAMETERS
2408  *
2409  * IN cellHandle - a previously opened cellHandle that corresponds
2410  * to the cell where the vldb entries exist.
2411  *
2412  * IN serverHandle - a previously opened serverHandle that corresponds
2413  * to the server where the vldb entries exist.  Can be null.
2414  *
2415  * IN callBack - a call back function pointer that may be called to report
2416  * status information.  Can be null.
2417  *
2418  * IN partition - the partition where the vldb entries exist.  Can be null.
2419  *
2420  * LOCKS
2421  * 
2422  * No locks are obtained or released by this function
2423  *
2424  * RETURN CODES
2425  *
2426  * Returns != 0 upon successful completion.
2427  */
2428
2429 int ADMINAPI
2430 vos_VLDBUnlock(const void *cellHandle, const void *serverHandle,
2431                vos_MessageCallBack_t callBack, const unsigned int *partition,
2432                afs_status_p st)
2433 {
2434     int rc = 0;
2435     afs_status_t tst = 0;
2436     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2437     file_server_p f_server = (file_server_p) serverHandle;
2438     struct VldbListByAttributes attr;
2439     nbulkentries entries;
2440     afs_int32 nentries;
2441     int i;
2442
2443     memset(&attr, 0, sizeof(attr));
2444     memset(&entries, 0, sizeof(entries));
2445
2446     /*
2447      * Validate arguments
2448      */
2449
2450     if (!IsValidCellHandle(c_handle, &tst)) {
2451         goto fail_vos_VLDBUnlock;
2452     }
2453
2454     if (f_server != NULL) {
2455         if (!IsValidServerHandle(f_server, &tst)) {
2456             goto fail_vos_VLDBUnlock;
2457         }
2458         attr.server = ntohl(rx_HostOf(rx_PeerOf(f_server->serv)));
2459         attr.Mask |= VLLIST_SERVER;
2460     }
2461
2462     if (partition != NULL) {
2463         if (*partition > VOLMAXPARTS) {
2464             tst = ADMVOSPARTITIONTOOLARGE;
2465             goto fail_vos_VLDBUnlock;
2466         }
2467         attr.partition = *partition;
2468         attr.Mask |= VLLIST_PARTITION;
2469     }
2470     attr.flag = VLOP_ALLOPERS;
2471     attr.Mask |= VLLIST_FLAG;
2472
2473
2474     if (!VLDB_ListAttributes(c_handle, &attr, &nentries, &entries, &tst)) {
2475         goto fail_vos_VLDBUnlock;
2476     }
2477
2478     if (nentries <= 0) {
2479         tst = ADMVOSVLDBNOENTRIES;
2480         goto fail_vos_VLDBUnlock;
2481     }
2482
2483     for (i = 0; i < nentries; i++) {
2484         vos_VLDBEntryUnlock(cellHandle, 0,
2485                             entries.nbulkentries_val[i].volumeId[RWVOL],
2486                             &tst);
2487     }
2488     rc = 1;
2489
2490   fail_vos_VLDBUnlock:
2491
2492     if (entries.nbulkentries_val) {
2493         free(entries.nbulkentries_val);
2494     }
2495
2496     if (st != NULL) {
2497         *st = tst;
2498     }
2499     return rc;
2500 }
2501
2502
2503 /*
2504  * vos_VLDBEntryLock - lock a vldb entry.
2505  *
2506  * PARAMETERS
2507  *
2508  * IN cellHandle - a previously opened cellHandle that corresponds
2509  * to the cell where the vldb entry exists.
2510  *
2511  * IN callBack - a call back function pointer that may be called to report
2512  * status information.  Can be null.
2513  *
2514  * IN volumeId - the volume id of the vldb entry to be deleted.
2515  *
2516  * LOCKS
2517  * 
2518  * No locks are obtained or released by this function
2519  *
2520  * RETURN CODES
2521  *
2522  * Returns != 0 upon successful completion.
2523  */
2524
2525 int ADMINAPI
2526 vos_VLDBEntryLock(const void *cellHandle, vos_MessageCallBack_t callBack,
2527                   unsigned int volumeId, afs_status_p st)
2528 {
2529     int rc = 0;
2530     afs_status_t tst = 0;
2531     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2532
2533     /*
2534      * Validate arguments
2535      */
2536
2537     if (!IsValidCellHandle(c_handle, &tst)) {
2538         goto fail_vos_VLDBEntryLock;
2539     }
2540
2541     tst = ubik_VL_SetLock(c_handle->vos, 0, volumeId, -1, VLOP_DELETE);
2542     if (tst != 0) {
2543         goto fail_vos_VLDBEntryLock;
2544     }
2545     rc = 1;
2546
2547   fail_vos_VLDBEntryLock:
2548
2549     if (st != NULL) {
2550         *st = tst;
2551     }
2552     return rc;
2553 }
2554
2555 /*
2556  * vos_VLDBEntryUnlock - unlock a vldb entry.
2557  *
2558  * PARAMETERS
2559  *
2560  * IN cellHandle - a previously opened cellHandle that corresponds
2561  * to the cell where the vldb entry exists.
2562  *
2563  * IN callBack - a call back function pointer that may be called to report
2564  * status information.  Can be null.
2565  *
2566  * IN volumeId - the volume id of the vldb entry to be unlocked.
2567  *
2568  * LOCKS
2569  * 
2570  * No locks are obtained or released by this function
2571  *
2572  * RETURN CODES
2573  *
2574  * Returns != 0 upon successful completion.
2575  */
2576
2577 int ADMINAPI
2578 vos_VLDBEntryUnlock(const void *cellHandle, vos_MessageCallBack_t callBack,
2579                     unsigned int volumeId, afs_status_p st)
2580 {
2581     int rc = 0;
2582     afs_status_t tst = 0;
2583     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2584
2585     /*
2586      * Validate arguments
2587      */
2588
2589     if (!IsValidCellHandle(c_handle, &tst)) {
2590         goto fail_vos_VLDBEntryUnlock;
2591     }
2592
2593
2594     tst =
2595         ubik_VL_ReleaseLock(c_handle->vos, 0, volumeId, -1,
2596                   LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP);
2597     if (tst != 0) {
2598         goto fail_vos_VLDBEntryUnlock;
2599     }
2600     rc = 1;
2601
2602   fail_vos_VLDBEntryUnlock:
2603
2604     if (st != NULL) {
2605         *st = tst;
2606     }
2607     return rc;
2608 }
2609
2610 /*
2611  * vos_VLDBReadOnlySiteCreate - create a readonly site for a volume.
2612  *
2613  * PARAMETERS
2614  *
2615  * IN cellHandle - a previously opened cellHandle that corresponds
2616  * to the cell where the volume exists.
2617  *
2618  * IN serverHandle - a previously opened serverHandle that corresponds
2619  * to the server where the new volume should be created.
2620  *
2621  * IN callBack - a call back function pointer that may be called to report
2622  * status information.  Can be null.
2623  *
2624  * IN partition - the partition where then new volume should be created.
2625  *
2626  * IN volumeId - the volume id of the volume to be replicated.
2627  *
2628  * LOCKS
2629  * 
2630  * No locks are obtained or released by this function
2631  *
2632  * RETURN CODES
2633  *
2634  * Returns != 0 upon successful completion.
2635  */
2636
2637 int ADMINAPI
2638 vos_VLDBReadOnlySiteCreate(const void *cellHandle, const void *serverHandle,
2639                            vos_MessageCallBack_t callBack,
2640                            unsigned int partition, unsigned int volumeId,
2641                            afs_status_p st)
2642 {
2643     int rc = 0;
2644     afs_status_t tst = 0;
2645     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2646     file_server_p f_server = (file_server_p) serverHandle;
2647
2648     /*
2649      * Validate arguments
2650      */
2651
2652     if (!IsValidCellHandle(c_handle, &tst)) {
2653         goto fail_vos_VLDBReadOnlySiteCreate;
2654     }
2655
2656     if (!IsValidServerHandle(f_server, &tst)) {
2657         goto fail_vos_VLDBReadOnlySiteCreate;
2658     }
2659
2660     if (partition > VOLMAXPARTS) {
2661         tst = ADMVOSPARTITIONTOOLARGE;
2662         goto fail_vos_VLDBReadOnlySiteCreate;
2663     }
2664
2665     if (!UV_AddSite
2666         (c_handle, ntohl(rx_HostOf(rx_PeerOf(f_server->serv))), partition,
2667          volumeId, &tst)) {
2668         goto fail_vos_VLDBReadOnlySiteCreate;
2669     }
2670     rc = 1;
2671
2672   fail_vos_VLDBReadOnlySiteCreate:
2673
2674     if (st != NULL) {
2675         *st = tst;
2676     }
2677     return rc;
2678 }
2679
2680 /*
2681  * vos_VLDBReadOnlySiteDelete - delete a replication site for a volume.
2682  *
2683  * PARAMETERS
2684  *
2685  *
2686  * IN cellHandle - a previously opened cellHandle that corresponds
2687  * to the cell where the volume exists.
2688  *
2689  * IN serverHandle - a previously opened serverHandle that corresponds
2690  * to the server where the volume should be deleted.
2691  *
2692  * IN callBack - a call back function pointer that may be called to report
2693  * status information.  Can be null.
2694  *
2695  * IN partition - the partition where then volume should be deleted.
2696  *
2697  * IN volumeId - the volume id of the volume to be deleted.
2698  *
2699  * LOCKS
2700  * 
2701  * No locks are obtained or released by this function
2702  *
2703  * RETURN CODES
2704  *
2705  * Returns != 0 upon successful completion.
2706  */
2707
2708 int ADMINAPI
2709 vos_VLDBReadOnlySiteDelete(const void *cellHandle, const void *serverHandle,
2710                            vos_MessageCallBack_t callBack,
2711                            unsigned int partition, unsigned int volumeId,
2712                            afs_status_p st)
2713 {
2714     int rc = 0;
2715     afs_status_t tst = 0;
2716     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2717     file_server_p f_server = (file_server_p) serverHandle;
2718
2719     /*
2720      * Validate arguments
2721      */
2722
2723     if (!IsValidCellHandle(c_handle, &tst)) {
2724         goto fail_vos_VLDBReadOnlySiteDelete;
2725     }
2726
2727     if (!IsValidServerHandle(f_server, &tst)) {
2728         goto fail_vos_VLDBReadOnlySiteDelete;
2729     }
2730
2731     if (partition > VOLMAXPARTS) {
2732         tst = ADMVOSPARTITIONTOOLARGE;
2733         goto fail_vos_VLDBReadOnlySiteDelete;
2734     }
2735
2736     if (!UV_RemoveSite
2737         (c_handle, ntohl(rx_HostOf(rx_PeerOf(f_server->serv))), partition,
2738          volumeId, &tst)) {
2739         goto fail_vos_VLDBReadOnlySiteDelete;
2740     }
2741     rc = 1;
2742
2743   fail_vos_VLDBReadOnlySiteDelete:
2744
2745     if (st != NULL) {
2746         *st = tst;
2747     }
2748     return rc;
2749 }
2750
2751 /*
2752  * vos_VLDBSync - synchronize the vldb with the fileserver.
2753  *
2754  * PARAMETERS
2755  *
2756  * IN cellHandle - a previously opened cellHandle that corresponds
2757  * to the cell where the sync should occur.
2758  *
2759  * IN serverHandle - a previously opened serverHandle that corresponds
2760  * to the server where the sync should occur.
2761  *
2762  * IN callBack - a call back function pointer that may be called to report
2763  * status information.  Can be null.
2764  *
2765  * IN partition - the partition where the sync should occur.  Can be null.
2766  *
2767  * IN force - force deletion of bad volumes.
2768  *
2769  * LOCKS
2770  * 
2771  * No locks are obtained or released by this function
2772  *
2773  * RETURN CODES
2774  *
2775  * Returns != 0 upon successful completion.
2776  */
2777
2778 int ADMINAPI
2779 vos_VLDBSync(const void *cellHandle, const void *serverHandle,
2780              vos_MessageCallBack_t callBack, const unsigned int *partition,
2781              vos_force_t force, afs_status_p st)
2782 {
2783     int rc = 0;
2784     afs_status_t tst = 0;
2785     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2786     file_server_p f_server = (file_server_p) serverHandle;
2787     afs_int32 part = 0;
2788     int flags = 0;
2789     int force_flag = 0;
2790
2791     /*
2792      * Validate arguments
2793      */
2794
2795     if (!IsValidCellHandle(c_handle, &tst)) {
2796         goto fail_vos_VLDBSync;
2797     }
2798
2799     if (!IsValidServerHandle(f_server, &tst)) {
2800         goto fail_vos_VLDBSync;
2801     }
2802
2803     if (partition != NULL) {
2804         if (*partition > VOLMAXPARTS) {
2805             tst = ADMVOSPARTITIONTOOLARGE;
2806             goto fail_vos_VLDBSync;
2807         }
2808         part = (afs_int32) * partition;
2809         flags = 1;
2810     }
2811
2812     if (force == VOS_FORCE) {
2813         force_flag = 1;
2814     }
2815
2816     /*
2817      * sync the vldb
2818      */
2819
2820     rc = UV_SyncVldb(c_handle, f_server->serv, part, flags, force_flag, &tst);
2821
2822   fail_vos_VLDBSync:
2823
2824     if (st != NULL) {
2825         *st = tst;
2826     }
2827     return rc;
2828 }
2829
2830 /*
2831  * vos_VolumeCreate - create a new partition.
2832  *
2833  * PARAMETERS
2834  *
2835  * IN cellHandle - a previously opened cellHandle that corresponds
2836  * to the cell where the server lives.
2837  *
2838  * IN serverHandle - a previously open vos server handle that holds
2839  * the partition where the volume should be create.
2840  *
2841  * IN callBack - a call back function pointer that may be called to report
2842  * status information.  Can be null.
2843  *
2844  * IN partition - the integer that represents the partition that will 
2845  * house the new volume.
2846  *
2847  * IN volumeName - the name of the new volume.
2848  *
2849  * IN quota - the quota of the new volume.
2850  *
2851  * OUT volumeId - the volume id of the newly created volume.
2852  *
2853  * LOCKS
2854  * 
2855  * No locks are obtained or released by this function
2856  *
2857  * RETURN CODES
2858  *
2859  * Returns != 0 upon successful completion.
2860  */
2861
2862 int ADMINAPI
2863 vos_VolumeCreate(const void *cellHandle, const void *serverHandle,
2864                  vos_MessageCallBack_t callBack, unsigned int partition,
2865                  char *volumeName, unsigned int quota,
2866                  unsigned int *volumeId, afs_status_p st)
2867 {
2868     int rc = 0;
2869     afs_status_t tst = 0;
2870     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2871     file_server_p f_server = (file_server_p) serverHandle;
2872     vos_partitionEntry_t pinfo;
2873     struct nvldbentry vinfo;
2874
2875     /*
2876      * Validate arguments
2877      */
2878
2879     if (!IsValidCellHandle(c_handle, &tst)) {
2880         goto fail_vos_VolumeCreate;
2881     }
2882
2883     if (!IsValidServerHandle(f_server, &tst)) {
2884         goto fail_vos_VolumeCreate;
2885     }
2886
2887     if (partition > VOLMAXPARTS) {
2888         tst = ADMVOSPARTITIONTOOLARGE;
2889         goto fail_vos_VolumeCreate;
2890     }
2891
2892     if (!ValidateVolumeName(volumeName, &tst)) {
2893         goto fail_vos_VolumeCreate;
2894     }
2895
2896     if (volumeId == NULL) {
2897         tst = ADMVOSVOLUMEID;
2898         goto fail_vos_VolumeCreate;
2899     }
2900
2901     /*
2902      * Check that partition is valid at the server
2903      */
2904
2905     if (!vos_PartitionGet
2906         (cellHandle, serverHandle, 0, partition, &pinfo, &tst)) {
2907         goto fail_vos_VolumeCreate;
2908     }
2909
2910     /*
2911      * Check that the volume doesn't already exist
2912      */
2913
2914     if (aVLDB_GetEntryByName(c_handle, volumeName, &vinfo, &tst)) {
2915         tst = ADMVOSVOLUMENAMEDUP;
2916         goto fail_vos_VolumeCreate;
2917     }
2918
2919     /*
2920      * Create the new volume
2921      */
2922
2923     rc = UV_CreateVolume(c_handle, f_server->serv, partition, volumeName,
2924                          quota, volumeId, &tst);
2925
2926   fail_vos_VolumeCreate:
2927
2928     if (st != NULL) {
2929         *st = tst;
2930     }
2931     return rc;
2932 }
2933
2934 /*
2935  * vos_VolumeDelete - remove a volume.
2936  *
2937  * PARAMETERS
2938  *
2939  * IN cellHandle - a previously opened cellHandle that corresponds
2940  * to the cell where the volume exists.
2941  *
2942  * IN serverHandle - a previously opened serverHandle that corresponds
2943  * to the server where the volume exists.
2944  *
2945  * IN callBack - a call back function pointer that may be called to report
2946  * status information.  Can be null.
2947  *
2948  * IN partition - the partition where the volume exists.
2949  *
2950  * IN volumeId - the volume id of the volume to be deleted.
2951  *
2952  * LOCKS
2953  * 
2954  * No locks are obtained or released by this function
2955  *
2956  * RETURN CODES
2957  *
2958  * Returns != 0 upon successful completion.
2959  */
2960
2961 int ADMINAPI
2962 vos_VolumeDelete(const void *cellHandle, const void *serverHandle,
2963                  vos_MessageCallBack_t callBack, unsigned int partition,
2964                  unsigned int volumeId, afs_status_p st)
2965 {
2966     int rc = 0;
2967     afs_status_t tst = 0;
2968     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2969     file_server_p f_server = (file_server_p) serverHandle;
2970     vos_partitionEntry_t pinfo;
2971
2972     /*
2973      * Validate arguments
2974      */
2975
2976     if (!IsValidCellHandle(c_handle, &tst)) {
2977         goto fail_vos_VolumeDelete;
2978     }
2979
2980     if (!IsValidServerHandle(f_server, &tst)) {
2981         goto fail_vos_VolumeDelete;
2982     }
2983
2984     if (partition > VOLMAXPARTS) {
2985         tst = ADMVOSPARTITIONTOOLARGE;
2986         goto fail_vos_VolumeDelete;
2987     }
2988
2989     /*
2990      * Check that partition is valid at the server
2991      */
2992
2993     if (!vos_PartitionGet
2994         (cellHandle, serverHandle, 0, partition, &pinfo, &tst)) {
2995         goto fail_vos_VolumeDelete;
2996     }
2997
2998     rc = UV_DeleteVolume(c_handle, f_server->serv, partition, volumeId, &tst);
2999
3000   fail_vos_VolumeDelete:
3001
3002     if (st != NULL) {
3003         *st = tst;
3004     }
3005     return rc;
3006 }
3007
3008 /*
3009  * vos_VolumeRename - rename a volume.
3010  *
3011  * PARAMETERS
3012  *
3013  * IN cellHandle - a previously opened cellHandle that corresponds
3014  * to the cell where the volume exists.
3015  *
3016  * IN serverHandle - a previously opened serverHandle that corresponds
3017  * to the server where the vldb entry exists.  Can be null.
3018  *
3019  * IN callBack - a call back function pointer that may be called to report
3020  * status information.  Can be null.
3021  *
3022  * IN readWriteVolumeId - the volume id of the volume to be renamed.
3023  *
3024  * IN newVolumeName - the new name.
3025  *
3026  * LOCKS
3027  * 
3028  * No locks are obtained or released by this function
3029  *
3030  * RETURN CODES
3031  *
3032  * Returns != 0 upon successful completion.
3033  */
3034
3035 int ADMINAPI
3036 vos_VolumeRename(const void *cellHandle, vos_MessageCallBack_t callBack,
3037                  unsigned int readWriteVolumeId, char *newVolumeName,
3038                  afs_status_p st)
3039 {
3040     int rc = 0;
3041     afs_status_t tst = 0;
3042     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
3043     struct nvldbentry entry;
3044
3045     /*
3046      * Validate arguments
3047      */
3048
3049     if (!IsValidCellHandle(c_handle, &tst)) {
3050         goto fail_vos_VolumeRename;
3051     }
3052
3053     if ((newVolumeName == NULL) || (*newVolumeName == 0)) {
3054         tst = ADMVOSNEWVOLUMENAMENULL;
3055         goto fail_vos_VolumeRename;
3056     }
3057
3058     /*
3059      * Retrieve the entry
3060      */
3061
3062     if (!aVLDB_GetEntryByID(c_handle, readWriteVolumeId, -1, &entry, &tst)) {
3063         goto fail_vos_VolumeRename;
3064     }
3065
3066     rc = UV_RenameVolume(c_handle, &entry, newVolumeName, &tst);
3067
3068   fail_vos_VolumeRename:
3069
3070     if (st != NULL) {
3071         *st = tst;
3072     }
3073     return rc;
3074 }
3075
3076 /*
3077  * vos_VolumeDump - dump a volume
3078  *
3079  * PARAMETERS
3080  *
3081  * IN cellHandle - a previously opened cellHandle that corresponds
3082  * to the cell where the volume exists.
3083  *
3084  * IN serverHandle - a previously opened serverHandle that corresponds
3085  * to the server where the volume exists.  Can be null.
3086  *
3087  * IN callBack - a call back function pointer that may be called to report
3088  * status information.  Can be null.
3089  *
3090  * IN volumeId - the volume id of the volume to be dumped.
3091  *
3092  * IN startTime - files with modification times >= this time will be dumped.
3093  *
3094  * IN dumpFile - the file to dump the volume to.
3095  *
3096  * LOCKS
3097  * 
3098  * No locks are obtained or released by this function
3099  *
3100  * RETURN CODES
3101  *
3102  * Returns != 0 upon successful completion.
3103  */
3104
3105 int ADMINAPI
3106 vos_VolumeDump(const void *cellHandle, const void *serverHandle,
3107                vos_MessageCallBack_t callBack, unsigned int *partition,
3108                unsigned int volumeId, unsigned int startTime,
3109                const char *dumpFile, afs_status_p st)
3110 {
3111     int rc = 0;
3112     afs_status_t tst = 0;
3113     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
3114     file_server_p f_server = (file_server_p) serverHandle;
3115     afs_int32 server, part, voltype;
3116     struct nvldbentry entry;
3117
3118     /*
3119      * Validate arguments
3120      */
3121
3122     if (!IsValidCellHandle(c_handle, &tst)) {
3123         goto fail_vos_VolumeDump;
3124     }
3125
3126     if (serverHandle != NULL) {
3127         if (!IsValidServerHandle(f_server, &tst)) {
3128             goto fail_vos_VolumeDump;
3129         }
3130     }
3131
3132     /*
3133      * You must specify both the serverHandle and the partition
3134      */
3135
3136     if (serverHandle || partition) {
3137         if (!serverHandle || !partition) {
3138             tst = ADMVOSSERVERANDPARTITION;
3139             goto fail_vos_VolumeDump;
3140         } else {
3141             if (*partition > VOLMAXPARTS) {
3142                 tst = ADMVOSPARTITIONTOOLARGE;
3143                 goto fail_vos_VolumeDump;
3144             }
3145             server = ntohl(rx_HostOf(rx_PeerOf(f_server->serv)));
3146             part = *partition;
3147         }
3148     } else {
3149         if (!GetVolumeInfo
3150             (c_handle, volumeId, &entry, &server, &part, &voltype, &tst)) {
3151             goto fail_vos_VolumeDump;
3152         }
3153     }
3154
3155     if ((dumpFile == NULL) || (*dumpFile == 0)) {
3156         tst = ADMVOSDUMPFILENULL;
3157         goto fail_vos_VolumeDump;
3158     }
3159
3160     rc = UV_DumpVolume(c_handle, volumeId, server, part, startTime, dumpFile,
3161                        &tst);
3162
3163   fail_vos_VolumeDump:
3164
3165     if (st != NULL) {
3166         *st = tst;
3167     }
3168     return rc;
3169 }
3170
3171 /*
3172  * vos_VolumeRestore - restore a volume from a dump
3173  *
3174  * PARAMETERS
3175  *
3176  * IN cellHandle - a previously opened cellHandle that corresponds
3177  * to the cell where the volume exists.
3178  *
3179  * IN serverHandle - a previously opened serverHandle that corresponds
3180  * to the server where the volume exists.
3181  *
3182  * IN callBack - a call back function pointer that may be called to report
3183  * status information.  Can be null.
3184  *
3185  * IN partition - the partition where the volume exists.
3186  *
3187  * IN volumeId - the volume id of the volume to be restored.
3188  *
3189  * IN volumeName - the volume name of the volume to be restored.
3190  *
3191  * IN dumpFile - the file from which to restore the volume.
3192  *
3193  * IN dumpType - the type of dump to perform.
3194  *
3195  * LOCKS
3196  * 
3197  * No locks are obtained or released by this function
3198  *
3199  * RETURN CODES
3200  *
3201  * Returns != 0 upon successful completion.
3202  */
3203
3204 int ADMINAPI
3205 vos_VolumeRestore(const void *cellHandle, const void *serverHandle,
3206                   vos_MessageCallBack_t callBack, unsigned int partition,
3207                   unsigned int *volumeId, char *volumeName,
3208                   const char *dumpFile, vos_volumeRestoreType_t dumpType,
3209                   afs_status_p st)
3210 {
3211     int rc = 0;
3212     afs_status_t tst = 0;
3213     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
3214     file_server_p f_server = (file_server_p) serverHandle;
3215     struct nvldbentry entry;
3216     afs_int32 volid, server;
3217     int fd;
3218     struct stat status;
3219     int restoreflags = 0;
3220     afs_int32 Oserver, Opart, Otype;
3221     struct nvldbentry Oentry;
3222     int equal;
3223
3224     /*
3225      * Validate arguments
3226      */
3227
3228     if (!IsValidCellHandle(c_handle, &tst)) {
3229         goto fail_vos_VolumeRestore;
3230     }
3231
3232     if (serverHandle != NULL) {
3233         if (!IsValidServerHandle(f_server, &tst)) {
3234             goto fail_vos_VolumeRestore;
3235         }
3236     }
3237
3238     /*
3239      * Must pass volumeName
3240      */
3241
3242     if ((volumeName == NULL) || (*volumeName == 0)) {
3243         tst = ADMVOSVOLUMENAMENULL;
3244         goto fail_vos_VolumeRestore;
3245     }
3246
3247     if (!ValidateVolumeName(volumeName, &tst)) {
3248         goto fail_vos_VolumeRestore;
3249     }
3250
3251     /*
3252      * If volumeId is passed, it must be a valid volume id
3253      */
3254
3255     if (volumeId != NULL) {
3256         if (!aVLDB_GetEntryByID(c_handle, *volumeId, -1, &entry, &tst)) {
3257             goto fail_vos_VolumeRestore;
3258         }
3259         volid = *volumeId;
3260     } else {
3261         volid = 0;
3262     }
3263
3264     server = ntohl(rx_HostOf(rx_PeerOf(f_server->serv)));
3265
3266     if (partition > VOLMAXPARTS) {
3267         tst = ADMVOSPARTITIONTOOLARGE;
3268         goto fail_vos_VolumeRestore;
3269     }
3270
3271     /*
3272      * Check that dumpFile exists and can be accessed
3273      */
3274
3275     fd = open(dumpFile, 0);
3276     if ((fd < 0) || (fstat(fd, &status) < 0)) {
3277         close(fd);
3278         tst = ADMVOSDUMPFILEOPENFAIL;
3279         goto fail_vos_VolumeRestore;
3280     } else {
3281         close(fd);
3282     }
3283
3284     if (!aVLDB_GetEntryByName(c_handle, volumeName, &entry, &tst)) {
3285         restoreflags = RV_FULLRST;
3286     } else if (Lp_GetRwIndex(c_handle, &entry, 0) == -1) {
3287         restoreflags = RV_FULLRST;
3288         if (volid == 0) {
3289             volid = entry.volumeId[RWVOL];
3290         } else if ((entry.volumeId[RWVOL] != 0)
3291                    && (entry.volumeId[RWVOL] != volid)) {
3292             volid = entry.volumeId[RWVOL];
3293         }
3294     } else {
3295
3296         if (volid == 0) {
3297             volid = entry.volumeId[RWVOL];
3298         } else if ((entry.volumeId[RWVOL] != 0)
3299                    && (entry.volumeId[RWVOL] != volid)) {
3300             volid = entry.volumeId[RWVOL];
3301         }
3302
3303         /*
3304          * If the vldb says the same volume exists somewhere else
3305          * the caller must specify a full restore, not an incremental
3306          */
3307
3308         if (dumpType == VOS_RESTORE_FULL) {
3309             restoreflags = RV_FULLRST;
3310         } else {
3311
3312             /*
3313              * Check to see if the volume exists where the caller said
3314              */
3315             if (!GetVolumeInfo
3316                 (c_handle, volid, &Oentry, &Oserver, &Opart, &Otype, &tst)) {
3317                 goto fail_vos_VolumeRestore;
3318             }
3319             if (!VLDB_IsSameAddrs(c_handle, Oserver, server, &equal, &tst)) {
3320                 goto fail_vos_VolumeRestore;
3321             }
3322
3323             if (!equal) {
3324                 tst = ADMVOSRESTOREVOLEXIST;
3325                 goto fail_vos_VolumeRestore;
3326             }
3327         }
3328     }
3329
3330     rc = UV_RestoreVolume(c_handle, server, partition, volid, volumeName,
3331                           restoreflags, dumpFile, &tst);
3332
3333   fail_vos_VolumeRestore:
3334
3335     if (st != NULL) {
3336         *st = tst;
3337     }
3338     return rc;
3339 }
3340
3341 /*
3342  * vos_VolumeOnline - bring a volume online.
3343  *
3344  * PARAMETERS
3345  *
3346  * IN serverHandle - a previously opened serverHandle that corresponds
3347  * to the server where the volume exists.
3348  *
3349  * IN callBack - a call back function pointer that may be called to report
3350  * status information.  Can be null.
3351  *
3352  * IN partition - the partition where the volume exists.
3353  *
3354  * IN volumeId - the volume id of the volume to be brought online.
3355  *
3356  * LOCKS
3357  * 
3358  * No locks are obtained or released by this function
3359  *
3360  * RETURN CODES
3361  *
3362  * Returns != 0 upon successful completion.
3363  */
3364
3365 int ADMINAPI
3366 vos_VolumeOnline(const void *serverHandle, vos_MessageCallBack_t callBack,
3367                  unsigned int partition, unsigned int volumeId,
3368                  unsigned int sleepTime, vos_volumeOnlineType_t volumeStatus,
3369                  afs_status_p st)
3370 {
3371     int rc = 0;
3372     afs_status_t tst = 0;
3373     file_server_p f_server = (file_server_p) serverHandle;
3374     int up = ITOffline;
3375
3376     /*
3377      * Validate arguments
3378      */
3379
3380     if (!IsValidServerHandle(f_server, &tst)) {
3381         goto fail_vos_VolumeOnline;
3382     }
3383
3384     if (partition > VOLMAXPARTS) {
3385         tst = ADMVOSPARTITIONIDTOOLARGE;
3386         goto fail_vos_VolumeOnline;
3387     }
3388
3389     if (volumeStatus == VOS_ONLINE_BUSY) {
3390         up = ITBusy;
3391     }
3392
3393     rc = UV_SetVolume(f_server->serv, partition, volumeId, up, 0, sleepTime,
3394                       &tst);
3395
3396   fail_vos_VolumeOnline:
3397
3398     if (st != NULL) {
3399         *st = tst;
3400     }
3401     return rc;
3402 }
3403
3404 /*
3405  * vos_VolumeOffline - take a volume offline.
3406  *
3407  * PARAMETERS
3408  *
3409  * IN serverHandle - a previously opened serverHandle that corresponds
3410  * to the server where the volume exists.
3411  *
3412  * IN callBack - a call back function pointer that may be called to report
3413  * status information.  Can be null.
3414  *
3415  * IN partition - the partition where the volume exists.
3416  *
3417  * IN volumeId - the volume id of the volume to be taken offline.
3418  *
3419  * LOCKS
3420  * 
3421  * No locks are obtained or released by this function
3422  *
3423  * RETURN CODES
3424  *
3425  * Returns != 0 upon successful completion.
3426  */
3427
3428 int ADMINAPI
3429 vos_VolumeOffline(const void *serverHandle, vos_MessageCallBack_t callBack,
3430                   unsigned int partition, unsigned int volumeId,
3431                   afs_status_p st)
3432 {
3433     int rc = 0;
3434     afs_status_t tst = 0;
3435     file_server_p f_server = (file_server_p) serverHandle;
3436
3437     /*
3438      * Validate arguments
3439      */
3440
3441     if (!IsValidServerHandle(f_server, &tst)) {
3442         goto fail_vos_VolumeOffline;
3443     }
3444
3445     if (partition > VOLMAXPARTS) {
3446         tst = ADMVOSPARTITIONIDTOOLARGE;
3447         goto fail_vos_VolumeOffline;
3448     }
3449
3450     rc = UV_SetVolume(f_server->serv, partition, volumeId, ITOffline,
3451                       VTOutOfService, 0, &tst);
3452
3453   fail_vos_VolumeOffline:
3454
3455     if (st != NULL) {
3456         *st = tst;
3457     }
3458     return rc;
3459 }
3460
3461 /*
3462  * copyvolintXInfo - copy a struct volintXInfo to a vos_volumeEntry_p.
3463  *
3464  * PARAMETERS
3465  *
3466  * IN source - the volintXInfo structure to copy.
3467  *
3468  * OUT dest - the vos_volumeEntry_t to fill
3469  *
3470  * LOCKS
3471  * 
3472  * No locks are obtained or released by this function
3473  *
3474  * RETURN CODES
3475  *
3476  * Returns != 0 upon successful completion.
3477  */
3478
3479 static int
3480 copyvolintXInfo(struct volintXInfo *source, vos_volumeEntry_p dest,
3481                 afs_status_p st)
3482 {
3483     int rc = 0;
3484     afs_status_t tst = 0;
3485     int i;
3486
3487     /*
3488      * If the volume is not marked OK, all the other fields are invalid
3489      * We take the extra step of blanking out dest here to prevent the
3490      * user from seeing stale data from a previous call
3491      */
3492
3493     memset(dest, 0, sizeof(*dest));
3494
3495     switch (source->status) {
3496     case VOK:
3497         dest->status = VOS_OK;
3498         break;
3499     case VSALVAGE:
3500         dest->status = VOS_SALVAGE;
3501         break;
3502     case VNOVNODE:
3503         dest->status = VOS_NO_VNODE;
3504         break;
3505     case VNOVOL:
3506         dest->status = VOS_NO_VOL;
3507         break;
3508     case VVOLEXISTS:
3509         dest->status = VOS_VOL_EXISTS;
3510         break;
3511     case VNOSERVICE:
3512         dest->status = VOS_NO_SERVICE;
3513         break;
3514     case VOFFLINE:
3515         dest->status = VOS_OFFLINE;
3516         break;
3517     case VONLINE:
3518         dest->status = VOS_ONLINE;
3519         break;
3520     case VDISKFULL:
3521         dest->status = VOS_DISK_FULL;
3522         break;
3523     case VOVERQUOTA:
3524         dest->status = VOS_OVER_QUOTA;
3525         break;
3526     case VBUSY:
3527         dest->status = VOS_BUSY;
3528         break;
3529     case VMOVED:
3530         dest->status = VOS_MOVED;
3531         break;
3532     }
3533
3534     /*
3535      * Check to see if the entry is marked ok before copying all the
3536      * fields
3537      */
3538
3539     if (dest->status == VOS_OK) {
3540         strncpy(dest->name, source->name, VOS_MAX_VOLUME_NAME_LEN);
3541         dest->name[VOS_MAX_VOLUME_NAME_LEN - 1] = '\0';
3542         dest->id = source->volid;
3543         if (source->type == 0) {
3544             dest->type = VOS_READ_WRITE_VOLUME;
3545         } else if (source->type == 1) {
3546             dest->type = VOS_READ_ONLY_VOLUME;
3547         } else if (source->type == 2) {
3548             dest->type = VOS_BACKUP_VOLUME;
3549         }
3550         dest->backupId = source->backupID;
3551         dest->readWriteId = source->parentID;
3552         dest->readOnlyId = source->cloneID;
3553         dest->copyCreationDate = source->copyDate;
3554         dest->creationDate = source->creationDate;
3555         dest->lastAccessDate = source->accessDate;
3556         dest->lastUpdateDate = source->updateDate;
3557         dest->lastBackupDate = source->backupDate;
3558         dest->accessesSinceMidnight = source->dayUse;
3559         dest->fileCount = source->filecount;
3560         dest->maxQuota = source->maxquota;
3561         dest->currentSize = source->size;
3562         if (source->inUse == 1) {
3563             dest->volumeDisposition = VOS_ONLINE;
3564         } else {
3565             dest->volumeDisposition = VOS_OFFLINE;
3566         }
3567
3568         for (i = 0; i < VOS_VOLUME_READ_WRITE_STATS_NUMBER; i++) {
3569             dest->readStats[i] = source->stat_reads[i];
3570             dest->writeStats[i] = source->stat_writes[i];
3571         }
3572
3573         for (i = 0; i < VOS_VOLUME_TIME_STATS_NUMBER; i++) {
3574             dest->fileAuthorWriteSameNetwork[i] =
3575                 source->stat_fileSameAuthor[i];
3576             dest->fileAuthorWriteDifferentNetwork[i] =
3577                 source->stat_fileDiffAuthor[i];
3578             dest->dirAuthorWriteSameNetwork[i] =
3579                 source->stat_dirSameAuthor[i];
3580             dest->dirAuthorWriteDifferentNetwork[i] =
3581                 source->stat_dirDiffAuthor[i];
3582         }
3583     }
3584
3585     rc = 1;
3586
3587     if (st != NULL) {
3588         *st = tst;
3589     }
3590     return rc;
3591 }
3592
3593 /*
3594  * vos_VolumeGet - get information about a particular volume.
3595  *
3596  * PARAMETERS
3597  *
3598  * IN cellHandle - a previously opened cellHandle that corresponds
3599  * to the cell where the volume exists.
3600  *
3601  * IN serverHandle - a previously opened serverHandle that corresponds
3602  * to the server where the volume exists.
3603  *
3604  * IN callBack - a call back function pointer that may be called to report
3605  * status information.  Can be null.
3606  *
3607  * IN partition - the partition where the volume exists.
3608  *
3609  * IN volumeId - the volume id of the volume to be retrieved.
3610  *
3611  * OUT volumeP - upon successful completion, contains the information about the 
3612  * specified volume.
3613  *
3614  * LOCKS
3615  * 
3616  * No locks are obtained or released by this function
3617  *
3618  * RETURN CODES
3619  *
3620  * Returns != 0 upon successful completion.
3621  */
3622
3623 int ADMINAPI
3624 vos_VolumeGet(const void *cellHandle, const void *serverHandle,
3625               vos_MessageCallBack_t callBack, unsigned int partition,
3626               unsigned int volumeId, vos_volumeEntry_p volumeP,
3627               afs_status_p st)
3628 {
3629     int rc = 0;
3630     afs_status_t tst = 0;
3631     file_server_p f_server = (file_server_p) serverHandle;
3632     struct volintXInfo *info = NULL;
3633
3634     /*
3635      * Validate arguments
3636      */
3637
3638     if (!IsValidServerHandle(f_server, &tst)) {
3639         goto fail_vos_VolumeGet;
3640     }
3641
3642     if (partition > VOLMAXPARTS) {
3643         tst = ADMVOSPARTITIONIDTOOLARGE;
3644         goto fail_vos_VolumeGet;
3645     }
3646
3647     if (volumeP == NULL) {
3648         tst = ADMVOSVOLUMEPNULL;
3649         goto fail_vos_VolumeGet;
3650     }
3651
3652     /*
3653      * Retrieve the information for the volume
3654      */
3655
3656     if (!UV_XListOneVolume(f_server->serv, partition, volumeId, &info, &tst)) {
3657         goto fail_vos_VolumeGet;
3658     }
3659
3660     /*
3661      * Copy the volume info to our structure
3662      */
3663
3664     if (!copyvolintXInfo(info, volumeP, &tst)) {
3665         goto fail_vos_VolumeGet;
3666     }
3667     rc = 1;
3668
3669   fail_vos_VolumeGet:
3670
3671     if (info != NULL) {
3672         free(info);
3673     }
3674
3675     if (st != NULL) {
3676         *st = tst;
3677     }
3678     return rc;
3679 }
3680
3681 /*
3682  * The iterator functions and data for the volume retrieval functions.
3683  */
3684
3685 typedef struct volume_get {
3686     struct volintXInfo *vollist;
3687     afs_int32 total;            /* total number of volumes at this partition */
3688     afs_int32 index;            /* index to the current volume */
3689     vos_volumeEntry_t entry[CACHED_ITEMS];      /* the cache of entries */
3690 } volume_get_t, *volume_get_p;
3691
3692 static int
3693 GetVolumeRPC(void *rpc_specific, int slot, int *last_item,
3694              int *last_item_contains_data, afs_status_p st)
3695 {
3696     int rc = 0;
3697     afs_status_t tst = 0;
3698     volume_get_p entry = (volume_get_p) rpc_specific;
3699
3700     /*
3701      * Copy the next entry into the cache
3702      */
3703
3704     if (!copyvolintXInfo
3705         (&entry->vollist[entry->index], &entry->entry[slot], &tst)) {
3706         goto fail_GetVolumeRPC;
3707     }
3708     entry->index++;
3709
3710     /*
3711      * See if we've processed all the entries
3712      */
3713
3714
3715     if (entry->index == entry->total) {
3716         *last_item = 1;
3717         *last_item_contains_data = 1;
3718     }
3719     rc = 1;
3720
3721   fail_GetVolumeRPC:
3722
3723     if (st != NULL) {
3724         *st = tst;
3725     }
3726     return rc;
3727 }
3728
3729 static int
3730 GetVolumeFromCache(void *rpc_specific, int slot, void *dest, afs_status_p st)
3731 {
3732     int rc = 0;
3733     afs_status_t tst = 0;
3734     volume_get_p entry = (volume_get_p) rpc_specific;
3735
3736     memcpy(dest, (const void *)&entry->entry[slot],
3737            sizeof(vos_volumeEntry_t));
3738     rc = 1;
3739
3740     if (st != NULL) {
3741         *st = tst;
3742     }
3743     return rc;
3744 }
3745
3746
3747 static int
3748 DestroyVolume(void *rpc_specific, afs_status_p st)
3749 {
3750     int rc = 0;
3751     afs_status_t tst = 0;
3752     volume_get_p entry = (volume_get_p) rpc_specific;
3753
3754     if (entry->vollist != NULL) {
3755         free(entry->vollist);
3756     }
3757     rc = 1;
3758
3759     if (st != NULL) {
3760         *st = tst;
3761     }
3762     return rc;
3763 }
3764
3765
3766 /*
3767  * vos_VolumeGetBegin - begin to iterator over the list of volumes at a server.
3768  *
3769  * PARAMETERS
3770  *
3771  * IN cellHandle - a previously opened cellHandle that corresponds
3772  * to the cell where the volumes exist.
3773  *
3774  * IN serverHandle - a handle to the server where the volumes exist.
3775  *
3776  * IN callBack - a call back function pointer that may be called to report
3777  * status information.  Can be null.
3778  *
3779  * IN partition - the partition whose volumes should be listed.  Can be null.
3780  *
3781  * OUT iterationIdP - upon successful completion, contains an iterator that
3782  * can be passed to vos_VolumeGetBegin.
3783  *
3784  * LOCKS
3785  * 
3786  * No locks are obtained or released by this function
3787  *
3788  * RETURN CODES
3789  *
3790  * Returns != 0 upon successful completion.
3791  */
3792
3793 int ADMINAPI
3794 vos_VolumeGetBegin(const void *cellHandle, const void *serverHandle,
3795                    vos_MessageCallBack_t callBack, unsigned int partition,
3796                    void **iterationIdP, afs_status_p st)
3797 {
3798     int rc = 0;
3799     afs_status_t tst = 0;
3800     file_server_p f_server = (file_server_p) serverHandle;
3801     afs_admin_iterator_p iter = malloc(sizeof(afs_admin_iterator_t));
3802     volume_get_p entry = calloc(1, sizeof(volume_get_t));
3803
3804     /*
3805      * Validate arguments
3806      */
3807
3808     if (!IsValidServerHandle(f_server, &tst)) {
3809         goto fail_vos_VolumeGetBegin;
3810     }
3811
3812     if (partition > VOLMAXPARTS) {
3813         tst = ADMVOSPARTITIONIDTOOLARGE;