1/*	$NetBSD$	*/
2
3/*++
4/* NAME
5/*	mkmap_dbm 3
6/* SUMMARY
7/*	create or open database, DBM style
8/* SYNOPSIS
9/*	#include <mkmap.h>
10/*
11/*	MKMAP	*mkmap_dbm_open(path)
12/*	const char *path;
13/* DESCRIPTION
14/*	This module implements support for creating DBM databases.
15/*
16/*	mkmap_dbm_open() takes a file name, appends the ".dir" and ".pag"
17/*	suffixes, and creates or opens the named DBM database.
18/*	This routine is a DBM-specific helper for the more general
19/*	mkmap_open() routine.
20/*
21/*	All errors are fatal.
22/* SEE ALSO
23/*	dict_dbm(3), DBM dictionary interface.
24/* LICENSE
25/* .ad
26/* .fi
27/*	The Secure Mailer license must be distributed with this software.
28/* AUTHOR(S)
29/*	Wietse Venema
30/*	IBM T.J. Watson Research
31/*	P.O. Box 704
32/*	Yorktown Heights, NY 10598, USA
33/*--*/
34
35/* System library. */
36
37#include <sys_defs.h>
38#include <unistd.h>
39
40/* Utility library. */
41
42#include <msg.h>
43#include <mymalloc.h>
44#include <stringops.h>
45#include <dict.h>
46#include <dict_dbm.h>
47#include <myflock.h>
48
49/* Application-specific. */
50
51#include "mkmap.h"
52
53#ifdef HAS_DBM
54#ifdef PATH_NDBM_H
55#include PATH_NDBM_H
56#else
57#include <ndbm.h>
58#endif
59
60typedef struct MKMAP_DBM {
61    MKMAP   mkmap;			/* parent class */
62    char   *lock_file;			/* path name */
63    int     lock_fd;			/* -1 or open locked file */
64} MKMAP_DBM;
65
66/* mkmap_dbm_after_close - clean up after closing database */
67
68static void mkmap_dbm_after_close(MKMAP *mp)
69{
70    MKMAP_DBM *mkmap = (MKMAP_DBM *) mp;
71
72    if (mkmap->lock_fd >= 0 && close(mkmap->lock_fd) < 0)
73	msg_warn("close %s: %m", mkmap->lock_file);
74    myfree(mkmap->lock_file);
75}
76
77/* mkmap_dbm_open - create or open database */
78
79MKMAP  *mkmap_dbm_open(const char *path)
80{
81    MKMAP_DBM *mkmap = (MKMAP_DBM *) mymalloc(sizeof(*mkmap));
82    char   *pag_file;
83    int     pag_fd;
84
85    /*
86     * Fill in the generic members.
87     */
88    mkmap->lock_file = concatenate(path, ".dir", (char *) 0);
89    mkmap->mkmap.open = dict_dbm_open;
90    mkmap->mkmap.after_open = 0;
91    mkmap->mkmap.after_close = mkmap_dbm_after_close;
92
93    /*
94     * Unfortunately, not all systems support locking on open(), so we open
95     * the .dir and .pag files before truncating them. Keep one file open for
96     * locking.
97     */
98    if ((mkmap->lock_fd = open(mkmap->lock_file, O_CREAT | O_RDWR, 0644)) < 0)
99	msg_fatal("open %s: %m", mkmap->lock_file);
100
101    pag_file = concatenate(path, ".pag", (char *) 0);
102    if ((pag_fd = open(pag_file, O_CREAT | O_RDWR, 0644)) < 0)
103	msg_fatal("open %s: %m", pag_file);
104    if (close(pag_fd))
105	msg_warn("close %s: %m", pag_file);
106    myfree(pag_file);
107
108    /*
109     * Get an exclusive lock - we're going to change the database so we can't
110     * have any spectators.
111     */
112    if (myflock(mkmap->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_EXCLUSIVE) < 0)
113	msg_fatal("lock %s: %m", mkmap->lock_file);
114
115    return (&mkmap->mkmap);
116}
117
118#endif
119