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