2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
12 #include <afsconfig.h>
13 #include <afs/param.h>
18 #include <sys/types.h>
21 #include <WINNT/afsevent.h>
25 #include <netinet/in.h>
31 #include <afs/cellconfig.h>
32 #include <afs/afsutil.h>
40 struct prheader cheader;
43 char *whoami = "db_verify";
44 #define UBIK_HEADERSIZE 64
47 afs_int32 printheader(h)
50 printf("Version = %d\n", ntohl(h->version));
51 printf("Header Size = %d\n", ntohl(h->headerSize));
52 printf("Free Ptr = 0x%x\n", ntohl(h->freePtr));
53 printf("EOF Ptr = 0x%x\n", ntohl(h->eofPtr));
54 printf("Max Group ID = %d\n", ntohl(h->maxGroup));
55 printf("Max User ID = %d\n", ntohl(h->maxID));
56 printf("Max Foreign ID = %d\n", ntohl(h->maxForeign));
57 /* printf("Max Sub/Super ID = %d\n", ntohl(h->maxInst)); */
58 printf("Orphaned groups = %d\n", ntohl(h->orphan));
59 printf("User Count = %d\n", ntohl(h->usercount));
60 printf("Group Count = %d\n", ntohl(h->groupcount));
61 /* printf("Foreign Count = %d\n", ntohl(h->foreigncount)); NYI */
62 /* printf("Sub/super Count = %d\n", ntohl(h->instcount)); NYI */
63 printf("Name Hash = %d buckets\n", HASHSIZE);
64 printf("ID Hash = %d buckets\n", HASHSIZE);
67 static afs_int32 pr_Read (pos, buff, len)
74 code = lseek(fd,UBIK_HEADERSIZE+pos, 0);
75 if (code == -1) return errno;
77 code = read(fd, buff, len);
78 if (code != len) return -1;
79 if (code == -1) return errno;
85 * Initializes the a transaction on the database and reads the header into
86 * the static variable cheader. If successful it returns a read-locked
87 * transaction. If ubik reports that cached database info should be up to date
88 * the cheader structure is not re-read from the ubik.
91 afs_int32 ReadHeader()
95 code = pr_Read (0, (char *) &cheader, sizeof(cheader));
97 com_err(whoami, code, "couldn't read header");
100 /* Check and see if database exists and is approximately OK. */
101 if (ntohl(cheader.headerSize) != sizeof(cheader) ||
102 ntohl(cheader.eofPtr) == 0) {
103 if (code) return code;
104 com_err (whoami, PRDBBAD, "header is bad");
110 static afs_int32 IDHash(x)
113 /* returns hash bucket for x */
114 return ((abs(x)) % HASHSIZE);
117 static afs_int32 NameHash(aname)
118 register unsigned char *aname;
120 /* returns hash bucket for aname */
121 register unsigned int hash=0;
123 /* stolen directly from the HashString function in the vol package */
124 for (i=strlen(aname),aname += i-1;i--;aname--)
125 hash = (hash*31) + (*aname-31);
126 return(hash % HASHSIZE);
129 #define MAP_NAMEHASH 1
131 #define MAP_HASHES (MAP_NAMEHASH | MAP_IDHASH)
134 #define MAP_OWNED 0x10
135 #define MAP_RECREATE 0x20
138 int nEntries; /* number of database entries */
139 int anon; /* found anonymous Id */
140 afs_int32 maxId; /* user */
141 afs_int32 minId; /* group */
142 afs_int32 maxForId; /* foreign user id */
143 int idRange; /* number of ids in map */
144 afs_int32 *idmap; /* map of all id's: midId is origin */
145 int nusers; /* counts of each type */
150 int maxOwnerLength; /* longest owner chain */
151 int maxContLength; /* longest chain of cont. blks */
152 int orphanLength; /* length of orphan list */
153 int freeLength; /* length of free list */
158 FILE *recreate; /* stream for recreate instructions */
161 int readUbikHeader(misc)
162 struct misc_data *misc;
165 struct ubik_hdr uheader;
167 offset = lseek(fd, 0, 0);
169 printf("error: lseek to 0 failed: %d %d\n", offset, errno);
173 /* now read the info */
174 r = read(fd, &uheader, sizeof(uheader));
175 if (r != sizeof(uheader)) {
176 printf("error: read of %d bytes failed: %d %d\n", sizeof(uheader), r, errno);
180 uheader.magic = ntohl(uheader.magic);
181 uheader.size = ntohl(uheader.size);
182 uheader.version.epoch = ntohl(uheader.version.epoch);
183 uheader.version.counter = ntohl(uheader.version.counter);
185 if (misc->listuheader) {
186 printf("Ubik Header\n");
187 printf(" Magic = 0x%x\n", uheader.magic);
188 printf(" Size = %u\n", uheader.size);
189 printf(" Version.epoch = %u\n", uheader.version.epoch);
190 printf(" Version.counter = %u\n", uheader.version.counter);
193 if (uheader.size != UBIK_HEADERSIZE)
194 printf("Ubik header size is %u (should be %u)\n", uheader.size, UBIK_HEADERSIZE);
195 if (uheader.magic != UBIK_MAGIC)
196 printf("Ubik header magic is 0x%x (should be 0x%x)\n", uheader.magic, UBIK_MAGIC);
201 afs_int32 ConvertDiskAddress (ea, eiP)
209 if (ea < sizeof(cheader)) return PRDBADDR;
210 if (ea >= ntohl(cheader.eofPtr)) return PRDBADDR;
211 ea -= sizeof(cheader);
212 i = ea / sizeof(struct prentry);
213 if (i*sizeof(struct prentry) != ea) return PRDBADDR;
214 /* if ((i < 0) || (i >= misc->nEntries)) return PRDBADDR; */
219 int PrintEntryError (misc, ea, e, indent)
220 struct misc_data *misc;
226 pr_PrintEntry (stderr, /*net order*/0, ea, e, indent);
230 afs_int32 WalkHashTable (hashtable, hashType, map, misc)
231 afs_int32 hashtable[]; /* hash table to walk */
232 int hashType; /* hash function to use */
233 char map[]; /* one byte per db entry */
234 struct misc_data *misc; /* stuff to keep track of */
237 int hi; /* index in hash table */
238 afs_int32 ea; /* entry's db addr */
239 int ei; /* entry's index */
240 char bit; /* bits to check for in map */
249 for (hi=0; hi<HASHSIZE; hi++) {
251 next_ea = ntohl(hashtable[hi]);
253 code = ConvertDiskAddress (next_ea, &ei);
255 fprintf (stderr, "Bad chain address %d\n", next_ea);
257 fprintf (stderr, "Last entry in chain:\n");
258 if (PrintEntryError (misc, ea, &e, 2)) return PRDBBAD;
261 "Skipping remainder of hash bucket %d\n", hi);
265 code = pr_Read (ea, (char *)&e, sizeof(e));
266 if (code) return code;
270 if ( ((ntohl(e.flags) & (PRGRP | PRINST)) == 0) &&
271 (strchr(e.name,'@')) ) {
273 if (id > misc->maxForId) misc->maxForId = id;
275 if (id == ANONYMOUSID) misc->anon++;
276 else if (id > misc->maxId) misc->maxId = id;
277 if (id < misc->minId) misc->minId = id;
282 next_ea = ntohl (e.nextName);
283 hash = NameHash (e.name);
286 next_ea = ntohl (e.nextID);
290 fprintf (stderr, "unknown hash table type %d\n", hashType);
296 "Entry found twice in hash table: bucket %d\n", hi);
299 "also in wrong bucket: should be in %d\n", hash);
300 if (PrintEntryError (misc, ea, &e, 2)) return PRDBBAD;
305 flags = ntohl(e.flags);
306 switch (flags & PRTYPE) {
308 fprintf (stderr, "ENTRY IS FREE");
311 fprintf (stderr, "ENTRY IS CONTINUATION");
320 "ENTRY IS unexpected type (flags=0x%x)\n", flags);
324 "ENTRY IS OF unknown type (flags=0x%x)\n", flags);
329 fprintf (stderr, "entry hashed in bucket %d should be %d\n",
332 if (PrintEntryError (misc, ea, &e, 2)) return PRDBBAD;
340 afs_int32 WalkNextChain (map, misc, ea, e)
341 char map[]; /* one byte per db entry */
342 struct misc_data *misc; /* stuff to keep track of */
349 struct prentry c; /* continuation entry */
350 afs_int32 na; /* next thread */
353 int count; /* number of members */
356 int length; /* length of chain */
359 head = ntohl(e->next);
362 count = 0; /* set to >9999 if list ends early */
363 for (i=0; i<PRSIZE; i++) {
364 afs_int32 id = ntohl(e->entries[i]);
365 if (id == PRBADID) continue;
369 /* in case the ids are large, convert to pure sign. */
370 if (id > 0) id_s = 1; else id_s = -1;
371 if (eid > 0) eid_s = 1; else eid_s = -1;
372 if (id_s * eid_s > 0) { /* sign should be different */
374 "Bad user/group dicotomy in membership list\n");
375 if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD;
378 /* count each user as a group, and each group a user is in */
379 if ((id >= misc->minId) && (id <= misc->maxId) &&
381 misc->idmap[id - misc->minId]++;
383 else if (head) count=9999;
388 head = ntohl(cheader.freePtr);
393 for (na=head; na; na=ntohl(c.next)) {
394 code = ConvertDiskAddress (na, &ni);
396 fprintf (stderr, "Bad continuation ptr %d", na);
397 if (e == 0) fprintf (stderr, "walking free list");
398 else if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD;
400 fprintf (stderr, "last block: \n");
401 if (PrintEntryError (misc, na, &c, 4)) return PRDBBAD;
405 code = pr_Read (na, (char *)&c, sizeof(c));
406 if (code) return code;
410 fprintf (stderr, "Continuation entry reused\n");
411 if (e == 0) fprintf (stderr, "walking free list");
412 else if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD;
413 if (PrintEntryError (misc, na, &c, 4)) return PRDBBAD;
418 if (e && (ntohl(c.id) != eid)) {
419 fprintf (stderr, "Continuation id mismatch\n");
420 if (e == 0) fprintf (stderr, "walking free list");
421 else if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD;
422 if (PrintEntryError (misc, na, &c, 4)) return PRDBBAD;
427 /* update membership count */
428 if (e) for (i=0; i<COSIZE; i++) {
429 afs_int32 id = ntohl(c.entries[i]);
430 if (id == PRBADID) continue;
434 /* in case the ids are large, convert to pure sign. */
435 if (id > 0) id_s = 1; else id_s = -1;
436 if (eid > 0) eid_s = 1; else eid_s = -1;
437 if (id_s * eid_s > 0) { /* sign should be different */
439 "Bad user/group dicotomy in membership list\n");
440 if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD;
441 if (PrintEntryError (misc, na, &c, 4)) return PRDBBAD;
444 /* count each user as a group, and each group a user is in */
445 if ((id >= misc->minId) && (id <= misc->maxId) &&
447 misc->idmap[id - misc->minId]++;
449 else if (c.next) count = 9999;
453 if (e && noErrors && (count != ntohl(e->count))) {
454 if (count > 9999) fprintf (stderr, "Membership list ends early\n");
455 fprintf (stderr, "Count was %d should be %d\n",
456 count, ntohl(e->count));
457 if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD;
461 if (length > misc->maxContLength) misc->maxContLength = length;
463 else misc->freeLength = length;
468 afs_int32 WalkOwnedChain (map, misc, ea, e)
469 char map[]; /* one byte per db entry */
470 struct misc_data *misc; /* stuff to keep track of */
476 struct prentry c; /* continuation entry */
477 afs_int32 na; /* next thread */
480 int length; /* length of chain */
483 head = ntohl(e->owned);
486 else head = ntohl(cheader.orphan);
489 for (na=head; na; na=ntohl(c.nextOwned)) {
490 code = ConvertDiskAddress (na, &ni);
492 fprintf (stderr, "Bad owned list ptr %d", na);
493 if (e == 0) fprintf (stderr, "walking orphan list");
494 else if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD;
496 fprintf (stderr, "last block: \n");
497 if (PrintEntryError (misc, na, &c, 4)) return PRDBBAD;
501 code = pr_Read (na, (char *)&c, sizeof(c));
502 if (code) return code;
505 if (map[ni] & MAP_OWNED) {
506 fprintf (stderr, "Entry on multiple owner chains\n");
507 if (e == 0) fprintf (stderr, "walking orphan list");
508 else if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD;
509 if (PrintEntryError (misc, na, &c, 4)) return PRDBBAD;
512 map[ni] |= MAP_OWNED;
513 if ((map[ni] & MAP_HASHES) != MAP_HASHES) {
514 fprintf (stderr, "Owned entry not hashed properly\n");
516 if (e == 0) fprintf (stderr, "walking orphan list");
517 else if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD;
518 if (PrintEntryError (misc, na, &c, 4)) return PRDBBAD;
522 if (ntohl(c.owner) != eid) {
523 fprintf (stderr, "Owner id mismatch\n");
527 else /* orphan */ if (c.owner) {
528 fprintf (stderr, "Orphan group owner not zero\n");
534 if (length > misc->maxOwnerLength) misc->maxOwnerLength = length;
536 else misc->orphanLength = length;
541 afs_int32 WalkChains (map, misc)
542 char map[]; /* one byte per db entry */
543 struct misc_data *misc; /* stuff to keep track of */
547 afs_int32 ea; /* entry's db addr */
552 /* check all entries found in hash table walks */
553 for (ei=0; ei < misc->nEntries; ei++) if (map[ei] & MAP_HASHES) {
554 ea = ei * sizeof(struct prentry) + sizeof(cheader);
555 code = pr_Read (ea, (char *)&e, sizeof(e));
556 if (code) return code;
558 if ((map[ei] & MAP_HASHES) != MAP_HASHES) {
559 fprintf (stderr, "entry not in both hashtables\n");
560 if ((map[ei] & MAP_NAMEHASH) != MAP_NAMEHASH)
561 fprintf (stderr, "--> entry not in Name hashtable\n");
562 if ((map[ei] & MAP_IDHASH) != MAP_IDHASH)
563 fprintf (stderr, "--> entry not in ID hashtable\n");
566 if (PrintEntryError (misc, ea, &e, 2)) return PRDBBAD;
572 type = ntohl (e.flags) & PRTYPE;
576 fprintf (stderr, "Group id not negative\n");
579 /* special case sysadmin: it owns itself */
580 if (id == SYSADMINID) {
581 if (ntohl(e.owner) != SYSADMINID) {
583 "System:administrators doesn't own itself\n");
587 code = WalkOwnedChain (map, misc, ea, &e);
588 if (code) return code;
589 code = WalkNextChain (map, misc, ea, &e);
590 if (code) return code;
595 fprintf (stderr, "User id negative\n");
599 /* Users are owned by sysadmin, but sysadmin doesn't have an owner
600 * chain. Check this then set the owned bit. */
601 if (ntohl(e.owner) != SYSADMINID) {
602 fprintf (stderr, "User not owned by system:administrators\n");
606 fprintf (stderr, "User has owned pointer\n");
609 map[ei] |= MAP_OWNED;
611 code = WalkOwnedChain (map, misc, ea, &e);
612 if (code) return code;
613 code = WalkNextChain (map, misc, ea, &e);
614 if (code) return code;
615 if (strchr(e.name,'@') == 0) {
616 misc->nusers++; /* Not a foreign user */
618 misc->nforeigns++; /* A foreign user */
627 fprintf (stderr, "ENTRY IS unexpected type [PRFOREIGN] (flags=0x%x)\n", e.flags);
633 fprintf (stderr, "entry with unexpected type");
641 afs_int32 GC (map, misc)
643 struct misc_data *misc;
651 for (ei=0; ei<misc->nEntries; ei++) {
652 ea = ei * sizeof(struct prentry) + sizeof(cheader);
653 code = pr_Read (ea, (char *)&e, sizeof(e));
654 if (code) return code;
657 fprintf (stderr, "Unreferenced entry:");
658 if (PrintEntryError (misc, ea, &e, 2)) return PRDBBAD;
660 /* all users and groups should be owned, and their membership counts
662 else if ((m & MAP_HASHES) == MAP_HASHES) {
665 if (!(m & MAP_OWNED)) {
666 fprintf (stderr, "Entry not on any owner chain:\n");
667 if (PrintEntryError (misc, ea, &e, 2)) return PRDBBAD;
670 if ((id >= misc->minId) && (id <= misc->maxId) &&
671 (id != ANONYMOUSID) &&
672 ((refCount = misc->idmap[id - misc->minId]) !=
675 fprintf (stderr, "Entry membership count is inconsistent: %d entries refer to this one\n", refCount);
676 if (PrintEntryError (misc, ea, &e, 2)) return PRDBBAD;
678 /* get continuation blocks too */
679 for (na=ntohl(e.next); na; na=ntohl(e.next)) {
681 code = ConvertDiskAddress (na, &ni);
682 if (code) return code;
683 code = pr_Read (na, (char *)&e, sizeof(e));
684 if (code) return code;
685 if (PrintEntryError (misc, na, &e, 4)) return PRDBBAD;
697 if (strpbrk (s," \t")) {
698 qs = (char *)malloc (strlen(s)+3);
706 afs_int32 DumpRecreate (map, misc)
708 struct misc_data *misc;
718 int builtinUsers = 0;
719 int createLow = 0; /* users uncreate from here */
720 afs_int32 *idmap; /* map of all id's */
726 memset(idmap, 0, misc->idRange*sizeof(misc->idmap[0]));
729 for (ei=createLow; ei<misc->nEntries; ei++) {
730 if ((map[ei] & MAP_HASHES) &&
731 (map[ei] & MAP_RECREATE) == 0) {
736 ea = ei * sizeof(struct prentry) + sizeof(cheader);
737 code = pr_Read (ea, (char *)&e, sizeof(e));
738 if (code) return code;
740 if (misc->listentries)
741 pr_PrintEntry(stdout, 0/*not in host order*/, ea, &e, 0);
744 flags = ntohl(e.flags);
745 owner = ntohl(e.owner);
746 name = QuoteName(e.name);
748 if (!strcmp (e.name, "system:administrators") ||
749 !strcmp (e.name, "system:anyuser") ||
750 !strcmp (e.name, "system:authuser") ||
751 !strcmp (e.name, "system:backup") ||
752 !strcmp (e.name, "anonymous")) {
757 /* check for duplicate id. This may still lead to duplicate
759 if (idmap[id-misc->minId]) {
761 "Skipping entry with duplicate id %di\n", id);
765 /* If owner doesn't exist skip for now, unless we're our own
766 * owner. If so, a special case allows a group to own itself
767 * if caller is sysadmin. This leaves only owner cycles to
770 if ((owner < misc->minId) || (owner > misc->maxId)) {
771 if (owner == ANONYMOUSID) fprintf (stderr, "Warning: id %di is owned by ANONYMOUS; using sysadmin instead\n", id);
772 else fprintf (stderr, "Bogus owner (%d) of id %di; using sysadmin instead\n", owner, id);
777 "Warning: group %s is self owning\n", name);
779 else if (owner == 0) {
780 fprintf (stderr, "Warning: orphan group %s will become self owning.\n", name);
783 else if (idmap[owner-misc->minId] == 0) goto user_skip;
785 if (rc) fprintf (rc, "cr %s %d %d\n", name, id, owner);
787 gq = uq = access = mask = 0;
788 if (flags & PRACCESS) {
789 access = (flags >> PRIVATE_SHIFT);
790 mask |= PR_SF_ALLBITS;
792 if (flags & PRQUOTA) {
793 gq = ntohl(e.ngroups);
794 uq = ntohl(e.nusers);
795 mask |= PR_SF_NGROUPS | PR_SF_NUSERS;
798 fprintf (rc, "sf %d %x %x %d %d\n",
799 id, mask, access, gq, uq);
802 map[ei] |= MAP_RECREATE;
803 if (id != ANONYMOUSID) idmap[id-misc->minId]++;
806 /* bump low water mark if possible */
807 if (ei == createLow) createLow++;
813 /* Now create the entries with circular owner dependencies and make them
814 * own themselves. This is the only way to create them with the correct
816 for (ei=0; ei<misc->nEntries; ei++)
817 if (((map[ei] & MAP_HASHES) == MAP_HASHES) &&
818 (map[ei] & MAP_RECREATE) == 0) {
819 ea = ei * sizeof(struct prentry) + sizeof(cheader);
820 code = pr_Read (ea, (char *)&e, sizeof(e));
821 if (code) return code;
824 name = QuoteName(e.name);
825 fprintf (stderr, "Warning: group %s in self owning cycle\n", name);
826 if (rc) fprintf (rc, "cr %s %d %d\n", name, id, id);
827 idmap[id-misc->minId]++;
829 for (ei=0; ei<misc->nEntries; ei++)
830 if (((map[ei] & MAP_HASHES) == MAP_HASHES) &&
831 (map[ei] & MAP_RECREATE) == 0) {
832 ea = ei * sizeof(struct prentry) + sizeof(cheader);
833 code = pr_Read (ea, (char *)&e, sizeof(e));
834 if (code) return code;
836 owner = ntohl(e.owner);
837 if (idmap[owner-misc->minId] == 0) {
839 "Skipping chown of '%s' to non-existant owner %di\n",
842 else if (rc) fprintf (rc, "ce %d \"\" %d 0\n",
843 ntohl(e.id), e.owner);
846 if (rc == 0) return 0;
848 /* Reconstruct membership information based on the groups' user lists. */
849 for (ei=0; ei<misc->nEntries; ei++) {
850 if ((map[ei] & MAP_HASHES) == MAP_HASHES) {
851 ea = ei * sizeof(struct prentry) + sizeof(cheader);
852 code = pr_Read (ea, (char *)&e, sizeof(e));
853 if (code) return code;
856 flags = ntohl(e.flags);
858 if ((id < 0) && (flags & PRGRP)) {
862 for (i=0; i<PRSIZE; i++) {
863 afs_int32 uid = ntohl(e.entries[i]);
865 if (uid == PRBADID) continue;
867 fprintf (rc, "au %d %d\n", uid, id);
869 } else fprintf (stderr,
870 "Skipping %di in group %di\n", uid, id);
875 code = pr_Read (na, (char *)&c, sizeof(c));
876 if (code) return code;
878 if ((id == ntohl(c.id)) && (ntohl(c.flags) & PRCONT)) {
879 for (i=0; i<COSIZE; i++) {
880 afs_int32 uid = ntohl(c.entries[i]);
882 if (uid == PRBADID) continue;
884 fprintf (rc, "au %d %d\n", uid, id);
886 } else fprintf (stderr,
887 "Skipping %di in group %di\n",
892 "Skipping continuation block at %d\n", na);
897 if (count != ntohl(e.count))
898 fprintf (stderr, "Group membership count problem found %d should be %d\n", count, ntohl(e.count));
899 } else if ((id < 0) || (flags & PRGRP)) {
900 fprintf (stderr, "Skipping group %di\n", id);
907 afs_int32 CheckPrDatabase (misc)
908 struct misc_data *misc; /* info & statistics */
913 char *map; /* map of each entry in db */
915 eof = ntohl (cheader.eofPtr);
916 eof -= sizeof(cheader);
917 n = eof / sizeof(struct prentry);
918 if ((eof < 0) || (n*sizeof(struct prentry) != eof)) {
920 com_err (whoami, code,
921 "eof ptr no good: eof=%d, sizeof(prentry)=%d",
922 eof, sizeof(struct prentry));
927 printf ("Database has %d entries\n", n);
928 map = (char *)malloc (n);
933 printf ("\nChecking name hash table\n");
936 code = WalkHashTable (cheader.nameHash, MAP_NAMEHASH, map, misc);
938 com_err (whoami, code, "walking name hash");
942 printf ("\nChecking id hash table\n");
945 code = WalkHashTable (cheader.idHash, MAP_IDHASH, map, misc);
947 com_err (whoami, code, "walking id hash");
951 /* hash walk calculates min and max id */
952 n = ((misc->maxId > misc->maxForId) ? misc->maxId : misc->maxForId);
953 misc->idRange = n - misc->minId + 1;
954 misc->idmap = (afs_int32 *)malloc (misc->idRange * sizeof(afs_int32));
956 com_err (whoami, 0, "Unable to malloc space for max ids of %d",
961 memset(misc->idmap, 0, misc->idRange*sizeof(misc->idmap[0]));
964 printf ("\nChecking entry chains\n");
967 code = WalkChains (map, misc);
969 com_err (whoami, code, "walking chains");
973 printf ("\nChecking free list\n");
976 code = WalkNextChain (map, misc, 0, 0);
978 com_err (whoami, code, "walking free list");
982 printf ("\nChecking orphans list\n");
985 code = WalkOwnedChain (map, misc, 0, 0);
987 com_err (whoami, code, "walking orphan list");
992 printf ("\nChecking for unreferenced entries\n");
995 code = GC (map, misc);
997 com_err (whoami, code, "looking for unreferenced entries");
1001 DumpRecreate (map, misc); /* check for owner cycles */
1002 if (misc->recreate) fclose (misc->recreate);
1004 if (misc->anon != 2) /* once for each hash table */
1005 fprintf (stderr, "Problems with ANON=%d\n", misc->anon);
1006 if (misc->ncells || misc->ninsts)
1007 fprintf (stderr, "Unexpected entry type\n");
1008 if (misc->nusers != ntohl(cheader.usercount)) {
1010 "User count inconsistent: should be %d, header claims: %d\n",
1011 misc->nusers, ntohl(cheader.usercount));
1013 if (misc->ngroups != ntohl(cheader.groupcount)) {
1015 "Group count inconsistent: should be %d, header claims: %d\n",
1016 misc->ngroups, ntohl(cheader.groupcount));
1018 if (misc->maxId > ntohl(cheader.maxID))
1019 fprintf (stderr, "Database's max user Id (%d) is smaller than largest user's Id (%d).\n", ntohl(cheader.maxID), misc->maxId);
1020 if (misc->minId < ntohl(cheader.maxGroup))
1021 fprintf (stderr, "Database's max group Id (%d) is smaller than largest group's Id (%d).\n", ntohl(cheader.maxGroup), misc->minId);
1023 if (misc->verbose) {
1024 printf ("\nMaxId = %d, MinId = %d, MaxForeignId = %d\n",
1025 misc->maxId, misc->minId, misc->maxForId);
1026 printf ("Free list is %d entries in length, %d groups on orphan list\n",
1027 misc->freeLength, misc->orphanLength);
1028 printf ("The longest owner list is %d, the longest continuation block chain is %d\n",
1029 misc->maxOwnerLength, misc->maxContLength);
1030 printf ("%d users ; %d foreign users ; and %d groups\n",
1031 misc->nusers, misc->nforeigns, misc->ngroups);
1037 #include "AFS_component_version_number.c"
1039 WorkerBee (as, arock)
1040 struct cmd_syndesc *as;
1045 struct misc_data misc; /* info & statistics */
1047 initialize_PT_error_table();
1048 initialize_U_error_table();
1050 pr_dbaseName = AFSDIR_SERVER_PRDB_FILEPATH;
1051 memset(&misc, 0, sizeof(misc));
1053 pr_dbaseName = as->parms[0].items->data; /* -database */
1054 misc.listuheader = (as->parms[1].items ? 1 : 0); /* -uheader */
1055 misc.listpheader = (as->parms[2].items ? 1 : 0); /* -pheader */
1056 misc.listentries = (as->parms[3].items ? 1 : 0); /* -entries */
1057 misc.verbose = (as->parms[4].items ? 1 : 0); /* -verbose */
1058 recreateFile = (as->parms[5].items ? as->parms[5].items->data :
1059 (char *)0); /* -rebuild */
1061 fd = open (pr_dbaseName, O_RDONLY, 0);
1063 com_err (whoami, errno, "Open failed on db %s", pr_dbaseName);
1067 /* Read the ubik header */
1068 if (misc.listuheader) {
1069 readUbikHeader(&misc);
1072 code = ReadHeader();
1073 if (code) return code;
1074 if (misc.listpheader) printheader(&cheader);
1077 misc.recreate = fopen (recreateFile, "w");
1078 if (misc.recreate == 0) {
1079 com_err (whoami, errno,
1080 "can't create file for recreation instructions: %s",
1085 code = CheckPrDatabase (&misc);
1087 com_err (whoami, code, "Checking prserver database");
1097 struct cmd_syndesc *ts;
1101 ts=cmd_CreateSyntax((char *)0, WorkerBee, (char *)0, "PRDB check");
1102 cmd_AddParm(ts, "-database", CMD_SINGLE, CMD_REQUIRED, "ptdb_file");
1103 cmd_AddParm(ts, "-uheader", CMD_FLAG, CMD_OPTIONAL, "Display UBIK header");
1104 cmd_AddParm(ts, "-pheader", CMD_FLAG, CMD_OPTIONAL, "Display KADB header");
1105 cmd_AddParm(ts, "-entries", CMD_FLAG, CMD_OPTIONAL, "Display entries");
1106 cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, "verbose");
1107 cmd_AddParm(ts, "-rebuild", CMD_SINGLE, CMD_OPTIONAL|CMD_HIDE, "out_file");
1109 return cmd_Dispatch(argc, argv);