GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/vi/build/../common/log.c Lines: 0 225 0.0 %
Date: 2017-11-07 Branches: 0 137 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: log.c,v 1.12 2017/04/18 01:45:35 deraadt Exp $	*/
2
3
/*-
4
 * Copyright (c) 1992, 1993, 1994
5
 *	The Regents of the University of California.  All rights reserved.
6
 * Copyright (c) 1992, 1993, 1994, 1995, 1996
7
 *	Keith Bostic.  All rights reserved.
8
 *
9
 * See the LICENSE file for redistribution information.
10
 */
11
12
#include "config.h"
13
14
#include <sys/types.h>
15
#include <sys/queue.h>
16
#include <sys/stat.h>
17
18
#include <bitstring.h>
19
#include <errno.h>
20
#include <fcntl.h>
21
#include <libgen.h>
22
#include <limits.h>
23
#include <stdio.h>
24
#include <stdlib.h>
25
#include <string.h>
26
27
#include "common.h"
28
29
/*
30
 * The log consists of records, each containing a type byte and a variable
31
 * length byte string, as follows:
32
 *
33
 *	LOG_CURSOR_INIT		MARK
34
 *	LOG_CURSOR_END		MARK
35
 *	LOG_LINE_APPEND		recno_t		char *
36
 *	LOG_LINE_DELETE		recno_t		char *
37
 *	LOG_LINE_INSERT		recno_t		char *
38
 *	LOG_LINE_RESET_F	recno_t		char *
39
 *	LOG_LINE_RESET_B	recno_t		char *
40
 *	LOG_MARK		LMARK
41
 *
42
 * We do before image physical logging.  This means that the editor layer
43
 * MAY NOT modify records in place, even if simply deleting or overwriting
44
 * characters.  Since the smallest unit of logging is a line, we're using
45
 * up lots of space.  This may eventually have to be reduced, probably by
46
 * doing logical logging, which is a much cooler database phrase.
47
 *
48
 * The implementation of the historic vi 'u' command, using roll-forward and
49
 * roll-back, is simple.  Each set of changes has a LOG_CURSOR_INIT record,
50
 * followed by a number of other records, followed by a LOG_CURSOR_END record.
51
 * LOG_LINE_RESET records come in pairs.  The first is a LOG_LINE_RESET_B
52
 * record, and is the line before the change.  The second is LOG_LINE_RESET_F,
53
 * and is the line after the change.  Roll-back is done by backing up to the
54
 * first LOG_CURSOR_INIT record before a change.  Roll-forward is done in a
55
 * similar fashion.
56
 *
57
 * The 'U' command is implemented by rolling backward to a LOG_CURSOR_END
58
 * record for a line different from the current one.  It should be noted that
59
 * this means that a subsequent 'u' command will make a change based on the
60
 * new position of the log's cursor.  This is okay, and, in fact, historic vi
61
 * behaved that way.
62
 */
63
64
static int	log_cursor1(SCR *, int);
65
static void	log_err(SCR *, char *, int);
66
#if defined(DEBUG) && 0
67
static void	log_trace(SCR *, char *, recno_t, u_char *);
68
#endif
69
70
/* Try and restart the log on failure, i.e. if we run out of memory. */
71
#define	LOG_ERR {							\
72
	log_err(sp, __FILE__, __LINE__);				\
73
	return (1);							\
74
}
75
76
/*
77
 * log_init --
78
 *	Initialize the logging subsystem.
79
 *
80
 * PUBLIC: int log_init(SCR *, EXF *);
81
 */
82
int
83
log_init(SCR *sp, EXF *ep)
84
{
85
	/*
86
	 * !!!
87
	 * ep MAY NOT BE THE SAME AS sp->ep, DON'T USE THE LATTER.
88
	 *
89
	 * Initialize the buffer.  The logging subsystem has its own
90
	 * buffers because the global ones are almost by definition
91
	 * going to be in use when the log runs.
92
	 */
93
	ep->l_lp = NULL;
94
	ep->l_len = 0;
95
	ep->l_cursor.lno = 1;		/* XXX Any valid recno. */
96
	ep->l_cursor.cno = 0;
97
	ep->l_high = ep->l_cur = 1;
98
99
	ep->log = dbopen(NULL, O_CREAT | O_NONBLOCK | O_RDWR,
100
	    S_IRUSR | S_IWUSR, DB_RECNO, NULL);
101
	if (ep->log == NULL) {
102
		msgq(sp, M_SYSERR, "Log file");
103
		F_SET(ep, F_NOLOG);
104
		return (1);
105
	}
106
107
	return (0);
108
}
109
110
/*
111
 * log_end --
112
 *	Close the logging subsystem.
113
 *
114
 * PUBLIC: int log_end(SCR *, EXF *);
115
 */
116
int
117
log_end(SCR *sp, EXF *ep)
118
{
119
	/*
120
	 * !!!
121
	 * ep MAY NOT BE THE SAME AS sp->ep, DON'T USE THE LATTER.
122
	 */
123
	if (ep->log != NULL) {
124
		(void)(ep->log->close)(ep->log);
125
		ep->log = NULL;
126
	}
127
	free(ep->l_lp);
128
	ep->l_lp = NULL;
129
	ep->l_len = 0;
130
	ep->l_cursor.lno = 1;		/* XXX Any valid recno. */
131
	ep->l_cursor.cno = 0;
132
	ep->l_high = ep->l_cur = 1;
133
	return (0);
134
}
135
136
/*
137
 * log_cursor --
138
 *	Log the current cursor position, starting an event.
139
 *
140
 * PUBLIC: int log_cursor(SCR *);
141
 */
142
int
143
log_cursor(SCR *sp)
144
{
145
	EXF *ep;
146
147
	ep = sp->ep;
148
	if (F_ISSET(ep, F_NOLOG))
149
		return (0);
150
151
	/*
152
	 * If any changes were made since the last cursor init,
153
	 * put out the ending cursor record.
154
	 */
155
	if (ep->l_cursor.lno == OOBLNO) {
156
		ep->l_cursor.lno = sp->lno;
157
		ep->l_cursor.cno = sp->cno;
158
		return (log_cursor1(sp, LOG_CURSOR_END));
159
	}
160
	ep->l_cursor.lno = sp->lno;
161
	ep->l_cursor.cno = sp->cno;
162
	return (0);
163
}
164
165
/*
166
 * log_cursor1 --
167
 *	Actually push a cursor record out.
168
 */
169
static int
170
log_cursor1(SCR *sp, int type)
171
{
172
	DBT data, key;
173
	EXF *ep;
174
175
	ep = sp->ep;
176
	BINC_RET(sp, ep->l_lp, ep->l_len, sizeof(u_char) + sizeof(MARK));
177
	ep->l_lp[0] = type;
178
	memmove(ep->l_lp + sizeof(u_char), &ep->l_cursor, sizeof(MARK));
179
180
	key.data = &ep->l_cur;
181
	key.size = sizeof(recno_t);
182
	data.data = ep->l_lp;
183
	data.size = sizeof(u_char) + sizeof(MARK);
184
	if (ep->log->put(ep->log, &key, &data, 0) == -1)
185
		LOG_ERR;
186
187
#if defined(DEBUG) && 0
188
	TRACE(sp, "%lu: %s: %u/%u\n", ep->l_cur,
189
	    type == LOG_CURSOR_INIT ? "log_cursor_init" : "log_cursor_end",
190
	    sp->lno, sp->cno);
191
#endif
192
	/* Reset high water mark. */
193
	ep->l_high = ++ep->l_cur;
194
195
	return (0);
196
}
197
198
/*
199
 * log_line --
200
 *	Log a line change.
201
 *
202
 * PUBLIC: int log_line(SCR *, recno_t, u_int);
203
 */
204
int
205
log_line(SCR *sp, recno_t lno, u_int action)
206
{
207
	DBT data, key;
208
	EXF *ep;
209
	size_t len;
210
	char *lp;
211
212
	ep = sp->ep;
213
	if (F_ISSET(ep, F_NOLOG))
214
		return (0);
215
216
	/*
217
	 * XXX
218
	 *
219
	 * Kluge for vi.  Clear the EXF undo flag so that the
220
	 * next 'u' command does a roll-back, regardless.
221
	 */
222
	F_CLR(ep, F_UNDO);
223
224
	/* Put out one initial cursor record per set of changes. */
225
	if (ep->l_cursor.lno != OOBLNO) {
226
		if (log_cursor1(sp, LOG_CURSOR_INIT))
227
			return (1);
228
		ep->l_cursor.lno = OOBLNO;
229
	}
230
231
	/*
232
	 * Put out the changes.  If it's a LOG_LINE_RESET_B call, it's a
233
	 * special case, avoid the caches.  Also, if it fails and it's
234
	 * line 1, it just means that the user started with an empty file,
235
	 * so fake an empty length line.
236
	 */
237
	if (action == LOG_LINE_RESET_B) {
238
		if (db_get(sp, lno, DBG_NOCACHE, &lp, &len)) {
239
			if (lno != 1) {
240
				db_err(sp, lno);
241
				return (1);
242
			}
243
			len = 0;
244
			lp = "";
245
		}
246
	} else
247
		if (db_get(sp, lno, DBG_FATAL, &lp, &len))
248
			return (1);
249
	BINC_RET(sp,
250
	    ep->l_lp, ep->l_len, len + sizeof(u_char) + sizeof(recno_t));
251
	ep->l_lp[0] = action;
252
	memmove(ep->l_lp + sizeof(u_char), &lno, sizeof(recno_t));
253
	memmove(ep->l_lp + sizeof(u_char) + sizeof(recno_t), lp, len);
254
255
	key.data = &ep->l_cur;
256
	key.size = sizeof(recno_t);
257
	data.data = ep->l_lp;
258
	data.size = len + sizeof(u_char) + sizeof(recno_t);
259
	if (ep->log->put(ep->log, &key, &data, 0) == -1)
260
		LOG_ERR;
261
262
#if defined(DEBUG) && 0
263
	switch (action) {
264
	case LOG_LINE_APPEND:
265
		TRACE(sp, "%u: log_line: append: %lu {%u}\n",
266
		    ep->l_cur, lno, len);
267
		break;
268
	case LOG_LINE_DELETE:
269
		TRACE(sp, "%lu: log_line: delete: %lu {%u}\n",
270
		    ep->l_cur, lno, len);
271
		break;
272
	case LOG_LINE_INSERT:
273
		TRACE(sp, "%lu: log_line: insert: %lu {%u}\n",
274
		    ep->l_cur, lno, len);
275
		break;
276
	case LOG_LINE_RESET_F:
277
		TRACE(sp, "%lu: log_line: reset_f: %lu {%u}\n",
278
		    ep->l_cur, lno, len);
279
		break;
280
	case LOG_LINE_RESET_B:
281
		TRACE(sp, "%lu: log_line: reset_b: %lu {%u}\n",
282
		    ep->l_cur, lno, len);
283
		break;
284
	}
285
#endif
286
	/* Reset high water mark. */
287
	ep->l_high = ++ep->l_cur;
288
289
	return (0);
290
}
291
292
/*
293
 * log_mark --
294
 *	Log a mark position.  For the log to work, we assume that there
295
 *	aren't any operations that just put out a log record -- this
296
 *	would mean that undo operations would only reset marks, and not
297
 *	cause any other change.
298
 *
299
 * PUBLIC: int log_mark(SCR *, LMARK *);
300
 */
301
int
302
log_mark(SCR *sp, LMARK *lmp)
303
{
304
	DBT data, key;
305
	EXF *ep;
306
307
	ep = sp->ep;
308
	if (F_ISSET(ep, F_NOLOG))
309
		return (0);
310
311
	/* Put out one initial cursor record per set of changes. */
312
	if (ep->l_cursor.lno != OOBLNO) {
313
		if (log_cursor1(sp, LOG_CURSOR_INIT))
314
			return (1);
315
		ep->l_cursor.lno = OOBLNO;
316
	}
317
318
	BINC_RET(sp, ep->l_lp,
319
	    ep->l_len, sizeof(u_char) + sizeof(LMARK));
320
	ep->l_lp[0] = LOG_MARK;
321
	memmove(ep->l_lp + sizeof(u_char), lmp, sizeof(LMARK));
322
323
	key.data = &ep->l_cur;
324
	key.size = sizeof(recno_t);
325
	data.data = ep->l_lp;
326
	data.size = sizeof(u_char) + sizeof(LMARK);
327
	if (ep->log->put(ep->log, &key, &data, 0) == -1)
328
		LOG_ERR;
329
330
#if defined(DEBUG) && 0
331
	TRACE(sp, "%lu: mark %c: %lu/%u\n",
332
	    ep->l_cur, lmp->name, lmp->lno, lmp->cno);
333
#endif
334
	/* Reset high water mark. */
335
	ep->l_high = ++ep->l_cur;
336
	return (0);
337
}
338
339
/*
340
 * Log_backward --
341
 *	Roll the log backward one operation.
342
 *
343
 * PUBLIC: int log_backward(SCR *, MARK *);
344
 */
345
int
346
log_backward(SCR *sp, MARK *rp)
347
{
348
	DBT key, data;
349
	EXF *ep;
350
	LMARK lm;
351
	MARK m;
352
	recno_t lno;
353
	int didop;
354
	u_char *p;
355
356
	ep = sp->ep;
357
	if (F_ISSET(ep, F_NOLOG)) {
358
		msgq(sp, M_ERR,
359
		    "Logging not being performed, undo not possible");
360
		return (1);
361
	}
362
363
	if (ep->l_cur == 1) {
364
		msgq(sp, M_BERR, "No changes to undo");
365
		return (1);
366
	}
367
368
	F_SET(ep, F_NOLOG);		/* Turn off logging. */
369
370
	key.data = &ep->l_cur;		/* Initialize db request. */
371
	key.size = sizeof(recno_t);
372
	for (didop = 0;;) {
373
		--ep->l_cur;
374
		if (ep->log->get(ep->log, &key, &data, 0))
375
			LOG_ERR;
376
#if defined(DEBUG) && 0
377
		log_trace(sp, "log_backward", ep->l_cur, data.data);
378
#endif
379
		switch (*(p = (u_char *)data.data)) {
380
		case LOG_CURSOR_INIT:
381
			if (didop) {
382
				memmove(rp, p + sizeof(u_char), sizeof(MARK));
383
				F_CLR(ep, F_NOLOG);
384
				return (0);
385
			}
386
			break;
387
		case LOG_CURSOR_END:
388
			break;
389
		case LOG_LINE_APPEND:
390
		case LOG_LINE_INSERT:
391
			didop = 1;
392
			memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
393
			if (db_delete(sp, lno))
394
				goto err;
395
			++sp->rptlines[L_DELETED];
396
			break;
397
		case LOG_LINE_DELETE:
398
			didop = 1;
399
			memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
400
			if (db_insert(sp, lno, p + sizeof(u_char) +
401
			    sizeof(recno_t), data.size - sizeof(u_char) -
402
			    sizeof(recno_t)))
403
				goto err;
404
			++sp->rptlines[L_ADDED];
405
			break;
406
		case LOG_LINE_RESET_F:
407
			break;
408
		case LOG_LINE_RESET_B:
409
			didop = 1;
410
			memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
411
			if (db_set(sp, lno, p + sizeof(u_char) +
412
			    sizeof(recno_t), data.size - sizeof(u_char) -
413
			    sizeof(recno_t)))
414
				goto err;
415
			if (sp->rptlchange != lno) {
416
				sp->rptlchange = lno;
417
				++sp->rptlines[L_CHANGED];
418
			}
419
			break;
420
		case LOG_MARK:
421
			didop = 1;
422
			memmove(&lm, p + sizeof(u_char), sizeof(LMARK));
423
			m.lno = lm.lno;
424
			m.cno = lm.cno;
425
			if (mark_set(sp, lm.name, &m, 0))
426
				goto err;
427
			break;
428
		default:
429
			abort();
430
		}
431
	}
432
433
err:	F_CLR(ep, F_NOLOG);
434
	return (1);
435
}
436
437
/*
438
 * Log_setline --
439
 *	Reset the line to its original appearance.
440
 *
441
 * XXX
442
 * There's a bug in this code due to our not logging cursor movements
443
 * unless a change was made.  If you do a change, move off the line,
444
 * then move back on and do a 'U', the line will be restored to the way
445
 * it was before the original change.
446
 *
447
 * PUBLIC: int log_setline(SCR *);
448
 */
449
int
450
log_setline(SCR *sp)
451
{
452
	DBT key, data;
453
	EXF *ep;
454
	LMARK lm;
455
	MARK m;
456
	recno_t lno;
457
	u_char *p;
458
459
	ep = sp->ep;
460
	if (F_ISSET(ep, F_NOLOG)) {
461
		msgq(sp, M_ERR,
462
		    "Logging not being performed, undo not possible");
463
		return (1);
464
	}
465
466
	if (ep->l_cur == 1)
467
		return (1);
468
469
	F_SET(ep, F_NOLOG);		/* Turn off logging. */
470
471
	key.data = &ep->l_cur;		/* Initialize db request. */
472
	key.size = sizeof(recno_t);
473
474
	for (;;) {
475
		--ep->l_cur;
476
		if (ep->log->get(ep->log, &key, &data, 0))
477
			LOG_ERR;
478
#if defined(DEBUG) && 0
479
		log_trace(sp, "log_setline", ep->l_cur, data.data);
480
#endif
481
		switch (*(p = (u_char *)data.data)) {
482
		case LOG_CURSOR_INIT:
483
			memmove(&m, p + sizeof(u_char), sizeof(MARK));
484
			if (m.lno != sp->lno || ep->l_cur == 1) {
485
				F_CLR(ep, F_NOLOG);
486
				return (0);
487
			}
488
			break;
489
		case LOG_CURSOR_END:
490
			memmove(&m, p + sizeof(u_char), sizeof(MARK));
491
			if (m.lno != sp->lno) {
492
				++ep->l_cur;
493
				F_CLR(ep, F_NOLOG);
494
				return (0);
495
			}
496
			break;
497
		case LOG_LINE_APPEND:
498
		case LOG_LINE_INSERT:
499
		case LOG_LINE_DELETE:
500
		case LOG_LINE_RESET_F:
501
			break;
502
		case LOG_LINE_RESET_B:
503
			memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
504
			if (lno == sp->lno &&
505
			    db_set(sp, lno, p + sizeof(u_char) +
506
			    sizeof(recno_t), data.size - sizeof(u_char) -
507
			    sizeof(recno_t)))
508
				goto err;
509
			if (sp->rptlchange != lno) {
510
				sp->rptlchange = lno;
511
				++sp->rptlines[L_CHANGED];
512
			}
513
		case LOG_MARK:
514
			memmove(&lm, p + sizeof(u_char), sizeof(LMARK));
515
			m.lno = lm.lno;
516
			m.cno = lm.cno;
517
			if (mark_set(sp, lm.name, &m, 0))
518
				goto err;
519
			break;
520
		default:
521
			abort();
522
		}
523
	}
524
525
err:	F_CLR(ep, F_NOLOG);
526
	return (1);
527
}
528
529
/*
530
 * Log_forward --
531
 *	Roll the log forward one operation.
532
 *
533
 * PUBLIC: int log_forward(SCR *, MARK *);
534
 */
535
int
536
log_forward(SCR *sp, MARK *rp)
537
{
538
	DBT key, data;
539
	EXF *ep;
540
	LMARK lm;
541
	MARK m;
542
	recno_t lno;
543
	int didop;
544
	u_char *p;
545
546
	ep = sp->ep;
547
	if (F_ISSET(ep, F_NOLOG)) {
548
		msgq(sp, M_ERR,
549
	    "Logging not being performed, roll-forward not possible");
550
		return (1);
551
	}
552
553
	if (ep->l_cur == ep->l_high) {
554
		msgq(sp, M_BERR, "No changes to re-do");
555
		return (1);
556
	}
557
558
	F_SET(ep, F_NOLOG);		/* Turn off logging. */
559
560
	key.data = &ep->l_cur;		/* Initialize db request. */
561
	key.size = sizeof(recno_t);
562
	for (didop = 0;;) {
563
		++ep->l_cur;
564
		if (ep->log->get(ep->log, &key, &data, 0))
565
			LOG_ERR;
566
#if defined(DEBUG) && 0
567
		log_trace(sp, "log_forward", ep->l_cur, data.data);
568
#endif
569
		switch (*(p = (u_char *)data.data)) {
570
		case LOG_CURSOR_END:
571
			if (didop) {
572
				++ep->l_cur;
573
				memmove(rp, p + sizeof(u_char), sizeof(MARK));
574
				F_CLR(ep, F_NOLOG);
575
				return (0);
576
			}
577
			break;
578
		case LOG_CURSOR_INIT:
579
			break;
580
		case LOG_LINE_APPEND:
581
		case LOG_LINE_INSERT:
582
			didop = 1;
583
			memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
584
			if (db_insert(sp, lno, p + sizeof(u_char) +
585
			    sizeof(recno_t), data.size - sizeof(u_char) -
586
			    sizeof(recno_t)))
587
				goto err;
588
			++sp->rptlines[L_ADDED];
589
			break;
590
		case LOG_LINE_DELETE:
591
			didop = 1;
592
			memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
593
			if (db_delete(sp, lno))
594
				goto err;
595
			++sp->rptlines[L_DELETED];
596
			break;
597
		case LOG_LINE_RESET_B:
598
			break;
599
		case LOG_LINE_RESET_F:
600
			didop = 1;
601
			memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
602
			if (db_set(sp, lno, p + sizeof(u_char) +
603
			    sizeof(recno_t), data.size - sizeof(u_char) -
604
			    sizeof(recno_t)))
605
				goto err;
606
			if (sp->rptlchange != lno) {
607
				sp->rptlchange = lno;
608
				++sp->rptlines[L_CHANGED];
609
			}
610
			break;
611
		case LOG_MARK:
612
			didop = 1;
613
			memmove(&lm, p + sizeof(u_char), sizeof(LMARK));
614
			m.lno = lm.lno;
615
			m.cno = lm.cno;
616
			if (mark_set(sp, lm.name, &m, 0))
617
				goto err;
618
			break;
619
		default:
620
			abort();
621
		}
622
	}
623
624
err:	F_CLR(ep, F_NOLOG);
625
	return (1);
626
}
627
628
/*
629
 * log_err --
630
 *	Try and restart the log on failure, i.e. if we run out of memory.
631
 */
632
static void
633
log_err(SCR *sp, char *file, int line)
634
{
635
	EXF *ep;
636
637
	msgq(sp, M_SYSERR, "%s/%d: log put error", basename(file), line);
638
	ep = sp->ep;
639
	(void)ep->log->close(ep->log);
640
	if (!log_init(sp, ep))
641
		msgq(sp, M_ERR, "Log restarted");
642
}
643
644
#if defined(DEBUG) && 0
645
static void
646
log_trace(SCR *sp, char *msg, recno_t rno, u_char *p)
647
{
648
	LMARK lm;
649
	MARK m;
650
	recno_t lno;
651
652
	switch (*p) {
653
	case LOG_CURSOR_INIT:
654
		memmove(&m, p + sizeof(u_char), sizeof(MARK));
655
		TRACE(sp, "%lu: %s:  C_INIT: %u/%u\n", rno, msg, m.lno, m.cno);
656
		break;
657
	case LOG_CURSOR_END:
658
		memmove(&m, p + sizeof(u_char), sizeof(MARK));
659
		TRACE(sp, "%lu: %s:   C_END: %u/%u\n", rno, msg, m.lno, m.cno);
660
		break;
661
	case LOG_LINE_APPEND:
662
		memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
663
		TRACE(sp, "%lu: %s:  APPEND: %lu\n", rno, msg, lno);
664
		break;
665
	case LOG_LINE_INSERT:
666
		memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
667
		TRACE(sp, "%lu: %s:  INSERT: %lu\n", rno, msg, lno);
668
		break;
669
	case LOG_LINE_DELETE:
670
		memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
671
		TRACE(sp, "%lu: %s:  DELETE: %lu\n", rno, msg, lno);
672
		break;
673
	case LOG_LINE_RESET_F:
674
		memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
675
		TRACE(sp, "%lu: %s: RESET_F: %lu\n", rno, msg, lno);
676
		break;
677
	case LOG_LINE_RESET_B:
678
		memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
679
		TRACE(sp, "%lu: %s: RESET_B: %lu\n", rno, msg, lno);
680
		break;
681
	case LOG_MARK:
682
		memmove(&lm, p + sizeof(u_char), sizeof(LMARK));
683
		TRACE(sp,
684
		    "%lu: %s:    MARK: %u/%u\n", rno, msg, lm.lno, lm.cno);
685
		break;
686
	default:
687
		abort();
688
	}
689
}
690
#endif