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