2 * Copyright 2000, International Business Machines Corporation and others.
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
12 #include <afsconfig.h>
13 #include <afs/param.h>
18 #include <sys/types.h>
21 #include <WINNT/afsevent.h>
25 #include <netinet/in.h>
31 #include <afs/cellconfig.h>
32 #include <afs/afsutil.h>
40 struct prheader cheader;
43 char *whoami = "db_verify";
44 #define UBIK_HEADERSIZE 64
47 afs_int32 printheader(h)
50 printf("Version = %d\n", ntohl(h->version));
51 printf("Header Size = %d\n", ntohl(h->headerSize));
52 printf("Free Ptr = 0x%x\n", ntohl(h->freePtr));
53 printf("EOF Ptr = 0x%x\n", ntohl(h->eofPtr));
54 printf("Max Group ID = %d\n", ntohl(h->maxGroup));
55 printf("Max User ID = %d\n", ntohl(h->maxID));
56 printf("Max Foreign ID = %d\n", ntohl(h->maxForeign));
57 /* printf("Max Sub/Super ID = %d\n", ntohl(h->maxInst)); */
58 printf("Orphaned groups = %d\n", ntohl(h->orphan));
59 printf("User Count = %d\n", ntohl(h->usercount));
60 printf("Group Count = %d\n", ntohl(h->groupcount));
61 /* printf("Foreign Count = %d\n", ntohl(h->foreigncount)); NYI */
62 /* printf("Sub/super Count = %d\n", ntohl(h->instcount)); NYI */
63 printf("Name Hash = %d buckets\n", HASHSIZE);
64 printf("ID Hash = %d buckets\n", HASHSIZE);
67 static afs_int32 pr_Read (pos, buff, len)
74 code = lseek(fd,UBIK_HEADERSIZE+pos, 0);
75 if (code == -1) return errno;
77 code = read(fd, buff, len);
78 if (code != len) return -1;
79 if (code == -1) return errno;
85 * Initializes the a transaction on the database and reads the header into
86 * the static variable cheader. If successful it returns a read-locked
87 * transaction. If ubik reports that cached database info should be up to date
88 * the cheader structure is not re-read from the ubik.
91 afs_int32 ReadHeader()
95 code = pr_Read (0, (char *) &cheader, sizeof(cheader));
97 com_err(whoami, code, "couldn't read header");
100 /* Check and see if database exists and is approximately OK. */
101 if (ntohl(cheader.headerSize) != sizeof(cheader) ||
102 ntohl(cheader.eofPtr) == 0) {
103 if (code) return code;
104 com_err (whoami, PRDBBAD, "header is bad");
110 static afs_int32 IDHash(x)
113 /* returns hash bucket for x */
114 return ((abs(x)) % HASHSIZE);
117 static afs_int32 NameHash(aname)
118 register unsigned char *aname;
120 /* returns hash bucket for aname */
121 register unsigned int hash=0;
123 /* stolen directly from the HashString function in the vol package */
124 for (i=strlen(aname),aname += i-1;i--;aname--)
125 hash = (hash*31) + (*aname-31);
126 return(hash % HASHSIZE);
129 #define MAP_NAMEHASH 1
131 #define MAP_HASHES (MAP_NAMEHASH | MAP_IDHASH)
134 #define MAP_OWNED 0x10
135 #define MAP_RECREATE 0x20
138 int nEntries; /* number of database entries */
139 int anon; /* found anonymous Id */
140 afs_int32 maxId; /* user */
141 afs_int32 minId; /* group */
142 afs_int32 maxForId; /* foreign user id */
143 int idRange; /* number of ids in map */
144 afs_int32 *idmap; /* map of all id's: midId is origin */
145 int nusers; /* counts of each type */
150 int maxOwnerLength; /* longest owner chain */
151 int maxContLength; /* longest chain of cont. blks */
152 int orphanLength; /* length of orphan list */
153 int freeLength; /* length of free list */
158 FILE *recreate; /* stream for recreate instructions */
161 int readUbikHeader(misc)
162 struct misc_data *misc;
165 struct ubik_hdr uheader;
167 offset = lseek(fd, 0, 0);
169 printf("error: lseek to 0 failed: %d %d\n", offset, errno);
173 /* now read the info */
174 r = read(fd, &uheader, sizeof(uheader));
175 if (r != sizeof(uheader)) {
176 printf("error: read of %d bytes failed: %d %d\n", sizeof(uheader), r, errno);
180 uheader.magic = ntohl(uheader.magic);
181 uheader.size = ntohl(uheader.size);
182 uheader.version.epoch = ntohl(uheader.version.epoch);
183 uheader.version.counter = ntohl(uheader.version.counter);
185 if (misc->listuheader) {
186 printf("Ubik Header\n");
187 printf(" Magic = 0x%x\n", uheader.magic);
188 printf(" Size = %u\n", uheader.size);
189 printf(" Version.epoch = %u\n", uheader.version.epoch);
190 printf(" Version.counter = %u\n", uheader.version.counter);
193 if (uheader.size != UBIK_HEADERSIZE)
194 printf("Ubik header size is %u (should be %u)\n", uheader.size, UBIK_HEADERSIZE);
195 if (uheader.magic != UBIK_MAGIC)
196 printf("Ubik header magic is 0x%x (should be 0x%x)\n", uheader.magic, UBIK_MAGIC);
201 afs_int32 ConvertDiskAddress (ea, eiP)
209 if (ea < sizeof(cheader)) return PRDBADDR;
210 if (ea >= ntohl(cheader.eofPtr)) return PRDBADDR;
211 ea -= sizeof(cheader);
212 i = ea / sizeof(struct prentry);
213 if (i*sizeof(struct prentry) != ea) return PRDBADDR;
214 /* if ((i < 0) || (i >= misc->nEntries)) return PRDBADDR; */
219 int PrintEntryError (misc, ea, e, indent)
220 struct misc_data *misc;
227 pr_PrintEntry (stderr, /*net order*/0, ea, e, indent);
231 afs_int32 WalkHashTable (hashtable, hashType, map, misc)
232 afs_int32 hashtable[]; /* hash table to walk */
233 int hashType; /* hash function to use */
234 char map[]; /* one byte per db entry */
235 struct misc_data *misc; /* stuff to keep track of */
238 int hi; /* index in hash table */
239 afs_int32 ea; /* entry's db addr */
240 int ei; /* entry's index */
241 char bit; /* bits to check for in map */
250 for (hi=0; hi<HASHSIZE; hi++) {
252 next_ea = ntohl(hashtable[hi]);
254 code = ConvertDiskAddress (next_ea, &ei);
256 fprintf (stderr, "Bad chain address %d\n", next_ea);
258 fprintf (stderr, "Last entry in chain:\n");
259 if (PrintEntryError (misc, ea, &e, 2)) return PRDBBAD;
262 "Skipping remainder of hash bucket %d\n", hi);
266 code = pr_Read (ea, (char *)&e, sizeof(e));
267 if (code) return code;
271 if ( ((ntohl(e.flags) & (PRGRP | PRINST)) == 0) &&
272 (strchr(e.name,'@')) ) {
274 if (id > misc->maxForId) misc->maxForId = id;
276 if (id == ANONYMOUSID) misc->anon++;
277 else if (id > misc->maxId) misc->maxId = id;
278 if (id < misc->minId) misc->minId = id;
283 next_ea = ntohl (e.nextName);
284 hash = NameHash (e.name);
287 next_ea = ntohl (e.nextID);
291 fprintf (stderr, "unknown hash table type %d\n", hashType);
297 "Entry found twice in hash table: bucket %d\n", hi);
300 "also in wrong bucket: should be in %d\n", hash);
301 if (PrintEntryError (misc, ea, &e, 2)) return PRDBBAD;
306 flags = ntohl(e.flags);
307 switch (flags & PRTYPE) {
309 fprintf (stderr, "ENTRY IS FREE");
312 fprintf (stderr, "ENTRY IS CONTINUATION");
321 "ENTRY IS unexpected type (flags=0x%x)\n", flags);
325 "ENTRY IS OF unknown type (flags=0x%x)\n", flags);
330 fprintf (stderr, "entry hashed in bucket %d should be %d\n",
333 if (PrintEntryError (misc, ea, &e, 2)) return PRDBBAD;
341 afs_int32 WalkNextChain (map, misc, ea, e)
342 char map[]; /* one byte per db entry */
343 struct misc_data *misc; /* stuff to keep track of */
350 struct prentry c; /* continuation entry */
351 afs_int32 na; /* next thread */
354 int count; /* number of members */
357 int length; /* length of chain */
360 head = ntohl(e->next);
363 count = 0; /* set to >9999 if list ends early */
364 for (i=0; i<PRSIZE; i++) {
365 afs_int32 id = ntohl(e->entries[i]);
366 if (id == PRBADID) continue;
370 /* in case the ids are large, convert to pure sign. */
371 if (id > 0) id_s = 1; else id_s = -1;
372 if (eid > 0) eid_s = 1; else eid_s = -1;
373 if (id_s * eid_s > 0) { /* sign should be different */
375 "Bad user/group dicotomy in membership list\n");
376 if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD;
379 /* count each user as a group, and each group a user is in */
380 if ((id >= misc->minId) && (id <= misc->maxId) &&
382 misc->idmap[id - misc->minId]++;
384 else if (head) count=9999;
389 head = ntohl(cheader.freePtr);
394 for (na=head; na; na=ntohl(c.next)) {
395 code = ConvertDiskAddress (na, &ni);
397 fprintf (stderr, "Bad continuation ptr %d", na);
398 if (e == 0) fprintf (stderr, "walking free list");
399 else if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD;
401 fprintf (stderr, "last block: \n");
402 if (PrintEntryError (misc, na, &c, 4)) return PRDBBAD;
406 code = pr_Read (na, (char *)&c, sizeof(c));
407 if (code) return code;
411 fprintf (stderr, "Continuation entry reused\n");
412 if (e == 0) fprintf (stderr, "walking free list");
413 else if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD;
414 if (PrintEntryError (misc, na, &c, 4)) return PRDBBAD;
419 if (e && (ntohl(c.id) != eid)) {
420 fprintf (stderr, "Continuation id mismatch\n");
421 if (e == 0) fprintf (stderr, "walking free list");
422 else if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD;
423 if (PrintEntryError (misc, na, &c, 4)) return PRDBBAD;
428 /* update membership count */
429 if (e) for (i=0; i<COSIZE; i++) {
430 afs_int32 id = ntohl(c.entries[i]);
431 if (id == PRBADID) continue;
435 /* in case the ids are large, convert to pure sign. */
436 if (id > 0) id_s = 1; else id_s = -1;
437 if (eid > 0) eid_s = 1; else eid_s = -1;
438 if (id_s * eid_s > 0) { /* sign should be different */
440 "Bad user/group dicotomy in membership list\n");
441 if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD;
442 if (PrintEntryError (misc, na, &c, 4)) return PRDBBAD;
445 /* count each user as a group, and each group a user is in */
446 if ((id >= misc->minId) && (id <= misc->maxId) &&
448 misc->idmap[id - misc->minId]++;
450 else if (c.next) count = 9999;
454 if (e && noErrors && (count != ntohl(e->count))) {
455 if (count > 9999) fprintf (stderr, "Membership list ends early\n");
456 fprintf (stderr, "Count was %d should be %d\n",
457 count, ntohl(e->count));
458 if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD;
462 if (length > misc->maxContLength) misc->maxContLength = length;
464 else misc->freeLength = length;
469 afs_int32 WalkOwnedChain (map, misc, ea, e)
470 char map[]; /* one byte per db entry */
471 struct misc_data *misc; /* stuff to keep track of */
477 struct prentry c; /* continuation entry */
478 afs_int32 na; /* next thread */
481 int length; /* length of chain */
484 head = ntohl(e->owned);
487 else head = ntohl(cheader.orphan);
490 for (na=head; na; na=ntohl(c.nextOwned)) {
491 code = ConvertDiskAddress (na, &ni);
493 fprintf (stderr, "Bad owned list ptr %d", na);
494 if (e == 0) fprintf (stderr, "walking orphan list");
495 else if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD;
497 fprintf (stderr, "last block: \n");
498 if (PrintEntryError (misc, na, &c, 4)) return PRDBBAD;
502 code = pr_Read (na, (char *)&c, sizeof(c));
503 if (code) return code;
506 if (map[ni] & MAP_OWNED) {
507 fprintf (stderr, "Entry on multiple owner chains\n");
508 if (e == 0) fprintf (stderr, "walking orphan list");
509 else if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD;
510 if (PrintEntryError (misc, na, &c, 4)) return PRDBBAD;
513 map[ni] |= MAP_OWNED;
514 if ((map[ni] & MAP_HASHES) != MAP_HASHES) {
515 fprintf (stderr, "Owned entry not hashed properly\n");
517 if (e == 0) fprintf (stderr, "walking orphan list");
518 else if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD;
519 if (PrintEntryError (misc, na, &c, 4)) return PRDBBAD;
523 if (ntohl(c.owner) != eid) {
524 fprintf (stderr, "Owner id mismatch\n");
528 else /* orphan */ if (c.owner) {
529 fprintf (stderr, "Orphan group owner not zero\n");
535 if (length > misc->maxOwnerLength) misc->maxOwnerLength = length;
537 else misc->orphanLength = length;
542 afs_int32 WalkChains (map, misc)
543 char map[]; /* one byte per db entry */
544 struct misc_data *misc; /* stuff to keep track of */
548 afs_int32 ea; /* entry's db addr */
553 /* check all entries found in hash table walks */
554 for (ei=0; ei < misc->nEntries; ei++) if (map[ei] & MAP_HASHES) {
555 ea = ei * sizeof(struct prentry) + sizeof(cheader);
556 code = pr_Read (ea, (char *)&e, sizeof(e));
557 if (code) return code;
559 if ((map[ei] & MAP_HASHES) != MAP_HASHES) {
560 fprintf (stderr, "entry not in both hashtables\n");
561 if ((map[ei] & MAP_NAMEHASH) != MAP_NAMEHASH)
562 fprintf (stderr, "--> entry not in Name hashtable\n");
563 if ((map[ei] & MAP_IDHASH) != MAP_IDHASH)
564 fprintf (stderr, "--> entry not in ID hashtable\n");
567 if (PrintEntryError (misc, ea, &e, 2)) return PRDBBAD;
573 type = ntohl (e.flags) & PRTYPE;
577 fprintf (stderr, "Group id not negative\n");
580 /* special case sysadmin: it owns itself */
581 if (id == SYSADMINID) {
582 if (ntohl(e.owner) != SYSADMINID) {
584 "System:administrators doesn't own itself\n");
588 code = WalkOwnedChain (map, misc, ea, &e);
589 if (code) return code;
590 code = WalkNextChain (map, misc, ea, &e);
591 if (code) return code;
596 fprintf (stderr, "User id negative\n");
600 /* Users are owned by sysadmin, but sysadmin doesn't have an owner
601 * chain. Check this then set the owned bit. */
602 if (ntohl(e.owner) != SYSADMINID) {
603 fprintf (stderr, "User not owned by system:administrators\n");
607 fprintf (stderr, "User has owned pointer\n");
610 map[ei] |= MAP_OWNED;
612 code = WalkOwnedChain (map, misc, ea, &e);
613 if (code) return code;
614 code = WalkNextChain (map, misc, ea, &e);
615 if (code) return code;
616 if (strchr(e.name,'@') == 0) {
617 misc->nusers++; /* Not a foreign user */
619 misc->nforeigns++; /* A foreign user */
628 fprintf (stderr, "ENTRY IS unexpected type [PRFOREIGN] (flags=0x%x)\n", e.flags);
634 fprintf (stderr, "entry with unexpected type");
642 afs_int32 GC (map, misc)
644 struct misc_data *misc;
652 for (ei=0; ei<misc->nEntries; ei++) {
653 ea = ei * sizeof(struct prentry) + sizeof(cheader);
654 code = pr_Read (ea, (char *)&e, sizeof(e));
655 if (code) return code;
658 fprintf (stderr, "Unreferenced entry:");
659 if (PrintEntryError (misc, ea, &e, 2)) return PRDBBAD;
661 /* all users and groups should be owned, and their membership counts
663 else if ((m & MAP_HASHES) == MAP_HASHES) {
666 if (!(m & MAP_OWNED)) {
667 fprintf (stderr, "Entry not on any owner chain:\n");
668 if (PrintEntryError (misc, ea, &e, 2)) return PRDBBAD;
671 if ((id >= misc->minId) && (id <= misc->maxId) &&
672 (id != ANONYMOUSID) &&
673 ((refCount = misc->idmap[id - misc->minId]) !=
676 fprintf (stderr, "Entry membership count is inconsistent: %d entries refer to this one\n", refCount);
677 if (PrintEntryError (misc, ea, &e, 2)) return PRDBBAD;
679 /* get continuation blocks too */
680 for (na=ntohl(e.next); na; na=ntohl(e.next)) {
682 code = ConvertDiskAddress (na, &ni);
683 if (code) return code;
684 code = pr_Read (na, (char *)&e, sizeof(e));
685 if (code) return code;
686 if (PrintEntryError (misc, na, &e, 4)) return PRDBBAD;
698 if (strpbrk (s," \t")) {
699 qs = (char *)malloc (strlen(s)+3);
707 afs_int32 DumpRecreate (map, misc)
709 struct misc_data *misc;
719 int builtinUsers = 0;
720 int createLow = 0; /* users uncreate from here */
721 afs_int32 *idmap; /* map of all id's */
727 memset(idmap, 0, misc->idRange*sizeof(misc->idmap[0]));
730 for (ei=createLow; ei<misc->nEntries; ei++) {
731 if ((map[ei] & MAP_HASHES) &&
732 (map[ei] & MAP_RECREATE) == 0) {
737 ea = ei * sizeof(struct prentry) + sizeof(cheader);
738 code = pr_Read (ea, (char *)&e, sizeof(e));
739 if (code) return code;
741 if (misc->listentries)
742 pr_PrintEntry(stdout, 0/*not in host order*/, ea, &e, 0);
745 flags = ntohl(e.flags);
746 owner = ntohl(e.owner);
747 name = QuoteName(e.name);
749 if (!strcmp (e.name, "system:administrators") ||
750 !strcmp (e.name, "system:anyuser") ||
751 !strcmp (e.name, "system:authuser") ||
752 !strcmp (e.name, "system:backup") ||
753 !strcmp (e.name, "anonymous")) {
758 /* check for duplicate id. This may still lead to duplicate
760 if (idmap[id-misc->minId]) {
762 "Skipping entry with duplicate id %di\n", id);
766 /* If owner doesn't exist skip for now, unless we're our own
767 * owner. If so, a special case allows a group to own itself
768 * if caller is sysadmin. This leaves only owner cycles to
771 if ((owner < misc->minId) || (owner > misc->maxId)) {
772 if (owner == ANONYMOUSID) fprintf (stderr, "Warning: id %di is owned by ANONYMOUS; using sysadmin instead\n", id);
773 else fprintf (stderr, "Bogus owner (%d) of id %di; using sysadmin instead\n", owner, id);
778 "Warning: group %s is self owning\n", name);
780 else if (owner == 0) {
781 fprintf (stderr, "Warning: orphan group %s will become self owning.\n", name);
784 else if (idmap[owner-misc->minId] == 0) goto user_skip;
786 if (rc) fprintf (rc, "cr %s %d %d\n", name, id, owner);
788 gq = uq = access = mask = 0;
789 if (flags & PRACCESS) {
790 access = (flags >> PRIVATE_SHIFT);
791 mask |= PR_SF_ALLBITS;
793 if (flags & PRQUOTA) {
794 gq = ntohl(e.ngroups);
795 uq = ntohl(e.nusers);
796 mask |= PR_SF_NGROUPS | PR_SF_NUSERS;
799 fprintf (rc, "sf %d %x %x %d %d\n",
800 id, mask, access, gq, uq);
803 map[ei] |= MAP_RECREATE;
804 if (id != ANONYMOUSID) idmap[id-misc->minId]++;
807 /* bump low water mark if possible */
808 if (ei == createLow) createLow++;
814 /* Now create the entries with circular owner dependencies and make them
815 * own themselves. This is the only way to create them with the correct
817 for (ei=0; ei<misc->nEntries; ei++)
818 if (((map[ei] & MAP_HASHES) == MAP_HASHES) &&
819 (map[ei] & MAP_RECREATE) == 0) {
820 ea = ei * sizeof(struct prentry) + sizeof(cheader);
821 code = pr_Read (ea, (char *)&e, sizeof(e));
822 if (code) return code;
825 name = QuoteName(e.name);
826 fprintf (stderr, "Warning: group %s in self owning cycle\n", name);
827 if (rc) fprintf (rc, "cr %s %d %d\n", name, id, id);
828 idmap[id-misc->minId]++;
830 for (ei=0; ei<misc->nEntries; ei++)
831 if (((map[ei] & MAP_HASHES) == MAP_HASHES) &&
832 (map[ei] & MAP_RECREATE) == 0) {
833 ea = ei * sizeof(struct prentry) + sizeof(cheader);
834 code = pr_Read (ea, (char *)&e, sizeof(e));
835 if (code) return code;
837 owner = ntohl(e.owner);
838 if (idmap[owner-misc->minId] == 0) {
840 "Skipping chown of '%s' to non-existant owner %di\n",
843 else if (rc) fprintf (rc, "ce %d \"\" %d 0\n",
844 ntohl(e.id), e.owner);
847 if (rc == 0) return 0;
849 /* Reconstruct membership information based on the groups' user lists. */
850 for (ei=0; ei<misc->nEntries; ei++) {
851 if ((map[ei] & MAP_HASHES) == MAP_HASHES) {
852 ea = ei * sizeof(struct prentry) + sizeof(cheader);
853 code = pr_Read (ea, (char *)&e, sizeof(e));
854 if (code) return code;
857 flags = ntohl(e.flags);
859 if ((id < 0) && (flags & PRGRP)) {
863 for (i=0; i<PRSIZE; i++) {
864 afs_int32 uid = ntohl(e.entries[i]);
866 if (uid == PRBADID) continue;
868 fprintf (rc, "au %d %d\n", uid, id);
870 } else fprintf (stderr,
871 "Skipping %di in group %di\n", uid, id);
876 code = pr_Read (na, (char *)&c, sizeof(c));
877 if (code) return code;
879 if ((id == ntohl(c.id)) && (ntohl(c.flags) & PRCONT)) {
880 for (i=0; i<COSIZE; i++) {
881 afs_int32 uid = ntohl(c.entries[i]);
883 if (uid == PRBADID) continue;
885 fprintf (rc, "au %d %d\n", uid, id);
887 } else fprintf (stderr,
888 "Skipping %di in group %di\n",
893 "Skipping continuation block at %d\n", na);
898 if (count != ntohl(e.count))
899 fprintf (stderr, "Group membership count problem found %d should be %d\n", count, ntohl(e.count));
900 } else if ((id < 0) || (flags & PRGRP)) {
901 fprintf (stderr, "Skipping group %di\n", id);
908 afs_int32 CheckPrDatabase (misc)
909 struct misc_data *misc; /* info & statistics */
914 char *map; /* map of each entry in db */
916 eof = ntohl (cheader.eofPtr);
917 eof -= sizeof(cheader);
918 n = eof / sizeof(struct prentry);
919 if ((eof < 0) || (n*sizeof(struct prentry) != eof)) {
921 com_err (whoami, code,
922 "eof ptr no good: eof=%d, sizeof(prentry)=%d",
923 eof, sizeof(struct prentry));
928 printf ("Database has %d entries\n", n);
929 map = (char *)malloc (n);
934 printf ("\nChecking name hash table\n");
937 code = WalkHashTable (cheader.nameHash, MAP_NAMEHASH, map, misc);
939 com_err (whoami, code, "walking name hash");
943 printf ("\nChecking id hash table\n");
946 code = WalkHashTable (cheader.idHash, MAP_IDHASH, map, misc);
948 com_err (whoami, code, "walking id hash");
952 /* hash walk calculates min and max id */
953 n = ((misc->maxId > misc->maxForId) ? misc->maxId : misc->maxForId);
954 misc->idRange = n - misc->minId + 1;
955 misc->idmap = (afs_int32 *)malloc (misc->idRange * sizeof(afs_int32));
957 com_err (whoami, 0, "Unable to malloc space for max ids of %d",
962 memset(misc->idmap, 0, misc->idRange*sizeof(misc->idmap[0]));
965 printf ("\nChecking entry chains\n");
968 code = WalkChains (map, misc);
970 com_err (whoami, code, "walking chains");
974 printf ("\nChecking free list\n");
977 code = WalkNextChain (map, misc, 0, 0);
979 com_err (whoami, code, "walking free list");
983 printf ("\nChecking orphans list\n");
986 code = WalkOwnedChain (map, misc, 0, 0);
988 com_err (whoami, code, "walking orphan list");
993 printf ("\nChecking for unreferenced entries\n");
996 code = GC (map, misc);
998 com_err (whoami, code, "looking for unreferenced entries");
1002 DumpRecreate (map, misc); /* check for owner cycles */
1003 if (misc->recreate) fclose (misc->recreate);
1005 if (misc->anon != 2) /* once for each hash table */
1006 fprintf (stderr, "Problems with ANON=%d\n", misc->anon);
1007 if (misc->ncells || misc->ninsts)
1008 fprintf (stderr, "Unexpected entry type\n");
1009 if (misc->nusers != ntohl(cheader.usercount)) {
1011 "User count inconsistent: should be %d, header claims: %d\n",
1012 misc->nusers, ntohl(cheader.usercount));
1014 if (misc->ngroups != ntohl(cheader.groupcount)) {
1016 "Group count inconsistent: should be %d, header claims: %d\n",
1017 misc->ngroups, ntohl(cheader.groupcount));
1019 if (misc->maxId > ntohl(cheader.maxID))
1020 fprintf (stderr, "Database's max user Id (%d) is smaller than largest user's Id (%d).\n", ntohl(cheader.maxID), misc->maxId);
1021 if (misc->minId < ntohl(cheader.maxGroup))
1022 fprintf (stderr, "Database's max group Id (%d) is smaller than largest group's Id (%d).\n", ntohl(cheader.maxGroup), misc->minId);
1024 if (misc->verbose) {
1025 printf ("\nMaxId = %d, MinId = %d, MaxForeignId = %d\n",
1026 misc->maxId, misc->minId, misc->maxForId);
1027 printf ("Free list is %d entries in length, %d groups on orphan list\n",
1028 misc->freeLength, misc->orphanLength);
1029 printf ("The longest owner list is %d, the longest continuation block chain is %d\n",
1030 misc->maxOwnerLength, misc->maxContLength);
1031 printf ("%d users ; %d foreign users ; and %d groups\n",
1032 misc->nusers, misc->nforeigns, misc->ngroups);
1038 #include "AFS_component_version_number.c"
1040 WorkerBee (as, arock)
1041 struct cmd_syndesc *as;
1046 struct misc_data misc; /* info & statistics */
1051 initialize_pt_error_table();
1052 initialize_u_error_table();
1054 pr_dbaseName = AFSDIR_SERVER_PRDB_FILEPATH;
1055 memset(&misc, 0, sizeof(misc));
1057 pr_dbaseName = as->parms[0].items->data; /* -database */
1058 misc.listuheader = (as->parms[1].items ? 1 : 0); /* -uheader */
1059 misc.listpheader = (as->parms[2].items ? 1 : 0); /* -pheader */
1060 misc.listentries = (as->parms[3].items ? 1 : 0); /* -entries */
1061 misc.verbose = (as->parms[4].items ? 1 : 0); /* -verbose */
1062 recreateFile = (as->parms[5].items ? as->parms[5].items->data :
1063 (char *)0); /* -rebuild */
1065 fd = open (pr_dbaseName, O_RDONLY, 0);
1067 com_err (whoami, errno, "Open failed on db %s", pr_dbaseName);
1071 /* Read the ubik header */
1072 if (misc.listuheader) {
1073 readUbikHeader(&misc);
1076 code = ReadHeader();
1077 if (code) return code;
1078 if (misc.listpheader) printheader(&cheader);
1081 misc.recreate = fopen (recreateFile, "w");
1082 if (misc.recreate == 0) {
1083 com_err (whoami, errno,
1084 "can't create file for recreation instructions: %s",
1089 code = CheckPrDatabase (&misc);
1091 com_err (whoami, code, "Checking prserver database");
1101 struct cmd_syndesc *ts;
1102 struct cmd_item *ti;
1106 ts=cmd_CreateSyntax((char *)0, WorkerBee, (char *)0, "PRDB check");
1107 cmd_AddParm(ts, "-database", CMD_SINGLE, CMD_REQUIRED, "ptdb_file");
1108 cmd_AddParm(ts, "-uheader", CMD_FLAG, CMD_OPTIONAL, "Display UBIK header");
1109 cmd_AddParm(ts, "-pheader", CMD_FLAG, CMD_OPTIONAL, "Display KADB header");
1110 cmd_AddParm(ts, "-entries", CMD_FLAG, CMD_OPTIONAL, "Display entries");
1111 cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, "verbose");
1112 cmd_AddParm(ts, "-rebuild", CMD_SINGLE, CMD_OPTIONAL|CMD_HIDE, "out_file");
1114 return cmd_Dispatch(argc, argv);