dbck-cache.c 32.6 KB
Newer Older
Linus Tolke Y's avatar
Linus Tolke Y committed
1
/*
2 3
 * $Id: dbck-cache.c,v 0.56 2003/08/23 16:38:17 ceder Exp $
 * Copyright (C) 1991-1999, 2001-2003  Lysator Academic Computer Association.
Linus Tolke Y's avatar
Linus Tolke Y committed
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
 *
 * This file is part of the LysKOM server.
 * 
 * LysKOM is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by 
 * the Free Software Foundation; either version 1, or (at your option) 
 * any later version.
 * 
 * LysKOM is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with LysKOM; see the file COPYING.  If not, write to
 * Lysator, c/o ISY, Linkoping University, S-581 83 Linkoping, SWEDEN,
 * or the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, 
 * MA 02139, USA.
 *
Per Cederqvist's avatar
Per Cederqvist committed
23
 * Please report bugs at http://bugzilla.lysator.liu.se/. 
Linus Tolke Y's avatar
Linus Tolke Y committed
24
 */
Per Cederqvist's avatar
Per Cederqvist committed
25 26 27 28 29 30 31 32 33 34
/*
 * This module contains some very simple simulations of the routines in
 * cache.c.
 *
 * Extracted from ram-cache.c and rewritten by ceder.
 *
 * New database format with texts in their own file by Inge Wallin.
 *   Also save time as a time_t instead of a struct tm.
 */

David Byers's avatar
David Byers committed
35 36 37 38 39

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

Per Cederqvist's avatar
Per Cederqvist committed
40
#include <stdio.h>
Per Cederqvist's avatar
Per Cederqvist committed
41
#ifndef SEEK_END
Per Cederqvist's avatar
Per Cederqvist committed
42
#  include <fcntl.h>
Per Cederqvist's avatar
Per Cederqvist committed
43 44
#endif
#ifndef SEEK_END
Per Cederqvist's avatar
Per Cederqvist committed
45 46 47 48 49
#  include <unistd.h>
#endif
#ifndef SEEK_END
#  define SEEK_SET 0
#  define SEEK_END 2
Per Cederqvist's avatar
Per Cederqvist committed
50
#endif
Per Cederqvist's avatar
Per Cederqvist committed
51 52 53
#ifdef HAVE_STDLIB_H
#  include <stdlib.h>
#endif
54
#include "timewrap.h"
Per Cederqvist's avatar
Per Cederqvist committed
55
#include <sys/types.h>
Per Cederqvist's avatar
Per Cederqvist committed
56 57 58
#ifdef TIME_SYNC
#  include <sys/resource.h>
#endif
59 60
#include <string.h>
#include <errno.h>
Per Cederqvist's avatar
Per Cederqvist committed
61

62
#include "ldifftime.h"
Per Cederqvist's avatar
Per Cederqvist committed
63 64
#include "exp.h"
#include "misc-types.h"
65
#include "s-string.h"
Per Cederqvist's avatar
Per Cederqvist committed
66 67
#include "kom-types.h"
#include "kom-errno.h"
Per Cederqvist's avatar
Per Cederqvist committed
68
#include "cache.h"
Per Cederqvist's avatar
Per Cederqvist committed
69 70 71
#include "debug.h"
#include "server/smalloc.h"
#include "log.h"
Per Cederqvist's avatar
Per Cederqvist committed
72
#include "lyskomd.h"
Per Cederqvist's avatar
Per Cederqvist committed
73
#include "kom-memory.h"
74
#include "ram-io.h"
Per Cederqvist's avatar
Per Cederqvist committed
75 76
#include "ram-parse.h"
#include "ram-output.h"
77
#include "conf-file.h"
Per Cederqvist's avatar
Per Cederqvist committed
78
#include "param.h"
Per Cederqvist's avatar
Per Cederqvist committed
79
#include "dbck-cache.h"
80
#include "local-to-global.h"
81
#include "unused.h"
82
#include "eintr.h"
Per Cederqvist's avatar
Per Cederqvist committed
83

Per Cederqvist's avatar
Per Cederqvist committed
84 85 86 87
/*
 * All functions that can fail sets kom_errno to a suitable value
 * if they fail.
 */
Per Cederqvist's avatar
Per Cederqvist committed
88

David Byers's avatar
David Byers committed
89 90 91
Person		** pers_arr;
Conference 	** conf_arr;
String		 * name_list; /* "cache" list */
Per Cederqvist's avatar
Per Cederqvist committed
92
			        	  /* Global var auto init to NULL */
93
static Conf_no     next_free_num = 1;
Per Cederqvist's avatar
Per Cederqvist committed
94

David Byers's avatar
David Byers committed
95
Text_stat 	** text_arr;
Per Cederqvist's avatar
Per Cederqvist committed
96
static Text_no next_text_num = 1;
Per Cederqvist's avatar
Per Cederqvist committed
97

98 99 100
/* Defined in standalone.c */

extern Info kom_info;
David Byers's avatar
David Byers committed
101 102


Per Cederqvist's avatar
Per Cederqvist committed
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
/* Defined in ramkomd.c */

static FILE          *text_file = NULL;
static FILE	     *new_text_file = NULL; /* Used when garbage collecting. */

BUGDECL;


/* Macros */

#define TRACE2(format, arg) if ( buglevel > 2 ) printf(format, arg)
#define TRACE1(format) if ( buglevel > 2 ) printf(format)
#define TRACESTR(str)  if ( buglevel > 2 ) s_puts(str)
#define INRANGE(str, num, retval) if ( num == 0 || num >= next_free_num ) \
{			\
    return retval;	\
    printf("%s: conf_no %d out of range 1 ... %d ", str, num, next_free_num); \
    fflush(stdout);	\
    fflush(stderr);	\
    abort();		\
}

#define TEXT_RANGE(str, num, retval) if ( num == 0 || num >= next_text_num ) \
{	\
    return retval;\
Per Cederqvist's avatar
Per Cederqvist committed
128
    printf("Text_no out of range 1 ... %ld ", next_text_num); \
Per Cederqvist's avatar
Per Cederqvist committed
129 130 131 132 133 134
    printf(str);	\
    fflush(stdout);	\
    fflush(stderr);	\
    abort(); 		\
}

Per Cederqvist's avatar
Per Cederqvist committed
135 136 137
#define VOID_TEXT_RANGE(str, num) if ( num == 0 || num >= next_text_num ) \
{	\
    return;\
Per Cederqvist's avatar
Per Cederqvist committed
138
    printf("Text_no out of range 1 ... %ld ", next_text_num); \
Per Cederqvist's avatar
Per Cederqvist committed
139 140 141 142 143 144
    printf(str);	\
    fflush(stdout);	\
    fflush(stderr);	\
    abort(); 		\
}

Per Cederqvist's avatar
Per Cederqvist committed
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175

extern Conf_type
cached_get_conf_type (Conf_no conf_no)
{
    return conf_arr [ conf_no ]->type;
}



/*
 * Various function calls to tell the cache that something is changed.
 */

void
mark_person_as_changed(Pers_no	pers_no)
{
    TRACE2("Person %d is changed\n", pers_no);
    return;    
}


void
mark_conference_as_changed(Conf_no	conf_no)
{
    TRACE2("Conf.  %d is changed\n", conf_no);
    return;
}

void
mark_text_as_changed( Text_no text_no )
{
176
    TRACE2("Text %lu is changed.\n", text_no);
Per Cederqvist's avatar
Per Cederqvist committed
177
    VOID_TEXT_RANGE("mark_text_as_changed\n", text_no);
Per Cederqvist's avatar
Per Cederqvist committed
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
}    


/*
 * Person-related calls
 */


extern Success
cached_create_person( Pers_no person )
{
    TRACE2("Person %d is being created.\n", person);
    INRANGE("cached_create_person\n", person, FAILURE);

    if ( pers_arr[ person ] != NULL )
    {
	TRACE1("pers_arr not NULL");
	fflush(stdout);
	fflush(stderr);
	abort();
    }
    
    pers_arr[ person ] = alloc_person();
    return OK;
}


extern Person *
cached_get_person_stat( Pers_no	person )
{
    INRANGE("cached_get_person_stat\n", person, NULL);
    TRACE2("cached_get_person_stat %d\n", person);
210
    err_stat = person;
Per Cederqvist's avatar
Per Cederqvist committed
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
    kom_errno = KOM_UNDEF_PERS;
    
    return pers_arr[ person ];
}



/*
 * Conference-related calls
 */
extern Conf_no	/* Also cache the name */
cached_create_conf (String  name)
{
    Conference * conf_c;
    Conf_no	 conf_no;

    TRACE1("cached_create_conf( ");
    TRACESTR(name);
    TRACE1(" )\n");

David Byers's avatar
David Byers committed
231
    if ( next_free_num >= param.max_conf )
Per Cederqvist's avatar
Per Cederqvist committed
232
    {
233
        err_stat = next_free_num;
Per Cederqvist's avatar
Per Cederqvist committed
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
	kom_errno = KOM_INDEX_OUT_OF_RANGE;
	return 0;
    }
    
    conf_no = next_free_num++;
    conf_c  = alloc_conference();

    conf_c->name = EMPTY_STRING;
    s_strcpy(&conf_c->name, name);

    TRACE2(" number %d\n", conf_no);

    conf_arr[ conf_no ] = conf_c;
    pers_arr[ conf_no ] = NULL;
    
    return conf_no;
}

extern Success
cached_delete_conf( Conf_no	conf )
{
    INRANGE("cached_delete_conf()", conf, FAILURE);
    if ( conf_arr[ conf ] == NULL )
    {
258
        err_stat = conf;
Per Cederqvist's avatar
Per Cederqvist committed
259 260 261 262 263 264 265 266 267 268 269 270 271 272
	kom_errno = KOM_UNDEF_CONF;
	return FAILURE;
    }
    free_conference(conf_arr[ conf ]);
    conf_arr[ conf ] = NULL;
    return OK;
}

Success
cached_delete_person(Pers_no pers)
{
    INRANGE("cached_delete_person()", pers, FAILURE);
    if ( pers_arr[ pers ] == NULL )
    {
273
        err_stat = pers;
Per Cederqvist's avatar
Per Cederqvist committed
274 275 276 277 278 279 280 281 282 283 284 285 286 287
	kom_errno = KOM_UNDEF_PERS;
	return FAILURE;
    }

    pers_arr[ pers ] = NULL;
    return OK;
}

Success
cached_delete_text(Text_no text)
{
    TEXT_RANGE("cached_delete_text()", text, FAILURE);
    if ( text_arr[ text ] == NULL )
    {
288
        err_stat = text;
Per Cederqvist's avatar
Per Cederqvist committed
289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304
	kom_errno = KOM_NO_SUCH_TEXT;
	return FAILURE;
    }
    free_text_stat(text_arr[ text ]);
    text_arr[ text ] = NULL;
    return OK;
    
}


extern Conference *
cached_get_conf_stat(	Conf_no		conf_no )
{
    INRANGE("cached_get_conf_stat\n", conf_no, NULL);
    TRACE2("cached_get_conf_stat %d\n", conf_no);
    kom_errno = KOM_UNDEF_CONF;
305
    err_stat = conf_no;
Per Cederqvist's avatar
Per Cederqvist committed
306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327
    
    return conf_arr[ conf_no ];
}

/*
 * Return TRUE if conf_no exists.
 */
Bool
cached_conf_exists(Conf_no conf_no)
{
    return conf_arr[ conf_no ] != NULL ? TRUE : FALSE;
}

    
/*
 * Calls to handle texts
 */

extern String
cached_get_text( Text_no text )
{
    String  the_string;
328
    Text_stat *t_stat;
Per Cederqvist's avatar
Per Cederqvist committed
329

330
    TRACE2("cached_get_text %lu\n", text);
Per Cederqvist's avatar
Per Cederqvist committed
331

332
    if ( (t_stat = cached_get_text_stat (text)) == NULL )
Per Cederqvist's avatar
Per Cederqvist committed
333
	return EMPTY_STRING;
334
    else if (t_stat->text_store.generation == 0)
Per Cederqvist's avatar
Per Cederqvist committed
335
    {
336 337 338 339 340 341 342 343 344
	the_string.string = tmp_alloc( t_stat->no_of_chars );
	the_string.len = t_stat->no_of_chars;
	if (fseek(text_file, t_stat->text_store.file_pos, SEEK_SET) != 0)
	{
	    kom_log("Failed to seek to %ld in text mass file: %s.\n",
		    t_stat->text_store.file_pos, strerror(errno));
	    return EMPTY_STRING;
	}

Per Cederqvist's avatar
Per Cederqvist committed
345
	if ( fread(the_string.string, sizeof(char), the_string.len, text_file)
David Byers's avatar
David Byers committed
346
	    != (size_t)the_string.len )
Per Cederqvist's avatar
Per Cederqvist committed
347
	{
348 349 350
	    kom_log("WARNING: cached_get_text: premature end on text %lu\n",
		    text);
	    return EMPTY_STRING;
Per Cederqvist's avatar
Per Cederqvist committed
351 352 353 354
	}
		    
	return the_string;
    }
355 356 357
    else
    {
#warning Generation > 0 not yet handled
358
	restart_kom("Only generation 0 is handled.\n");
359
    }
Per Cederqvist's avatar
Per Cederqvist committed
360 361 362 363 364 365
}

extern Text_stat *	/* NULL on error */
cached_get_text_stat(	Text_no		text )
{
    kom_errno = KOM_NO_SUCH_TEXT;
366
    err_stat = text;
Per Cederqvist's avatar
Per Cederqvist committed
367
    TEXT_RANGE("cached_get_text_stat\n", text, NULL);
368
    TRACE2("cached_get_text_stat %lu\n", text);
Per Cederqvist's avatar
Per Cederqvist committed
369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389
    
    return text_arr[ text ];
}



/*
 * The text is set up with an empty misc-field. The misc field is
 * later initialized by create_text.
 */

#if 0
extern Text_no
cached_create_text( String message)
{
    Text_no tno;

    tno = next_text_num++;

    TRACE2("cached_create_text (len=%d)\n", message.len);

David Byers's avatar
David Byers committed
390
    if ( tno >= param.max_text )
Per Cederqvist's avatar
Per Cederqvist committed
391
    {
David Byers's avatar
David Byers committed
392
	next_text_num = param.max_text;
393 394
	kom_errno = KOM_INDEX_OUT_OF_RANGE;
        err_stat = next_text_num;
Per Cederqvist's avatar
Per Cederqvist committed
395 396 397 398 399 400 401 402 403 404 405 406 407 408 409
	
	return 0;
    }
        
    text_arr[ tno ] = alloc_text_stat();
    text_arr[ tno ]->no_of_misc = 0;
    text_arr[ tno ]->misc_items = NULL;
    text_arr[ tno ]->no_of_marks = 0;
    text_arr[ tno ]->no_of_lines = 0;
    text_arr[ tno ]->no_of_chars = 0;
    fseek(text_file, 0, SEEK_END);
    text_arr[ tno ]->file_pos = ftell(text_file);

    if ( fwrite(message.string, sizeof(char), message.len, text_file)
	!= message.len ) {
David Byers's avatar
David Byers committed
410
	kom_log("WARNING: cached_create_text: Couldn't write the text %d\n",
Per Cederqvist's avatar
Per Cederqvist committed
411 412 413 414 415 416 417 418 419 420 421
	    tno);
    }

    fflush(text_file);
    
    TRACE2("cached_create_text -> %d\n", tno);
    
    return tno;
}
#endif

Per Cederqvist's avatar
Per Cederqvist committed
422
void
Per Cederqvist's avatar
Per Cederqvist committed
423 424 425 426 427
cached_flush_text(Text_no text_no,
		  String message)
{
    if ( text_no >= next_text_num )
    {
428 429
	kom_log("cached_flush_text(%lu, string): only text %lu exists.\n",
		(u_long) text_no, (u_long) next_text_num);
Per Cederqvist's avatar
Per Cederqvist committed
430 431 432 433
	return;
    }
        
    fseek(new_text_file, 0, SEEK_END);
434
#warning Generation > 0 not yet handled
435 436 437
    text_arr[ text_no ]->text_store.generation = 0;
    text_arr[ text_no ]->text_store.file_pos = ftell(new_text_file);
    text_arr[ text_no ]->text_store.file_size = 0;
Per Cederqvist's avatar
Per Cederqvist committed
438 439

    if ( fwrite(message.string, sizeof(char), message.len, new_text_file)
David Byers's avatar
David Byers committed
440
	!= (size_t)message.len )
Per Cederqvist's avatar
Per Cederqvist committed
441
    {
David Byers's avatar
David Byers committed
442
	kom_log("WARNING: cached_flush_text: Couldn't write the text %ld\n",
443
	    (unsigned long)text_no);
Per Cederqvist's avatar
Per Cederqvist committed
444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487
    }

    fflush(new_text_file);
}

Text_no
traverse_text(Text_no seed)
{
    seed++;
    
    while ( seed < next_text_num && text_arr[ seed ] == NULL )
	seed++;

    return (seed == next_text_num) ? 0 : seed ;
}

Pers_no
traverse_person(Pers_no seed)
{
    seed++;
    
    while ( seed < next_free_num && pers_arr[ seed ] == NULL )
	seed++;

    return (seed == next_free_num) ? 0 : seed ;
}

Conf_no
traverse_conference(Conf_no seed)
{
    seed++;
    
    while ( seed < next_free_num && conf_arr[ seed ] == NULL )
	seed++;

    return (seed == next_free_num) ? 0 : seed ;
}

extern Garb_nice
cached_get_garb_nice (Conf_no conf_no)
{
    return conf_arr [ conf_no ]->nice;
}

488 489 490 491 492 493
extern Garb_nice
cached_get_keep_commented(Conf_no conf_no)
{
    return conf_arr[conf_no]->keep_commented;
}

Per Cederqvist's avatar
Per Cederqvist committed
494 495 496
extern Local_text_no
cached_get_highest_local_no (Conf_no conf_no)
{
497
    return l2g_first_appendable_key(&conf_arr[conf_no]->texts) - 1;
Per Cederqvist's avatar
Per Cederqvist committed
498 499 500 501
}

/* Lock a person struct in memory. Increase a referenc count. */
void
502
cached_lock_person(Pers_no UNUSED(pers_no))
Per Cederqvist's avatar
Per Cederqvist committed
503 504 505 506
{}

/* Decrease reference count. If zero, unlock person. */
void
507
cached_unlock_person(Pers_no UNUSED(pers_no))
Per Cederqvist's avatar
Per Cederqvist committed
508 509 510 511
{}

/* Lock a conf struct in memory. Increase a referenc count. */
void
512
cached_lock_conf(Conf_no UNUSED(conf_no))
Per Cederqvist's avatar
Per Cederqvist committed
513 514 515 516
{}

/* Decrease reference count. If zero, unlock conf. */
void
517
cached_unlock_conf(Conf_no UNUSED(conf_no))
Per Cederqvist's avatar
Per Cederqvist committed
518 519 520 521 522 523 524 525
{}


static Bool
is_clean(const char *fn)
{
    FILE *fp;

526
    if ((fp = i_fopen(fn, "rb")) == NULL)
Per Cederqvist's avatar
Per Cederqvist committed
527 528
	return FALSE;

David Byers's avatar
David Byers committed
529 530 531 532 533
    if ( getc(fp) == 'C' && 
         getc(fp) == 'L' &&
         getc(fp) == 'E' &&
         getc(fp) == 'A' &&
         getc(fp) == 'N' )
Per Cederqvist's avatar
Per Cederqvist committed
534
    {
535
	i_fclose(fp);
Per Cederqvist's avatar
Per Cederqvist committed
536 537 538 539
	return TRUE;
    }
    else
    {
540
	i_fclose(fp);
Per Cederqvist's avatar
Per Cederqvist committed
541 542 543 544
	return FALSE;
    }
}

David Byers's avatar
David Byers committed
545

Per Cederqvist's avatar
Per Cederqvist committed
546 547 548 549 550
#ifdef TIME_SYNC
static long
timerdiff(struct timeval a,
	   struct timeval b)
{
551
    /* Ignore the tv_usec parts.  One second more or less doesn't matter.  */
Per Cederqvist's avatar
Per Cederqvist committed
552 553 554 555 556
    return a.tv_sec - b.tv_sec;
}
#endif

extern void			/* Write out everything. */
557
cache_sync_all(void)
Per Cederqvist's avatar
Per Cederqvist committed
558
{
559
    struct dbfile *fp;
560 561
    Conf_no ic;
    Text_no it;
Per Cederqvist's avatar
Per Cederqvist committed
562 563 564 565 566 567 568 569 570 571 572 573 574

#ifdef TIME_SYNC
    struct rusage start, after_confs, after_persons, after_text_stats,
    	after_text_masses;
    time_t st, ac, ap, ats, atm;
    void getrusage(int who, struct rusage *rusage);
#endif
    
#ifdef TIME_SYNC
    getrusage(0, &start);
    time(&st);
#endif

Per Cederqvist's avatar
Per Cederqvist committed
575
    if ( is_clean(param.datafile_name) )
Per Cederqvist's avatar
Per Cederqvist committed
576
    {
577 578
	if (is_clean(param.backupfile_name))
	{
579 580
	    if (i_rename(param.backupfile_name,
			 param.backupfile_name_2) != 0)
581
	    {
David Byers's avatar
David Byers committed
582
		kom_log("pre_sync: can't do extra backup.\n");
583 584 585
	    }
	}

586
	if (i_rename(param.datafile_name, param.backupfile_name) != 0)
David Byers's avatar
David Byers committed
587
	    kom_log("WARNING: cache_sync_all: can't backup.\n");
Per Cederqvist's avatar
Per Cederqvist committed
588 589
    }
    else
David Byers's avatar
David Byers committed
590
	kom_log("cache_sync_all: datafile not clean. No backup taken.\n");
Per Cederqvist's avatar
Per Cederqvist committed
591
    
592
    if ((fp = dbfile_open_write(param.datafile_name, "DIRTY", NULL)) == NULL)
Per Cederqvist's avatar
Per Cederqvist committed
593
    {
David Byers's avatar
David Byers committed
594
	kom_log("WARNING: cache_sync_all: can't open file to save in.\n");
Per Cederqvist's avatar
Per Cederqvist committed
595 596 597
	return;
    }

598 599 600
    /*
     * Print file header and other things that go before the conferences.
     */
Per Cederqvist's avatar
Per Cederqvist committed
601

602
    switch (fp->format)
603 604
    {
    case 0:
605
	fprintf(fp->fp, "%d\n", next_free_num);	  /* NEXT_FREE_NUM */
606 607
        break;
    case 1:
David Byers's avatar
David Byers committed
608
    case 2:
609
    case 3:
610 611 612
	fprintf(fp->fp, "#C %d\n", next_free_num);
	fprintf(fp->fp, "#T %ld\n", next_text_num);
        fprintf(fp->fp, "I");
613
        foutput_info(fp, &kom_info);
614
        foutput_newline(fp);
615 616
        break;
    default:
617
        restart_kom("Unknown output file format: %d\n", fp->format);
618 619
    }
    
620
    for (ic = 1; ic < next_free_num; ic++) /* CONFS */
Per Cederqvist's avatar
Per Cederqvist committed
621
    {
622
        switch (fp->format)
623 624
        {
        case 0:
625
            if (conf_arr[ic] == NULL)
626
                foutput_atsign(fp);
627 628
            else
            {
629
                fprintf(fp->fp, "+ ");
630
                foutput_conference(fp, conf_arr[ic]);
631
            }
632
            foutput_newline(fp);
633 634
            break;
        case 1:
David Byers's avatar
David Byers committed
635
        case 2:
636
	case 3:
637
            if (conf_arr[ic] != NULL)
638
            {
639
                fprintf(fp->fp, "C %lu", (unsigned long)ic);
640
                foutput_conference(fp, conf_arr[ic]);
641
                foutput_newline(fp);
642 643 644 645
            }
            break;

        default:
646
            restart_kom("Bad output file format: %d\n", fp->format);
647
        }
Per Cederqvist's avatar
Per Cederqvist committed
648 649 650 651 652
    }
#ifdef TIME_SYNC
    getrusage(0, &after_confs);
    time(&ac);
#endif
653
    for (ic = 1; ic < next_free_num; ic++) /* PERSONS */
Per Cederqvist's avatar
Per Cederqvist committed
654
    {
655
        switch (fp->format)
656 657
        {
        case 0:
658
            if (pers_arr[ic] == NULL)
659
                foutput_atsign(fp);
660 661
            else
            {
662 663 664
                fprintf(fp->fp, "+ ");
                fprintf(fp->fp, "%dH", PASSWD_LEN);
                fwrite(pers_arr[ic]->pwd, PASSWD_LEN, 1, fp->fp);
665
                foutput_person(fp, pers_arr[ic]);
666
            }
667
            foutput_newline(fp);
668 669
            break;
        case 1:
David Byers's avatar
David Byers committed
670
        case 2:
671
	case 3:
672
            if (pers_arr[ic] != NULL )
673
            {
674 675 676
                fprintf(fp->fp, "P %lu", (unsigned long)ic);
                fprintf(fp->fp, " %dH", PASSWD_LEN);
                fwrite(pers_arr[ic]->pwd, PASSWD_LEN, 1, fp->fp);
677
                foutput_person(fp, pers_arr[ic]);
678
                foutput_newline(fp);
679 680 681 682
            }
            break;

        default:
683
            restart_kom("Bad output file format: %d\n", fp->format);
684
        }
Per Cederqvist's avatar
Per Cederqvist committed
685 686 687 688 689 690
    }
#ifdef TIME_SYNC
    getrusage(0, &after_persons);
    time(&ap);
#endif

691 692 693 694
    /*
     * Print things that go between persons and texts
     */

695
    switch (fp->format)
696 697
    {
    case 0:
698
	fprintf(fp->fp, "%ld\n", next_text_num);	/* NEXT_TEXT_NUM */
699 700
        break;
    case 1:
701
    case 2:
702
    case 3:
703 704
        break;
    default:
705
        restart_kom("Unknown output file format: %d\n", fp->format);
706 707
    }
    
Per Cederqvist's avatar
Per Cederqvist committed
708

709
    for (it = 1; it < next_text_num; it++) /* TEXT_STATS */
Per Cederqvist's avatar
Per Cederqvist committed
710
    {
711
        switch (fp->format)
712 713
        {
        case 0:
714
            if (text_arr[it] == NULL)
715
                foutput_atsign(fp);
716 717
            else
            {
718
                fprintf(fp->fp, "+ ");
719
                foutput_text_stat(fp, text_arr[it]);
720
            }
721
            foutput_newline(fp);
722 723
            break;
        case 1:
David Byers's avatar
David Byers committed
724
        case 2:
725
        case 3:
726
            if (text_arr[it] != NULL)
727
            {
728
                fprintf(fp->fp, "T %lu", it);
729
                foutput_text_stat(fp, text_arr[it]);
730
                foutput_newline(fp);
731 732 733
            }
            break;
        default:
734
            restart_kom("Unknown output file format: %d\n", fp->format);
735 736
                
        }
Per Cederqvist's avatar
Per Cederqvist committed
737 738
    }

739 740 741 742 743 744 745 746
    /*
     * Print file footer
     *
     * Ho-hum. I thought there was supposed to be a newline at the end
     * of a version zero file, but it seems I was wrong, so this code
     * basically does...absolutely nothing.
     */

747
    switch (fp->format)
David Byers's avatar
David Byers committed
748
    {
749 750 751
    case 0:
        break;
    case 1:
David Byers's avatar
David Byers committed
752
    case 2:
753
    case 3:
754 755
        break;
    default:
756
        restart_kom("Unknown output file format: %d\n", fp->format);
David Byers's avatar
David Byers committed
757 758
    }
    
Per Cederqvist's avatar
Per Cederqvist committed
759 760 761 762 763 764 765 766
#ifdef TIME_SYNC
    getrusage(0, &after_text_stats);
    time(&ats);

    getrusage(0, &after_text_masses);
    time(&atm);
#endif

767
    dbfile_change_magic(fp, "CLEAN");
768 769
    dbfile_delete(fp);
    fp = NULL;
Per Cederqvist's avatar
Per Cederqvist committed
770 771

#ifdef TIME_SYNC
David Byers's avatar
David Byers committed
772
    kom_log("Sync ready.\n"
Per Cederqvist's avatar
Per Cederqvist committed
773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789
    	"User: %4ld sec (%4ld conf, %4ld pers, %4ld stat, %4ld text)\n"
    	"Sys:  %4ld sec (%4ld conf, %4ld pers, %4ld stat, %4ld text)\n"
	"Real: %4ld sec (%4ld conf, %4ld pers, %4ld stat, %4ld text)\n"
	"Page faults: %4ld. Swapped: %4ld. Outblocked: %4ld.\n",
	
	timerdiff(after_text_masses.ru_utime, start.ru_utime),
	timerdiff(after_confs.ru_utime, start.ru_utime),
	timerdiff(after_persons.ru_utime, after_confs.ru_utime),
	timerdiff(after_text_stats.ru_utime, after_persons.ru_utime),
	timerdiff(after_text_masses.ru_utime, after_text_stats.ru_utime),
	
	timerdiff(after_text_masses.ru_stime, start.ru_stime),
	timerdiff(after_confs.ru_stime, start.ru_stime),
	timerdiff(after_persons.ru_stime, after_confs.ru_stime),
	timerdiff(after_text_stats.ru_stime, after_persons.ru_stime),
	timerdiff(after_text_masses.ru_stime, after_text_stats.ru_stime),

790 791 792 793 794
	(u_long)ldifftime(atm, st),
	(u_long)ldifftime(ac, st),
	(u_long)ldifftime(ap, ac),
	(u_long)ldifftime(ats, ap),
	(u_long)ldifftime(atm, ats),
Per Cederqvist's avatar
Per Cederqvist committed
795 796 797 798 799 800 801

	after_text_masses.ru_majflt - start.ru_majflt,
	after_text_masses.ru_nswap - start.ru_nswap,
	after_text_masses.ru_oublock - start.ru_oublock);
#endif    
}

Per Cederqvist's avatar
Per Cederqvist committed
802
void
Per Cederqvist's avatar
Per Cederqvist committed
803 804
cache_open_new_text_file(void)
{
805
    if ((new_text_file = i_fopen(param.textfile_name, "w")) == NULL)
Per Cederqvist's avatar
Per Cederqvist committed
806
    {
David Byers's avatar
David Byers committed
807
	kom_log("Can't open file to save new texts. Goodbye.\n");
Per Cederqvist's avatar
Per Cederqvist committed
808 809 810 811 812 813 814
	exit(1);
    }
}

extern Success
init_cache(void)
{
815
    struct dbfile *fp = NULL;
816
    unsigned long i;
Per Cederqvist's avatar
Per Cederqvist committed
817
    extern int vflag;		/* from dbck.c */
818
    extern Bool truncated_texts; /* from dbck.c */
David Byers's avatar
David Byers committed
819
    long num;
820 821
    char done, read_text_num, read_conf_num;
    int c;
822 823 824 825
    extern int modifications;
    extern int pers_pres_conf;
    extern int conf_pres_conf;
    extern int motd_conf;
826
    extern Text_no motd_of_lyskom;
827 828 829 830 831
    extern int kom_news_conf;
       
    read_text_num = 0;
    read_conf_num = 0;
        
David Byers's avatar
David Byers committed
832 833 834 835 836 837
    pers_arr = smalloc(sizeof(*pers_arr) * param.max_conf);
    conf_arr = smalloc(sizeof(*conf_arr) * param.max_conf);
    text_arr = smalloc(sizeof(*text_arr) * param.max_text);
    name_list = smalloc(sizeof(*name_list) * param.max_conf);

    for (i = 0; i < param.max_conf; i++)
David Byers's avatar
David Byers committed
838
	conf_arr[i] = NULL;
David Byers's avatar
David Byers committed
839
    for (i = 0; i < param.max_conf; i++)
David Byers's avatar
David Byers committed
840
	pers_arr[i] = NULL;
David Byers's avatar
David Byers committed
841
    for (i = 0; i < param.max_text; i++)
David Byers's avatar
David Byers committed
842 843 844
	text_arr[i] = NULL;
    
    
Per Cederqvist's avatar
Per Cederqvist committed
845 846
    new_text_file = NULL;
    
847
    if ((text_file = i_fopen(param.textfile_name, "rb")) == NULL)
Per Cederqvist's avatar
Per Cederqvist committed
848
    {
Per Cederqvist's avatar
Per Cederqvist committed
849
	perror(param.textfile_name);
850
	restart_kom("ERROR: init_cache: can't open text file %s.\n",
Per Cederqvist's avatar
Per Cederqvist committed
851
		    param.textfile_name);
Per Cederqvist's avatar
Per Cederqvist committed
852 853
    }

Per Cederqvist's avatar
Per Cederqvist committed
854
    if ( is_clean(param.datafile_name) )
Per Cederqvist's avatar
Per Cederqvist committed
855
    {
856
	if ((fp = dbfile_open_read(param.datafile_name, "CLEAN")) == NULL)
Per Cederqvist's avatar
Per Cederqvist committed
857
	{
David Byers's avatar
David Byers committed
858
	    kom_log("WARNING: init_cache: can't open datafile.\n");
Per Cederqvist's avatar
Per Cederqvist committed
859 860
	    return FAILURE;
	}
David Byers's avatar
David Byers committed
861
	kom_log("MSG: init_cache: using datafile.\n");
Per Cederqvist's avatar
Per Cederqvist committed
862
    }
Per Cederqvist's avatar
Per Cederqvist committed
863
    else if ( is_clean(param.backupfile_name) )
Per Cederqvist's avatar
Per Cederqvist committed
864
    {
865 866
	if ((fp = dbfile_open_read(param.backupfile_name, "CLEAN"))
	    == NULL)
Per Cederqvist's avatar
Per Cederqvist committed
867
	{
David Byers's avatar
David Byers committed
868
	    kom_log("WARNING: init_cache: can't open backupfile.\n");
Per Cederqvist's avatar
Per Cederqvist committed
869 870
	    return FAILURE;
	}
David Byers's avatar
David Byers committed
871
	kom_log("MSG: init_cache: using backup file.\n");
Per Cederqvist's avatar
Per Cederqvist committed
872 873 874
    }
    else
    {
David Byers's avatar
David Byers committed
875
	kom_log("WARNING: init_cache: can't find old data base.\n");
Per Cederqvist's avatar
Per Cederqvist committed
876 877 878
	return FAILURE;
    }

879 880 881
    /*
     * Read file header
     */
David Byers's avatar
David Byers committed
882

883
    switch (fp->format)
884 885
    {
    case 0:
886
	fparse_set_pos(fp, 6);	/* skip clean/dirty flag. */
David Byers's avatar
David Byers committed
887 888
	next_free_num = fparse_long(fp);	  /* NEXT_FREE_NUM */
	read_conf_num = 1;
889 890
        if (vflag)
        {
891
            kom_log("Data file version is '%d'\n", fp->format);
David Byers's avatar
David Byers committed
892
            kom_log("Reading %d conferences, starting at pos %ld.\n",
893
                next_free_num-1, dbfile_ftell(fp));
894 895 896
        }
        break;
    case 1:
897
	fparse_set_pos(fp, 12);
898
        if (vflag)
899
            kom_log("Data file version is '%d'\n", fp->format);
900
        break;
David Byers's avatar
David Byers committed
901
    case 2:
902
    case 3:
903
        fparse_set_pos(fp, 33);
David Byers's avatar
David Byers committed
904
        if (vflag)
905
            kom_log("Data file version is '%d'\n", fp->format);
David Byers's avatar
David Byers committed
906
        break;
907
    default:
908
        restart_kom("Unknown input file format: %d\n", fp->format);
909
    }
David Byers's avatar
David Byers committed
910 911
    
    done = 0;
912 913 914 915 916 917 918

    /*
     * Loop over records in the database. For a version zero database,
     * loop next_free_num times and for a version one database, loop
     * until the end of the file or until done is set
     */
    
David Byers's avatar
David Byers committed
919
    for ( i = 1;
920
          (fp->format == 0 && i < next_free_num && !dbfile_feof(fp)) ||
921
          (fp->format == 1 && !done) ||
922 923
          (fp->format == 2 && !done) ||
          (fp->format == 3 && !done);
924
          i++ )
Per Cederqvist's avatar
Per Cederqvist committed
925
    {
David Byers's avatar
David Byers committed
926
	num = i;
Per Cederqvist's avatar
Per Cederqvist committed
927
	fskipwhite(fp);
David Byers's avatar
David Byers committed
928

929
	switch(c = dbfile_getc(fp))
930 931
	{
        case EOF:
932
            switch (fp->format)
933
            {
934 935
            case 0:
                restart_kom("Unexpected end-of-file reading conferences "
936 937
                            "in data file version %d.",
                            fp->format);
938 939 940
                break;

            case 1:
941
	    case 2:
942
	    case 3:
943 944 945 946
                done = 1;
                break;

            default:
947 948
                restart_kom("Unknown input file format: %d\n",
                            fp->format);
949
            }
950 951 952
            break;
            
	case '@':
953
            switch (fp->format)
954
            {
955 956 957 958
            case 0:
                conf_arr[num] = NULL;
                break;
            case 1:
959
            case 2:
960
            case 3:
961 962
		restart_kom("@ record in data file version %d at %ld.\n",
                            fp->format, dbfile_ftell(fp));
963 964
                break;
            default:
965 966
                restart_kom("Unknown input file format: %d\n",
                            fp->format);
967
            }
968