dbck-cache.c 32.3 KB
Newer Older
Linus Tolke's avatar
Linus Tolke 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's avatar
Linus Tolke 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's avatar
Linus Tolke 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
Per Cederqvist's avatar
Per Cederqvist committed
59

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

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

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

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

96
97
98
/* Defined in standalone.c */

extern Info kom_info;
David Byers's avatar
David Byers committed
99
100


Per Cederqvist's avatar
Per Cederqvist committed
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/* 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
126
    printf("Text_no out of range 1 ... %ld ", next_text_num); \
Per Cederqvist's avatar
Per Cederqvist committed
127
128
129
130
131
132
    printf(str);	\
    fflush(stdout);	\
    fflush(stderr);	\
    abort(); 		\
}

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

Per Cederqvist's avatar
Per Cederqvist committed
143
144
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

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 )
{
174
    TRACE2("Text %lu is changed.\n", text_no);
Per Cederqvist's avatar
Per Cederqvist committed
175
    VOID_TEXT_RANGE("mark_text_as_changed\n", text_no);
Per Cederqvist's avatar
Per Cederqvist committed
176
177
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
}    


/*
 * 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);
208
    err_stat = person;
Per Cederqvist's avatar
Per Cederqvist committed
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
    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
229
    if ( next_free_num >= param.max_conf )
Per Cederqvist's avatar
Per Cederqvist committed
230
    {
231
        err_stat = next_free_num;
Per Cederqvist's avatar
Per Cederqvist committed
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
	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 )
    {
256
        err_stat = conf;
Per Cederqvist's avatar
Per Cederqvist committed
257
258
259
260
261
262
263
264
265
266
267
268
269
270
	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 )
    {
271
        err_stat = pers;
Per Cederqvist's avatar
Per Cederqvist committed
272
273
274
275
276
277
278
279
280
281
282
283
284
285
	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 )
    {
286
        err_stat = text;
Per Cederqvist's avatar
Per Cederqvist committed
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
	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;
303
    err_stat = conf_no;
Per Cederqvist's avatar
Per Cederqvist committed
304
305
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;

    TEXT_RANGE("cached_get_text\n", text, EMPTY_STRING);
328
    TRACE2("cached_get_text %lu\n", text);
Per Cederqvist's avatar
Per Cederqvist committed
329
330
331
332
333
334
335
336
337

    if ( text_arr[ text ] == NULL )
	return EMPTY_STRING;
    else
    {
	the_string.string = tmp_alloc( text_arr[text]->no_of_chars );
	the_string.len = text_arr[text]->no_of_chars;
	fseek(text_file, text_arr[ text ]->file_pos, SEEK_SET);
	if ( fread(the_string.string, sizeof(char), the_string.len, text_file)
David Byers's avatar
David Byers committed
338
	    != (size_t)the_string.len )
Per Cederqvist's avatar
Per Cederqvist committed
339
	{
David Byers's avatar
David Byers committed
340
	    kom_log("%s read enough characters of text %lu\n",
Per Cederqvist's avatar
Per Cederqvist committed
341
		"WARNING: cached_get_text: couldn't",
342
		(unsigned long)text);
Per Cederqvist's avatar
Per Cederqvist committed
343
344
345
346
347
348
349
350
351
352
	}
		    
	return the_string;
    }
}

extern Text_stat *	/* NULL on error */
cached_get_text_stat(	Text_no		text )
{
    kom_errno = KOM_NO_SUCH_TEXT;
353
    err_stat = text;
Per Cederqvist's avatar
Per Cederqvist committed
354
    TEXT_RANGE("cached_get_text_stat\n", text, NULL);
355
    TRACE2("cached_get_text_stat %lu\n", text);
Per Cederqvist's avatar
Per Cederqvist committed
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
    
    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
377
    if ( tno >= param.max_text )
Per Cederqvist's avatar
Per Cederqvist committed
378
    {
David Byers's avatar
David Byers committed
379
	next_text_num = param.max_text;
380
381
	kom_errno = KOM_INDEX_OUT_OF_RANGE;
        err_stat = next_text_num;
Per Cederqvist's avatar
Per Cederqvist committed
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
	
	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
397
	kom_log("WARNING: cached_create_text: Couldn't write the text %d\n",
Per Cederqvist's avatar
Per Cederqvist committed
398
399
400
401
402
403
404
405
406
407
408
	    tno);
    }

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

Per Cederqvist's avatar
Per Cederqvist committed
409
void
Per Cederqvist's avatar
Per Cederqvist committed
410
411
412
413
414
cached_flush_text(Text_no text_no,
		  String message)
{
    if ( text_no >= next_text_num )
    {
415
416
	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
417
418
419
420
421
422
423
	return;
    }
        
    fseek(new_text_file, 0, SEEK_END);
    text_arr[ text_no ]->file_pos = ftell(new_text_file);

    if ( fwrite(message.string, sizeof(char), message.len, new_text_file)
David Byers's avatar
David Byers committed
424
	!= (size_t)message.len )
Per Cederqvist's avatar
Per Cederqvist committed
425
    {
David Byers's avatar
David Byers committed
426
	kom_log("WARNING: cached_flush_text: Couldn't write the text %ld\n",
427
	    (unsigned long)text_no);
Per Cederqvist's avatar
Per Cederqvist committed
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
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
    }

    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;
}

472
473
474
475
476
477
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
478
479
480
extern Local_text_no
cached_get_highest_local_no (Conf_no conf_no)
{
481
    return l2g_first_appendable_key(&conf_arr[conf_no]->texts) - 1;
Per Cederqvist's avatar
Per Cederqvist committed
482
483
484
485
}

/* Lock a person struct in memory. Increase a referenc count. */
void
486
cached_lock_person(Pers_no UNUSED(pers_no))
Per Cederqvist's avatar
Per Cederqvist committed
487
488
489
490
{}

/* Decrease reference count. If zero, unlock person. */
void
491
cached_unlock_person(Pers_no UNUSED(pers_no))
Per Cederqvist's avatar
Per Cederqvist committed
492
493
494
495
{}

/* Lock a conf struct in memory. Increase a referenc count. */
void
496
cached_lock_conf(Conf_no UNUSED(conf_no))
Per Cederqvist's avatar
Per Cederqvist committed
497
498
499
500
{}

/* Decrease reference count. If zero, unlock conf. */
void
501
cached_unlock_conf(Conf_no UNUSED(conf_no))
Per Cederqvist's avatar
Per Cederqvist committed
502
503
504
505
506
507
508
509
{}


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

510
    if ((fp = i_fopen(fn, "rb")) == NULL)
Per Cederqvist's avatar
Per Cederqvist committed
511
512
	return FALSE;

David Byers's avatar
David Byers committed
513
514
515
516
517
    if ( getc(fp) == 'C' && 
         getc(fp) == 'L' &&
         getc(fp) == 'E' &&
         getc(fp) == 'A' &&
         getc(fp) == 'N' )
Per Cederqvist's avatar
Per Cederqvist committed
518
    {
519
	i_fclose(fp);
Per Cederqvist's avatar
Per Cederqvist committed
520
521
522
523
	return TRUE;
    }
    else
    {
524
	i_fclose(fp);
Per Cederqvist's avatar
Per Cederqvist committed
525
526
527
528
	return FALSE;
    }
}

David Byers's avatar
David Byers committed
529
static void
530
sync_output_header(struct dbfile* fp, const char *state)
David Byers's avatar
David Byers committed
531
{
532
    switch (fp->format)
David Byers's avatar
David Byers committed
533
534
    {
    case 0:
535
        fprintf(fp->fp, "%s\n", state);
David Byers's avatar
David Byers committed
536
537
        break;
    case 1:
538
        fprintf(fp->fp, "%s:%05d\n", state, fp->format);
David Byers's avatar
David Byers committed
539
540
        break;
    case 2:
541
	foutput_header(fp, state, 1);
David Byers's avatar
David Byers committed
542
543
544
        break;
    default:
        restart_kom("sync_output_header(): Unknown output format %d",
545
                    fp->format);
David Byers's avatar
David Byers committed
546
547
548
549
550
    }
}



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

extern void			/* Write out everything. */
562
cache_sync_all(void)
Per Cederqvist's avatar
Per Cederqvist committed
563
{
564
    struct dbfile *fp;
565
566
    Conf_no ic;
    Text_no it;
Per Cederqvist's avatar
Per Cederqvist committed
567
568
569
570
571
572
573
574
575
576
577
578
579

#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
580
    if ( is_clean(param.datafile_name) )
Per Cederqvist's avatar
Per Cederqvist committed
581
    {
582
583
	if (is_clean(param.backupfile_name))
	{
584
585
	    if (i_rename(param.backupfile_name,
			 param.backupfile_name_2) != 0)
586
	    {
David Byers's avatar
David Byers committed
587
		kom_log("pre_sync: can't do extra backup.\n");
588
589
590
	    }
	}

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

603
604
605
    /*
     * Print file header and other things that go before the conferences.
     */
Per Cederqvist's avatar
Per Cederqvist committed
606

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

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

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

695
696
697
698
    /*
     * Print things that go between persons and texts
     */

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

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

741
742
743
744
745
746
747
748
    /*
     * 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.
     */

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

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

768
769
770
771
    rewind(fp->fp);
    sync_output_header(fp, "CLEAN");
    dbfile_delete(fp);
    fp = NULL;
Per Cederqvist's avatar
Per Cederqvist committed
772
773

#ifdef TIME_SYNC
David Byers's avatar
David Byers committed
774
    kom_log("Sync ready.\n"
Per Cederqvist's avatar
Per Cederqvist committed
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
    	"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),

792
793
794
795
796
	(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
797
798
799
800
801
802
803

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

extern Success
init_cache(void)
{
817
    struct dbfile *fp = NULL;
818
    unsigned long i;
Per Cederqvist's avatar
Per Cederqvist committed
819
    extern int vflag;		/* from dbck.c */
820
    extern Bool truncated_texts; /* from dbck.c */
David Byers's avatar
David Byers committed
821
    long num;
822
823
    char done, read_text_num, read_conf_num;
    int c;
824
825
826
827
    extern int modifications;
    extern int pers_pres_conf;
    extern int conf_pres_conf;
    extern int motd_conf;
828
    extern Text_no motd_of_lyskom;
829
830
831
832
833
    extern int kom_news_conf;
       
    read_text_num = 0;
    read_conf_num = 0;
        
David Byers's avatar
David Byers committed
834
835
836
837
838
839
    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
840
	conf_arr[i] = NULL;
David Byers's avatar
David Byers committed
841
    for (i = 0; i < param.max_conf; i++)
David Byers's avatar
David Byers committed
842
	pers_arr[i] = NULL;
David Byers's avatar
David Byers committed
843
    for (i = 0; i < param.max_text; i++)
David Byers's avatar
David Byers committed
844
845
846
	text_arr[i] = NULL;
    
    
Per Cederqvist's avatar
Per Cederqvist committed
847
848
    new_text_file = NULL;
    
849
    if ((text_file = i_fopen(param.textfile_name, "rb")) == NULL)
Per Cederqvist's avatar
Per Cederqvist committed
850
    {
Per Cederqvist's avatar
Per Cederqvist committed
851
	perror(param.textfile_name);
852
	restart_kom("ERROR: init_cache: can't open text file %s.\n",
Per Cederqvist's avatar
Per Cederqvist committed
853
		    param.textfile_name);
Per Cederqvist's avatar
Per Cederqvist committed
854
855
    }

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

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

884
    switch (fp->format)
885
886
    {
    case 0:
887
	fparse_set_pos(fp, 6);	/* skip clean/dirty flag. */
David Byers's avatar
David Byers committed
888
889
	next_free_num = fparse_long(fp);	  /* NEXT_FREE_NUM */
	read_conf_num = 1;
890
891
        if (vflag)
        {
892
            kom_log("Data file version is '%d'\n", fp->format);
David Byers's avatar
David Byers committed
893
            kom_log("Reading %d conferences, starting at pos %ld.\n",
894
                next_free_num-1, dbfile_ftell(fp));
895
896
897
        }
        break;
    case 1:
898
	fparse_set_pos(fp, 12);
899
        if (vflag)
900
            kom_log("Data file version is '%d'\n", fp->format);
901
        break;
David Byers's avatar
David Byers committed
902
    case 2:
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
921
922
          (fp->format == 0 && i < next_free_num && !feof(fp->fp)) ||
          (fp->format == 1 && !done) ||
          (fp->format == 2 && !done);
923
          i++ )
Per Cederqvist's avatar
Per Cederqvist committed
924
    {
David Byers's avatar
David Byers committed
925
	num = i;
Per Cederqvist's avatar
Per Cederqvist committed
926
	fskipwhite(fp);
David Byers's avatar
David Byers committed
927

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

            case 1:
940
	    case 2:
941
942
943
944
                done = 1;
                break;

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

	case 'I':
968
            switch (fp->format)
969
            {
970
            case 0:
971
972
                restart_kom("I record in data file version %d at %ld.\n",
                            fp->format, dbfile_ftell(fp));
973
974
                break;
            case 1:
975
            case 2:
976
                if (fparse_info(fp, &kom_info) != OK)
977
978
                    restart_kom("Invalid I record in data file version %d at %ld.\n",
                                fp->format, dbfile_ftell(fp));
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
                
                if (pers_pres_conf != -1)
                {
                    modifications += (kom_info.pers_pres_conf !=
                                      pers_pres_conf);
                    kom_info.pers_pres_conf = pers_pres_conf;
                }
                if (conf_pres_conf != -1)
                {
                    modifications += (kom_info.conf_pres_conf !=
                                      conf_pres_conf);
                    kom_info.conf_pres_conf = conf_pres_conf;
                }
                if (motd_conf != -1)
                {
                    modifications += (kom_info.motd_conf !=
                                      motd_conf);
                    kom_info.motd_conf = motd_conf;
                }
                if (kom_news_conf != -1)
                {
                    modifications += (kom_info.kom_news_conf !=
                                      kom_news_conf);
                    kom_info.kom_news_conf = kom_news_conf;
                }
1004
                if (motd_of_lyskom != (Text_no)-1)
1005
1006
1007
1008
1009
1010
1011
                {
                    modifications += (kom_info.motd_of_lyskom !=
                                      motd_of_lyskom);
                    kom_info.motd_of_lyskom = motd_of_lyskom;
                }
                break;
            default:
1012
1013
                restart_kom("Unknown input file format: %d\n",
                            fp->format);
1014
            }
1015
            break;
David Byers's avatar
David Byers committed
1016
1017
	    
	case 'C':
1018
            switch (fp->format)
1019
1020
            {
            case 0:
1021
1022
                restart_kom("C record in data file version %d at %ld.\n",
                            fp->format, dbfile_ftell(fp));
1023
1024
1025
                break;

            case 1:
1026
            case 2:
1027
1028
1029
1030
1031
                num = fparse_long(fp);
                if (conf_arr[num])
                    free_conference(conf_arr[num]);
                conf_arr[num] = alloc_conference();
                if (fparse_conference(fp, conf_arr[num]) != OK)
1032
                    restart_kom("init_cache(): %s. i == %lu\n", 
1033
1034
1035
1036
1037
1038
                                "fparse_conference failed", i);
                name_list[num] = EMPTY_STRING;
                s_strcpy(&name_list[num], conf_arr[ num ]->name);
                break;

            default:
1039
1040
                restart_kom("Unknown input file format: %d\n",
                            fp->format);
1041
            }
Per Cederqvist's avatar
Per Cederqvist committed
1042
1043
	    break;

David Byers's avatar
David Byers committed
1044
	case 'P':
1045
            switch (fp->format)
1046
1047
            {
            case 0:
1048
1049
                restart_kom("P record in data file version %d at %ld.\n",
                            fp->format, dbfile_ftell(fp));
1050
1051
1052
                break;

            case 1:
1053
            case 2:
1054
1055
1056
1057
1058
                num = fparse_long(fp);
                if (pers_arr[num])
                    free_person(pers_arr[num]);
                pers_arr[num] = alloc_person();
                if ( fparse_person(fp, pers_arr[ num ]) != OK )
1059
                    restart_kom("init_cache: fparse_person failed. num==%ld\n",
1060
1061
1062
1063
                                num);
                break;

            default:
1064
1065
                restart_kom("Unknown input file format: %d\n",
                            fp->format);
1066
            }
David Byers's avatar
David Byers committed
1067
1068
1069
	    break;
	    
	case 'T':
1070
            switch (fp->format)
1071
1072
            {
            case 0:
1073
1074
                restart_kom("T record in data file version %d at %ld\n",
                            fp->format, dbfile_ftell(fp));
1075
1076
1077
                break;

            case 1:
1078
            case 2:
1079
1080
1081
1082
1083
1084
1085
1086
1087
                num = fparse_long(fp);
                if (text_arr[num])
                    free_text_stat(text_arr[num]);
                text_arr[ num ] = alloc_text_stat();
                if ( fparse_text_stat(fp, text_arr[ num ]) != OK )
                {
                    /* Simply ignore everything else.  The cause of this
                       error might be that the file has been truncated (maybe
                       due to an overfull disk). */
David Byers's avatar
David Byers committed
1088
                    kom_log("init_cache(): fparse_text_stat failed "
1089
                        "for text %ld.\n%s",
1090
1091
1092
1093
1094
1095
1096
1097
1098
                        num, "Everything remaining is lost.\n");
                    next_text_num = i;
                    read_text_num = 1;
                    truncated_texts = TRUE;
                    done = 1;
                }
                break;

            default:
1099
1100
                restart_kom("Unknown input file format: %d\n",
                            fp->format);
1101
            }
David Byers's avatar
David Byers committed
1102
1103
	    break;	
    
Per Cederqvist's avatar
Per Cederqvist committed
1104
	case '+':
1105
            switch (fp->format)
1106
1107
1108
1109
            {
            case 0:
                conf_arr[ i ] = alloc_conference();
                if ( fparse_conference(fp, conf_arr[ i ]) != OK )
1110
                    restart_kom("init_cache(): %s. i == %lu\n", 
1111
1112
1113
1114
1115
                                "fparse_conference failed", i);
                name_list[i] = EMPTY_STRING;
                s_strcpy(&name_list[i], conf_arr[ i ]->name);
                break;
            case 1:
1116
            case 2:
1117
1118
                restart_kom("+ record in data file version %d at %ld.\n",
                            fp->format, dbfile_ftell(fp));
1119
1120
                break;
            default:
1121
1122
                restart_kom("Unknown input file format: %d\n",
                            fp->format);
1123
1124
            }
            break;
David Byers's avatar
David Byers committed
1125
1126

	case '#':
1127
            switch (fp->format)
1128
1129
            {
            case 0:
1130
1131
                restart_kom("#record in data file version %d at %ld.\n",
                            fp->format, dbfile_ftell(fp));
1132
1133
1134
                break;

            case 1:
1135
            case 2:
1136
                switch (c = dbfile_getc(fp))
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
                {
                case 'C':
                    next_free_num = fparse_long(fp);
                    read_conf_num = 1;
                    break;
                case 'T':
                    next_text_num = fparse_long(fp);
                    read_text_num = 1;
                    break;
                default:
                    restart_kom("Unknown # record (#%c) in data "
1148
1149
                                "file version %d at %ld.\n",
                                c, fp->format,