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