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