Skip to content
Snippets Groups Projects
dbck.c 28.6 KiB
Newer Older
Per Cederqvist's avatar
Per Cederqvist committed
	{
	    adjust_text_list(tlist);
	    mark_conference_as_changed(cc);
	    modifications++;
	    log("Repaired: text_list adjusted.\n");
	}
	else
	    error++;
    }
    
    return error;
}

static Membership *
Per Cederqvist's avatar
Per Cederqvist committed
locate_membership(Conf_no     conf_no,
		  Person    * pers_p)
{
    Membership * confp;
    int    i;

    for(confp = pers_p->conferences.confs, i = pers_p->conferences.no_of_confs;
	i > 0; i--, confp++)
    {
	if ( confp->conf_no == conf_no )
	{
	    return confp;
	}
    }

    return NULL;
}

static int
check_member(Conf_no cc,
	     Member *memb)
{
    Person *pp;
    int error=0;

    pp = cached_get_person_stat(memb->member);
    if ( pp == NULL )
    {
Per Cederqvist's avatar
Per Cederqvist committed
	log("Person %lu, supposedly a member in conf %lu, is nonexistent.\n",
	    (unsigned long)memb->member, (unsigned long)cc);
Per Cederqvist's avatar
Per Cederqvist committed
	error++;
    }
    else
    {
	if ( locate_membership(cc, pp) == NULL )
	{
	    log("Person %lu is not a member in conf %lu.\n",
		(unsigned long)memb->member,
		(unsigned long)cc);
Per Cederqvist's avatar
Per Cederqvist committed
	    error++;
	}
    }

    return error;
}

static int
check_member_list(Conf_no cc,
		  const Member_list *mlist)
{
    int errors=0;
    int i;
    
    for (i = 0; i < mlist->no_of_members; i++)
	errors += check_member(cc, &mlist->members[i]);

    return errors;
}


static int
check_confs(void)
{
    Conf_no     cc = 0;
    Person     *pstat=NULL;
    Conference *cstat=NULL;
    long	errors = 0;
    Conf_no	number_of_confs = 0;

    while ( (cc = traverse_conference(cc)) != 0 )
    {
	number_of_confs++;
	cstat = cached_get_conf_stat (cc);
	
	if ( cstat == NULL )
	{
	    log("Conference %lu nonexistent.\n", (unsigned long)cc);
Per Cederqvist's avatar
Per Cederqvist committed
	    errors++;
	}
	else
	{
	    if (cstat->type.letter_box)
	    {
		pstat = cached_get_person_stat(cc);
		if (pstat == NULL)
		{
		    log("Mailbox %lu has no person.\n", (unsigned long)cc);
Per Cederqvist's avatar
Per Cederqvist committed
		    errors++;
		}
	    }
	    else		/* not letter_box */
	    {
		/* Remember that the creator might no longer exist. */
		if ( person_scratchpad[ cstat->creator ] != NULL )
		    ++person_scratchpad[ cstat->creator ]->created_confs;
	    }

	    errors += (check_texts_in_conf(cc, &cstat->texts)
		       + check_member_list(cc, &cstat->members));
	}
    }

    if ( vflag )
	log("Total of %lu conferences.\n", (unsigned long)number_of_confs);
Per Cederqvist's avatar
Per Cederqvist committed

    return errors;
}

static void
init_person_scratch(void)
{
    Pers_no pno = 0;
    
    while( (pno = traverse_person(pno)) != 0 )
    {
	person_scratchpad[pno] = alloc_person_scratchpad();
    }
}

static long
post_check_persons(void)
{
    long errors = 0;
    
    Pers_no pers_no = 0;
    Person *pstat;

    while ( (pers_no = traverse_person(pers_no)) != 0 )
    {
	if ( (pstat = cached_get_person_stat(pers_no)) == NULL )
	{
Per Cederqvist's avatar
Per Cederqvist committed
	    log("%s(): can't cached_get_person_stat(%d).\n", 
		"INTERNAL DBCK ERROR: post_check_persons", pers_no);
Per Cederqvist's avatar
Per Cederqvist committed
	}
    }

    return errors;
}

		
/*
 * Returns 0 if the database seems to be correct.
 */
static long
check_data_base(void)
{
    long errors;

    init_person_scratch();
    errors = check_texts() + check_persons() + check_confs();
    return errors + post_check_persons();
}

static void
init_data_base(char *dbase_dir)
Per Cederqvist's avatar
Per Cederqvist committed
{
    sprintf(datafilename,   "%s/%s", dbase_dir, param.datafile_name);
    sprintf(backupfilename, "%s/%s", dbase_dir, param.backupfile_name);
    sprintf(textfilename, "%s/%s", dbase_dir, param.textfile_name);
    sprintf(textbackupfilename, "%s/%s", dbase_dir, param.textbackupfile_name);
Per Cederqvist's avatar
Per Cederqvist committed

    if ( vflag )
    {
	log("Database = %s\n", datafilename);
	log("Backup   = %s\n", backupfilename);
	log("Text     = %s\n", textfilename);
	log("Textback = %s\n", textbackupfilename);
    }
    
    if ( init_cache() == FAILURE )
	restart_kom("Can't find database.\n");
}

static void
Per Cederqvist's avatar
Per Cederqvist committed
garb_text_file(void)
{
    Text_no tno = 0;
    String text;

    log("Renaming %s to %s\n", textfilename, textbackupfilename);
Per Cederqvist's avatar
Per Cederqvist committed
    rename(textfilename, textbackupfilename);
    log("Writing texts to (new) %s\n", textfilename);
Per Cederqvist's avatar
Per Cederqvist committed
    fflush(stdout);
    fflush(stderr);
    cache_open_new_text_file();

    while ( (tno = traverse_text(tno)) != 0 )
    {
	text = cached_get_text(tno);
	cached_flush_text(tno, text);
	free_tmp();
    }
    log("Writing datafile with new indexes.\n");
    fflush(stdout);
    fflush(stderr);
    cache_sync();
    log("Ready.");    
}

	
	
static void
print_statistics(void)
{
    Text_stat *ts;
    Text_no    t;
    int  *hist;
    int i;

    hist = calloc(param.text_len, sizeof(int));
    if (hist == NULL)
    {
	perror("dbck: print_statistics(): can't calloc()");
	return;
    }
    
    for (t=0; (t=traverse_text(t)) != 0;)
    {
	ts = cached_get_text_stat(t);
	if (ts == NULL)
	{
	    log("print_statistics(): Can't get text_stat.\n");
	    return;
	}
		
	hist[ts->no_of_chars]++;
    }

    log("Length  Frequency\n");
    for(i=0; i<param.text_len; i++)
	if(hist[i] != 0)
	    log("%8d %d\n", i, hist[i]);
}
Per Cederqvist's avatar
Per Cederqvist committed

/* Stop "no previous prototype" warning from gcc 2.0 */
int main(int, char**);
Per Cederqvist's avatar
Per Cederqvist committed

int
main (int    argc,
      char **argv)
{
    int i;
    int errors;
    char *default_config_file;
    char *config_file;
Per Cederqvist's avatar
Per Cederqvist committed
    BUGDECL;

    for (i = 1; i < argc && argv[i][0] == '-'; i++)
    {
	switch (argv[i][1])
	{
#ifndef NDEBUG
Per Cederqvist's avatar
Per Cederqvist committed
	case 'd':
	    buglevel++;
	    break;
#endif

	case 'i':		/* Running interactively. */
	    iflag++;		/* Will ask user and try to repair. */
	    break;

	case 'r':		/* Repair simple errors wihtout asking. */
	    rflag++;
	    break;

	case 'v':		/* Verbose: report more than errors. */
	    vflag++;
	    break;

	case 'g':		/* Garbage collect: compress text-file. */
	    gflag++;
	    break;

	case 's':		/* Statistics: text length et c. */
	    sflag++;
	    break;

	case 'c':		/* Consider an unset change_name an error. */
	    unset_change_name_is_error = 1;
	    break;

Per Cederqvist's avatar
Per Cederqvist committed
	default:
	    restart_kom("usage: %s %s [config_file]\n",
			argv[0], "[-d ...] [-i] [-r] [-v] [-g] [-s] [-c]");
    /* Read in the configuration file. */

    default_config_file = smalloc(strlen(DEFAULT_DBASE_DIR) +
				  strlen(CONFIG_FILE) + 2);
    sprintf(default_config_file, "%s/%s", DEFAULT_DBASE_DIR, CONFIG_FILE);
    if (i < argc)
	config_file = argv[i++];
    else
	config_file = default_config_file;

    read_configuration(config_file);
    sfree(default_config_file);

    if (i != argc)
	restart_kom("usage: %s %s [config_file]\n",
		    argv[0], "[-d ...] [-i] [-r] [-v] [-g] [-s] [-c]");
Per Cederqvist's avatar
Per Cederqvist committed
    s_set_storage_management(smalloc, srealloc, sfree);

    init_data_base(param.dbase_dir);
Per Cederqvist's avatar
Per Cederqvist committed
    errors = check_data_base();

    if (truncated_texts == TRUE)
	modifications++;

Per Cederqvist's avatar
Per Cederqvist committed
    if ( iflag )
	log("Total of %d error%s remains.\n", errors, errors == 1 ? "" : "s");
    else if ( vflag && errors > 0 )
	log("%d error%s found.\n", errors, errors == 1 ? "" : "s");

    if ( modifications > 0 )
    {
	log("%d modification%s made. Syncing...\n",
	    modifications, modifications == 1 ? "" : "s");
	fflush(stdout);
	fflush(stderr);
	cache_sync();
	log("ready.\n");
    }

Per Cederqvist's avatar
Per Cederqvist committed
    if ( gflag )
Per Cederqvist's avatar
Per Cederqvist committed
    {
Per Cederqvist's avatar
Per Cederqvist committed
	if ( modifications == 0 && errors == 0 )
	{
	    log("No errors found. Compressing textfile.\n");
	    fflush(stdout);
	    fflush(stderr);
	    garb_text_file();
	    log("ready.\n");
	}
	else
	    log("Compression not done since errors was found.\n");
Per Cederqvist's avatar
Per Cederqvist committed
    }
    
    return errors != 0;
}