/* $Header$ */ #include #include #include #define FIXERRORS #define max(x, y) ((x) > (y) ? (x) : (y)) EXEC SQL INCLUDE sqlca; struct member { int list_id; int member_id; union { short all; struct { short u_ref_count:12; unsigned short u_direct:1; unsigned short u_baddirect:1; unsigned short u_found:1; unsigned short u_scanned:1; } u_flags; } flags; } *find_member(), *allocmember(); #define frefc flags.u_flags.u_ref_count #define fdirect flags.u_flags.u_direct #define fbaddirect flags.u_flags.u_baddirect #define ffound flags.u_flags.u_found #define fscanned flags.u_flags.u_scanned #define fall flags.all #define member2id(c, id) (((c & 0xff) << 24) | (id & 0xffffff)) #define id2type(id) ((id >> 24) & 0xff) #define id2id(id) (id & 0xffffff) struct member_list { struct member_list *next; struct member *member; }; struct hash *lists, *members; void fix_member(), display_member(); int debug = 0, records = 0; char *db = "moira/moira"; main(argc, argv) int argc; char **argv; { char buf[256]; #ifdef DEBUG if (argc > 1) debug = atoi(argv[1]); #endif /* DEBUG */ /* ingres sms */ EXEC SQL CONNECT :db; /* begin transaction */ /* range of m is imembers */ /* No equivalent */ lists = create_hash(50000); members = create_hash(300000); records = 0; load_members(); #ifdef DEBUG if (debug > 3) hash_step(lists, display_member, NULL); #endif /* DEBUG */ verify_members(); fix_members(); #ifdef FIXERRORS printf("Commit changes (Y/N)?"); fflush(stdout); fgets(buf, sizeof(buf), stdin); if (buf[0] == 'Y' || buf[0] == 'y') { printf("Ending transaction\n"); /* end transaction */ EXEC SQL COMMIT WORK; } else { #endif /* FIXERRORS */ printf("Aborting transaction\n"); /* abort */ EXEC SQL ROLLBACK WORK; #ifdef FIXERRORS } #endif /* FIXERRORS */ /* exit */ /* No equivalent (?) */ printf("Done.\n"); exit(0); } load_members() { struct member *m, *m1, *md, *ma; struct member_list *descendants, *ancestors, *desc, *ance, la, ld; EXEC SQL BEGIN DECLARE SECTION; int list_id, member_id, ref_count, ref; char mtype[9]; EXEC SQL END DECLARE SECTION; struct save_queue *sq; printf("Loading members\n"); sq = sq_create(); /* retrieve (list_id = m.#list_id, member_id = m.#member_id, * mtype = m.#member_type, ref_count = m.#ref_count) * where m.direct = 1 { */ EXEC SQL DECLARE csrm1 CURSOR FOR SELECT list_id, member_id, member_type, ref_count FROM imembers WHERE direct=1; EXEC SQL OPEN csrm1; while(1) { EXEC SQL FETCH csrm1 INTO :list_id, :member_id, :mtype, :ref_count; if(sqlca.sqlcode != 0) break; #ifdef DEBUG if (debug > 5) printf("Working on list %d member %s %d refc %d\n", list_id, mtype, member_id, ref_count); #endif /* DEBUG */ if ((m = find_member(list_id, member2id(mtype[0], member_id))) == NULL) { m = allocmember(); m->list_id = list_id; m->member_id = member2id(mtype[0], member_id); insert_list(m); insert_member(m); } m->fdirect = 1; la.next = (struct member_list *) hash_lookup(members, member2id('L', list_id)); la.member = m; if (isinchain(m, la.next)) ance = la.next; else ance = &la; if (mtype[0] == 'L') ld.next = (struct member_list *) hash_lookup(lists, member_id); else ld.next = NULL; ld.member = m; if (isinchain(m, ld.next)) desc = ld.next; else desc = &ld; #ifdef DEBUG if (debug > 5) printf("%d ancestors, %d descendants\n", chainlen(ance), chainlen(desc)); #endif /* DEBUG */ for (ancestors = ance; ancestors; ancestors = ancestors->next) { ma = ancestors->member; for (descendants = desc; descendants; descendants=descendants->next) { md = descendants->member; if (member2id('L', ma->list_id) == md->member_id) fprintf(stderr, "Loop detected! list %d member %d\n", md->list_id, ma->member_id); ref = md->frefc * ma->frefc; if (ref == 0) { ref = max(md->frefc, ma->frefc); if (ref == 0) ref = 1; } #ifdef DEBUG if (debug > 5) printf("Checking list %d member %d, ref = %d\n", ma->list_id, id2id(md->member_id), ref); #endif /* DEBUG */ if (m1 = find_member(ma->list_id, md->member_id)) { m1->frefc += ref; #ifdef DEBUG if (debug > 5) printf("set refc to %d (%d) on list %d, member %d\n", m1->frefc, ref, m1->list_id, id2id(m1->member_id)); #endif /* DEBUG */ if (ma == m && md == m) m1->fdirect = 1; } else { m1 = allocmember(); m1->list_id = ma->list_id; m1->member_id = md->member_id; m1->frefc = ref; #ifdef DEBUG if (debug > 5) printf("set new refc to %d (%d) on list %d, member %d\n", m1->frefc, ref, m1->list_id, id2id(m1->member_id)); #endif /* DEBUG */ sq_save_data(sq, m1); } } } while (sq_get_data(sq, &m)) { insert_list(m); insert_member(m); } sq_destroy(sq); sq = sq_create(); } EXEC SQL CLOSE csrm1; printf("created %d records\n", records); } verify_members() { struct member *m; struct save_queue *sq; EXEC SQL BEGIN DECLARE SECTION; int list_id, member_id, ref_count, dflag; char mtype[9]; EXEC SQL END DECLARE SECTION; int errxtra, errbref, errbdir; #ifdef DEBUG int ref0, ref1, ref2, ref3, refg; int db0, db1, db2, db3, dbg; #endif /* DEBUG */ /* verify members from database */ printf("Verifying members\n"); errxtra = errbref = errbdir = 0; #ifdef DEBUG ref0 = ref1 = ref2 = ref3 = refg = 0; db0 = db1 = db2 = db3 = dbg = 0; #endif /* DEBUG */ sq = sq_create(); /* retrieve (list_id = m.#list_id, member_id = m.#member_id, * mtype = m.member_type, ref_count = m.#ref_count, * dflag = m.#direct) { */ EXEC SQL DECLARE csrm2 CURSOR FOR SELECT list_id, member_id, member_type, ref_count, direct FROM imembers; EXEC SQL OPEN csrm2; while(1) { EXEC SQL FETCH csrm2 INTO :list_id, :member_id, :mtype, :ref_count, :dflag; if(sqlca.sqlcode != 0) break; #ifdef DEBUG if (debug > 1) switch (ref_count) { case 0: db0++; break; case 1: db1++; break; case 2: db2++; break; case 3: db3++; break; default: dbg++; } #endif /* DEBUG */ m = find_member(list_id, member2id(mtype[0], member_id)); if (m == NULL) { m = allocmember(); m->list_id = list_id; m->member_id = member2id(mtype[0], member_id); m->fdirect = dflag; m->frefc = ref_count; sq_save_data(sq, m); errxtra++; } else { m->ffound = 1; #ifdef DEBUG if (debug > 1) switch (m->frefc) { case 0: ref0++; break; case 1: ref1++; break; case 2: ref2++; break; case 3: ref3++; break; default: refg++; } #endif /* DEBUG */ m->frefc -= ref_count; if (m->frefc != 0) errbref++; if (m->fdirect != dflag) { m->fbaddirect = 1; errbdir++; } } } EXEC SQL CLOSE csrm2; printf("Found %d extra records, %d bad ref counts, %d bad direct flags\n", errxtra, errbref, errbdir); #ifdef DEBUG if (debug > 1) { printf("Found in db: %d 0; %d 1; %d 2; %d 3; %d > 3\n", db0, db1, db2, db3, dbg); printf("Found refs: %d 0; %d 1; %d 2; %d 3; %d > 3\n", ref0, ref1, ref2, ref3, refg); } #endif /* DEBUG */ } fix_members() { struct member *m; struct save_queue *sq; int errmis = 0; EXEC SQL BEGIN DECLARE SECTION; int list_id, member_id, rowcount; char mtype[9]; EXEC SQL END DECLARE SECTION; char buf[512]; /* fix any errors */ printf("Fixing errors\n"); hash_step(lists, fix_member, &errmis); while (sq_get_data(sq, &m)) { printf("Extraneous member record, deleting:\n"); list_id = m->list_id; member_id = id2id(m->member_id); switch (id2type(m->member_id)) { case 'U': strcpy(mtype, "USER"); break; case 'L': strcpy(mtype, "LIST"); break; case 'S': strcpy(mtype, "STRING"); break; case 'K': strcpy(mtype, "KERBEROS"); break; default: mtype[0] = id2type(m->member_id); mtype[1] = 0; } printf(" List: %d, Member: %s %d, Refc: %d, Direct %d\n", list_id, mtype, member_id, m->frefc, m->fdirect); #ifdef FIXERRORS /* delete m where m.#list_id = list_id and m.#member_id = member_id * and m.member_type = mtype */ EXEC SQL DELETE FROM imembers WHERE list_id = :list_id AND member_id = :member_id AND member_type = :mtype; rowcount = sqlca.sqlerrd[2]; if (rowcount > 0) printf("%d entr%s deleted\n", rowcount, rowcount == 1 ? "y" : "ies"); #endif /* FIXERRORS */ } if (errmis > 0) printf("Added %d missing records\n", errmis); } insert_list(m) struct member *m; { struct member_list *l, *l1; l = (struct member_list *) hash_lookup(lists, m->list_id); if (l == NULL) { l = (struct member_list *)malloc(sizeof(struct member_list)); if (l == NULL) { fprintf(stderr, "No memory for insert_list\n"); exit(1); } l->next = NULL; l->member = m; if( hash_store(lists, m->list_id, l) == -1 ) { fprintf(stderr,"Out of mem while storing lists in hash table\n"); exit(1); } return; } for (l1 = l; l1; l1 = l1->next) if (l1->member->member_id == m->member_id) { fprintf(stderr, "Found 2nd copy of list record for\n"); fprintf(stderr, "List: %d, Member: %c %d, Refc: %d, Direct %d\n", m->list_id, id2type(m->member_id), id2id(m->member_id), m->frefc, m->fdirect); kill(getpid(), SIGQUIT); exit(2); } l1 = (struct member_list *)malloc(sizeof(struct member_list)); if (l1 == NULL) { fprintf(stderr, "No memory for insert_list\n"); exit(1); } l1->next = l->next; l->next = l1; l1->member = m; } insert_member(m) struct member *m; { struct member_list *l, *l1; l = (struct member_list *) hash_lookup(members, m->member_id); if (l == NULL) { l = (struct member_list *)malloc(sizeof(struct member_list)); if (l == NULL) { fprintf(stderr, "No memory for insert_member\n"); exit(1); } l->next = NULL; l->member = m; if( hash_store(members, m->member_id, l) == -1 ) { fprintf(stderr,"Out of mem while storing members in hash table\n"); exit(1); } return; } for (l1 = l; l1; l1 = l1->next) if (l1->member->list_id == m->list_id) { fprintf(stderr, "Found 2nd copy of member record for\n"); fprintf(stderr, "List: %d, Member: %c %d, Refc: %d, Direct %d\n", m->list_id, id2type(m->member_id), id2id(m->member_id), m->frefc, m->fdirect); kill(getpid(), SIGQUIT); exit(2); } l1 = (struct member_list *)malloc(sizeof(struct member_list)); if (l1 == NULL) { fprintf(stderr, "No memory for insert_member\n"); exit(1); } l1->next = l->next; l->next = l1; l1->member = m; } struct member *find_member(listid, memberid) int listid; int memberid; { struct member_list *l; for (l = (struct member_list *) hash_lookup(lists, listid); l; l = l->next) if (l->member->member_id == memberid) return(l->member); return(NULL); } /*ARGSUSED*/ void fix_member(dummy, l, errmis) int dummy; struct member_list *l; int *errmis; { EXEC SQL BEGIN DECLARE SECTION; int list_id, member_id, ref_count, dflag, rowcount; char *mtype; EXEC SQL END DECLARE SECTION; char buf[2]; struct member *m; for (; l; l = l->next) { m = l->member; if (m->fscanned) continue; m->fscanned = 1; if (m->fbaddirect == 0 && m->frefc == 0 && m->ffound == 1) continue; if (m->ffound == 0) { printf("Missing member record, adding:\n"); list_id = m->list_id; member_id = id2id(m->member_id); ref_count = m->frefc; dflag = m->fdirect; switch (id2type(m->member_id)) { case 'U': mtype = "USER"; break; case 'L': mtype = "LIST"; break; case 'S': mtype = "STRING"; break; case 'K': mtype = "KERBEROS"; break; default: mtype = buf; buf[0] = id2type(m->member_id); buf[1] = 0; } printf(" List: %d, Member: %s %d, Refc: %d, Direct %d\n", list_id, mtype, member_id, ref_count, dflag); (*errmis)++; #ifdef FIXERRORS /* append imembers (#list_id = list_id, #member_id = member_id, * member_type = mtype, #ref_count = ref_count, * direct = dflag); */ EXEC SQL INSERT INTO imembers (list_id, member_id, member_type, ref_count, direct) VALUES (:list_id, :member_id, :mtype, :ref_count, :dflag); rowcount = sqlca.sqlerrd[2]; if (rowcount > 0) printf("%d entr%s added\n", rowcount, rowcount == 1 ? "y" : "ies"); #endif /* FIXERRORS */ continue; } printf("Member record has bad ref_count and/or direct flag, fixing\n"); list_id = m->list_id; member_id = id2id(m->member_id); ref_count = m->frefc; dflag = m->fdirect; switch (id2type(m->member_id)) { case 'U': mtype = "USER"; break; case 'L': mtype = "LIST"; break; case 'S': mtype = "STRING"; break; case 'K': mtype = "KERBEROS"; break; default: mtype = buf; buf[0] = id2type(m->member_id); buf[1] = 0; } printf(" List: %d, Member: %s %d, Refc: %d, Direct %d\n", list_id, mtype, member_id, ref_count, dflag); #ifdef FIXERRORS /* replace m (#ref_count = m.#ref_count + ref_count, direct = dflag) * where m.#list_id = list_id and m.#member_id = member_id and * m.member_type = mtype */ EXEC SQL UPDATE imembers SET ref_count=ref_count+:ref_count, direct = :dflag WHERE list_id = :list_id AND member_id = :member_id AND member_tpe = :mtype; rowcount = sqlca.sqlerrd[2]; if (rowcount > 0) printf("%d entr%s updated\n", rowcount, rowcount == 1 ? "y" : "ies"); #endif /* FIXERRORS */ } } struct member *allocmember() { struct member *m; m = (struct member *) malloc(sizeof(struct member)); if (m == NULL) { fprintf(stderr, "No memory for new member\n"); exit(1); } m->fall = 0; records++; return(m); } int isinchain(m, l) struct member *m; struct member_list *l; { for (; l; l = l->next) if (l->member == m) return(1); return(0); } int chainlen(l) struct member_list *l; { int i; for (i = 0; l; l = l->next, i++); return(i); } #ifdef DEBUG /*ARGSUSED*/ void display_member(key, l, dummy1) int key, dummy1; struct member_list *l; { struct member *m; char *mtype; printf("%d*", key); for(; l; l = l->next) { m = l->member; switch (id2type(m->member_id)) { case 'U': mtype = "USER"; break; case 'L': mtype = "LIST"; break; case 'S': mtype = "STRING"; break; case 'K': mtype = "KERBEROS"; break; default: mtype = "???"; break; } printf("List: %d, Member: %s %d, Refc: %d, Direct %d\n", m->list_id, mtype, id2id(m->member_id), m->frefc, m->fdirect); } } #endif /* DEBUG */