]> andersk Git - moira.git/commitdiff
Initial revision
authorgenoa <genoa>
Thu, 19 Nov 1992 23:49:54 +0000 (23:49 +0000)
committergenoa <genoa>
Thu, 19 Nov 1992 23:49:54 +0000 (23:49 +0000)
dbck/dbck.dc [new file with mode: 0644]
dbck/fix.dc [new file with mode: 0644]
dbck/members.dc [new file with mode: 0644]
dbck/phase1.dc [new file with mode: 0644]
dbck/phase2.dc [new file with mode: 0644]
dbck/phase3.dc [new file with mode: 0644]
dbck/phase4.dc [new file with mode: 0644]

diff --git a/dbck/dbck.dc b/dbck/dbck.dc
new file mode 100644 (file)
index 0000000..5595702
--- /dev/null
@@ -0,0 +1,185 @@
+/* $Header$
+ *
+ * Moira database consistency checker
+ *
+ *  (c) Copyright 1988 by the Massachusetts Institute of Technology.
+ *  For copying and distribution information, please see the file
+ *  <mit-copyright.h>.
+ */
+
+#include <mit-copyright.h>
+#include <stdio.h>
+#include <strings.h>
+#include <signal.h>
+#include "dbck.h"
+
+
+static char dbck_qc_rcsid[] = "$Header$";
+
+
+int debug = 0;
+int mode = MODE_ASK;
+int fast = 0;
+int warn = 1;
+int abort = 0;
+struct hash *users, *machines, *clusters, *lists, *filesys, *nfsphys;
+struct hash *strings, *members;
+##int dcmenable;
+struct save_queue *modtables, *sq_create();
+int interrupt();
+
+
+main(argc, argv)
+int argc;
+char **argv;
+{
+    char **arg = argv;
+##  char *database;
+    int ingerr();
+    int countonly = 0;
+
+    database = "sms";
+
+    while (++arg - argv < argc) {
+       if  (**arg == '-')
+         switch ((*arg)[1]) {
+         case 'd':
+             debug = atoi((*arg)[2] ? *arg+2 : *++arg);
+             break;
+         case 'n':
+             mode = MODE_NO;
+             break;
+         case 'y':
+             mode = MODE_YES;
+             break;
+         case 'p':
+             mode = MODE_PREEN;
+             break;
+         case 'a':
+             mode = MODE_ASK;
+             break;
+         case 'c':
+             countonly++;
+             break;
+         case 'f':
+             fast++;
+             break;
+         case 'w':
+             warn = 0;
+             break;
+         default:
+             printf("Usage: %s [-d level] [-n] [-y] [-p] [-a] [-c] [-f] [-w] [database]\n",
+                    argv[0]);
+             exit(1);
+         }
+       else
+         database = *arg;
+    }
+    if (countonly)
+      printf("Only doing counts\n");
+    else if (fast)
+      printf("Doing fast version (skipping some checks)\n");
+    if (mode == MODE_NO)
+      printf("Will NOT modify the database\n");
+    else if (mode == MODE_PREEN)
+      printf("Will fix simple things without asking\n");
+    else if (mode == MODE_YES)
+      printf("Will fix everything without asking\n");
+    if (debug)
+      printf("Debug level is %d\n", debug);
+
+    setlinebuf(stdout);
+
+    signal(SIGHUP, interrupt);
+    signal(SIGQUIT, interrupt);
+    signal(SIGINT, interrupt);
+    modtables = sq_create();
+
+    IIseterr(ingerr);
+    printf("Opening database %s...", database);
+    fflush(stdout);
+##  ingres database
+    printf("done\n");
+##  retrieve (dcmenable = values.value) where values.name = "dcm_enable"
+    dprintf("DCM disabled (was %d)\n", dcmenable);
+##  replace values (value = 0) where values.name = "dcm_enable"
+
+##  begin transaction
+
+    if (!countonly) {
+       phase1();
+       phase2();
+       phase3();
+    } else {
+       count_only_setup();
+    }
+    phase4();
+
+##  end transaction
+    cleanup();
+    printf("Done.\n");
+    exit(0);
+}
+
+ingerr(num)
+int    *num;
+{
+    printf("An ingres error occuurred, code %d\n", *num);
+    printf("Aborting...\n");
+    if (!abort) {
+       abort++;
+##     abort
+    }
+    exit(1);
+}
+
+
+int interrupt()
+##{
+    printf("Signal caught\n");
+    if (prompt("Save database changes")) {
+       /* break out of a retrieve loop */
+       IIbreak();
+##     end transaction
+       cleanup();
+       exit(0);
+    }
+    printf("Aborting transaction\n");
+    if (!abort) {
+       abort++;
+       /* break out of a retrieve loop */
+       IIbreak();
+##     abort
+    }
+##  replace values (value = dcmenable) where values.name = "dcm_enable"
+##  exit
+    exit(0);
+##}
+
+
+modified(table)
+char *table;
+{
+    sq_save_unique_string(modtables, table);
+}
+
+cleanup()
+##{
+##  char *tab;
+
+    while (sq_get_data(modtables, &tab)) {
+##     replace tblstats (modtime = "now") where tblstats.table = tab
+    }
+##  replace values (value = dcmenable) where values.name = "dcm_enable"
+##  exit
+##}
+
+
+out_of_mem(msg)
+char *msg;
+{
+    fprintf(stderr, "Out of memory while %s\n", msg);
+##  end transaction    
+    cleanup();
+    exit(1);
+}
diff --git a/dbck/fix.dc b/dbck/fix.dc
new file mode 100644 (file)
index 0000000..6a05e78
--- /dev/null
@@ -0,0 +1,208 @@
+/* $Header$
+ *
+ * User interface routines for dbck (Moira database consistency checker)
+ *
+ *  (c) Copyright 1988 by the Massachusetts Institute of Technology.
+ *  For copying and distribution information, please see the file
+ *  <mit-copyright.h>.
+ */
+
+#include <mit-copyright.h>
+#include <moira.h>
+#include <stdio.h>
+#include "dbck.h"
+
+static char fix_qc_rcsid[] = "$Header$";
+
+
+##char *_table;
+##char *_idfield;
+
+##generic_ffunc(id)
+##int id;
+##{
+##  int rowcount;
+
+##  delete _table where _table._idfield = id
+##  inquire_equel(rowcount = "rowcount")
+    if (rowcount > 0)
+      printf("%d entr%s deleted\n", rowcount, rowcount==1?"y":"ies");
+    else
+      printf("Not deleted\n");
+    modified(_table);
+##}
+
+
+generic_delete(sq, pfunc, table, idfield, preen)
+struct save_queue *sq;
+void (*pfunc)();
+char *table, *idfield;
+int preen;
+{
+    _table = table;
+    _idfield = idfield;
+    generic_fix(sq, pfunc, "Delete", generic_ffunc, preen);
+}
+
+
+single_delete(table, idfield, id)
+char *table, *idfield;
+int id;
+{
+    _table = table;
+    _idfield = idfield;
+    generic_ffunc(id);
+}
+
+
+##zero_fix(table, zrfield, idfield, id)
+##char *table, *zrfield, *idfield;
+##int id;
+##{
+##  int rowcount;
+
+##  replace table (zrfield = 0) where table.idfield = id
+##  inquire_equel(rowcount = "rowcount")
+    if (rowcount > 0)
+      printf("%d entr%s fixed\n", rowcount, rowcount==1?"y":"ies");
+    else
+      printf("Not fixed\n");
+    modified(table);
+##}
+
+
+int single_fix(msg, preen)
+char *msg;
+int preen;
+{
+    if (mode == MODE_PREEN)
+      return(preen);
+
+    switch (mode) {
+    case MODE_ASK:
+       if (!prompt(msg))
+         break;
+    case MODE_YES:
+       return(1);
+       break;
+    case MODE_NO:
+       ;
+    }
+    return(0);
+}
+
+
+generic_fix(sq, pfunc, msg, ffunc, preen)
+struct save_queue *sq;
+char *msg;
+int (*pfunc)(), (*ffunc)();
+int preen;
+{
+    int id;
+
+    while (sq_get_data(sq, &id)) {
+       if ((*pfunc)(id) == 0 && single_fix(msg, preen))
+         (*ffunc)(id);
+    }
+    sq_destroy(sq);
+}
+
+
+int prompt(msg)
+char *msg;
+{
+    char buf[BUFSIZ];
+##  extern int dcmenable;
+
+    while (1) {
+       printf("%s (Y/N/Q)? ", msg);
+       fflush(stdout);
+       gets(buf);
+       if (buf[0] == 'Y' || buf[0] == 'y')
+         return(1);
+       if (buf[0] == 'N' || buf[0] == 'n')
+         return(0);
+       if (buf[0] == 'Q' || buf[0] == 'q') {
+           if (prompt("Are you sure you want to quit")) {
+               if (prompt("Save database changes")) {
+##                 end transaction
+                   cleanup();
+                   exit(0);
+               } else {
+##                 abort
+##                 replace values (value = dcmenable)
+##                     where values.name = "dcm_enable"
+##                 exit
+                   exit(1);
+               }
+           }
+       }
+    }
+}
+
+
+/**
+ ** set_next_object_id - set next object id in values table
+ **
+ ** Inputs: object - object name in values table and in objects
+ **        table - name of table objects are found in
+ **
+ ** - called before an APPEND operation to set the next object id to
+ **   be used for the new record to the next free value
+ **
+ **/
+
+int set_next_object_id(object, table)
+    char *object;
+    char *table;
+##{
+##  char *name, *tbl;
+##  int rowcount, exists, value;
+
+    name = object;
+    tbl = table;
+##  range of v is values
+##  repeat retrieve (value = v.#value) where v.#name = @name
+##  inquire_equel(rowcount = "rowcount")
+    if (rowcount != 1)
+       return(MR_NO_ID);
+
+##  retrieve (exists = any(tbl.name where tbl.name = value))
+##  inquire_equel(rowcount = "rowcount")
+    if (rowcount != 1)
+       return(MR_NO_ID);
+    while (exists) {
+       value++;
+       if (value > MAX_ID_VALUE)
+           value = MIN_ID_VALUE;
+##     retrieve (exists = any(tbl.name where tbl.name = value))
+    }
+
+    printf("setting ID %s to %d\n", name, value);
+##  repeat replace v (#value = @value) where v.#name = @name
+    modified("values");
+    return(MR_SUCCESS);
+##}
+
+
+##generic_fix_id(table, idfield, txtfield, oldid, name)
+##char *table;
+##char *idfield;
+##char *txtfield;
+##int oldid;
+##char *name;
+##{
+##  int rowcount, id;
+
+    set_next_object_id(table, idfield);
+##  retrieve (id = values.value) where values.#name = idfield
+##  replace table (idfield = values.value) where values.#name = idfield and
+##     table.idfield = oldid and table.txtfield = name
+##  inquire_equel(rowcount = "rowcount")
+    if (rowcount == 1)
+      printf("Fixed\n");
+    else
+      printf("Not fixed, rowcount = %d\n", rowcount);
+    modified(table);
+    return(id);
+##}
diff --git a/dbck/members.dc b/dbck/members.dc
new file mode 100644 (file)
index 0000000..f5eae0a
--- /dev/null
@@ -0,0 +1,537 @@
+/* $Header$
+ */
+
+#include <stdio.h>
+#include <signal.h>
+#include <moira.h>
+
+#define FIXERRORS
+
+#define max(x, y)      ((x) > (y) ? (x) : (y))
+
+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;
+
+
+main(argc, argv)
+int argc;
+char **argv;
+##{
+    char buf[256];
+
+#ifdef DEBUG
+    if (argc > 1)
+      debug = atoi(argv[1]);
+#endif DEBUG
+
+##  ingres sms
+##  begin transaction
+##  range of m is imembers
+
+    lists = create_hash(10000);
+    members = create_hash(10000);
+    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
+    } else {
+#endif FIXERRORS
+       printf("Aborting transaction\n");
+##     abort
+#ifdef FIXERRORS
+    }
+#endif FIXERRORS
+
+##  exit
+    printf("Done.\n");
+
+    exit(0);
+##}
+
+
+
+load_members()
+##{
+    struct member *m, *m1, *md, *ma;
+    struct member_list *descendants, *ancestors, *desc, *ance, la, ld;
+##  int list_id, member_id, ref_count, ref;
+##  char mtype[9];
+    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 {
+#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();
+##  }
+    printf("created %d records\n", records);
+##}
+
+verify_members()
+##{
+    struct member *m;
+    struct save_queue *sq;
+##  int list_id, member_id, ref_count, dflag;
+##  char mtype[9];
+    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) {
+#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++;
+         }
+      }
+##  }
+    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;
+##  int list_id, member_id, rowcount;
+##  char mtype[9];
+    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
+##     inquire_equel(rowcount = "rowcount")
+       printf("  %d rows deleted\n", rowcount);
+#endif FIXERRORS
+    }
+    if (errmis > 0)
+      printf("Added %d missing records\n", errmis);
+##}
+
+
+insert_list(m)
+struct member *m;
+{
+    register 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;
+       hash_store(lists, m->list_id, l);
+       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;
+{
+    register 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;
+       hash_store(members, m->member_id, l);
+       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;
+{
+    register 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;
+##{
+##  int list_id, member_id, ref_count, dflag, rowcount;
+##  char *mtype;
+    char buf[2];
+    register 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);
+##         inquire_equel(rowcount = "rowcount")
+           printf("  %d rows added\n", rowcount);
+#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
+##     inquire_equel(rowcount = "rowcount");
+       printf("  %d rows fixed\n", rowcount);
+#endif FIXERRORS
+    }
+##}
+
+
+struct member *allocmember()
+{
+    register 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;
+register struct member_list *l;
+{
+    for (; l; l = l->next)
+      if (l->member == m)
+       return(1);
+    return(0);
+}
+
+
+int chainlen(l)
+register struct member_list *l;
+{
+    register 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
diff --git a/dbck/phase1.dc b/dbck/phase1.dc
new file mode 100644 (file)
index 0000000..a5e0e69
--- /dev/null
@@ -0,0 +1,426 @@
+/* $Header$
+ *
+ *  (c) Copyright 1988 by the Massachusetts Institute of Technology.
+ *  For copying and distribution information, please see the file
+ *  <mit-copyright.h>.
+ */
+
+#include <mit-copyright.h>
+#include <moira.h>
+#include "dbck.h"
+
+static char phase1_qc_rcsid[] = "$Header$";
+
+
+show_user_id(u)
+struct user *u;
+{
+    printf("User %s (%s, status %d) has duplicate ID\n",
+          u->login, u->fullname, u->status);
+    return(0);
+}
+
+handle_duplicate_logins(sq)
+struct save_queue *sq;
+{
+    struct user *u, *uu, *tmp;
+
+    uu = (struct user *)0;
+    while (sq_get_data(sq, &u)) {
+       if (!strcmp(u->login, uu->login)) {
+           if (uu->status == 1 || u->status == 0) {
+               tmp = u;
+               u = uu;
+               uu = tmp;
+           }
+           printf("User %s (%s, status %d) and\n",
+                  u->login, u->fullname, u->status);
+           printf("User %s (%s, status %d) have duplicate logins\n",
+                  uu->login, uu->fullname, uu->status);
+           if (!strcmp(u->fullname, uu->fullname) &&
+               single_fix("Delete the second one")) {
+               single_delete("users", "users_id", uu->users_id);
+           } else if (single_fix("Unregister the second one"))
+##           {
+##             int id = uu->users_id, rowcount;
+
+##             replace users (login = "#"+text(users.uid), status = 0)
+##                 where users.users_id = id
+##             inquire_equel(rowcount = "rowcount")
+               if (rowcount > 0)
+                 printf("%d entr%s fixed\n", rowcount, rowcount==1?"y":"ies");
+               else
+                 printf("Not fixed\n");
+               modified("users");
+##         }
+       } else {
+           uu = u;
+       }
+    }
+}
+
+fix_user_id(u)
+struct user *u;
+{
+    u->users_id = generic_fix_id("users", "users_id", "login",
+                                u->users_id, u->login);
+}
+
+
+cant_fix(id)
+int id;
+{
+    printf("Sorry, don't know how to fix that\n");
+}
+
+show_mach_id(m)
+struct machine *m;
+{
+    printf("Machine %s has duplicate ID %d\n", m->name, m->mach_id);
+    return(0);
+}
+
+show_mach_name(m)
+struct machine *m;
+{
+    printf("Machine %s (%d) has duplicate name\n", m->name, m->mach_id);
+    return(0);
+}
+
+fix_mach_id(m)
+struct machine *m;
+{
+    m->mach_id = generic_fix_id("machine", "mach_id", "name",
+                               m->mach_id, m->name);
+}
+
+show_clu_id(c)
+struct cluster *c;
+{
+    printf("Cluster %s has duplicate ID %d\n", c->name, c->clu_id);
+    return(0);
+}
+
+show_clu_name(c)
+struct cluster *c;
+{
+    printf("Cluster %s (%d) has duplicate name\n", c->name, c->clu_id);
+    return(0);
+}
+
+fix_clu_id(c)
+struct cluster *c;
+{
+    c->clu_id = generic_fix_id("cluster", "clu_id", "name", c->clu_id, c->name);
+}
+
+show_list_id(l)
+struct list *l;
+{
+    printf("List %s has duplicate ID %d\n", l->name, l->list_id);
+    return(0);
+}
+
+show_list_name(l)
+struct list *l;
+{
+    printf("List %s (%d) has duplicate name\n", l->name, l->list_id);
+    return(0);
+}
+
+fix_list_id(l)
+struct list *l;
+{
+    l->list_id = generic_fix_id("list", "list_id", "name", l->list_id, l->name);
+}
+
+show_fs_id(f)
+struct filesys *f;
+{
+    printf("Filesys %s has duplicate ID %d\n", f->name, f->filsys_id);
+    return(0);
+}
+
+fix_fs_id(f)
+struct filesys *f;
+{
+    f->filsys_id = generic_fix_id("filesys", "filsys_id", "label",
+                                 f->filsys_id, f->name);
+}
+
+
+show_np_id(n)
+struct nfsphys *n;
+{
+    printf("NfsPhys %s:%s has duplicate ID %d\n",
+          ((struct machine *)hash_lookup(machines, n->mach_id))->name,
+          n->dir, n->nfsphys_id);
+    return(0);
+}
+
+fix_np_id(n)
+struct nfsphys *n;
+{
+    n->nfsphys_id = generic_fix_id("nfsphys", "nfsphys_id", "dir",
+                                  n->nfsphys_id, n->dir);
+}
+
+show_str_id(s)
+struct string *s;
+{
+    printf("String %s has duplicate ID %d\n", s->name, s->string_id);
+    return(0);
+}
+
+
+phase1()
+##{
+##  char name[81], name1[81], last[17], first[17], buf[257];
+##  int id, id2, id3, aid, aid2, status, sid, sid2, sid3, sid4, sid5;
+    struct save_queue *sq;
+    struct user *u;
+    struct machine *m;
+    struct list *l;
+    struct cluster *c;
+    struct string *s;
+    struct filesys *f;
+    struct nfsphys *n;
+
+    printf("Phase 1 - Looking for duplicates\n");
+
+    dprintf("Loading strings...\n");
+    sq = sq_create();
+    strings = create_hash(5000);
+##  range of s is strings
+##  retrieve (id = s.string_id, buf = s.string) {
+       s = (struct string *) malloc(sizeof(struct string));
+       if (s == NULL)
+         out_of_mem("storing strings");
+       s->name = strsave(strtrim(buf));
+       s->string_id = id;
+       s->refc = 0;
+       if (hash_store(strings, id, s)) {
+           sq_save_data(sq, hash_lookup(strings, id));
+           sq_save_data(sq, s);
+       }
+##  }
+    generic_delete(sq, show_str_id, "strings", "string_id", 0);
+    string_check(0);
+
+    dprintf("Loading users...\n");
+    sq = sq_create();
+    users = create_hash(10000);
+##  range of u is users
+##  retrieve (id = u.users_id, name = u.login, last = u.#last,
+##           first = u.#first, status = u.#status, buf = u.potype,
+##           id2 = u.pop_id, id3 = u.box_id, sid = u.modby, sid2 = u.fmodby,
+##           sid3 = u.pmodby, sid4 = u.comment, sid5 = u.sigwho) {
+       u = (struct user *) malloc(sizeof(struct user));
+       if (u == NULL)
+         out_of_mem("storing users");
+       strcpy(u->login, strtrim(name));
+       u->potype = buf[0];
+       sprintf(buf, "%s, %s", strtrim(last), strtrim(first));
+       u->fullname = strsave(buf);
+       u->status = status;
+       u->users_id = id;
+       switch (u->potype) {
+       case 'P':
+           u->pobox_id = id2;
+           break;
+       case 'S':
+           u->pobox_id = id3;
+           break;
+       default:
+           u->pobox_id = 0;
+       }
+       if (hash_store(users, id, u)) {
+           sq_save_data(sq, hash_lookup(users, id));
+           sq_save_data(sq, u);
+       }
+       if (sid < 0)
+         string_check(-sid);
+       if (sid2 < 0)
+         string_check(-sid2);
+       if (sid3 < 0)
+         string_check(-sid3);
+       if (sid4)
+         string_check(sid4);
+       if (sid5)
+         string_check(sid5);
+##  }
+    generic_fix(sq, show_user_id, "Change ID", fix_user_id, 0);
+
+    if (!fast) {
+       sq = sq_create();
+##     retrieve (id = u.users_id)
+##         where u.login = users.login and u.tid != users.tid {
+         sq_save_data(sq, hash_lookup(users, id));
+##     }
+       handle_duplicate_logins(sq);
+    }
+
+    dprintf("Loading machines...\n");
+    machines = create_hash(1000);
+    sq = sq_create();
+##  range of m is machine
+##  retrieve (id = m.mach_id, name = m.#name, sid = m.modby) {
+       m = (struct machine *) malloc(sizeof(struct machine));
+       if (m == NULL)
+         out_of_mem("storing machines");
+       strcpy(m->name, strtrim(name));
+       m->mach_id = id;
+       m->clucount = 0;
+       if (hash_store(machines, id, m)) {
+           sq_save_data(sq, hash_lookup(machines, id));
+           sq_save_data(sq, m);
+       }
+       if (sid < 0)
+         string_check(-sid);
+##  }
+    generic_fix(sq, show_mach_id, "Change ID", fix_mach_id, 0);
+
+    if (!fast) {
+       sq = sq_create();
+##     retrieve (id = m.mach_id)
+##         where m.#name = machine.#name and m.tid != machine.tid {
+         sq_save_data(sq, hash_lookup(machines, id));
+##     }
+       generic_fix(sq, show_mach_name, "Change name", cant_fix, 0);
+    }  
+
+    dprintf("Loading clusters...\n");
+    sq = sq_create();
+    clusters = create_hash(100);
+##  range of c is cluster
+##  retrieve (id = c.clu_id, name = c.#name, sid = c.modby) {
+       c = (struct cluster *) malloc(sizeof(struct cluster));
+       if (c == NULL)
+         out_of_mem("storing clusters");
+       strcpy(c->name, strtrim(name));
+       c->clu_id = id;
+       if (hash_store(clusters, id, c)) {
+           sq_save_data(sq, hash_lookup(clusters, id));
+           sq_save_data(sq, c);
+       }
+       if (sid < 0)
+         string_check(-sid);
+##  }
+    generic_fix(sq, show_clu_id, "Change ID", fix_clu_id, 0);
+
+    if (!fast) {
+       sq = sq_create();
+##     retrieve (id = c.clu_id)
+##         where c.#name = cluster.#name and c.tid != cluster.tid {
+         sq_save_data(sq, hash_lookup(clusters, id));
+##     }
+       generic_fix(sq, show_clu_name, "Change name", cant_fix, 0);
+    }
+
+    dprintf("Loading lists...\n");
+    sq = sq_create();
+    lists = create_hash(10000);
+##  range of l is list
+##  retrieve (id = l.list_id, name = l.#name,
+##           aid = l.acl_id, buf = l.acl_type, sid = l.modby) {
+       l = (struct list *) malloc(sizeof(struct list));
+       if (l == NULL)
+         out_of_mem("storing lists");
+       strcpy(l->name, strtrim(name));
+       l->acl_type = buf[0];
+       l->acl_id = aid;
+       l->list_id = id;
+       l->members = 0;
+       if (hash_store(lists, id, l)) {
+           sq_save_data(sq, hash_lookup(lists, id));
+           sq_save_data(sq, l);
+       }
+       if (sid < 0)
+         string_check(-sid);
+##  }
+    generic_fix(sq, show_list_id, "Change ID", fix_list_id, 0);
+
+    if (!fast) {
+       sq = sq_create();
+##     retrieve (id = l.list_id)
+##         where l.#name = list.#name and l.tid != list.tid {
+         sq_save_data(sq, hash_lookup(lists, id));
+##     }
+       generic_fix(sq, show_list_name, "Change name", cant_fix, 0);
+    }
+
+    dprintf("Loading filesys...\n");
+    sq = sq_create();
+    filesys = create_hash(10000);
+##  retrieve (id = filesys.filsys_id, name = filesys.label, aid = filesys.owner,
+##           aid2 = filesys.owners, id2 = filesys.phys_id,
+##           id3 = filesys.mach_id, buf = filesys.type,
+##           name1 = filesys.#name, sid = filesys.modby) {
+       f = (struct filesys *) malloc(sizeof(struct filesys));
+       if (f == NULL)
+         out_of_mem("storing filesystems");
+       strcpy(f->name, strtrim(name));
+       strcpy(f->dir, strtrim(name1));
+       f->filsys_id = id;
+       f->owner = aid;
+       f->owners = aid2;
+       f->phys_id = id2;
+       f->mach_id = id3;
+       f->type = buf[0];
+       if (hash_store(filesys, id, f)) {
+           sq_save_data(sq, hash_lookup(filesys, id));
+           sq_save_data(sq, f);
+       }
+       if (sid < 0)
+         string_check(-sid);
+##  }
+    generic_fix(sq, show_fs_id, "Change ID", fix_fs_id, 0);
+
+    dprintf("Loading nfsphys...\n");
+    sq = sq_create();
+    nfsphys = create_hash(500);
+##  retrieve (id = nfsphys.nfsphys_id, name = nfsphys.dir,
+##           id2 = nfsphys.mach_id, id3 = nfsphys.allocated,
+##           sid = nfsphys.modby) {
+       n = (struct nfsphys *) malloc(sizeof(struct nfsphys));
+       if (n == NULL)
+         out_of_mem("storing nfsphys");
+       strcpy(n->dir, strtrim(name));
+       n->mach_id = id2;
+       n->nfsphys_id = id;
+       n->allocated = id3;
+       n->count = 0;
+       if (hash_store(nfsphys, id, n)) {
+           sq_save_data(sq, hash_lookup(nfsphys, id));
+           sq_save_data(sq, n);
+       }
+       if (sid < 0)
+         string_check(-sid);
+##  }
+    generic_fix(sq, show_np_id, "Change ID", fix_np_id, 0);
+
+    if (!fast) {
+##     range of s is strings
+##     retrieve (id = s.string_id, buf = s.string)
+##         where s.string = strings.string and s.tid != strings.tid {
+         printf("String %s(%d) is a duplicate!\n", strtrim(buf), id);
+         printf("Not fixing this error\n");
+##     }
+    }
+
+    if (!fast) {
+       dprintf("Scanning krbmap...\n");
+##     range of k is krbmap
+##     retrieve (id = k.users_id)
+##         where k.users_id = krbmap.users_id and k.tid != krbmap.tid {
+         printf("User %d is in the krbmap more than once!\n", id);
+         printf("Not fixing this error\n");
+##     }
+##     retrieve (id = k.string_id)
+##         where k.string_id = krbmap.string_id and k.tid != krbmap.tid {
+         printf("Principal %d is in the krbmap more than once!\n", id);
+         printf("Not fixing this error\n");
+##     }
+    }
+##}
+
diff --git a/dbck/phase2.dc b/dbck/phase2.dc
new file mode 100644 (file)
index 0000000..9a0840d
--- /dev/null
@@ -0,0 +1,954 @@
+/* $Header$
+ *
+ *  (c) Copyright 1988 by the Massachusetts Institute of Technology.
+ *  For copying and distribution information, please see the file
+ *  <mit-copyright.h>.
+ */
+
+#include <mit-copyright.h>
+#include <stdio.h>
+#include <moira.h>
+#include "dbck.h"
+
+static char phase2_qc_rcsid[] = "$Header$";
+
+
+show_mcm_mach(id)
+int id;
+##{
+##  int iid = id, found = 1;
+##  char name[33];
+
+##  retrieve (name = cluster.#name) where cluster.clu_id = mcmap.clu_id
+##     and mcmap.mach_id = iid {
+      strtrim(name);
+      found = 0;
+      printf("Cluster %s, non-existant machine %d in cluster map\n", name, id);
+##  }
+    return(found);
+##}
+
+show_mcm_clu(id)
+int id;
+##{
+##  int iid = id, found = 1;
+##  char name[33];
+
+##  retrieve (name = machine.#name) where machine.mach_id = mcmap.mach_id
+##     and mcmap.clu_id = iid {
+      strtrim(name);
+      found = 0;
+      printf("Machine %s, non-existant cluster %d in cluster map\n", name, id);
+##  }
+    return(found);
+##}
+
+pobox_check(id, u, hint)
+int id;
+struct user *u;
+int hint;
+{
+    switch (u->potype) {
+    case 'P':
+       if (!hash_lookup(machines, u->pobox_id)) {
+           printf("User %s(%s) has P.O.Box on non-existant machine %d\n",
+                  u->login, u->fullname, u->pobox_id);
+           if (single_fix("Delete", 0)) {
+               remove_pobox(u->users_id);
+               u->potype = 'N';
+           }
+       }
+       break;
+    case 'S':
+       if (!string_check(u->pobox_id)) {
+           printf("User %s(%s) has P.O.Box with non-existant string %d\n",
+                  u->login, u->fullname, u->pobox_id);
+           if (single_fix("Delete", 0)) {
+               remove_pobox(u->users_id);
+               u->potype = 'N';
+           }
+       }
+       break;
+    default:
+       ;
+    }
+}
+
+
+remove_pobox(id)
+int id;
+##{
+##  int rowcount, iid = id;
+##  replace users (potype = "NONE") where users.users_id = iid
+##  inquire_equel(rowcount = "rowcount")
+    if (rowcount > 0)
+      printf("%d entr%s removed\n", rowcount, rowcount==1?"y":"ies");
+    else
+      printf("Not removed\n");
+    modified("users");
+##}
+
+show_svc(id)
+int id;
+##{
+##  int iid = id, found = 1;
+##  char label[17], data[33];
+
+##  retrieve (label = svc.serv_label, data = svc.serv_cluster) 
+##     where svc.clu_id = iid {
+      strtrim(label);
+      strtrim(data);
+      found = 0;
+      printf("Cluster data [%s] %s for non-existant cluster %d\n",
+            label, data, id);
+##  }
+    return(found);
+##}
+
+list_check(id, l, hint)
+int id;
+struct list *l;
+int hint;
+{
+    switch (l->acl_type) {
+    case 'L':
+       if (!hash_lookup(lists, l->acl_id)) {
+           printf("List %s has bad LIST acl %d\n", l->name, l->acl_id);
+           if (single_fix("Patch", 1)) {
+               fix_list_acl(l->list_id);
+           }
+       }
+       break;
+    case 'U':
+       if (!hash_lookup(users, l->acl_id)) {
+           printf("List %s has bad USER acl %d\n", l->name, l->acl_id);
+           if (single_fix("Patch", 1)) {
+               fix_list_acl(l->list_id);
+           }
+       }
+       break;
+    }
+}
+
+fix_list_acl(id)
+int id;
+##{
+##  int rowcount, iid = id;
+##  replace list (acl_id = iid, acl_type = "LIST") where list.list_id = iid
+##  inquire_equel(rowcount = "rowcount")
+    if (rowcount > 0)
+      printf("%d entr%s fixed\n", rowcount, rowcount==1?"y":"ies");
+    else
+      printf("Not fixed\n");
+    modified("list");
+##}
+
+
+show_member_list(id)
+int id;
+##{
+##  int mid, iid = id, found = 1;
+##  char mtype[9], *name = "";
+
+##  retrieve (mtype = imembers.member_type, mid = imembers.member_id)
+##     where imembers.list_id = iid and imembers.direct = 1 {
+      strtrim(mtype);
+      found = 0;
+      if (mtype[0] == 'L')
+       name = ((struct list *) hash_lookup(lists, mid))->name;
+      else if (mtype[0] == 'U')
+       name = ((struct user *) hash_lookup(users, mid))->login;
+      else if (mtype[0] == 'S' || mtype[0] == 'K')
+       name = ((struct string *) hash_lookup(strings, mid))->name;
+      printf("Non-existant list %d has member %s %s\n", iid, mtype, name);
+##  }
+    return(found);
+##}
+
+show_mem_user(id)
+int id;
+##{
+##  int lid, iid = id, found = 1;
+##  char name[33];
+
+##  retrieve (lid = imembers.list_id)
+##     where imembers.member_id = iid and imembers.member_type = "USER" and
+##           imembers.direct = 1 {
+      found = 0;
+      printf("List %s has non-existant user member, id %d\n",
+            ((struct list *)hash_lookup(lists, lid))->name, iid);
+##  }
+    return(found);
+##}
+
+show_mem_list(id)
+int id;
+##{
+##  int lid, iid = id, found = 1;
+##  char name[33];
+
+##  retrieve (lid = imembers.list_id)
+##     where imembers.member_id = iid and imembers.member_type = "LIST" and
+##           imembers.direct = 1 {
+      found = 0;
+      printf("List %s has non-existant list member, id %d\n",
+            ((struct list *)hash_lookup(lists, lid))->name, iid);
+##  }
+    return(found);
+##}
+
+show_mem_str(id)
+int id;
+##{
+##  int lid, iid = id, found = 1;
+##  char name[33];
+
+##  retrieve (lid = imembers.list_id)
+##     where imembers.member_id = iid and imembers.member_type = "STRING" and
+##           imembers.direct = 1 {
+      found = 0;
+      printf("List %s has non-existant string member, id %d\n",
+            ((struct list *)hash_lookup(lists, lid))->name, iid);
+##  }
+    return(found);
+##}
+
+
+show_mem_krb(id)
+int id;
+##{
+##  int lid, iid = id, found = 1;
+##  char name[33];
+
+##  retrieve (lid = imembers.list_id)
+##     where imembers.member_id = iid and imembers.member_type = "KERBEROS" and
+##           imembers.direct = 1 {
+      found = 0;
+      printf("List %s has non-existant kerberos member, id %d\n",
+            ((struct list *)hash_lookup(lists, lid))->name, iid);
+##  }
+    return(found);
+##}
+
+
+##del_mem_user(id)
+##int id;
+##{
+##  int rowcount;
+
+##  delete imembers where imembers.member_type = "USER" and
+##     imembers.member_id = id and imembers.direct = 1
+##  inquire_equel(rowcount = "rowcount");
+    if (rowcount > 0)
+      printf("%d entr%s deleted\n", rowcount, rowcount==1?"y":"ies");
+    else
+      printf("Not deleted\n");
+    modified("imembers");
+##}
+
+##del_mem_list(id)
+##int id;
+##{
+##  int rowcount;
+
+##  delete imembers where imembers.member_type = "LIST" and
+##     imembers.member_id = id and imembers.direct = 1
+##  inquire_equel(rowcount = "rowcount");
+    if (rowcount > 0)
+      printf("%d entr%s deleted\n", rowcount, rowcount==1?"y":"ies");
+    else
+      printf("Not deleted\n");
+    modified("imembers");
+##}
+
+##del_mem_str(id)
+##int id;
+##{
+##  int rowcount;
+
+##  delete imembers where imembers.member_type = "STRING" and
+##     imembers.member_id = id and imembers.direct = 1
+##  inquire_equel(rowcount = "rowcount");
+    if (rowcount > 0)
+      printf("%d entr%s deleted\n", rowcount, rowcount==1?"y":"ies");
+    else
+      printf("Not deleted\n");
+    modified("imembers");
+##}
+
+
+##del_mem_krb(id)
+##int id;
+##{
+##  int rowcount;
+
+##  delete imembers where imembers.member_type = "KERBEROS" and
+##     imembers.member_id = id and imembers.direct = 1
+##  inquire_equel(rowcount = "rowcount");
+    if (rowcount > 0)
+      printf("%d entr%s deleted\n", rowcount, rowcount==1?"y":"ies");
+    else
+      printf("Not deleted\n");
+    modified("imembers");
+##}
+
+
+##show_sh(id)
+##int id;
+##{
+##  char name[33];
+    int found = 1;
+
+##  retrieve (name = serverhosts.service) where serverhosts.mach_id = id {
+      found = 0;
+      printf("ServerHost entry for service %s non-existant host %d\n",
+            name, id);
+##  }
+    return(found);
+##}
+
+##del_sh_mach(id)
+##int id;
+##{
+##  int rowcount;
+
+##  delete serverhosts where serverhosts.mach_id = id
+##  inquire_equel(rowcount = "rowcount");
+    if (rowcount > 0)
+      printf("%d entr%s deleted\n", rowcount, rowcount==1?"y":"ies");
+    else
+      printf("Not deleted\n");
+    modified("serverhosts");
+##}
+
+
+static int fnchecklen;
+
+fsmatch(id, n, f)
+int id;
+struct nfsphys *n;
+struct filesys *f;
+{
+    if (n->mach_id == f->mach_id &&
+       !strncmp(f->dir, n->dir, strlen(n->dir)) &&
+       strlen(n->dir) > fnchecklen) {
+       f->phys_id = id;
+       fnchecklen = strlen(n->dir);
+    }
+}
+
+
+##check_fs(id, f, hint)
+##int id;
+register struct filesys *f;
+int hint;
+##{
+##  int id1, id2, id3, rowcount;
+##  char *dir;
+    struct nfsphys *n;
+    struct machine *m;
+
+    if (!hash_lookup(machines, f->mach_id)) {
+       printf("Filesys %s with bad machine %d\n", f->name, f->mach_id);
+       if (single_fix("Fix", 0)) {
+##         replace filesys (mach_id = 0) where filesys.filsys_id = id
+##         inquire_equel(rowcount = "rowcount")
+           if (rowcount > 0)
+             printf("%d entr%s fixed\n",rowcount, rowcount==1?"y":"ies");
+           else
+             printf("Not fixed\n");
+           modified("filesys");
+           f->mach_id = 0;
+       }
+    }
+
+    if (!hash_lookup(users, f->owner)) {
+       printf("Filesys %s with bad owning user %d\n", f->name, f->owner);
+       if (single_fix("Fix", 1)) {
+           zero_fix("filesys", "owner", "filsys_id", f->filsys_id);
+           f->owner = 0;
+       }
+    }
+    if (!hash_lookup(lists, f->owners)) {
+       printf("Filesys %s with bad owning group %d\n", f->name, f->owners);
+       if (single_fix("Fix", 1)) {
+           zero_fix("filesys", "owners", "filsys_id", f->filsys_id);
+           f->owners = 0;
+       }
+    }
+
+    if (f->type == 'N') {
+       if (!hash_lookup(nfsphys, f->phys_id)) {
+           m = (struct machine *)hash_lookup(machines, f->mach_id);
+           printf("Filesys %s with bad phys_id %d\n", f->name, f->phys_id);
+           if (single_fix("Fix", 1)) {
+               fnchecklen = 0;
+               hash_step(nfsphys, fsmatch, f);
+               if (fnchecklen != 0) {
+                 id1 = f->phys_id;
+                 id2 = f->filsys_id;
+                 id3 = f->mach_id;
+##               replace filesys (phys_id = id1) where filesys.filsys_id = id2
+##               inquire_equel(rowcount = "rowcount")
+                 if (rowcount > 0)
+                   printf("%d entr%s fixed\n",rowcount, rowcount==1?"y":"ies");
+                 else
+                   printf("Not fixed\n");
+                 modified("filesys");
+               } else {
+                   printf("No NFSphys exsits for %s:%s\n", m->name, f->dir);
+                   if (single_fix("Create", 0)) {
+                       dir = f->dir;
+                       id1 = f->phys_id;
+                       id2 = f->filsys_id;
+                       id3 = f->mach_id;
+                       if (set_next_object_id("nfsphys_id", "nfsphys") !=
+                               MR_SUCCESS) {
+                           printf("Unable to assign unique ID\n");
+                           return;
+                       }
+##                     retrieve (id1 = values.value)
+##                       where values.name = "nfsphys_id"
+##                     inquire_equel(rowcount = "rowcount")
+                       if (rowcount != 1) {
+                           printf("Unable to retrieve unique ID\n");
+                           return;
+                       }
+##                     append nfsphys (nfsphys_id = id1, mach_id = id3,
+##                                     device = "???", #dir = dir, status = 0,
+##                                     allocated = 0, size = 0,
+##                                     modtime = "now", modby = 0,
+##                                     modwith = "dbck")
+##                     inquire_equel(rowcount = "rowcount")
+                       if (rowcount > 0)
+                         printf("%d entr%s created\n", rowcount,
+                                rowcount==1?"y":"ies");
+                       else
+                         printf("Not created\n");
+                       modified("nfsphys");
+                       n = (struct nfsphys *)malloc(sizeof(struct nfsphys));
+                       if (n == NULL)
+                         out_of_mem("storing new nfsphys");
+                       strcpy(n->dir, dir);
+                       n->mach_id = id3;
+                       n->nfsphys_id = id1;
+                       n->allocated = 0;
+                       n->count = 0;
+                       hash_store(nfsphys, id1, n);
+##                     replace filesys (phys_id = id1)
+##                       where filesys.filsys_id = id2
+##                     inquire_equel(rowcount = "rowcount")
+                       if (rowcount > 0)
+                         printf("%d filesys entr%s fixed\n", rowcount,
+                                rowcount==1?"y":"ies");
+                       else
+                         printf("Not fixed\n");
+                       modified("filesys");
+                   }
+               }
+           }
+       }
+    }
+##}
+
+
+check_nfsphys(id, n, hint)
+int id;
+struct nfsphys *n;
+int hint;
+{
+    if (!hash_lookup(machines, n->mach_id)) {
+       printf("NFSphys %d(%s) on non-existant machine %d\n",
+              id, n->dir, n->mach_id);
+       if (single_fix("Delete", 0))
+         single_delete("nfsphys", "nfsphys_id", id);
+    }
+}
+
+##show_fsg_missing(id)
+##int id;
+##{
+##  int id1, found = 1;
+    struct filesys *f;
+
+##  retrieve (id1 = fsgroup.filsys_id) where fsgroup.group_id = id {
+      found = 0;
+      if (f = (struct filesys *) hash_lookup(filesys, id1))
+       printf("Missing fsgroup %d has member filesystem %s\n", id, f->name);
+      else
+       printf("Missing fsgroup %d has member filesystem %d\n", id, id1);
+##  }
+    return(found);
+##}
+
+show_fsg_type(f)
+struct filesys *f;
+{
+    char *t;
+
+    switch (f->type) {
+    case 'N':
+       t = "NFS";
+       break;
+    case 'R':
+       t = "RVD";
+       break;
+    case 'A':
+       t = "AFS";
+       break;
+    case 'E':
+       t = "ERR";
+       break;
+    case 'F':
+       t = "FSGROUP";
+       break;
+    case 'M':
+       t = "MUL";
+       break;
+    default:
+       t = "???";
+    }
+    printf("FSGroup %s has type %s instead of FSGROUP\n", f->name, t);
+    return(0);
+}
+
+fix_fsg_type(f)
+struct filesys *f;
+##{
+##  int rowcount, id = f->filsys_id;
+
+##  replace filesys (type = "FSGROUP") where filesys.filsys_id = id
+##  inquire_equel(rowcount = "rowcount")
+    if (rowcount > 0)
+      printf("%d entr%s fixed\n", rowcount, rowcount==1?"y":"ies");
+    else
+      printf("Not fixed\n");
+    modified("filesys");
+##}
+
+##show_fsg_nomember(id)
+##int id;
+##{
+##  int id1, found = 1;
+    struct filesys *f;
+
+##  retrieve (id1 = fsgroup.group_id) where fsgroup.filsys_id = id {
+      found = 0;
+      if (f = (struct filesys *) hash_lookup(filesys, id1))
+       printf("FSGroup %s has missing member %d\n", f->name, id);
+      else
+       printf("FSGroup %d has missing member %d\n", id1, id);
+##  }
+    return(found);
+##}
+
+##show_quota_nouser(id)
+##int id;
+##{
+##  int id1, found = 1;
+
+##  retrieve (id1 = quota.filsys_id) where quota.entity_id = id and
+##     quota.type = "USER" {
+      found = 0;
+      printf("Quota on fs %d for non-existant user %d\n", id1, id);
+##  }
+    return(found);
+##}
+
+##show_quota_nolist(id)
+##int id;
+##{
+##  int id1, found = 1;
+
+##  retrieve (id1 = quota.filsys_id) where quota.entity_id = id and
+##     quota.type = "GROUP" {
+      found = 0;
+      printf("Quota on fs %d for non-existant list %d\n", id1, id);
+##  }
+    return(found);
+##}
+
+##fix_quota_nouser(id)
+##int id;
+##{
+##  int rowcount, id1;
+
+    id1 = ((struct filesys *)hash_lookup(filesys, id))->phys_id;
+##  delete quota where quota.entity_id = id and quota.type = "USER"
+##  inquire_equel(rowcount = "rowcount")
+    if (rowcount > 0)
+      printf("%d entr%s deleted\n",rowcount, rowcount==1?"y":"ies");
+    else
+      printf("Not deleted\n");
+    modified("quota");
+##}
+
+##fix_quota_nolist(id)
+##int id;
+##{
+##  int rowcount, id1;
+
+    id1 = ((struct filesys *)hash_lookup(filesys, id))->phys_id;
+##  delete quota where quota.entity_id = id and quota.type = "GROUP"
+##  inquire_equel(rowcount = "rowcount")
+    if (rowcount > 0)
+      printf("%d entr%s deleted\n",rowcount, rowcount==1?"y":"ies");
+    else
+      printf("Not deleted\n");
+    modified("quota");
+##}
+
+##show_quota_nofs(id)
+##int id;
+##{
+##  int id1, found = 1;
+##  char type[9];
+
+##  retrieve (id1 = quota.entity_id, type = quota.#type)
+##     where quota.filsys_id = id {
+      found = 0;
+      printf("Quota for %s %d on non-existant filesys %d\n", type, id1, id);
+##  }
+    return(found);
+##}
+
+fix_quota_nofs(id)
+{
+    single_delete("quota", "filsys_id", id);
+}
+
+##show_quota_wrongpid(id)
+##int id;
+##{
+##  int id1, found = 1;
+##  char type[9];
+    struct user *u;
+    struct filesys *f;
+
+    f = (struct filesys *)hash_lookup(filesys, id);
+##  retrieve (id1 = quota.entity_id, type = quota.#type)
+##     where quota.filsys_id = id {
+      found = 0;
+      printf("Quota for %s %d on filesys %s has wrong phys_id %d\n",
+            type, id1, f->name, id);
+##  }
+    return(found);
+##}
+
+##fix_quota_physid(id)
+##int id;
+##{
+##  int rowcount, id1;
+
+    id1 = ((struct filesys *)hash_lookup(filesys, id))->phys_id;
+##  replace quota (phys_id = id1) where quota.filsys_id = id and
+##     quota.phys_id != id1    
+##  inquire_equel(rowcount = "rowcount")
+    if (rowcount > 0)
+      printf("%d entr%s fixed\n",rowcount, rowcount==1?"y":"ies");
+    else
+      printf("Not fixed\n");
+    modified("quota");
+##}
+
+##show_srv_user(id)
+##int id;
+##{
+##  char name[33];
+    int found = 1;
+
+##  retrieve (name = s.#name) where s.acl_type = "USER" and s.acl_id = id {
+       strtrim(name);
+       printf("Service %s has acl non-existant user %d\n", name, id);
+       found = 0;
+##  }
+    return(found);
+##}
+
+##show_srv_list(id)
+##int id;
+##{
+##  char name[33];
+    int found = 1;
+
+##  retrieve (name = s.#name) where s.acl_type = "LIST" and s.acl_id = id {
+       strtrim(name);
+       printf("Service %s has acl non-existant list %d\n", name, id);
+       found = 0;
+##  }
+    return(found);
+##}
+
+##zero_srv_user(id)
+##int id;
+##{
+##  int rowcount;
+
+##  replace servers (acl_id = 0) where servers.acl_id = id and
+##     servers.acl_type = "USER"
+##  inquire_equel(rowcount = "rowcount")
+    if (rowcount > 0)
+      printf("%d entr%s fixed\n", rowcount, rowcount==1?"y":"ies");
+    else
+      printf("Not fixed\n");
+    modified("servers");
+##}
+
+##zero_srv_list(id)
+##int id;
+##{
+##  int rowcount;
+
+##  replace servers (acl_id = 0) where servers.acl_id = id and
+##     servers.acl_type = "LIST"
+##  inquire_equel(rowcount = "rowcount")
+    if (rowcount > 0)
+      printf("%d entr%s fixed\n", rowcount, rowcount==1?"y":"ies");
+    else
+      printf("Not fixed\n");
+    modified("servers");
+##}
+
+
+##show_krb_usr(id)
+##int id;
+##{
+##  int found = 1, id1;
+    struct string *s;
+    char *ss;
+
+##  retrieve (id1 = krbmap.string_id) where krbmap.users_id = id {
+       if (s = ((struct string *)hash_lookup(strings, id1)))
+         ss = s->name;
+       else
+         ss = "[unknown]";
+       found = 0;
+       printf("Kerberos map for non-existant user %d to principal %s\n",
+              id, s);
+##  }
+    return(found);
+##}
+
+
+##show_krb_str(id)
+##int id;
+##{
+##  int found = 1, id1;
+    struct user *u;
+    char *s;
+
+##  retrieve (id1 = krbmap.users_id) where krbmap.string_id = id {
+       if (u = ((struct user *)hash_lookup(users, id1)))
+         s = u->login;
+       else
+         s = "[???]";
+       found = 0;
+       printf("Kerberos map for user %s (%d) to non-existant string %d\n",
+              s, id1, id);
+##  }
+    return(found);
+##}
+
+
+##show_pdm_mach(id)
+##int id;
+##{
+##  char name[33];
+    int found = 1;
+
+##  retrieve (name = palladium.#name) where palladium.mach_id = id {
+       strtrim(name);
+        printf("Palladium server/supervisor %s is on non-existant machine %d\n",
+              name, id);
+       found = 0;
+##  }
+    return(found);
+##}
+
+
+phase2()
+##{
+##  int id1, id2, id3, id4, id5;
+##  char type[9], name[33];
+    struct save_queue *sq, *sq1, *sq2, *sq3, *sq4, *sq5;
+    struct filesys *f;
+    struct list *l;
+    struct nfsphys *n;
+    struct machine *m;
+
+    printf("Phase 2 - Checking references\n");
+
+    dprintf("Checking users...\n");
+    hash_step(users, pobox_check, NULL);
+
+    dprintf("Checking mcmap...\n");
+    sq1 = sq_create();
+    sq2 = sq_create();
+##  retrieve (id1 = mcmap.mach_id, id2 = mcmap.clu_id) {
+       if (!(m = (struct machine *)hash_lookup(machines, id1)))
+         sq_save_unique_data(sq1, id1);
+       if (!hash_lookup(clusters, id2))
+         sq_save_unique_data(sq2, id2);
+       if (m) m->clucount++;
+##  }
+    generic_delete(sq1, show_mcm_mach, "mcmap", "mach_id", 1);
+    generic_delete(sq2, show_mcm_clu, "mcmap", "clu_id", 1);
+
+    dprintf("Checking service clusters...\n");
+    sq1 = sq_create();
+##  retrieve (id1 = svc.clu_id) {
+       if (!hash_lookup(clusters, id1))
+         sq_save_unique_data(sq1, id1);
+##  }
+    generic_delete(sq1, show_svc, "svc", "clu_id", 1);
+
+    dprintf("Checking lists...\n");
+    hash_step(lists, list_check, NULL);
+
+    dprintf("Checking members...\n");
+    sq1 = sq_create();
+    sq2 = sq_create();
+    sq3 = sq_create();
+    sq4 = sq_create();
+    sq5 = sq_create();
+##  range of m is imembers
+##  retrieve (id1 = m.list_id, type = m.member_type, id2 = m.member_id,
+##           id3 = m.ref_count, id4 = m.direct) {
+       if ((l = (struct list *) hash_lookup(lists, id1)) == NULL)
+         sq_save_unique_data(sq1, id1);
+       else if (type[0] == 'U' && !hash_lookup(users, id2))
+         sq_save_unique_data(sq2, id2);
+       else if (type[0] == 'L' && !hash_lookup(lists, id2))
+         sq_save_unique_data(sq3, id2);
+       else if (type[0] == 'S' && !string_check(id2))
+         sq_save_unique_data(sq4, id2);
+       else if (type[0] == 'K' && !string_check(id2))
+         sq_save_unique_data(sq5, id2);
+       else
+         l->members++;
+##  }
+    generic_delete(sq1, show_member_list, "imembers", "list_id", 1);
+    generic_fix(sq2, show_mem_user, "Delete", del_mem_user, 1);
+    generic_fix(sq3, show_mem_list, "Delete", del_mem_list, 1);
+    generic_fix(sq4, show_mem_str, "Delete", del_mem_str, 1);
+    generic_fix(sq5, show_mem_krb, "Delete", del_mem_krb, 1);
+
+    dprintf("Checking servers...\n");
+    sq1 = sq_create();
+    sq2 = sq_create();
+##  range of s is servers
+##  retrieve (name = s.#name, type = s.acl_type, id1 = s.acl_id) {
+       strtrim(type);
+       if (!strcmp(type, "USER") && !hash_lookup(users, id1)) {
+           sq_save_data(sq1, id1);
+       } else if (!strcmp(type, "LIST") && !hash_lookup(lists, id1)) {
+           sq_save_data(sq2, id1);
+       }
+##  }
+    generic_fix(sq1, show_srv_user, "Fix", zero_srv_user, 1);
+    generic_fix(sq2, show_srv_list, "Fix", zero_srv_list, 1);
+
+    dprintf("Checking servershosts...\n");
+    sq = sq_create();
+##  retrieve (id1 = serverhosts.mach_id) {
+       if (!hash_lookup(machines, id1))
+         sq_save_data(sq, id1);
+##  }
+    generic_fix(sq, show_sh, "Delete", del_sh_mach, 0);
+
+    dprintf("Checking nfsphys...\n");
+    hash_step(nfsphys, check_nfsphys, NULL);
+
+    dprintf("Checking filesys...\n");
+    hash_step(filesys, check_fs, NULL);
+
+    dprintf("Checking filesystem groups...\n");
+    sq1 = sq_create();
+    sq2 = sq_create();
+    sq3 = sq_create();
+##  retrieve (id1 = fsgroup.group_id, id2 = fsgroup.filsys_id) {
+       if (!(f = (struct filesys *) hash_lookup(filesys, id1)))
+         sq_save_data(sq1, id1);
+       if (!hash_lookup(filesys, id2))
+         sq_save_data(sq3, id2);
+##  }
+    generic_delete(sq1, show_fsg_missing, "fsgroup", "group_id", 0);
+    generic_delete(sq3, show_fsg_nomember, "fsgroup", "filsys_id", 1);
+
+    dprintf("Checking quotas...\n");
+    sq1 = sq_create();
+    sq2 = sq_create();
+    sq3 = sq_create();
+    sq4 = sq_create();
+##  retrieve (id1 = quota.entity_id, type = quota.#type, id2 = quota.filsys_id,
+##           id3 = quota.phys_id, id4 = quota.quota) {
+       if (type[0] == 'U' && id1 != 0 && !hash_lookup(users, id1))
+         sq_save_data(sq1, id1);
+       else if (type[0] == 'G' && !hash_lookup(lists, id1))
+         sq_save_data(sq4, id1);
+       else if (!(f = (struct filesys *) hash_lookup(filesys, id2)))
+         sq_save_data(sq2, id2);
+       else if (id3 != f->phys_id ||
+           ((n = (struct nfsphys*) hash_lookup(nfsphys, id3)) ==
+           (struct nfsphys *)NULL))
+         sq_save_data(sq3, id2);
+       else
+         n->count += id4;
+##  }
+    generic_fix(sq1, show_quota_nouser, "Delete", fix_quota_nouser, 1);
+    generic_fix(sq2, show_quota_nofs, "Delete", fix_quota_nofs, 0);
+    generic_fix(sq3, show_quota_wrongpid, "Fix", fix_quota_physid, 1);
+    generic_fix(sq4, show_quota_nolist, "Delete", fix_quota_nolist, 1);
+
+    dprintf("Not checking zephyr.\n");
+
+    dprintf("Checking hostaccess...\n");
+##  range of h is hostaccess
+##  retrieve (id1 = h.mach_id, type = h.acl_type, id2 = h.acl_id) {
+       strtrim(type);
+       if (!hash_lookup(machines, id1)) {
+           printf("Hostaccess for non-existant host %d\n", id1);
+           printf("Not fixing this error\n");
+       }
+       if (!strcmp(type, "USER") && !hash_lookup(users, id2)) {
+           printf("Hostaccess for %d is non-existant user %d\n", id1, id2);
+           printf("Not fixing this error\n");
+       } else if (!strcmp(type, "LIST") && !hash_lookup(lists, id2)) {
+           printf("Hostaccess for %d is non-existant list %d\n", id1, id2);
+           printf("Not fixing this error\n");
+       }
+##  }
+
+    dprintf("Checking palladium...\n");
+    sq1 = sq_create();
+##  range of p is palladium
+##  retrieve (id1 = p.mach_id) {
+       if (!hash_lookup(machines, id1)) {
+           sq_save_unique_data(sq1, id1);
+       }
+##  }
+    generic_delete(sq1, show_pdm_mach, "palladium", "mach_id", 1);
+
+    dprintf("Checking krbmap...\n");
+    sq1 = sq_create();
+    sq2 = sq_create();
+##  range of k is krbmap
+##  retrieve (id1 = k.users_id, id2 = k.string_id) {
+       if (!hash_lookup(users, id1))
+         sq_save_unique_data(sq1, id1);
+       if (!string_check(id2))
+         sq_save_unique_data(sq2, id2);
+##  }
+    generic_delete(sq1, show_krb_usr, "krbmap", "users_id", 1);
+    generic_delete(sq2, show_krb_str, "krbmap", "string_id", 1);
+
+    dprintf("Checking capacls...\n");
+##  retrieve (id1 = capacls.list_id, name = capacls.tag) {
+       if (!hash_lookup(lists, id1)) {
+           printf("Capacl for %s is non-existant list %d\n", name, id1);
+           printf("Not fixing this error\n");
+       }
+##  }
+
+##}
+
diff --git a/dbck/phase3.dc b/dbck/phase3.dc
new file mode 100644 (file)
index 0000000..0a85f74
--- /dev/null
@@ -0,0 +1,80 @@
+/* $Header$
+ *
+ *  (c) Copyright 1988 by the Massachusetts Institute of Technology.
+ *  For copying and distribution information, please see the file
+ *  <mit-copyright.h>.
+ */
+
+#include <mit-copyright.h>
+#include "dbck.h"
+
+#define NULL 0
+
+static char phase3_qc_rcsid[] = "$Header$";
+
+
+empty_list_check(id, l, hint)
+int id, hint;
+struct list *l;
+{
+    if (l->members == 0 && l->list_id != 0)
+      printf("Warning: List %s is empty\n", l->name);
+}
+
+
+/* Used by other parts of the program to check that a string_id is good.
+ * This returns TRUE if it is, or FALSE if it is not, and as a side effect
+ * increments the string reference count.
+ */
+
+struct string *string_check(id)
+int id;
+{
+    register struct string *s;
+
+    s = (struct string *) hash_lookup(strings, id);
+    if (s == NULL)
+      return(s);
+    s->refc++;
+    return(s);
+}
+
+
+unref_string_check(id, s, hint)
+int id, hint;
+struct string *s;
+{
+    if (s->refc == 0) {
+       printf("Unreferenced string %s id %d\n", s->name, id);
+       if (single_fix("Delete", 1))
+         single_delete("strings", "string_id", id);
+    }
+}
+
+
+noclu_mach_check(id, m, hint)
+int id, hint;
+struct machine *m;
+{
+    if (m->clucount == 0 && m->mach_id != 0)
+      printf("Warning: machine %s is not in any clusters\n", m->name);
+}
+
+
+phase3()
+##{
+    printf("Phase 3 - Finding unused objects\n");
+
+    if (warn) {
+       dprintf("Checking machines...\n");
+       hash_step(machines, noclu_mach_check, NULL);
+
+       dprintf("Checking lists...\n");
+       hash_step(lists, empty_list_check, NULL);
+    }
+
+    dprintf("Checking strings...\n");
+    hash_step(strings, unref_string_check, NULL);
+
+##}
+
diff --git a/dbck/phase4.dc b/dbck/phase4.dc
new file mode 100644 (file)
index 0000000..535a22a
--- /dev/null
@@ -0,0 +1,179 @@
+/* $Header$
+ *
+ *  (c) Copyright 1988 by the Massachusetts Institute of Technology.
+ *  For copying and distribution information, please see the file
+ *  <mit-copyright.h>.
+ */
+
+#include <mit-copyright.h>
+#include <moira.h>
+#include "dbck.h"
+
+static char phase4_qc_rcsid[] = "$Header$";
+
+
+count_boxes(id, u, boxes)
+int id;
+struct user *u;
+struct hash *boxes;
+{
+    int i;
+
+    if (u->potype == 'P') {
+       if (i = (int) hash_lookup(boxes, u->pobox_id))
+         hash_store(boxes, u->pobox_id, i+1);
+       else {
+         printf("User %s(%s) has pobox on non-POP server %d\n",
+                u->fullname, u->login, u->pobox_id);
+         printf("Not fixing this error\n");
+        }
+    }
+}
+
+
+##check_box_counts(id, cnt, counts)
+##int id, cnt;
+struct hash *counts;
+##{
+##  int oldval, rowcount;
+
+    oldval = (int) hash_lookup(counts, id);
+    cnt--;
+    if (oldval != cnt) {
+       printf("Count wrong on POBox machine %s; is %d in db, counted %d\n",
+              ((struct machine *) hash_lookup(machines, id))->name,
+              oldval, cnt);
+       if (single_fix("Update", 1)) {
+##         range of s is serverhosts
+##         replace s (value1 = cnt) where
+##             s.service = "POP" and s.mach_id = id
+##         inquire_equel(rowcount = "rowcount")
+           if (rowcount > 0)
+             printf("%d entr%s fixed\n", rowcount, rowcount==1?"y":"ies");
+           else
+             printf("Not fixed\n");
+           modified("serverhosts");
+       }
+    }
+##}
+
+
+##check_nfs_counts(id, n, hint)
+##int id, hint;
+struct nfsphys *n;
+##{
+##  int val, rowcount;
+
+    val = n->count;
+    if (n->allocated != val) {
+       printf("Count wrong on NFSphys %s:%s; is %d in db, counted %d\n",
+              ((struct machine *) hash_lookup(machines, n->mach_id))->name,
+              n->dir, n->allocated, val);
+       if (single_fix("Update", 1)) {
+##         replace nfsphys (allocated = val) where nfsphys.nfsphys_id = id
+##         inquire_equel(rowcount = "rowcount")
+           if (rowcount > 0)
+             printf("%d entr%s fixed\n", rowcount, rowcount==1?"y":"ies");
+           else
+             printf("Not fixed\n");
+           modified("nfsphys");
+       }
+    }
+##}
+
+
+phase4()
+##{
+    struct hash *boxes, *counts;
+##  int id, cnt;
+
+    printf("Phase 4 - Checking counts\n");
+
+    dprintf("Doing POBoxes...\n");
+    boxes = create_hash(10);
+    counts = create_hash(10);
+##  retrieve (id = serverhosts.mach_id, cnt = serverhosts.value1)
+##     where serverhosts.service = "POP" {
+      hash_store(boxes, id, 1);
+      hash_store(counts, id, cnt);
+##  }
+    hash_step(users, count_boxes, boxes);
+    hash_step(boxes, check_box_counts, counts);
+
+    dprintf("Doing NFSphys...\n");
+    hash_step(nfsphys, check_nfs_counts, 0);
+##}
+
+
+count_only_setup()
+##{
+##  int id, status, id2, id3;
+##  char name[33], last[17], first[17], buf[257];
+    struct save_queue *sq;
+    struct user *u;
+    struct nfsphys *n;
+    struct machine *m;
+
+    dprintf("Loading users...\n");
+    users = create_hash(10000);
+##  range of u is users
+##  retrieve (id = u.users_id, name = u.login, last = u.#last,
+##           first = u.#first, status = u.#status, buf = u.potype,
+##           id2 = u.pop_id, id3 = u.box_id) 
+##    where u.potype = "POP" {
+       u = (struct user *) malloc(sizeof(struct user));
+       if (u == NULL)
+         out_of_mem("storing users");
+       strcpy(u->login, strtrim(name));
+       u->potype = buf[0];
+       sprintf(buf, "%s, %s", strtrim(last), strtrim(first));
+       u->fullname = strsave(buf);
+       u->status = status;
+       u->users_id = id;
+       switch (u->potype) {
+       case 'P':
+           u->pobox_id = id2;
+           break;
+       case 'S':
+           u->pobox_id = id3;
+           break;
+       default:
+           u->pobox_id = 0;
+       }
+       hash_store(users, id, u);
+##  }
+
+    dprintf("Loading machines...\n");
+    machines = create_hash(1000);
+##  range of m is machine
+##  retrieve (id = m.mach_id, name = m.#name) {
+       m = (struct machine *) malloc(sizeof(struct machine));
+       if (m == NULL)
+         out_of_mem("storing machines");
+       strcpy(m->name, strtrim(name));
+       m->mach_id = id;
+       hash_store(machines, id, m);
+##  }
+
+    dprintf("Loading nfsphys...\n");
+    nfsphys = create_hash(500);
+##  retrieve (id = nfsphys.nfsphys_id, name = nfsphys.dir,
+##           id2 = nfsphys.mach_id, id3 = nfsphys.allocated) {
+       n = (struct nfsphys *) malloc(sizeof(struct nfsphys));
+       if (n == NULL)
+         out_of_mem("storing nfsphys");
+       strcpy(n->dir, strtrim(name));
+       n->mach_id = id2;
+       n->nfsphys_id = id;
+       n->allocated = id3;
+       n->count = 0;
+       hash_store(nfsphys, id, n);
+##  }
+
+    dprintf("Counting quotas...\n");
+##  retrieve (id = quota.phys_id, id2 = quota.quota) {
+        if (n = (struct nfsphys  *) hash_lookup(nfsphys, id)) {
+           n->count += id2;
+       }
+##  }
+##}
This page took 0.167995 seconds and 5 git commands to generate.