libadmin-ubik_call-20070715
[openafs.git] / src / libadmin / vos / vosutils.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 "vosutils.h"
17 #include "vsprocs.h"
18 #include "lockprocs.h"
19 #include <afs/afs_AdminErrors.h>
20 #ifdef HAVE_STRING_H
21 #include <string.h>
22 #else
23 #ifdef HAVE_STRINGS_H
24 #include <strings.h>
25 #endif
26 #endif
27
28 /*
29  * VLDB entry conversion routines.
30  * convert from one type of VLDB record to another.  There are only
31  * two types "old" and "new".
32  */
33
34 static int
35 OldVLDB_to_NewVLDB(struct vldbentry *source, struct nvldbentry *dest,
36                    afs_status_p st)
37 {
38     register int i;
39     int rc = 0;
40     afs_status_t tst = 0;
41
42     memset(dest, 0, sizeof(struct nvldbentry));
43     strncpy(dest->name, source->name, sizeof(dest->name));
44     for (i = 0; i < source->nServers; i++) {
45         dest->serverNumber[i] = source->serverNumber[i];
46         dest->serverPartition[i] = source->serverPartition[i];
47         dest->serverFlags[i] = source->serverFlags[i];
48     }
49     dest->nServers = source->nServers;
50     for (i = 0; i < MAXTYPES; i++)
51         dest->volumeId[i] = source->volumeId[i];
52     dest->cloneId = source->cloneId;
53     dest->flags = source->flags;
54
55     rc = 1;
56
57     if (st != NULL) {
58         *st = tst;
59     }
60     return rc;
61 }
62
63 /*
64  * We can fail to store the new to old VLDB record if there are more
65  * servers in the cell than the old format can handle.  If we fail,
66  * return an error.
67  */
68
69 static int
70 NewVLDB_to_OldVLDB(struct nvldbentry *source, struct vldbentry *dest,
71                    afs_status_p st)
72 {
73     register int i;
74     afs_status_t tst = 0;
75     int rc = 0;
76
77     memset(dest, 0, sizeof(struct vldbentry));
78     strncpy(dest->name, source->name, sizeof(dest->name));
79     if (source->nServers <= OMAXNSERVERS) {
80         for (i = 0; i < source->nServers; i++) {
81             dest->serverNumber[i] = source->serverNumber[i];
82             dest->serverPartition[i] = source->serverPartition[i];
83             dest->serverFlags[i] = source->serverFlags[i];
84         }
85         dest->nServers = i;
86         for (i = 0; i < MAXTYPES; i++)
87             dest->volumeId[i] = source->volumeId[i];
88         dest->cloneId = source->cloneId;
89         dest->flags = source->flags;
90         rc = 1;
91     } else {
92         tst = VL_BADSERVER;
93     }
94
95     if (st != NULL) {
96         *st = tst;
97     }
98     return rc;
99 }
100
101 int
102 VLDB_CreateEntry(afs_cell_handle_p cellHandle, struct nvldbentry *entryp,
103                  afs_status_p st)
104 {
105     struct vldbentry oentry;
106     afs_status_t tst = 0;
107     int rc = 0;
108
109     do {
110         if (cellHandle->vos_new) {
111             tst = ubik_VL_CreateEntryN(cellHandle->vos, 0, entryp);
112             if (tst) {
113                 if (tst == RXGEN_OPCODE) {
114                     cellHandle->vos_new = 0;
115                 }
116             } else {
117                 rc = 1;
118             }
119         } else {
120             if (NewVLDB_to_OldVLDB(entryp, &oentry, &tst)) {
121                 tst = ubik_VL_CreateEntry(cellHandle->vos, 0, &oentry);
122                 if (!tst) {
123                     rc = 1;
124                 }
125             }
126         }
127     } while (tst == RXGEN_OPCODE);
128
129     if (st != NULL) {
130         *st = tst;
131     }
132     return rc;
133 }
134
135 int
136 aVLDB_GetEntryByID(afs_cell_handle_p cellHandle, afs_int32 volid,
137                   afs_int32 voltype, struct nvldbentry *entryp,
138                   afs_status_p st)
139 {
140     struct vldbentry oentry;
141     afs_status_t tst = 0;
142     int rc = 0;
143
144     do {
145         if (cellHandle->vos_new) {
146             tst =
147                 ubik_VL_GetEntryByIDN(cellHandle->vos, 0, volid,
148                           voltype, entryp);
149             if (tst) {
150                 if (tst == RXGEN_OPCODE) {
151                     cellHandle->vos_new = 0;
152                 }
153             } else {
154                 rc = 1;
155             }
156         } else {
157             tst =
158                 ubik_VL_GetEntryByID(cellHandle->vos, 0, volid, voltype,
159                           &oentry);
160             if (tst == 0) {
161                 rc = OldVLDB_to_NewVLDB(&oentry, entryp, &tst);
162             }
163         }
164
165     } while (tst == RXGEN_OPCODE);
166
167     if (st != NULL) {
168         *st = tst;
169     }
170     return rc;
171 }
172
173 int
174 aVLDB_GetEntryByName(afs_cell_handle_p cellHandle, const char *namep,
175                     struct nvldbentry *entryp, afs_status_p st)
176 {
177     struct vldbentry oentry;
178     afs_status_t tst = 0;
179     int rc = 0;
180
181     do {
182         if (cellHandle->vos_new) {
183             tst =
184                 ubik_VL_GetEntryByNameN(cellHandle->vos, 0, namep,
185                           entryp);
186             if (tst) {
187                 if (tst == RXGEN_OPCODE) {
188                     cellHandle->vos_new = 0;
189                 }
190             } else {
191                 rc = 1;
192             }
193         } else {
194             tst =
195                 ubik_VL_GetEntryByNameO(cellHandle->vos, 0, namep,
196                           &oentry);
197             if (tst == 0) {
198                 rc = OldVLDB_to_NewVLDB(&oentry, entryp, &tst);
199             }
200         }
201
202     } while (tst == RXGEN_OPCODE);
203
204     if (st != NULL) {
205         *st = tst;
206     }
207     return rc;
208 }
209
210 int
211 VLDB_ReplaceEntry(afs_cell_handle_p cellHandle, afs_int32 volid,
212                   afs_int32 voltype, struct nvldbentry *entryp,
213                   afs_int32 releasetype, afs_status_p st)
214 {
215     struct vldbentry oentry;
216     afs_status_t tst = 0;
217     int rc = 0;
218
219     do {
220         if (cellHandle->vos_new) {
221             tst =
222                 ubik_VL_ReplaceEntryN(cellHandle->vos, 0, volid,
223                           voltype, entryp, releasetype);
224             if (tst) {
225                 if (tst == RXGEN_OPCODE) {
226                     cellHandle->vos_new = 0;
227                 }
228             } else {
229                 rc = 1;
230             }
231         } else {
232             if (NewVLDB_to_OldVLDB(entryp, &oentry, &tst)) {
233                 tst =
234                     ubik_VL_ReplaceEntry(cellHandle->vos, 0, volid,
235                               voltype, &oentry, releasetype);
236                 if (!tst) {
237                     rc = 1;
238                 }
239             }
240         }
241     } while (tst == RXGEN_OPCODE);
242
243     if (st != NULL) {
244         *st = tst;
245     }
246     return rc;
247 }
248
249 int
250 VLDB_ListAttributes(afs_cell_handle_p cellHandle,
251                     VldbListByAttributes * attrp, afs_int32 * entriesp,
252                     nbulkentries * blkentriesp, afs_status_p st)
253 {
254     bulkentries arrayEntries;
255     int i;
256     afs_status_t tst = 0;
257     int rc = 0;
258
259     do {
260         if (cellHandle->vos_new) {
261             tst =
262                 ubik_VL_ListAttributesN(cellHandle->vos, 0, attrp,
263                           entriesp, blkentriesp);
264             if (tst) {
265                 if (tst == RXGEN_OPCODE) {
266                     cellHandle->vos_new = 0;
267                 }
268             } else {
269                 rc = 1;
270             }
271         } else {
272             memset((void *)&arrayEntries, 0, sizeof(arrayEntries));
273             tst =
274                 ubik_VL_ListAttributes(cellHandle->vos, 0, attrp,
275                           entriesp, &arrayEntries);
276             if (tst == 0) {
277                 blkentriesp->nbulkentries_val =
278                     (nvldbentry *) malloc(*entriesp * sizeof(*blkentriesp));
279                 if (blkentriesp->nbulkentries_val != NULL) {
280                     for (i = 0; i < *entriesp; i++) {
281                         OldVLDB_to_NewVLDB((struct vldbentry *)&arrayEntries.
282                                            bulkentries_val[i],
283                                            (struct nvldbentry *)&blkentriesp->
284                                            nbulkentries_val[i], &tst);
285                     }
286                 } else {
287                     tst = ADMNOMEM;
288                 }
289                 if (arrayEntries.bulkentries_val) {
290                     free(arrayEntries.bulkentries_val);
291                 }
292                 rc = 1;
293             }
294         }
295
296     } while (tst == RXGEN_OPCODE);
297
298     if (st != NULL) {
299         *st = tst;
300     }
301     return rc;
302 }
303
304 int
305 VLDB_ListAttributesN2(afs_cell_handle_p cellHandle,
306                       VldbListByAttributes * attrp, char *name,
307                       afs_int32 thisindex, afs_int32 * nentriesp,
308                       nbulkentries * blkentriesp, afs_int32 * nextindexp,
309                       afs_status_p st)
310 {
311     int rc = 0;
312     afs_status_t tst = 0;
313
314     tst =
315         ubik_VL_ListAttributesN2(cellHandle->vos, 0, attrp,
316                   (name ? name : ""), thisindex, nentriesp, blkentriesp,
317                   nextindexp);
318     if (!tst) {
319         rc = 1;
320     }
321
322     if (st != NULL) {
323         *st = tst;
324     }
325     return rc;
326 }
327
328 int
329 VLDB_IsSameAddrs(afs_cell_handle_p cellHandle, afs_int32 serv1,
330                  afs_int32 serv2, int *equal, afs_status_p st)
331 {
332     int rc = 0;
333     afs_status_t tst = 0;
334
335     ListAddrByAttributes attrs;
336     bulkaddrs addrs;
337     afs_uint32 *addrp, nentries, unique, i;
338     afsUUID uuid;
339
340     *equal = 0;
341
342     if (serv1 == serv2) {
343         *equal = 1;
344         rc = 1;
345         goto fail_VLDB_IsSameAddrs;
346     }
347
348     memset(&attrs, 0, sizeof(attrs));
349     attrs.Mask = VLADDR_IPADDR;
350     attrs.ipaddr = serv1;
351     memset(&addrs, 0, sizeof(addrs));
352     memset(&uuid, 0, sizeof(uuid));
353     tst =
354         ubik_VL_GetAddrsU(cellHandle->vos, 0, &attrs, &uuid, &unique,
355                   &nentries, &addrs);
356     if (tst) {
357         *equal = 0;
358         goto fail_VLDB_IsSameAddrs;
359     }
360
361     addrp = addrs.bulkaddrs_val;
362     for (i = 0; i < nentries; i++, addrp++) {
363         if (serv2 == *addrp) {
364             *equal = 1;
365             break;
366         }
367     }
368     rc = 1;
369
370   fail_VLDB_IsSameAddrs:
371
372     if (st != NULL) {
373         *st = tst;
374     }
375     return rc;
376 }
377
378 /*
379  * GetVolumeInfo - retrieve information about a particular volume.
380  *
381  * PARAMETERS
382  *
383  * IN cellHandle - a handle that corresponds to the cell where the volume
384  * is located.
385  *
386  * IN volid - the volume to be retrieved.
387  *
388  * OUT rentry - the vldb entry of the volume.
389  *
390  * OUT server - the address of the server where the volume resides in 
391  * host byte order.
392  *
393  * OUT partition - the volume to be retrieved.
394  *
395  * OUT voltype - the type of volume retrieved.
396  *
397  * LOCKS
398  *
399  * No locks are obtained or released by this function
400  *
401  * RETURN CODES
402  *
403  * Returns != 0 upon successful completion.
404  */
405
406 int
407 GetVolumeInfo(afs_cell_handle_p cellHandle, unsigned int volid,
408               struct nvldbentry *rentry, afs_int32 * server,
409               afs_int32 * partition, afs_int32 * voltype, afs_status_p st)
410 {
411     int rc = 0;
412     afs_status_t tst;
413     int i, index = -1;
414
415     if (!aVLDB_GetEntryByID(cellHandle, volid, -1, rentry, &tst)) {
416         rc = 0;
417         goto fail_GetVolumeInfo;
418     }
419
420     if (volid == rentry->volumeId[ROVOL]) {
421         *voltype = ROVOL;
422         for (i = 0; i < rentry->nServers; i++) {
423             if ((index == -1) && (rentry->serverFlags[i] & ITSROVOL)
424                 && !(rentry->serverFlags[i] & RO_DONTUSE))
425                 index = i;
426         }
427         if (index == -1) {
428             tst = 1;
429             goto fail_GetVolumeInfo;
430         }
431         *server = rentry->serverNumber[index];
432         *partition = rentry->serverPartition[index];
433         rc = 1;
434         goto fail_GetVolumeInfo;
435     }
436
437     if ((index = Lp_GetRwIndex(cellHandle, rentry, &tst)) < 0) {
438         goto fail_GetVolumeInfo;
439     }
440     if (volid == rentry->volumeId[RWVOL]) {
441         *voltype = RWVOL;
442         *server = rentry->serverNumber[index];
443         *partition = rentry->serverPartition[index];
444     } else if (volid == rentry->volumeId[BACKVOL]) {
445         *voltype = BACKVOL;
446         *server = rentry->serverNumber[index];
447         *partition = rentry->serverPartition[index];
448     }
449     rc = 1;
450
451   fail_GetVolumeInfo:
452
453     if (st != NULL) {
454         *st = tst;
455     }
456     return rc;
457 }
458
459 /*
460  * ValidateVolumeName - validate a potential volume name
461  *
462  * PARAMETERS
463  *
464  * IN volumeName - the volume name to be validated.
465  *
466  * LOCKS
467  *
468  * No locks are obtained or released by this function
469  *
470  * RETURN CODES
471  *
472  * Returns != 0 upon successful completion.
473  */
474
475 int
476 ValidateVolumeName(const char *volumeName, afs_status_p st)
477 {
478     int rc = 0;
479     afs_status_t tst = 0;
480     size_t len;
481
482     if ((volumeName == NULL) || (*volumeName == 0)) {
483         tst = ADMVOSVOLUMENAMENULL;
484         goto fail_ValidateVolumeName;
485     }
486
487     if (!ISNAMEVALID(volumeName)) {
488         tst = ADMVOSVOLUMENAMETOOLONG;
489         goto fail_ValidateVolumeName;
490     }
491
492     len = strlen(volumeName);
493
494     if (((len > 8) && (!strcmp(&volumeName[len - 9], ".readonly")))
495         || ((len > 6) && (!strcmp(&volumeName[len - 7], ".backup")))) {
496         tst = ADMVOSVOLUMENAMEINVALID;
497         goto fail_ValidateVolumeName;
498     }
499
500     rc = 1;
501
502   fail_ValidateVolumeName:
503
504     if (st != NULL) {
505         *st = tst;
506     }
507
508     return rc;
509 }
510
511 /*extract the name of volume <name> without readonly or backup suffixes
512  * and return the result as <rname>.
513  */
514 int
515 vsu_ExtractName(char *rname, char *name)
516 {
517     char sname[32];
518     size_t total;
519
520     strncpy(sname, name, 32);
521     sname[31] ='\0';
522     total = strlen(sname);
523     if ((total > 9) && (!strcmp(&sname[total - 9], ".readonly"))) {
524         /*discard the last 8 chars */
525         sname[total - 9] = '\0';
526         strcpy(rname, sname);
527         return 0;
528     } else if ((total > 7) && (!strcmp(&sname[total - 7], ".backup"))) {
529         /*discard last 6 chars */
530         sname[total - 7] = '\0';
531         strcpy(rname, sname);
532         return 0;
533     } else {
534         strncpy(rname, name, VOLSER_OLDMAXVOLNAME);
535         return -1;
536     }
537 }
538
539
540
541 /*
542  * AddressMatch - determines if an IP address matches a pattern
543  *
544  * PARAMETERS
545  *
546  * IN addrTest - the IP address to test, in either byte-order
547  * IN addrPattern - the IP address pattern, in the same byte-order
548  *
549  * LOCKS
550  *
551  * No locks are obtained or released by this function
552  *
553  * RETURN CODES
554  *
555  * Returns != 0 if the address matches the pattern specified
556  * (where 255 in any byte in the pattern indicates a wildcard).
557  */
558
559 int
560 AddressMatch(int addrTest, int addrPattern)
561 {
562     int bTest;
563     int bPattern;
564
565     /* Test the high byte */
566     bTest = addrTest >> 24;
567     bPattern = addrPattern >> 24;
568     if ((bTest != bPattern) && (bPattern != 255)) {
569         return FALSE;
570     }
571
572     /* Test the next-highest byte */
573     bTest = (addrTest >> 16) & 255;
574     bPattern = (addrPattern >> 16) & 255;
575     if ((bTest != bPattern) && (bPattern != 255)) {
576         return FALSE;
577     }
578
579     /* Test the next-to-lowest byte */
580     bTest = (addrTest >> 8) & 255;
581     bPattern = (addrPattern >> 8) & 255;
582     if ((bTest != bPattern) && (bPattern != 255)) {
583         return FALSE;
584     }
585
586     /* Test the low byte */
587     bTest = addrTest & 255;
588     bPattern = addrPattern & 255;
589     if ((bTest != bPattern) && (bPattern != 255)) {
590         return FALSE;
591     }
592
593     return TRUE;
594 }
595
596
597 /*
598  * RemoveBadAddresses - (optionally) removes addresses that are better ignored
599  *
600  * PARAMETERS
601  *
602  * IN OUT totalp - the number of addresses in the addrsp structure
603  * IN OUT addrsp - a bulk array of addresses
604  *
605  * LOCKS
606  *
607  * No locks are obtained or released by this function
608  *
609  * RETURN CODES
610  *
611  * Returns != 0 upon successful completion.
612  */
613
614 static pthread_once_t badaddr_init_once = PTHREAD_ONCE_INIT;
615 static int addr_to_skip;
616
617 static void
618 badaddr_once(void)
619 {
620
621 #ifdef AFS_NT40_ENV
622
623 #define cszREG_IGNORE_KEY "Software\\OpenAFS\\AFS Control Center"
624 #define cszREG_IGNORE_VALUE "IgnoreBadAddrs"
625
626     /*
627      * In order for this routine to do anything, it must first validate
628      * that the user of this machine wants this filtering to take place.
629      * There is an undocumented registry value which signifies that it's
630      * okay to filter bogus IP addresses--and, moreover, indicates
631      * the range of values which may be ignored. Check that value.
632      */
633
634     HKEY hk;
635     addr_to_skip = 0;           /* don't ignore any addrs unless we find otherwise */
636     if (RegOpenKey(HKEY_LOCAL_MACHINE, cszREG_IGNORE_KEY, &hk) == 0) {
637         DWORD dwType = REG_DWORD;
638         DWORD dwSize = sizeof(addr_to_skip);
639         RegQueryValueEx(hk, cszREG_IGNORE_VALUE, 0, &dwType,
640                         (PBYTE) & addr_to_skip, &dwSize);
641         RegCloseKey(hk);
642     }
643 #else
644
645     /*
646      * We only support this functionality (so far) on NT; on other
647      * platforms, we'll never ignore IP addresses. If the feature
648      * is needed in the future, here's the place to add it.
649      *
650      */
651
652     addr_to_skip = 0;           /* don't skip any addresses */
653
654 #endif
655
656 }
657
658 int
659 RemoveBadAddresses(afs_int32 * totalp, bulkaddrs * addrsp)
660 {
661     pthread_once(&badaddr_init_once, badaddr_once);
662
663     /*
664      * If we've been requested to skip anything, addr_to_skip will be
665      * non-zero. It's actually an IP address of the form:
666      *    10.0.0.255
667      * A "255" means any value is acceptable, and any other value means
668      * the to-be-skipped address must match that value.
669      */
670
671     if (addr_to_skip && addrsp && addrsp->bulkaddrs_val) {
672         size_t iiWrite = 0;
673         size_t iiRead = 0;
674         for (; iiRead < addrsp->bulkaddrs_len; ++iiRead) {
675
676             /*
677              * Check this IP address to see if it should be skipped.
678              */
679
680             if (!AddressMatch(addrsp->bulkaddrs_val[iiRead], addr_to_skip)) {
681
682                 /*
683                  * The address is okay; make sure it stays in the list.
684                  */
685
686                 if (iiWrite != iiRead) {
687                     addrsp->bulkaddrs_val[iiWrite] =
688                         addrsp->bulkaddrs_val[iiRead];
689                 }
690
691                 ++iiWrite;
692             }
693         }
694         *totalp = (afs_int32) iiWrite;
695         addrsp->bulkaddrs_len = iiWrite;
696     }
697
698     return TRUE;
699 }