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