1 /*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1996, 1997, 1998, 1999
5 * Sleepycat Software. All rights reserved.
6 */
7
8
9 #include "db_config.h"
10
11 #ifndef lint
12 static const char sccsid[] = "@(#)db_err.c 11.10 (Sleepycat) 11/8/99";
13 #endif /* not lint */
14
15 #ifndef NO_SYSTEM_INCLUDES
16 #include <sys/types.h>
17
18 #include <errno.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22
23 #ifndef _MSC_VER /* WIN32 */
24 #ifdef __STDC__
25 #include <stdarg.h>
26 #else
27 #include <varargs.h>
28 #endif
29 #endif
30 #endif
31
32 #include "db_int.h"
33 #include "db_shash.h"
34 #include "lock.h"
35 #include "lock_ext.h"
36 #include "log.h"
37 #include "log_ext.h"
38 #include "mp.h"
39 #include "mp_ext.h"
40 #include "txn.h"
41 #include "txn_ext.h"
42 #include "common_ext.h"
43 #include "db_auto.h"
44
45 static void CDB___db_errcall __P((const DB_ENV *, int, int, const char *, va_list));
46 static void CDB___db_errfile __P((const DB_ENV *, int, int, const char *, va_list));
47
48 /*
49 * CDB___db_fchk --
50 * General flags checking routine.
51 *
52 * PUBLIC: int CDB___db_fchk __P((DB_ENV *, const char *, u_int32_t, u_int32_t));
53 */
54 int
CDB___db_fchk(dbenv,name,flags,ok_flags)55 CDB___db_fchk(dbenv, name, flags, ok_flags)
56 DB_ENV *dbenv;
57 const char *name;
58 u_int32_t flags, ok_flags;
59 {
60 return (LF_ISSET(~ok_flags) ? CDB___db_ferr(dbenv, name, 0) : 0);
61 }
62
63 /*
64 * CDB___db_fcchk --
65 * General combination flags checking routine.
66 *
67 * PUBLIC: int CDB___db_fcchk
68 * PUBLIC: __P((DB_ENV *, const char *, u_int32_t, u_int32_t, u_int32_t));
69 */
70 int
CDB___db_fcchk(dbenv,name,flags,flag1,flag2)71 CDB___db_fcchk(dbenv, name, flags, flag1, flag2)
72 DB_ENV *dbenv;
73 const char *name;
74 u_int32_t flags, flag1, flag2;
75 {
76 return (LF_ISSET(flag1) &&
77 LF_ISSET(flag2) ? CDB___db_ferr(dbenv, name, 1) : 0);
78 }
79
80 /*
81 * CDB___db_ferr --
82 * Common flag errors.
83 *
84 * PUBLIC: int CDB___db_ferr __P((const DB_ENV *, const char *, int));
85 */
86 int
CDB___db_ferr(dbenv,name,iscombo)87 CDB___db_ferr(dbenv, name, iscombo)
88 const DB_ENV *dbenv;
89 const char *name;
90 int iscombo;
91 {
92 CDB___db_err(dbenv, "illegal flag %sspecified to %s",
93 iscombo ? "combination " : "", name);
94 return (EINVAL);
95 }
96
97 /*
98 * CDB___db_pgerr --
99 * Error when unable to retrieve a specified page.
100 *
101 * PUBLIC: int CDB___db_pgerr __P((DB *, db_pgno_t));
102 */
103 int
CDB___db_pgerr(dbp,pgno)104 CDB___db_pgerr(dbp, pgno)
105 DB *dbp;
106 db_pgno_t pgno;
107 {
108 /*
109 * Three things are certain:
110 * Death, taxes, and lost data.
111 * Guess which has occurred.
112 */
113 CDB___db_err(dbp->dbenv,
114 "unable to create/retrieve page %lu", (u_long)pgno);
115 return (CDB___db_panic(dbp->dbenv, EIO));
116 }
117
118 /*
119 * CDB___db_pgfmt --
120 * Error when a page has the wrong format.
121 *
122 * PUBLIC: int CDB___db_pgfmt __P((DB *, db_pgno_t));
123 */
124 int
CDB___db_pgfmt(dbp,pgno)125 CDB___db_pgfmt(dbp, pgno)
126 DB *dbp;
127 db_pgno_t pgno;
128 {
129 CDB___db_err(dbp->dbenv,
130 "page %lu: illegal page type or format", (u_long)pgno);
131 return (CDB___db_panic(dbp->dbenv, EINVAL));
132 }
133
134 #ifdef DIAGNOSTIC
135 /*
136 * __db_assert --
137 * Error when an assertion fails. Only checked if #DIAGNOSTIC defined.
138 *
139 * PUBLIC: #ifdef DIAGNOSTIC
140 * PUBLIC: void __db_assert __P((const char *, const char *, int));
141 * PUBLIC: #endif
142 */
143 void
__db_assert(failedexpr,file,line)144 __db_assert(failedexpr, file, line)
145 const char *failedexpr, *file;
146 int line;
147 {
148 (void)fprintf(stderr,
149 "__db_assert: \"%s\" failed: file \"%s\", line %d\n",
150 failedexpr, file, line);
151 fflush(stderr);
152
153 /* We want a stack trace of how this could possibly happen. */
154 abort();
155
156 /* NOTREACHED */
157 }
158 #endif
159
160 /*
161 * CDB___db_panic_msg --
162 * Just report that someone else paniced.
163 *
164 * PUBLIC: int CDB___db_panic_msg __P((DB_ENV *));
165 */
166 int
CDB___db_panic_msg(dbenv)167 CDB___db_panic_msg(dbenv)
168 DB_ENV *dbenv;
169 {
170 CDB___db_err(dbenv, "region error detected; run recovery.");
171 /* Hack to make fatal errors really fatal... */
172 fprintf(stderr,"DB_RUNRECOVERY: Fatal error, run database recovery\n");
173 exit(1);
174 return (DB_RUNRECOVERY);
175 }
176
177 /*
178 * CDB___db_panic --
179 * Lock out the tree due to unrecoverable error.
180 *
181 * PUBLIC: int CDB___db_panic __P((DB_ENV *, int));
182 */
183 int
CDB___db_panic(dbenv,errval)184 CDB___db_panic(dbenv, errval)
185 DB_ENV *dbenv;
186 int errval;
187 {
188 if (dbenv != NULL) {
189 ((REGENV *)((REGINFO *)dbenv->reginfo)->addr)->panic = 1;
190
191 dbenv->db_panic = errval;
192
193 CDB___db_err(dbenv, "PANIC: %s", CDB_db_strerror(errval));
194
195 if (dbenv->db_paniccall != NULL)
196 dbenv->db_paniccall(dbenv, errval);
197 }
198
199 /*
200 * Chaos reigns within.
201 * Reflect, repent, and reboot.
202 * Order shall return.
203 */
204 /* Hack to make fatal errors really fatal... */
205 fprintf(stderr,"DB_RUNRECOVERY: Fatal error, run database recovery\n");
206 exit(1);
207 return (DB_RUNRECOVERY);
208 }
209
210 /*
211 * CDB_db_strerror --
212 * ANSI C strerror(3) for DB.
213 */
214 char *
CDB_db_strerror(error)215 CDB_db_strerror(error)
216 int error;
217 {
218 if (error == 0)
219 return ("Successful return: 0");
220 if (error > 0)
221 return (strerror(error));
222
223 /*
224 * !!!
225 * The Tcl API requires that some of these return strings be compared
226 * against strings stored in application scripts. So, any of these
227 * errors that do not invariably result in a Tcl exception may not be
228 * altered.
229 */
230 switch (error) {
231 case DB_INCOMPLETE:
232 return ("DB_INCOMPLETE: Cache flush was unable to complete");
233 case DB_KEYEMPTY:
234 return ("DB_KEYEMPTY: Non-existent key/data pair");
235 case DB_KEYEXIST:
236 return ("DB_KEYEXIST: Key/data pair already exists");
237 case DB_LOCK_DEADLOCK:
238 return
239 ("DB_LOCK_DEADLOCK: Locker killed to resolve a deadlock");
240 case DB_LOCK_NOTGRANTED:
241 return ("DB_LOCK_NOTGRANTED: Lock not granted");
242 case DB_NOTFOUND:
243 return ("DB_NOTFOUND: No matching key/data pair found");
244 case DB_OLD_VERSION:
245 return ("DB_OLDVERSION: Database requires a version upgrade");
246 case DB_RUNRECOVERY:
247 return ("DB_RUNRECOVERY: Fatal error, run database recovery");
248 default: {
249 /*
250 * !!!
251 * Room for a 64-bit number + slop. This buffer is only used
252 * if we're given an unknown error, which should never happen.
253 * Note, however, we're no longer thread-safe if it does.
254 */
255 static char ebuf[40];
256
257 (void)snprintf(ebuf, sizeof(ebuf), "Unknown error: %d", error);
258 return(ebuf);
259 }
260 }
261 }
262
263 /*
264 * CDB___db_err --
265 * Standard DB error routine. The same as db_errx, except that we
266 * don't write to stderr if no output mechanism was specified.
267 *
268 * PUBLIC: #ifdef __STDC__
269 * PUBLIC: void CDB___db_err __P((const DB_ENV *, const char *, ...));
270 * PUBLIC: #else
271 * PUBLIC: void CDB___db_err();
272 * PUBLIC: #endif
273 */
274 void
275 #if defined( __STDC__) || defined(_MSC_VER) /* WIN32 */
CDB___db_err(const DB_ENV * dbenv,const char * fmt,...)276 CDB___db_err(const DB_ENV *dbenv, const char *fmt, ...)
277 #else
278 CDB___db_err(dbenv, fmt, va_alist)
279 const DB_ENV *dbenv;
280 const char *fmt;
281 va_dcl
282 #endif
283 {
284 va_list ap;
285
286 #if defined(__STDC__) || defined(_MSC_VER) /* WIN32 */
287 va_start(ap, fmt);
288 #else
289 va_start(ap);
290 #endif
291 CDB___db_real_err(dbenv, 0, 0, 0, fmt, ap);
292
293 va_end(ap);
294 }
295
296 /*
297 * CDB___db_real_err --
298 * All the DB error routines end up here.
299 *
300 * PUBLIC: void CDB___db_real_err
301 * PUBLIC: __P((const DB_ENV *, int, int, int, const char *, va_list));
302 */
303 void
CDB___db_real_err(dbenv,error,error_set,stderr_default,fmt,ap)304 CDB___db_real_err(dbenv, error, error_set, stderr_default, fmt, ap)
305 const DB_ENV *dbenv;
306 int error, error_set, stderr_default;
307 const char *fmt;
308 va_list ap;
309 {
310 if (dbenv != NULL && dbenv->db_errcall != NULL)
311 CDB___db_errcall(dbenv, error, error_set, fmt, ap);
312
313 if (dbenv != NULL && dbenv->db_errfile != NULL)
314 CDB___db_errfile(dbenv, error, error_set, fmt, ap);
315
316 if (stderr_default && (dbenv == NULL ||
317 (dbenv->db_errcall == NULL && dbenv->db_errfile == NULL)))
318 CDB___db_errfile(NULL, error, error_set, fmt, ap);
319 }
320
321 /*
322 * CDB___db_errcall --
323 * Do the error message work for callback functions.
324 */
325 static void
CDB___db_errcall(dbenv,error,error_set,fmt,ap)326 CDB___db_errcall(dbenv, error, error_set, fmt, ap)
327 const DB_ENV *dbenv;
328 int error, error_set;
329 const char *fmt;
330 va_list ap;
331 {
332 char *p;
333 char __errbuf[2048]; /* XXX: END OF THE STACK DON'T TRUST SPRINTF. */
334
335 p = __errbuf;
336 if (fmt != NULL) {
337 p += vsnprintf(__errbuf, sizeof(__errbuf), fmt, ap);
338 if (error_set) {
339 *p++ = ':';
340 *p++ = ' ';
341 }
342 }
343 if (error_set)
344 (void)strcpy(p, CDB_db_strerror(error));
345
346 dbenv->db_errcall(dbenv->db_errpfx, __errbuf);
347 }
348
349 /*
350 * CDB___db_errfile --
351 * Do the error message work for FILE *s.
352 */
353 static void
CDB___db_errfile(dbenv,error,error_set,fmt,ap)354 CDB___db_errfile(dbenv, error, error_set, fmt, ap)
355 const DB_ENV *dbenv;
356 int error, error_set;
357 const char *fmt;
358 va_list ap;
359 {
360 FILE *fp;
361
362 fp = dbenv == NULL ||
363 dbenv->db_errfile == NULL ? stderr : dbenv->db_errfile;
364
365 if (dbenv != NULL && dbenv->db_errpfx != NULL)
366 (void)fprintf(fp, "%s: ", dbenv->db_errpfx);
367 if (fmt != NULL) {
368 (void)vfprintf(fp, fmt, ap);
369 if (error_set)
370 (void)fprintf(fp, ": ");
371 }
372 if (error_set)
373 (void)fprintf(fp, "%s", CDB_db_strerror(error));
374 (void)fprintf(fp, "\n");
375 (void)fflush(fp);
376 }
377
378 /*
379 * CDB___db_logmsg --
380 * Write information into the DB log.
381 *
382 * PUBLIC: #ifdef __STDC__
383 * PUBLIC: int CDB___db_logmsg __P((DB_ENV *,
384 * PUBLIC: DB_TXN *, const char *, u_int32_t, const char *, ...));
385 * PUBLIC: #else
386 * PUBLIC: int CDB___db_logmsg();
387 * PUBLIC: #endif
388 */
389 int
390 #if defined(__STDC__) || defined(_MSC_VER) /* WIN32 */
CDB___db_logmsg(DB_ENV * dbenv,DB_TXN * txnid,const char * opname,u_int32_t flags,const char * fmt,...)391 CDB___db_logmsg(DB_ENV *dbenv,
392 DB_TXN *txnid, const char *opname, u_int32_t flags, const char *fmt, ...)
393 #else
394 CDB___db_logmsg(dbenv, txnid, opname, flags, fmt, va_alist)
395 DB_ENV *dbenv;
396 DB_TXN *txnid;
397 const char *opname, *fmt;
398 u_int32_t flags;
399 va_dcl
400 #endif
401 {
402 DBT opdbt, msgdbt;
403 DB_LSN lsn;
404 va_list ap;
405 char __logbuf[2048]; /* XXX: END OF THE STACK DON'T TRUST SPRINTF. */
406
407 if (!F_ISSET(dbenv, DB_ENV_LOGGING))
408 return (0);
409
410 memset(&opdbt, 0, sizeof(opdbt));
411 opdbt.data = (void *)opname;
412 opdbt.size = strlen(opname) + 1;
413
414 memset(&msgdbt, 0, sizeof(msgdbt));
415 msgdbt.data = __logbuf;
416 #if defined(__STDC__) || defined(_MSC_VER) /* WIN32 */
417 va_start(ap, fmt);
418 #else
419 va_start(ap);
420 #endif
421 msgdbt.size = vsnprintf(__logbuf, sizeof(__logbuf), fmt, ap);
422 va_end(ap);
423
424 return (CDB___db_debug_log(dbenv,
425 txnid, &lsn, flags, &opdbt, -1, &msgdbt, NULL, 0));
426 }
427