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>
38 #include <afs/cellconfig.h>
39 #include <afs/afsutil.h>
47 struct prheader cheader;
50 char *whoami = "db_verify";
51 #define UBIK_HEADERSIZE 64
54 afs_int32 printheader(h)
57 printf("Version = %d\n", ntohl(h->version));
58 printf("Header Size = %d\n", ntohl(h->headerSize));
59 printf("Free Ptr = 0x%x\n", ntohl(h->freePtr));
60 printf("EOF Ptr = 0x%x\n", ntohl(h->eofPtr));
61 printf("Max Group ID = %d\n", ntohl(h->maxGroup));
62 printf("Max User ID = %d\n", ntohl(h->maxID));
63 printf("Max Foreign ID = %d\n", ntohl(h->maxForeign));
64 /* printf("Max Sub/Super ID = %d\n", ntohl(h->maxInst)); */
65 printf("Orphaned groups = %d\n", ntohl(h->orphan));
66 printf("User Count = %d\n", ntohl(h->usercount));
67 printf("Group Count = %d\n", ntohl(h->groupcount));
68 /* printf("Foreign Count = %d\n", ntohl(h->foreigncount)); NYI */
69 /* printf("Sub/super Count = %d\n", ntohl(h->instcount)); NYI */
70 printf("Name Hash = %d buckets\n", HASHSIZE);
71 printf("ID Hash = %d buckets\n", HASHSIZE);
74 static afs_int32 pr_Read (pos, buff, len)
81 code = lseek(fd,UBIK_HEADERSIZE+pos, 0);
82 if (code == -1) return errno;
84 code = read(fd, buff, len);
85 if (code != len) return -1;
86 if (code == -1) return errno;
92 * Initializes the a transaction on the database and reads the header into
93 * the static variable cheader. If successful it returns a read-locked
94 * transaction. If ubik reports that cached database info should be up to date
95 * the cheader structure is not re-read from the ubik.
98 afs_int32 ReadHeader()
102 code = pr_Read (0, (char *) &cheader, sizeof(cheader));
104 com_err(whoami, code, "couldn't read header");
107 /* Check and see if database exists and is approximately OK. */
108 if (ntohl(cheader.headerSize) != sizeof(cheader) ||
109 ntohl(cheader.eofPtr) == 0) {
110 if (code) return code;
111 com_err (whoami, PRDBBAD, "header is bad");
117 static afs_int32 IDHash(x)
120 /* returns hash bucket for x */
121 return ((abs(x)) % HASHSIZE);
124 static afs_int32 NameHash(aname)
125 register unsigned char *aname;
127 /* returns hash bucket for aname */
128 register unsigned int hash=0;
130 /* stolen directly from the HashString function in the vol package */
131 for (i=strlen(aname),aname += i-1;i--;aname--)
132 hash = (hash*31) + (*aname-31);
133 return(hash % HASHSIZE);
136 #define MAP_NAMEHASH 1
138 #define MAP_HASHES (MAP_NAMEHASH | MAP_IDHASH)
141 #define MAP_OWNED 0x10
142 #define MAP_RECREATE 0x20
145 int nEntries; /* number of database entries */
146 int anon; /* found anonymous Id */
147 afs_int32 maxId; /* user */
148 afs_int32 minId; /* group */
149 afs_int32 maxForId; /* foreign user id */
150 int idRange; /* number of ids in map */
151 afs_int32 *idmap; /* map of all id's: midId is origin */
152 int nusers; /* counts of each type */
157 int maxOwnerLength; /* longest owner chain */
158 int maxContLength; /* longest chain of cont. blks */
159 int orphanLength; /* length of orphan list */
160 int freeLength; /* length of free list */
165 FILE *recreate; /* stream for recreate instructions */
168 int readUbikHeader(misc)
169 struct misc_data *misc;
172 struct ubik_hdr uheader;
174 offset = lseek(fd, 0, 0);
176 printf("error: lseek to 0 failed: %d %d\n", offset, errno);
180 /* now read the info */
181 r = read(fd, &uheader, sizeof(uheader));
182 if (r != sizeof(uheader)) {
183 printf("error: read of %d bytes failed: %d %d\n", sizeof(uheader), r, errno);
187 uheader.magic = ntohl(uheader.magic);
188 uheader.size = ntohl(uheader.size);
189 uheader.version.epoch = ntohl(uheader.version.epoch);
190 uheader.version.counter = ntohl(uheader.version.counter);
192 if (misc->listuheader) {
193 printf("Ubik Header\n");
194 printf(" Magic = 0x%x\n", uheader.magic);
195 printf(" Size = %u\n", uheader.size);
196 printf(" Version.epoch = %u\n", uheader.version.epoch);
197 printf(" Version.counter = %u\n", uheader.version.counter);
200 if (uheader.size != UBIK_HEADERSIZE)
201 printf("Ubik header size is %u (should be %u)\n", uheader.size, UBIK_HEADERSIZE);
202 if (uheader.magic != UBIK_MAGIC)
203 printf("Ubik header magic is 0x%x (should be 0x%x)\n", uheader.magic, UBIK_MAGIC);
208 afs_int32 ConvertDiskAddress (ea, eiP)
216 if (ea < sizeof(cheader)) return PRDBADDR;
217 if (ea >= ntohl(cheader.eofPtr)) return PRDBADDR;
218 ea -= sizeof(cheader);
219 i = ea / sizeof(struct prentry);
220 if (i*sizeof(struct prentry) != ea) return PRDBADDR;
221 /* if ((i < 0) || (i >= misc->nEntries)) return PRDBADDR; */
226 int PrintEntryError (misc, ea, e, indent)
227 struct misc_data *misc;
233 pr_PrintEntry (stderr, /*net order*/0, ea, e, indent);
237 afs_int32 WalkHashTable (hashtable, hashType, map, misc)
238 afs_int32 hashtable[]; /* hash table to walk */
239 int hashType; /* hash function to use */
240 char map[]; /* one byte per db entry */
241 struct misc_data *misc; /* stuff to keep track of */
244 int hi; /* index in hash table */
245 afs_int32 ea; /* entry's db addr */
246 int ei; /* entry's index */
247 char bit; /* bits to check for in map */
256 for (hi=0; hi<HASHSIZE; hi++) {
258 next_ea = ntohl(hashtable[hi]);
260 code = ConvertDiskAddress (next_ea, &ei);
262 fprintf (stderr, "Bad chain address %d\n", next_ea);
264 fprintf (stderr, "Last entry in chain:\n");
265 if (PrintEntryError (misc, ea, &e, 2)) return PRDBBAD;
268 "Skipping remainder of hash bucket %d\n", hi);
272 code = pr_Read (ea, (char *)&e, sizeof(e));
273 if (code) return code;
277 if ( ((ntohl(e.flags) & (PRGRP | PRINST)) == 0) &&
278 (strchr(e.name,'@')) ) {
280 if (id > misc->maxForId) misc->maxForId = id;
282 if (id == ANONYMOUSID) misc->anon++;
283 else if (id > misc->maxId) misc->maxId = id;
284 if (id < misc->minId) misc->minId = id;
289 next_ea = ntohl (e.nextName);
290 hash = NameHash (e.name);
293 next_ea = ntohl (e.nextID);
297 fprintf (stderr, "unknown hash table type %d\n", hashType);
303 "Entry found twice in hash table: bucket %d\n", hi);
306 "also in wrong bucket: should be in %d\n", hash);
307 if (PrintEntryError (misc, ea, &e, 2)) return PRDBBAD;
312 flags = ntohl(e.flags);
313 switch (flags & PRTYPE) {
315 fprintf (stderr, "ENTRY IS FREE");
318 fprintf (stderr, "ENTRY IS CONTINUATION");
327 "ENTRY IS unexpected type (flags=0x%x)\n", flags);
331 "ENTRY IS OF unknown type (flags=0x%x)\n", flags);
336 fprintf (stderr, "entry hashed in bucket %d should be %d\n",
339 if (PrintEntryError (misc, ea, &e, 2)) return PRDBBAD;
347 afs_int32 WalkNextChain (map, misc, ea, e)
348 char map[]; /* one byte per db entry */
349 struct misc_data *misc; /* stuff to keep track of */
356 struct prentry c; /* continuation entry */
357 afs_int32 na; /* next thread */
360 int count; /* number of members */
363 int length; /* length of chain */
366 head = ntohl(e->next);
369 count = 0; /* set to >9999 if list ends early */
370 for (i=0; i<PRSIZE; i++) {
371 afs_int32 id = ntohl(e->entries[i]);
372 if (id == PRBADID) continue;
376 /* in case the ids are large, convert to pure sign. */
377 if (id > 0) id_s = 1; else id_s = -1;
378 if (eid > 0) eid_s = 1; else eid_s = -1;
379 if (id_s * eid_s > 0) { /* sign should be different */
381 "Bad user/group dicotomy in membership list\n");
382 if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD;
385 /* count each user as a group, and each group a user is in */
386 if ((id >= misc->minId) && (id <= misc->maxId) &&
388 misc->idmap[id - misc->minId]++;
390 else if (head) count=9999;
395 head = ntohl(cheader.freePtr);
400 for (na=head; na; na=ntohl(c.next)) {
401 code = ConvertDiskAddress (na, &ni);
403 fprintf (stderr, "Bad continuation ptr %d", na);
404 if (e == 0) fprintf (stderr, "walking free list");
405 else if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD;
407 fprintf (stderr, "last block: \n");
408 if (PrintEntryError (misc, na, &c, 4)) return PRDBBAD;
412 code = pr_Read (na, (char *)&c, sizeof(c));
413 if (code) return code;
417 fprintf (stderr, "Continuation entry reused\n");
418 if (e == 0) fprintf (stderr, "walking free list");
419 else if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD;
420 if (PrintEntryError (misc, na, &c, 4)) return PRDBBAD;
425 if (e && (ntohl(c.id) != eid)) {
426 fprintf (stderr, "Continuation id mismatch\n");
427 if (e == 0) fprintf (stderr, "walking free list");
428 else if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD;
429 if (PrintEntryError (misc, na, &c, 4)) return PRDBBAD;
434 /* update membership count */
435 if (e) for (i=0; i<COSIZE; i++) {
436 afs_int32 id = ntohl(c.entries[i]);
437 if (id == PRBADID) continue;
441 /* in case the ids are large, convert to pure sign. */
442 if (id > 0) id_s = 1; else id_s = -1;
443 if (eid > 0) eid_s = 1; else eid_s = -1;
444 if (id_s * eid_s > 0) { /* sign should be different */
446 "Bad user/group dicotomy in membership list\n");
447 if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD;
448 if (PrintEntryError (misc, na, &c, 4)) return PRDBBAD;
451 /* count each user as a group, and each group a user is in */
452 if ((id >= misc->minId) && (id <= misc->maxId) &&
454 misc->idmap[id - misc->minId]++;
456 else if (c.next) count = 9999;
460 if (e && noErrors && (count != ntohl(e->count))) {
461 if (count > 9999) fprintf (stderr, "Membership list ends early\n");
462 fprintf (stderr, "Count was %d should be %d\n",
463 count, ntohl(e->count));
464 if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD;
468 if (length > misc->maxContLength) misc->maxContLength = length;
470 else misc->freeLength = length;
475 afs_int32 WalkOwnedChain (map, misc, ea, e)
476 char map[]; /* one byte per db entry */
477 struct misc_data *misc; /* stuff to keep track of */
483 struct prentry c; /* continuation entry */
484 afs_int32 na; /* next thread */
487 int length; /* length of chain */
490 head = ntohl(e->owned);
493 else head = ntohl(cheader.orphan);
496 for (na=head; na; na=ntohl(c.nextOwned)) {
497 code = ConvertDiskAddress (na, &ni);
499 fprintf (stderr, "Bad owned list ptr %d", na);
500 if (e == 0) fprintf (stderr, "walking orphan list");
501 else if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD;
503 fprintf (stderr, "last block: \n");
504 if (PrintEntryError (misc, na, &c, 4)) return PRDBBAD;
508 code = pr_Read (na, (char *)&c, sizeof(c));
509 if (code) return code;
512 if (map[ni] & MAP_OWNED) {
513 fprintf (stderr, "Entry on multiple owner chains\n");
514 if (e == 0) fprintf (stderr, "walking orphan list");
515 else if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD;
516 if (PrintEntryError (misc, na, &c, 4)) return PRDBBAD;
519 map[ni] |= MAP_OWNED;
520 if ((map[ni] & MAP_HASHES) != MAP_HASHES) {
521 fprintf (stderr, "Owned entry not hashed properly\n");
523 if (e == 0) fprintf (stderr, "walking orphan list");
524 else if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD;
525 if (PrintEntryError (misc, na, &c, 4)) return PRDBBAD;
529 if (ntohl(c.owner) != eid) {
530 fprintf (stderr, "Owner id mismatch\n");
534 else /* orphan */ if (c.owner) {
535 fprintf (stderr, "Orphan group owner not zero\n");
541 if (length > misc->maxOwnerLength) misc->maxOwnerLength = length;
543 else misc->orphanLength = length;
548 afs_int32 WalkChains (map, misc)
549 char map[]; /* one byte per db entry */
550 struct misc_data *misc; /* stuff to keep track of */
554 afs_int32 ea; /* entry's db addr */
559 /* check all entries found in hash table walks */
560 for (ei=0; ei < misc->nEntries; ei++) if (map[ei] & MAP_HASHES) {
561 ea = ei * sizeof(struct prentry) + sizeof(cheader);
562 code = pr_Read (ea, (char *)&e, sizeof(e));
563 if (code) return code;
565 if ((map[ei] & MAP_HASHES) != MAP_HASHES) {
566 fprintf (stderr, "entry not in both hashtables\n");
567 if ((map[ei] & MAP_NAMEHASH) != MAP_NAMEHASH)
568 fprintf (stderr, "--> entry not in Name hashtable\n");
569 if ((map[ei] & MAP_IDHASH) != MAP_IDHASH)
570 fprintf (stderr, "--> entry not in ID hashtable\n");
573 if (PrintEntryError (misc, ea, &e, 2)) return PRDBBAD;
579 type = ntohl (e.flags) & PRTYPE;
583 fprintf (stderr, "Group id not negative\n");
586 /* special case sysadmin: it owns itself */
587 if (id == SYSADMINID) {
588 if (ntohl(e.owner) != SYSADMINID) {
590 "System:administrators doesn't own itself\n");
594 code = WalkOwnedChain (map, misc, ea, &e);
595 if (code) return code;
596 code = WalkNextChain (map, misc, ea, &e);
597 if (code) return code;
602 fprintf (stderr, "User id negative\n");
606 /* Users are owned by sysadmin, but sysadmin doesn't have an owner
607 * chain. Check this then set the owned bit. */
608 if (ntohl(e.owner) != SYSADMINID) {
609 fprintf (stderr, "User not owned by system:administrators\n");
613 fprintf (stderr, "User has owned pointer\n");
616 map[ei] |= MAP_OWNED;
618 code = WalkOwnedChain (map, misc, ea, &e);
619 if (code) return code;
620 code = WalkNextChain (map, misc, ea, &e);
621 if (code) return code;
622 if (strchr(e.name,'@') == 0) {
623 misc->nusers++; /* Not a foreign user */
625 misc->nforeigns++; /* A foreign user */
634 fprintf (stderr, "ENTRY IS unexpected type [PRFOREIGN] (flags=0x%x)\n", e.flags);
640 fprintf (stderr, "entry with unexpected type");
648 afs_int32 GC (map, misc)
650 struct misc_data *misc;
658 for (ei=0; ei<misc->nEntries; ei++) {
659 ea = ei * sizeof(struct prentry) + sizeof(cheader);
660 code = pr_Read (ea, (char *)&e, sizeof(e));
661 if (code) return code;
664 fprintf (stderr, "Unreferenced entry:");
665 if (PrintEntryError (misc, ea, &e, 2)) return PRDBBAD;
667 /* all users and groups should be owned, and their membership counts
669 else if ((m & MAP_HASHES) == MAP_HASHES) {
672 if (!(m & MAP_OWNED)) {
673 fprintf (stderr, "Entry not on any owner chain:\n");
674 if (PrintEntryError (misc, ea, &e, 2)) return PRDBBAD;
677 if ((id >= misc->minId) && (id <= misc->maxId) &&
678 (id != ANONYMOUSID) &&
679 ((refCount = misc->idmap[id - misc->minId]) !=
682 fprintf (stderr, "Entry membership count is inconsistent: %d entries refer to this one\n", refCount);
683 if (PrintEntryError (misc, ea, &e, 2)) return PRDBBAD;
685 /* get continuation blocks too */
686 for (na=ntohl(e.next); na; na=ntohl(e.next)) {
688 code = ConvertDiskAddress (na, &ni);
689 if (code) return code;
690 code = pr_Read (na, (char *)&e, sizeof(e));
691 if (code) return code;
692 if (PrintEntryError (misc, na, &e, 4)) return PRDBBAD;
704 if (strpbrk (s," \t")) {
705 qs = (char *)malloc (strlen(s)+3);
713 afs_int32 DumpRecreate (map, misc)
715 struct misc_data *misc;
725 int builtinUsers = 0;
726 int createLow = 0; /* users uncreate from here */
727 afs_int32 *idmap; /* map of all id's */
733 memset(idmap, 0, misc->idRange*sizeof(misc->idmap[0]));
736 for (ei=createLow; ei<misc->nEntries; ei++) {
737 if ((map[ei] & MAP_HASHES) &&
738 (map[ei] & MAP_RECREATE) == 0) {
743 ea = ei * sizeof(struct prentry) + sizeof(cheader);
744 code = pr_Read (ea, (char *)&e, sizeof(e));
745 if (code) return code;
747 if (misc->listentries)
748 pr_PrintEntry(stdout, 0/*not in host order*/, ea, &e, 0);
751 flags = ntohl(e.flags);
752 owner = ntohl(e.owner);
753 name = QuoteName(e.name);
755 if (!strcmp (e.name, "system:administrators") ||
756 !strcmp (e.name, "system:anyuser") ||
757 !strcmp (e.name, "system:authuser") ||
758 !strcmp (e.name, "system:backup") ||
759 !strcmp (e.name, "anonymous")) {
764 /* check for duplicate id. This may still lead to duplicate
766 if (idmap[id-misc->minId]) {
768 "Skipping entry with duplicate id %di\n", id);
772 /* If owner doesn't exist skip for now, unless we're our own
773 * owner. If so, a special case allows a group to own itself
774 * if caller is sysadmin. This leaves only owner cycles to
777 if ((owner < misc->minId) || (owner > misc->maxId)) {
778 if (owner == ANONYMOUSID) fprintf (stderr, "Warning: id %di is owned by ANONYMOUS; using sysadmin instead\n", id);
779 else fprintf (stderr, "Bogus owner (%d) of id %di; using sysadmin instead\n", owner, id);
784 "Warning: group %s is self owning\n", name);
786 else if (owner == 0) {
787 fprintf (stderr, "Warning: orphan group %s will become self owning.\n", name);
790 else if (idmap[owner-misc->minId] == 0) goto user_skip;
792 if (rc) fprintf (rc, "cr %s %d %d\n", name, id, owner);
794 gq = uq = access = mask = 0;
795 if (flags & PRACCESS) {
796 access = (flags >> PRIVATE_SHIFT);
797 mask |= PR_SF_ALLBITS;
799 if (flags & PRQUOTA) {
800 gq = ntohl(e.ngroups);
801 uq = ntohl(e.nusers);
802 mask |= PR_SF_NGROUPS | PR_SF_NUSERS;
805 fprintf (rc, "sf %d %x %x %d %d\n",
806 id, mask, access, gq, uq);
809 map[ei] |= MAP_RECREATE;
810 if (id != ANONYMOUSID) idmap[id-misc->minId]++;
813 /* bump low water mark if possible */
814 if (ei == createLow) createLow++;
820 /* Now create the entries with circular owner dependencies and make them
821 * own themselves. This is the only way to create them with the correct
823 for (ei=0; ei<misc->nEntries; ei++)
824 if (((map[ei] & MAP_HASHES) == MAP_HASHES) &&
825 (map[ei] & MAP_RECREATE) == 0) {
826 ea = ei * sizeof(struct prentry) + sizeof(cheader);
827 code = pr_Read (ea, (char *)&e, sizeof(e));
828 if (code) return code;
831 name = QuoteName(e.name);
832 fprintf (stderr, "Warning: group %s in self owning cycle\n", name);
833 if (rc) fprintf (rc, "cr %s %d %d\n", name, id, id);
834 idmap[id-misc->minId]++;
836 for (ei=0; ei<misc->nEntries; ei++)
837 if (((map[ei] & MAP_HASHES) == MAP_HASHES) &&
838 (map[ei] & MAP_RECREATE) == 0) {
839 ea = ei * sizeof(struct prentry) + sizeof(cheader);
840 code = pr_Read (ea, (char *)&e, sizeof(e));
841 if (code) return code;
843 owner = ntohl(e.owner);
844 if (idmap[owner-misc->minId] == 0) {
846 "Skipping chown of '%s' to non-existant owner %di\n",
849 else if (rc) fprintf (rc, "ce %d \"\" %d 0\n",
850 ntohl(e.id), e.owner);
853 if (rc == 0) return 0;
855 /* Reconstruct membership information based on the groups' user lists. */
856 for (ei=0; ei<misc->nEntries; ei++) {
857 if ((map[ei] & MAP_HASHES) == MAP_HASHES) {
858 ea = ei * sizeof(struct prentry) + sizeof(cheader);
859 code = pr_Read (ea, (char *)&e, sizeof(e));
860 if (code) return code;
863 flags = ntohl(e.flags);
865 if ((id < 0) && (flags & PRGRP)) {
869 for (i=0; i<PRSIZE; i++) {
870 afs_int32 uid = ntohl(e.entries[i]);
872 if (uid == PRBADID) continue;
874 fprintf (rc, "au %d %d\n", uid, id);
876 } else fprintf (stderr,
877 "Skipping %di in group %di\n", uid, id);
882 code = pr_Read (na, (char *)&c, sizeof(c));
883 if (code) return code;
885 if ((id == ntohl(c.id)) && (ntohl(c.flags) & PRCONT)) {
886 for (i=0; i<COSIZE; i++) {
887 afs_int32 uid = ntohl(c.entries[i]);
889 if (uid == PRBADID) continue;
891 fprintf (rc, "au %d %d\n", uid, id);
893 } else fprintf (stderr,
894 "Skipping %di in group %di\n",
899 "Skipping continuation block at %d\n", na);
904 if (count != ntohl(e.count))
905 fprintf (stderr, "Group membership count problem found %d should be %d\n", count, ntohl(e.count));
906 } else if ((id < 0) || (flags & PRGRP)) {
907 fprintf (stderr, "Skipping group %di\n", id);
914 afs_int32 CheckPrDatabase (misc)
915 struct misc_data *misc; /* info & statistics */
920 char *map; /* map of each entry in db */
922 eof = ntohl (cheader.eofPtr);
923 eof -= sizeof(cheader);
924 n = eof / sizeof(struct prentry);
925 if ((eof < 0) || (n*sizeof(struct prentry) != eof)) {
927 com_err (whoami, code,
928 "eof ptr no good: eof=%d, sizeof(prentry)=%d",
929 eof, sizeof(struct prentry));
934 printf ("Database has %d entries\n", n);
935 map = (char *)malloc (n);
940 printf ("\nChecking name hash table\n");
943 code = WalkHashTable (cheader.nameHash, MAP_NAMEHASH, map, misc);
945 com_err (whoami, code, "walking name hash");
949 printf ("\nChecking id hash table\n");
952 code = WalkHashTable (cheader.idHash, MAP_IDHASH, map, misc);
954 com_err (whoami, code, "walking id hash");
958 /* hash walk calculates min and max id */
959 n = ((misc->maxId > misc->maxForId) ? misc->maxId : misc->maxForId);
960 misc->idRange = n - misc->minId + 1;
961 misc->idmap = (afs_int32 *)malloc (misc->idRange * sizeof(afs_int32));
963 com_err (whoami, 0, "Unable to malloc space for max ids of %d",
968 memset(misc->idmap, 0, misc->idRange*sizeof(misc->idmap[0]));
971 printf ("\nChecking entry chains\n");
974 code = WalkChains (map, misc);
976 com_err (whoami, code, "walking chains");
980 printf ("\nChecking free list\n");
983 code = WalkNextChain (map, misc, 0, 0);
985 com_err (whoami, code, "walking free list");
989 printf ("\nChecking orphans list\n");
992 code = WalkOwnedChain (map, misc, 0, 0);
994 com_err (whoami, code, "walking orphan list");
999 printf ("\nChecking for unreferenced entries\n");
1002 code = GC (map, misc);
1004 com_err (whoami, code, "looking for unreferenced entries");
1008 DumpRecreate (map, misc); /* check for owner cycles */
1009 if (misc->recreate) fclose (misc->recreate);
1011 if (misc->anon != 2) /* once for each hash table */
1012 fprintf (stderr, "Problems with ANON=%d\n", misc->anon);
1013 if (misc->ncells || misc->ninsts)
1014 fprintf (stderr, "Unexpected entry type\n");
1015 if (misc->nusers != ntohl(cheader.usercount)) {
1017 "User count inconsistent: should be %d, header claims: %d\n",
1018 misc->nusers, ntohl(cheader.usercount));
1020 if (misc->ngroups != ntohl(cheader.groupcount)) {
1022 "Group count inconsistent: should be %d, header claims: %d\n",
1023 misc->ngroups, ntohl(cheader.groupcount));
1025 if (misc->maxId > ntohl(cheader.maxID))
1026 fprintf (stderr, "Database's max user Id (%d) is smaller than largest user's Id (%d).\n", ntohl(cheader.maxID), misc->maxId);
1027 if (misc->minId < ntohl(cheader.maxGroup))
1028 fprintf (stderr, "Database's max group Id (%d) is smaller than largest group's Id (%d).\n", ntohl(cheader.maxGroup), misc->minId);
1030 if (misc->verbose) {
1031 printf ("\nMaxId = %d, MinId = %d, MaxForeignId = %d\n",
1032 misc->maxId, misc->minId, misc->maxForId);
1033 printf ("Free list is %d entries in length, %d groups on orphan list\n",
1034 misc->freeLength, misc->orphanLength);
1035 printf ("The longest owner list is %d, the longest continuation block chain is %d\n",
1036 misc->maxOwnerLength, misc->maxContLength);
1037 printf ("%d users ; %d foreign users ; and %d groups\n",
1038 misc->nusers, misc->nforeigns, misc->ngroups);
1044 #include "AFS_component_version_number.c"
1046 WorkerBee (as, arock)
1047 struct cmd_syndesc *as;
1052 struct misc_data misc; /* info & statistics */
1054 initialize_PT_error_table();
1055 initialize_U_error_table();
1057 pr_dbaseName = AFSDIR_SERVER_PRDB_FILEPATH;
1058 memset(&misc, 0, sizeof(misc));
1060 pr_dbaseName = as->parms[0].items->data; /* -database */
1061 misc.listuheader = (as->parms[1].items ? 1 : 0); /* -uheader */
1062 misc.listpheader = (as->parms[2].items ? 1 : 0); /* -pheader */
1063 misc.listentries = (as->parms[3].items ? 1 : 0); /* -entries */
1064 misc.verbose = (as->parms[4].items ? 1 : 0); /* -verbose */
1065 recreateFile = (as->parms[5].items ? as->parms[5].items->data :
1066 NULL); /* -rebuild */
1068 fd = open (pr_dbaseName, O_RDONLY, 0);
1070 com_err (whoami, errno, "Open failed on db %s", pr_dbaseName);
1074 /* Read the ubik header */
1075 if (misc.listuheader) {
1076 readUbikHeader(&misc);
1079 code = ReadHeader();
1080 if (code) return code;
1081 if (misc.listpheader) printheader(&cheader);
1084 misc.recreate = fopen (recreateFile, "w");
1085 if (misc.recreate == 0) {
1086 com_err (whoami, errno,
1087 "can't create file for recreation instructions: %s",
1092 code = CheckPrDatabase (&misc);
1094 com_err (whoami, code, "Checking prserver database");
1104 struct cmd_syndesc *ts;
1108 ts=cmd_CreateSyntax(NULL, WorkerBee, NULL, "PRDB check");
1109 cmd_AddParm(ts, "-database", CMD_SINGLE, CMD_REQUIRED, "ptdb_file");
1110 cmd_AddParm(ts, "-uheader", CMD_FLAG, CMD_OPTIONAL, "Display UBIK header");
1111 cmd_AddParm(ts, "-pheader", CMD_FLAG, CMD_OPTIONAL, "Display KADB header");
1112 cmd_AddParm(ts, "-entries", CMD_FLAG, CMD_OPTIONAL, "Display entries");
1113 cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, "verbose");
1114 cmd_AddParm(ts, "-rebuild", CMD_SINGLE, CMD_OPTIONAL|CMD_HIDE, "out_file");
1116 return cmd_Dispatch(argc, argv);