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