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>
16 * (3) Define a structure, idused, instead of an
17 * array of long integers, idmap, to count group
18 * memberships. These structures are on a linked
19 * list, with each structure containing IDCOUNT
21 * (4) Add new functions to processs the structure
23 * zeromap(), idcount(), inccount().
24 * (5) Add code, primarily in WalkNextChain():
25 * 1. Test id's, allowing groups within groups.
26 * 2. Count the membership list for supergroups,
27 * and follow the continuation chain for
29 * (6) Add fprintf statements for various error
34 #include <sys/types.h>
37 #include <WINNT/afsevent.h>
41 #include <netinet/in.h>
48 #include <afs/cellconfig.h>
49 #include <afs/afsutil.h>
52 #include <afs/com_err.h>
60 struct prheader cheader
;
62 const char *pr_dbaseName
;
63 char *whoami
= "db_verify";
64 #define UBIK_HEADERSIZE 64
67 printheader(struct prheader
*h
)
69 printf("Version = %d\n", ntohl(h
->version
));
70 printf("Header Size = %d\n", ntohl(h
->headerSize
));
71 printf("Free Ptr = 0x%x\n", ntohl(h
->freePtr
));
72 printf("EOF Ptr = 0x%x\n", ntohl(h
->eofPtr
));
73 printf("Max Group ID = %d\n", ntohl(h
->maxGroup
));
74 printf("Max User ID = %d\n", ntohl(h
->maxID
));
75 printf("Max Foreign ID = %d\n", ntohl(h
->maxForeign
));
76 /* printf("Max Sub/Super ID = %d\n", ntohl(h->maxInst)); */
77 printf("Orphaned groups = %d\n", ntohl(h
->orphan
));
78 printf("User Count = %d\n", ntohl(h
->usercount
));
79 printf("Group Count = %d\n", ntohl(h
->groupcount
));
80 /* printf("Foreign Count = %d\n", ntohl(h->foreigncount)); NYI */
81 /* printf("Sub/super Count = %d\n", ntohl(h->instcount)); NYI */
82 printf("Name Hash = %d buckets\n", HASHSIZE
);
83 printf("ID Hash = %d buckets\n", HASHSIZE
);
88 pr_Read(afs_int32 pos
, void *buff
, afs_int32 len
)
92 code
= lseek(fd
, UBIK_HEADERSIZE
+ pos
, 0);
96 code
= read(fd
, buff
, len
);
106 * Initializes the a transaction on the database and reads the header into
107 * the static variable cheader. If successful it returns a read-locked
108 * transaction. If ubik reports that cached database info should be up to date
109 * the cheader structure is not re-read from the ubik.
117 code
= pr_Read(0, (char *)&cheader
, sizeof(cheader
));
119 afs_com_err(whoami
, code
, "couldn't read header");
122 /* Check and see if database exists and is approximately OK. */
123 if (ntohl(cheader
.headerSize
) != sizeof(cheader
)
124 || ntohl(cheader
.eofPtr
) == 0) {
127 afs_com_err(whoami
, PRDBBAD
, "header is bad");
136 /* returns hash bucket for x */
137 return ((abs(x
)) % HASHSIZE
);
141 NameHash(char *aname
)
143 /* returns hash bucket for aname */
144 unsigned int hash
= 0;
146 /* stolen directly from the HashString function in the vol package */
147 for (i
= strlen(aname
), aname
+= i
- 1; i
--; aname
--)
148 hash
= (hash
* 31) + (*(unsigned char *)aname
- 31);
149 return (hash
% HASHSIZE
);
152 #define MAP_NAMEHASH 1
154 #define MAP_HASHES (MAP_NAMEHASH | MAP_IDHASH)
157 #define MAP_OWNED 0x10
158 #define MAP_RECREATE 0x20
161 int nEntries
; /* number of database entries */
162 int anon
; /* found anonymous Id */
163 afs_int32 maxId
; /* user */
164 afs_int32 minId
; /* group */
165 afs_int32 maxForId
; /* foreign user id */
166 #if defined(SUPERGROUPS)
170 afs_int32 idcount
[IDCOUNT
];
171 struct idused
*idnext
;
174 int idRange
; /* number of ids in map */
175 afs_int32
*idmap
; /* map of all id's: midId is origin */
176 #endif /* SUPERGROUPS */
177 int nusers
; /* counts of each type */
182 int maxOwnerLength
; /* longest owner chain */
183 int maxContLength
; /* longest chain of cont. blks */
184 int orphanLength
; /* length of orphan list */
185 int freeLength
; /* length of free list */
190 FILE *recreate
; /* stream for recreate instructions */
193 #if defined(SUPERGROUPS)
194 void zeromap(struct idused
*idmap
);
195 void inccount(struct idused
**idmapp
, int id
);
196 int idcount(struct idused
**idmapp
, int id
);
200 readUbikHeader(struct misc_data
*misc
)
203 struct ubik_hdr uheader
;
205 offset
= lseek(fd
, 0, 0);
207 printf("error: lseek to 0 failed: %d %d\n", offset
, errno
);
211 /* now read the info */
212 r
= read(fd
, &uheader
, sizeof(uheader
));
213 if (r
!= sizeof(uheader
)) {
214 printf("error: read of %" AFS_SIZET_FMT
" bytes failed: %d %d\n",
215 sizeof(uheader
), r
, errno
);
219 uheader
.magic
= ntohl(uheader
.magic
);
220 uheader
.size
= ntohs(uheader
.size
);
221 uheader
.version
.epoch
= ntohl(uheader
.version
.epoch
);
222 uheader
.version
.counter
= ntohl(uheader
.version
.counter
);
224 if (misc
->listuheader
) {
225 printf("Ubik Header\n");
226 printf(" Magic = 0x%x\n", uheader
.magic
);
227 printf(" Size = %u\n", uheader
.size
);
228 printf(" Version.epoch = %u\n", uheader
.version
.epoch
);
229 printf(" Version.counter = %u\n", uheader
.version
.counter
);
232 if (uheader
.size
!= UBIK_HEADERSIZE
)
233 printf("Ubik header size is %u (should be %u)\n", uheader
.size
,
235 if (uheader
.magic
!= UBIK_MAGIC
)
236 printf("Ubik header magic is 0x%x (should be 0x%x)\n", uheader
.magic
,
243 ConvertDiskAddress(afs_uint32 ea
, int *eiP
)
249 if (ea
< sizeof(cheader
))
251 if (ea
>= ntohl(cheader
.eofPtr
))
253 ea
-= sizeof(cheader
);
254 i
= ea
/ sizeof(struct prentry
);
255 if (i
* sizeof(struct prentry
) != ea
)
257 /* if ((i < 0) || (i >= misc->nEntries)) return PRDBADDR; */
263 PrintEntryError(struct misc_data
*misc
, afs_int32 ea
, struct prentry
*e
, int indent
)
266 pr_PrintEntry(stderr
, /*net order */ 0, ea
, e
, indent
);
271 PrintContError(struct misc_data
*misc
, afs_int32 ea
, struct contentry
*c
, int indent
)
273 pr_PrintContEntry(stderr
, /*net order */ 0, ea
, c
, indent
);
278 WalkHashTable(afs_int32 hashtable
[], /* hash table to walk */
279 int hashType
, /* hash function to use */
280 char map
[], /* one byte per db entry */
281 struct misc_data
*misc
) /* stuff to keep track of */
284 int hi
; /* index in hash table */
285 afs_int32 ea
; /* entry's db addr */
286 int ei
; /* entry's index */
287 char bit
; /* bits to check for in map */
296 for (hi
= 0; hi
< HASHSIZE
; hi
++) {
298 next_ea
= ntohl(hashtable
[hi
]);
300 code
= ConvertDiskAddress(next_ea
, &ei
);
302 fprintf(stderr
, "Bad chain address %d\n", next_ea
);
304 fprintf(stderr
, "Last entry in chain:\n");
305 if (PrintEntryError(misc
, ea
, &e
, 2))
308 fprintf(stderr
, "Skipping remainder of hash bucket %d\n", hi
);
312 code
= pr_Read(ea
, (char *)&e
, sizeof(e
));
318 if (((e
.flags
& htonl((PRGRP
| PRINST
))) == 0)
319 && (strchr(e
.name
, '@'))) {
321 if (id
> misc
->maxForId
)
324 if (id
== ANONYMOUSID
)
326 else if (id
> misc
->maxId
)
328 if (id
< misc
->minId
)
334 next_ea
= ntohl(e
.nextName
);
335 hash
= NameHash(e
.name
);
338 next_ea
= ntohl(e
.nextID
);
342 fprintf(stderr
, "unknown hash table type %d\n", hashType
);
348 "Entry found twice in hash table: bucket %d\n", hi
);
350 fprintf(stderr
, "also in wrong bucket: should be in %d\n",
352 if (PrintEntryError(misc
, ea
, &e
, 2))
358 flags
= ntohl(e
.flags
);
359 switch (flags
& PRTYPE
) {
361 fprintf(stderr
, "ENTRY IS FREE");
364 fprintf(stderr
, "ENTRY IS CONTINUATION");
372 fprintf(stderr
, "ENTRY IS unexpected type (flags=0x%x)\n",
376 fprintf(stderr
, "ENTRY IS OF unknown type (flags=0x%x)\n",
382 fprintf(stderr
, "entry hashed in bucket %d should be %d\n",
385 if (PrintEntryError(misc
, ea
, &e
, 2))
395 WalkNextChain(char map
[], /* one byte per db entry */
396 struct misc_data
*misc
, /* stuff to keep track of */
397 afs_int32 ea
, struct prentry
*e
)
402 struct contentry c
; /* continuation entry */
403 afs_int32 na
; /* next thread */
406 int count
= 0; /* number of members, set to > 9999 if */
407 /* list ends early */
410 int length
; /* length of chain */
411 #if defined(SUPERGROUPS)
412 int sgcount
= 0; /* number of sgentrys */
414 #define g (((struct prentryg *)e))
418 head
= ntohl(e
->next
);
421 #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 (PrintContError(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 (PrintContError(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 (PrintContError(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. */
555 "User can't be member of supergroup list\n");
556 if (PrintEntryError(misc
, ea
, e
, 2))
558 if (PrintContError(misc
, na
, &c
, 4))
562 /* count each user as a group, and each group a user is in */
563 if ((id
!= ANONYMOUSID
))
564 inccount(&misc
->idmap
, id
);
571 if (length
> misc
->maxContLength
)
572 misc
->maxContLength
= length
;
573 #endif /* SUPERGROUPS */
575 for (na
= head
; na
; na
= ntohl(c
.next
)) {
576 code
= ConvertDiskAddress(na
, &ni
);
578 fprintf(stderr
, "Bad continuation ptr %d", na
);
580 fprintf(stderr
, "walking free list");
581 else if (PrintEntryError(misc
, ea
, e
, 2))
584 fprintf(stderr
, "last block: \n");
585 if (PrintContError(misc
, na
, &c
, 4))
590 code
= pr_Read(na
, (char *)&c
, sizeof(c
));
596 fprintf(stderr
, "Continuation entry reused\n");
598 fprintf(stderr
, "walking free list");
599 else if (PrintEntryError(misc
, ea
, e
, 2))
601 if (PrintContError(misc
, na
, &c
, 4))
607 if (e
&& (ntohl(c
.id
) != eid
)) {
608 fprintf(stderr
, "Continuation id mismatch\n");
610 fprintf(stderr
, "walking free list");
611 else if (PrintEntryError(misc
, ea
, e
, 2))
613 if (PrintContError(misc
, na
, &c
, 4))
619 /* update membership count */
621 for (i
= 0; i
< COSIZE
; i
++) {
622 afs_int32 id
= ntohl(c
.entries
[i
]);
628 /* in case the ids are large, convert to pure sign. */
637 #if defined(SUPERGROUPS)
638 if (id_s
> 0 && eid_s
> 0) {
640 "User can't be member of user in membership list\n");
641 if (PrintEntryError(misc
, ea
, e
, 2))
643 if (PrintContError(misc
, na
, &c
, 4))
648 if (id_s
* eid_s
> 0) { /* sign should be different */
650 "Bad user/group dicotomy in membership list\n");
651 if (PrintEntryError(misc
, ea
, e
, 2))
653 if (PrintContError(misc
, na
, &c
, 4))
657 #endif /* SUPERGROUPS */
658 /* count each user as a group, and each group a user is in */
659 #if defined(SUPERGROUPS)
660 if (!(id
< 0 && eid
< 0) && (id
!= ANONYMOUSID
))
661 inccount(&misc
->idmap
, id
);
663 if ((id
>= misc
->minId
) && (id
<= misc
->maxId
)
664 && (id
!= ANONYMOUSID
))
665 misc
->idmap
[id
- misc
->minId
]++;
666 #endif /* SUPERGROUPS */
673 if (e
&& noErrors
&& (count
!= ntohl(e
->count
))) {
674 #if defined(SUPERGROUPS)
676 fprintf(stderr
, "Membership list ends early\n");
679 fprintf(stderr
, "Membership list ends early\n");
680 #endif /* SUPERGROUPS */
681 fprintf(stderr
, "Count was %d should be %d\n", count
,
683 if (PrintEntryError(misc
, ea
, e
, 2))
685 #if defined(SUPERGROUPS)
688 if (e
&& (e
->flags
& htonl(PRGRP
)) && (sgcount
!= ntohl(g
->countsg
))) {
689 fprintf(stderr
, "SGCount was %d should be %d\n", sgcount
,
691 if (PrintEntryError(misc
, ea
, e
, 2))
697 if (length
> misc
->maxContLength
)
698 misc
->maxContLength
= length
;
700 misc
->freeLength
= length
;
703 #if defined(SUPERGROUPS)
709 WalkOwnedChain(char map
[], /* one byte per db entry */
710 struct misc_data
*misc
, /* stuff to keep track of */
711 afs_int32 ea
, struct prentry
*e
)
715 struct prentry te
; /* next entry in owner chain */
716 afs_int32 na
; /* next thread */
719 int length
; /* length of chain */
722 head
= ntohl(e
->owned
);
725 head
= ntohl(cheader
.orphan
);
728 for (na
= head
; na
; na
= ntohl(te
.nextOwned
)) {
729 code
= ConvertDiskAddress(na
, &ni
);
731 fprintf(stderr
, "Bad owned list ptr %d", na
);
733 fprintf(stderr
, "walking orphan list");
734 else if (PrintEntryError(misc
, ea
, e
, 2))
737 fprintf(stderr
, "last block: \n");
738 if (PrintEntryError(misc
, na
, &te
, 4))
743 code
= pr_Read(na
, (char *)&te
, sizeof(te
));
748 if ((ntohl(te
.flags
) & PRTYPE
) == PRCONT
) {
749 fprintf(stderr
, "Continuation entry found on owner chain\n");
751 fprintf(stderr
, "walking orphan list");
752 else if (PrintEntryError(misc
, ea
, e
, 2))
754 if (PrintEntryError(misc
, na
, &te
, 4))
758 if (map
[ni
] & MAP_OWNED
) {
759 fprintf(stderr
, "Entry on multiple owner chains\n");
761 fprintf(stderr
, "walking orphan list");
762 else if (PrintEntryError(misc
, ea
, e
, 2))
764 if (PrintEntryError(misc
, na
, &te
, 4))
768 map
[ni
] |= MAP_OWNED
;
769 if ((map
[ni
] & MAP_HASHES
) != MAP_HASHES
) {
770 fprintf(stderr
, "Owned entry not hashed properly\n");
773 fprintf(stderr
, "walking orphan list");
774 else if (PrintEntryError(misc
, ea
, e
, 2))
776 if (PrintEntryError(misc
, na
, &te
, 4))
781 if (ntohl(te
.owner
) != eid
) {
782 fprintf(stderr
, "Owner id mismatch\n");
785 } else /* orphan */ if (te
.owner
) {
786 fprintf(stderr
, "Orphan group owner not zero\n");
792 if (length
> misc
->maxOwnerLength
)
793 misc
->maxOwnerLength
= length
;
795 misc
->orphanLength
= length
;
801 WalkChains(char map
[], /* one byte per db entry */
802 struct misc_data
*misc
) /* stuff to keep track of */
806 afs_int32 ea
; /* entry's db addr */
811 /* check all entries found in hash table walks */
812 for (ei
= 0; ei
< misc
->nEntries
; ei
++)
813 if (map
[ei
] & MAP_HASHES
) {
814 ea
= ei
* sizeof(struct prentry
) + sizeof(cheader
);
815 code
= pr_Read(ea
, (char *)&e
, sizeof(e
));
819 if ((map
[ei
] & MAP_HASHES
) != MAP_HASHES
) {
820 fprintf(stderr
, "entry not in both hashtables\n");
821 if ((map
[ei
] & MAP_NAMEHASH
) != MAP_NAMEHASH
)
822 fprintf(stderr
, "--> entry not in Name hashtable\n");
823 if ((map
[ei
] & MAP_IDHASH
) != MAP_IDHASH
)
824 fprintf(stderr
, "--> entry not in ID hashtable\n");
827 if (PrintEntryError(misc
, ea
, &e
, 2))
834 type
= ntohl(e
.flags
) & PRTYPE
;
838 fprintf(stderr
, "Group id not negative\n");
841 /* special case sysadmin: it owns itself */
842 if (id
== SYSADMINID
) {
843 if (ntohl(e
.owner
) != SYSADMINID
) {
845 "System:administrators doesn't own itself\n");
849 code
= WalkOwnedChain(map
, misc
, ea
, &e
);
852 code
= WalkNextChain(map
, misc
, ea
, &e
);
859 #if defined(SUPERGROUPS)
860 fprintf(stderr
, "User id not positive\n");
862 fprintf(stderr
, "User id negative\n");
867 /* Users are owned by sysadmin, but sysadmin doesn't have an owner
868 * chain. Check this then set the owned bit. */
869 if (ntohl(e
.owner
) != SYSADMINID
) {
871 "User not owned by system:administrators\n");
875 fprintf(stderr
, "User has owned pointer\n");
878 map
[ei
] |= MAP_OWNED
;
880 code
= WalkOwnedChain(map
, misc
, ea
, &e
);
883 code
= WalkNextChain(map
, misc
, ea
, &e
);
886 if (strchr(e
.name
, '@') == 0) {
887 misc
->nusers
++; /* Not a foreign user */
889 misc
->nforeigns
++; /* A foreign user */
899 "ENTRY IS unexpected type [PRFOREIGN] (flags=0x%x)\n",
906 fprintf(stderr
, "entry with unexpected type");
915 GC(char map
[], struct misc_data
*misc
)
923 for (ei
= 0; ei
< misc
->nEntries
; ei
++) {
924 ea
= ei
* sizeof(struct prentry
) + sizeof(cheader
);
925 code
= pr_Read(ea
, (char *)&e
, sizeof(e
));
930 fprintf(stderr
, "Unreferenced entry:");
931 if (PrintEntryError(misc
, ea
, &e
, 2))
934 /* all users and groups should be owned, and their membership counts
936 else if ((m
& MAP_HASHES
) == MAP_HASHES
) {
939 if (!(m
& MAP_OWNED
)) {
940 fprintf(stderr
, "Entry not on any owner chain:\n");
941 if (PrintEntryError(misc
, ea
, &e
, 2))
945 #if defined(SUPERGROUPS)
946 if ((id
!= ANONYMOUSID
)
947 && ((refCount
= idcount(&misc
->idmap
, id
)) != ntohl(e
.count
)))
949 if ((id
>= misc
->minId
) && (id
<= misc
->maxId
)
950 && (id
!= ANONYMOUSID
)
951 && ((refCount
= misc
->idmap
[id
- misc
->minId
]) !=
953 #endif /* SUPERGROUPS */
957 "Entry membership count is inconsistent: %d entries refer to this one\n",
959 if (PrintEntryError(misc
, ea
, &e
, 2))
962 /* get continuation blocks too */
963 for (na
= ntohl(e
.next
); na
; na
= ntohl(e
.next
)) {
965 code
= ConvertDiskAddress(na
, &ni
);
968 code
= pr_Read(na
, (char *)&e
, sizeof(e
));
971 if (PrintEntryError(misc
, na
, &e
, 4))
984 if (strpbrk(s
, " \t")) {
985 qs
= (char *)malloc(strlen(s
) + 3);
995 DumpRecreate(char map
[], struct misc_data
*misc
)
1005 int builtinUsers
= 0;
1006 int createLow
= 0; /* users uncreate from here */
1007 #if defined(SUPERGROUPS)
1008 struct idused
*idmap
; /* map of all id's */
1010 afs_int32
*idmap
; /* map of all id's */
1015 rc
= misc
->recreate
;
1016 idmap
= misc
->idmap
;
1017 #if defined(SUPERGROUPS)
1020 memset(idmap
, 0, misc
->idRange
* sizeof(misc
->idmap
[0]));
1024 for (ei
= createLow
; ei
< misc
->nEntries
; ei
++) {
1025 if ((map
[ei
] & MAP_HASHES
) && (map
[ei
] & MAP_RECREATE
) == 0) {
1030 ea
= ei
* sizeof(struct prentry
) + sizeof(cheader
);
1031 code
= pr_Read(ea
, (char *)&e
, sizeof(e
));
1035 if (misc
->listentries
)
1036 pr_PrintEntry(stdout
, 0 /*not in host order */ , ea
, &e
,
1040 flags
= ntohl(e
.flags
);
1041 owner
= ntohl(e
.owner
);
1042 name
= QuoteName(e
.name
);
1044 if (!strcmp(e
.name
, "system:administrators")
1045 || !strcmp(e
.name
, "system:anyuser")
1046 || !strcmp(e
.name
, "system:authuser")
1047 || !strcmp(e
.name
, "system:backup")
1048 || !strcmp(e
.name
, "anonymous")) {
1053 /* check for duplicate id. This may still lead to duplicate
1055 #if defined(SUPERGROUPS)
1056 if (idcount(&idmap
, id
))
1058 if (idmap
[id
- misc
->minId
])
1061 fprintf(stderr
, "Skipping entry with duplicate id %di\n",
1066 /* If owner doesn't exist skip for now, unless we're our own
1067 * owner. If so, a special case allows a group to own itself
1068 * if caller is sysadmin. This leaves only owner cycles to
1071 if ((owner
< misc
->minId
) || (owner
> misc
->maxId
)) {
1072 if (owner
== ANONYMOUSID
)
1074 "Warning: id %di is owned by ANONYMOUS; using sysadmin instead\n",
1078 "Bogus owner (%d) of id %di; using sysadmin instead\n",
1083 fprintf(stderr
, "Warning: group %s is self owning\n",
1085 } else if (owner
== 0) {
1087 "Warning: orphan group %s will become self owning.\n",
1091 #if defined(SUPERGROUPS)
1092 else if (!idcount(&idmap
, owner
))
1095 else if (idmap
[owner
- misc
->minId
] == 0)
1100 fprintf(rc
, "cr %s %d %d\n", name
, id
, owner
);
1102 gq
= uq
= access
= mask
= 0;
1103 if (flags
& PRACCESS
) {
1104 access
= (flags
>> PRIVATE_SHIFT
);
1105 mask
|= PR_SF_ALLBITS
;
1107 if (flags
& PRQUOTA
) {
1108 gq
= ntohl(e
.ngroups
);
1109 uq
= ntohl(e
.nusers
);
1110 mask
|= PR_SF_NGROUPS
| PR_SF_NUSERS
;
1113 fprintf(rc
, "sf %d %x %x %d %d\n", id
, mask
, access
, gq
,
1117 map
[ei
] |= MAP_RECREATE
;
1118 #if defined(SUPERGROUPS)
1119 if (id
!= ANONYMOUSID
)
1120 inccount(&idmap
, id
);
1122 if (id
!= ANONYMOUSID
)
1123 idmap
[id
- misc
->minId
]++;
1127 /* bump low water mark if possible */
1128 if (ei
== createLow
)
1135 /* Now create the entries with circular owner dependencies and make them
1136 * own themselves. This is the only way to create them with the correct
1138 for (ei
= 0; ei
< misc
->nEntries
; ei
++)
1139 if (((map
[ei
] & MAP_HASHES
) == MAP_HASHES
)
1140 && (map
[ei
] & MAP_RECREATE
) == 0) {
1141 ea
= ei
* sizeof(struct prentry
) + sizeof(cheader
);
1142 code
= pr_Read(ea
, (char *)&e
, sizeof(e
));
1147 name
= QuoteName(e
.name
);
1148 fprintf(stderr
, "Warning: group %s in self owning cycle\n", name
);
1150 fprintf(rc
, "cr %s %d %d\n", name
, id
, id
);
1151 #if defined(SUPERGROUPS)
1152 inccount(&idmap
, id
);
1154 idmap
[id
- misc
->minId
]++;
1157 for (ei
= 0; ei
< misc
->nEntries
; ei
++)
1158 if (((map
[ei
] & MAP_HASHES
) == MAP_HASHES
)
1159 && (map
[ei
] & MAP_RECREATE
) == 0) {
1160 ea
= ei
* sizeof(struct prentry
) + sizeof(cheader
);
1161 code
= pr_Read(ea
, (char *)&e
, sizeof(e
));
1165 owner
= ntohl(e
.owner
);
1166 #if defined(SUPERGROUPS)
1167 if (!idcount(&idmap
, owner
))
1169 if (idmap
[owner
- misc
->minId
] == 0)
1173 "Skipping chown of '%s' to non-existant owner %di\n",
1176 fprintf(rc
, "ce %d \"\" %d 0\n", ntohl(e
.id
), e
.owner
);
1182 /* Reconstruct membership information based on the groups' user lists. */
1183 for (ei
= 0; ei
< misc
->nEntries
; ei
++) {
1184 if ((map
[ei
] & MAP_HASHES
) == MAP_HASHES
) {
1185 ea
= ei
* sizeof(struct prentry
) + sizeof(cheader
);
1186 code
= pr_Read(ea
, (char *)&e
, sizeof(e
));
1191 flags
= ntohl(e
.flags
);
1193 if ((id
< 0) && (flags
& PRGRP
)) {
1197 for (i
= 0; i
< PRSIZE
; i
++) {
1198 afs_int32 uid
= ntohl(e
.entries
[i
]);
1203 #if !defined(SUPERGROUPS)
1206 fprintf(rc
, "au %d %d\n", uid
, id
);
1208 #if !defined(SUPERGROUPS)
1210 fprintf(stderr
, "Skipping %di in group %di\n", uid
,
1217 code
= pr_Read(na
, (char *)&c
, sizeof(c
));
1221 if ((id
== ntohl(c
.id
)) && (c
.flags
& htonl(PRCONT
))) {
1222 for (i
= 0; i
< COSIZE
; i
++) {
1223 afs_int32 uid
= ntohl(c
.entries
[i
]);
1228 #if !defined(SUPERGROUPS)
1231 fprintf(rc
, "au %d %d\n", uid
, id
);
1233 #if !defined(SUPERGROUPS)
1235 fprintf(stderr
, "Skipping %di in group %di\n",
1240 fprintf(stderr
, "Skipping continuation block at %d\n",
1246 if (count
!= ntohl(e
.count
))
1248 "Group membership count problem found %d should be %d\n",
1249 count
, ntohl(e
.count
));
1250 } else if ((id
< 0) || (flags
& PRGRP
)) {
1251 fprintf(stderr
, "Skipping group %di\n", id
);
1259 CheckPrDatabase(struct misc_data
*misc
) /* info & statistics */
1264 char *map
; /* map of each entry in db */
1266 eof
= ntohl(cheader
.eofPtr
);
1267 eof
-= sizeof(cheader
);
1268 n
= eof
/ sizeof(struct prentry
);
1269 if ((eof
< 0) || (n
* sizeof(struct prentry
) != eof
)) {
1271 afs_com_err(whoami
, code
,
1272 "eof ptr no good: eof=%d, sizeof(prentry)=%" AFS_SIZET_FMT
,
1273 eof
, sizeof(struct prentry
));
1278 printf("Database has %d entries\n", n
);
1279 map
= (char *)malloc(n
);
1283 if (misc
->verbose
) {
1284 printf("\nChecking name hash table\n");
1287 code
= WalkHashTable(cheader
.nameHash
, MAP_NAMEHASH
, map
, misc
);
1289 afs_com_err(whoami
, code
, "walking name hash");
1292 if (misc
->verbose
) {
1293 printf("\nChecking id hash table\n");
1296 code
= WalkHashTable(cheader
.idHash
, MAP_IDHASH
, map
, misc
);
1298 afs_com_err(whoami
, code
, "walking id hash");
1302 /* hash walk calculates min and max id */
1303 #if defined(SUPERGROUPS)
1306 n
= ((misc
->maxId
> misc
->maxForId
) ? misc
->maxId
: misc
->maxForId
);
1307 misc
->idRange
= n
- misc
->minId
+ 1;
1308 misc
->idmap
= (afs_int32
*) malloc(misc
->idRange
* sizeof(afs_int32
));
1310 afs_com_err(whoami
, 0, "Unable to malloc space for max ids of %d",
1315 memset(misc
->idmap
, 0, misc
->idRange
* sizeof(misc
->idmap
[0]));
1316 #endif /* SUPERGROUPS */
1318 if (misc
->verbose
) {
1319 printf("\nChecking entry chains\n");
1322 code
= WalkChains(map
, misc
);
1324 afs_com_err(whoami
, code
, "walking chains");
1327 if (misc
->verbose
) {
1328 printf("\nChecking free list\n");
1331 code
= WalkNextChain(map
, misc
, 0, 0);
1333 afs_com_err(whoami
, code
, "walking free list");
1336 if (misc
->verbose
) {
1337 printf("\nChecking orphans list\n");
1340 code
= WalkOwnedChain(map
, misc
, 0, 0);
1342 afs_com_err(whoami
, code
, "walking orphan list");
1346 if (misc
->verbose
) {
1347 printf("\nChecking for unreferenced entries\n");
1350 code
= GC(map
, misc
);
1352 afs_com_err(whoami
, code
, "looking for unreferenced entries");
1356 DumpRecreate(map
, misc
); /* check for owner cycles */
1358 fclose(misc
->recreate
);
1360 if (misc
->anon
!= 2) /* once for each hash table */
1361 fprintf(stderr
, "Problems with ANON=%d\n", misc
->anon
);
1362 if (misc
->ncells
|| misc
->ninsts
)
1363 fprintf(stderr
, "Unexpected entry type\n");
1364 if (misc
->nusers
!= ntohl(cheader
.usercount
)) {
1366 "User count inconsistent: should be %d, header claims: %d\n",
1367 misc
->nusers
, ntohl(cheader
.usercount
));
1369 if (misc
->ngroups
!= ntohl(cheader
.groupcount
)) {
1371 "Group count inconsistent: should be %d, header claims: %d\n",
1372 misc
->ngroups
, ntohl(cheader
.groupcount
));
1374 if (misc
->maxId
> ntohl(cheader
.maxID
))
1376 "Database's max user Id (%d) is smaller than largest user's Id (%d).\n",
1377 ntohl(cheader
.maxID
), misc
->maxId
);
1378 if (misc
->minId
< ntohl(cheader
.maxGroup
))
1380 "Database's max group Id (%d) is smaller than largest group's Id (%d).\n",
1381 ntohl(cheader
.maxGroup
), misc
->minId
);
1383 if (misc
->verbose
) {
1384 printf("\nMaxId = %d, MinId = %d, MaxForeignId = %d\n", misc
->maxId
,
1385 misc
->minId
, misc
->maxForId
);
1387 ("Free list is %d entries in length, %d groups on orphan list\n",
1388 misc
->freeLength
, misc
->orphanLength
);
1390 ("The longest owner list is %d, the longest continuation block chain is %d\n",
1391 misc
->maxOwnerLength
, misc
->maxContLength
);
1392 printf("%d users ; %d foreign users ; and %d groups\n", misc
->nusers
,
1393 misc
->nforeigns
, misc
->ngroups
);
1400 #include "AFS_component_version_number.c"
1403 WorkerBee(struct cmd_syndesc
*as
, void *arock
)
1407 struct misc_data misc
; /* info & statistics */
1409 initialize_PT_error_table();
1410 initialize_U_error_table();
1412 pr_dbaseName
= AFSDIR_SERVER_PRDB_FILEPATH
;
1413 memset(&misc
, 0, sizeof(misc
));
1415 pr_dbaseName
= as
->parms
[0].items
->data
; /* -database */
1416 misc
.listuheader
= (as
->parms
[1].items
? 1 : 0); /* -uheader */
1417 misc
.listpheader
= (as
->parms
[2].items
? 1 : 0); /* -pheader */
1418 misc
.listentries
= (as
->parms
[3].items
? 1 : 0); /* -entries */
1419 misc
.verbose
= (as
->parms
[4].items
? 1 : 0); /* -verbose */
1420 recreateFile
= (as
->parms
[5].items
? as
->parms
[5].items
->data
: NULL
); /* -rebuild */
1422 fd
= open(pr_dbaseName
, O_RDONLY
, 0);
1424 afs_com_err(whoami
, errno
, "Open failed on db %s", pr_dbaseName
);
1428 /* Read the ubik header */
1429 if (misc
.listuheader
) {
1430 readUbikHeader(&misc
);
1433 code
= ReadHeader();
1436 if (misc
.listpheader
)
1437 printheader(&cheader
);
1440 misc
.recreate
= fopen(recreateFile
, "w");
1441 if (misc
.recreate
== 0) {
1442 afs_com_err(whoami
, errno
,
1443 "can't create file for recreation instructions: %s",
1448 code
= CheckPrDatabase(&misc
);
1450 afs_com_err(whoami
, code
, "Checking prserver database");
1457 main(int argc
, char *argv
[])
1459 struct cmd_syndesc
*ts
;
1463 ts
= cmd_CreateSyntax(NULL
, WorkerBee
, NULL
, "PRDB check");
1464 cmd_AddParm(ts
, "-database", CMD_SINGLE
, CMD_REQUIRED
, "ptdb_file");
1465 cmd_AddParm(ts
, "-uheader", CMD_FLAG
, CMD_OPTIONAL
,
1466 "Display UBIK header");
1467 cmd_AddParm(ts
, "-pheader", CMD_FLAG
, CMD_OPTIONAL
,
1468 "Display KADB header");
1469 cmd_AddParm(ts
, "-entries", CMD_FLAG
, CMD_OPTIONAL
, "Display entries");
1470 cmd_AddParm(ts
, "-verbose", CMD_FLAG
, CMD_OPTIONAL
, "verbose");
1471 cmd_AddParm(ts
, "-rebuild", CMD_SINGLE
, CMD_OPTIONAL
| CMD_HIDE
,
1474 return cmd_Dispatch(argc
, argv
);
1478 #if defined(SUPERGROUPS)
1480 /* new routines to deal with very large ID numbers */
1483 zeromap(struct idused
*idmap
)
1486 memset(idmap
->idcount
, 0, sizeof idmap
->idcount
);
1487 idmap
= idmap
->idnext
;
1492 inccount(struct idused
**idmapp
, int id
)
1494 struct idused
*idmap
;
1496 if (IDCOUNT
& (IDCOUNT
- 1)) {
1497 fprintf(stderr
, "IDCOUNT must be power of 2!\n");
1500 while ((idmap
= *idmapp
) != NULL
) {
1501 if (idmap
->idstart
== (id
& ~(IDCOUNT
- 1)))
1503 idmapp
= &idmap
->idnext
;
1506 idmap
= calloc(1, sizeof *idmap
);
1511 idmap
->idstart
= id
& ~(IDCOUNT
- 1);
1512 idmap
->idnext
= *idmapp
;
1515 ++idmap
->idcount
[id
& (IDCOUNT
- 1)];
1519 idcount(struct idused
**idmapp
, int id
)
1521 struct idused
*idmap
;
1523 if (IDCOUNT
& (IDCOUNT
- 1)) {
1524 fprintf(stderr
, "IDCOUNT must be power of 2!\n");
1527 while ((idmap
= *idmapp
) != NULL
) {
1528 if (idmap
->idstart
== (id
& ~(IDCOUNT
- 1))) {
1529 return idmap
->idcount
[id
& (IDCOUNT
- 1)];
1531 idmapp
= &idmap
->idnext
;
1535 #endif /* SUPERGROUPS */