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
10 #include <afsconfig.h>
11 #include <afs/param.h>
17 * (3) Define a structure, idused, instead of an
18 * array of long integers, idmap, to count group
19 * memberships. These structures are on a linked
20 * list, with each structure containing IDCOUNT
22 * (4) Add new functions to processs the structure
24 * zeromap(), idcount(), inccount().
25 * (5) Add code, primarily in WalkNextChain():
26 * 1. Test id's, allowing groups within groups.
27 * 2. Count the membership list for supergroups,
28 * and follow the continuation chain for
30 * (6) Add fprintf statements for various error
36 #include <WINNT/afsevent.h>
41 #include <afs/cellconfig.h>
42 #include <afs/afsutil.h>
45 #include <afs/com_err.h>
53 struct prheader cheader;
55 const char *pr_dbaseName;
56 char *whoami = "db_verify";
57 #define UBIK_HEADERSIZE 64
60 printheader(struct prheader *h)
62 printf("Version = %d\n", ntohl(h->version));
63 printf("Header Size = %d\n", ntohl(h->headerSize));
64 printf("Free Ptr = 0x%x\n", ntohl(h->freePtr));
65 printf("EOF Ptr = 0x%x\n", ntohl(h->eofPtr));
66 printf("Max Group ID = %d\n", ntohl(h->maxGroup));
67 printf("Max User ID = %d\n", ntohl(h->maxID));
68 printf("Max Foreign ID = %d\n", ntohl(h->maxForeign));
69 /* printf("Max Sub/Super ID = %d\n", ntohl(h->maxInst)); */
70 printf("Orphaned groups = %d\n", ntohl(h->orphan));
71 printf("User Count = %d\n", ntohl(h->usercount));
72 printf("Group Count = %d\n", ntohl(h->groupcount));
73 /* printf("Foreign Count = %d\n", ntohl(h->foreigncount)); NYI */
74 /* printf("Sub/super Count = %d\n", ntohl(h->instcount)); NYI */
75 printf("Name Hash = %d buckets\n", HASHSIZE);
76 printf("ID Hash = %d buckets\n", HASHSIZE);
81 pr_Read(afs_int32 pos, void *buff, afs_int32 len)
85 code = lseek(fd, UBIK_HEADERSIZE + pos, 0);
89 code = read(fd, buff, len);
99 * Initializes the a transaction on the database and reads the header into
100 * the static variable cheader. If successful it returns a read-locked
101 * transaction. If ubik reports that cached database info should be up to date
102 * the cheader structure is not re-read from the ubik.
110 code = pr_Read(0, (char *)&cheader, sizeof(cheader));
112 afs_com_err(whoami, code, "couldn't read header");
115 /* Check and see if database exists and is approximately OK. */
116 if (ntohl(cheader.headerSize) != sizeof(cheader)
117 || ntohl(cheader.eofPtr) == 0) {
120 afs_com_err(whoami, PRDBBAD, "header is bad");
129 /* returns hash bucket for x */
130 return ((abs(x)) % HASHSIZE);
134 NameHash(char *aname)
136 /* returns hash bucket for aname */
137 unsigned int hash = 0;
139 /* stolen directly from the HashString function in the vol package */
140 for (i = strlen(aname), aname += i - 1; i--; aname--)
141 hash = (hash * 31) + (*(unsigned char *)aname - 31);
142 return (hash % HASHSIZE);
145 #define MAP_NAMEHASH 1
147 #define MAP_HASHES (MAP_NAMEHASH | MAP_IDHASH)
150 #define MAP_OWNED 0x10
151 #define MAP_RECREATE 0x20
154 int nEntries; /* number of database entries */
155 int anon; /* found anonymous Id */
156 afs_int32 maxId; /* user */
157 afs_int32 minId; /* group */
158 afs_int32 maxForId; /* foreign user id */
159 #if defined(SUPERGROUPS)
163 afs_int32 idcount[IDCOUNT];
164 struct idused *idnext;
167 int idRange; /* number of ids in map */
168 afs_int32 *idmap; /* map of all id's: midId is origin */
169 #endif /* SUPERGROUPS */
170 int nusers; /* counts of each type */
175 int maxOwnerLength; /* longest owner chain */
176 int maxContLength; /* longest chain of cont. blks */
177 int orphanLength; /* length of orphan list */
178 int freeLength; /* length of free list */
183 FILE *recreate; /* stream for recreate instructions */
186 #if defined(SUPERGROUPS)
187 void zeromap(struct idused *idmap);
188 void inccount(struct idused **idmapp, int id);
189 int idcount(struct idused **idmapp, int id);
193 readUbikHeader(struct misc_data *misc)
196 struct ubik_hdr uheader;
198 offset = lseek(fd, 0, 0);
200 printf("error: lseek to 0 failed: %d %d\n", offset, errno);
204 /* now read the info */
205 r = read(fd, &uheader, sizeof(uheader));
206 if (r != sizeof(uheader)) {
207 printf("error: read of %" AFS_SIZET_FMT " bytes failed: %d %d\n",
208 sizeof(uheader), r, errno);
212 uheader.magic = ntohl(uheader.magic);
213 uheader.size = ntohs(uheader.size);
214 uheader.version.epoch = ntohl(uheader.version.epoch);
215 uheader.version.counter = ntohl(uheader.version.counter);
217 if (misc->listuheader) {
218 printf("Ubik Header\n");
219 printf(" Magic = 0x%x\n", uheader.magic);
220 printf(" Size = %u\n", uheader.size);
221 printf(" Version.epoch = %u\n", uheader.version.epoch);
222 printf(" Version.counter = %u\n", uheader.version.counter);
225 if (uheader.size != UBIK_HEADERSIZE)
226 printf("Ubik header size is %u (should be %u)\n", uheader.size,
228 if (uheader.magic != UBIK_MAGIC)
229 printf("Ubik header magic is 0x%x (should be 0x%x)\n", uheader.magic,
236 ConvertDiskAddress(afs_uint32 ea, int *eiP)
242 if (ea < sizeof(cheader))
244 if (ea >= ntohl(cheader.eofPtr))
246 ea -= sizeof(cheader);
247 i = ea / sizeof(struct prentry);
248 if (i * sizeof(struct prentry) != ea)
250 /* if ((i < 0) || (i >= misc->nEntries)) return PRDBADDR; */
256 PrintEntryError(struct misc_data *misc, afs_int32 ea, struct prentry *e, int indent)
259 pr_PrintEntry(stderr, /*net order */ 0, ea, e, indent);
264 WalkHashTable(afs_int32 hashtable[], /* hash table to walk */
265 int hashType, /* hash function to use */
266 char map[], /* one byte per db entry */
267 struct misc_data *misc) /* stuff to keep track of */
270 int hi; /* index in hash table */
271 afs_int32 ea; /* entry's db addr */
272 int ei; /* entry's index */
273 char bit; /* bits to check for in map */
282 for (hi = 0; hi < HASHSIZE; hi++) {
284 next_ea = ntohl(hashtable[hi]);
286 code = ConvertDiskAddress(next_ea, &ei);
288 fprintf(stderr, "Bad chain address %d\n", next_ea);
290 fprintf(stderr, "Last entry in chain:\n");
291 if (PrintEntryError(misc, ea, &e, 2))
294 fprintf(stderr, "Skipping remainder of hash bucket %d\n", hi);
298 code = pr_Read(ea, (char *)&e, sizeof(e));
304 if (((e.flags & htonl((PRGRP | PRINST))) == 0)
305 && (strchr(e.name, '@'))) {
307 if (id > misc->maxForId)
310 if (id == ANONYMOUSID)
312 else if (id > misc->maxId)
314 if (id < misc->minId)
320 next_ea = ntohl(e.nextName);
321 hash = NameHash(e.name);
324 next_ea = ntohl(e.nextID);
328 fprintf(stderr, "unknown hash table type %d\n", hashType);
334 "Entry found twice in hash table: bucket %d\n", hi);
336 fprintf(stderr, "also in wrong bucket: should be in %d\n",
338 if (PrintEntryError(misc, ea, &e, 2))
344 flags = ntohl(e.flags);
345 switch (flags & PRTYPE) {
347 fprintf(stderr, "ENTRY IS FREE");
350 fprintf(stderr, "ENTRY IS CONTINUATION");
358 fprintf(stderr, "ENTRY IS unexpected type (flags=0x%x)\n",
362 fprintf(stderr, "ENTRY IS OF unknown type (flags=0x%x)\n",
368 fprintf(stderr, "entry hashed in bucket %d should be %d\n",
371 if (PrintEntryError(misc, ea, &e, 2))
381 WalkNextChain(char map[], /* one byte per db entry */
382 struct misc_data *misc, /* stuff to keep track of */
383 afs_int32 ea, struct prentry *e)
388 struct prentry c; /* continuation entry */
389 afs_int32 na; /* next thread */
392 int count = 0; /* number of members, set to > 9999 if */
393 /* list ends early */
396 int length; /* length of chain */
397 #if defined(SUPERGROUPS)
398 int sgcount = 0; /* number of sgentrys */
400 #define g (((struct prentryg *)e))
404 head = ntohl(e->next);
407 #if defined(SUPERGROUPS)
408 sghead = ntohl(g->next);
410 for (i = 0; i < PRSIZE; i++) {
411 afs_int32 id = ntohl(e->entries[i]);
417 /* in case the ids are large, convert to pure sign. */
426 #if defined(SUPERGROUPS)
427 if (id_s > 0 && eid_s > 0) {
429 "User can't be member of user in membership list\n");
430 if (PrintEntryError(misc, ea, e, 2))
435 if (id_s * eid_s > 0) { /* sign should be different */
437 "Bad user/group dicotomy in membership list\n");
438 if (PrintEntryError(misc, ea, e, 2))
442 #endif /* SUPERGROUPS */
443 /* count each user as a group, and each group a user is in */
444 #if defined(SUPERGROUPS)
445 if (!(id < 0 && eid < 0) && (id != ANONYMOUSID))
446 inccount(&misc->idmap, id);
448 if ((id >= misc->minId) && (id <= misc->maxId)
449 && (id != ANONYMOUSID))
450 misc->idmap[id - misc->minId]++;
451 #endif /* SUPERGROUPS */
457 #if defined(SUPERGROUPS)
458 sghead = ntohl(g->nextsg);
459 if ((e->flags & htonl(PRGRP))) {
460 for (i = 0; i < SGSIZE; ++i) {
461 afs_int32 id = ntohl(g->supergroup[i]);
467 "User can't be member of supergroup list\n");
468 if (PrintEntryError(misc, ea, e, 2))
473 inccount(&misc->idmap, id);
477 #endif /* SUPERGROUPS */
479 head = ntohl(cheader.freePtr);
480 #if defined(SUPERGROUPS)
486 #if defined(SUPERGROUPS)
488 for (na = sghead; na; na = ntohl(c.next)) {
489 code = ConvertDiskAddress(na, &ni);
491 fprintf(stderr, "Bad SGcontinuation ptr %d", na);
492 if (PrintEntryError(misc, ea, e, 2))
495 fprintf(stderr, "last block: \n");
496 if (PrintEntryError(misc, na, &c, 4))
501 code = pr_Read(na, (char *)&c, sizeof(c));
507 fprintf(stderr, "Continuation entry reused\n");
508 if (PrintEntryError(misc, ea, e, 2))
510 if (PrintEntryError(misc, na, &c, 4))
516 if ((ntohl(c.id) != eid)) {
517 fprintf(stderr, "Continuation id mismatch\n");
518 if (PrintEntryError(misc, ea, e, 2))
520 if (PrintEntryError(misc, na, &c, 4))
526 /* update membership count */
527 for (i = 0; i < COSIZE; i++) {
528 afs_int32 id = ntohl(c.entries[i]);
534 /* in case the ids are large, convert to pure sign. */
545 "User can't be member of supergroup list\n");
546 if (PrintEntryError(misc, ea, e, 2))
548 if (PrintEntryError(misc, na, &c, 4))
552 /* count each user as a group, and each group a user is in */
553 if ((id != ANONYMOUSID))
554 inccount(&misc->idmap, id);
561 if (length > misc->maxContLength)
562 misc->maxContLength = length;
563 #endif /* SUPERGROUPS */
565 for (na = head; na; na = ntohl(c.next)) {
566 code = ConvertDiskAddress(na, &ni);
568 fprintf(stderr, "Bad continuation ptr %d", na);
570 fprintf(stderr, "walking free list");
571 else if (PrintEntryError(misc, ea, e, 2))
574 fprintf(stderr, "last block: \n");
575 if (PrintEntryError(misc, na, &c, 4))
580 code = pr_Read(na, (char *)&c, sizeof(c));
586 fprintf(stderr, "Continuation entry reused\n");
588 fprintf(stderr, "walking free list");
589 else if (PrintEntryError(misc, ea, e, 2))
591 if (PrintEntryError(misc, na, &c, 4))
597 if (e && (ntohl(c.id) != eid)) {
598 fprintf(stderr, "Continuation id mismatch\n");
600 fprintf(stderr, "walking free list");
601 else if (PrintEntryError(misc, ea, e, 2))
603 if (PrintEntryError(misc, na, &c, 4))
609 /* update membership count */
611 for (i = 0; i < COSIZE; i++) {
612 afs_int32 id = ntohl(c.entries[i]);
618 /* in case the ids are large, convert to pure sign. */
627 #if defined(SUPERGROUPS)
628 if (id_s > 0 && eid_s > 0) {
630 "User can't be member of user in membership list\n");
631 if (PrintEntryError(misc, ea, e, 2))
633 if (PrintEntryError(misc, na, &c, 4))
638 if (id_s * eid_s > 0) { /* sign should be different */
640 "Bad user/group dicotomy in membership list\n");
641 if (PrintEntryError(misc, ea, e, 2))
643 if (PrintEntryError(misc, na, &c, 4))
647 #endif /* SUPERGROUPS */
648 /* count each user as a group, and each group a user is in */
649 #if defined(SUPERGROUPS)
650 if (!(id < 0 && eid < 0) && (id != ANONYMOUSID))
651 inccount(&misc->idmap, id);
653 if ((id >= misc->minId) && (id <= misc->maxId)
654 && (id != ANONYMOUSID))
655 misc->idmap[id - misc->minId]++;
656 #endif /* SUPERGROUPS */
663 if (e && noErrors && (count != ntohl(e->count))) {
664 #if defined(SUPERGROUPS)
666 fprintf(stderr, "Membership list ends early\n");
669 fprintf(stderr, "Membership list ends early\n");
670 #endif /* SUPERGROUPS */
671 fprintf(stderr, "Count was %d should be %d\n", count,
673 if (PrintEntryError(misc, ea, e, 2))
675 #if defined(SUPERGROUPS)
678 if (e && (e->flags & htonl(PRGRP)) && (sgcount != ntohl(g->countsg))) {
679 fprintf(stderr, "SGCount was %d should be %d\n", sgcount,
681 if (PrintEntryError(misc, ea, e, 2))
687 if (length > misc->maxContLength)
688 misc->maxContLength = length;
690 misc->freeLength = length;
693 #if defined(SUPERGROUPS)
699 WalkOwnedChain(char map[], /* one byte per db entry */
700 struct misc_data *misc, /* stuff to keep track of */
701 afs_int32 ea, struct prentry *e)
705 struct prentry c; /* continuation entry */
706 afs_int32 na; /* next thread */
709 int length; /* length of chain */
712 head = ntohl(e->owned);
715 head = ntohl(cheader.orphan);
718 for (na = head; na; na = ntohl(c.nextOwned)) {
719 code = ConvertDiskAddress(na, &ni);
721 fprintf(stderr, "Bad owned list ptr %d", na);
723 fprintf(stderr, "walking orphan list");
724 else if (PrintEntryError(misc, ea, e, 2))
727 fprintf(stderr, "last block: \n");
728 if (PrintEntryError(misc, na, &c, 4))
733 code = pr_Read(na, (char *)&c, sizeof(c));
738 if (map[ni] & MAP_OWNED) {
739 fprintf(stderr, "Entry on multiple owner chains\n");
741 fprintf(stderr, "walking orphan list");
742 else if (PrintEntryError(misc, ea, e, 2))
744 if (PrintEntryError(misc, na, &c, 4))
748 map[ni] |= MAP_OWNED;
749 if ((map[ni] & MAP_HASHES) != MAP_HASHES) {
750 fprintf(stderr, "Owned entry not hashed properly\n");
753 fprintf(stderr, "walking orphan list");
754 else if (PrintEntryError(misc, ea, e, 2))
756 if (PrintEntryError(misc, na, &c, 4))
761 if (ntohl(c.owner) != eid) {
762 fprintf(stderr, "Owner id mismatch\n");
765 } else /* orphan */ if (c.owner) {
766 fprintf(stderr, "Orphan group owner not zero\n");
772 if (length > misc->maxOwnerLength)
773 misc->maxOwnerLength = length;
775 misc->orphanLength = length;
781 WalkChains(char map[], /* one byte per db entry */
782 struct misc_data *misc) /* stuff to keep track of */
786 afs_int32 ea; /* entry's db addr */
791 /* check all entries found in hash table walks */
792 for (ei = 0; ei < misc->nEntries; ei++)
793 if (map[ei] & MAP_HASHES) {
794 ea = ei * sizeof(struct prentry) + sizeof(cheader);
795 code = pr_Read(ea, (char *)&e, sizeof(e));
799 if ((map[ei] & MAP_HASHES) != MAP_HASHES) {
800 fprintf(stderr, "entry not in both hashtables\n");
801 if ((map[ei] & MAP_NAMEHASH) != MAP_NAMEHASH)
802 fprintf(stderr, "--> entry not in Name hashtable\n");
803 if ((map[ei] & MAP_IDHASH) != MAP_IDHASH)
804 fprintf(stderr, "--> entry not in ID hashtable\n");
807 if (PrintEntryError(misc, ea, &e, 2))
814 type = ntohl(e.flags) & PRTYPE;
818 fprintf(stderr, "Group id not negative\n");
821 /* special case sysadmin: it owns itself */
822 if (id == SYSADMINID) {
823 if (ntohl(e.owner) != SYSADMINID) {
825 "System:administrators doesn't own itself\n");
829 code = WalkOwnedChain(map, misc, ea, &e);
832 code = WalkNextChain(map, misc, ea, &e);
839 #if defined(SUPERGROUPS)
840 fprintf(stderr, "User id not positive\n");
842 fprintf(stderr, "User id negative\n");
847 /* Users are owned by sysadmin, but sysadmin doesn't have an owner
848 * chain. Check this then set the owned bit. */
849 if (ntohl(e.owner) != SYSADMINID) {
851 "User not owned by system:administrators\n");
855 fprintf(stderr, "User has owned pointer\n");
858 map[ei] |= MAP_OWNED;
860 code = WalkOwnedChain(map, misc, ea, &e);
863 code = WalkNextChain(map, misc, ea, &e);
866 if (strchr(e.name, '@') == 0) {
867 misc->nusers++; /* Not a foreign user */
869 misc->nforeigns++; /* A foreign user */
879 "ENTRY IS unexpected type [PRFOREIGN] (flags=0x%x)\n",
886 fprintf(stderr, "entry with unexpected type");
895 GC(char map[], struct misc_data *misc)
903 for (ei = 0; ei < misc->nEntries; ei++) {
904 ea = ei * sizeof(struct prentry) + sizeof(cheader);
905 code = pr_Read(ea, (char *)&e, sizeof(e));
910 fprintf(stderr, "Unreferenced entry:");
911 if (PrintEntryError(misc, ea, &e, 2))
914 /* all users and groups should be owned, and their membership counts
916 else if ((m & MAP_HASHES) == MAP_HASHES) {
919 if (!(m & MAP_OWNED)) {
920 fprintf(stderr, "Entry not on any owner chain:\n");
921 if (PrintEntryError(misc, ea, &e, 2))
925 #if defined(SUPERGROUPS)
926 if ((id != ANONYMOUSID)
927 && ((refCount = idcount(&misc->idmap, id)) != ntohl(e.count)))
929 if ((id >= misc->minId) && (id <= misc->maxId)
930 && (id != ANONYMOUSID)
931 && ((refCount = misc->idmap[id - misc->minId]) !=
933 #endif /* SUPERGROUPS */
937 "Entry membership count is inconsistent: %d entries refer to this one\n",
939 if (PrintEntryError(misc, ea, &e, 2))
942 /* get continuation blocks too */
943 for (na = ntohl(e.next); na; na = ntohl(e.next)) {
945 code = ConvertDiskAddress(na, &ni);
948 code = pr_Read(na, (char *)&e, sizeof(e));
951 if (PrintEntryError(misc, na, &e, 4))
964 if (strpbrk(s, " \t")) {
965 asprintf(&qs, "\"%s\"", s);
972 DumpRecreate(char map[], struct misc_data *misc)
982 int builtinUsers = 0;
983 int createLow = 0; /* users uncreate from here */
984 #if defined(SUPERGROUPS)
985 struct idused *idmap; /* map of all id's */
987 afs_int32 *idmap; /* map of all id's */
994 #if defined(SUPERGROUPS)
997 memset(idmap, 0, misc->idRange * sizeof(misc->idmap[0]));
1001 for (ei = createLow; ei < misc->nEntries; ei++) {
1002 if ((map[ei] & MAP_HASHES) && (map[ei] & MAP_RECREATE) == 0) {
1007 ea = ei * sizeof(struct prentry) + sizeof(cheader);
1008 code = pr_Read(ea, (char *)&e, sizeof(e));
1012 if (misc->listentries)
1013 pr_PrintEntry(stdout, 0 /*not in host order */ , ea, &e,
1017 flags = ntohl(e.flags);
1018 owner = ntohl(e.owner);
1019 name = QuoteName(e.name);
1021 if (!strcmp(e.name, "system:administrators")
1022 || !strcmp(e.name, "system:anyuser")
1023 || !strcmp(e.name, "system:authuser")
1024 || !strcmp(e.name, "system:backup")
1025 || !strcmp(e.name, "anonymous")) {
1030 /* check for duplicate id. This may still lead to duplicate
1032 #if defined(SUPERGROUPS)
1033 if (idcount(&idmap, id))
1035 if (idmap[id - misc->minId])
1038 fprintf(stderr, "Skipping entry with duplicate id %di\n",
1043 /* If owner doesn't exist skip for now, unless we're our own
1044 * owner. If so, a special case allows a group to own itself
1045 * if caller is sysadmin. This leaves only owner cycles to
1048 if ((owner < misc->minId) || (owner > misc->maxId)) {
1049 if (owner == ANONYMOUSID)
1051 "Warning: id %di is owned by ANONYMOUS; using sysadmin instead\n",
1055 "Bogus owner (%d) of id %di; using sysadmin instead\n",
1060 fprintf(stderr, "Warning: group %s is self owning\n",
1062 } else if (owner == 0) {
1064 "Warning: orphan group %s will become self owning.\n",
1068 #if defined(SUPERGROUPS)
1069 else if (!idcount(&idmap, owner))
1072 else if (idmap[owner - misc->minId] == 0)
1077 fprintf(rc, "cr %s %d %d\n", name, id, owner);
1079 gq = uq = access = mask = 0;
1080 if (flags & PRACCESS) {
1081 access = (flags >> PRIVATE_SHIFT);
1082 mask |= PR_SF_ALLBITS;
1084 if (flags & PRQUOTA) {
1085 gq = ntohl(e.ngroups);
1086 uq = ntohl(e.nusers);
1087 mask |= PR_SF_NGROUPS | PR_SF_NUSERS;
1090 fprintf(rc, "sf %d %x %x %d %d\n", id, mask, access, gq,
1094 map[ei] |= MAP_RECREATE;
1095 #if defined(SUPERGROUPS)
1096 if (id != ANONYMOUSID)
1097 inccount(&idmap, id);
1099 if (id != ANONYMOUSID)
1100 idmap[id - misc->minId]++;
1104 /* bump low water mark if possible */
1105 if (ei == createLow)
1112 /* Now create the entries with circular owner dependencies and make them
1113 * own themselves. This is the only way to create them with the correct
1115 for (ei = 0; ei < misc->nEntries; ei++)
1116 if (((map[ei] & MAP_HASHES) == MAP_HASHES)
1117 && (map[ei] & MAP_RECREATE) == 0) {
1118 ea = ei * sizeof(struct prentry) + sizeof(cheader);
1119 code = pr_Read(ea, (char *)&e, sizeof(e));
1124 name = QuoteName(e.name);
1125 fprintf(stderr, "Warning: group %s in self owning cycle\n", name);
1127 fprintf(rc, "cr %s %d %d\n", name, id, id);
1128 #if defined(SUPERGROUPS)
1129 inccount(&idmap, id);
1131 idmap[id - misc->minId]++;
1134 for (ei = 0; ei < misc->nEntries; ei++)
1135 if (((map[ei] & MAP_HASHES) == MAP_HASHES)
1136 && (map[ei] & MAP_RECREATE) == 0) {
1137 ea = ei * sizeof(struct prentry) + sizeof(cheader);
1138 code = pr_Read(ea, (char *)&e, sizeof(e));
1142 owner = ntohl(e.owner);
1143 #if defined(SUPERGROUPS)
1144 if (!idcount(&idmap, owner))
1146 if (idmap[owner - misc->minId] == 0)
1150 "Skipping chown of '%s' to non-existant owner %di\n",
1153 fprintf(rc, "ce %d \"\" %d 0\n", ntohl(e.id), e.owner);
1159 /* Reconstruct membership information based on the groups' user lists. */
1160 for (ei = 0; ei < misc->nEntries; ei++) {
1161 if ((map[ei] & MAP_HASHES) == MAP_HASHES) {
1162 ea = ei * sizeof(struct prentry) + sizeof(cheader);
1163 code = pr_Read(ea, (char *)&e, sizeof(e));
1168 flags = ntohl(e.flags);
1170 if ((id < 0) && (flags & PRGRP)) {
1174 for (i = 0; i < PRSIZE; i++) {
1175 afs_int32 uid = ntohl(e.entries[i]);
1180 #if !defined(SUPERGROUPS)
1183 fprintf(rc, "au %d %d\n", uid, id);
1185 #if !defined(SUPERGROUPS)
1187 fprintf(stderr, "Skipping %di in group %di\n", uid,
1194 code = pr_Read(na, (char *)&c, sizeof(c));
1198 if ((id == ntohl(c.id)) && (c.flags & htonl(PRCONT))) {
1199 for (i = 0; i < COSIZE; i++) {
1200 afs_int32 uid = ntohl(c.entries[i]);
1205 #if !defined(SUPERGROUPS)
1208 fprintf(rc, "au %d %d\n", uid, id);
1210 #if !defined(SUPERGROUPS)
1212 fprintf(stderr, "Skipping %di in group %di\n",
1217 fprintf(stderr, "Skipping continuation block at %d\n",
1223 if (count != ntohl(e.count))
1225 "Group membership count problem found %d should be %d\n",
1226 count, ntohl(e.count));
1227 } else if ((id < 0) || (flags & PRGRP)) {
1228 fprintf(stderr, "Skipping group %di\n", id);
1236 CheckPrDatabase(struct misc_data *misc) /* info & statistics */
1241 char *map; /* map of each entry in db */
1243 eof = ntohl(cheader.eofPtr);
1244 eof -= sizeof(cheader);
1245 n = eof / sizeof(struct prentry);
1246 if ((eof < 0) || (n * sizeof(struct prentry) != eof)) {
1248 afs_com_err(whoami, code,
1249 "eof ptr no good: eof=%d, sizeof(prentry)=%" AFS_SIZET_FMT,
1250 eof, sizeof(struct prentry));
1255 printf("Database has %d entries\n", n);
1256 map = (char *)malloc(n);
1260 if (misc->verbose) {
1261 printf("\nChecking name hash table\n");
1264 code = WalkHashTable(cheader.nameHash, MAP_NAMEHASH, map, misc);
1266 afs_com_err(whoami, code, "walking name hash");
1269 if (misc->verbose) {
1270 printf("\nChecking id hash table\n");
1273 code = WalkHashTable(cheader.idHash, MAP_IDHASH, map, misc);
1275 afs_com_err(whoami, code, "walking id hash");
1279 /* hash walk calculates min and max id */
1280 #if defined(SUPERGROUPS)
1283 n = ((misc->maxId > misc->maxForId) ? misc->maxId : misc->maxForId);
1284 misc->idRange = n - misc->minId + 1;
1285 misc->idmap = (afs_int32 *) malloc(misc->idRange * sizeof(afs_int32));
1287 afs_com_err(whoami, 0, "Unable to malloc space for max ids of %d",
1292 memset(misc->idmap, 0, misc->idRange * sizeof(misc->idmap[0]));
1293 #endif /* SUPERGROUPS */
1295 if (misc->verbose) {
1296 printf("\nChecking entry chains\n");
1299 code = WalkChains(map, misc);
1301 afs_com_err(whoami, code, "walking chains");
1304 if (misc->verbose) {
1305 printf("\nChecking free list\n");
1308 code = WalkNextChain(map, misc, 0, 0);
1310 afs_com_err(whoami, code, "walking free list");
1313 if (misc->verbose) {
1314 printf("\nChecking orphans list\n");
1317 code = WalkOwnedChain(map, misc, 0, 0);
1319 afs_com_err(whoami, code, "walking orphan list");
1323 if (misc->verbose) {
1324 printf("\nChecking for unreferenced entries\n");
1327 code = GC(map, misc);
1329 afs_com_err(whoami, code, "looking for unreferenced entries");
1333 DumpRecreate(map, misc); /* check for owner cycles */
1335 fclose(misc->recreate);
1337 if (misc->anon != 2) /* once for each hash table */
1338 fprintf(stderr, "Problems with ANON=%d\n", misc->anon);
1339 if (misc->ncells || misc->ninsts)
1340 fprintf(stderr, "Unexpected entry type\n");
1341 if (misc->nusers != ntohl(cheader.usercount)) {
1343 "User count inconsistent: should be %d, header claims: %d\n",
1344 misc->nusers, ntohl(cheader.usercount));
1346 if (misc->ngroups != ntohl(cheader.groupcount)) {
1348 "Group count inconsistent: should be %d, header claims: %d\n",
1349 misc->ngroups, ntohl(cheader.groupcount));
1351 if (misc->maxId > ntohl(cheader.maxID))
1353 "Database's max user Id (%d) is smaller than largest user's Id (%d).\n",
1354 ntohl(cheader.maxID), misc->maxId);
1355 if (misc->minId < ntohl(cheader.maxGroup))
1357 "Database's max group Id (%d) is smaller than largest group's Id (%d).\n",
1358 ntohl(cheader.maxGroup), misc->minId);
1360 if (misc->verbose) {
1361 printf("\nMaxId = %d, MinId = %d, MaxForeignId = %d\n", misc->maxId,
1362 misc->minId, misc->maxForId);
1364 ("Free list is %d entries in length, %d groups on orphan list\n",
1365 misc->freeLength, misc->orphanLength);
1367 ("The longest owner list is %d, the longest continuation block chain is %d\n",
1368 misc->maxOwnerLength, misc->maxContLength);
1369 printf("%d users ; %d foreign users ; and %d groups\n", misc->nusers,
1370 misc->nforeigns, misc->ngroups);
1377 #include "AFS_component_version_number.c"
1380 WorkerBee(struct cmd_syndesc *as, void *arock)
1384 struct misc_data misc; /* info & statistics */
1386 initialize_PT_error_table();
1387 initialize_U_error_table();
1389 pr_dbaseName = AFSDIR_SERVER_PRDB_FILEPATH;
1390 memset(&misc, 0, sizeof(misc));
1392 pr_dbaseName = as->parms[0].items->data; /* -database */
1393 misc.listuheader = (as->parms[1].items ? 1 : 0); /* -uheader */
1394 misc.listpheader = (as->parms[2].items ? 1 : 0); /* -pheader */
1395 misc.listentries = (as->parms[3].items ? 1 : 0); /* -entries */
1396 misc.verbose = (as->parms[4].items ? 1 : 0); /* -verbose */
1397 recreateFile = (as->parms[5].items ? as->parms[5].items->data : NULL); /* -rebuild */
1399 fd = open(pr_dbaseName, O_RDONLY, 0);
1401 afs_com_err(whoami, errno, "Open failed on db %s", pr_dbaseName);
1405 /* Read the ubik header */
1406 if (misc.listuheader) {
1407 readUbikHeader(&misc);
1410 code = ReadHeader();
1413 if (misc.listpheader)
1414 printheader(&cheader);
1417 misc.recreate = fopen(recreateFile, "w");
1418 if (misc.recreate == 0) {
1419 afs_com_err(whoami, errno,
1420 "can't create file for recreation instructions: %s",
1425 code = CheckPrDatabase(&misc);
1427 afs_com_err(whoami, code, "Checking prserver database");
1434 main(int argc, char *argv[])
1436 struct cmd_syndesc *ts;
1440 ts = cmd_CreateSyntax(NULL, WorkerBee, NULL, "PRDB check");
1441 cmd_AddParm(ts, "-database", CMD_SINGLE, CMD_REQUIRED, "ptdb_file");
1442 cmd_AddParm(ts, "-uheader", CMD_FLAG, CMD_OPTIONAL,
1443 "Display UBIK header");
1444 cmd_AddParm(ts, "-pheader", CMD_FLAG, CMD_OPTIONAL,
1445 "Display KADB header");
1446 cmd_AddParm(ts, "-entries", CMD_FLAG, CMD_OPTIONAL, "Display entries");
1447 cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, "verbose");
1448 cmd_AddParm(ts, "-rebuild", CMD_SINGLE, CMD_OPTIONAL | CMD_HIDE,
1451 return cmd_Dispatch(argc, argv);
1455 #if defined(SUPERGROUPS)
1457 /* new routines to deal with very large ID numbers */
1460 zeromap(struct idused *idmap)
1463 memset(idmap->idcount, 0, sizeof idmap->idcount);
1464 idmap = idmap->idnext;
1469 inccount(struct idused **idmapp, int id)
1471 struct idused *idmap;
1473 if (IDCOUNT & (IDCOUNT - 1)) {
1474 fprintf(stderr, "IDCOUNT must be power of 2!\n");
1477 while ((idmap = *idmapp) != NULL) {
1478 if (idmap->idstart == (id & ~(IDCOUNT - 1)))
1480 idmapp = &idmap->idnext;
1483 idmap = (struct idused *)malloc(sizeof *idmap);
1488 memset(idmap, 0, sizeof idmap);
1489 idmap->idstart = id & ~(IDCOUNT - 1);
1490 idmap->idnext = *idmapp;
1493 ++idmap->idcount[id & (IDCOUNT - 1)];
1497 idcount(struct idused **idmapp, int id)
1499 struct idused *idmap;
1501 if (IDCOUNT & (IDCOUNT - 1)) {
1502 fprintf(stderr, "IDCOUNT must be power of 2!\n");
1505 while ((idmap = *idmapp) != NULL) {
1506 if (idmap->idstart == (id & ~(IDCOUNT - 1))) {
1507 return idmap->idcount[id & (IDCOUNT - 1)];
1509 idmapp = &idmap->idnext;
1513 #endif /* SUPERGROUPS */