68 #define SCOPY(buf, data, size) \
69 vstring_str(vstring_strncpy(buf ? buf : (buf = vstring_alloc(10)), data, size))
73 static const char *dict_sdbm_lookup(
DICT *dict,
const char *name)
75 DICT_SDBM *dict_sdbm = (DICT_SDBM *) dict;
78 const char *result = 0;
86 msg_panic(
"dict_sdbm_lookup: no DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL flag");
103 msg_fatal(
"%s: lock dictionary: %m", dict_sdbm->dict.name);
110 dbm_key.dptr = (
void *) name;
111 dbm_key.dsize = strlen(name) + 1;
112 dbm_value = sdbm_fetch(dict_sdbm->dbm, dbm_key);
113 if (dbm_value.dptr != 0) {
115 result = SCOPY(dict_sdbm->val_buf, dbm_value.dptr, dbm_value.dsize);
124 dbm_key.dptr = (
void *) name;
125 dbm_key.dsize = strlen(name);
126 dbm_value = sdbm_fetch(dict_sdbm->dbm, dbm_key);
127 if (dbm_value.dptr != 0) {
129 result = SCOPY(dict_sdbm->val_buf, dbm_value.dptr, dbm_value.dsize);
138 msg_fatal(
"%s: unlock dictionary: %m", dict_sdbm->dict.name);
145 static int dict_sdbm_update(
DICT *dict,
const char *name,
const char *value)
147 DICT_SDBM *dict_sdbm = (DICT_SDBM *) dict;
158 msg_panic(
"dict_sdbm_update: no DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL flag");
169 dbm_key.dptr = (
void *) name;
170 dbm_value.dptr = (
void *) value;
171 dbm_key.dsize = strlen(name);
172 dbm_value.dsize = strlen(value);
180 #ifdef DBM_NO_TRAILING_NULL
200 msg_fatal(
"%s: lock dictionary: %m", dict_sdbm->dict.name);
205 if ((status = sdbm_store(dict_sdbm->dbm, dbm_key, dbm_value,
207 msg_fatal(
"error writing SDBM database %s: %m", dict_sdbm->dict.name);
212 msg_warn(
"%s: duplicate entry: \"%s\"", dict_sdbm->dict.name, name);
214 msg_fatal(
"%s: duplicate entry: \"%s\"", dict_sdbm->dict.name, name);
222 msg_fatal(
"%s: unlock dictionary: %m", dict_sdbm->dict.name);
229 static int dict_sdbm_delete(
DICT *dict,
const char *name)
231 DICT_SDBM *dict_sdbm = (DICT_SDBM *) dict;
241 msg_panic(
"dict_sdbm_delete: no DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL flag");
258 msg_fatal(
"%s: lock dictionary: %m", dict_sdbm->dict.name);
265 dbm_key.dptr = (
void *) name;
266 dbm_key.dsize = strlen(name) + 1;
267 sdbm_clearerr(dict_sdbm->dbm);
268 if ((status = sdbm_delete(dict_sdbm->dbm, dbm_key)) < 0) {
269 if (sdbm_error(dict_sdbm->dbm) != 0)
270 msg_fatal(
"error deleting from %s: %m", dict_sdbm->dict.name);
282 dbm_key.dptr = (
void *) name;
283 dbm_key.dsize = strlen(name);
284 sdbm_clearerr(dict_sdbm->dbm);
285 if ((status = sdbm_delete(dict_sdbm->dbm, dbm_key)) < 0) {
286 if (sdbm_error(dict_sdbm->dbm) != 0)
287 msg_fatal(
"error deleting from %s: %m", dict_sdbm->dict.name);
299 msg_fatal(
"%s: unlock dictionary: %m", dict_sdbm->dict.name);
306 static int dict_sdbm_sequence(
DICT *dict,
const int function,
307 const char **key,
const char **value)
309 const char *myname =
"dict_sdbm_sequence";
310 DICT_SDBM *dict_sdbm = (DICT_SDBM *) dict;
322 msg_fatal(
"%s: lock dictionary: %m", dict_sdbm->dict.name);
327 sdbm_clearerr(dict_sdbm->dbm);
330 dbm_key = sdbm_firstkey(dict_sdbm->dbm);
333 dbm_key = sdbm_nextkey(dict_sdbm->dbm);
336 msg_panic(
"%s: invalid function: %d", myname,
function);
339 if (dbm_key.dptr != 0 && dbm_key.dsize > 0) {
344 *key = SCOPY(dict_sdbm->key_buf, dbm_key.dptr, dbm_key.dsize);
349 dbm_value = sdbm_fetch(dict_sdbm->dbm, dbm_key);
351 if (dbm_value.dptr != 0 && dbm_value.dsize > 0) {
356 *value = SCOPY(dict_sdbm->val_buf, dbm_value.dptr, dbm_value.dsize);
364 if (sdbm_error(dict_sdbm->dbm))
365 msg_fatal(
"error seeking %s: %m", dict_sdbm->dict.name);
374 if (sdbm_error(dict_sdbm->dbm))
375 msg_fatal(
"error seeking %s: %m", dict_sdbm->dict.name);
384 msg_fatal(
"%s: unlock dictionary: %m", dict_sdbm->dict.name);
391 static void dict_sdbm_close(
DICT *dict)
393 DICT_SDBM *dict_sdbm = (DICT_SDBM *) dict;
395 sdbm_close(dict_sdbm->dbm);
396 if (dict_sdbm->key_buf)
398 if (dict_sdbm->val_buf)
409 DICT_SDBM *dict_sdbm;
424 if ((lock_fd = open(dbm_path, open_flags, 0644)) < 0)
425 msg_fatal(
"open database %s: %m", dbm_path);
427 msg_fatal(
"shared-lock database %s for open: %m", dbm_path);
433 if ((dbm = sdbm_open((
char *) path, open_flags, 0644)) == 0)
434 msg_fatal(
"open database %s.{dir,pag}: %m", path);
436 if (dict_flags & DICT_FLAG_LOCK) {
438 msg_fatal(
"unlock database %s for open: %m", dbm_path);
439 if (close(lock_fd) < 0)
440 msg_fatal(
"close database %s: %m", dbm_path);
443 dict_sdbm->dict.
lookup = dict_sdbm_lookup;
444 dict_sdbm->dict.update = dict_sdbm_update;
445 dict_sdbm->dict.delete = dict_sdbm_delete;
446 dict_sdbm->dict.sequence = dict_sdbm_sequence;
447 dict_sdbm->dict.close = dict_sdbm_close;
448 dict_sdbm->dict.lock_fd = sdbm_dirfno(dbm);
449 dict_sdbm->dict.stat_fd = sdbm_pagfno(dbm);
450 if (
fstat(dict_sdbm->dict.stat_fd, &st) < 0)
452 dict_sdbm->dict.mtime = st.st_mtime;
453 dict_sdbm->dict.owner.uid = st.st_uid;
454 dict_sdbm->dict.owner.status = (st.st_uid != 0);
460 if ((dict_flags & DICT_FLAG_LOCK) != 0
461 &&
stat(path, &st) == 0
462 && st.st_mtime > dict_sdbm->dict.mtime
463 && st.st_mtime < time((time_t *) 0) - 100)
464 msg_warn(
"database %s is older than source file %s", dbm_path, path);
473 dict_sdbm->dbm = dbm;
474 dict_sdbm->key_buf = 0;
475 dict_sdbm->val_buf = 0;
477 if ((dict_flags & DICT_FLAG_LOCK))
#define DICT_FLAG_DUP_IGNORE
#define MYFLOCK_OP_SHARED
#define DICT_SEQ_FUN_FIRST
NORETURN msg_panic(const char *fmt,...)
#define DICT_SEQ_FUN_NEXT
#define MYFLOCK_OP_EXCLUSIVE
#define DICT_FLAG_FOLD_FIX
VSTRING * vstring_strcpy(VSTRING *vp, const char *src)
#define DICT_FLAG_DUP_REPLACE
#define DICT_FLAG_TRY1NULL
void msg_warn(const char *fmt,...)
VSTRING * vstring_alloc(ssize_t len)
int myflock(int fd, int lock_style, int operation)
char * lowercase(char *string)
const char *(* lookup)(struct DICT *, const char *)
#define DICT_FLAG_DUP_WARN
NORETURN msg_fatal(const char *fmt,...)
char * concatenate(const char *arg0,...)
VSTRING * vstring_free(VSTRING *vp)
DICT * dict_sdbm_open(const char *, int, int)
DICT * dict_alloc(const char *, const char *, ssize_t)
#define DICT_FLAG_TRY0NULL
int close_on_exec(int fd, int on)