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 
58 typedef 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 
mkmap_dbm_after_close(MKMAP * mp)66 static 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 
mkmap_dbm_open(const char * path)77 MKMAP  *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