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 16static 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 73static int log_cursor1 __P((SCR *, int)); 74static void log_err __P((SCR *, const char *, int)); 75#if defined(LOGDEBUG) && defined(TRACE) 76static 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 */ 88typedef 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 */ 100int 101log_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 */ 137int 138log_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 */ 166int 167log_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 */ 196static int 197log_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 */ 244int 245log_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 */ 362int 363log_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 */ 409int 410log_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 504err: 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 */ 521int 522log_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 604err: 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 */ 615int 616log_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 710err: 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 */ 719static void 720log_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) 732static void 733log_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