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>
60 #include <afs/com_err.h>
66 struct prheader cheader;
69 char *whoami = "db_verify";
70 #define UBIK_HEADERSIZE 64
73 printheader(struct prheader *h)
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);
94 pr_Read(afs_int32 pos, char *buff, afs_int32 len)
98 code = lseek(fd, UBIK_HEADERSIZE + pos, 0);
102 code = read(fd, buff, len);
112 * Initializes the a transaction on the database and reads the header into
113 * the static variable cheader. If successful it returns a read-locked
114 * transaction. If ubik reports that cached database info should be up to date
115 * the cheader structure is not re-read from the ubik.
123 code = pr_Read(0, (char *)&cheader, sizeof(cheader));
125 afs_com_err(whoami, code, "couldn't read header");
128 /* Check and see if database exists and is approximately OK. */
129 if (ntohl(cheader.headerSize) != sizeof(cheader)
130 || ntohl(cheader.eofPtr) == 0) {
133 afs_com_err(whoami, PRDBBAD, "header is bad");
142 /* returns hash bucket for x */
143 return ((abs(x)) % HASHSIZE);
147 NameHash(register unsigned char *aname)
149 /* returns hash bucket for aname */
150 register unsigned int hash = 0;
152 /* stolen directly from the HashString function in the vol package */
153 for (i = strlen(aname), aname += i - 1; i--; aname--)
154 hash = (hash * 31) + (*aname - 31);
155 return (hash % HASHSIZE);
158 #define MAP_NAMEHASH 1
160 #define MAP_HASHES (MAP_NAMEHASH | MAP_IDHASH)
163 #define MAP_OWNED 0x10
164 #define MAP_RECREATE 0x20
167 int nEntries; /* number of database entries */
168 int anon; /* found anonymous Id */
169 afs_int32 maxId; /* user */
170 afs_int32 minId; /* group */
171 afs_int32 maxForId; /* foreign user id */
172 #if defined(SUPERGROUPS)
176 afs_int32 idcount[IDCOUNT];
177 struct idused *idnext;
180 int idRange; /* number of ids in map */
181 afs_int32 *idmap; /* map of all id's: midId is origin */
182 #endif /* SUPERGROUPS */
183 int nusers; /* counts of each type */
188 int maxOwnerLength; /* longest owner chain */
189 int maxContLength; /* longest chain of cont. blks */
190 int orphanLength; /* length of orphan list */
191 int freeLength; /* length of free list */
196 FILE *recreate; /* stream for recreate instructions */
199 #if defined(SUPERGROUPS)
200 void zeromap(struct idused *idmap);
201 void inccount(struct idused **idmapp, int id);
202 int idcount(struct idused **idmapp, int id);
206 readUbikHeader(struct misc_data *misc)
209 struct ubik_hdr uheader;
211 offset = lseek(fd, 0, 0);
213 printf("error: lseek to 0 failed: %d %d\n", offset, errno);
217 /* now read the info */
218 r = read(fd, &uheader, sizeof(uheader));
219 if (r != sizeof(uheader)) {
220 printf("error: read of %d bytes failed: %d %d\n", sizeof(uheader), r,
225 uheader.magic = ntohl(uheader.magic);
226 uheader.size = ntohl(uheader.size);
227 uheader.version.epoch = ntohl(uheader.version.epoch);
228 uheader.version.counter = ntohl(uheader.version.counter);
230 if (misc->listuheader) {
231 printf("Ubik Header\n");
232 printf(" Magic = 0x%x\n", uheader.magic);
233 printf(" Size = %u\n", uheader.size);
234 printf(" Version.epoch = %u\n", uheader.version.epoch);
235 printf(" Version.counter = %u\n", uheader.version.counter);
238 if (uheader.size != UBIK_HEADERSIZE)
239 printf("Ubik header size is %u (should be %u)\n", uheader.size,
241 if (uheader.magic != UBIK_MAGIC)
242 printf("Ubik header magic is 0x%x (should be 0x%x)\n", uheader.magic,
249 ConvertDiskAddress(afs_uint32 ea, int *eiP)
255 if (ea < sizeof(cheader))
257 if (ea >= ntohl(cheader.eofPtr))
259 ea -= sizeof(cheader);
260 i = ea / sizeof(struct prentry);
261 if (i * sizeof(struct prentry) != ea)
263 /* if ((i < 0) || (i >= misc->nEntries)) return PRDBADDR; */
269 PrintEntryError(struct misc_data *misc, afs_int32 ea, struct prentry *e, int indent)
272 pr_PrintEntry(stderr, /*net order */ 0, ea, e, indent);
277 WalkHashTable(afs_int32 hashtable[], /* hash table to walk */
278 int hashType, /* hash function to use */
279 char map[], /* one byte per db entry */
280 struct misc_data *misc) /* stuff to keep track of */
283 int hi; /* index in hash table */
284 afs_int32 ea; /* entry's db addr */
285 int ei; /* entry's index */
286 char bit; /* bits to check for in map */
295 for (hi = 0; hi < HASHSIZE; hi++) {
297 next_ea = ntohl(hashtable[hi]);
299 code = ConvertDiskAddress(next_ea, &ei);
301 fprintf(stderr, "Bad chain address %d\n", next_ea);
303 fprintf(stderr, "Last entry in chain:\n");
304 if (PrintEntryError(misc, ea, &e, 2))
307 fprintf(stderr, "Skipping remainder of hash bucket %d\n", hi);
311 code = pr_Read(ea, (char *)&e, sizeof(e));
317 if (((e.flags & htonl((PRGRP | PRINST))) == 0)
318 && (strchr(e.name, '@'))) {
320 if (id > misc->maxForId)
323 if (id == ANONYMOUSID)
325 else if (id > misc->maxId)
327 if (id < misc->minId)
333 next_ea = ntohl(e.nextName);
334 hash = NameHash(e.name);
337 next_ea = ntohl(e.nextID);
341 fprintf(stderr, "unknown hash table type %d\n", hashType);
347 "Entry found twice in hash table: bucket %d\n", hi);
349 fprintf(stderr, "also in wrong bucket: should be in %d\n",
351 if (PrintEntryError(misc, ea, &e, 2))
357 flags = ntohl(e.flags);
358 switch (flags & PRTYPE) {
360 fprintf(stderr, "ENTRY IS FREE");
363 fprintf(stderr, "ENTRY IS CONTINUATION");
371 fprintf(stderr, "ENTRY IS unexpected type (flags=0x%x)\n",
375 fprintf(stderr, "ENTRY IS OF unknown type (flags=0x%x)\n",
381 fprintf(stderr, "entry hashed in bucket %d should be %d\n",
384 if (PrintEntryError(misc, ea, &e, 2))
394 WalkNextChain(char map[], /* one byte per db entry */
395 struct misc_data *misc, /* stuff to keep track of */
396 afs_int32 ea, struct prentry *e)
401 struct prentry c; /* continuation entry */
402 afs_int32 na; /* next thread */
405 int count; /* number of members */
408 int length; /* length of chain */
409 #if defined(SUPERGROUPS)
410 int sgcount; /* number of sgentrys */
412 #define g (((struct prentryg *)e))
416 head = ntohl(e->next);
419 count = 0; /* set to >9999 if list ends early */
420 #if defined(SUPERGROUPS)
422 sghead = ntohl(g->next);
424 for (i = 0; i < PRSIZE; i++) {
425 afs_int32 id = ntohl(e->entries[i]);
431 /* in case the ids are large, convert to pure sign. */
440 #if defined(SUPERGROUPS)
441 if (id_s > 0 && eid_s > 0) {
443 "User can't be member of user in membership list\n");
444 if (PrintEntryError(misc, ea, e, 2))
449 if (id_s * eid_s > 0) { /* sign should be different */
451 "Bad user/group dicotomy in membership list\n");
452 if (PrintEntryError(misc, ea, e, 2))
456 #endif /* SUPERGROUPS */
457 /* count each user as a group, and each group a user is in */
458 #if defined(SUPERGROUPS)
459 if (!(id < 0 && eid < 0) && (id != ANONYMOUSID))
460 inccount(&misc->idmap, id);
462 if ((id >= misc->minId) && (id <= misc->maxId)
463 && (id != ANONYMOUSID))
464 misc->idmap[id - misc->minId]++;
465 #endif /* SUPERGROUPS */
471 #if defined(SUPERGROUPS)
472 sghead = ntohl(g->nextsg);
473 if ((e->flags & htonl(PRGRP))) {
474 for (i = 0; i < SGSIZE; ++i) {
475 afs_int32 id = ntohl(g->supergroup[i]);
481 "User can't be member of supergroup list\n");
482 if (PrintEntryError(misc, ea, e, 2))
487 inccount(&misc->idmap, id);
491 #endif /* SUPERGROUPS */
493 head = ntohl(cheader.freePtr);
494 #if defined(SUPERGROUPS)
500 #if defined(SUPERGROUPS)
502 for (na = sghead; na; na = ntohl(c.next)) {
503 code = ConvertDiskAddress(na, &ni);
505 fprintf(stderr, "Bad SGcontinuation ptr %d", na);
506 if (PrintEntryError(misc, ea, e, 2))
509 fprintf(stderr, "last block: \n");
510 if (PrintEntryError(misc, na, &c, 4))
515 code = pr_Read(na, (char *)&c, sizeof(c));
521 fprintf(stderr, "Continuation entry reused\n");
522 if (PrintEntryError(misc, ea, e, 2))
524 if (PrintEntryError(misc, na, &c, 4))
530 if ((ntohl(c.id) != eid)) {
531 fprintf(stderr, "Continuation id mismatch\n");
532 if (PrintEntryError(misc, ea, e, 2))
534 if (PrintEntryError(misc, na, &c, 4))
540 /* update membership count */
541 for (i = 0; i < COSIZE; i++) {
542 afs_int32 id = ntohl(c.entries[i]);
548 /* in case the ids are large, convert to pure sign. */
559 "User can't be member of supergroup list\n");
560 if (PrintEntryError(misc, ea, e, 2))
562 if (PrintEntryError(misc, na, &c, 4))
566 /* count each user as a group, and each group a user is in */
567 if ((id != ANONYMOUSID))
568 inccount(&misc->idmap, id);
575 if (length > misc->maxContLength)
576 misc->maxContLength = length;
577 #endif /* SUPERGROUPS */
579 for (na = head; na; na = ntohl(c.next)) {
580 code = ConvertDiskAddress(na, &ni);
582 fprintf(stderr, "Bad continuation ptr %d", na);
584 fprintf(stderr, "walking free list");
585 else if (PrintEntryError(misc, ea, e, 2))
588 fprintf(stderr, "last block: \n");
589 if (PrintEntryError(misc, na, &c, 4))
594 code = pr_Read(na, (char *)&c, sizeof(c));
600 fprintf(stderr, "Continuation entry reused\n");
602 fprintf(stderr, "walking free list");
603 else if (PrintEntryError(misc, ea, e, 2))
605 if (PrintEntryError(misc, na, &c, 4))
611 if (e && (ntohl(c.id) != eid)) {
612 fprintf(stderr, "Continuation id mismatch\n");
614 fprintf(stderr, "walking free list");
615 else if (PrintEntryError(misc, ea, e, 2))
617 if (PrintEntryError(misc, na, &c, 4))
623 /* update membership count */
625 for (i = 0; i < COSIZE; i++) {
626 afs_int32 id = ntohl(c.entries[i]);
632 /* in case the ids are large, convert to pure sign. */
641 #if defined(SUPERGROUPS)
642 if (id_s > 0 && eid_s > 0) {
644 "User can't be member of user in membership list\n");
645 if (PrintEntryError(misc, ea, e, 2))
647 if (PrintEntryError(misc, na, &c, 4))
652 if (id_s * eid_s > 0) { /* sign should be different */
654 "Bad user/group dicotomy in membership list\n");
655 if (PrintEntryError(misc, ea, e, 2))
657 if (PrintEntryError(misc, na, &c, 4))
661 #endif /* SUPERGROUPS */
662 /* count each user as a group, and each group a user is in */
663 #if defined(SUPERGROUPS)
664 if (!(id < 0 && eid < 0) && (id != ANONYMOUSID))
665 inccount(&misc->idmap, id);
667 if ((id >= misc->minId) && (id <= misc->maxId)
668 && (id != ANONYMOUSID))
669 misc->idmap[id - misc->minId]++;
670 #endif /* SUPERGROUPS */
677 if (e && noErrors && (count != ntohl(e->count))) {
678 #if defined(SUPERGROUPS)
680 fprintf(stderr, "Membership list ends early\n");
683 fprintf(stderr, "Membership list ends early\n");
684 #endif /* SUPERGROUPS */
685 fprintf(stderr, "Count was %d should be %d\n", count,
687 if (PrintEntryError(misc, ea, e, 2))
689 #if defined(SUPERGROUPS)
692 if (e && (e->flags & htonl(PRGRP)) && (sgcount != ntohl(g->countsg))) {
693 fprintf(stderr, "SGCount was %d should be %d\n", sgcount,
695 if (PrintEntryError(misc, ea, e, 2))
701 if (length > misc->maxContLength)
702 misc->maxContLength = length;
704 misc->freeLength = length;
707 #if defined(SUPERGROUPS)
713 WalkOwnedChain(char map[], /* one byte per db entry */
714 struct misc_data *misc, /* stuff to keep track of */
715 afs_int32 ea, struct prentry *e)
719 struct prentry c; /* continuation entry */
720 afs_int32 na; /* next thread */
723 int length; /* length of chain */
726 head = ntohl(e->owned);
729 head = ntohl(cheader.orphan);
732 for (na = head; na; na = ntohl(c.nextOwned)) {
733 code = ConvertDiskAddress(na, &ni);
735 fprintf(stderr, "Bad owned list ptr %d", na);
737 fprintf(stderr, "walking orphan list");
738 else if (PrintEntryError(misc, ea, e, 2))
741 fprintf(stderr, "last block: \n");
742 if (PrintEntryError(misc, na, &c, 4))
747 code = pr_Read(na, (char *)&c, sizeof(c));
752 if (map[ni] & MAP_OWNED) {
753 fprintf(stderr, "Entry on multiple owner chains\n");
755 fprintf(stderr, "walking orphan list");
756 else if (PrintEntryError(misc, ea, e, 2))
758 if (PrintEntryError(misc, na, &c, 4))
762 map[ni] |= MAP_OWNED;
763 if ((map[ni] & MAP_HASHES) != MAP_HASHES) {
764 fprintf(stderr, "Owned entry not hashed properly\n");
767 fprintf(stderr, "walking orphan list");
768 else if (PrintEntryError(misc, ea, e, 2))
770 if (PrintEntryError(misc, na, &c, 4))
775 if (ntohl(c.owner) != eid) {
776 fprintf(stderr, "Owner id mismatch\n");
779 } else /* orphan */ if (c.owner) {
780 fprintf(stderr, "Orphan group owner not zero\n");
786 if (length > misc->maxOwnerLength)
787 misc->maxOwnerLength = length;
789 misc->orphanLength = length;
795 WalkChains(char map[], /* one byte per db entry */
796 struct misc_data *misc) /* stuff to keep track of */
800 afs_int32 ea; /* entry's db addr */
805 /* check all entries found in hash table walks */
806 for (ei = 0; ei < misc->nEntries; ei++)
807 if (map[ei] & MAP_HASHES) {
808 ea = ei * sizeof(struct prentry) + sizeof(cheader);
809 code = pr_Read(ea, (char *)&e, sizeof(e));
813 if ((map[ei] & MAP_HASHES) != MAP_HASHES) {
814 fprintf(stderr, "entry not in both hashtables\n");
815 if ((map[ei] & MAP_NAMEHASH) != MAP_NAMEHASH)
816 fprintf(stderr, "--> entry not in Name hashtable\n");
817 if ((map[ei] & MAP_IDHASH) != MAP_IDHASH)
818 fprintf(stderr, "--> entry not in ID hashtable\n");
821 if (PrintEntryError(misc, ea, &e, 2))
828 type = ntohl(e.flags) & PRTYPE;
832 fprintf(stderr, "Group id not negative\n");
835 /* special case sysadmin: it owns itself */
836 if (id == SYSADMINID) {
837 if (ntohl(e.owner) != SYSADMINID) {
839 "System:administrators doesn't own itself\n");
843 code = WalkOwnedChain(map, misc, ea, &e);
846 code = WalkNextChain(map, misc, ea, &e);
853 #if defined(SUPERGROUPS)
854 fprintf(stderr, "User id not positive\n");
856 fprintf(stderr, "User id negative\n");
861 /* Users are owned by sysadmin, but sysadmin doesn't have an owner
862 * chain. Check this then set the owned bit. */
863 if (ntohl(e.owner) != SYSADMINID) {
865 "User not owned by system:administrators\n");
869 fprintf(stderr, "User has owned pointer\n");
872 map[ei] |= MAP_OWNED;
874 code = WalkOwnedChain(map, misc, ea, &e);
877 code = WalkNextChain(map, misc, ea, &e);
880 if (strchr(e.name, '@') == 0) {
881 misc->nusers++; /* Not a foreign user */
883 misc->nforeigns++; /* A foreign user */
893 "ENTRY IS unexpected type [PRFOREIGN] (flags=0x%x)\n",
900 fprintf(stderr, "entry with unexpected type");
909 GC(char map[], struct misc_data *misc)
917 for (ei = 0; ei < misc->nEntries; ei++) {
918 ea = ei * sizeof(struct prentry) + sizeof(cheader);
919 code = pr_Read(ea, (char *)&e, sizeof(e));
924 fprintf(stderr, "Unreferenced entry:");
925 if (PrintEntryError(misc, ea, &e, 2))
928 /* all users and groups should be owned, and their membership counts
930 else if ((m & MAP_HASHES) == MAP_HASHES) {
933 if (!(m & MAP_OWNED)) {
934 fprintf(stderr, "Entry not on any owner chain:\n");
935 if (PrintEntryError(misc, ea, &e, 2))
939 #if defined(SUPERGROUPS)
940 if ((id != ANONYMOUSID)
941 && ((refCount = idcount(&misc->idmap, id)) != ntohl(e.count)))
943 if ((id >= misc->minId) && (id <= misc->maxId)
944 && (id != ANONYMOUSID)
945 && ((refCount = misc->idmap[id - misc->minId]) !=
947 #endif /* SUPERGROUPS */
951 "Entry membership count is inconsistent: %d entries refer to this one\n",
953 if (PrintEntryError(misc, ea, &e, 2))
956 /* get continuation blocks too */
957 for (na = ntohl(e.next); na; na = ntohl(e.next)) {
959 code = ConvertDiskAddress(na, &ni);
962 code = pr_Read(na, (char *)&e, sizeof(e));
965 if (PrintEntryError(misc, na, &e, 4))
978 if (strpbrk(s, " \t")) {
979 qs = (char *)malloc(strlen(s) + 3);
989 DumpRecreate(char map[], struct misc_data *misc)
999 int builtinUsers = 0;
1000 int createLow = 0; /* users uncreate from here */
1001 #if defined(SUPERGROUPS)
1002 struct idused *idmap; /* map of all id's */
1004 afs_int32 *idmap; /* map of all id's */
1009 rc = misc->recreate;
1010 idmap = misc->idmap;
1011 #if defined(SUPERGROUPS)
1014 memset(idmap, 0, misc->idRange * sizeof(misc->idmap[0]));
1018 for (ei = createLow; ei < misc->nEntries; ei++) {
1019 if ((map[ei] & MAP_HASHES) && (map[ei] & MAP_RECREATE) == 0) {
1024 ea = ei * sizeof(struct prentry) + sizeof(cheader);
1025 code = pr_Read(ea, (char *)&e, sizeof(e));
1029 if (misc->listentries)
1030 pr_PrintEntry(stdout, 0 /*not in host order */ , ea, &e,
1034 flags = ntohl(e.flags);
1035 owner = ntohl(e.owner);
1036 name = QuoteName(e.name);
1038 if (!strcmp(e.name, "system:administrators")
1039 || !strcmp(e.name, "system:anyuser")
1040 || !strcmp(e.name, "system:authuser")
1041 || !strcmp(e.name, "system:backup")
1042 || !strcmp(e.name, "anonymous")) {
1047 /* check for duplicate id. This may still lead to duplicate
1049 #if defined(SUPERGROUPS)
1050 if (idcount(&idmap, id))
1052 if (idmap[id - misc->minId])
1055 fprintf(stderr, "Skipping entry with duplicate id %di\n",
1060 /* If owner doesn't exist skip for now, unless we're our own
1061 * owner. If so, a special case allows a group to own itself
1062 * if caller is sysadmin. This leaves only owner cycles to
1065 if ((owner < misc->minId) || (owner > misc->maxId)) {
1066 if (owner == ANONYMOUSID)
1068 "Warning: id %di is owned by ANONYMOUS; using sysadmin instead\n",
1072 "Bogus owner (%d) of id %di; using sysadmin instead\n",
1077 fprintf(stderr, "Warning: group %s is self owning\n",
1079 } else if (owner == 0) {
1081 "Warning: orphan group %s will become self owning.\n",
1085 #if defined(SUPERGROUPS)
1086 else if (!idcount(&idmap, owner))
1089 else if (idmap[owner - misc->minId] == 0)
1094 fprintf(rc, "cr %s %d %d\n", name, id, owner);
1096 gq = uq = access = mask = 0;
1097 if (flags & PRACCESS) {
1098 access = (flags >> PRIVATE_SHIFT);
1099 mask |= PR_SF_ALLBITS;
1101 if (flags & PRQUOTA) {
1102 gq = ntohl(e.ngroups);
1103 uq = ntohl(e.nusers);
1104 mask |= PR_SF_NGROUPS | PR_SF_NUSERS;
1107 fprintf(rc, "sf %d %x %x %d %d\n", id, mask, access, gq,
1111 map[ei] |= MAP_RECREATE;
1112 #if defined(SUPERGROUPS)
1113 if (id != ANONYMOUSID)
1114 inccount(&idmap, id);
1116 if (id != ANONYMOUSID)
1117 idmap[id - misc->minId]++;
1121 /* bump low water mark if possible */
1122 if (ei == createLow)
1129 /* Now create the entries with circular owner dependencies and make them
1130 * own themselves. This is the only way to create them with the correct
1132 for (ei = 0; ei < misc->nEntries; ei++)
1133 if (((map[ei] & MAP_HASHES) == MAP_HASHES)
1134 && (map[ei] & MAP_RECREATE) == 0) {
1135 ea = ei * sizeof(struct prentry) + sizeof(cheader);
1136 code = pr_Read(ea, (char *)&e, sizeof(e));
1141 name = QuoteName(e.name);
1142 fprintf(stderr, "Warning: group %s in self owning cycle\n", name);
1144 fprintf(rc, "cr %s %d %d\n", name, id, id);
1145 #if defined(SUPERGROUPS)
1146 inccount(&idmap, id);
1148 idmap[id - misc->minId]++;
1151 for (ei = 0; ei < misc->nEntries; ei++)
1152 if (((map[ei] & MAP_HASHES) == MAP_HASHES)
1153 && (map[ei] & MAP_RECREATE) == 0) {
1154 ea = ei * sizeof(struct prentry) + sizeof(cheader);
1155 code = pr_Read(ea, (char *)&e, sizeof(e));
1159 owner = ntohl(e.owner);
1160 #if defined(SUPERGROUPS)
1161 if (!idcount(&idmap, owner))
1163 if (idmap[owner - misc->minId] == 0)
1167 "Skipping chown of '%s' to non-existant owner %di\n",
1170 fprintf(rc, "ce %d \"\" %d 0\n", ntohl(e.id), e.owner);
1176 /* Reconstruct membership information based on the groups' user lists. */
1177 for (ei = 0; ei < misc->nEntries; ei++) {
1178 if ((map[ei] & MAP_HASHES) == MAP_HASHES) {
1179 ea = ei * sizeof(struct prentry) + sizeof(cheader);
1180 code = pr_Read(ea, (char *)&e, sizeof(e));
1185 flags = ntohl(e.flags);
1187 if ((id < 0) && (flags & PRGRP)) {
1190 #if defined(SUPERGROUPS)
1194 for (i = 0; i < PRSIZE; i++) {
1195 afs_int32 uid = ntohl(e.entries[i]);
1200 #if !defined(SUPERGROUPS)
1203 fprintf(rc, "au %d %d\n", uid, id);
1205 #if !defined(SUPERGROUPS)
1207 fprintf(stderr, "Skipping %di in group %di\n", uid,
1211 #if defined(SUPERGROUPS)
1212 #define g (*((struct prentryg *)&e))
1213 ng = ntohl(g.nextsg);
1214 for (i = 0; i < SGSIZE; i++) {
1215 afs_int32 uid = ntohl(g.supergroup[i]);
1220 fprintf(rc, "au %d %d\n", uid, id);
1225 code = pr_Read(ng, (char *)&c, sizeof(c));
1229 if ((id == ntohl(c.id)) && (c.flags & htonl(PRCONT))) {
1230 for (i = 0; i < COSIZE; i++) {
1231 afs_int32 uid = ntohl(c.entries[i]);
1236 fprintf(rc, "au %d %d\n", uid, id);
1240 fprintf(stderr, "Skipping continuation block at %d\n",
1247 #endif /* SUPERGROUPS */
1251 code = pr_Read(na, (char *)&c, sizeof(c));
1255 if ((id == ntohl(c.id)) && (c.flags & htonl(PRCONT))) {
1256 for (i = 0; i < COSIZE; i++) {
1257 afs_int32 uid = ntohl(c.entries[i]);
1262 #if !defined(SUPERGROUPS)
1265 fprintf(rc, "au %d %d\n", uid, id);
1267 #if !defined(SUPERGROUPS)
1269 fprintf(stderr, "Skipping %di in group %di\n",
1274 fprintf(stderr, "Skipping continuation block at %d\n",
1280 if (count != ntohl(e.count))
1282 "Group membership count problem found %d should be %d\n",
1283 count, ntohl(e.count));
1284 } else if ((id < 0) || (flags & PRGRP)) {
1285 fprintf(stderr, "Skipping group %di\n", id);
1293 CheckPrDatabase(struct misc_data *misc) /* info & statistics */
1298 char *map; /* map of each entry in db */
1300 eof = ntohl(cheader.eofPtr);
1301 eof -= sizeof(cheader);
1302 n = eof / sizeof(struct prentry);
1303 if ((eof < 0) || (n * sizeof(struct prentry) != eof)) {
1305 afs_com_err(whoami, code, "eof ptr no good: eof=%d, sizeof(prentry)=%d",
1306 eof, sizeof(struct prentry));
1311 printf("Database has %d entries\n", n);
1312 map = (char *)malloc(n);
1316 if (misc->verbose) {
1317 printf("\nChecking name hash table\n");
1320 code = WalkHashTable(cheader.nameHash, MAP_NAMEHASH, map, misc);
1322 afs_com_err(whoami, code, "walking name hash");
1325 if (misc->verbose) {
1326 printf("\nChecking id hash table\n");
1329 code = WalkHashTable(cheader.idHash, MAP_IDHASH, map, misc);
1331 afs_com_err(whoami, code, "walking id hash");
1335 /* hash walk calculates min and max id */
1336 #if defined(SUPERGROUPS)
1339 n = ((misc->maxId > misc->maxForId) ? misc->maxId : misc->maxForId);
1340 misc->idRange = n - misc->minId + 1;
1341 misc->idmap = (afs_int32 *) malloc(misc->idRange * sizeof(afs_int32));
1343 afs_com_err(whoami, 0, "Unable to malloc space for max ids of %d",
1348 memset(misc->idmap, 0, misc->idRange * sizeof(misc->idmap[0]));
1349 #endif /* SUPERGROUPS */
1351 if (misc->verbose) {
1352 printf("\nChecking entry chains\n");
1355 code = WalkChains(map, misc);
1357 afs_com_err(whoami, code, "walking chains");
1360 if (misc->verbose) {
1361 printf("\nChecking free list\n");
1364 code = WalkNextChain(map, misc, 0, 0);
1366 afs_com_err(whoami, code, "walking free list");
1369 if (misc->verbose) {
1370 printf("\nChecking orphans list\n");
1373 code = WalkOwnedChain(map, misc, 0, 0);
1375 afs_com_err(whoami, code, "walking orphan list");
1379 if (misc->verbose) {
1380 printf("\nChecking for unreferenced entries\n");
1383 code = GC(map, misc);
1385 afs_com_err(whoami, code, "looking for unreferenced entries");
1389 DumpRecreate(map, misc); /* check for owner cycles */
1391 fclose(misc->recreate);
1393 if (misc->anon != 2) /* once for each hash table */
1394 fprintf(stderr, "Problems with ANON=%d\n", misc->anon);
1395 if (misc->ncells || misc->ninsts)
1396 fprintf(stderr, "Unexpected entry type\n");
1397 if (misc->nusers != ntohl(cheader.usercount)) {
1399 "User count inconsistent: should be %d, header claims: %d\n",
1400 misc->nusers, ntohl(cheader.usercount));
1402 if (misc->ngroups != ntohl(cheader.groupcount)) {
1404 "Group count inconsistent: should be %d, header claims: %d\n",
1405 misc->ngroups, ntohl(cheader.groupcount));
1407 if (misc->maxId > ntohl(cheader.maxID))
1409 "Database's max user Id (%d) is smaller than largest user's Id (%d).\n",
1410 ntohl(cheader.maxID), misc->maxId);
1411 if (misc->minId < ntohl(cheader.maxGroup))
1413 "Database's max group Id (%d) is smaller than largest group's Id (%d).\n",
1414 ntohl(cheader.maxGroup), misc->minId);
1416 if (misc->verbose) {
1417 printf("\nMaxId = %d, MinId = %d, MaxForeignId = %d\n", misc->maxId,
1418 misc->minId, misc->maxForId);
1420 ("Free list is %d entries in length, %d groups on orphan list\n",
1421 misc->freeLength, misc->orphanLength);
1423 ("The longest owner list is %d, the longest continuation block chain is %d\n",
1424 misc->maxOwnerLength, misc->maxContLength);
1425 printf("%d users ; %d foreign users ; and %d groups\n", misc->nusers,
1426 misc->nforeigns, misc->ngroups);
1433 #include "AFS_component_version_number.c"
1436 WorkerBee(struct cmd_syndesc *as, char *arock)
1440 struct misc_data misc; /* info & statistics */
1442 initialize_PT_error_table();
1443 initialize_U_error_table();
1445 pr_dbaseName = AFSDIR_SERVER_PRDB_FILEPATH;
1446 memset(&misc, 0, sizeof(misc));
1448 pr_dbaseName = as->parms[0].items->data; /* -database */
1449 misc.listuheader = (as->parms[1].items ? 1 : 0); /* -uheader */
1450 misc.listpheader = (as->parms[2].items ? 1 : 0); /* -pheader */
1451 misc.listentries = (as->parms[3].items ? 1 : 0); /* -entries */
1452 misc.verbose = (as->parms[4].items ? 1 : 0); /* -verbose */
1453 recreateFile = (as->parms[5].items ? as->parms[5].items->data : NULL); /* -rebuild */
1455 fd = open(pr_dbaseName, O_RDONLY, 0);
1457 afs_com_err(whoami, errno, "Open failed on db %s", pr_dbaseName);
1461 /* Read the ubik header */
1462 if (misc.listuheader) {
1463 readUbikHeader(&misc);
1466 code = ReadHeader();
1469 if (misc.listpheader)
1470 printheader(&cheader);
1473 misc.recreate = fopen(recreateFile, "w");
1474 if (misc.recreate == 0) {
1475 afs_com_err(whoami, errno,
1476 "can't create file for recreation instructions: %s",
1481 code = CheckPrDatabase(&misc);
1483 afs_com_err(whoami, code, "Checking prserver database");
1490 main(int argc, char *argv[])
1492 struct cmd_syndesc *ts;
1496 ts = cmd_CreateSyntax(NULL, WorkerBee, NULL, "PRDB check");
1497 cmd_AddParm(ts, "-database", CMD_SINGLE, CMD_REQUIRED, "ptdb_file");
1498 cmd_AddParm(ts, "-uheader", CMD_FLAG, CMD_OPTIONAL,
1499 "Display UBIK header");
1500 cmd_AddParm(ts, "-pheader", CMD_FLAG, CMD_OPTIONAL,
1501 "Display KADB header");
1502 cmd_AddParm(ts, "-entries", CMD_FLAG, CMD_OPTIONAL, "Display entries");
1503 cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, "verbose");
1504 cmd_AddParm(ts, "-rebuild", CMD_SINGLE, CMD_OPTIONAL | CMD_HIDE,
1507 return cmd_Dispatch(argc, argv);
1511 #if defined(SUPERGROUPS)
1513 /* new routines to deal with very large ID numbers */
1516 zeromap(struct idused *idmap)
1519 memset((char *)idmap->idcount, 0, sizeof idmap->idcount);
1520 idmap = idmap->idnext;
1525 inccount(struct idused **idmapp, int id)
1527 struct idused *idmap;
1529 if (IDCOUNT & (IDCOUNT - 1)) {
1530 fprintf(stderr, "IDCOUNT must be power of 2!\n");
1533 while (idmap = *idmapp) {
1534 if (idmap->idstart == (id & ~(IDCOUNT - 1)))
1536 idmapp = &idmap->idnext;
1539 idmap = (struct idused *)malloc(sizeof *idmap);
1544 memset((char *)idmap, 0, sizeof idmap);
1545 idmap->idstart = id & ~(IDCOUNT - 1);
1546 idmap->idnext = *idmapp;
1549 ++idmap->idcount[id & (IDCOUNT - 1)];
1553 idcount(struct idused **idmapp, int id)
1555 struct idused *idmap;
1557 if (IDCOUNT & (IDCOUNT - 1)) {
1558 fprintf(stderr, "IDCOUNT must be power of 2!\n");
1561 while (idmap = *idmapp) {
1562 if (idmap->idstart == (id & ~(IDCOUNT - 1))) {
1563 return idmap->idcount[id & (IDCOUNT - 1)];
1565 idmapp = &idmap->idnext;
1569 #endif /* SUPERGROUPS */