+
+const char *tdb_errorstr(const struct tdb_context *tdb)
+{
+ /* Gcc warns if you miss a case in the switch, so use that. */
+ switch (tdb->ecode) {
+ case TDB_SUCCESS: return "Success";
+ case TDB_ERR_CORRUPT: return "Corrupt database";
+ case TDB_ERR_IO: return "IO Error";
+ case TDB_ERR_LOCK: return "Locking error";
+ case TDB_ERR_OOM: return "Out of memory";
+ case TDB_ERR_EXISTS: return "Record exists";
+ case TDB_ERR_NESTING: return "Transaction already started";
+ case TDB_ERR_EINVAL: return "Invalid parameter";
+ case TDB_ERR_NOEXIST: return "Record does not exist";
+ case TDB_ERR_RDONLY: return "write not permitted";
+ }
+ return "Invalid error code";
+}
+
+void COLD tdb_logerr(struct tdb_context *tdb,
+ enum TDB_ERROR ecode,
+ enum tdb_debug_level level,
+ const char *fmt, ...)
+{
+ char *message;
+ va_list ap;
+ size_t len;
+ /* tdb_open paths care about errno, so save it. */
+ int saved_errno = errno;
+
+ tdb->ecode = ecode;
+
+ if (!tdb->logfn)
+ return;
+
+ /* FIXME: Doesn't assume asprintf. */
+ va_start(ap, fmt);
+ len = vsnprintf(NULL, 0, fmt, ap);
+ va_end(ap);
+
+ message = malloc(len + 1);
+ if (!message) {
+ tdb->logfn(tdb, level, tdb->log_private,
+ "out of memory formatting message");
+ return;
+ }
+ va_start(ap, fmt);
+ len = vsprintf(message, fmt, ap);
+ va_end(ap);
+ tdb->logfn(tdb, level, tdb->log_private, message);
+ free(message);
+ errno = saved_errno;
+}