* Exim - an Internet mail transport agent *
*************************************************/
+/* Copyright (c) The Exim Maintainers 2020 - 2024 */
/* Copyright (c) University of Cambridge 1995 - 2018 */
-/* Copyright (c) The Exim Maintainers 2020 - 2021 */
/* See the file NOTICE for conditions of use and distribution. */
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/* This single source file is used to compile three utility programs for
uschar *spool_directory;
+BOOL keyonly = FALSE;
BOOL utc = FALSE;
readconf_printtime(int t)
{ return NULL; }
gstring *
+string_catn(gstring * g, const uschar * s, int count)
+{ return NULL; }
+gstring *
string_vformat_trc(gstring * g, const uschar * func, unsigned line,
unsigned size_limit, unsigned flags, const char *format, va_list ap)
{ return NULL; }
/******************************************************************************/
-/*************************************************
-* Berkeley DB error callback *
-*************************************************/
-
-/* For Berkeley DB >= 2, we can define a function to be called in case of DB
-errors. This should help with debugging strange DB problems, e.g. getting "File
-exists" when you try to open a db file. The API changed at release 4.3. */
-
-#if defined(USE_DB) && defined(DB_VERSION_STRING)
-void
-#if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3)
-dbfn_bdb_error_callback(const DB_ENV *dbenv, const char *pfx, const char *msg)
-{
-dbenv = dbenv;
-#else
-dbfn_bdb_error_callback(const char *pfx, char *msg)
-{
-#endif
-pfx = pfx;
-printf("Berkeley DB error: %s\n", msg);
-}
-#endif
-
-
-
/*************************************************
* SIGALRM handler *
*************************************************/
uschar * aname = argv[optind + 1];
if (argc - optind == 2)
{
- if (Ustrcmp(aname, "retry") == 0) return type_retry;
- if (Ustrcmp(aname, "misc") == 0) return type_misc;
+ if (Ustrcmp(aname, "retry") == 0) return type_retry;
+ if (Ustrcmp(aname, "misc") == 0) return type_misc;
if (Ustrncmp(aname, "wait-", 5) == 0) return type_wait;
- if (Ustrcmp(aname, "callout") == 0) return type_callout;
+ if (Ustrcmp(aname, "callout") == 0) return type_callout;
if (Ustrcmp(aname, "ratelimit") == 0) return type_ratelimit;
- if (Ustrcmp(aname, "tls") == 0) return type_tls;
- if (Ustrcmp(aname, "seen") == 0) return type_seen;
+ if (Ustrcmp(aname, "tls") == 0) return type_tls;
+ if (Ustrcmp(aname, "seen") == 0) return type_seen;
}
usage(name, options);
return -1; /* Never obeyed */
}
+FUNC_MAYBE_UNUSED
static void
-options(int argc, uschar * argv[], uschar * name)
+options(int argc, uschar * argv[], uschar * name, const uschar * opts)
{
int opt;
opterr = 0;
-while ((opt = getopt(argc, (char * const *)argv, "z")) != -1)
+while ((opt = getopt(argc, (char * const *)argv, CCS opts)) != -1)
switch (opt)
{
+ case 'k': keyonly = TRUE; break;
case 'z': utc = TRUE; break;
- default: usage(name, US" [-z]");
+ default: usage(name, US" [-z] [-k]");
}
}
*/
open_db *
-dbfn_open(uschar *name, int flags, open_db *dbblock, BOOL lof, BOOL panic)
+dbfn_open(const uschar * name, int flags, open_db * dbblock,
+ BOOL lof, BOOL panic)
{
int rc;
struct flock lock_data;
-BOOL read_only = flags == O_RDONLY;
+BOOL read_only = (flags & (O_WRONLY|O_RDWR)) == O_RDONLY;
uschar * dirname, * filename;
/* The first thing to do is to open a separate file on which to lock. This
ensures that Exim has exclusive use of the database before it even tries to
-open it. If there is a database, there should be a lock file in existence. */
+open it. If there is a database, there should be a lock file in existence;
+if no lockfile we infer there is no database and error out. We open the
+lockfile using the r/w mode requested for the DB, users lacking permission
+for the DB access mode will error out here. */
-#ifdef COMPILE_UTILITY
if ( asprintf(CSS &dirname, "%s/db", spool_directory) < 0
|| asprintf(CSS &filename, "%s/%s.lockfile", dirname, name) < 0)
return NULL;
-#else
-dirname = string_sprintf("%s/db", spool_directory);
-filename = string_sprintf("%s/%s.lockfile", dirname, name);
-#endif
-dbblock->lockfd = Uopen(filename, flags, 0);
-if (dbblock->lockfd < 0)
+if ((dbblock->lockfd = Uopen(filename, flags, 0)) < 0)
{
printf("** Failed to open database lock file %s: %s\n", filename,
strerror(errno));
if (rc < 0)
{
printf("** Failed to get %s lock for %s: %s",
- flags & O_WRONLY ? "write" : "read",
+ read_only ? "read" : "write",
filename,
errno == ETIMEDOUT ? "timed out" : strerror(errno));
(void)close(dbblock->lockfd);
/* At this point we have an opened and locked separate lock file, that is,
exclusive access to the database, so we can go ahead and open it. */
-#ifdef COMPILE_UTILITY
if (asprintf(CSS &filename, "%s/%s", dirname, name) < 0) return NULL;
-#else
-filename = string_sprintf("%s/%s", dirname, name);
-#endif
-EXIM_DBOPEN(filename, dirname, flags, 0, &dbblock->dbptr);
-if (!dbblock->dbptr)
+if (flags & O_RDWR) flags |= O_CREAT;
+
+if (!(dbblock->dbptr = exim_dbopen(filename, dirname, flags, 0)))
{
printf("** Failed to open DBM file %s for %s:\n %s%s\n", filename,
read_only? "reading" : "writing", strerror(errno),
void
dbfn_close(open_db *dbblock)
{
-EXIM_DBCLOSE(dbblock->dbptr);
+exim_dbclose(dbblock->dbptr);
(void)close(dbblock->lockfd);
}
*/
void *
-dbfn_read_with_length(open_db *dbblock, const uschar *key, int *length)
+dbfn_read_with_length(open_db * dbblock, const uschar * key, int * length)
{
-void *yield;
+void * yield;
EXIM_DATUM key_datum, result_datum;
int klen = Ustrlen(key) + 1;
uschar * key_copy = store_get(klen, key);
+unsigned dlen;
memcpy(key_copy, key, klen);
-EXIM_DATUM_INIT(key_datum); /* Some DBM libraries require the datum */
-EXIM_DATUM_INIT(result_datum); /* to be cleared before use. */
-EXIM_DATUM_DATA(key_datum) = CS key_copy;
-EXIM_DATUM_SIZE(key_datum) = klen;
+exim_datum_init(&key_datum); /* Some DBM libraries require the datum */
+exim_datum_init(&result_datum); /* to be cleared before use. */
+exim_datum_data_set(&key_datum, key_copy);
+exim_datum_size_set(&key_datum, klen);
-if (!EXIM_DBGET(dbblock->dbptr, key_datum, result_datum)) return NULL;
+if (!exim_dbget(dbblock->dbptr, &key_datum, &result_datum)) return NULL;
/* Assume for now that anything stored could have been tainted. Properly
we should store the taint status along with the data. */
-yield = store_get(EXIM_DATUM_SIZE(result_datum), GET_TAINTED);
-memcpy(yield, EXIM_DATUM_DATA(result_datum), EXIM_DATUM_SIZE(result_datum));
-if (length) *length = EXIM_DATUM_SIZE(result_datum);
+dlen = exim_datum_size_get(&result_datum);
+yield = store_get(dlen, GET_TAINTED);
+memcpy(yield, exim_datum_data_get(&result_datum), dlen);
+if (length) *length = dlen;
-EXIM_DATUM_FREE(result_datum); /* Some DBM libs require freeing */
+exim_datum_free(&result_datum); /* Some DBM libs require freeing */
return yield;
}
memcpy(key_copy, key, klen);
gptr->time_stamp = time(NULL);
-EXIM_DATUM_INIT(key_datum); /* Some DBM libraries require the datum */
-EXIM_DATUM_INIT(value_datum); /* to be cleared before use. */
-EXIM_DATUM_DATA(key_datum) = CS key_copy;
-EXIM_DATUM_SIZE(key_datum) = klen;
-EXIM_DATUM_DATA(value_datum) = CS ptr;
-EXIM_DATUM_SIZE(value_datum) = length;
-return EXIM_DBPUT(dbblock->dbptr, key_datum, value_datum);
+exim_datum_init(&key_datum); /* Some DBM libraries require the datum */
+exim_datum_init(&value_datum); /* to be cleared before use. */
+exim_datum_data_set(&key_datum, key_copy);
+exim_datum_size_set(&key_datum, klen);
+exim_datum_data_set(&value_datum, ptr);
+exim_datum_size_set(&value_datum, length);
+return exim_dbput(dbblock->dbptr, &key_datum, &value_datum);
}
{
int klen = Ustrlen(key) + 1;
uschar * key_copy = store_get(klen, key);
+EXIM_DATUM key_datum;
memcpy(key_copy, key, klen);
-EXIM_DATUM key_datum;
-EXIM_DATUM_INIT(key_datum); /* Some DBM libraries require clearing */
-EXIM_DATUM_DATA(key_datum) = CS key_copy;
-EXIM_DATUM_SIZE(key_datum) = klen;
-return EXIM_DBDEL(dbblock->dbptr, key_datum);
+exim_datum_init(&key_datum); /* Some DBM libraries require clearing */
+exim_datum_data_set(&key_datum, key_copy);
+exim_datum_size_set(&key_datum, klen);
+return exim_dbdel(dbblock->dbptr, &key_datum);
}
#endif /* EXIM_TIDYDB || EXIM_FIXDB */
cursor a pointer to a pointer to a cursor anchor, for those dbm libraries
that use the notion of a cursor
-Returns: the next record from the file, or
+Returns: the next *key* (nul-terminated) from the file, or
NULL if there are no more
*/
/* Some dbm require an initialization */
-if (start) EXIM_DBCREATE_CURSOR(dbblock->dbptr, cursor);
+if (start) *cursor = exim_dbcreate_cursor(dbblock->dbptr);
-EXIM_DATUM_INIT(key_datum); /* Some DBM libraries require the datum */
-EXIM_DATUM_INIT(value_datum); /* to be cleared before use. */
+exim_datum_init(&key_datum); /* Some DBM libraries require the datum */
+exim_datum_init(&value_datum); /* to be cleared before use. */
-yield = (EXIM_DBSCAN(dbblock->dbptr, key_datum, value_datum, start, *cursor))?
- US EXIM_DATUM_DATA(key_datum) : NULL;
+yield = exim_dbscan(dbblock->dbptr, &key_datum, &value_datum, start, *cursor)
+ ? US exim_datum_data_get(&key_datum) : NULL;
/* Some dbm require a termination */
-if (!yield) EXIM_DBDELETE_CURSOR(*cursor);
+if (!yield) exim_dbdelete_cursor(*cursor);
return yield;
}
#endif /* EXIM_DUMPDB || EXIM_TIDYDB */
uschar keybuffer[1024];
store_init();
-options(argc, argv, US"dumpdb");
+options(argc, argv, US"dumpdb", US"kz");
/* Check the arguments, and open the database */
-dbdata_type = check_args(argc, argv, US"dumpdb", US" [-z]");
+dbdata_type = check_args(argc, argv, US"dumpdb", US" [-z] [-k]");
argc -= optind; argv += optind;
spool_directory = argv[0];
}
Ustrcpy(keybuffer, key);
- if (!(value = dbfn_read_with_length(dbm, keybuffer, &length)))
+ if (keyonly)
+ printf(" %s\n", keybuffer);
+ else if (!(value = dbfn_read_with_length(dbm, keybuffer, &length)))
fprintf(stderr, "**** Entry \"%s\" was in the key scan, but the record "
"was not found in the file - something is wrong!\n",
CS keybuffer);
else
- {
/* Note: don't use print_time more than once in one statement, since
it uses a single buffer. */
print_time(retry->first_failed));
printf("%s ", print_time(retry->last_try));
printf("%s %s\n", print_time(retry->next_try),
- (retry->expired)? "*" : "");
+ retry->expired ? "*" : "");
break;
case type_wait:
printf("%s\t%s\n", keybuffer, print_time(seen->time_stamp));
break;
}
- }
store_reset(reset_point);
}
uschar * aname;
store_init();
-options(argc, argv, US"fixdb");
+options(argc, argv, US"fixdb", US"z");
name[0] = 0; /* No name set */
/* Sort out the database type, verify what we are working on and then process
#endif /* EXIM_TIDYDB */
/* End of exim_dbutil.c */
+/* vi: aw ai sw=2
+*/