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. */
541 "User can't be member of supergroup list\n");
542 if (PrintEntryError(misc, ea, e, 2))
544 if (PrintEntryError(misc, na, &c, 4))
548 /* count each user as a group, and each group a user is in */
549 if ((id != ANONYMOUSID))
550 inccount(&misc->idmap, id);
557 if (length > misc->maxContLength)
558 misc->maxContLength = length;
559 #endif /* SUPERGROUPS */
561 for (na = head; na; na = ntohl(c.next)) {
562 code = ConvertDiskAddress(na, &ni);
564 fprintf(stderr, "Bad continuation ptr %d", na);
566 fprintf(stderr, "walking free list");
567 else if (PrintEntryError(misc, ea, e, 2))
570 fprintf(stderr, "last block: \n");
571 if (PrintEntryError(misc, na, &c, 4))
576 code = pr_Read(na, (char *)&c, sizeof(c));
582 fprintf(stderr, "Continuation entry reused\n");
584 fprintf(stderr, "walking free list");
585 else if (PrintEntryError(misc, ea, e, 2))
587 if (PrintEntryError(misc, na, &c, 4))
593 if (e && (ntohl(c.id) != eid)) {
594 fprintf(stderr, "Continuation id mismatch\n");
596 fprintf(stderr, "walking free list");
597 else if (PrintEntryError(misc, ea, e, 2))
599 if (PrintEntryError(misc, na, &c, 4))
605 /* update membership count */
607 for (i = 0; i < COSIZE; i++) {
608 afs_int32 id = ntohl(c.entries[i]);
614 /* in case the ids are large, convert to pure sign. */
623 #if defined(SUPERGROUPS)
624 if (id_s > 0 && eid_s > 0) {
626 "User can't be member of user in membership list\n");
627 if (PrintEntryError(misc, ea, e, 2))
629 if (PrintEntryError(misc, na, &c, 4))
634 if (id_s * eid_s > 0) { /* sign should be different */
636 "Bad user/group dicotomy in membership list\n");
637 if (PrintEntryError(misc, ea, e, 2))
639 if (PrintEntryError(misc, na, &c, 4))
643 #endif /* SUPERGROUPS */
644 /* count each user as a group, and each group a user is in */
645 #if defined(SUPERGROUPS)
646 if (!(id < 0 && eid < 0) && (id != ANONYMOUSID))
647 inccount(&misc->idmap, id);
649 if ((id >= misc->minId) && (id <= misc->maxId)
650 && (id != ANONYMOUSID))
651 misc->idmap[id - misc->minId]++;
652 #endif /* SUPERGROUPS */
659 if (e && noErrors && (count != ntohl(e->count))) {
660 #if defined(SUPERGROUPS)
662 fprintf(stderr, "Membership list ends early\n");
665 fprintf(stderr, "Membership list ends early\n");
666 #endif /* SUPERGROUPS */
667 fprintf(stderr, "Count was %d should be %d\n", count,
669 if (PrintEntryError(misc, ea, e, 2))
671 #if defined(SUPERGROUPS)
674 if (e && (e->flags & htonl(PRGRP)) && (sgcount != ntohl(g->countsg))) {
675 fprintf(stderr, "SGCount was %d should be %d\n", sgcount,
677 if (PrintEntryError(misc, ea, e, 2))
683 if (length > misc->maxContLength)
684 misc->maxContLength = length;
686 misc->freeLength = length;
689 #if defined(SUPERGROUPS)
695 WalkOwnedChain(char map[], /* one byte per db entry */
696 struct misc_data *misc, /* stuff to keep track of */
697 afs_int32 ea, struct prentry *e)
701 struct prentry c; /* continuation entry */
702 afs_int32 na; /* next thread */
705 int length; /* length of chain */
708 head = ntohl(e->owned);
711 head = ntohl(cheader.orphan);
714 for (na = head; na; na = ntohl(c.nextOwned)) {
715 code = ConvertDiskAddress(na, &ni);
717 fprintf(stderr, "Bad owned list ptr %d", na);
719 fprintf(stderr, "walking orphan list");
720 else if (PrintEntryError(misc, ea, e, 2))
723 fprintf(stderr, "last block: \n");
724 if (PrintEntryError(misc, na, &c, 4))
729 code = pr_Read(na, (char *)&c, sizeof(c));
734 if (map[ni] & MAP_OWNED) {
735 fprintf(stderr, "Entry on multiple owner chains\n");
737 fprintf(stderr, "walking orphan list");
738 else if (PrintEntryError(misc, ea, e, 2))
740 if (PrintEntryError(misc, na, &c, 4))
744 map[ni] |= MAP_OWNED;
745 if ((map[ni] & MAP_HASHES) != MAP_HASHES) {
746 fprintf(stderr, "Owned entry not hashed properly\n");
749 fprintf(stderr, "walking orphan list");
750 else if (PrintEntryError(misc, ea, e, 2))
752 if (PrintEntryError(misc, na, &c, 4))
757 if (ntohl(c.owner) != eid) {
758 fprintf(stderr, "Owner id mismatch\n");
761 } else /* orphan */ if (c.owner) {
762 fprintf(stderr, "Orphan group owner not zero\n");
768 if (length > misc->maxOwnerLength)
769 misc->maxOwnerLength = length;
771 misc->orphanLength = length;
777 WalkChains(char map[], /* one byte per db entry */
778 struct misc_data *misc) /* stuff to keep track of */
782 afs_int32 ea; /* entry's db addr */
787 /* check all entries found in hash table walks */
788 for (ei = 0; ei < misc->nEntries; ei++)
789 if (map[ei] & MAP_HASHES) {
790 ea = ei * sizeof(struct prentry) + sizeof(cheader);
791 code = pr_Read(ea, (char *)&e, sizeof(e));
795 if ((map[ei] & MAP_HASHES) != MAP_HASHES) {
796 fprintf(stderr, "entry not in both hashtables\n");
797 if ((map[ei] & MAP_NAMEHASH) != MAP_NAMEHASH)
798 fprintf(stderr, "--> entry not in Name hashtable\n");
799 if ((map[ei] & MAP_IDHASH) != MAP_IDHASH)
800 fprintf(stderr, "--> entry not in ID hashtable\n");
803 if (PrintEntryError(misc, ea, &e, 2))
810 type = ntohl(e.flags) & PRTYPE;
814 fprintf(stderr, "Group id not negative\n");
817 /* special case sysadmin: it owns itself */
818 if (id == SYSADMINID) {
819 if (ntohl(e.owner) != SYSADMINID) {
821 "System:administrators doesn't own itself\n");
825 code = WalkOwnedChain(map, misc, ea, &e);
828 code = WalkNextChain(map, misc, ea, &e);
835 #if defined(SUPERGROUPS)
836 fprintf(stderr, "User id not positive\n");
838 fprintf(stderr, "User id negative\n");
843 /* Users are owned by sysadmin, but sysadmin doesn't have an owner
844 * chain. Check this then set the owned bit. */
845 if (ntohl(e.owner) != SYSADMINID) {
847 "User not owned by system:administrators\n");
851 fprintf(stderr, "User has owned pointer\n");
854 map[ei] |= MAP_OWNED;
856 code = WalkOwnedChain(map, misc, ea, &e);
859 code = WalkNextChain(map, misc, ea, &e);
862 if (strchr(e.name, '@') == 0) {
863 misc->nusers++; /* Not a foreign user */
865 misc->nforeigns++; /* A foreign user */
875 "ENTRY IS unexpected type [PRFOREIGN] (flags=0x%x)\n",
882 fprintf(stderr, "entry with unexpected type");
891 GC(char map[], struct misc_data *misc)
899 for (ei = 0; ei < misc->nEntries; ei++) {
900 ea = ei * sizeof(struct prentry) + sizeof(cheader);
901 code = pr_Read(ea, (char *)&e, sizeof(e));
906 fprintf(stderr, "Unreferenced entry:");
907 if (PrintEntryError(misc, ea, &e, 2))
910 /* all users and groups should be owned, and their membership counts
912 else if ((m & MAP_HASHES) == MAP_HASHES) {
915 if (!(m & MAP_OWNED)) {
916 fprintf(stderr, "Entry not on any owner chain:\n");
917 if (PrintEntryError(misc, ea, &e, 2))
921 #if defined(SUPERGROUPS)
922 if ((id != ANONYMOUSID)
923 && ((refCount = idcount(&misc->idmap, id)) != ntohl(e.count)))
925 if ((id >= misc->minId) && (id <= misc->maxId)
926 && (id != ANONYMOUSID)
927 && ((refCount = misc->idmap[id - misc->minId]) !=
929 #endif /* SUPERGROUPS */
933 "Entry membership count is inconsistent: %d entries refer to this one\n",
935 if (PrintEntryError(misc, ea, &e, 2))
938 /* get continuation blocks too */
939 for (na = ntohl(e.next); na; na = ntohl(e.next)) {
941 code = ConvertDiskAddress(na, &ni);
944 code = pr_Read(na, (char *)&e, sizeof(e));
947 if (PrintEntryError(misc, na, &e, 4))
960 if (strpbrk(s, " \t")) {
961 asprintf(&qs, "\"%s\"", s);
968 DumpRecreate(char map[], struct misc_data *misc)
978 int builtinUsers = 0;
979 int createLow = 0; /* users uncreate from here */
980 #if defined(SUPERGROUPS)
981 struct idused *idmap; /* map of all id's */
983 afs_int32 *idmap; /* map of all id's */
990 #if defined(SUPERGROUPS)
993 memset(idmap, 0, misc->idRange * sizeof(misc->idmap[0]));
997 for (ei = createLow; ei < misc->nEntries; ei++) {
998 if ((map[ei] & MAP_HASHES) && (map[ei] & MAP_RECREATE) == 0) {
1003 ea = ei * sizeof(struct prentry) + sizeof(cheader);
1004 code = pr_Read(ea, (char *)&e, sizeof(e));
1008 if (misc->listentries)
1009 pr_PrintEntry(stdout, 0 /*not in host order */ , ea, &e,
1013 flags = ntohl(e.flags);
1014 owner = ntohl(e.owner);
1015 name = QuoteName(e.name);
1017 if (!strcmp(e.name, "system:administrators")
1018 || !strcmp(e.name, "system:anyuser")
1019 || !strcmp(e.name, "system:authuser")
1020 || !strcmp(e.name, "system:backup")
1021 || !strcmp(e.name, "anonymous")) {
1026 /* check for duplicate id. This may still lead to duplicate
1028 #if defined(SUPERGROUPS)
1029 if (idcount(&idmap, id))
1031 if (idmap[id - misc->minId])
1034 fprintf(stderr, "Skipping entry with duplicate id %di\n",
1039 /* If owner doesn't exist skip for now, unless we're our own
1040 * owner. If so, a special case allows a group to own itself
1041 * if caller is sysadmin. This leaves only owner cycles to
1044 if ((owner < misc->minId) || (owner > misc->maxId)) {
1045 if (owner == ANONYMOUSID)
1047 "Warning: id %di is owned by ANONYMOUS; using sysadmin instead\n",
1051 "Bogus owner (%d) of id %di; using sysadmin instead\n",
1056 fprintf(stderr, "Warning: group %s is self owning\n",
1058 } else if (owner == 0) {
1060 "Warning: orphan group %s will become self owning.\n",
1064 #if defined(SUPERGROUPS)
1065 else if (!idcount(&idmap, owner))
1068 else if (idmap[owner - misc->minId] == 0)
1073 fprintf(rc, "cr %s %d %d\n", name, id, owner);
1075 gq = uq = access = mask = 0;
1076 if (flags & PRACCESS) {
1077 access = (flags >> PRIVATE_SHIFT);
1078 mask |= PR_SF_ALLBITS;
1080 if (flags & PRQUOTA) {
1081 gq = ntohl(e.ngroups);
1082 uq = ntohl(e.nusers);
1083 mask |= PR_SF_NGROUPS | PR_SF_NUSERS;
1086 fprintf(rc, "sf %d %x %x %d %d\n", id, mask, access, gq,
1090 map[ei] |= MAP_RECREATE;
1091 #if defined(SUPERGROUPS)
1092 if (id != ANONYMOUSID)
1093 inccount(&idmap, id);
1095 if (id != ANONYMOUSID)
1096 idmap[id - misc->minId]++;
1100 /* bump low water mark if possible */
1101 if (ei == createLow)
1108 /* Now create the entries with circular owner dependencies and make them
1109 * own themselves. This is the only way to create them with the correct
1111 for (ei = 0; ei < misc->nEntries; ei++)
1112 if (((map[ei] & MAP_HASHES) == MAP_HASHES)
1113 && (map[ei] & MAP_RECREATE) == 0) {
1114 ea = ei * sizeof(struct prentry) + sizeof(cheader);
1115 code = pr_Read(ea, (char *)&e, sizeof(e));
1120 name = QuoteName(e.name);
1121 fprintf(stderr, "Warning: group %s in self owning cycle\n", name);
1123 fprintf(rc, "cr %s %d %d\n", name, id, id);
1124 #if defined(SUPERGROUPS)
1125 inccount(&idmap, id);
1127 idmap[id - misc->minId]++;
1130 for (ei = 0; ei < misc->nEntries; ei++)
1131 if (((map[ei] & MAP_HASHES) == MAP_HASHES)
1132 && (map[ei] & MAP_RECREATE) == 0) {
1133 ea = ei * sizeof(struct prentry) + sizeof(cheader);
1134 code = pr_Read(ea, (char *)&e, sizeof(e));
1138 owner = ntohl(e.owner);
1139 #if defined(SUPERGROUPS)
1140 if (!idcount(&idmap, owner))
1142 if (idmap[owner - misc->minId] == 0)
1146 "Skipping chown of '%s' to non-existant owner %di\n",
1149 fprintf(rc, "ce %d \"\" %d 0\n", ntohl(e.id), e.owner);
1155 /* Reconstruct membership information based on the groups' user lists. */
1156 for (ei = 0; ei < misc->nEntries; ei++) {
1157 if ((map[ei] & MAP_HASHES) == MAP_HASHES) {
1158 ea = ei * sizeof(struct prentry) + sizeof(cheader);
1159 code = pr_Read(ea, (char *)&e, sizeof(e));
1164 flags = ntohl(e.flags);
1166 if ((id < 0) && (flags & PRGRP)) {
1170 for (i = 0; i < PRSIZE; i++) {
1171 afs_int32 uid = ntohl(e.entries[i]);
1176 #if !defined(SUPERGROUPS)
1179 fprintf(rc, "au %d %d\n", uid, id);
1181 #if !defined(SUPERGROUPS)
1183 fprintf(stderr, "Skipping %di in group %di\n", uid,
1190 code = pr_Read(na, (char *)&c, sizeof(c));
1194 if ((id == ntohl(c.id)) && (c.flags & htonl(PRCONT))) {
1195 for (i = 0; i < COSIZE; i++) {
1196 afs_int32 uid = ntohl(c.entries[i]);
1201 #if !defined(SUPERGROUPS)
1204 fprintf(rc, "au %d %d\n", uid, id);
1206 #if !defined(SUPERGROUPS)
1208 fprintf(stderr, "Skipping %di in group %di\n",
1213 fprintf(stderr, "Skipping continuation block at %d\n",
1219 if (count != ntohl(e.count))
1221 "Group membership count problem found %d should be %d\n",
1222 count, ntohl(e.count));
1223 } else if ((id < 0) || (flags & PRGRP)) {
1224 fprintf(stderr, "Skipping group %di\n", id);
1232 CheckPrDatabase(struct misc_data *misc) /* info & statistics */
1237 char *map; /* map of each entry in db */
1239 eof = ntohl(cheader.eofPtr);
1240 eof -= sizeof(cheader);
1241 n = eof / sizeof(struct prentry);
1242 if ((eof < 0) || (n * sizeof(struct prentry) != eof)) {
1244 afs_com_err(whoami, code,
1245 "eof ptr no good: eof=%d, sizeof(prentry)=%" AFS_SIZET_FMT,
1246 eof, sizeof(struct prentry));
1251 printf("Database has %d entries\n", n);
1255 if (misc->verbose) {
1256 printf("\nChecking name hash table\n");
1259 code = WalkHashTable(cheader.nameHash, MAP_NAMEHASH, map, misc);
1261 afs_com_err(whoami, code, "walking name hash");
1264 if (misc->verbose) {
1265 printf("\nChecking id hash table\n");
1268 code = WalkHashTable(cheader.idHash, MAP_IDHASH, map, misc);
1270 afs_com_err(whoami, code, "walking id hash");
1274 /* hash walk calculates min and max id */
1275 #if defined(SUPERGROUPS)
1278 n = ((misc->maxId > misc->maxForId) ? misc->maxId : misc->maxForId);
1279 misc->idRange = n - misc->minId + 1;
1280 misc->idmap = calloc(misc->idRange, sizeof(afs_int32));
1282 afs_com_err(whoami, 0, "Unable to malloc space for max ids of %d",
1287 #endif /* SUPERGROUPS */
1289 if (misc->verbose) {
1290 printf("\nChecking entry chains\n");
1293 code = WalkChains(map, misc);
1295 afs_com_err(whoami, code, "walking chains");
1298 if (misc->verbose) {
1299 printf("\nChecking free list\n");
1302 code = WalkNextChain(map, misc, 0, 0);
1304 afs_com_err(whoami, code, "walking free list");
1307 if (misc->verbose) {
1308 printf("\nChecking orphans list\n");
1311 code = WalkOwnedChain(map, misc, 0, 0);
1313 afs_com_err(whoami, code, "walking orphan list");
1317 if (misc->verbose) {
1318 printf("\nChecking for unreferenced entries\n");
1321 code = GC(map, misc);
1323 afs_com_err(whoami, code, "looking for unreferenced entries");
1327 DumpRecreate(map, misc); /* check for owner cycles */
1329 fclose(misc->recreate);
1331 if (misc->anon != 2) /* once for each hash table */
1332 fprintf(stderr, "Problems with ANON=%d\n", misc->anon);
1333 if (misc->ncells || misc->ninsts)
1334 fprintf(stderr, "Unexpected entry type\n");
1335 if (misc->nusers != ntohl(cheader.usercount)) {
1337 "User count inconsistent: should be %d, header claims: %d\n",
1338 misc->nusers, ntohl(cheader.usercount));
1340 if (misc->ngroups != ntohl(cheader.groupcount)) {
1342 "Group count inconsistent: should be %d, header claims: %d\n",
1343 misc->ngroups, ntohl(cheader.groupcount));
1345 if (misc->maxId > ntohl(cheader.maxID))
1347 "Database's max user Id (%d) is smaller than largest user's Id (%d).\n",
1348 ntohl(cheader.maxID), misc->maxId);
1349 if (misc->minId < ntohl(cheader.maxGroup))
1351 "Database's max group Id (%d) is smaller than largest group's Id (%d).\n",
1352 ntohl(cheader.maxGroup), misc->minId);
1354 if (misc->verbose) {
1355 printf("\nMaxId = %d, MinId = %d, MaxForeignId = %d\n", misc->maxId,
1356 misc->minId, misc->maxForId);
1358 ("Free list is %d entries in length, %d groups on orphan list\n",
1359 misc->freeLength, misc->orphanLength);
1361 ("The longest owner list is %d, the longest continuation block chain is %d\n",
1362 misc->maxOwnerLength, misc->maxContLength);
1363 printf("%d users ; %d foreign users ; and %d groups\n", misc->nusers,
1364 misc->nforeigns, misc->ngroups);
1371 #include "AFS_component_version_number.c"
1374 WorkerBee(struct cmd_syndesc *as, void *arock)
1378 struct misc_data misc; /* info & statistics */
1380 initialize_PT_error_table();
1381 initialize_U_error_table();
1383 pr_dbaseName = AFSDIR_SERVER_PRDB_FILEPATH;
1384 memset(&misc, 0, sizeof(misc));
1386 pr_dbaseName = as->parms[0].items->data; /* -database */
1387 misc.listuheader = (as->parms[1].items ? 1 : 0); /* -uheader */
1388 misc.listpheader = (as->parms[2].items ? 1 : 0); /* -pheader */
1389 misc.listentries = (as->parms[3].items ? 1 : 0); /* -entries */
1390 misc.verbose = (as->parms[4].items ? 1 : 0); /* -verbose */
1391 recreateFile = (as->parms[5].items ? as->parms[5].items->data : NULL); /* -rebuild */
1393 fd = open(pr_dbaseName, O_RDONLY, 0);
1395 afs_com_err(whoami, errno, "Open failed on db %s", pr_dbaseName);
1399 /* Read the ubik header */
1400 if (misc.listuheader) {
1401 readUbikHeader(&misc);
1404 code = ReadHeader();
1407 if (misc.listpheader)
1408 printheader(&cheader);
1411 misc.recreate = fopen(recreateFile, "w");
1412 if (misc.recreate == 0) {
1413 afs_com_err(whoami, errno,
1414 "can't create file for recreation instructions: %s",
1419 code = CheckPrDatabase(&misc);
1421 afs_com_err(whoami, code, "Checking prserver database");
1428 main(int argc, char *argv[])
1430 struct cmd_syndesc *ts;
1434 ts = cmd_CreateSyntax(NULL, WorkerBee, NULL, 0, "PRDB check");
1435 cmd_AddParm(ts, "-database", CMD_SINGLE, CMD_REQUIRED, "ptdb_file");
1436 cmd_AddParm(ts, "-uheader", CMD_FLAG, CMD_OPTIONAL,
1437 "Display UBIK header");
1438 cmd_AddParm(ts, "-pheader", CMD_FLAG, CMD_OPTIONAL,
1439 "Display KADB header");
1440 cmd_AddParm(ts, "-entries", CMD_FLAG, CMD_OPTIONAL, "Display entries");
1441 cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, "verbose");
1442 cmd_AddParm(ts, "-rebuild", CMD_SINGLE, CMD_OPTIONAL | CMD_HIDE,
1445 return cmd_Dispatch(argc, argv);
1449 #if defined(SUPERGROUPS)
1451 /* new routines to deal with very large ID numbers */
1454 zeromap(struct idused *idmap)
1457 memset(idmap->idcount, 0, sizeof idmap->idcount);
1458 idmap = idmap->idnext;
1463 inccount(struct idused **idmapp, int id)
1465 struct idused *idmap;
1467 if (IDCOUNT & (IDCOUNT - 1)) {
1468 fprintf(stderr, "IDCOUNT must be power of 2!\n");
1471 while ((idmap = *idmapp) != NULL) {
1472 if (idmap->idstart == (id & ~(IDCOUNT - 1)))
1474 idmapp = &idmap->idnext;
1477 idmap = calloc(1, sizeof *idmap);
1482 idmap->idstart = id & ~(IDCOUNT - 1);
1483 idmap->idnext = *idmapp;
1486 ++idmap->idcount[id & (IDCOUNT - 1)];
1490 idcount(struct idused **idmapp, int id)
1492 struct idused *idmap;
1494 if (IDCOUNT & (IDCOUNT - 1)) {
1495 fprintf(stderr, "IDCOUNT must be power of 2!\n");
1498 while ((idmap = *idmapp) != NULL) {
1499 if (idmap->idstart == (id & ~(IDCOUNT - 1))) {
1500 return idmap->idcount[id & (IDCOUNT - 1)];
1502 idmapp = &idmap->idnext;
1506 #endif /* SUPERGROUPS */