]> andersk Git - moira.git/blob - dbck/members.dc
50441d7cfefe5bbbac544f4073dbf71a73d35ac6
[moira.git] / dbck / members.dc
1 /* $Header$
2  */
3
4 #include <stdio.h>
5 #include <signal.h>
6 #include <moira.h>
7
8 #define FIXERRORS
9
10 #define max(x, y)       ((x) > (y) ? (x) : (y))
11
12 EXEC SQL INCLUDE sqlca;
13
14 struct member {
15     int list_id;
16     int member_id;
17     union {
18         short all;
19         struct {
20             short u_ref_count:12;
21             unsigned short u_direct:1;
22             unsigned short u_baddirect:1;
23             unsigned short u_found:1;
24             unsigned short u_scanned:1;
25         } u_flags;
26     } flags;
27 } *find_member(), *allocmember();
28 #define frefc           flags.u_flags.u_ref_count
29 #define fdirect         flags.u_flags.u_direct
30 #define fbaddirect      flags.u_flags.u_baddirect
31 #define ffound          flags.u_flags.u_found
32 #define fscanned        flags.u_flags.u_scanned
33 #define fall            flags.all
34
35 #define member2id(c, id)        (((c & 0xff) << 24) | (id & 0xffffff))
36 #define id2type(id)             ((id >> 24) & 0xff)
37 #define id2id(id)               (id & 0xffffff)
38
39 struct member_list {
40     struct member_list *next;
41     struct member *member;
42 };
43
44 struct hash *lists, *members;
45 void fix_member(), display_member();
46 int debug = 0, records = 0;
47
48
49 main(argc, argv)
50 int argc;
51 char **argv;
52 {
53     char buf[256];
54
55 #ifdef DEBUG
56     if (argc > 1)
57       debug = atoi(argv[1]);
58 #endif DEBUG
59
60 /*  ingres sms */
61     EXEC SQL CONNECT moira;
62 /*  begin transaction */
63 /*  range of m is imembers */
64     /* No equivalent */
65
66     lists = create_hash(10000);
67     members = create_hash(10000);
68     records = 0;
69
70     load_members();
71 #ifdef DEBUG
72     if (debug > 3)
73       hash_step(lists, display_member, NULL);
74 #endif DEBUG
75     verify_members();
76     fix_members();
77
78 #ifdef FIXERRORS
79     printf("Commit changes (Y/N)?");
80     fflush(stdout);
81     fgets(buf, sizeof(buf), stdin);
82     if (buf[0] == 'Y' || buf[0] == 'y') {
83         printf("Ending transaction\n");
84 /*      end transaction */
85         EXEC SQL COMMIT WORK;
86     } else {
87 #endif FIXERRORS
88         printf("Aborting transaction\n");
89 /*      abort */
90         EXEC SQL ROLLBACK WORK;
91 #ifdef FIXERRORS
92     }
93 #endif FIXERRORS
94
95 /*  exit */
96     /* No equivalent (?) */
97     printf("Done.\n");
98
99     exit(0);
100 }
101
102
103
104 load_members()
105 {
106     struct member *m, *m1, *md, *ma;
107     struct member_list *descendants, *ancestors, *desc, *ance, la, ld;
108     EXEC SQL BEGIN DECLARE SECTION; 
109     int list_id, member_id, ref_count, ref;
110     char mtype[9];
111     EXEC SQL END DECLARE SECTION; 
112     struct save_queue *sq;
113
114     printf("Loading members\n");
115     sq = sq_create();
116
117 /*  retrieve (list_id = m.#list_id, member_id = m.#member_id,
118  *            mtype = m.#member_type, ref_count = m.#ref_count)
119  *      where m.direct = 1 {  */
120     EXEC SQL DECLARE csrm1 CURSOR FOR
121         SELECT list_id, member_id, member_type, ref_count FROM imembers
122             WHERE direct=1;
123     EXEC SQL OPEN csrm1;
124     while(1) {
125         EXEC SQL FETCH csrm1 INTO :list_id, :member_id, :mtype, :ref_count;
126         if(sqlca.sqlcode != 0) break; 
127
128 #ifdef DEBUG
129       if (debug > 5)
130         printf("Working on list %d member %s %d refc %d\n",
131                list_id, mtype, member_id, ref_count);
132 #endif DEBUG
133       if ((m = find_member(list_id, member2id(mtype[0], member_id))) == NULL) {
134           m = allocmember();
135           m->list_id = list_id;
136           m->member_id = member2id(mtype[0], member_id);
137           insert_list(m);
138           insert_member(m);
139       }
140       m->fdirect = 1;
141       la.next = (struct member_list *) hash_lookup(members,
142                                                    member2id('L', list_id));
143       la.member = m;
144       if (isinchain(m, la.next))
145         ance = la.next;
146       else
147         ance = &la;
148       if (mtype[0] == 'L')
149         ld.next = (struct member_list *) hash_lookup(lists, member_id);
150       else
151         ld.next = NULL;
152       ld.member = m;
153       if (isinchain(m, ld.next))
154         desc = ld.next;
155       else
156         desc = &ld;
157 #ifdef DEBUG
158       if (debug > 5)
159         printf("%d ancestors, %d descendants\n",
160                chainlen(ance), chainlen(desc));
161 #endif DEBUG
162       for (ancestors = ance; ancestors; ancestors = ancestors->next) {
163           ma = ancestors->member;
164           for (descendants = desc; descendants; descendants=descendants->next) {
165               md = descendants->member;
166               if (member2id('L', ma->list_id) == md->member_id)
167                 fprintf(stderr, "Loop detected! list %d member %d\n",
168                         md->list_id, ma->member_id);
169               ref = md->frefc * ma->frefc;
170               if (ref == 0) {
171                   ref = max(md->frefc, ma->frefc);
172                   if (ref == 0)
173                     ref = 1;
174               }
175 #ifdef DEBUG
176               if (debug > 5)
177                 printf("Checking list %d member %d, ref = %d\n",
178                        ma->list_id, id2id(md->member_id), ref);
179 #endif DEBUG
180               if (m1 = find_member(ma->list_id, md->member_id)) {
181                   m1->frefc += ref;
182 #ifdef DEBUG
183                   if (debug > 5)
184                     printf("set refc to %d (%d) on list %d, member %d\n",
185                            m1->frefc, ref, m1->list_id, id2id(m1->member_id));
186 #endif DEBUG
187                   if (ma == m && md == m)
188                     m1->fdirect = 1;
189               } else {
190                   m1 = allocmember();
191                   m1->list_id = ma->list_id;
192                   m1->member_id = md->member_id;
193                   m1->frefc = ref;
194 #ifdef DEBUG
195                   if (debug > 5)
196                     printf("set new refc to %d (%d) on list %d, member %d\n",
197                            m1->frefc, ref, m1->list_id, id2id(m1->member_id));
198 #endif DEBUG
199                   sq_save_data(sq, m1);
200               }
201           }
202       }
203       while (sq_get_data(sq, &m)) {
204           insert_list(m);
205           insert_member(m);
206       }
207       sq_destroy(sq);
208       sq = sq_create();
209     }
210     EXEC SQL CLOSE csrm1; 
211     printf("created %d records\n", records);
212 }
213
214 verify_members()
215 {
216     struct member *m;
217     struct save_queue *sq;
218     EXEC SQL BEGIN DECLARE SECTION; 
219     int list_id, member_id, ref_count, dflag;
220     char mtype[9];
221     EXEC SQL END DECLARE SECTION; 
222     int errxtra, errbref, errbdir;
223 #ifdef DEBUG
224     int ref0, ref1, ref2, ref3, refg;
225     int db0, db1, db2, db3, dbg;
226 #endif DEBUG
227
228     /* verify members from database */
229     printf("Verifying members\n");
230     errxtra = errbref = errbdir = 0;
231 #ifdef DEBUG
232     ref0 = ref1 = ref2 = ref3 = refg = 0;
233     db0 = db1 = db2 = db3 = dbg = 0;
234 #endif DEBUG
235     sq = sq_create();
236 /*  retrieve (list_id = m.#list_id, member_id = m.#member_id,
237  *            mtype = m.member_type, ref_count = m.#ref_count,
238  *            dflag = m.#direct) { */
239     EXEC SQL DECLARE csrm2 CURSOR FOR
240         SELECT list_id, member_id, member_type, ref_count, direct 
241             FROM imembers;
242     EXEC SQL OPEN csrm2;
243     while(1) {
244         EXEC SQL FETCH csrm2 
245             INTO :list_id, :member_id, :mtype, :ref_count, :dflag;
246         if(sqlca.sqlcode != 0) break; 
247
248 #ifdef DEBUG
249       if (debug > 1)
250         switch (ref_count) {
251         case 0: db0++; break;
252         case 1: db1++; break;
253         case 2: db2++; break;
254         case 3: db3++; break;
255         default: dbg++;
256         }
257 #endif DEBUG
258       m = find_member(list_id, member2id(mtype[0], member_id));
259       if (m == NULL) {
260           m = allocmember();
261           m->list_id = list_id;
262           m->member_id = member2id(mtype[0], member_id);
263           m->fdirect = dflag;
264           m->frefc = ref_count;
265           sq_save_data(sq, m);
266           errxtra++;
267       } else {
268           m->ffound = 1;
269 #ifdef DEBUG    
270           if (debug > 1)
271             switch (m->frefc) {
272             case 0: ref0++; break;
273             case 1: ref1++; break;
274             case 2: ref2++; break;
275             case 3: ref3++; break;
276             default: refg++;
277             }
278 #endif DEBUG
279           m->frefc -= ref_count;
280           if (m->frefc != 0)
281             errbref++;
282           if (m->fdirect != dflag) {
283               m->fbaddirect = 1;
284               errbdir++;
285           }
286       }
287     }
288     EXEC SQL CLOSE csrm2; 
289     printf("Found %d extra records, %d bad ref counts, %d bad direct flags\n",
290            errxtra, errbref, errbdir);
291 #ifdef DEBUG
292     if (debug > 1) {
293         printf("Found in db: %d 0; %d 1; %d 2; %d 3; %d > 3\n",
294                db0, db1, db2, db3, dbg);
295         printf("Found  refs: %d 0; %d 1; %d 2; %d 3; %d > 3\n",
296                ref0, ref1, ref2, ref3, refg);
297     }
298 #endif DEBUG
299 }
300
301
302 fix_members()
303 {
304     struct member *m;
305     struct save_queue *sq;
306     int errmis = 0;
307     EXEC SQL BEGIN DECLARE SECTION; 
308     int list_id, member_id, rowcount;
309     char mtype[9];
310     EXEC SQL END DECLARE SECTION; 
311     char buf[512];
312
313     /* fix any errors */
314     printf("Fixing errors\n");
315     hash_step(lists, fix_member, &errmis);
316     while (sq_get_data(sq, &m)) {
317         printf("Extraneous member record, deleting:\n");
318         list_id = m->list_id;
319         member_id = id2id(m->member_id);
320         switch (id2type(m->member_id)) {
321         case 'U': strcpy(mtype, "USER"); break;
322         case 'L': strcpy(mtype, "LIST"); break;
323         case 'S': strcpy(mtype, "STRING"); break;
324         case 'K': strcpy(mtype, "KERBEROS"); break;
325         default:
326             mtype[0] = id2type(m->member_id);
327             mtype[1] = 0;
328         }
329         printf("  List: %d, Member: %s %d, Refc: %d, Direct %d\n",
330                list_id, mtype, member_id, m->frefc, m->fdirect);
331 #ifdef FIXERRORS
332 /*      delete m where m.#list_id = list_id and m.#member_id = member_id
333  *              and m.member_type = mtype */
334         EXEC SQL DELETE FROM imembers WHERE list_id = :list_id AND
335             member_id = :member_id AND member_type = :mtype;
336         EXEC SQL INQUIRE_SQL(:rowcount = rowcount); 
337         printf("  %d rows deleted\n", rowcount);
338 #endif FIXERRORS
339     }
340     if (errmis > 0)
341       printf("Added %d missing records\n", errmis);
342 }
343
344
345 insert_list(m)
346 struct member *m;
347 {
348     register struct member_list *l, *l1;
349
350     l = (struct member_list *) hash_lookup(lists, m->list_id);
351     if (l == NULL) {
352         l = (struct member_list *)malloc(sizeof(struct member_list));
353         if (l == NULL) {
354             fprintf(stderr, "No memory for insert_list\n");
355             exit(1);
356         }
357         l->next = NULL;
358         l->member = m;
359         hash_store(lists, m->list_id, l);
360         return;
361     }
362     for (l1 = l; l1; l1 = l1->next)
363       if (l1->member->member_id == m->member_id) {
364           fprintf(stderr, "Found 2nd copy of list record for\n");
365           fprintf(stderr, "List: %d, Member: %c %d, Refc: %d, Direct %d\n",
366                   m->list_id, id2type(m->member_id), id2id(m->member_id),
367                   m->frefc, m->fdirect);
368           kill(getpid(), SIGQUIT);
369           exit(2);
370       }
371
372     l1 = (struct member_list *)malloc(sizeof(struct member_list));
373     if (l1 == NULL) {
374         fprintf(stderr, "No memory for insert_list\n");
375         exit(1);
376     }
377     l1->next = l->next;
378     l->next = l1;
379     l1->member = m;
380 }
381
382
383 insert_member(m)
384 struct member *m;
385 {
386     register struct member_list *l, *l1;
387
388     l = (struct member_list *) hash_lookup(members, m->member_id);
389     if (l == NULL) {
390         l = (struct member_list *)malloc(sizeof(struct member_list));
391         if (l == NULL) {
392             fprintf(stderr, "No memory for insert_member\n");
393             exit(1);
394         }
395         l->next = NULL;
396         l->member = m;
397         hash_store(members, m->member_id, l);
398         return;
399     }
400
401     for (l1 = l; l1; l1 = l1->next)
402       if (l1->member->list_id == m->list_id) {
403           fprintf(stderr, "Found 2nd copy of member record for\n");
404           fprintf(stderr, "List: %d, Member: %c %d, Refc: %d, Direct %d\n",
405                   m->list_id, id2type(m->member_id), id2id(m->member_id),
406                   m->frefc, m->fdirect);
407           kill(getpid(), SIGQUIT);
408           exit(2);
409       }
410
411     l1 = (struct member_list *)malloc(sizeof(struct member_list));
412     if (l1 == NULL) {
413         fprintf(stderr, "No memory for insert_member\n");
414         exit(1);
415     }
416     l1->next = l->next;
417     l->next = l1;
418     l1->member = m;
419 }
420
421
422 struct member *find_member(listid, memberid)
423 int listid;
424 int memberid;
425 {
426     register struct member_list *l;
427
428     for (l = (struct member_list *) hash_lookup(lists, listid); l; l = l->next)
429       if (l->member->member_id == memberid)
430         return(l->member);
431     return(NULL);
432 }
433
434
435 /*ARGSUSED*/
436 void fix_member(dummy, l, errmis)
437 int dummy;
438 struct member_list *l;
439 int *errmis;
440 {
441     EXEC SQL BEGIN DECLARE SECTION; 
442     int list_id, member_id, ref_count, dflag, rowcount;
443     char *mtype;
444     EXEC SQL END DECLARE SECTION; 
445     char buf[2];
446     register struct member *m;
447
448     for (; l; l = l->next) {
449         m = l->member;
450
451         if (m->fscanned)
452           continue;
453         m->fscanned = 1;
454         if (m->fbaddirect == 0 && m->frefc == 0 && m->ffound == 1)
455           continue;
456         if (m->ffound == 0) {
457             printf("Missing member record, adding:\n");
458             list_id = m->list_id;
459             member_id = id2id(m->member_id);
460             ref_count = m->frefc;
461             dflag = m->fdirect;
462             switch (id2type(m->member_id)) {
463             case 'U': mtype = "USER"; break;
464             case 'L': mtype = "LIST"; break;
465             case 'S': mtype = "STRING"; break;
466             case 'K': mtype = "KERBEROS"; break;
467             default:
468                 mtype = buf;
469                 buf[0] = id2type(m->member_id);
470                 buf[1] = 0;
471             }
472             printf("  List: %d, Member: %s %d, Refc: %d, Direct %d\n",
473                    list_id, mtype, member_id, ref_count, dflag);
474             (*errmis)++;
475 #ifdef FIXERRORS
476 /*          append imembers (#list_id = list_id, #member_id = member_id,
477  *                           member_type = mtype, #ref_count = ref_count,
478  *                           direct = dflag); */
479             EXEC SQL INSERT INTO imembers (list_id, member_id, 
480                 member_type, ref_count, direct)
481               VALUES (:list_id, :member_id, :mtype, :ref_count, :dflag);
482             EXEC SQL INQUIRE_SQL(:rowcount = rowcount); 
483             printf("  %d rows added\n", rowcount);
484 #endif FIXERRORS
485             continue;
486         }
487         printf("Member record has bad ref_count and/or direct flag, fixing\n");
488         list_id = m->list_id;
489         member_id = id2id(m->member_id);
490         ref_count = m->frefc;
491         dflag = m->fdirect;
492         switch (id2type(m->member_id)) {
493         case 'U': mtype = "USER"; break;
494         case 'L': mtype = "LIST"; break;
495         case 'S': mtype = "STRING"; break;
496         case 'K': mtype = "KERBEROS"; break;
497         default:
498             mtype = buf;
499             buf[0] = id2type(m->member_id);
500             buf[1] = 0;
501         }
502         printf("  List: %d, Member: %s %d, Refc: %d, Direct %d\n",
503                list_id, mtype, member_id, ref_count, dflag);
504 #ifdef FIXERRORS
505 /*      replace m (#ref_count = m.#ref_count + ref_count, direct = dflag)
506  *        where m.#list_id = list_id and m.#member_id = member_id and
507  *          m.member_type = mtype */
508         EXEC SQL UPDATE imembers 
509             SET ref_count=ref_count+:ref_count, direct = :dflag 
510             WHERE list_id = :list_id AND member_id = :member_id AND
511                 member_tpe = :mtype;
512         EXEC SQL INQUIRE_SQL(:rowcount = rowcount); 
513         printf("  %d rows fixed\n", rowcount);
514 #endif FIXERRORS
515     }
516 }
517
518
519 struct member *allocmember()
520 {
521     register struct member *m;
522
523     m = (struct member *) malloc(sizeof(struct member));
524     if (m == NULL) {
525         fprintf(stderr, "No memory for new member\n");
526         exit(1);
527     }
528     m->fall = 0;
529     records++;
530     return(m);
531 }
532
533
534 int isinchain(m, l)
535 struct member *m;
536 register struct member_list *l;
537 {
538     for (; l; l = l->next)
539       if (l->member == m)
540         return(1);
541     return(0);
542 }
543
544
545 int chainlen(l)
546 register struct member_list *l;
547 {
548     register int i;
549     for (i = 0; l; l = l->next, i++);
550     return(i);
551 }
552
553
554 #ifdef DEBUG
555
556 /*ARGSUSED*/
557 void display_member(key, l, dummy1)
558 int key, dummy1;
559 struct member_list *l;
560 {
561     struct member *m;
562     char *mtype;
563
564     printf("%d*", key);
565     for(; l; l = l->next) {
566         m = l->member;
567         switch (id2type(m->member_id)) {
568         case 'U': mtype = "USER"; break;
569         case 'L': mtype = "LIST"; break;
570         case 'S': mtype = "STRING"; break;
571         case 'K': mtype = "KERBEROS"; break;
572         default: mtype = "???"; break;
573         }
574         printf("List: %d, Member: %s %d, Refc: %d, Direct %d\n",
575                m->list_id, mtype, id2id(m->member_id), m->frefc,
576                m->fdirect);
577     }
578 }
579
580 #endif DEBUG
This page took 0.165651 seconds and 3 git commands to generate.