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