Home | History | Annotate | Line # | Download | only in util
      1 /*	$NetBSD: mkmap_db.c,v 1.2 2023/12/23 20:30:46 christos Exp $	*/
      2 
      3 /*++
      4 /* NAME
      5 /*	mkmap_db 3
      6 /* SUMMARY
      7 /*	create or open database, DB style
      8 /* SYNOPSIS
      9 /*	#include <dict_db.h>
     10 /*
     11 /*	MKMAP	*mkmap_hash_open(path)
     12 /*	const char *path;
     13 /*
     14 /*	MKMAP	*mkmap_btree_open(path)
     15 /*	const char *path;
     16 /* DESCRIPTION
     17 /*	This module implements support for creating DB databases.
     18 /*
     19 /*	mkmap_hash_open() and mkmap_btree_open() take a file name,
     20 /*	append the ".db" suffix, and do whatever initialization is
     21 /*	required before the Berkeley DB open routine is called.
     22 /*
     23 /*	All errors are fatal.
     24 /* SEE ALSO
     25 /*	dict_db(3), DB dictionary interface.
     26 /* LICENSE
     27 /* .ad
     28 /* .fi
     29 /*	The Secure Mailer license must be distributed with this software.
     30 /* AUTHOR(S)
     31 /*	Wietse Venema
     32 /*	IBM T.J. Watson Research
     33 /*	P.O. Box 704
     34 /*	Yorktown Heights, NY 10598, USA
     35 /*
     36 /*	Wietse Venema
     37 /*	Google, Inc.
     38 /*	111 8th Avenue
     39 /*	New York, NY 10011, USA
     40 /*--*/
     41 
     42 /* System library. */
     43 
     44 #include <sys_defs.h>
     45 #include <sys/stat.h>
     46 #include <unistd.h>
     47 #include <errno.h>
     48 
     49 /* Utility library. */
     50 
     51 #include <msg.h>
     52 #include <mymalloc.h>
     53 #include <stringops.h>
     54 #include <dict_db.h>
     55 #include <myflock.h>
     56 #include <warn_stat.h>
     57 
     58 #ifdef HAS_DB
     59 #ifdef PATH_DB_H
     60 #include PATH_DB_H
     61 #else
     62 #include <db.h>
     63 #endif
     64 
     65 typedef struct MKMAP_DB {
     66     MKMAP   mkmap;			/* parent class */
     67     char   *lock_file;			/* path name */
     68     int     lock_fd;			/* -1 or open locked file */
     69 } MKMAP_DB;
     70 
     71 /* mkmap_db_after_close - clean up after closing database */
     72 
     73 static void mkmap_db_after_close(MKMAP *mp)
     74 {
     75     MKMAP_DB *mkmap = (MKMAP_DB *) mp;
     76 
     77     if (mkmap->lock_fd >= 0 && close(mkmap->lock_fd) < 0)
     78 	msg_warn("close %s: %m", mkmap->lock_file);
     79     myfree(mkmap->lock_file);
     80 }
     81 
     82 /* mkmap_db_after_open - lock newly created database */
     83 
     84 static void mkmap_db_after_open(MKMAP *mp)
     85 {
     86     MKMAP_DB *mkmap = (MKMAP_DB *) mp;
     87 
     88     if (mkmap->lock_fd < 0) {
     89 	if ((mkmap->lock_fd = open(mkmap->lock_file, O_RDWR, 0644)) < 0)
     90 	    msg_fatal("open lockfile %s: %m", mkmap->lock_file);
     91 	if (myflock(mkmap->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_EXCLUSIVE) < 0)
     92 	    msg_fatal("lock %s: %m", mkmap->lock_file);
     93     }
     94 }
     95 
     96 /* mkmap_db_before_open - lock existing database */
     97 
     98 static MKMAP *mkmap_db_before_open(const char *path,
     99 			          DICT *(*db_open) (const char *, int, int))
    100 {
    101     MKMAP_DB *mkmap = (MKMAP_DB *) mymalloc(sizeof(*mkmap));
    102     struct stat st;
    103 
    104     /*
    105      * Assumes that  dict_db_cache_size = var_db_create_buf was done in the
    106      * caller, because this code has no access to Postfix variables.
    107      */
    108 
    109     /*
    110      * Fill in the generic members.
    111      */
    112     mkmap->lock_file = concatenate(path, ".db", (char *) 0);
    113     mkmap->mkmap.open = db_open;
    114     mkmap->mkmap.after_open = mkmap_db_after_open;
    115     mkmap->mkmap.after_close = mkmap_db_after_close;
    116 
    117     /*
    118      * Unfortunately, not all systems that might support db databases do
    119      * support locking on open(), so we open the file before updating it.
    120      *
    121      * XXX Berkeley DB 4.1 refuses to open a zero-length file. This means we can
    122      * open and lock only an existing file, and that we must not truncate it.
    123      */
    124     if ((mkmap->lock_fd = open(mkmap->lock_file, O_RDWR, 0644)) < 0) {
    125 	if (errno != ENOENT)
    126 	    msg_fatal("open %s: %m", mkmap->lock_file);
    127     }
    128 
    129     /*
    130      * Get an exclusive lock - we're going to change the database so we can't
    131      * have any spectators.
    132      *
    133      * XXX Horror. Berkeley DB 4.1 refuses to open a zero-length file. This
    134      * means that we must examine the size while the file is locked, and that
    135      * we must unlink a zero-length file while it is locked. Avoid a race
    136      * condition where two processes try to open the same zero-length file
    137      * and where the second process ends up deleting the wrong file.
    138      */
    139     else {
    140 	if (myflock(mkmap->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_EXCLUSIVE) < 0)
    141 	    msg_fatal("lock %s: %m", mkmap->lock_file);
    142 	if (fstat(mkmap->lock_fd, &st) < 0)
    143 	    msg_fatal("fstat %s: %m", mkmap->lock_file);
    144 	if (st.st_size == 0) {
    145 	    if (st.st_nlink > 0) {
    146 		if (unlink(mkmap->lock_file) < 0)
    147 		    msg_fatal("cannot remove zero-length database file %s: %m",
    148 			      mkmap->lock_file);
    149 		msg_warn("removing zero-length database file: %s",
    150 			 mkmap->lock_file);
    151 	    }
    152 	    close(mkmap->lock_fd);
    153 	    mkmap->lock_fd = -1;
    154 	}
    155     }
    156 
    157     return (&mkmap->mkmap);
    158 }
    159 
    160 /* mkmap_hash_open - create or open hashed DB file */
    161 
    162 MKMAP  *mkmap_hash_open(const char *path)
    163 {
    164     return (mkmap_db_before_open(path, dict_hash_open));
    165 }
    166 
    167 /* mkmap_btree_open - create or open btree DB file */
    168 
    169 MKMAP  *mkmap_btree_open(const char *path)
    170 {
    171     return (mkmap_db_before_open(path, dict_btree_open));
    172 }
    173 
    174 #endif
    175