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