summaryrefslogtreecommitdiffstats
path: root/libdb/db_gdbm.c
blob: 99dbcfe9e831c6d96117a238e8af6bb657aa371f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
/*
 * db_gdbm.c: low level gdbm interface routines for man.
 *
 * Copyright (C) 1994, 1995 Graeme W. Wilford. (Wilf.)
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Mon Aug  8 20:35:30 BST 1994  Wilf. (G.Wilford@ee.surrey.ac.uk)
 */

#ifdef HAVE_CONFIG_H
#  include "config.h"
#endif /* HAVE_CONFIG_H */

#ifdef GDBM

#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <setjmp.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

#include "stat-time.h"
#include "timespec.h"
#include "xalloc.h"

#include "manconfig.h"

#include "cleanup.h"
#include "debug.h"

#include "db_xdbm.h"
#include "mydbm.h"

/* setjmp/longjmp handling to defend against _gdbm_fatal exiting under our
 * feet.  Not thread-safe, but there is no plan for man-db to ever use
 * threads.
 */
static jmp_buf open_env;
static bool opening;

/* Mimic _gdbm_fatal's error output, but handle errors during open more
 * gracefully than exiting.
 */
static void trap_error (const char *val)
{
	if (opening) {
		debug ("gdbm error: %s\n", val);
		longjmp (open_env, 1);
	} else
		fprintf (stderr, "gdbm fatal: %s\n", val);
}

man_gdbm_wrapper man_gdbm_new (const char *name)
{
	man_gdbm_wrapper wrap;

	wrap = xmalloc (sizeof *wrap);
	wrap->name = xstrdup (name);
	wrap->file = NULL;
	wrap->mtime = NULL;

	return wrap;
}

bool man_gdbm_open_wrapper (man_gdbm_wrapper wrap, int flags)
{
	datum key, content;

	opening = true;
	if (setjmp (open_env))
		return false;
	wrap->file = gdbm_open (wrap->name, BLK_SIZE, flags, DBMODE,
				trap_error);
	if (!wrap->file)
		return false;

	if ((flags & ~GDBM_FAST) != GDBM_NEWDB) {
		/* While the setjmp/longjmp guard is in effect, make sure we
		 * can read from the database at all.
		 */
		memset (&key, 0, sizeof key);
		MYDBM_SET (key, xstrdup (VER_KEY));
		content = MYDBM_FETCH (wrap, key);
		MYDBM_FREE_DPTR (key);
		MYDBM_FREE_DPTR (content);
	}

	opening = false;

	return true;
}

static datum unsorted_firstkey (man_gdbm_wrapper wrap)
{
	return gdbm_firstkey (wrap->file);
}

static datum unsorted_nextkey (man_gdbm_wrapper wrap, datum key)
{
	return gdbm_nextkey (wrap->file, key);
}

datum man_gdbm_firstkey (man_gdbm_wrapper wrap)
{
	return man_xdbm_firstkey (wrap, unsorted_firstkey, unsorted_nextkey);
}

datum man_gdbm_nextkey (man_gdbm_wrapper wrap, datum key)
{
	return man_xdbm_nextkey (wrap, key);
}

struct timespec man_gdbm_get_time (man_gdbm_wrapper wrap)
{
	struct stat st;

	if (!wrap->mtime) {
		wrap->mtime = XMALLOC (struct timespec);
		if (fstat (gdbm_fdesc (wrap->file), &st) < 0) {
			wrap->mtime->tv_sec = -1;
			wrap->mtime->tv_nsec = -1;
		} else
			*wrap->mtime = get_stat_mtime (&st);
	}

	return *wrap->mtime;
}

static void raw_close (man_gdbm_wrapper wrap)
{
	if (wrap->file)
		gdbm_close (wrap->file);
}

void man_gdbm_free (man_gdbm_wrapper wrap)
{
	man_xdbm_free (wrap, raw_close);
}

#ifndef HAVE_GDBM_EXISTS

int gdbm_exists (GDBM_FILE file, datum key)
{
	char *memory;

	memory = MYDBM_DPTR (gdbm_fetch (file, key));
	if (memory) {
		free (memory);
		return 1;
	}

	return 0;
}

#endif /* !HAVE_GDBM_EXISTS */

#endif /* GDBM */