1/*	$NetBSD$	*/
2
3/*++
4/* NAME
5/*	mkmap_sdbm 3
6/* SUMMARY
7/*	create or open database, SDBM style
8/* SYNOPSIS
9/*	#include <mkmap.h>
10/*
11/*	MKMAP	*mkmap_sdbm_open(path)
12/*	const char *path;
13/* DESCRIPTION
14/*	This module implements support for creating SDBM databases.
15/*
16/*	mkmap_sdbm_open() takes a file name, appends the ".dir" and ".pag"
17/*	suffixes, and creates or opens the named SDBM database.
18/*	This routine is a SDBM-specific helper for the more general
19/*	mkmap_open() routine.
20/*
21/*	All errors are fatal.
22/* SEE ALSO
23/*	dict_sdbm(3), SDBM 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_sdbm.h>
47#include <myflock.h>
48
49/* Application-specific. */
50
51#include "mkmap.h"
52
53#ifdef HAS_SDBM
54
55#include <sdbm.h>
56
57typedef struct MKMAP_SDBM {
58    MKMAP   mkmap;			/* parent class */
59    char   *lock_file;			/* path name */
60    int     lock_fd;			/* -1 or open locked file */
61} MKMAP_SDBM;
62
63/* mkmap_sdbm_after_close - clean up after closing database */
64
65static void mkmap_sdbm_after_close(MKMAP *mp)
66{
67    MKMAP_SDBM *mkmap = (MKMAP_SDBM *) mp;
68
69    if (mkmap->lock_fd >= 0 && close(mkmap->lock_fd) < 0)
70	msg_warn("close %s: %m", mkmap->lock_file);
71    myfree(mkmap->lock_file);
72}
73
74/* mkmap_sdbm_open - create or open database */
75
76MKMAP  *mkmap_sdbm_open(const char *path)
77{
78    MKMAP_SDBM *mkmap = (MKMAP_SDBM *) mymalloc(sizeof(*mkmap));
79    char   *pag_file;
80    int     pag_fd;
81
82    /*
83     * Fill in the generic members.
84     */
85    mkmap->lock_file = concatenate(path, ".dir", (char *) 0);
86    mkmap->mkmap.open = dict_sdbm_open;
87    mkmap->mkmap.after_open = 0;
88    mkmap->mkmap.after_close = mkmap_sdbm_after_close;
89
90    /*
91     * Unfortunately, not all systems support locking on open(), so we open
92     * the .dir and .pag files before truncating them. Keep one file open for
93     * locking.
94     */
95    if ((mkmap->lock_fd = open(mkmap->lock_file, O_CREAT | O_RDWR, 0644)) < 0)
96	msg_fatal("open %s: %m", mkmap->lock_file);
97
98    pag_file = concatenate(path, ".pag", (char *) 0);
99    if ((pag_fd = open(pag_file, O_CREAT | O_RDWR, 0644)) < 0)
100	msg_fatal("open %s: %m", pag_file);
101    if (close(pag_fd))
102	msg_warn("close %s: %m", pag_file);
103    myfree(pag_file);
104
105    /*
106     * Get an exclusive lock - we're going to change the database so we can't
107     * have any spectators.
108     */
109    if (myflock(mkmap->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_EXCLUSIVE) < 0)
110	msg_fatal("lock %s: %m", mkmap->lock_file);
111
112    return (&mkmap->mkmap);
113}
114
115#endif
116