/* $Header: /afs/sipb.mit.edu/project/sipb-athena/repository/src/moira/dbck/dbck.dc,v 1.5 1996/06/02 07:42:32 ghudson Exp $
 *
 * 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: /afs/sipb.mit.edu/project/sipb-athena/repository/src/moira/dbck/dbck.dc,v 1.5 1996/06/02 07:42:32 ghudson Exp $";


int debug = 0;
int mode = MODE_ASK;
int fast = 0;
int warn = 1;
int abort_p = 0;
struct hash *users, *machines, *clusters, *lists, *filesys, *nfsphys;
struct hash *strings, *members, *subnets;
EXEC SQL BEGIN DECLARE SECTION; 
int dcmenable;
EXEC SQL END DECLARE SECTION; 
struct save_queue *modtables, *sq_create();
int interrupt();


main(argc, argv)
int argc;
char **argv;
{
    char **arg = argv;
EXEC SQL BEGIN DECLARE SECTION; 
    char *database;
EXEC SQL END DECLARE SECTION; 
    int ingerr();
    int countonly = 0;

    database = "moira";

    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);
    EXEC SQL CONNECT :database;
    printf("done\n");
    EXEC SQL SELECT value INTO :dcmenable FROM numvalues 
	WHERE name='dcm_enable'; 
    dprintf("DCM disabled (was %d)\n", dcmenable);
    EXEC SQL UPDATE numvalues SET value=0 WHERE name='dcm_enable';

    /* Begin transaction here. */

    if (!countonly) {
	phase1();
	EXEC SQL COMMIT WORK;
	phase2();
	EXEC SQL COMMIT WORK;
	phase3();
	EXEC SQL COMMIT WORK;
    } else {
	count_only_setup();
	EXEC SQL COMMIT WORK;
    }
    phase4();

    EXEC SQL COMMIT WORK;

    cleanup();
    printf("Done.\n");
    exit(0);
}

ingerr(num)
int	*num;
{
    if (*num == 100) return;
    printf("An ingres error occuurred, code %d\n", *num);
    printf("Aborting...\n");
    if (!abort_p) {
	abort_p++;
	EXEC SQL ROLLBACK WORK;
    }
    exit(1);
}


int interrupt()
{
    printf("Signal caught\n");
    if (prompt("Save database changes")) {
	/* break out of a retrieve loop */
	IIbreak();

	EXEC SQL COMMIT WORK;
	cleanup();
	exit(0);
    }
    printf("Aborting transaction\n");
    if (!abort_p) {
	abort_p++;
	/* break out of a retrieve loop */
	IIbreak();
	EXEC SQL ROLLBACK WORK;
    }

    EXEC SQL UPDATE numvalues SET value=:dcmenable
	WHERE name='dcm_enable';

    exit(0);
}


modified(table)
char *table;
{
    sq_save_unique_string(modtables, table);
}

cleanup()
{
    EXEC SQL BEGIN DECLARE SECTION; 
    char *tab;
    EXEC SQL END DECLARE SECTION; 

    while (sq_get_data(modtables, &tab)) {
	EXEC SQL REPEATED UPDATE tblstats SET modtime='now'
	    WHERE table_name = :tab;
    }
    EXEC SQL UPDATE numvalues SET value = :dcmenable
	WHERE name='dcm_enable';
}


out_of_mem(msg)
char *msg;
{
    fprintf(stderr, "Out of memory while %s\n", msg);
    if (prompt("Save database changes")) {
	/* break out of a retrieve loop */
	IIbreak();

	EXEC SQL COMMIT WORK;
	cleanup();
	exit(1);
    }
    printf("Aborting transaction\n");
    IIbreak();
    EXEC SQL ROLLBACK WORK;
    exit(1);
}
