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
11 #include <afsconfig.h>
12 #include <afs/param.h>
18 * (3) Define a structure, idused, instead of an
19 * array of long integers, idmap, to count group
20 * memberships. These structures are on a linked
21 * list, with each structure containing IDCOUNT
23 * (4) Add new functions to processs the structure
25 * zeromap(), idcount(), inccount().
26 * (5) Add code, primarily in WalkNextChain():
27 * 1. Test id's, allowing groups within groups.
28 * 2. Count the membership list for supergroups,
29 * and follow the continuation chain for
31 * (6) Add fprintf statements for various error
36 #include <sys/types.h>
39 #include <WINNT/afsevent.h>
43 #include <netinet/in.h>
56 #include <afs/cellconfig.h>
57 #include <afs/afsutil.h>
65 struct prheader cheader;
68 char *whoami = "db_verify";
69 #define UBIK_HEADERSIZE 64
75 printf("Version = %d\n", ntohl(h->version));
76 printf("Header Size = %d\n", ntohl(h->headerSize));
77 printf("Free Ptr = 0x%x\n", ntohl(h->freePtr));
78 printf("EOF Ptr = 0x%x\n", ntohl(h->eofPtr));
79 printf("Max Group ID = %d\n", ntohl(h->maxGroup));
80 printf("Max User ID = %d\n", ntohl(h->maxID));
81 printf("Max Foreign ID = %d\n", ntohl(h->maxForeign));
82 /* printf("Max Sub/Super ID = %d\n", ntohl(h->maxInst)); */
83 printf("Orphaned groups = %d\n", ntohl(h->orphan));
84 printf("User Count = %d\n", ntohl(h->usercount));
85 printf("Group Count = %d\n", ntohl(h->groupcount));
86 /* printf("Foreign Count = %d\n", ntohl(h->foreigncount)); NYI */
87 /* printf("Sub/super Count = %d\n", ntohl(h->instcount)); NYI */
88 printf("Name Hash = %d buckets\n", HASHSIZE);
89 printf("ID Hash = %d buckets\n", HASHSIZE);
93 pr_Read(pos, buff, len)
100 code = lseek(fd, UBIK_HEADERSIZE + pos, 0);
104 code = read(fd, buff, len);
114 * Initializes the a transaction on the database and reads the header into
115 * the static variable cheader. If successful it returns a read-locked
116 * transaction. If ubik reports that cached database info should be up to date
117 * the cheader structure is not re-read from the ubik.
125 code = pr_Read(0, (char *)&cheader, sizeof(cheader));
127 com_err(whoami, code, "couldn't read header");
130 /* Check and see if database exists and is approximately OK. */
131 if (ntohl(cheader.headerSize) != sizeof(cheader)
132 || ntohl(cheader.eofPtr) == 0) {
135 com_err(whoami, PRDBBAD, "header is bad");
145 /* returns hash bucket for x */
146 return ((abs(x)) % HASHSIZE);
151 register unsigned char *aname;
153 /* returns hash bucket for aname */
154 register unsigned int hash = 0;
156 /* stolen directly from the HashString function in the vol package */
157 for (i = strlen(aname), aname += i - 1; i--; aname--)
158 hash = (hash * 31) + (*aname - 31);
159 return (hash % HASHSIZE);
162 #define MAP_NAMEHASH 1
164 #define MAP_HASHES (MAP_NAMEHASH | MAP_IDHASH)
167 #define MAP_OWNED 0x10
168 #define MAP_RECREATE 0x20
171 int nEntries; /* number of database entries */
172 int anon; /* found anonymous Id */
173 afs_int32 maxId; /* user */
174 afs_int32 minId; /* group */
175 afs_int32 maxForId; /* foreign user id */
176 #if defined(SUPERGROUPS)
180 afs_int32 idcount[IDCOUNT];
181 struct idused *idnext;
184 int idRange; /* number of ids in map */
185 afs_int32 *idmap; /* map of all id's: midId is origin */
186 #endif /* SUPERGROUPS */
187 int nusers; /* counts of each type */
192 int maxOwnerLength; /* longest owner chain */
193 int maxContLength; /* longest chain of cont. blks */
194 int orphanLength; /* length of orphan list */
195 int freeLength; /* length of free list */
200 FILE *recreate; /* stream for recreate instructions */
203 #if defined(SUPERGROUPS)
204 void zeromap(struct idused *idmap);
205 void inccount(struct idused **idmapp, int id);
206 int idcount(struct idused **idmapp, int id);
211 struct misc_data *misc;
214 struct ubik_hdr uheader;
216 offset = lseek(fd, 0, 0);
218 printf("error: lseek to 0 failed: %d %d\n", offset, errno);
222 /* now read the info */
223 r = read(fd, &uheader, sizeof(uheader));
224 if (r != sizeof(uheader)) {
225 printf("error: read of %d bytes failed: %d %d\n", sizeof(uheader), r,
230 uheader.magic = ntohl(uheader.magic);
231 uheader.size = ntohl(uheader.size);
232 uheader.version.epoch = ntohl(uheader.version.epoch);
233 uheader.version.counter = ntohl(uheader.version.counter);
235 if (misc->listuheader) {
236 printf("Ubik Header\n");
237 printf(" Magic = 0x%x\n", uheader.magic);
238 printf(" Size = %u\n", uheader.size);
239 printf(" Version.epoch = %u\n", uheader.version.epoch);
240 printf(" Version.counter = %u\n", uheader.version.counter);
243 if (uheader.size != UBIK_HEADERSIZE)
244 printf("Ubik header size is %u (should be %u)\n", uheader.size,
246 if (uheader.magic != UBIK_MAGIC)
247 printf("Ubik header magic is 0x%x (should be 0x%x)\n", uheader.magic,
254 ConvertDiskAddress(ea, eiP)
262 if (ea < sizeof(cheader))
264 if (ea >= ntohl(cheader.eofPtr))
266 ea -= sizeof(cheader);
267 i = ea / sizeof(struct prentry);
268 if (i * sizeof(struct prentry) != ea)
270 /* if ((i < 0) || (i >= misc->nEntries)) return PRDBADDR; */
276 PrintEntryError(misc, ea, e, indent)
277 struct misc_data *misc;
283 pr_PrintEntry(stderr, /*net order */ 0, ea, e, indent);
288 WalkHashTable(hashtable, hashType, map, misc)
289 afs_int32 hashtable[]; /* hash table to walk */
290 int hashType; /* hash function to use */
291 char map[]; /* one byte per db entry */
292 struct misc_data *misc; /* stuff to keep track of */
295 int hi; /* index in hash table */
296 afs_int32 ea; /* entry's db addr */
297 int ei; /* entry's index */
298 char bit; /* bits to check for in map */
307 for (hi = 0; hi < HASHSIZE; hi++) {
309 next_ea = ntohl(hashtable[hi]);
311 code = ConvertDiskAddress(next_ea, &ei);
313 fprintf(stderr, "Bad chain address %d\n", next_ea);
315 fprintf(stderr, "Last entry in chain:\n");
316 if (PrintEntryError(misc, ea, &e, 2))
319 fprintf(stderr, "Skipping remainder of hash bucket %d\n", hi);
323 code = pr_Read(ea, (char *)&e, sizeof(e));
329 if (((ntohl(e.flags) & (PRGRP | PRINST)) == 0)
330 && (strchr(e.name, '@'))) {
332 if (id > misc->maxForId)
335 if (id == ANONYMOUSID)
337 else if (id > misc->maxId)
339 if (id < misc->minId)
345 next_ea = ntohl(e.nextName);
346 hash = NameHash(e.name);
349 next_ea = ntohl(e.nextID);
353 fprintf(stderr, "unknown hash table type %d\n", hashType);
359 "Entry found twice in hash table: bucket %d\n", hi);
361 fprintf(stderr, "also in wrong bucket: should be in %d\n",
363 if (PrintEntryError(misc, ea, &e, 2))
369 flags = ntohl(e.flags);
370 switch (flags & PRTYPE) {
372 fprintf(stderr, "ENTRY IS FREE");
375 fprintf(stderr, "ENTRY IS CONTINUATION");
383 fprintf(stderr, "ENTRY IS unexpected type (flags=0x%x)\n",
387 fprintf(stderr, "ENTRY IS OF unknown type (flags=0x%x)\n",
393 fprintf(stderr, "entry hashed in bucket %d should be %d\n",
396 if (PrintEntryError(misc, ea, &e, 2))
406 WalkNextChain(map, misc, ea, e)
407 char map[]; /* one byte per db entry */
408 struct misc_data *misc; /* stuff to keep track of */
415 struct prentry c; /* continuation entry */
416 afs_int32 na; /* next thread */
419 int count; /* number of members */
422 int length; /* length of chain */
423 #if defined(SUPERGROUPS)
424 int sgcount; /* number of sgentrys */
426 #define g (((struct prentryg *)e))
430 head = ntohl(e->next);
433 count = 0; /* set to >9999 if list ends early */
434 #if defined(SUPERGROUPS)
436 sghead = ntohl(g->next);
438 for (i = 0; i < PRSIZE; i++) {
439 afs_int32 id = ntohl(e->entries[i]);
445 /* in case the ids are large, convert to pure sign. */
454 #if defined(SUPERGROUPS)
455 if (id_s > 0 && eid_s > 0) {
457 "User can't be member of user in membership list\n");
458 if (PrintEntryError(misc, ea, e, 2))
463 if (id_s * eid_s > 0) { /* sign should be different */
465 "Bad user/group dicotomy in membership list\n");
466 if (PrintEntryError(misc, ea, e, 2))
470 #endif /* SUPERGROUPS */
471 /* count each user as a group, and each group a user is in */
472 #if defined(SUPERGROUPS)
473 if (!(id < 0 && eid < 0) && (id != ANONYMOUSID))
474 inccount(&misc->idmap, id);
476 if ((id >= misc->minId) && (id <= misc->maxId)
477 && (id != ANONYMOUSID))
478 misc->idmap[id - misc->minId]++;
479 #endif /* SUPERGROUPS */
485 #if defined(SUPERGROUPS)
487 if ((e->flags & PRGRP)) {
488 for (i = 0; i < SGSIZE; ++i) {
489 afs_int32 id = ntohl(g->supergroup[i]);
495 "User can't be member of supergroup list\n");
496 if (PrintEntryError(misc, ea, e, 2))
501 inccount(&misc->idmap, id);
505 #endif /* SUPERGROUPS */
507 head = ntohl(cheader.freePtr);
508 #if defined(SUPERGROUPS)
514 #if defined(SUPERGROUPS)
516 for (na = sghead; na; na = ntohl(c.next)) {
517 code = ConvertDiskAddress(na, &ni);
519 fprintf(stderr, "Bad continuation ptr %d", na);
520 if (PrintEntryError(misc, ea, e, 2))
523 fprintf(stderr, "last block: \n");
524 if (PrintEntryError(misc, na, &c, 4))
529 code = pr_Read(na, (char *)&c, sizeof(c));
535 fprintf(stderr, "Continuation entry reused\n");
536 if (PrintEntryError(misc, ea, e, 2))
538 if (PrintEntryError(misc, na, &c, 4))
544 if ((ntohl(c.id) != eid)) {
545 fprintf(stderr, "Continuation id mismatch\n");
546 if (PrintEntryError(misc, ea, e, 2))
548 if (PrintEntryError(misc, na, &c, 4))
554 /* update membership count */
555 for (i = 0; i < COSIZE; i++) {
556 afs_int32 id = ntohl(c.entries[i]);
562 /* in case the ids are large, convert to pure sign. */
573 "User can't be member of supergroup list\n");
574 if (PrintEntryError(misc, ea, e, 2))
576 if (PrintEntryError(misc, na, &c, 4))
580 /* count each user as a group, and each group a user is in */
581 if ((id != ANONYMOUSID))
582 inccount(&misc->idmap, id);
589 if (length > misc->maxContLength)
590 misc->maxContLength = length;
591 #endif /* SUPERGROUPS */
593 for (na = head; na; na = ntohl(c.next)) {
594 code = ConvertDiskAddress(na, &ni);
596 fprintf(stderr, "Bad continuation ptr %d", na);
598 fprintf(stderr, "walking free list");
599 else if (PrintEntryError(misc, ea, e, 2))
602 fprintf(stderr, "last block: \n");
603 if (PrintEntryError(misc, na, &c, 4))
608 code = pr_Read(na, (char *)&c, sizeof(c));
614 fprintf(stderr, "Continuation entry reused\n");
616 fprintf(stderr, "walking free list");
617 else if (PrintEntryError(misc, ea, e, 2))
619 if (PrintEntryError(misc, na, &c, 4))
625 if (e && (ntohl(c.id) != eid)) {
626 fprintf(stderr, "Continuation id mismatch\n");
628 fprintf(stderr, "walking free list");
629 else if (PrintEntryError(misc, ea, e, 2))
631 if (PrintEntryError(misc, na, &c, 4))
637 /* update membership count */
639 for (i = 0; i < COSIZE; i++) {
640 afs_int32 id = ntohl(c.entries[i]);
646 /* in case the ids are large, convert to pure sign. */
655 #if defined(SUPERGROUPS)
656 if (id_s > 0 && eid_s > 0) {
658 "User can't be member of user in membership list\n");
659 if (PrintEntryError(misc, ea, e, 2))
661 if (PrintEntryError(misc, na, &c, 4))
666 if (id_s * eid_s > 0) { /* sign should be different */
668 "Bad user/group dicotomy in membership list\n");
669 if (PrintEntryError(misc, ea, e, 2))
671 if (PrintEntryError(misc, na, &c, 4))
675 #endif /* SUPERGROUPS */
676 /* count each user as a group, and each group a user is in */
677 #if defined(SUPERGROUPS)
678 if (!(id < 0 && eid < 0) && (id != ANONYMOUSID))
679 inccount(&misc->idmap, id);
681 if ((id >= misc->minId) && (id <= misc->maxId)
682 && (id != ANONYMOUSID))
683 misc->idmap[id - misc->minId]++;
684 #endif /* SUPERGROUPS */
691 if (e && noErrors && (count != ntohl(e->count))) {
692 #if defined(SUPERGROUPS)
694 fprintf(stderr, "Membership list ends early\n");
697 fprintf(stderr, "Membership list ends early\n");
698 #endif /* SUPERGROUPS */
699 fprintf(stderr, "Count was %d should be %d\n", count,
701 if (PrintEntryError(misc, ea, e, 2))
703 #if defined(SUPERGROUPS)
706 if (e && (e->flags & PRGRP) && (sgcount != ntohl(g->countsg))) {
707 fprintf(stderr, "SGCount was %d should be %d\n", sgcount,
709 if (PrintEntryError(misc, ea, e, 2))
715 if (length > misc->maxContLength)
716 misc->maxContLength = length;
718 misc->freeLength = length;
721 #if defined(SUPERGROUPS)
727 WalkOwnedChain(map, misc, ea, e)
728 char map[]; /* one byte per db entry */
729 struct misc_data *misc; /* stuff to keep track of */
735 struct prentry c; /* continuation entry */
736 afs_int32 na; /* next thread */
739 int length; /* length of chain */
742 head = ntohl(e->owned);
745 head = ntohl(cheader.orphan);
748 for (na = head; na; na = ntohl(c.nextOwned)) {
749 code = ConvertDiskAddress(na, &ni);
751 fprintf(stderr, "Bad owned list ptr %d", na);
753 fprintf(stderr, "walking orphan list");
754 else if (PrintEntryError(misc, ea, e, 2))
757 fprintf(stderr, "last block: \n");
758 if (PrintEntryError(misc, na, &c, 4))
763 code = pr_Read(na, (char *)&c, sizeof(c));
768 if (map[ni] & MAP_OWNED) {
769 fprintf(stderr, "Entry on multiple owner chains\n");
771 fprintf(stderr, "walking orphan list");
772 else if (PrintEntryError(misc, ea, e, 2))
774 if (PrintEntryError(misc, na, &c, 4))
778 map[ni] |= MAP_OWNED;
779 if ((map[ni] & MAP_HASHES) != MAP_HASHES) {
780 fprintf(stderr, "Owned entry not hashed properly\n");
783 fprintf(stderr, "walking orphan list");
784 else if (PrintEntryError(misc, ea, e, 2))
786 if (PrintEntryError(misc, na, &c, 4))
791 if (ntohl(c.owner) != eid) {
792 fprintf(stderr, "Owner id mismatch\n");
795 } else /* orphan */ if (c.owner) {
796 fprintf(stderr, "Orphan group owner not zero\n");
802 if (length > misc->maxOwnerLength)
803 misc->maxOwnerLength = length;
805 misc->orphanLength = length;
811 WalkChains(map, misc)
812 char map[]; /* one byte per db entry */
813 struct misc_data *misc; /* stuff to keep track of */
817 afs_int32 ea; /* entry's db addr */
822 /* check all entries found in hash table walks */
823 for (ei = 0; ei < misc->nEntries; ei++)
824 if (map[ei] & MAP_HASHES) {
825 ea = ei * sizeof(struct prentry) + sizeof(cheader);
826 code = pr_Read(ea, (char *)&e, sizeof(e));
830 if ((map[ei] & MAP_HASHES) != MAP_HASHES) {
831 fprintf(stderr, "entry not in both hashtables\n");
832 if ((map[ei] & MAP_NAMEHASH) != MAP_NAMEHASH)
833 fprintf(stderr, "--> entry not in Name hashtable\n");
834 if ((map[ei] & MAP_IDHASH) != MAP_IDHASH)
835 fprintf(stderr, "--> entry not in ID hashtable\n");
838 if (PrintEntryError(misc, ea, &e, 2))
845 type = ntohl(e.flags) & PRTYPE;
849 fprintf(stderr, "Group id not negative\n");
852 /* special case sysadmin: it owns itself */
853 if (id == SYSADMINID) {
854 if (ntohl(e.owner) != SYSADMINID) {
856 "System:administrators doesn't own itself\n");
860 code = WalkOwnedChain(map, misc, ea, &e);
863 code = WalkNextChain(map, misc, ea, &e);
870 #if defined(SUPERGROUPS)
871 fprintf(stderr, "User id not positive\n");
873 fprintf(stderr, "User id negative\n");
878 /* Users are owned by sysadmin, but sysadmin doesn't have an owner
879 * chain. Check this then set the owned bit. */
880 if (ntohl(e.owner) != SYSADMINID) {
882 "User not owned by system:administrators\n");
886 fprintf(stderr, "User has owned pointer\n");
889 map[ei] |= MAP_OWNED;
891 code = WalkOwnedChain(map, misc, ea, &e);
894 code = WalkNextChain(map, misc, ea, &e);
897 if (strchr(e.name, '@') == 0) {
898 misc->nusers++; /* Not a foreign user */
900 misc->nforeigns++; /* A foreign user */
910 "ENTRY IS unexpected type [PRFOREIGN] (flags=0x%x)\n",
917 fprintf(stderr, "entry with unexpected type");
928 struct misc_data *misc;
936 for (ei = 0; ei < misc->nEntries; ei++) {
937 ea = ei * sizeof(struct prentry) + sizeof(cheader);
938 code = pr_Read(ea, (char *)&e, sizeof(e));
943 fprintf(stderr, "Unreferenced entry:");
944 if (PrintEntryError(misc, ea, &e, 2))
947 /* all users and groups should be owned, and their membership counts
949 else if ((m & MAP_HASHES) == MAP_HASHES) {
952 if (!(m & MAP_OWNED)) {
953 fprintf(stderr, "Entry not on any owner chain:\n");
954 if (PrintEntryError(misc, ea, &e, 2))
958 #if defined(SUPERGROUPS)
959 if ((id != ANONYMOUSID)
960 && ((refCount = idcount(&misc->idmap, id)) != ntohl(e.count))) {
962 if ((id >= misc->minId) && (id <= misc->maxId)
963 && (id != ANONYMOUSID)
964 && ((refCount = misc->idmap[id - misc->minId]) !=
966 #endif /* SUPERGROUPS */
969 "Entry membership count is inconsistent: %d entries refer to this one\n",
971 if (PrintEntryError(misc, ea, &e, 2))
974 /* get continuation blocks too */
975 for (na = ntohl(e.next); na; na = ntohl(e.next)) {
977 code = ConvertDiskAddress(na, &ni);
980 code = pr_Read(na, (char *)&e, sizeof(e));
983 if (PrintEntryError(misc, na, &e, 4))
997 if (strpbrk(s, " \t")) {
998 qs = (char *)malloc(strlen(s) + 3);
1008 DumpRecreate(map, misc)
1010 struct misc_data *misc;
1020 int builtinUsers = 0;
1021 int createLow = 0; /* users uncreate from here */
1022 #if defined(SUPERGROUPS)
1023 struct idused *idmap; /* map of all id's */
1025 afs_int32 *idmap; /* map of all id's */
1030 rc = misc->recreate;
1031 idmap = misc->idmap;
1032 #if defined(SUPERGROUPS)
1035 memset(idmap, 0, misc->idRange * sizeof(misc->idmap[0]));
1039 for (ei = createLow; ei < misc->nEntries; ei++) {
1040 if ((map[ei] & MAP_HASHES) && (map[ei] & MAP_RECREATE) == 0) {
1045 ea = ei * sizeof(struct prentry) + sizeof(cheader);
1046 code = pr_Read(ea, (char *)&e, sizeof(e));
1050 if (misc->listentries)
1051 pr_PrintEntry(stdout, 0 /*not in host order */ , ea, &e,
1055 flags = ntohl(e.flags);
1056 owner = ntohl(e.owner);
1057 name = QuoteName(e.name);
1059 if (!strcmp(e.name, "system:administrators")
1060 || !strcmp(e.name, "system:anyuser")
1061 || !strcmp(e.name, "system:authuser")
1062 || !strcmp(e.name, "system:backup")
1063 || !strcmp(e.name, "anonymous")) {
1068 /* check for duplicate id. This may still lead to duplicate
1070 #if defined(SUPERGROUPS)
1071 if (idcount(&idmap, id)) {
1073 if (idmap[id - misc->minId]) {
1075 fprintf(stderr, "Skipping entry with duplicate id %di\n",
1080 /* If owner doesn't exist skip for now, unless we're our own
1081 * owner. If so, a special case allows a group to own itself
1082 * if caller is sysadmin. This leaves only owner cycles to
1085 if ((owner < misc->minId) || (owner > misc->maxId)) {
1086 if (owner == ANONYMOUSID)
1088 "Warning: id %di is owned by ANONYMOUS; using sysadmin instead\n",
1092 "Bogus owner (%d) of id %di; using sysadmin instead\n",
1097 fprintf(stderr, "Warning: group %s is self owning\n",
1099 } else if (owner == 0) {
1101 "Warning: orphan group %s will become self owning.\n",
1105 #if defined(SUPERGROUPS)
1106 else if (!idcount(&idmap, owner))
1109 else if (idmap[owner - misc->minId] == 0)
1114 fprintf(rc, "cr %s %d %d\n", name, id, owner);
1116 gq = uq = access = mask = 0;
1117 if (flags & PRACCESS) {
1118 access = (flags >> PRIVATE_SHIFT);
1119 mask |= PR_SF_ALLBITS;
1121 if (flags & PRQUOTA) {
1122 gq = ntohl(e.ngroups);
1123 uq = ntohl(e.nusers);
1124 mask |= PR_SF_NGROUPS | PR_SF_NUSERS;
1127 fprintf(rc, "sf %d %x %x %d %d\n", id, mask, access, gq,
1131 map[ei] |= MAP_RECREATE;
1132 #if defined(SUPERGROUPS)
1133 if (id != ANONYMOUSID)
1134 inccount(&idmap, id);
1136 if (id != ANONYMOUSID)
1137 idmap[id - misc->minId]++;
1141 /* bump low water mark if possible */
1142 if (ei == createLow)
1149 /* Now create the entries with circular owner dependencies and make them
1150 * own themselves. This is the only way to create them with the correct
1152 for (ei = 0; ei < misc->nEntries; ei++)
1153 if (((map[ei] & MAP_HASHES) == MAP_HASHES)
1154 && (map[ei] & MAP_RECREATE) == 0) {
1155 ea = ei * sizeof(struct prentry) + sizeof(cheader);
1156 code = pr_Read(ea, (char *)&e, sizeof(e));
1161 name = QuoteName(e.name);
1162 fprintf(stderr, "Warning: group %s in self owning cycle\n", name);
1164 fprintf(rc, "cr %s %d %d\n", name, id, id);
1165 #if defined(SUPERGROUPS)
1166 inccount(&idmap, id);
1168 idmap[id - misc->minId]++;
1171 for (ei = 0; ei < misc->nEntries; ei++)
1172 if (((map[ei] & MAP_HASHES) == MAP_HASHES)
1173 && (map[ei] & MAP_RECREATE) == 0) {
1174 ea = ei * sizeof(struct prentry) + sizeof(cheader);
1175 code = pr_Read(ea, (char *)&e, sizeof(e));
1179 owner = ntohl(e.owner);
1180 #if defined(SUPERGROUPS)
1181 if (!idcount(&idmap, owner)) {
1183 if (idmap[owner - misc->minId] == 0) {
1186 "Skipping chown of '%s' to non-existant owner %di\n",
1189 fprintf(rc, "ce %d \"\" %d 0\n", ntohl(e.id), e.owner);
1195 /* Reconstruct membership information based on the groups' user lists. */
1196 for (ei = 0; ei < misc->nEntries; ei++) {
1197 if ((map[ei] & MAP_HASHES) == MAP_HASHES) {
1198 ea = ei * sizeof(struct prentry) + sizeof(cheader);
1199 code = pr_Read(ea, (char *)&e, sizeof(e));
1204 flags = ntohl(e.flags);
1206 if ((id < 0) && (flags & PRGRP)) {
1209 #if defined(SUPERGROUPS)
1213 for (i = 0; i < PRSIZE; i++) {
1214 afs_int32 uid = ntohl(e.entries[i]);
1219 #if !defined(SUPERGROUPS)
1222 fprintf(rc, "au %d %d\n", uid, id);
1224 #if !defined(SUPERGROUPS)
1226 fprintf(stderr, "Skipping %di in group %di\n", uid,
1230 #if defined(SUPERGROUPS)
1231 #define g (*((struct prentryg *)&e))
1232 ng = ntohl(g.nextsg);
1233 for (i = 0; i < SGSIZE; i++) {
1234 afs_int32 uid = ntohl(g.supergroup[i]);
1239 fprintf(rc, "au %d %d\n", uid, id);
1244 code = pr_Read(ng, (char *)&c, sizeof(c));
1248 if ((id == ntohl(c.id)) && (ntohl(c.flags) & PRCONT)) {
1249 for (i = 0; i < COSIZE; i++) {
1250 afs_int32 uid = ntohl(c.entries[i]);
1255 fprintf(rc, "au %d %d\n", uid, id);
1259 fprintf(stderr, "Skipping continuation block at %d\n",
1266 #endif /* SUPERGROUPS */
1270 code = pr_Read(na, (char *)&c, sizeof(c));
1274 if ((id == ntohl(c.id)) && (ntohl(c.flags) & PRCONT)) {
1275 for (i = 0; i < COSIZE; i++) {
1276 afs_int32 uid = ntohl(c.entries[i]);
1281 #if !defined(SUPERGROUPS)
1284 fprintf(rc, "au %d %d\n", uid, id);
1286 #if !defined(SUPERGROUPS)
1288 fprintf(stderr, "Skipping %di in group %di\n",
1293 fprintf(stderr, "Skipping continuation block at %d\n",
1299 if (count != ntohl(e.count))
1301 "Group membership count problem found %d should be %d\n",
1302 count, ntohl(e.count));
1303 } else if ((id < 0) || (flags & PRGRP)) {
1304 fprintf(stderr, "Skipping group %di\n", id);
1312 CheckPrDatabase(misc)
1313 struct misc_data *misc; /* info & statistics */
1318 char *map; /* map of each entry in db */
1320 eof = ntohl(cheader.eofPtr);
1321 eof -= sizeof(cheader);
1322 n = eof / sizeof(struct prentry);
1323 if ((eof < 0) || (n * sizeof(struct prentry) != eof)) {
1325 com_err(whoami, code, "eof ptr no good: eof=%d, sizeof(prentry)=%d",
1326 eof, sizeof(struct prentry));
1331 printf("Database has %d entries\n", n);
1332 map = (char *)malloc(n);
1336 if (misc->verbose) {
1337 printf("\nChecking name hash table\n");
1340 code = WalkHashTable(cheader.nameHash, MAP_NAMEHASH, map, misc);
1342 com_err(whoami, code, "walking name hash");
1345 if (misc->verbose) {
1346 printf("\nChecking id hash table\n");
1349 code = WalkHashTable(cheader.idHash, MAP_IDHASH, map, misc);
1351 com_err(whoami, code, "walking id hash");
1355 /* hash walk calculates min and max id */
1356 #if defined(SUPERGROUPS)
1359 n = ((misc->maxId > misc->maxForId) ? misc->maxId : misc->maxForId);
1360 misc->idRange = n - misc->minId + 1;
1361 misc->idmap = (afs_int32 *) malloc(misc->idRange * sizeof(afs_int32));
1363 com_err(whoami, 0, "Unable to malloc space for max ids of %d",
1368 memset(misc->idmap, 0, misc->idRange * sizeof(misc->idmap[0]));
1369 #endif /* SUPERGROUPS */
1371 if (misc->verbose) {
1372 printf("\nChecking entry chains\n");
1375 code = WalkChains(map, misc);
1377 com_err(whoami, code, "walking chains");
1380 if (misc->verbose) {
1381 printf("\nChecking free list\n");
1384 code = WalkNextChain(map, misc, 0, 0);
1386 com_err(whoami, code, "walking free list");
1389 if (misc->verbose) {
1390 printf("\nChecking orphans list\n");
1393 code = WalkOwnedChain(map, misc, 0, 0);
1395 com_err(whoami, code, "walking orphan list");
1399 if (misc->verbose) {
1400 printf("\nChecking for unreferenced entries\n");
1403 code = GC(map, misc);
1405 com_err(whoami, code, "looking for unreferenced entries");
1409 DumpRecreate(map, misc); /* check for owner cycles */
1411 fclose(misc->recreate);
1413 if (misc->anon != 2) /* once for each hash table */
1414 fprintf(stderr, "Problems with ANON=%d\n", misc->anon);
1415 if (misc->ncells || misc->ninsts)
1416 fprintf(stderr, "Unexpected entry type\n");
1417 if (misc->nusers != ntohl(cheader.usercount)) {
1419 "User count inconsistent: should be %d, header claims: %d\n",
1420 misc->nusers, ntohl(cheader.usercount));
1422 if (misc->ngroups != ntohl(cheader.groupcount)) {
1424 "Group count inconsistent: should be %d, header claims: %d\n",
1425 misc->ngroups, ntohl(cheader.groupcount));
1427 if (misc->maxId > ntohl(cheader.maxID))
1429 "Database's max user Id (%d) is smaller than largest user's Id (%d).\n",
1430 ntohl(cheader.maxID), misc->maxId);
1431 if (misc->minId < ntohl(cheader.maxGroup))
1433 "Database's max group Id (%d) is smaller than largest group's Id (%d).\n",
1434 ntohl(cheader.maxGroup), misc->minId);
1436 if (misc->verbose) {
1437 printf("\nMaxId = %d, MinId = %d, MaxForeignId = %d\n", misc->maxId,
1438 misc->minId, misc->maxForId);
1440 ("Free list is %d entries in length, %d groups on orphan list\n",
1441 misc->freeLength, misc->orphanLength);
1443 ("The longest owner list is %d, the longest continuation block chain is %d\n",
1444 misc->maxOwnerLength, misc->maxContLength);
1445 printf("%d users ; %d foreign users ; and %d groups\n", misc->nusers,
1446 misc->nforeigns, misc->ngroups);
1452 #include "AFS_component_version_number.c"
1454 WorkerBee(as, arock)
1455 struct cmd_syndesc *as;
1460 struct misc_data misc; /* info & statistics */
1462 initialize_PT_error_table();
1463 initialize_U_error_table();
1465 pr_dbaseName = AFSDIR_SERVER_PRDB_FILEPATH;
1466 memset(&misc, 0, sizeof(misc));
1468 pr_dbaseName = as->parms[0].items->data; /* -database */
1469 misc.listuheader = (as->parms[1].items ? 1 : 0); /* -uheader */
1470 misc.listpheader = (as->parms[2].items ? 1 : 0); /* -pheader */
1471 misc.listentries = (as->parms[3].items ? 1 : 0); /* -entries */
1472 misc.verbose = (as->parms[4].items ? 1 : 0); /* -verbose */
1473 recreateFile = (as->parms[5].items ? as->parms[5].items->data : NULL); /* -rebuild */
1475 fd = open(pr_dbaseName, O_RDONLY, 0);
1477 com_err(whoami, errno, "Open failed on db %s", pr_dbaseName);
1481 /* Read the ubik header */
1482 if (misc.listuheader) {
1483 readUbikHeader(&misc);
1486 code = ReadHeader();
1489 if (misc.listpheader)
1490 printheader(&cheader);
1493 misc.recreate = fopen(recreateFile, "w");
1494 if (misc.recreate == 0) {
1495 com_err(whoami, errno,
1496 "can't create file for recreation instructions: %s",
1501 code = CheckPrDatabase(&misc);
1503 com_err(whoami, code, "Checking prserver database");
1513 struct cmd_syndesc *ts;
1517 ts = cmd_CreateSyntax(NULL, WorkerBee, NULL, "PRDB check");
1518 cmd_AddParm(ts, "-database", CMD_SINGLE, CMD_REQUIRED, "ptdb_file");
1519 cmd_AddParm(ts, "-uheader", CMD_FLAG, CMD_OPTIONAL,
1520 "Display UBIK header");
1521 cmd_AddParm(ts, "-pheader", CMD_FLAG, CMD_OPTIONAL,
1522 "Display KADB header");
1523 cmd_AddParm(ts, "-entries", CMD_FLAG, CMD_OPTIONAL, "Display entries");
1524 cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, "verbose");
1525 cmd_AddParm(ts, "-rebuild", CMD_SINGLE, CMD_OPTIONAL | CMD_HIDE,
1528 return cmd_Dispatch(argc, argv);
1532 #if defined(SUPERGROUPS)
1534 /* new routines to deal with very large ID numbers */
1538 struct idused *idmap;
1541 bzero((char *)idmap->idcount, sizeof idmap->idcount);
1542 idmap = idmap->idnext;
1547 inccount(struct idused **idmapp, int id)
1549 struct idused *idmap;
1551 if (IDCOUNT & (IDCOUNT - 1)) {
1552 fprintf(stderr, "IDCOUNT must be power of 2!\n");
1555 while (idmap = *idmapp) {
1556 if (idmap->idstart == (id & ~(IDCOUNT - 1)))
1558 idmapp = &idmap->idnext;
1561 idmap = (struct idused *)malloc(sizeof *idmap);
1566 bzero((char *)idmap, sizeof idmap);
1567 idmap->idstart = id & ~(IDCOUNT - 1);
1568 idmap->idnext = *idmapp;
1571 ++idmap->idcount[id & (IDCOUNT - 1)];
1576 struct idused **idmapp;
1578 struct idused *idmap;
1580 if (IDCOUNT & (IDCOUNT - 1)) {
1581 fprintf(stderr, "IDCOUNT must be power of 2!\n");
1584 while (idmap = *idmapp) {
1585 if (idmap->idstart == (id & ~(IDCOUNT - 1))) {
1586 return idmap->idcount[id & (IDCOUNT - 1)];
1588 idmapp = &idmap->idnext;
1593 #endif /* SUPERGROUPS */