1 /*
2 * db_gdbm.c: low level gdbm interface routines for man.
3 *
4 * Copyright (C) 1994, 1995 Graeme W. Wilford. (Wilf.)
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 *
20 * Mon Aug 8 20:35:30 BST 1994 Wilf. (G.Wilford@ee.surrey.ac.uk)
21 */
22
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif /* HAVE_CONFIG_H */
26
27 #ifdef GDBM
28
29 #include <stdbool.h>
30 #include <string.h>
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <setjmp.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <unistd.h>
37
38 #include "stat-time.h"
39 #include "timespec.h"
40 #include "xalloc.h"
41
42 #include "manconfig.h"
43
44 #include "cleanup.h"
45 #include "debug.h"
46
47 #include "db_xdbm.h"
48 #include "mydbm.h"
49
50 /* setjmp/longjmp handling to defend against _gdbm_fatal exiting under our
51 * feet. Not thread-safe, but there is no plan for man-db to ever use
52 * threads.
53 */
54 static jmp_buf open_env;
55 static bool opening;
56
57 /* Mimic _gdbm_fatal's error output, but handle errors during open more
58 * gracefully than exiting.
59 */
60 static void trap_error (const char *val)
61 {
62 if (opening) {
63 debug ("gdbm error: %s\n", val);
64 longjmp (open_env, 1);
65 } else
66 fprintf (stderr, "gdbm fatal: %s\n", val);
67 }
68
69 man_gdbm_wrapper man_gdbm_new (const char *name)
70 {
71 man_gdbm_wrapper wrap;
72
73 wrap = xmalloc (sizeof *wrap);
74 wrap->name = xstrdup (name);
75 wrap->file = NULL;
76 wrap->mtime = NULL;
77
78 return wrap;
79 }
80
81 bool man_gdbm_open_wrapper (man_gdbm_wrapper wrap, int flags)
82 {
83 datum key, content;
84
85 opening = true;
86 if (setjmp (open_env))
87 return false;
88 wrap->file = gdbm_open (wrap->name, BLK_SIZE, flags, DBMODE,
89 trap_error);
90 if (!wrap->file)
91 return false;
92
93 if ((flags & ~GDBM_FAST) != GDBM_NEWDB) {
94 /* While the setjmp/longjmp guard is in effect, make sure we
95 * can read from the database at all.
96 */
97 memset (&key, 0, sizeof key);
98 MYDBM_SET (key, xstrdup (VER_KEY));
99 content = MYDBM_FETCH (wrap, key);
100 MYDBM_FREE_DPTR (key);
101 MYDBM_FREE_DPTR (content);
102 }
103
104 opening = false;
105
106 return true;
107 }
108
109 static datum unsorted_firstkey (man_gdbm_wrapper wrap)
110 {
111 return gdbm_firstkey (wrap->file);
112 }
113
114 static datum unsorted_nextkey (man_gdbm_wrapper wrap, datum key)
115 {
116 return gdbm_nextkey (wrap->file, key);
117 }
118
119 datum man_gdbm_firstkey (man_gdbm_wrapper wrap)
120 {
121 return man_xdbm_firstkey (wrap, unsorted_firstkey, unsorted_nextkey);
122 }
123
124 datum man_gdbm_nextkey (man_gdbm_wrapper wrap, datum key)
125 {
126 return man_xdbm_nextkey (wrap, key);
127 }
128
129 struct timespec man_gdbm_get_time (man_gdbm_wrapper wrap)
130 {
131 struct stat st;
132
133 if (!wrap->mtime) {
134 wrap->mtime = XMALLOC (struct timespec);
135 if (fstat (gdbm_fdesc (wrap->file), &st) < 0) {
136 wrap->mtime->tv_sec = -1;
137 wrap->mtime->tv_nsec = -1;
138 } else
139 *wrap->mtime = get_stat_mtime (&st);
140 }
141
142 return *wrap->mtime;
143 }
144
145 static void raw_close (man_gdbm_wrapper wrap)
146 {
147 if (wrap->file)
148 gdbm_close (wrap->file);
149 }
150
151 void man_gdbm_free (man_gdbm_wrapper wrap)
152 {
153 man_xdbm_free (wrap, raw_close);
154 }
155
156 #ifndef HAVE_GDBM_EXISTS
157
158 int gdbm_exists (GDBM_FILE file, datum key)
159 {
160 char *memory;
161
162 memory = MYDBM_DPTR (gdbm_fetch (file, key));
163 if (memory) {
164 free (memory);
165 return 1;
166 }
167
168 return 0;
169 }
170
171 #endif /* !HAVE_GDBM_EXISTS */
172
173 #endif /* GDBM */