1 /*-
2 * Copyright (c) 1996, 2020 Oracle and/or its affiliates. All rights reserved.
3 *
4 * See the file LICENSE for license information.
5 *
6 * $Id$
7 */
8
9 #include "db_config.h"
10
11 #include "db_int.h"
12 #include "dbinc/db_page.h"
13 #include "dbinc/db_am.h"
14 #include "dbinc/lock.h"
15 #include "dbinc/mp.h"
16 #include "dbinc/txn.h"
17
18 #if defined(HAVE_ERROR_HISTORY)
19 static void __db_thread_once_func __P((void));
20 static void __db_deferred_free __P((void *));
21 #endif
22
23 /*
24 * __db_fchk --
25 * General flags checking routine.
26 *
27 * PUBLIC: int __db_fchk __P((ENV *, const char *, u_int32_t, u_int32_t));
28 */
29 int
__db_fchk(env,name,flags,ok_flags)30 __db_fchk(env, name, flags, ok_flags)
31 ENV *env;
32 const char *name;
33 u_int32_t flags, ok_flags;
34 {
35 return (LF_ISSET(~ok_flags) ? __db_ferr(env, name, 0) : 0);
36 }
37
38 /*
39 * __db_fcchk --
40 * General combination flags checking routine.
41 *
42 * PUBLIC: int __db_fcchk
43 * PUBLIC: __P((ENV *, const char *, u_int32_t, u_int32_t, u_int32_t));
44 */
45 int
__db_fcchk(env,name,flags,flag1,flag2)46 __db_fcchk(env, name, flags, flag1, flag2)
47 ENV *env;
48 const char *name;
49 u_int32_t flags, flag1, flag2;
50 {
51 return (LF_ISSET(flag1) &&
52 LF_ISSET(flag2) ? __db_ferr(env, name, 1) : 0);
53 }
54
55 /*
56 * __db_ferr --
57 * Common flag errors.
58 *
59 * PUBLIC: int __db_ferr __P((const ENV *, const char *, int));
60 */
61 int
__db_ferr(env,name,iscombo)62 __db_ferr(env, name, iscombo)
63 const ENV *env;
64 const char *name;
65 int iscombo;
66 {
67 int ret;
68
69 ret = USR_ERR(env, EINVAL);
70 if (iscombo)
71 __db_errx(env, DB_STR_A("0054",
72 "illegal flag combination specified to %s", "%s"), name);
73 else
74 __db_errx(env, DB_STR_A("0055",
75 "illegal flag specified to %s", "%s"), name);
76
77 return (ret);
78 }
79
80 /*
81 * __db_fnl --
82 * Common flag-needs-locking message.
83 *
84 * PUBLIC: int __db_fnl __P((const ENV *, const char *));
85 */
86 int
__db_fnl(env,name)87 __db_fnl(env, name)
88 const ENV *env;
89 const char *name;
90 {
91 int ret;
92
93 ret = USR_ERR(env, EINVAL);
94 __db_errx(env, DB_STR_A("0056",
95 "%s: DB_READ_COMMITTED, DB_READ_UNCOMMITTED and DB_RMW require locking",
96 "%s"), name);
97 return (ret);
98 }
99
100 /*
101 * __db_pgerr --
102 * Error when unable to retrieve a specified page.
103 *
104 * PUBLIC: int __db_pgerr __P((DB *, db_pgno_t, int));
105 */
106 int
__db_pgerr(dbp,pgno,errval)107 __db_pgerr(dbp, pgno, errval)
108 DB *dbp;
109 db_pgno_t pgno;
110 int errval;
111 {
112 /*
113 * Three things are certain:
114 * Death, taxes, and lost data.
115 * Guess which has occurred.
116 */
117 __db_errx(dbp->env, DB_STR_A("0057",
118 "unable to create/retrieve page %lu", "%lu"), (u_long)pgno);
119 return (__env_panic(dbp->env, errval));
120 }
121
122 /*
123 * __db_pgfmt --
124 * Error when a page has the wrong format.
125 *
126 * PUBLIC: int __db_pgfmt __P((ENV *, db_pgno_t));
127 */
128 int
__db_pgfmt(env,pgno)129 __db_pgfmt(env, pgno)
130 ENV *env;
131 db_pgno_t pgno;
132 {
133 __db_errx(env, DB_STR_A("0058",
134 "page %lu: illegal page type or format", "%lu"), (u_long)pgno);
135 return (__env_panic(env, EINVAL));
136 }
137
138 #ifdef DIAGNOSTIC
139 /*
140 * __db_assert --
141 * Error when an assertion fails. Only checked if #DIAGNOSTIC defined.
142 *
143 * PUBLIC: #ifdef DIAGNOSTIC
144 * PUBLIC: void __db_assert __P((ENV *, const char *, const char *, int));
145 * PUBLIC: #endif
146 */
147 void
__db_assert(env,e,file,line)148 __db_assert(env, e, file, line)
149 ENV *env;
150 const char *e, *file;
151 int line;
152 {
153 if (DB_GLOBAL(j_assert) != NULL)
154 DB_GLOBAL(j_assert)(e, file, line);
155 else {
156 /*
157 * If a panic has preceded this assertion failure, print that
158 * message as well -- it might be relevant.
159 */
160 #ifdef HAVE_FAILCHK_BROADCAST
161 if (PANIC_ISSET(env)) {
162 REGENV *renv;
163 renv = (env == NULL || env->reginfo == NULL) ?
164 NULL : env->reginfo->primary;
165 __db_errx(env, DB_STR_A("0242",
166 "assert failure (%s/%d: %s) after panic %s",
167 "%s %d %s %s"), file, line, e,
168 renv == NULL ? "" : renv->failure_symptom);
169 } else
170 #endif
171 __db_errx(env, DB_STR_A("0059",
172 "assert failure: %s/%d: \"%s\"",
173 "%s %d %s"), file, line, e);
174
175 __os_abort(env);
176 /* NOTREACHED */
177 }
178 }
179 #endif
180
181 /*
182 * __env_panic_event -
183 * Notify the application of a db_register, failchk, or generic panic.
184 *
185 * PUBLIC: void __env_panic_event __P((ENV *, int));
186 */
187 void
__env_panic_event(env,errval)188 __env_panic_event(env, errval)
189 ENV *env;
190 int errval;
191 {
192 DB_ENV *dbenv;
193 REGENV *renv;
194 u_int32_t event;
195 void *info;
196 DB_EVENT_FAILCHK_INFO failinfo;
197
198 dbenv = env->dbenv;
199 info = &errval;
200 if (dbenv->db_paniccall != NULL) /* Deprecated */
201 dbenv->db_paniccall(dbenv, errval);
202 /*
203 * We check for DB_EVENT_FAILCHK and DB_EVENT_REG_PANIC first because
204 * they are not set by themselves. If one of those is set, it means that
205 * this panic is somewhat an expected consequence of a previous failure.
206 */
207 renv = (env->reginfo == NULL) ? NULL : env->reginfo->primary;
208 if (renv != NULL && renv->failure_panic) {
209 event = DB_EVENT_FAILCHK_PANIC;
210 failinfo.error = errval;
211 (void)strncpy(failinfo.symptom,
212 renv->failure_symptom, sizeof(failinfo.symptom));
213 failinfo.symptom[sizeof(failinfo.symptom) - 1] = '\0';
214 info = &failinfo;
215 } else if (renv != NULL && renv->reg_panic)
216 event = DB_EVENT_REG_PANIC;
217 else
218 event = DB_EVENT_PANIC;
219 DB_EVENT(env, event, info);
220 }
221
222 /*
223 * __env_panic_msg --
224 * Report that we noticed a panic which had been set somewhere else.
225 *
226 * PUBLIC: int __env_panic_msg __P((ENV *));
227 */
228 int
__env_panic_msg(env)229 __env_panic_msg(env)
230 ENV *env;
231 {
232 int ret;
233
234 ret = DB_RUNRECOVERY;
235 /* Make a note saying where this panic was detected. */
236 (void)USR_ERR(env, ret);
237
238 __db_errx(env, DB_STR("0060",
239 "PANIC: fatal region error detected; run recovery"));
240
241 __env_panic_event(env, ret);
242
243 return (ret);
244 }
245
246 /*
247 * __env_panic --
248 * Lock out the database environment due to unrecoverable error.
249 *
250 * PUBLIC: int __env_panic __P((ENV *, int));
251 */
252 int
__env_panic(env,errval)253 __env_panic(env, errval)
254 ENV *env;
255 int errval;
256 {
257 if (env != NULL) {
258 __env_panic_set(env, 1);
259
260 if (errval != DB_RUNRECOVERY)
261 __db_err(env, errval, DB_STR("0061", "PANIC"));
262
263 __env_panic_event(env, errval);
264 }
265
266 #if defined(DIAGNOSTIC) && !defined(CONFIG_TEST)
267 /*
268 * We want a stack trace of how this could possibly happen.
269 *
270 * Don't drop core if it's the test suite -- it's reasonable for the
271 * test suite to check to make sure that DB_RUNRECOVERY is returned
272 * under certain conditions.
273 */
274 __os_abort(env);
275 /* NOTREACHED */
276 #endif
277
278 /*
279 * Chaos reigns within.
280 * Reflect, repent, and reboot.
281 * Order shall return.
282 */
283 return (DB_RUNRECOVERY);
284 }
285
286 /*
287 * db_strerror --
288 * ANSI C strerror(3) for DB.
289 *
290 * EXTERN: char *db_strerror __P((int));
291 */
292 char *
db_strerror(error)293 db_strerror(error)
294 int error;
295 {
296 char *p;
297
298 if (error == 0)
299 return (DB_STR("0062", "Successful return: 0"));
300 if (error > 0) {
301 if ((p = strerror(error)) != NULL)
302 return (p);
303 return (__db_unknown_error(error));
304 }
305
306 /*
307 * !!!
308 * The Tcl API requires that some of these return strings be compared
309 * against strings stored in application scripts. So, any of these
310 * errors that do not invariably result in a Tcl exception may not be
311 * altered.
312 */
313 switch (error) {
314 case DB_BUFFER_SMALL:
315 return (DB_STR("0063",
316 "DB_BUFFER_SMALL: User memory too small for return value"));
317 case DB_DONOTINDEX:
318 return (DB_STR("0064",
319 "DB_DONOTINDEX: Secondary index callback returns null"));
320 case DB_FOREIGN_CONFLICT:
321 return (DB_STR("0065",
322 "DB_FOREIGN_CONFLICT: A foreign database constraint has been violated"));
323 case DB_HEAP_FULL:
324 return (DB_STR("0208","DB_HEAP_FULL: no free space in db"));
325 case DB_KEYEMPTY:
326 return (DB_STR("0066",
327 "DB_KEYEMPTY: Non-existent key/data pair"));
328 case DB_KEYEXIST:
329 return (DB_STR("0067",
330 "DB_KEYEXIST: Key/data pair already exists"));
331 case DB_LOCK_DEADLOCK:
332 return (DB_STR("0068",
333 "DB_LOCK_DEADLOCK: Locker killed to resolve a deadlock"));
334 case DB_LOCK_NOTGRANTED:
335 return (DB_STR("0069", "DB_LOCK_NOTGRANTED: Lock not granted"));
336 case DB_LOG_BUFFER_FULL:
337 return (DB_STR("0070",
338 "DB_LOG_BUFFER_FULL: In-memory log buffer is full"));
339 case DB_LOG_VERIFY_BAD:
340 return (DB_STR("0071",
341 "DB_LOG_VERIFY_BAD: Log verification failed"));
342 case DB_META_CHKSUM_FAIL:
343 return (DB_STR("0247",
344 "DB_META_CHKSUM_FAIL: Checksum mismatch detected on a database metadata page"));
345 case DB_NOSERVER:
346 return (DB_STR("3655",
347 "DB_NOSERVER: No message dispatch call-back function has been configured"));
348 case DB_NOTFOUND:
349 return (DB_STR("0073",
350 "DB_NOTFOUND: No matching key/data pair found"));
351 case DB_OLD_VERSION:
352 return (DB_STR("0074",
353 "DB_OLDVERSION: Database requires a version upgrade"));
354 case DB_PAGE_NOTFOUND:
355 return (DB_STR("0075",
356 "DB_PAGE_NOTFOUND: Requested page not found"));
357 case DB_REP_DUPMASTER:
358 return (DB_STR("0076",
359 "DB_REP_DUPMASTER: A second master site appeared"));
360 case DB_REP_HANDLE_DEAD:
361 return (DB_STR("0077",
362 "DB_REP_HANDLE_DEAD: Handle is no longer valid"));
363 case DB_REP_HOLDELECTION:
364 return (DB_STR("0078",
365 "DB_REP_HOLDELECTION: Need to hold an election"));
366 case DB_REP_IGNORE:
367 return (DB_STR("0079",
368 "DB_REP_IGNORE: Replication record/operation ignored"));
369 case DB_REP_INELECT:
370 return (DB_STR("0252",
371 "DB_REP_INELECT: Replication election in progress"));
372 case DB_REP_ISPERM:
373 return (DB_STR("0080",
374 "DB_REP_ISPERM: Permanent record written"));
375 case DB_REP_JOIN_FAILURE:
376 return (DB_STR("0081",
377 "DB_REP_JOIN_FAILURE: Unable to join replication group"));
378 case DB_REP_LEASE_EXPIRED:
379 return (DB_STR("0082",
380 "DB_REP_LEASE_EXPIRED: Replication leases have expired"));
381 case DB_REP_LOCKOUT:
382 return (DB_STR("0083",
383 "DB_REP_LOCKOUT: Waiting for replication recovery to complete"));
384 case DB_REP_NEWSITE:
385 return (DB_STR("0084",
386 "DB_REP_NEWSITE: A new site has entered the system"));
387 case DB_REP_NOTPERM:
388 return (DB_STR("0085",
389 "DB_REP_NOTPERM: Permanent log record not written"));
390 case DB_REP_UNAVAIL:
391 return (DB_STR("0086",
392 "DB_REP_UNAVAIL: Too few remote sites to complete operation"));
393 case DB_REP_WOULDROLLBACK: /* Undocumented; C API only. */
394 return (DB_STR("0207",
395 "DB_REP_WOULDROLLBACK: Client data has diverged"));
396 case DB_RUNRECOVERY:
397 return (DB_STR("0087",
398 "DB_RUNRECOVERY: Fatal error, run database recovery"));
399 case DB_SECONDARY_BAD:
400 return (DB_STR("0088",
401 "DB_SECONDARY_BAD: Secondary index inconsistent with primary"));
402 case DB_SLICE_CORRUPT:
403 return (DB_STR("0251",
404 "DB_SLICE_CORRUPT: One or more slices of this environment are malformed"));
405 case DB_TIMEOUT:
406 return (DB_STR("0089", "DB_TIMEOUT: Operation timed out"));
407 case DB_VERIFY_BAD:
408 return (DB_STR("0090",
409 "DB_VERIFY_BAD: Database verification failed"));
410 case DB_VERSION_MISMATCH:
411 return (DB_STR("0091",
412 "DB_VERSION_MISMATCH: Database environment version mismatch"));
413 case DB_SYSTEM_MEM_MISSING:
414 return (DB_STR("5509",
415 "DB_SYSTEM_MEM_MISSING: A required shared memory segment was not found"));
416 default:
417 break;
418 }
419
420 return (__db_unknown_error(error));
421 }
422
423 /*
424 * __db_unknown_error --
425 * Format an unknown error value into a static buffer.
426 *
427 * PUBLIC: char *__db_unknown_error __P((int));
428 */
429 char *
__db_unknown_error(error)430 __db_unknown_error(error)
431 int error;
432 {
433 /*
434 * !!!
435 * Room for a 64-bit number + slop. This buffer is only used
436 * if we're given an unknown error number, which should never
437 * happen.
438 *
439 * We're no longer thread-safe if it does happen, but the worst
440 * result is a corrupted error string because there will always
441 * be a trailing nul byte since the error buffer is nul filled
442 * and longer than any error message.
443 */
444 (void)snprintf(DB_GLOBAL(error_buf),
445 sizeof(DB_GLOBAL(error_buf)), DB_STR_A("0092",
446 "Unknown error: %d", "%d"), error);
447 return (DB_GLOBAL(error_buf));
448 }
449
450 /*
451 * __db_syserr --
452 * Standard error routine.
453 *
454 * PUBLIC: void __db_syserr __P((const ENV *, int, const char *, ...))
455 * PUBLIC: __attribute__ ((__format__ (__printf__, 3, 4)));
456 */
457 void
__db_syserr(const ENV * env,int error,const char * fmt,...)458 __db_syserr(const ENV *env, int error, const char *fmt, ...)
459 {
460 DB_ENV *dbenv;
461
462 dbenv = env == NULL ? NULL : env->dbenv;
463 if (env != NULL)
464 (void)USR_ERR(env, error);
465
466 /*
467 * The same as DB->err, except we don't default to writing to stderr
468 * after any output channel has been configured, and we use a system-
469 * specific function to translate errors to strings.
470 */
471 DB_REAL_ERR(dbenv,
472 error, error == 0 ? DB_ERROR_NOT_SET : DB_ERROR_SYSTEM, 0, fmt);
473 }
474
475 /*
476 * __db_err --
477 * Standard error routine with an error code.
478 *
479 * PUBLIC: void __db_err __P((const ENV *, int, const char *, ...))
480 * PUBLIC: __attribute__ ((__format__ (__printf__, 3, 4)));
481 */
482 void
__db_err(const ENV * env,int error,const char * fmt,...)483 __db_err(const ENV *env, int error, const char *fmt, ...)
484 {
485 DB_ENV *dbenv;
486
487 dbenv = env == NULL ? NULL : env->dbenv;
488
489 /* (If no deferred messages yet, at least?) add this calls' info.
490 (void)USR_ERR(env, error);
491 */
492
493 /*
494 * The same as DB->err, except we don't default to writing to stderr
495 * once an output channel has been configured.
496 */
497 DB_REAL_ERR(dbenv, error, DB_ERROR_SET, 0, fmt);
498 }
499
500 /*
501 * __db_errx --
502 * Standard error routine without any error code.
503 *
504 * PUBLIC: void __db_errx __P((const ENV *, const char *, ...))
505 * PUBLIC: __attribute__ ((__format__ (__printf__, 2, 3)));
506 */
507 void
__db_errx(const ENV * env,const char * fmt,...)508 __db_errx(const ENV *env, const char *fmt, ...)
509 {
510 DB_ENV *dbenv;
511
512 dbenv = env == NULL ? NULL : env->dbenv;
513
514 /*
515 * The same as DB->errx, except we don't default to writing to stderr
516 * once an output channel has been configured.
517 */
518 DB_REAL_ERR(dbenv, 0, DB_ERROR_NOT_SET, 0, fmt);
519 }
520
521 /*
522 * __db_errcall --
523 * Do the error message work for callback functions.
524 *
525 * PUBLIC: void __db_errcall
526 * PUBLIC: __P((const DB_ENV *, int, db_error_set_t, const char *, va_list));
527 */
528 void
__db_errcall(dbenv,error,error_set,fmt,ap)529 __db_errcall(dbenv, error, error_set, fmt, ap)
530 const DB_ENV *dbenv;
531 int error;
532 db_error_set_t error_set;
533 const char *fmt;
534 va_list ap;
535 {
536 char *end, *p;
537 char buf[2048 + DB_ERROR_HISTORY_SIZE];
538 char sysbuf[1024];
539 #ifdef HAVE_ERROR_HISTORY
540 DB_MSGBUF *deferred_mb;
541 ptrdiff_t len;
542 #endif
543
544 p = buf;
545 /* Reserve 1 byte at the end for '\0'. */
546 end = buf + sizeof(buf) - 1;
547 if (fmt != NULL)
548 p += vsnprintf(buf, sizeof(buf), fmt, ap);
549
550 if (error_set != DB_ERROR_NOT_SET)
551 p += snprintf(p, (size_t)(end - p), ": %s",
552 error_set == DB_ERROR_SET ? db_strerror(error) :
553 __os_strerror(error, sysbuf, sizeof(sysbuf)));
554
555 #ifdef HAVE_ERROR_HISTORY
556 /*
557 * Append any messages (e.g., diagnostics) stashed away in the deferred
558 * msgbuf. Strncpy() can't be trusted to append '\0', do it "manually".
559 */
560 if ((deferred_mb = __db_deferred_get()) != NULL &&
561 (len = deferred_mb->cur - deferred_mb->buf) != 0) {
562 p += snprintf(p,
563 (size_t)(end - p), "\nErrors during this API call: ");
564 if (len > (end - p))
565 len = end - p;
566 if (len != 0) {
567 memmove(p, deferred_mb->buf, (size_t)len);
568 p[len] = '\0';
569 }
570 }
571 #endif
572
573 dbenv->db_errcall(dbenv, dbenv->db_errpfx, buf);
574 }
575
576 /*
577 * __db_errfile --
578 * Do the error message work for FILE *s. Combine the messages into a
579 * single fprintf() call, to avoid interspersed output when there are
580 * multiple active threads.
581 *
582 * Display a ": " after the dbenv prefix, if it has one.
583 * Display a ": " before the error message string, if it error was set.
584 *
585 * PUBLIC: void __db_errfile
586 * PUBLIC: __P((const DB_ENV *, int, db_error_set_t, const char *, va_list));
587 */
588 void
__db_errfile(dbenv,error,error_set,fmt,ap)589 __db_errfile(dbenv, error, error_set, fmt, ap)
590 const DB_ENV *dbenv;
591 int error;
592 db_error_set_t error_set;
593 const char *fmt;
594 va_list ap;
595 {
596 FILE *fp;
597 char *defintro, *defmsgs, *error_str, *prefix, *sep1, *sep2;
598 char sysbuf[200];
599 char prefix_buf[200];
600 char full_fmt[4096];
601 #ifdef HAVE_ERROR_HISTORY
602 DB_MSGBUF *deferred_mb;
603 size_t room;
604 #endif
605
606 prefix = sep1 = sep2 = error_str = "";
607 fp = dbenv == NULL ||
608 dbenv->db_errfile == NULL ? stderr : dbenv->db_errfile;
609 if (fmt == NULL)
610 fmt = "";
611
612 if (dbenv != NULL && dbenv->db_errpfx != NULL) {
613 /*
614 * Double each '%' in user-defined prefix so that
615 * we can get the right output with printf.
616 */
617 prefix = __db_fmt_quote(prefix_buf,
618 sizeof(prefix_buf), dbenv->db_errpfx);
619 sep1 = ": ";
620 }
621 switch (error_set) {
622 case DB_ERROR_NOT_SET:
623 break;
624 case DB_ERROR_SET:
625 error_str = db_strerror(error);
626 sep2 = ": ";
627 break;
628 case DB_ERROR_SYSTEM:
629 error_str = __os_strerror(error, sysbuf, sizeof(sysbuf));
630 sep2 = ": ";
631 break;
632 }
633 #ifdef HAVE_ERROR_HISTORY
634 if ((deferred_mb = __db_deferred_get()) != NULL &&
635 deferred_mb->cur != deferred_mb->buf) {
636 defmsgs =
637 __db_fmt_quote(deferred_mb->buf, deferred_mb->len, NULL);
638 defintro = "\nErrors during this API call: ";
639 /*
640 * If there are more deferred messages than will be displayed
641 * change the introductory message to warn of the truncation.
642 */
643 room = sizeof(full_fmt) - (strlen(sep1) +
644 strlen(fmt) + strlen(sep2) + strlen(error_str));
645 if (deferred_mb->len + strlen(defintro) > room) {
646 defintro =
647 "\nFirst recorded errors during this API call: ";
648 memmove(defmsgs + room - 4, "...\n", 4);
649 }
650
651 } else
652 #endif
653 defmsgs = defintro = "";
654 (void)snprintf(full_fmt, sizeof(full_fmt), "%s%s%s%s%s%s%s\n", prefix,
655 sep1, fmt, sep2, error_str, defintro, defmsgs);
656 (void)vfprintf(fp, full_fmt, ap);
657 (void)fflush(fp);
658 }
659
660 /*
661 * __db_msgadd --
662 * Aggregate a set of strings into a buffer for the callback API.
663 *
664 * PUBLIC: void __db_msgadd __P((const ENV *, DB_MSGBUF *, const char *, ...))
665 * PUBLIC: __attribute__ ((__format__ (__printf__, 3, 4)));
666 */
667 void
__db_msgadd(const ENV * env,DB_MSGBUF * mbp,const char * fmt,...)668 __db_msgadd(const ENV *env, DB_MSGBUF *mbp, const char *fmt, ...)
669 {
670 va_list ap;
671
672 va_start(ap, fmt);
673 __db_msgadd_ap(env, mbp, fmt, ap);
674 va_end(ap);
675 }
676
677 /*
678 * __db_msgadd_ap --
679 * Aggregate a set of strings into a buffer for the callback API.
680 *
681 * PUBLIC: void __db_msgadd_ap
682 * PUBLIC: __P((const ENV *, DB_MSGBUF *, const char *, va_list));
683 */
684 void
__db_msgadd_ap(env,mbp,fmt,ap)685 __db_msgadd_ap(env, mbp, fmt, ap)
686 const ENV *env;
687 DB_MSGBUF *mbp;
688 const char *fmt;
689 va_list ap;
690 {
691 size_t len, nlen, olen;
692 char buf[2048];
693
694 len = (size_t)vsnprintf(buf, sizeof(buf), fmt, ap);
695
696 /*
697 * There's a heap buffer in the ENV handle we use to aggregate the
698 * message chunks. We maintain a pointer to the buffer, the next slot
699 * to be filled in in the buffer, and a total buffer length.
700 */
701 olen = (size_t)(mbp->cur - mbp->buf);
702 if (olen + len >= mbp->len) {
703 /* Don't write too much for preallocated DB_MSGBUFs. */
704 if (F_ISSET(mbp, DB_MSGBUF_PREALLOCATED)) {
705 memset(mbp->cur, '*', mbp->len - olen);
706 mbp->cur = mbp->buf + mbp->len;
707 return;
708 }
709 nlen = mbp->len + len + (env == NULL ? 8192 : 256);
710 if (__os_realloc(env, nlen, &mbp->buf))
711 return;
712 mbp->len = nlen;
713 mbp->cur = mbp->buf + olen;
714 }
715
716 memcpy(mbp->cur, buf, len + 1);
717 mbp->cur += len;
718 }
719
720 /*
721 * __db_msg --
722 * Standard DB stat message routine.
723 *
724 * PUBLIC: void __db_msg __P((const ENV *, const char *, ...))
725 * PUBLIC: __attribute__ ((__format__ (__printf__, 2, 3)));
726 */
727 void
__db_msg(const ENV * env,const char * fmt,...)728 __db_msg(const ENV *env, const char *fmt, ...)
729 {
730 DB_ENV *dbenv;
731
732 dbenv = env == NULL ? NULL : env->dbenv;
733
734 DB_REAL_MSG(dbenv, fmt);
735 }
736
737 /*
738 * __db_debug_msg --
739 * Save a message to be displayed only if this API call returns an error.
740 * The message is discarded if this API call succeeds.
741 *
742 * PUBLIC: void __db_debug_msg __P((const ENV *, const char *, ...));
743 */
744 void
__db_debug_msg(const ENV * env,const char * fmt,...)745 __db_debug_msg(const ENV *env, const char *fmt, ...)
746 {
747 #ifdef HAVE_ERROR_HISTORY
748 DB_MSGBUF *mb;
749 va_list ap;
750
751 if (env == NULL || (mb = __db_deferred_get()) == NULL)
752 return;
753
754 va_start(ap, fmt);
755 __db_msgadd_ap(env, mb, fmt, ap);
756 va_end(ap);
757 #endif
758 COMPQUIET(env, NULL);
759 COMPQUIET(fmt, NULL);
760 }
761
762 /*
763 * __db_repmsg --
764 * Replication system message routine.
765 *
766 * PUBLIC: void __db_repmsg __P((const ENV *, const char *, ...))
767 * PUBLIC: __attribute__ ((__format__ (__printf__, 2, 3)));
768 */
769 void
__db_repmsg(const ENV * env,const char * fmt,...)770 __db_repmsg(const ENV *env, const char *fmt, ...)
771 {
772 va_list ap;
773 char buf[2048];
774
775 va_start(ap, fmt);
776 (void)vsnprintf(buf, sizeof(buf), fmt, ap);
777 __rep_msg(env, buf);
778 va_end(ap);
779 }
780
781 /*
782 * __db_msgcall --
783 * Do the non-error message work for callback functions.
784 *
785 * PUBLIC: void __db_msgcall
786 * PUBLIC: __P((const DB_ENV *, const char *, va_list));
787 */
788 void
__db_msgcall(dbenv,fmt,ap)789 __db_msgcall(dbenv, fmt, ap)
790 const DB_ENV *dbenv;
791 const char *fmt;
792 va_list ap;
793 {
794 char buf[2048];
795
796 (void)vsnprintf(buf, sizeof(buf), fmt, ap);
797 dbenv->db_msgcall(dbenv, dbenv->db_msgpfx, buf);
798 }
799
800 /*
801 * __db_msgfile --
802 * Do the non-error message work for FILE *s. Combine the messages into
803 * a single fprintf() call, to avoid interspersed output when there are
804 * multiple active threads.
805 *
806 * Display a ": " after the dbenv prefix, if it has one.
807 *
808 * PUBLIC: void __db_msgfile
809 * PUBLIC: __P((const DB_ENV *, const char *, va_list));
810 */
811 void
__db_msgfile(dbenv,fmt,ap)812 __db_msgfile(dbenv, fmt, ap)
813 const DB_ENV *dbenv;
814 const char *fmt;
815 va_list ap;
816 {
817 FILE *fp;
818 char *prefix, *sep;
819 char prefix_buf[200];
820 char full_fmt[4096];
821
822 prefix = sep = "";
823 fp = dbenv == NULL ||
824 dbenv->db_msgfile == NULL ? stdout : dbenv->db_msgfile;
825
826 if (dbenv != NULL && dbenv->db_msgpfx != NULL) {
827 /*
828 * Double each '%' in user-defined prefix so that
829 * we can get the right output with printf.
830 */
831 prefix = __db_fmt_quote(prefix_buf,
832 sizeof(prefix_buf), dbenv->db_msgpfx);
833 sep = ": ";
834 }
835
836 (void)snprintf(full_fmt, sizeof(full_fmt), "%s%s%s\n",
837 prefix, sep, fmt);
838 (void)vfprintf(fp, full_fmt, ap);
839 (void)fflush(fp);
840 }
841
842 /*
843 * __db_unknown_flag -- report internal error
844 *
845 * PUBLIC: int __db_unknown_flag __P((ENV *, char *, u_int32_t));
846 */
847 int
__db_unknown_flag(env,routine,flag)848 __db_unknown_flag(env, routine, flag)
849 ENV *env;
850 char *routine;
851 u_int32_t flag;
852 {
853 int ret;
854
855 ret = USR_ERR(env, EINVAL);
856 __db_errx(env, DB_STR_A("0093", "%s: Unknown flag: %#x", "%s %#x"),
857 routine, (u_int)flag);
858
859 #ifdef DIAGNOSTIC
860 __os_abort(env);
861 /* NOTREACHED */
862 #endif
863 return (ret);
864 }
865
866 /*
867 * __db_unknown_type -- report internal database type error
868 *
869 * PUBLIC: int __db_unknown_type __P((ENV *, char *, DBTYPE));
870 */
871 int
__db_unknown_type(env,routine,type)872 __db_unknown_type(env, routine, type)
873 ENV *env;
874 char *routine;
875 DBTYPE type;
876 {
877 int ret;
878
879 ret = USR_ERR(env, EINVAL);
880 __db_errx(env, DB_STR_A("0094", "%s: Unexpected database type: %s",
881 "%s %s"), routine, __db_dbtype_to_string(type));
882
883 #ifdef DIAGNOSTIC
884 __os_abort(env);
885 /* NOTREACHED */
886 #endif
887 return (ret);
888 }
889
890 /*
891 * __db_unknown_path -- report unexpected database code path error.
892 *
893 * PUBLIC: int __db_unknown_path __P((ENV *, char *));
894 */
895 int
__db_unknown_path(env,routine)896 __db_unknown_path(env, routine)
897 ENV *env;
898 char *routine;
899 {
900 int ret;
901
902 ret = USR_ERR(env, EINVAL);
903 __db_errx(env, DB_STR_A("0095", "%s: Unexpected code path error",
904 "%s"), routine);
905
906 #ifdef DIAGNOSTIC
907 __os_abort(env);
908 /* NOTREACHED */
909 #endif
910 return (ret);
911 }
912
913 /*
914 * __db_check_txn --
915 * Check for common transaction errors.
916 *
917 * PUBLIC: int __db_check_txn __P((DB *, DB_TXN *, DB_LOCKER *, int));
918 */
919 int
__db_check_txn(dbp,txn,assoc_locker,read_op)920 __db_check_txn(dbp, txn, assoc_locker, read_op)
921 DB *dbp;
922 DB_TXN *txn;
923 DB_LOCKER *assoc_locker;
924 int read_op;
925 {
926 ENV *env;
927 int related, ret;
928
929 env = dbp->env;
930
931 /*
932 * If we are in recovery or aborting a transaction, then we
933 * don't need to enforce the rules about dbp's not allowing
934 * transactional operations in non-transactional dbps and
935 * vica-versa. This happens all the time as the dbp during
936 * an abort may be transactional, but we undo operations
937 * outside a transaction since we're aborting.
938 */
939 if (IS_RECOVERING(env) || F_ISSET(dbp, DB_AM_RECOVER))
940 return (0);
941
942 if (txn != NULL && dbp->blob_threshold &&
943 F_ISSET(txn, (TXN_READ_UNCOMMITTED | TXN_SNAPSHOT))) {
944 ret = USR_ERR(env, EINVAL);
945 __db_errx(env, DB_STR("0237",
946 "External file databases do not support DB_READ_UNCOMMITTED and TXN_SNAPSHOT")
947 );
948 return (ret);
949 }
950
951 /*
952 * Check for common transaction errors:
953 * an operation on a handle whose open commit hasn't completed.
954 * a transaction handle in a non-transactional environment
955 * a transaction handle for a non-transactional database
956 */
957 if (!read_op && txn != NULL && F_ISSET(txn, TXN_READONLY)) {
958 ret = USR_ERR(env, EINVAL);
959 __db_errx(env, DB_STR("0096",
960 "Read-only transaction cannot be used for an update"));
961 } else if (txn == NULL || F_ISSET(txn, TXN_PRIVATE)) {
962 if (dbp->cur_locker != NULL &&
963 dbp->cur_locker->id >= TXN_MINIMUM)
964 goto open_err;
965
966 if (!read_op && F_ISSET(dbp, DB_AM_TXN)) {
967 ret = USR_ERR(env, EINVAL);
968 __db_errx(env, DB_STR("0097",
969 "Transaction not specified for a transactional database"));
970 return (ret);
971 }
972 } else if (F_ISSET(txn, TXN_FAMILY)) {
973 /*
974 * Family transaction handles can be passed to any method,
975 * since they only determine locker IDs.
976 */
977 return (0);
978 } else {
979 if (!TXN_ON(env))
980 return (__db_not_txn_env(env));
981
982 if (!F_ISSET(dbp, DB_AM_TXN)) {
983 ret = USR_ERR(env, EINVAL);
984 __db_errx(env, DB_STR("0098",
985 "Transaction specified for a non-transactional database"));
986 return (ret);
987 }
988
989 if (F_ISSET(txn, TXN_DEADLOCK))
990 return (__db_txn_deadlock_err(env, txn));
991
992 if (dbp->cur_locker != NULL &&
993 dbp->cur_locker->id >= TXN_MINIMUM &&
994 dbp->cur_locker->id != txn->txnid) {
995 if ((ret = __lock_locker_same_family(env,
996 dbp->cur_locker, txn->locker, &related)) != 0)
997 return (ret);
998 if (!related)
999 goto open_err;
1000 }
1001 }
1002
1003 /*
1004 * If dbp->associate_locker is not NULL, that means we're in
1005 * the middle of a DB->associate with DB_CREATE (i.e., a secondary index
1006 * creation).
1007 *
1008 * In addition to the usual transaction rules, we need to lock out
1009 * non-transactional updates that aren't part of the associate (and
1010 * thus are using some other locker ID).
1011 *
1012 * Transactional updates should simply block; from the time we
1013 * decide to build the secondary until commit, we'll hold a write
1014 * lock on all of its pages, so it should be safe to attempt to update
1015 * the secondary in another transaction (presumably by updating the
1016 * primary).
1017 */
1018 if (!read_op && dbp->associate_locker != NULL &&
1019 txn != NULL && dbp->associate_locker != assoc_locker) {
1020 ret = USR_ERR(env, EINVAL);
1021 __db_errx(env, DB_STR("0099",
1022 "Operation forbidden while secondary index is being created"));
1023 return (ret);
1024 }
1025
1026 /*
1027 * Check the txn and dbp are from the same env.
1028 */
1029 if (txn != NULL && env != txn->mgrp->env) {
1030 ret = USR_ERR(env, EINVAL);
1031 __db_errx(env, DB_STR("0100",
1032 "Transaction and database from different environments"));
1033 return (ret);
1034 }
1035
1036 return (0);
1037 open_err:
1038 ret = USR_ERR(env, EINVAL);
1039 if (F2_ISSET(dbp, DB2_AM_EXCL))
1040 __db_errx(env, DB_STR("0749",
1041 "Exclusive database handles can only have one active transaction at a time."));
1042 else
1043 __db_errx(env, DB_STR("0101",
1044 "Transaction that opened the DB handle is still active"));
1045 return (ret);
1046 }
1047
1048 /*
1049 * __db_txn_deadlock_err --
1050 * Transaction has allready been deadlocked.
1051 *
1052 * PUBLIC: int __db_txn_deadlock_err __P((ENV *, DB_TXN *));
1053 */
1054 int
__db_txn_deadlock_err(env,txn)1055 __db_txn_deadlock_err(env, txn)
1056 ENV *env;
1057 DB_TXN *txn;
1058 {
1059 const char *name;
1060 int ret;
1061
1062 ret = USR_ERR(env, EINVAL);
1063 name = NULL;
1064 (void)__txn_get_name(txn, &name);
1065
1066 __db_errx(env, DB_STR_A("0102",
1067 "%s%sprevious transaction deadlock return not resolved",
1068 "%s %s"), name == NULL ? "" : name, name == NULL ? "" : ": ");
1069
1070 return (ret);
1071 }
1072
1073 /*
1074 * __db_not_txn_env --
1075 * DB handle must be in an environment that supports transactions.
1076 *
1077 * PUBLIC: int __db_not_txn_env __P((ENV *));
1078 */
1079 int
__db_not_txn_env(env)1080 __db_not_txn_env(env)
1081 ENV *env;
1082 {
1083 int ret;
1084
1085 ret = USR_ERR(env, EINVAL);
1086 __db_errx(env, DB_STR("0103",
1087 "DB environment not configured for transactions"));
1088 return (ret);
1089 }
1090
1091 /*
1092 * __db_not_log_env --
1093 * DB handle must be in an environment that supports logging.
1094 *
1095 * PUBLIC: int __db_not_log_env __P((ENV *));
1096 */
1097 int
__db_not_log_env(env)1098 __db_not_log_env(env)
1099 ENV *env;
1100 {
1101 int ret;
1102
1103 ret = USR_ERR(env, EINVAL);
1104 __db_errx(env, DB_STR("5536",
1105 "DB environment not configured for logging"));
1106 return (ret);
1107 }
1108 /*
1109 * __db_rec_toobig --
1110 * Fixed record length exceeded error message.
1111 *
1112 * PUBLIC: int __db_rec_toobig __P((ENV *, u_int32_t, u_int32_t));
1113 */
1114 int
__db_rec_toobig(env,data_len,fixed_rec_len)1115 __db_rec_toobig(env, data_len, fixed_rec_len)
1116 ENV *env;
1117 u_int32_t data_len, fixed_rec_len;
1118 {
1119 int ret;
1120
1121 ret = USR_ERR(env, EINVAL);
1122 __db_errx(env, DB_STR_A("0104",
1123 "%lu larger than database's maximum record length %lu",
1124 "%lu %lu"), (u_long)data_len, (u_long)fixed_rec_len);
1125 return (ret);
1126 }
1127
1128 /*
1129 * __db_rec_repl --
1130 * Fixed record replacement length error message.
1131 *
1132 * PUBLIC: int __db_rec_repl __P((ENV *, u_int32_t, u_int32_t));
1133 */
1134 int
__db_rec_repl(env,data_size,data_dlen)1135 __db_rec_repl(env, data_size, data_dlen)
1136 ENV *env;
1137 u_int32_t data_size, data_dlen;
1138 {
1139 int ret;
1140
1141 ret = USR_ERR(env, EINVAL);
1142 __db_errx(env, DB_STR_A("0105",
1143 "Record length error: "
1144 "replacement length %lu differs from replaced length %lu",
1145 "%lu %lu"), (u_long)data_size, (u_long)data_dlen);
1146 return (ret);
1147 }
1148
1149 #if defined(DIAGNOSTIC) || defined(DEBUG_ROP) || defined(DEBUG_WOP)
1150 /*
1151 * __dbc_logging --
1152 * In DIAGNOSTIC mode, check for bad replication combinations.
1153 *
1154 * PUBLIC: int __dbc_logging __P((DBC *));
1155 */
1156 int
__dbc_logging(dbc)1157 __dbc_logging(dbc)
1158 DBC *dbc;
1159 {
1160 DB_REP *db_rep;
1161 ENV *env;
1162 int ret;
1163
1164 env = dbc->env;
1165 db_rep = env->rep_handle;
1166
1167 ret = LOGGING_ON(env) &&
1168 !F_ISSET(dbc, DBC_RECOVER) && !IS_REP_CLIENT(env);
1169
1170 /*
1171 * If we're not using replication or running recovery, return.
1172 */
1173 if (db_rep == NULL || F_ISSET(dbc, DBC_RECOVER))
1174 return (ret);
1175
1176 #ifndef DEBUG_ROP
1177 /*
1178 * Only check when DEBUG_ROP is not configured. People often do
1179 * non-transactional reads, and debug_rop is going to write
1180 * a log record.
1181 */
1182 {
1183 REP *rep;
1184
1185 rep = db_rep->region;
1186
1187 /*
1188 * If we're a client and not running recovery or non durably, error.
1189 */
1190 if (IS_REP_CLIENT(env) && !F_ISSET(dbc->dbp, DB_AM_NOT_DURABLE)) {
1191 __db_errx(env, DB_STR("0106",
1192 "dbc_logging: Client update"));
1193 goto err;
1194 }
1195
1196 #ifndef DEBUG_WOP
1197 /*
1198 * If DEBUG_WOP is enabled, then we'll generate debugging log records
1199 * that are non-transactional. This is OK.
1200 */
1201 if (IS_REP_MASTER(env) &&
1202 dbc->txn == NULL && !F_ISSET(dbc->dbp, DB_AM_NOT_DURABLE)) {
1203 __db_errx(env, DB_STR("0107",
1204 "Dbc_logging: Master non-txn update"));
1205 goto err;
1206 }
1207 #endif
1208
1209 if (0) {
1210 err: __db_errx(env, DB_STR_A("0108", "Rep: flags 0x%lx msg_th %lu",
1211 "%lx %lu"), (u_long)rep->flags, (u_long)rep->msg_th);
1212 __db_errx(env, DB_STR_A("0109", "Rep: handle %lu, opcnt %lu",
1213 "%lu %lu"), (u_long)rep->handle_cnt, (u_long)rep->op_cnt);
1214 __os_abort(env);
1215 /* NOTREACHED */
1216 }
1217 }
1218 #endif
1219 return (ret);
1220 }
1221 #endif
1222
1223 /*
1224 * __db_check_lsn --
1225 * Display the log sequence error message.
1226 *
1227 * PUBLIC: int __db_check_lsn __P((ENV *, DB_LSN *, DB_LSN *));
1228 */
1229 int
__db_check_lsn(env,lsn,prev)1230 __db_check_lsn(env, lsn, prev)
1231 ENV *env;
1232 DB_LSN *lsn, *prev;
1233 {
1234 int ret;
1235
1236 ret = USR_ERR(env, EINVAL);
1237 __db_errx(env, DB_STR_A("0110",
1238 "Log sequence error: page LSN %lu %lu; previous LSN %lu %lu",
1239 "%lu %lu %lu %lu"), (u_long)(lsn)->file,
1240 (u_long)(lsn)->offset, (u_long)(prev)->file,
1241 (u_long)(prev)->offset);
1242 return (ret);
1243 }
1244
1245 /*
1246 * __db_rdonly --
1247 * Common readonly message.
1248 * PUBLIC: int __db_rdonly __P((const ENV *, const char *));
1249 */
1250 int
__db_rdonly(env,name)1251 __db_rdonly(env, name)
1252 const ENV *env;
1253 const char *name;
1254 {
1255 int ret;
1256
1257 ret = USR_ERR(env, EACCES);
1258 __db_errx(env, DB_STR_A("0111",
1259 "%s: attempt to modify a read-only database", "%s"), name);
1260 return (ret);
1261 }
1262
1263 /*
1264 * __db_space_err --
1265 * Common out of space message.
1266 * PUBLIC: int __db_space_err __P((const DB *));
1267 */
1268 int
__db_space_err(dbp)1269 __db_space_err(dbp)
1270 const DB *dbp;
1271 {
1272 int ret;
1273
1274 ret = USR_ERR(dbp->env, ENOSPC);
1275 __db_errx(dbp->env, DB_STR_A("3023",
1276 "%s: file limited to %lu pages", "%s %lu"),
1277 dbp->fname, (u_long)dbp->mpf->mfp->maxpgno);
1278 return (ret);
1279 }
1280
1281 /*
1282 * __db_failed --
1283 * Common failed thread message, e.g., after it is seen to have crashed.
1284 *
1285 PUBLIC: int __db_failed __P((const ENV *,
1286 * PUBLIC: const char *, pid_t, db_threadid_t));
1287 */
1288 int
__db_failed(env,msg,pid,tid)1289 __db_failed(env, msg, pid, tid)
1290 const ENV *env;
1291 const char *msg;
1292 pid_t pid;
1293 db_threadid_t tid;
1294 {
1295 DB_ENV *dbenv;
1296 int ret;
1297 char tidstr[DB_THREADID_STRLEN], failmsg[DB_FAILURE_SYMPTOM_SIZE];
1298
1299 dbenv = env->dbenv;
1300 (void)dbenv->thread_id_string(dbenv, pid, tid, tidstr);
1301 ret = USR_ERR(env, DB_RUNRECOVERY);
1302 snprintf(failmsg, sizeof(failmsg), DB_STR_A("0113",
1303 "Thread/process %s failed: %s", "%s %s"), tidstr, msg);
1304 (void)__env_failure_remember(env, failmsg);
1305 __db_errx(env, "%s", failmsg);
1306 return (ret);
1307 }
1308
1309 /*
1310 * __env_failure_remember --
1311 * If this failure of a process in the environment is about to set panic
1312 * for the first time, record that a crashed thread was thw culprit. Do
1313 * nothing if panic has already been set, or if the shared environment
1314 * region is no longer the one which we opened (i.e., our env handle is
1315 * "stale". It does not get any mutexes; to avoid hanging on any crashed
1316 * threads.
1317 *
1318 * PUBLIC: int __env_failure_remember __P((const ENV *, const char *));
1319 */
1320 int
__env_failure_remember(env,reason)1321 __env_failure_remember(env, reason)
1322 const ENV *env;
1323 const char *reason;
1324 {
1325 REGENV *renv;
1326
1327 renv = env->reginfo->primary;
1328 if (renv == NULL || renv->envid != env->envid || renv->failure_panic) {
1329 if (renv->envid != env->envid)
1330 DB_DEBUG_MSG(env,
1331 "failure_remember envid panic %u != %u",
1332 renv->envid, env->envid);
1333 return (0);
1334 }
1335 renv->failure_panic = 1;
1336 if (renv->failure_symptom[0] == '\0') {
1337 (void)strncpy(renv->failure_symptom,
1338 reason, sizeof(renv->failure_symptom));
1339 renv->failure_symptom[sizeof(renv->failure_symptom) - 1] = '\0';
1340 }
1341 return (0);
1342 }
1343
1344 #if defined(HAVE_ERROR_HISTORY)
1345 /*
1346 * __db_deferred_free --
1347 * Pthread_exit() calls this to release DB_GLOBAL(msgs_key)'s
1348 * thread-local storage.
1349 */
1350 static void
__db_deferred_free(void * p)1351 __db_deferred_free(void *p)
1352 {
1353 DB_MSGBUF *mb;
1354
1355 if ((mb = p) != NULL) {
1356 (void)pthread_setspecific(DB_GLOBAL(msgs_key), NULL);
1357 if (mb->buf != NULL)
1358 __os_free(NULL, mb->buf);
1359 free(mb);
1360 }
1361 }
1362
1363 /*
1364 * __db_thread_once_func --
1365 * The pthread_once() functions to initialize thread local storage.
1366 */
1367 static void
__db_thread_once_func()1368 __db_thread_once_func()
1369 {
1370 (void)pthread_key_create(&DB_GLOBAL(msgs_key), __db_deferred_free);
1371 }
1372
1373 /*
1374 * __db_thread_init --
1375 * Initialization hook to be called at least once per process, before
1376 * deferring any messages.
1377 *
1378 * PUBLIC: #ifdef HAVE_ERROR_HISTORY
1379 * PUBLIC: void __db_thread_init __P((void));
1380 * PUBLIC: #endif
1381 */
1382 void
__db_thread_init()1383 __db_thread_init()
1384 {
1385 /*
1386 * Assign the thread-local storage identifier. Tell thread exit to clean
1387 * up withl __db_deferred_free().
1388 */
1389 (void)pthread_once(&DB_GLOBAL(thread_once), __db_thread_once_func);
1390 }
1391
1392 /*
1393 * __db_diags --
1394 *
1395 * Save the context which triggers the "first notice" of an error code;
1396 * i.e., its creation. It doesn't touch anything when err == 0.
1397 *
1398 * PUBLIC: #ifdef HAVE_ERROR_HISTORY
1399 * PUBLIC: int __db_diags __P((const ENV *, int));
1400 * PUBLIC: #endif
1401 */
1402 int
__db_diags(env,err)1403 __db_diags(env, err)
1404 const ENV *env;
1405 int err;
1406 {
1407 DB_MSGBUF *mb;
1408
1409 if (err != 0 && (mb = __db_deferred_get()) != NULL)
1410 (void)__db_remember_context(env, mb, err);
1411 return (err);
1412 }
1413
1414 /*
1415 * __db_deferred_get --
1416 * Get this thread's deferred DB_MSGBUF, possibly allocating it.
1417 *
1418 * PUBLIC: #ifdef HAVE_ERROR_HISTORY
1419 * PUBLIC: DB_MSGBUF *__db_deferred_get __P((void));
1420 * PUBLIC: #endif
1421 */
1422 DB_MSGBUF *
__db_deferred_get()1423 __db_deferred_get()
1424 {
1425 DB_MSGBUF *mb;
1426
1427 if ((mb = pthread_getspecific(DB_GLOBAL(msgs_key))) == NULL) {
1428 if ((mb = calloc(1, sizeof(*mb))) != NULL)
1429 if (pthread_setspecific(DB_GLOBAL(msgs_key), mb) != 0) {
1430 /* Nothing else is safe do on an error. */
1431 free(mb);
1432 mb = NULL;
1433 }
1434 }
1435 return (mb);
1436 }
1437
1438 /*
1439 * __db_deferred_discard --
1440 * Discard any saved-up deferred messages, at e.g. the end of the command.
1441 *
1442 * PUBLIC: #ifdef HAVE_ERROR_HISTORY
1443 * PUBLIC: void __db_deferred_discard __P((void));
1444 * PUBLIC: #endif
1445 */
1446 void
__db_deferred_discard()1447 __db_deferred_discard()
1448 {
1449 DB_MSGBUF *mb;
1450
1451 if ((mb = pthread_getspecific(DB_GLOBAL(msgs_key))) != NULL)
1452 mb->cur = mb->buf;
1453 }
1454
1455 /*
1456 * __db_remember_context
1457 * Save the context which triggers the "first notice" of an error code;
1458 * i.e., its creation. Include the time, thread, recent portion of the
1459 * stack, and the error number. Add replication info too?
1460 *
1461 * Return the error number passed in, or 0?
1462 *
1463 * PUBLIC: #ifdef HAVE_ERROR_HISTORY
1464 * PUBLIC: int __db_remember_context __P((const ENV *, DB_MSGBUF *, int));
1465 * PUBLIC: #endif
1466 */
1467 int
__db_remember_context(env,mb,err)1468 __db_remember_context(env, mb, err)
1469 const ENV *env;
1470 DB_MSGBUF *mb;
1471 int err;
1472 {
1473 DB_ENV *dbenv;
1474 LOG *lp;
1475 REGENV *renv;
1476 db_timespec now;
1477 pid_t pid;
1478 db_threadid_t tid;
1479 char threadid[DB_THREADID_STRLEN], timestr[CTIME_BUFLEN];
1480
1481 /* Limit the amount of context messges which are remembered. */
1482 if (mb->len >= DB_ERROR_HISTORY_SIZE)
1483 return (0);
1484
1485 lp = NULL;
1486 renv = NULL;
1487 if (env == NULL) {
1488 dbenv = NULL;
1489 threadid[0] = '\0';
1490 } else {
1491 dbenv = env->dbenv;
1492 dbenv->thread_id(dbenv, &pid, &tid);
1493 (void)dbenv->thread_id_string(dbenv, pid, tid, threadid);
1494 if (env->reginfo != NULL)
1495 renv = env->reginfo->primary;
1496 if (LOGGING_ON(env) && !IS_RECOVERING(env))
1497 lp = env->lg_handle->reginfo.primary;
1498 }
1499
1500 __os_gettime(env, &now, 0);
1501 (void)__db_ctimespec(&now, timestr);
1502 __db_msgadd(env, mb, "\n[%s][%s] %s",
1503 timestr, threadid, db_strerror(err));
1504 if (lp != NULL)
1505 __db_msgadd(env, mb, " lsn [%lu][%lu]",
1506 (u_long)lp->lsn.file, (u_long)lp->lsn.offset);
1507 if (renv != NULL) {
1508 __db_msgadd(env, mb, " envid %x", renv->envid);
1509 if (renv->magic != DB_REGION_MAGIC)
1510 __db_msgadd(env, mb, " bad magic %x", renv->magic);
1511 if (renv->envid != env->envid ||
1512 renv->reg_panic || renv->failure_panic)
1513 __db_msgadd(env, mb,
1514 " panic ids %x : %x; reg %d fail %d", renv->envid,
1515 env->envid, renv->reg_panic, renv->failure_panic);
1516 if (renv->failure_symptom[0] != '\0')
1517 __db_msgadd(env, mb, " symptom %s",
1518 renv->failure_symptom);
1519 }
1520
1521 #if defined(HAVE_BACKTRACE) && defined(HAVE_BACKTRACE_SYMBOLS)
1522 /*
1523 * Add many frames of stack trace to the record, skipping the first two
1524 * frames: __os_stack_msgadd() and __db_remember_context().
1525 */
1526 __db_msgadd(env, mb, " from\n");
1527 __os_stack_msgadd(env, mb, 15, 2, NULL);
1528 #endif
1529
1530 return (0);
1531 }
1532 #endif
1533
1534 /*
1535 * __db_ctimespec --
1536 * Format a timespec in microseconds, similar to a terse __os_ctime(),
1537 * storing the results into a CTIME_BUFLEN sized buffer.
1538 * The result format depends on the availability of localtime, etc
1539 * MM/DD HH:MM:SS.uuuuuu if strftime is available, or
1540 * Jan DD HH:MM:SS.uuuuuu if only __os_ctime() is available.
1541 * Both are small enough to use __os_ctime() sized buffer, e.g. 26.
1542 * The other fields (year, day-of-week, ...) are intentionally removed.
1543 *
1544 * PUBLIC: char * __db_ctimespec __P((const db_timespec *, char *));
1545 */
1546 char *
__db_ctimespec(timespec,buf)1547 __db_ctimespec(timespec, buf)
1548 const db_timespec *timespec;
1549 char *buf;
1550 {
1551 char *d, date[CTIME_BUFLEN];
1552 #ifdef HAVE_STRFTIME
1553 struct tm *tm_p;
1554 #ifdef HAVE_LOCALTIME_R
1555 struct tm tm;
1556 #endif
1557 #endif
1558
1559 /* Print the time readably if possible; else print seconds. */
1560 #ifdef HAVE_STRFTIME
1561 #ifdef HAVE_LOCALTIME_R
1562 tm_p = localtime_r(×pec->tv_sec, &tm);
1563 #else
1564 tm_p = localtime(×pec->tv_sec);
1565 #endif
1566 if (tm_p != NULL) {
1567 d = date;
1568 (void)strftime(d, sizeof(date), DB_GLOBAL(time_format), tm_p);
1569 }
1570 else
1571 #endif
1572 {
1573 /* Trim off the leading day-of-week; then the trailing year. */
1574 d = __os_ctime(×pec->tv_sec, date) + 4;
1575 d[sizeof("Jan 01 00:00:00")] = '\0';
1576 }
1577 (void)snprintf(buf, CTIME_BUFLEN,
1578 "%s.%06lu", d, (u_long)(timespec->tv_nsec / NS_PER_US));
1579 buf[CTIME_BUFLEN - 1] = '\0'; /* In case of buggy snprintf. */
1580 return (buf);
1581 }
1582
1583 /*
1584 * __db_fmt_quote --
1585 * Copy a printf format string, quoting (doubling) each '%' along the way.
1586 * Use this when inserting a user-defined string into a *printf format.
1587 * If the src parameter is NULL, then quote in-place, shifting the
1588 * rest of the string down by one character for each quote.
1589 *
1590 * PUBLIC: char *__db_fmt_quote __P((char *, size_t, const char *));
1591 */
1592 char *
__db_fmt_quote(dest,destsize,src)1593 __db_fmt_quote(dest, destsize, src)
1594 char *dest;
1595 size_t destsize;
1596 const char *src;
1597 {
1598 char *d, *end;
1599 const char *s;
1600 size_t len;
1601
1602 /* Stop early enough so that dest always has room for a '\0'. */
1603 end = dest + destsize - 1;
1604 if (src == NULL) {
1605 d = dest;
1606 while ((d = strchr(d, '%')) != NULL && d[1] != '\0') {
1607 /*
1608 * Shift the rest of the string by one byte to make
1609 * space for another '%'. By starting at d and adding 1
1610 * to the length, we double the '%' while copying the
1611 * string and its terminating '\0'.
1612 */
1613 len = strlen(d) + 1;
1614 memmove(d + 1, d, len);
1615 /*
1616 * We're done if the string now is larger than the
1617 * reserved size; else advance over both '%'s.
1618 */
1619 if (d + len >= end) {
1620 DB_ASSERT(NULL, d + len == end);
1621 *end = '\0';
1622 break;
1623 }
1624 d += 2;
1625 }
1626 } else {
1627 for (s = src, d = dest; *s != '\0' && d < end; d++, s++)
1628 if ((*d = *s) == '%') {
1629 /* Discard a % at the end of the string. */
1630 if (s[1] == '\0')
1631 break;
1632 *++d = '%';
1633 }
1634 *d = '\0';
1635 }
1636 return (dest);
1637 }
1638