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 PrintContError(struct misc_data
*misc
, afs_int32 ea
, struct contentry
*c
, int indent
)
266 pr_PrintContEntry(stderr
, /*net order */ 0, ea
, c
, indent
);
271 WalkHashTable(afs_int32 hashtable
[], /* hash table to walk */
272 int hashType
, /* hash function to use */
273 char map
[], /* one byte per db entry */
274 struct misc_data
*misc
) /* stuff to keep track of */
277 int hi
; /* index in hash table */
278 afs_int32 ea
; /* entry's db addr */
279 int ei
; /* entry's index */
280 char bit
; /* bits to check for in map */
289 for (hi
= 0; hi
< HASHSIZE
; hi
++) {
291 next_ea
= ntohl(hashtable
[hi
]);
293 code
= ConvertDiskAddress(next_ea
, &ei
);
295 fprintf(stderr
, "Bad chain address %d\n", next_ea
);
297 fprintf(stderr
, "Last entry in chain:\n");
298 if (PrintEntryError(misc
, ea
, &e
, 2))
301 fprintf(stderr
, "Skipping remainder of hash bucket %d\n", hi
);
305 code
= pr_Read(ea
, (char *)&e
, sizeof(e
));
311 if (((e
.flags
& htonl((PRGRP
| PRINST
))) == 0)
312 && (strchr(e
.name
, '@'))) {
314 if (id
> misc
->maxForId
)
317 if (id
== ANONYMOUSID
)
319 else if (id
> misc
->maxId
)
321 if (id
< misc
->minId
)
327 next_ea
= ntohl(e
.nextName
);
328 hash
= NameHash(e
.name
);
331 next_ea
= ntohl(e
.nextID
);
335 fprintf(stderr
, "unknown hash table type %d\n", hashType
);
341 "Entry found twice in hash table: bucket %d\n", hi
);
343 fprintf(stderr
, "also in wrong bucket: should be in %d\n",
345 if (PrintEntryError(misc
, ea
, &e
, 2))
351 flags
= ntohl(e
.flags
);
352 switch (flags
& PRTYPE
) {
354 fprintf(stderr
, "ENTRY IS FREE");
357 fprintf(stderr
, "ENTRY IS CONTINUATION");
365 fprintf(stderr
, "ENTRY IS unexpected type (flags=0x%x)\n",
369 fprintf(stderr
, "ENTRY IS OF unknown type (flags=0x%x)\n",
375 fprintf(stderr
, "entry hashed in bucket %d should be %d\n",
378 if (PrintEntryError(misc
, ea
, &e
, 2))
388 WalkNextChain(char map
[], /* one byte per db entry */
389 struct misc_data
*misc
, /* stuff to keep track of */
390 afs_int32 ea
, struct prentry
*e
)
395 struct contentry c
; /* continuation entry */
396 afs_int32 na
; /* next thread */
399 int count
= 0; /* number of members, set to > 9999 if */
400 /* list ends early */
403 int length
; /* length of chain */
404 #if defined(SUPERGROUPS)
405 int sgcount
= 0; /* number of sgentrys */
407 #define g (((struct prentryg *)e))
411 head
= ntohl(e
->next
);
414 #if defined(SUPERGROUPS)
415 sghead
= ntohl(g
->next
);
417 for (i
= 0; i
< PRSIZE
; i
++) {
418 afs_int32 id
= ntohl(e
->entries
[i
]);
424 /* in case the ids are large, convert to pure sign. */
433 #if defined(SUPERGROUPS)
434 if (id_s
> 0 && eid_s
> 0) {
436 "User can't be member of user in membership list\n");
437 if (PrintEntryError(misc
, ea
, e
, 2))
442 if (id_s
* eid_s
> 0) { /* sign should be different */
444 "Bad user/group dicotomy in membership list\n");
445 if (PrintEntryError(misc
, ea
, e
, 2))
449 #endif /* SUPERGROUPS */
450 /* count each user as a group, and each group a user is in */
451 #if defined(SUPERGROUPS)
452 if (!(id
< 0 && eid
< 0) && (id
!= ANONYMOUSID
))
453 inccount(&misc
->idmap
, id
);
455 if ((id
>= misc
->minId
) && (id
<= misc
->maxId
)
456 && (id
!= ANONYMOUSID
))
457 misc
->idmap
[id
- misc
->minId
]++;
458 #endif /* SUPERGROUPS */
464 #if defined(SUPERGROUPS)
465 sghead
= ntohl(g
->nextsg
);
466 if ((e
->flags
& htonl(PRGRP
))) {
467 for (i
= 0; i
< SGSIZE
; ++i
) {
468 afs_int32 id
= ntohl(g
->supergroup
[i
]);
474 "User can't be member of supergroup list\n");
475 if (PrintEntryError(misc
, ea
, e
, 2))
480 inccount(&misc
->idmap
, id
);
484 #endif /* SUPERGROUPS */
486 head
= ntohl(cheader
.freePtr
);
487 #if defined(SUPERGROUPS)
493 #if defined(SUPERGROUPS)
495 for (na
= sghead
; na
; na
= ntohl(c
.next
)) {
496 code
= ConvertDiskAddress(na
, &ni
);
498 fprintf(stderr
, "Bad SGcontinuation ptr %d", na
);
499 if (PrintEntryError(misc
, ea
, e
, 2))
502 fprintf(stderr
, "last block: \n");
503 if (PrintContError(misc
, na
, &c
, 4))
508 code
= pr_Read(na
, (char *)&c
, sizeof(c
));
514 fprintf(stderr
, "Continuation entry reused\n");
515 if (PrintEntryError(misc
, ea
, e
, 2))
517 if (PrintContError(misc
, na
, &c
, 4))
523 if ((ntohl(c
.id
) != eid
)) {
524 fprintf(stderr
, "Continuation id mismatch\n");
525 if (PrintEntryError(misc
, ea
, e
, 2))
527 if (PrintContError(misc
, na
, &c
, 4))
533 /* update membership count */
534 for (i
= 0; i
< COSIZE
; i
++) {
535 afs_int32 id
= ntohl(c
.entries
[i
]);
541 /* in case the ids are large, convert to pure sign. */
548 "User can't be member of supergroup list\n");
549 if (PrintEntryError(misc
, ea
, e
, 2))
551 if (PrintContError(misc
, na
, &c
, 4))
555 /* count each user as a group, and each group a user is in */
556 if ((id
!= ANONYMOUSID
))
557 inccount(&misc
->idmap
, id
);
564 if (length
> misc
->maxContLength
)
565 misc
->maxContLength
= length
;
566 #endif /* SUPERGROUPS */
568 for (na
= head
; na
; na
= ntohl(c
.next
)) {
569 code
= ConvertDiskAddress(na
, &ni
);
571 fprintf(stderr
, "Bad continuation ptr %d", na
);
573 fprintf(stderr
, "walking free list");
574 else if (PrintEntryError(misc
, ea
, e
, 2))
577 fprintf(stderr
, "last block: \n");
578 if (PrintContError(misc
, na
, &c
, 4))
583 code
= pr_Read(na
, (char *)&c
, sizeof(c
));
589 fprintf(stderr
, "Continuation entry reused\n");
591 fprintf(stderr
, "walking free list");
592 else if (PrintEntryError(misc
, ea
, e
, 2))
594 if (PrintContError(misc
, na
, &c
, 4))
600 if (e
&& (ntohl(c
.id
) != eid
)) {
601 fprintf(stderr
, "Continuation id mismatch\n");
603 fprintf(stderr
, "walking free list");
604 else if (PrintEntryError(misc
, ea
, e
, 2))
606 if (PrintContError(misc
, na
, &c
, 4))
612 /* update membership count */
614 for (i
= 0; i
< COSIZE
; i
++) {
615 afs_int32 id
= ntohl(c
.entries
[i
]);
621 /* in case the ids are large, convert to pure sign. */
630 #if defined(SUPERGROUPS)
631 if (id_s
> 0 && eid_s
> 0) {
633 "User can't be member of user in membership list\n");
634 if (PrintEntryError(misc
, ea
, e
, 2))
636 if (PrintContError(misc
, na
, &c
, 4))
641 if (id_s
* eid_s
> 0) { /* sign should be different */
643 "Bad user/group dicotomy in membership list\n");
644 if (PrintEntryError(misc
, ea
, e
, 2))
646 if (PrintContError(misc
, na
, &c
, 4))
650 #endif /* SUPERGROUPS */
651 /* count each user as a group, and each group a user is in */
652 #if defined(SUPERGROUPS)
653 if (!(id
< 0 && eid
< 0) && (id
!= ANONYMOUSID
))
654 inccount(&misc
->idmap
, id
);
656 if ((id
>= misc
->minId
) && (id
<= misc
->maxId
)
657 && (id
!= ANONYMOUSID
))
658 misc
->idmap
[id
- misc
->minId
]++;
659 #endif /* SUPERGROUPS */
666 if (e
&& noErrors
&& (count
!= ntohl(e
->count
))) {
667 #if defined(SUPERGROUPS)
669 fprintf(stderr
, "Membership list ends early\n");
672 fprintf(stderr
, "Membership list ends early\n");
673 #endif /* SUPERGROUPS */
674 fprintf(stderr
, "Count was %d should be %d\n", count
,
676 if (PrintEntryError(misc
, ea
, e
, 2))
678 #if defined(SUPERGROUPS)
681 if (e
&& (e
->flags
& htonl(PRGRP
)) && (sgcount
!= ntohl(g
->countsg
))) {
682 fprintf(stderr
, "SGCount was %d should be %d\n", sgcount
,
684 if (PrintEntryError(misc
, ea
, e
, 2))
690 if (length
> misc
->maxContLength
)
691 misc
->maxContLength
= length
;
693 misc
->freeLength
= length
;
696 #if defined(SUPERGROUPS)
702 WalkOwnedChain(char map
[], /* one byte per db entry */
703 struct misc_data
*misc
, /* stuff to keep track of */
704 afs_int32 ea
, struct prentry
*e
)
708 struct prentry te
; /* next entry in owner chain */
709 afs_int32 na
; /* next thread */
712 int length
; /* length of chain */
715 head
= ntohl(e
->owned
);
718 head
= ntohl(cheader
.orphan
);
721 for (na
= head
; na
; na
= ntohl(te
.nextOwned
)) {
722 code
= ConvertDiskAddress(na
, &ni
);
724 fprintf(stderr
, "Bad owned list ptr %d", na
);
726 fprintf(stderr
, "walking orphan list");
727 else if (PrintEntryError(misc
, ea
, e
, 2))
730 fprintf(stderr
, "last block: \n");
731 if (PrintEntryError(misc
, na
, &te
, 4))
736 code
= pr_Read(na
, (char *)&te
, sizeof(te
));
741 if ((ntohl(te
.flags
) & PRTYPE
) == PRCONT
) {
742 fprintf(stderr
, "Continuation entry found on owner chain\n");
744 fprintf(stderr
, "walking orphan list");
745 else if (PrintEntryError(misc
, ea
, e
, 2))
747 if (PrintEntryError(misc
, na
, &te
, 4))
751 if (map
[ni
] & MAP_OWNED
) {
752 fprintf(stderr
, "Entry on multiple owner chains\n");
754 fprintf(stderr
, "walking orphan list");
755 else if (PrintEntryError(misc
, ea
, e
, 2))
757 if (PrintEntryError(misc
, na
, &te
, 4))
761 map
[ni
] |= MAP_OWNED
;
762 if ((map
[ni
] & MAP_HASHES
) != MAP_HASHES
) {
763 fprintf(stderr
, "Owned entry not hashed properly\n");
766 fprintf(stderr
, "walking orphan list");
767 else if (PrintEntryError(misc
, ea
, e
, 2))
769 if (PrintEntryError(misc
, na
, &te
, 4))
774 if (ntohl(te
.owner
) != eid
) {
775 fprintf(stderr
, "Owner id mismatch\n");
778 } else /* orphan */ if (te
.owner
) {
779 fprintf(stderr
, "Orphan group owner not zero\n");
785 if (length
> misc
->maxOwnerLength
)
786 misc
->maxOwnerLength
= length
;
788 misc
->orphanLength
= length
;
794 WalkChains(char map
[], /* one byte per db entry */
795 struct misc_data
*misc
) /* stuff to keep track of */
799 afs_int32 ea
; /* entry's db addr */
804 /* check all entries found in hash table walks */
805 for (ei
= 0; ei
< misc
->nEntries
; ei
++)
806 if (map
[ei
] & MAP_HASHES
) {
807 ea
= ei
* sizeof(struct prentry
) + sizeof(cheader
);
808 code
= pr_Read(ea
, (char *)&e
, sizeof(e
));
812 if ((map
[ei
] & MAP_HASHES
) != MAP_HASHES
) {
813 fprintf(stderr
, "entry not in both hashtables\n");
814 if ((map
[ei
] & MAP_NAMEHASH
) != MAP_NAMEHASH
)
815 fprintf(stderr
, "--> entry not in Name hashtable\n");
816 if ((map
[ei
] & MAP_IDHASH
) != MAP_IDHASH
)
817 fprintf(stderr
, "--> entry not in ID hashtable\n");
820 if (PrintEntryError(misc
, ea
, &e
, 2))
827 type
= ntohl(e
.flags
) & PRTYPE
;
831 fprintf(stderr
, "Group id not negative\n");
834 /* special case sysadmin: it owns itself */
835 if (id
== SYSADMINID
) {
836 if (ntohl(e
.owner
) != SYSADMINID
) {
838 "System:administrators doesn't own itself\n");
842 code
= WalkOwnedChain(map
, misc
, ea
, &e
);
845 code
= WalkNextChain(map
, misc
, ea
, &e
);
852 #if defined(SUPERGROUPS)
853 fprintf(stderr
, "User id not positive\n");
855 fprintf(stderr
, "User id negative\n");
860 /* Users are owned by sysadmin, but sysadmin doesn't have an owner
861 * chain. Check this then set the owned bit. */
862 if (ntohl(e
.owner
) != SYSADMINID
) {
864 "User not owned by system:administrators\n");
868 fprintf(stderr
, "User has owned pointer\n");
871 map
[ei
] |= MAP_OWNED
;
873 code
= WalkOwnedChain(map
, misc
, ea
, &e
);
876 code
= WalkNextChain(map
, misc
, ea
, &e
);
879 if (strchr(e
.name
, '@') == 0) {
880 misc
->nusers
++; /* Not a foreign user */
882 misc
->nforeigns
++; /* A foreign user */
892 "ENTRY IS unexpected type [PRFOREIGN] (flags=0x%x)\n",
899 fprintf(stderr
, "entry with unexpected type");
908 GC(char map
[], struct misc_data
*misc
)
916 for (ei
= 0; ei
< misc
->nEntries
; ei
++) {
917 ea
= ei
* sizeof(struct prentry
) + sizeof(cheader
);
918 code
= pr_Read(ea
, (char *)&e
, sizeof(e
));
923 fprintf(stderr
, "Unreferenced entry:");
924 if (PrintEntryError(misc
, ea
, &e
, 2))
927 /* all users and groups should be owned, and their membership counts
929 else if ((m
& MAP_HASHES
) == MAP_HASHES
) {
932 if (!(m
& MAP_OWNED
)) {
933 fprintf(stderr
, "Entry not on any owner chain:\n");
934 if (PrintEntryError(misc
, ea
, &e
, 2))
938 #if defined(SUPERGROUPS)
939 if ((id
!= ANONYMOUSID
)
940 && ((refCount
= idcount(&misc
->idmap
, id
)) != ntohl(e
.count
)))
942 if ((id
>= misc
->minId
) && (id
<= misc
->maxId
)
943 && (id
!= ANONYMOUSID
)
944 && ((refCount
= misc
->idmap
[id
- misc
->minId
]) !=
946 #endif /* SUPERGROUPS */
950 "Entry membership count is inconsistent: %d entries refer to this one\n",
952 if (PrintEntryError(misc
, ea
, &e
, 2))
955 /* get continuation blocks too */
956 for (na
= ntohl(e
.next
); na
; na
= ntohl(e
.next
)) {
958 code
= ConvertDiskAddress(na
, &ni
);
961 code
= pr_Read(na
, (char *)&e
, sizeof(e
));
964 if (PrintEntryError(misc
, na
, &e
, 4))
977 if (strpbrk(s
, " \t")) {
978 if (asprintf(&qs
, "\"%s\"", s
) < 0)
979 qs
= "<<-OUT-OF-MEMORY->>";
986 DumpRecreate(char map
[], struct misc_data
*misc
)
996 int builtinUsers
= 0;
997 int createLow
= 0; /* users uncreate from here */
998 #if defined(SUPERGROUPS)
999 struct idused
*idmap
; /* map of all id's */
1001 afs_int32
*idmap
; /* map of all id's */
1006 rc
= misc
->recreate
;
1007 idmap
= misc
->idmap
;
1008 #if defined(SUPERGROUPS)
1011 memset(idmap
, 0, misc
->idRange
* sizeof(misc
->idmap
[0]));
1015 for (ei
= createLow
; ei
< misc
->nEntries
; ei
++) {
1016 if ((map
[ei
] & MAP_HASHES
) && (map
[ei
] & MAP_RECREATE
) == 0) {
1021 ea
= ei
* sizeof(struct prentry
) + sizeof(cheader
);
1022 code
= pr_Read(ea
, (char *)&e
, sizeof(e
));
1026 if (misc
->listentries
)
1027 pr_PrintEntry(stdout
, 0 /*not in host order */ , ea
, &e
,
1031 flags
= ntohl(e
.flags
);
1032 owner
= ntohl(e
.owner
);
1033 name
= QuoteName(e
.name
);
1035 if (!strcmp(e
.name
, "system:administrators")
1036 || !strcmp(e
.name
, "system:anyuser")
1037 || !strcmp(e
.name
, "system:authuser")
1038 || !strcmp(e
.name
, "system:backup")
1039 || !strcmp(e
.name
, "anonymous")) {
1044 /* check for duplicate id. This may still lead to duplicate
1046 #if defined(SUPERGROUPS)
1047 if (idcount(&idmap
, id
))
1049 if (idmap
[id
- misc
->minId
])
1052 fprintf(stderr
, "Skipping entry with duplicate id %di\n",
1057 /* If owner doesn't exist skip for now, unless we're our own
1058 * owner. If so, a special case allows a group to own itself
1059 * if caller is sysadmin. This leaves only owner cycles to
1062 if ((owner
< misc
->minId
) || (owner
> misc
->maxId
)) {
1063 if (owner
== ANONYMOUSID
)
1065 "Warning: id %di is owned by ANONYMOUS; using sysadmin instead\n",
1069 "Bogus owner (%d) of id %di; using sysadmin instead\n",
1074 fprintf(stderr
, "Warning: group %s is self owning\n",
1076 } else if (owner
== 0) {
1078 "Warning: orphan group %s will become self owning.\n",
1082 #if defined(SUPERGROUPS)
1083 else if (!idcount(&idmap
, owner
))
1086 else if (idmap
[owner
- misc
->minId
] == 0)
1091 fprintf(rc
, "cr %s %d %d\n", name
, id
, owner
);
1093 gq
= uq
= access
= mask
= 0;
1094 if (flags
& PRACCESS
) {
1095 access
= (flags
>> PRIVATE_SHIFT
);
1096 mask
|= PR_SF_ALLBITS
;
1098 if (flags
& PRQUOTA
) {
1099 gq
= ntohl(e
.ngroups
);
1100 uq
= ntohl(e
.nusers
);
1101 mask
|= PR_SF_NGROUPS
| PR_SF_NUSERS
;
1104 fprintf(rc
, "sf %d %x %x %d %d\n", id
, mask
, access
, gq
,
1108 map
[ei
] |= MAP_RECREATE
;
1109 #if defined(SUPERGROUPS)
1110 if (id
!= ANONYMOUSID
)
1111 inccount(&idmap
, id
);
1113 if (id
!= ANONYMOUSID
)
1114 idmap
[id
- misc
->minId
]++;
1118 /* bump low water mark if possible */
1119 if (ei
== createLow
)
1126 /* Now create the entries with circular owner dependencies and make them
1127 * own themselves. This is the only way to create them with the correct
1129 for (ei
= 0; ei
< misc
->nEntries
; ei
++)
1130 if (((map
[ei
] & MAP_HASHES
) == MAP_HASHES
)
1131 && (map
[ei
] & MAP_RECREATE
) == 0) {
1132 ea
= ei
* sizeof(struct prentry
) + sizeof(cheader
);
1133 code
= pr_Read(ea
, (char *)&e
, sizeof(e
));
1138 name
= QuoteName(e
.name
);
1139 fprintf(stderr
, "Warning: group %s in self owning cycle\n", name
);
1141 fprintf(rc
, "cr %s %d %d\n", name
, id
, id
);
1142 #if defined(SUPERGROUPS)
1143 inccount(&idmap
, id
);
1145 idmap
[id
- misc
->minId
]++;
1148 for (ei
= 0; ei
< misc
->nEntries
; ei
++)
1149 if (((map
[ei
] & MAP_HASHES
) == MAP_HASHES
)
1150 && (map
[ei
] & MAP_RECREATE
) == 0) {
1151 ea
= ei
* sizeof(struct prentry
) + sizeof(cheader
);
1152 code
= pr_Read(ea
, (char *)&e
, sizeof(e
));
1156 owner
= ntohl(e
.owner
);
1157 #if defined(SUPERGROUPS)
1158 if (!idcount(&idmap
, owner
))
1160 if (idmap
[owner
- misc
->minId
] == 0)
1164 "Skipping chown of '%s' to non-existant owner %di\n",
1167 fprintf(rc
, "ce %d \"\" %d 0\n", ntohl(e
.id
), e
.owner
);
1173 /* Reconstruct membership information based on the groups' user lists. */
1174 for (ei
= 0; ei
< misc
->nEntries
; ei
++) {
1175 if ((map
[ei
] & MAP_HASHES
) == MAP_HASHES
) {
1176 ea
= ei
* sizeof(struct prentry
) + sizeof(cheader
);
1177 code
= pr_Read(ea
, (char *)&e
, sizeof(e
));
1182 flags
= ntohl(e
.flags
);
1184 if ((id
< 0) && (flags
& PRGRP
)) {
1188 for (i
= 0; i
< PRSIZE
; i
++) {
1189 afs_int32 uid
= ntohl(e
.entries
[i
]);
1194 #if !defined(SUPERGROUPS)
1197 fprintf(rc
, "au %d %d\n", uid
, id
);
1199 #if !defined(SUPERGROUPS)
1201 fprintf(stderr
, "Skipping %di in group %di\n", uid
,
1208 code
= pr_Read(na
, (char *)&c
, sizeof(c
));
1212 if ((id
== ntohl(c
.id
)) && (c
.flags
& htonl(PRCONT
))) {
1213 for (i
= 0; i
< COSIZE
; i
++) {
1214 afs_int32 uid
= ntohl(c
.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",
1231 fprintf(stderr
, "Skipping continuation block at %d\n",
1237 if (count
!= ntohl(e
.count
))
1239 "Group membership count problem found %d should be %d\n",
1240 count
, ntohl(e
.count
));
1241 } else if ((id
< 0) || (flags
& PRGRP
)) {
1242 fprintf(stderr
, "Skipping group %di\n", id
);
1250 CheckPrDatabase(struct misc_data
*misc
) /* info & statistics */
1255 char *map
; /* map of each entry in db */
1257 eof
= ntohl(cheader
.eofPtr
);
1258 eof
-= sizeof(cheader
);
1259 n
= eof
/ sizeof(struct prentry
);
1260 if ((eof
< 0) || (n
* sizeof(struct prentry
) != eof
)) {
1262 afs_com_err(whoami
, code
,
1263 "eof ptr no good: eof=%d, sizeof(prentry)=%" AFS_SIZET_FMT
,
1264 eof
, sizeof(struct prentry
));
1269 printf("Database has %d entries\n", n
);
1273 if (misc
->verbose
) {
1274 printf("\nChecking name hash table\n");
1277 code
= WalkHashTable(cheader
.nameHash
, MAP_NAMEHASH
, map
, misc
);
1279 afs_com_err(whoami
, code
, "walking name hash");
1282 if (misc
->verbose
) {
1283 printf("\nChecking id hash table\n");
1286 code
= WalkHashTable(cheader
.idHash
, MAP_IDHASH
, map
, misc
);
1288 afs_com_err(whoami
, code
, "walking id hash");
1292 /* hash walk calculates min and max id */
1293 #if defined(SUPERGROUPS)
1296 n
= ((misc
->maxId
> misc
->maxForId
) ? misc
->maxId
: misc
->maxForId
);
1297 misc
->idRange
= n
- misc
->minId
+ 1;
1298 misc
->idmap
= calloc(misc
->idRange
, sizeof(afs_int32
));
1300 afs_com_err(whoami
, 0, "Unable to malloc space for max ids of %d",
1305 #endif /* SUPERGROUPS */
1307 if (misc
->verbose
) {
1308 printf("\nChecking entry chains\n");
1311 code
= WalkChains(map
, misc
);
1313 afs_com_err(whoami
, code
, "walking chains");
1316 if (misc
->verbose
) {
1317 printf("\nChecking free list\n");
1320 code
= WalkNextChain(map
, misc
, 0, 0);
1322 afs_com_err(whoami
, code
, "walking free list");
1325 if (misc
->verbose
) {
1326 printf("\nChecking orphans list\n");
1329 code
= WalkOwnedChain(map
, misc
, 0, 0);
1331 afs_com_err(whoami
, code
, "walking orphan list");
1335 if (misc
->verbose
) {
1336 printf("\nChecking for unreferenced entries\n");
1339 code
= GC(map
, misc
);
1341 afs_com_err(whoami
, code
, "looking for unreferenced entries");
1345 DumpRecreate(map
, misc
); /* check for owner cycles */
1347 fclose(misc
->recreate
);
1349 if (misc
->anon
!= 2) /* once for each hash table */
1350 fprintf(stderr
, "Problems with ANON=%d\n", misc
->anon
);
1351 if (misc
->ncells
|| misc
->ninsts
)
1352 fprintf(stderr
, "Unexpected entry type\n");
1353 if (misc
->nusers
!= ntohl(cheader
.usercount
)) {
1355 "User count inconsistent: should be %d, header claims: %d\n",
1356 misc
->nusers
, ntohl(cheader
.usercount
));
1358 if (misc
->ngroups
!= ntohl(cheader
.groupcount
)) {
1360 "Group count inconsistent: should be %d, header claims: %d\n",
1361 misc
->ngroups
, ntohl(cheader
.groupcount
));
1363 if (misc
->maxId
> ntohl(cheader
.maxID
))
1365 "Database's max user Id (%d) is smaller than largest user's Id (%d).\n",
1366 ntohl(cheader
.maxID
), misc
->maxId
);
1367 if (misc
->minId
< ntohl(cheader
.maxGroup
))
1369 "Database's max group Id (%d) is smaller than largest group's Id (%d).\n",
1370 ntohl(cheader
.maxGroup
), misc
->minId
);
1372 if (misc
->verbose
) {
1373 printf("\nMaxId = %d, MinId = %d, MaxForeignId = %d\n", misc
->maxId
,
1374 misc
->minId
, misc
->maxForId
);
1376 ("Free list is %d entries in length, %d groups on orphan list\n",
1377 misc
->freeLength
, misc
->orphanLength
);
1379 ("The longest owner list is %d, the longest continuation block chain is %d\n",
1380 misc
->maxOwnerLength
, misc
->maxContLength
);
1381 printf("%d users ; %d foreign users ; and %d groups\n", misc
->nusers
,
1382 misc
->nforeigns
, misc
->ngroups
);
1389 #include "AFS_component_version_number.c"
1392 WorkerBee(struct cmd_syndesc
*as
, void *arock
)
1396 struct misc_data misc
; /* info & statistics */
1398 initialize_PT_error_table();
1399 initialize_U_error_table();
1401 pr_dbaseName
= AFSDIR_SERVER_PRDB_FILEPATH
;
1402 memset(&misc
, 0, sizeof(misc
));
1404 pr_dbaseName
= as
->parms
[0].items
->data
; /* -database */
1405 misc
.listuheader
= (as
->parms
[1].items
? 1 : 0); /* -uheader */
1406 misc
.listpheader
= (as
->parms
[2].items
? 1 : 0); /* -pheader */
1407 misc
.listentries
= (as
->parms
[3].items
? 1 : 0); /* -entries */
1408 misc
.verbose
= (as
->parms
[4].items
? 1 : 0); /* -verbose */
1409 recreateFile
= (as
->parms
[5].items
? as
->parms
[5].items
->data
: NULL
); /* -rebuild */
1411 fd
= open(pr_dbaseName
, O_RDONLY
, 0);
1413 afs_com_err(whoami
, errno
, "Open failed on db %s", pr_dbaseName
);
1417 /* Read the ubik header */
1418 if (misc
.listuheader
) {
1419 readUbikHeader(&misc
);
1422 code
= ReadHeader();
1425 if (misc
.listpheader
)
1426 printheader(&cheader
);
1429 misc
.recreate
= fopen(recreateFile
, "w");
1430 if (misc
.recreate
== 0) {
1431 afs_com_err(whoami
, errno
,
1432 "can't create file for recreation instructions: %s",
1437 code
= CheckPrDatabase(&misc
);
1439 afs_com_err(whoami
, code
, "Checking prserver database");
1446 main(int argc
, char *argv
[])
1448 struct cmd_syndesc
*ts
;
1452 ts
= cmd_CreateSyntax(NULL
, WorkerBee
, NULL
, 0, "PRDB check");
1453 cmd_AddParm(ts
, "-database", CMD_SINGLE
, CMD_REQUIRED
, "ptdb_file");
1454 cmd_AddParm(ts
, "-uheader", CMD_FLAG
, CMD_OPTIONAL
,
1455 "Display UBIK header");
1456 cmd_AddParm(ts
, "-pheader", CMD_FLAG
, CMD_OPTIONAL
,
1457 "Display KADB header");
1458 cmd_AddParm(ts
, "-entries", CMD_FLAG
, CMD_OPTIONAL
, "Display entries");
1459 cmd_AddParm(ts
, "-verbose", CMD_FLAG
, CMD_OPTIONAL
, "verbose");
1460 cmd_AddParm(ts
, "-rebuild", CMD_SINGLE
, CMD_OPTIONAL
| CMD_HIDE
,
1463 return cmd_Dispatch(argc
, argv
);
1467 #if defined(SUPERGROUPS)
1469 /* new routines to deal with very large ID numbers */
1472 zeromap(struct idused
*idmap
)
1475 memset(idmap
->idcount
, 0, sizeof idmap
->idcount
);
1476 idmap
= idmap
->idnext
;
1481 inccount(struct idused
**idmapp
, int id
)
1483 struct idused
*idmap
;
1485 if (IDCOUNT
& (IDCOUNT
- 1)) {
1486 fprintf(stderr
, "IDCOUNT must be power of 2!\n");
1489 while ((idmap
= *idmapp
) != NULL
) {
1490 if (idmap
->idstart
== (id
& ~(IDCOUNT
- 1)))
1492 idmapp
= &idmap
->idnext
;
1495 idmap
= calloc(1, sizeof *idmap
);
1500 idmap
->idstart
= id
& ~(IDCOUNT
- 1);
1501 idmap
->idnext
= *idmapp
;
1504 ++idmap
->idcount
[id
& (IDCOUNT
- 1)];
1508 idcount(struct idused
**idmapp
, int id
)
1510 struct idused
*idmap
;
1512 if (IDCOUNT
& (IDCOUNT
- 1)) {
1513 fprintf(stderr
, "IDCOUNT must be power of 2!\n");
1516 while ((idmap
= *idmapp
) != NULL
) {
1517 if (idmap
->idstart
== (id
& ~(IDCOUNT
- 1))) {
1518 return idmap
->idcount
[id
& (IDCOUNT
- 1)];
1520 idmapp
= &idmap
->idnext
;
1524 #endif /* SUPERGROUPS */