libafscp: Actually return callback from FindCallback
[openafs.git] / src / libafscp / afscp_volume.c
1 /* AUTORIGHTS
2 Copyright (C) 2003 - 2010 Chaskiel Grundman
3 All rights reserved
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10    notice, this list of conditions and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13    notice, this list of conditions and the following disclaimer in the
14    documentation and/or other materials provided with the distribution.
15
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27 #include <afsconfig.h>
28 #include <afs/param.h>
29
30 #include <roken.h>
31
32 #include <search.h>
33
34 #include <afs/vlserver.h>
35 #include <afs/vldbint.h>
36 #include <afs/volint.h>
37 #include "afscp.h"
38 #include "afscp_internal.h"
39
40 static int
41 icompare(const void *pa, const void *pb)
42 {
43     const struct afscp_volume *va = pa, *vb = pb;
44
45     if (va->id > vb->id)
46         return 1;
47     if (va->id < vb->id)
48         return -1;
49     return 0;
50 }
51
52 static int
53 ncompare(const void *pa, const void *pb)
54 {
55     const struct afscp_volume *va = pa, *vb = pb;
56
57     if (va->voltype > vb->voltype)
58         return 1;
59     if (vb->voltype < va->voltype)
60         return -1;
61     return strcmp(va->name, vb->name);
62 }
63
64 union allvldbentry {
65     struct uvldbentry u;
66     struct nvldbentry n;
67     struct vldbentry o;
68 };
69
70 struct afscp_volume *
71 afscp_VolumeByName(struct afscp_cell *cell, const char *vname,
72                    afs_int32 intype)
73 {
74     union allvldbentry u;
75     struct afscp_volume *ret, key;
76     struct afscp_server *server;
77     afs_int32 code, vtype, type, srv;
78     void *s;
79 #ifdef AFSCP_DEBUG
80     struct in_addr i;
81 #endif
82     if (intype == RWVOL)
83         vtype = VLSF_RWVOL;
84     else if (intype == ROVOL)
85         vtype = VLSF_ROVOL;
86     else if (intype == BACKVOL)
87         vtype = VLSF_BACKVOL;
88     else {
89         afscp_errno = EINVAL;
90         return NULL;
91     }
92
93     memset(&key, 0, sizeof(key));
94     strlcpy(key.name, vname, sizeof(key.name));
95     key.voltype = vtype;
96     s = tfind(&key, &cell->volsbyname, ncompare);
97     if (s) {
98         ret = *(struct afscp_volume **)s;
99         return ret;
100     }
101
102     type = 0;
103     code = ubik_VL_GetEntryByNameU(cell->vlservers, 0, (char *)vname, &u.u);
104     if (code == RXGEN_OPCODE) {
105         type = 1;
106         code =
107             ubik_VL_GetEntryByNameN(cell->vlservers, 0, (char *)vname, &u.n);
108         if (code == RXGEN_OPCODE) {
109             type = 2;
110             code = ubik_VL_GetEntryByNameO(cell->vlservers, 0, (char *)vname,
111                                            &u.o);
112         }
113     }
114     if (code != 0) {
115         afscp_errno = code;
116         return NULL;
117     }
118     ret = calloc(1, sizeof(struct afscp_volume));
119     if (ret == NULL) {
120         afscp_errno = ENOMEM;
121         return NULL;
122     }
123     strlcpy(ret->name, u.u.name, sizeof(ret->name));
124     ret->nservers = 0;
125     ret->cell = cell;
126     switch (type) {
127     case 0:
128         ret->id = u.u.volumeId[intype];
129         for (srv = 0; srv < u.u.nServers; srv++) {
130             if ((u.u.serverFlags[srv] & vtype) == 0)
131                 continue;
132             afs_dprintf(("uvldbentry server %d flags: %x\n", srv,
133                          u.u.serverFlags[srv]));
134
135             if ((u.u.serverFlags[srv] & VLSF_UUID) == 0)
136                 server =
137                     afscp_ServerByAddr(cell, u.u.serverNumber[srv].time_low);
138             else
139                 server = afscp_ServerById(cell, &u.u.serverNumber[srv]);
140             if (!server)
141                 continue;
142             ret->servers[ret->nservers++] = server->index;
143         }
144         break;
145     case 1:
146         ret->id = u.n.volumeId[intype];
147         for (srv = 0; srv < u.n.nServers; srv++) {
148             if ((u.n.serverFlags[srv] & vtype) == 0)
149                 continue;
150             server = afscp_ServerByAddr(cell, u.n.serverNumber[srv]);
151             if (!server)
152                 continue;
153             ret->servers[ret->nservers++] = server->index;
154         }
155         break;
156     case 2:
157         ret->id = u.o.volumeId[intype];
158         for (srv = 0; srv < u.o.nServers; srv++) {
159             if ((u.o.serverFlags[srv] & vtype) == 0)
160                 continue;
161             server = afscp_ServerByAddr(cell, u.o.serverNumber[srv]);
162             if (!server)
163                 continue;
164             ret->servers[ret->nservers++] = server->index;
165         }
166         break;
167     }
168     if (!ret->nservers || !ret->id) {
169         free(ret);
170         return NULL;
171     }
172
173     ret->voltype = intype;
174 #ifdef AFSCP_DEBUG
175     server = afscp_ServerByIndex(ret->servers[0]);
176     if (server != NULL)
177         i.s_addr = server->addrs[0];
178     else
179         i.s_addr = 0;
180 #endif
181     afs_dprintf(("New volume BYNAME %s (%lu) on %s (%d)\n", ret->name,
182                  afs_printable_uint32_lu(ret->id),
183                  inet_ntoa(i), ret->servers[0]));
184     s = tsearch(&key, &cell->volsbyname, ncompare);
185     if (s)
186         *(struct afscp_volume **)s = ret;
187     key.id = ret->id;
188     s = tsearch(&key, &cell->volsbyid, icompare);
189     if (s)
190         *(struct afscp_volume **)s = ret;
191     return ret;
192 }
193
194 struct afscp_volume *
195 afscp_VolumeById(struct afscp_cell *cell, afs_uint32 id)
196 {
197     union allvldbentry u;
198     struct afscp_volume *ret, key;
199     struct afscp_server *server;
200     afs_int32 code, vtype, type, srv;
201     int voltype = -1;
202     char idbuffer[16];
203     void *s;
204 #ifdef AFSCP_DEBUG
205     struct in_addr i;
206 #endif
207
208     memset(&key, 0, sizeof(key));
209     key.id = id;
210     s = tfind(&key, &cell->volsbyid, icompare);
211     if (s) {
212         ret = *(struct afscp_volume **)s;
213         return ret;
214     }
215
216     snprintf(idbuffer, sizeof(idbuffer), "%lu", afs_printable_uint32_lu(id));
217     type = 0;
218     code = ubik_VL_GetEntryByNameU(cell->vlservers, 0, idbuffer, &u.u);
219     if (code == RXGEN_OPCODE) {
220         type = 1;
221         code = ubik_VL_GetEntryByIDN(cell->vlservers, 0, id, -1, &u.n);
222         if (code == RXGEN_OPCODE) {
223             type = 2;
224             code = ubik_VL_GetEntryByID(cell->vlservers, 0, id, -1, &u.o);
225         }
226     }
227     if (code != 0) {
228         afscp_errno = code;
229         return NULL;
230     }
231     ret = calloc(1, sizeof(struct afscp_volume));
232     if (ret == NULL) {
233         afscp_errno = ENOMEM;
234         return NULL;
235     }
236     strlcpy(ret->name, u.u.name, sizeof(ret->name));
237     ret->nservers = 0;
238     ret->cell = cell;
239
240     switch (type) {
241     case 0:
242         if (id == u.u.volumeId[RWVOL]) {
243             vtype = VLSF_RWVOL;
244             voltype = RWVOL;
245         } else if (id == u.u.volumeId[ROVOL]) {
246             vtype = VLSF_ROVOL;
247             voltype = ROVOL;
248         } else if (id == u.u.volumeId[BACKVOL]) {
249             vtype = VLSF_BACKVOL;
250             voltype = BACKVOL;
251         } else {
252             vtype = 0;
253             voltype = -1;
254         }
255         for (srv = 0; srv < u.u.nServers; srv++) {
256             if ((u.u.serverFlags[srv] & vtype) == 0)
257                 continue;
258             if ((u.u.serverFlags[srv] & VLSF_UUID) == 0)
259                 server =
260                     afscp_ServerByAddr(cell, u.u.serverNumber[srv].time_low);
261             else
262                 server = afscp_ServerById(cell, &u.u.serverNumber[srv]);
263             if (!server)
264                 continue;
265             ret->servers[ret->nservers++] = server->index;
266         }
267         break;
268     case 1:
269         if (id == u.n.volumeId[RWVOL]) {
270             vtype = VLSF_RWVOL;
271             voltype = RWVOL;
272         } else if (id == u.n.volumeId[ROVOL]) {
273             vtype = VLSF_ROVOL;
274             voltype = ROVOL;
275         } else if (id == u.n.volumeId[BACKVOL]) {
276             vtype = VLSF_BACKVOL;
277             voltype = BACKVOL;
278         } else {
279             vtype = 0;
280             voltype = -1;
281         }
282         for (srv = 0; srv < u.n.nServers; srv++) {
283             if ((u.n.serverFlags[srv] & vtype) == 0)
284                 continue;
285             server = afscp_ServerByAddr(cell, u.n.serverNumber[srv]);
286             if (server == NULL)
287                 continue;
288             ret->servers[ret->nservers++] = server->index;
289         }
290         break;
291     case 2:
292         if (id == u.o.volumeId[RWVOL]) {
293             vtype = VLSF_RWVOL;
294             voltype = RWVOL;
295         } else if (id == u.o.volumeId[ROVOL]) {
296             vtype = VLSF_ROVOL;
297             voltype = ROVOL;
298         } else if (id == u.o.volumeId[BACKVOL]) {
299             vtype = VLSF_BACKVOL;
300             voltype = BACKVOL;
301         } else {
302             vtype = 0;
303             voltype = -1;
304         }
305         for (srv = 0; srv < u.o.nServers; srv++) {
306             if ((u.o.serverFlags[srv] & vtype) == 0)
307                 continue;
308             server = afscp_ServerByAddr(cell, u.o.serverNumber[srv]);
309             if (server == NULL)
310                 continue;
311             ret->servers[ret->nservers++] = server->index;
312         }
313         break;
314     }
315     ret->voltype = voltype;
316 #ifdef AFSCP_DEBUG
317     server = afscp_ServerByIndex(ret->servers[0]);
318     if (server)
319         i.s_addr = server->addrs[0];
320     else
321         i.s_addr = 0;
322 #endif
323     afs_dprintf(("New volume BYID %s (%lu) on %s (%d)\n", ret->name,
324                  afs_printable_uint32_lu(ret->id), inet_ntoa(i),
325                  ret->servers[0]));
326     s = tsearch(&key, &cell->volsbyid, icompare);
327     if (s)
328         *(struct afscp_volume **)s = ret;
329     strlcpy(key.name, ret->name, sizeof(key.name));
330     s = tsearch(&key, &cell->volsbyname, ncompare);
331     if (s)
332         *(struct afscp_volume **)s = ret;
333     return ret;
334 }