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(&timespec->tv_sec, &tm);
1563 #else
1564 	tm_p = localtime(&timespec->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(&timespec->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