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