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 <afs/param.h>
14 #include <sys/types.h>
17 #include <WINNT/afsevent.h>
21 #include <netinet/in.h>
27 #include <afs/cellconfig.h>
28 #include <afs/afsutil.h>
36 struct prheader cheader;
39 char *whoami = "db_verify";
40 #define UBIK_HEADERSIZE 64
43 afs_int32 printheader(h)
46 printf("Version = %d\n", ntohl(h->version));
47 printf("Header Size = %d\n", ntohl(h->headerSize));
48 printf("Free Ptr = 0x%x\n", ntohl(h->freePtr));
49 printf("EOF Ptr = 0x%x\n", ntohl(h->eofPtr));
50 printf("Max Group ID = %d\n", ntohl(h->maxGroup));
51 printf("Max User ID = %d\n", ntohl(h->maxID));
52 printf("Max Foreign ID = %d\n", ntohl(h->maxForeign));
53 /* printf("Max Sub/Super ID = %d\n", ntohl(h->maxInst)); */
54 printf("Orphaned groups = %d\n", ntohl(h->orphan));
55 printf("User Count = %d\n", ntohl(h->usercount));
56 printf("Group Count = %d\n", ntohl(h->groupcount));
57 /* printf("Foreign Count = %d\n", ntohl(h->foreigncount)); NYI */
58 /* printf("Sub/super Count = %d\n", ntohl(h->instcount)); NYI */
59 printf("Name Hash = %d buckets\n", HASHSIZE);
60 printf("ID Hash = %d buckets\n", HASHSIZE);
63 static afs_int32 pr_Read (pos, buff, len)
70 code = lseek(fd,UBIK_HEADERSIZE+pos, 0);
71 if (code == -1) return errno;
73 code = read(fd, buff, len);
74 if (code != len) return -1;
75 if (code == -1) return errno;
81 * Initializes the a transaction on the database and reads the header into
82 * the static variable cheader. If successful it returns a read-locked
83 * transaction. If ubik reports that cached database info should be up to date
84 * the cheader structure is not re-read from the ubik.
87 afs_int32 ReadHeader()
91 code = pr_Read (0, (char *) &cheader, sizeof(cheader));
93 com_err(whoami, code, "couldn't read header");
96 /* Check and see if database exists and is approximately OK. */
97 if (ntohl(cheader.headerSize) != sizeof(cheader) ||
98 ntohl(cheader.eofPtr) == 0) {
99 if (code) return code;
100 com_err (whoami, PRDBBAD, "header is bad");
106 static afs_int32 IDHash(x)
109 /* returns hash bucket for x */
110 return ((abs(x)) % HASHSIZE);
113 static afs_int32 NameHash(aname)
114 register unsigned char *aname;
116 /* returns hash bucket for aname */
117 register unsigned int hash=0;
119 /* stolen directly from the HashString function in the vol package */
120 for (i=strlen(aname),aname += i-1;i--;aname--)
121 hash = (hash*31) + (*aname-31);
122 return(hash % HASHSIZE);
125 #define MAP_NAMEHASH 1
127 #define MAP_HASHES (MAP_NAMEHASH | MAP_IDHASH)
130 #define MAP_OWNED 0x10
131 #define MAP_RECREATE 0x20
134 int nEntries; /* number of database entries */
135 int anon; /* found anonymous Id */
136 afs_int32 maxId; /* user */
137 afs_int32 minId; /* group */
138 afs_int32 maxForId; /* foreign user id */
139 int idRange; /* number of ids in map */
140 afs_int32 *idmap; /* map of all id's: midId is origin */
141 int nusers; /* counts of each type */
146 int maxOwnerLength; /* longest owner chain */
147 int maxContLength; /* longest chain of cont. blks */
148 int orphanLength; /* length of orphan list */
149 int freeLength; /* length of free list */
154 FILE *recreate; /* stream for recreate instructions */
157 int readUbikHeader(misc)
158 struct misc_data *misc;
161 struct ubik_hdr uheader;
163 offset = lseek(fd, 0, 0);
165 printf("error: lseek to 0 failed: %d %d\n", offset, errno);
169 /* now read the info */
170 r = read(fd, &uheader, sizeof(uheader));
171 if (r != sizeof(uheader)) {
172 printf("error: read of %d bytes failed: %d %d\n", sizeof(uheader), r, errno);
176 uheader.magic = ntohl(uheader.magic);
177 uheader.size = ntohl(uheader.size);
178 uheader.version.epoch = ntohl(uheader.version.epoch);
179 uheader.version.counter = ntohl(uheader.version.counter);
181 if (misc->listuheader) {
182 printf("Ubik Header\n");
183 printf(" Magic = 0x%x\n", uheader.magic);
184 printf(" Size = %u\n", uheader.size);
185 printf(" Version.epoch = %u\n", uheader.version.epoch);
186 printf(" Version.counter = %u\n", uheader.version.counter);
189 if (uheader.size != UBIK_HEADERSIZE)
190 printf("Ubik header size is %u (should be %u)\n", uheader.size, UBIK_HEADERSIZE);
191 if (uheader.magic != UBIK_MAGIC)
192 printf("Ubik header magic is 0x%x (should be 0x%x)\n", uheader.magic, UBIK_MAGIC);
197 afs_int32 ConvertDiskAddress (ea, eiP)
205 if (ea < sizeof(cheader)) return PRDBADDR;
206 if (ea >= ntohl(cheader.eofPtr)) return PRDBADDR;
207 ea -= sizeof(cheader);
208 i = ea / sizeof(struct prentry);
209 if (i*sizeof(struct prentry) != ea) return PRDBADDR;
210 /* if ((i < 0) || (i >= misc->nEntries)) return PRDBADDR; */
215 int PrintEntryError (misc, ea, e, indent)
216 struct misc_data *misc;
223 pr_PrintEntry (stderr, /*net order*/0, ea, e, indent);
227 afs_int32 WalkHashTable (hashtable, hashType, map, misc)
228 afs_int32 hashtable[]; /* hash table to walk */
229 int hashType; /* hash function to use */
230 char map[]; /* one byte per db entry */
231 struct misc_data *misc; /* stuff to keep track of */
234 int hi; /* index in hash table */
235 afs_int32 ea; /* entry's db addr */
236 int ei; /* entry's index */
237 char bit; /* bits to check for in map */
246 for (hi=0; hi<HASHSIZE; hi++) {
248 next_ea = ntohl(hashtable[hi]);
250 code = ConvertDiskAddress (next_ea, &ei);
252 fprintf (stderr, "Bad chain address %d\n", next_ea);
254 fprintf (stderr, "Last entry in chain:\n");
255 if (PrintEntryError (misc, ea, &e, 2)) return PRDBBAD;
258 "Skipping remainder of hash bucket %d\n", hi);
262 code = pr_Read (ea, (char *)&e, sizeof(e));
263 if (code) return code;
267 if ( ((ntohl(e.flags) & (PRGRP | PRINST)) == 0) &&
268 (index(e.name,'@')) ) {
270 if (id > misc->maxForId) misc->maxForId = id;
272 if (id == ANONYMOUSID) misc->anon++;
273 else if (id > misc->maxId) misc->maxId = id;
274 if (id < misc->minId) misc->minId = id;
279 next_ea = ntohl (e.nextName);
280 hash = NameHash (e.name);
283 next_ea = ntohl (e.nextID);
287 fprintf (stderr, "unknown hash table type %d\n", hashType);
293 "Entry found twice in hash table: bucket %d\n", hi);
296 "also in wrong bucket: should be in %d\n", hash);
297 if (PrintEntryError (misc, ea, &e, 2)) return PRDBBAD;
302 flags = ntohl(e.flags);
303 switch (flags & PRTYPE) {
305 fprintf (stderr, "ENTRY IS FREE");
308 fprintf (stderr, "ENTRY IS CONTINUATION");
317 "ENTRY IS unexpected type (flags=0x%x)\n", flags);
321 "ENTRY IS OF unknown type (flags=0x%x)\n", flags);
326 fprintf (stderr, "entry hashed in bucket %d should be %d\n",
329 if (PrintEntryError (misc, ea, &e, 2)) return PRDBBAD;
337 afs_int32 WalkNextChain (map, misc, ea, e)
338 char map[]; /* one byte per db entry */
339 struct misc_data *misc; /* stuff to keep track of */
346 struct prentry c; /* continuation entry */
347 afs_int32 na; /* next thread */
350 int count; /* number of members */
353 int length; /* length of chain */
356 head = ntohl(e->next);
359 count = 0; /* set to >9999 if list ends early */
360 for (i=0; i<PRSIZE; i++) {
361 afs_int32 id = ntohl(e->entries[i]);
362 if (id == PRBADID) continue;
366 /* in case the ids are large, convert to pure sign. */
367 if (id > 0) id_s = 1; else id_s = -1;
368 if (eid > 0) eid_s = 1; else eid_s = -1;
369 if (id_s * eid_s > 0) { /* sign should be different */
371 "Bad user/group dicotomy in membership list\n");
372 if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD;
375 /* count each user as a group, and each group a user is in */
376 if ((id >= misc->minId) && (id <= misc->maxId) &&
378 misc->idmap[id - misc->minId]++;
380 else if (head) count=9999;
385 head = ntohl(cheader.freePtr);
390 for (na=head; na; na=ntohl(c.next)) {
391 code = ConvertDiskAddress (na, &ni);
393 fprintf (stderr, "Bad continuation ptr %d", na);
394 if (e == 0) fprintf (stderr, "walking free list");
395 else if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD;
397 fprintf (stderr, "last block: \n");
398 if (PrintEntryError (misc, na, &c, 4)) return PRDBBAD;
402 code = pr_Read (na, (char *)&c, sizeof(c));
403 if (code) return code;
407 fprintf (stderr, "Continuation entry reused\n");
408 if (e == 0) fprintf (stderr, "walking free list");
409 else if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD;
410 if (PrintEntryError (misc, na, &c, 4)) return PRDBBAD;
415 if (e && (ntohl(c.id) != eid)) {
416 fprintf (stderr, "Continuation id mismatch\n");
417 if (e == 0) fprintf (stderr, "walking free list");
418 else if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD;
419 if (PrintEntryError (misc, na, &c, 4)) return PRDBBAD;
424 /* update membership count */
425 if (e) for (i=0; i<COSIZE; i++) {
426 afs_int32 id = ntohl(c.entries[i]);
427 if (id == PRBADID) continue;
431 /* in case the ids are large, convert to pure sign. */
432 if (id > 0) id_s = 1; else id_s = -1;
433 if (eid > 0) eid_s = 1; else eid_s = -1;
434 if (id_s * eid_s > 0) { /* sign should be different */
436 "Bad user/group dicotomy in membership list\n");
437 if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD;
438 if (PrintEntryError (misc, na, &c, 4)) return PRDBBAD;
441 /* count each user as a group, and each group a user is in */
442 if ((id >= misc->minId) && (id <= misc->maxId) &&
444 misc->idmap[id - misc->minId]++;
446 else if (c.next) count = 9999;
450 if (e && noErrors && (count != ntohl(e->count))) {
451 if (count > 9999) fprintf (stderr, "Membership list ends early\n");
452 fprintf (stderr, "Count was %d should be %d\n",
453 count, ntohl(e->count));
454 if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD;
458 if (length > misc->maxContLength) misc->maxContLength = length;
460 else misc->freeLength = length;
465 afs_int32 WalkOwnedChain (map, misc, ea, e)
466 char map[]; /* one byte per db entry */
467 struct misc_data *misc; /* stuff to keep track of */
473 struct prentry c; /* continuation entry */
474 afs_int32 na; /* next thread */
477 int length; /* length of chain */
480 head = ntohl(e->owned);
483 else head = ntohl(cheader.orphan);
486 for (na=head; na; na=ntohl(c.nextOwned)) {
487 code = ConvertDiskAddress (na, &ni);
489 fprintf (stderr, "Bad owned list ptr %d", na);
490 if (e == 0) fprintf (stderr, "walking orphan list");
491 else if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD;
493 fprintf (stderr, "last block: \n");
494 if (PrintEntryError (misc, na, &c, 4)) return PRDBBAD;
498 code = pr_Read (na, (char *)&c, sizeof(c));
499 if (code) return code;
502 if (map[ni] & MAP_OWNED) {
503 fprintf (stderr, "Entry on multiple owner chains\n");
504 if (e == 0) fprintf (stderr, "walking orphan list");
505 else if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD;
506 if (PrintEntryError (misc, na, &c, 4)) return PRDBBAD;
509 map[ni] |= MAP_OWNED;
510 if ((map[ni] & MAP_HASHES) != MAP_HASHES) {
511 fprintf (stderr, "Owned entry not hashed properly\n");
513 if (e == 0) fprintf (stderr, "walking orphan list");
514 else if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD;
515 if (PrintEntryError (misc, na, &c, 4)) return PRDBBAD;
519 if (ntohl(c.owner) != eid) {
520 fprintf (stderr, "Owner id mismatch\n");
524 else /* orphan */ if (c.owner) {
525 fprintf (stderr, "Orphan group owner not zero\n");
531 if (length > misc->maxOwnerLength) misc->maxOwnerLength = length;
533 else misc->orphanLength = length;
538 afs_int32 WalkChains (map, misc)
539 char map[]; /* one byte per db entry */
540 struct misc_data *misc; /* stuff to keep track of */
544 afs_int32 ea; /* entry's db addr */
549 /* check all entries found in hash table walks */
550 for (ei=0; ei < misc->nEntries; ei++) if (map[ei] & MAP_HASHES) {
551 ea = ei * sizeof(struct prentry) + sizeof(cheader);
552 code = pr_Read (ea, (char *)&e, sizeof(e));
553 if (code) return code;
555 if ((map[ei] & MAP_HASHES) != MAP_HASHES) {
556 fprintf (stderr, "entry not in both hashtables\n");
557 if ((map[ei] & MAP_NAMEHASH) != MAP_NAMEHASH)
558 fprintf (stderr, "--> entry not in Name hashtable\n");
559 if ((map[ei] & MAP_IDHASH) != MAP_IDHASH)
560 fprintf (stderr, "--> entry not in ID hashtable\n");
563 if (PrintEntryError (misc, ea, &e, 2)) return PRDBBAD;
569 type = ntohl (e.flags) & PRTYPE;
573 fprintf (stderr, "Group id not negative\n");
576 /* special case sysadmin: it owns itself */
577 if (id == SYSADMINID) {
578 if (ntohl(e.owner) != SYSADMINID) {
580 "System:administrators doesn't own itself\n");
584 code = WalkOwnedChain (map, misc, ea, &e);
585 if (code) return code;
586 code = WalkNextChain (map, misc, ea, &e);
587 if (code) return code;
592 fprintf (stderr, "User id negative\n");
596 /* Users are owned by sysadmin, but sysadmin doesn't have an owner
597 * chain. Check this then set the owned bit. */
598 if (ntohl(e.owner) != SYSADMINID) {
599 fprintf (stderr, "User not owned by system:administrators\n");
603 fprintf (stderr, "User has owned pointer\n");
606 map[ei] |= MAP_OWNED;
608 code = WalkOwnedChain (map, misc, ea, &e);
609 if (code) return code;
610 code = WalkNextChain (map, misc, ea, &e);
611 if (code) return code;
612 if (index(e.name,'@') == 0) {
613 misc->nusers++; /* Not a foreign user */
615 misc->nforeigns++; /* A foreign user */
624 fprintf (stderr, "ENTRY IS unexpected type [PRFOREIGN] (flags=0x%x)\n", e.flags);
630 fprintf (stderr, "entry with unexpected type");
638 afs_int32 GC (map, misc)
640 struct misc_data *misc;
648 for (ei=0; ei<misc->nEntries; ei++) {
649 ea = ei * sizeof(struct prentry) + sizeof(cheader);
650 code = pr_Read (ea, (char *)&e, sizeof(e));
651 if (code) return code;
654 fprintf (stderr, "Unreferenced entry:");
655 if (PrintEntryError (misc, ea, &e, 2)) return PRDBBAD;
657 /* all users and groups should be owned, and their membership counts
659 else if ((m & MAP_HASHES) == MAP_HASHES) {
662 if (!(m & MAP_OWNED)) {
663 fprintf (stderr, "Entry not on any owner chain:\n");
664 if (PrintEntryError (misc, ea, &e, 2)) return PRDBBAD;
667 if ((id >= misc->minId) && (id <= misc->maxId) &&
668 (id != ANONYMOUSID) &&
669 ((refCount = misc->idmap[id - misc->minId]) !=
672 fprintf (stderr, "Entry membership count is inconsistent: %d entries refer to this one\n", refCount);
673 if (PrintEntryError (misc, ea, &e, 2)) return PRDBBAD;
675 /* get continuation blocks too */
676 for (na=ntohl(e.next); na; na=ntohl(e.next)) {
678 code = ConvertDiskAddress (na, &ni);
679 if (code) return code;
680 code = pr_Read (na, (char *)&e, sizeof(e));
681 if (code) return code;
682 if (PrintEntryError (misc, na, &e, 4)) return PRDBBAD;
694 if (strpbrk (s," \t")) {
695 qs = (char *)malloc (strlen(s)+3);
703 afs_int32 DumpRecreate (map, misc)
705 struct misc_data *misc;
715 int builtinUsers = 0;
716 int createLow = 0; /* users uncreate from here */
717 afs_int32 *idmap; /* map of all id's */
723 bzero (idmap, misc->idRange*sizeof(misc->idmap[0]));
726 for (ei=createLow; ei<misc->nEntries; ei++) {
727 if ((map[ei] & MAP_HASHES) &&
728 (map[ei] & MAP_RECREATE) == 0) {
733 ea = ei * sizeof(struct prentry) + sizeof(cheader);
734 code = pr_Read (ea, (char *)&e, sizeof(e));
735 if (code) return code;
737 if (misc->listentries)
738 pr_PrintEntry(stdout, 0/*not in host order*/, ea, &e, 0);
741 flags = ntohl(e.flags);
742 owner = ntohl(e.owner);
743 name = QuoteName(e.name);
745 if (!strcmp (e.name, "system:administrators") ||
746 !strcmp (e.name, "system:anyuser") ||
747 !strcmp (e.name, "system:authuser") ||
748 !strcmp (e.name, "system:backup") ||
749 !strcmp (e.name, "anonymous")) {
754 /* check for duplicate id. This may still lead to duplicate
756 if (idmap[id-misc->minId]) {
758 "Skipping entry with duplicate id %di\n", id);
762 /* If owner doesn't exist skip for now, unless we're our own
763 * owner. If so, a special case allows a group to own itself
764 * if caller is sysadmin. This leaves only owner cycles to
767 if ((owner < misc->minId) || (owner > misc->maxId)) {
768 if (owner == ANONYMOUSID) fprintf (stderr, "Warning: id %di is owned by ANONYMOUS; using sysadmin instead\n", id);
769 else fprintf (stderr, "Bogus owner (%d) of id %di; using sysadmin instead\n", owner, id);
774 "Warning: group %s is self owning\n", name);
776 else if (owner == 0) {
777 fprintf (stderr, "Warning: orphan group %s will become self owning.\n", name);
780 else if (idmap[owner-misc->minId] == 0) goto user_skip;
782 if (rc) fprintf (rc, "cr %s %d %d\n", name, id, owner);
784 gq = uq = access = mask = 0;
785 if (flags & PRACCESS) {
786 access = (flags >> PRIVATE_SHIFT);
787 mask |= PR_SF_ALLBITS;
789 if (flags & PRQUOTA) {
790 gq = ntohl(e.ngroups);
791 uq = ntohl(e.nusers);
792 mask |= PR_SF_NGROUPS | PR_SF_NUSERS;
795 fprintf (rc, "sf %d %x %x %d %d\n",
796 id, mask, access, gq, uq);
799 map[ei] |= MAP_RECREATE;
800 if (id != ANONYMOUSID) idmap[id-misc->minId]++;
803 /* bump low water mark if possible */
804 if (ei == createLow) createLow++;
810 /* Now create the entries with circular owner dependencies and make them
811 * own themselves. This is the only way to create them with the correct
813 for (ei=0; ei<misc->nEntries; ei++)
814 if (((map[ei] & MAP_HASHES) == MAP_HASHES) &&
815 (map[ei] & MAP_RECREATE) == 0) {
816 ea = ei * sizeof(struct prentry) + sizeof(cheader);
817 code = pr_Read (ea, (char *)&e, sizeof(e));
818 if (code) return code;
821 name = QuoteName(e.name);
822 fprintf (stderr, "Warning: group %s in self owning cycle\n", name);
823 if (rc) fprintf (rc, "cr %s %d %d\n", name, id, id);
824 idmap[id-misc->minId]++;
826 for (ei=0; ei<misc->nEntries; ei++)
827 if (((map[ei] & MAP_HASHES) == MAP_HASHES) &&
828 (map[ei] & MAP_RECREATE) == 0) {
829 ea = ei * sizeof(struct prentry) + sizeof(cheader);
830 code = pr_Read (ea, (char *)&e, sizeof(e));
831 if (code) return code;
833 owner = ntohl(e.owner);
834 if (idmap[owner-misc->minId] == 0) {
836 "Skipping chown of '%s' to non-existant owner %di\n",
839 else if (rc) fprintf (rc, "ce %d \"\" %d 0\n",
840 ntohl(e.id), e.owner);
843 if (rc == 0) return 0;
845 /* Reconstruct membership information based on the groups' user lists. */
846 for (ei=0; ei<misc->nEntries; ei++) {
847 if ((map[ei] & MAP_HASHES) == MAP_HASHES) {
848 ea = ei * sizeof(struct prentry) + sizeof(cheader);
849 code = pr_Read (ea, (char *)&e, sizeof(e));
850 if (code) return code;
853 flags = ntohl(e.flags);
855 if ((id < 0) && (flags & PRGRP)) {
859 for (i=0; i<PRSIZE; i++) {
860 afs_int32 uid = ntohl(e.entries[i]);
862 if (uid == PRBADID) continue;
864 fprintf (rc, "au %d %d\n", uid, id);
866 } else fprintf (stderr,
867 "Skipping %di in group %di\n", uid, id);
872 code = pr_Read (na, (char *)&c, sizeof(c));
873 if (code) return code;
875 if ((id == ntohl(c.id)) && (ntohl(c.flags) & PRCONT)) {
876 for (i=0; i<COSIZE; i++) {
877 afs_int32 uid = ntohl(c.entries[i]);
879 if (uid == PRBADID) continue;
881 fprintf (rc, "au %d %d\n", uid, id);
883 } else fprintf (stderr,
884 "Skipping %di in group %di\n",
889 "Skipping continuation block at %d\n", na);
894 if (count != ntohl(e.count))
895 fprintf (stderr, "Group membership count problem found %d should be %d\n", count, ntohl(e.count));
896 } else if ((id < 0) || (flags & PRGRP)) {
897 fprintf (stderr, "Skipping group %di\n", id);
904 afs_int32 CheckPrDatabase (misc)
905 struct misc_data *misc; /* info & statistics */
910 char *map; /* map of each entry in db */
912 eof = ntohl (cheader.eofPtr);
913 eof -= sizeof(cheader);
914 n = eof / sizeof(struct prentry);
915 if ((eof < 0) || (n*sizeof(struct prentry) != eof)) {
917 com_err (whoami, code,
918 "eof ptr no good: eof=%d, sizeof(prentry)=%d",
919 eof, sizeof(struct prentry));
924 printf ("Database has %d entries\n", n);
925 map = (char *)malloc (n);
930 printf ("\nChecking name hash table\n");
933 code = WalkHashTable (cheader.nameHash, MAP_NAMEHASH, map, misc);
935 com_err (whoami, code, "walking name hash");
939 printf ("\nChecking id hash table\n");
942 code = WalkHashTable (cheader.idHash, MAP_IDHASH, map, misc);
944 com_err (whoami, code, "walking id hash");
948 /* hash walk calculates min and max id */
949 n = ((misc->maxId > misc->maxForId) ? misc->maxId : misc->maxForId);
950 misc->idRange = n - misc->minId + 1;
951 misc->idmap = (afs_int32 *)malloc (misc->idRange * sizeof(afs_int32));
953 com_err (whoami, 0, "Unable to malloc space for max ids of %d",
958 bzero (misc->idmap, misc->idRange*sizeof(misc->idmap[0]));
961 printf ("\nChecking entry chains\n");
964 code = WalkChains (map, misc);
966 com_err (whoami, code, "walking chains");
970 printf ("\nChecking free list\n");
973 code = WalkNextChain (map, misc, 0, 0);
975 com_err (whoami, code, "walking free list");
979 printf ("\nChecking orphans list\n");
982 code = WalkOwnedChain (map, misc, 0, 0);
984 com_err (whoami, code, "walking orphan list");
989 printf ("\nChecking for unreferenced entries\n");
992 code = GC (map, misc);
994 com_err (whoami, code, "looking for unreferenced entries");
998 DumpRecreate (map, misc); /* check for owner cycles */
999 if (misc->recreate) fclose (misc->recreate);
1001 if (misc->anon != 2) /* once for each hash table */
1002 fprintf (stderr, "Problems with ANON=%d\n", misc->anon);
1003 if (misc->ncells || misc->ninsts)
1004 fprintf (stderr, "Unexpected entry type\n");
1005 if (misc->nusers != ntohl(cheader.usercount)) {
1007 "User count inconsistent: should be %d, header claims: %d\n",
1008 misc->nusers, ntohl(cheader.usercount));
1010 if (misc->ngroups != ntohl(cheader.groupcount)) {
1012 "Group count inconsistent: should be %d, header claims: %d\n",
1013 misc->ngroups, ntohl(cheader.groupcount));
1015 if (misc->maxId > ntohl(cheader.maxID))
1016 fprintf (stderr, "Database's max user Id (%d) is smaller than largest user's Id (%d).\n", ntohl(cheader.maxID), misc->maxId);
1017 if (misc->minId < ntohl(cheader.maxGroup))
1018 fprintf (stderr, "Database's max group Id (%d) is smaller than largest group's Id (%d).\n", ntohl(cheader.maxGroup), misc->minId);
1020 if (misc->verbose) {
1021 printf ("\nMaxId = %d, MinId = %d, MaxForeignId = %d\n",
1022 misc->maxId, misc->minId, misc->maxForId);
1023 printf ("Free list is %d entries in length, %d groups on orphan list\n",
1024 misc->freeLength, misc->orphanLength);
1025 printf ("The longest owner list is %d, the longest continuation block chain is %d\n",
1026 misc->maxOwnerLength, misc->maxContLength);
1027 printf ("%d users ; %d foreign users ; and %d groups\n",
1028 misc->nusers, misc->nforeigns, misc->ngroups);
1034 #include "AFS_component_version_number.c"
1036 WorkerBee (as, arock)
1037 struct cmd_syndesc *as;
1042 struct misc_data misc; /* info & statistics */
1047 initialize_pt_error_table();
1048 initialize_u_error_table();
1050 pr_dbaseName = AFSDIR_SERVER_PRDB_FILEPATH;
1051 bzero (&misc, sizeof(misc));
1053 pr_dbaseName = as->parms[0].items->data; /* -database */
1054 misc.listuheader = (as->parms[1].items ? 1 : 0); /* -uheader */
1055 misc.listpheader = (as->parms[2].items ? 1 : 0); /* -pheader */
1056 misc.listentries = (as->parms[3].items ? 1 : 0); /* -entries */
1057 misc.verbose = (as->parms[4].items ? 1 : 0); /* -verbose */
1058 recreateFile = (as->parms[5].items ? as->parms[5].items->data :
1059 (char *)0); /* -rebuild */
1061 fd = open (pr_dbaseName, O_RDONLY, 0);
1063 com_err (whoami, errno, "Open failed on db %s", pr_dbaseName);
1067 /* Read the ubik header */
1068 if (misc.listuheader) {
1069 readUbikHeader(&misc);
1072 code = ReadHeader();
1073 if (code) return code;
1074 if (misc.listpheader) printheader(&cheader);
1077 misc.recreate = fopen (recreateFile, "w");
1078 if (misc.recreate == 0) {
1079 com_err (whoami, errno,
1080 "can't create file for recreation instructions: %s",
1085 code = CheckPrDatabase (&misc);
1087 com_err (whoami, code, "Checking prserver database");
1097 struct cmd_syndesc *ts;
1098 struct cmd_item *ti;
1102 ts=cmd_CreateSyntax((char *)0, WorkerBee, (char *)0, "PRDB check");
1103 cmd_AddParm(ts, "-database", CMD_SINGLE, CMD_REQUIRED, "ptdb_file");
1104 cmd_AddParm(ts, "-uheader", CMD_FLAG, CMD_OPTIONAL, "Display UBIK header");
1105 cmd_AddParm(ts, "-pheader", CMD_FLAG, CMD_OPTIONAL, "Display KADB header");
1106 cmd_AddParm(ts, "-entries", CMD_FLAG, CMD_OPTIONAL, "Display entries");
1107 cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, "verbose");
1108 cmd_AddParm(ts, "-rebuild", CMD_SINGLE, CMD_OPTIONAL|CMD_HIDE, "out_file");
1110 return cmd_Dispatch(argc, argv);