1/*	$NetBSD: pkgdb.c,v 1.1.1.8 2010/04/23 20:54:11 joerg Exp $	*/
2
3#if HAVE_CONFIG_H
4#include "config.h"
5#endif
6#include <nbcompat.h>
7#if HAVE_SYS_CDEFS_H
8#include <sys/cdefs.h>
9#endif
10__RCSID("$NetBSD: pkgdb.c,v 1.1.1.8 2010/04/23 20:54:11 joerg Exp $");
11
12/*-
13 * Copyright (c) 1999-2010 The NetBSD Foundation, Inc.
14 * All rights reserved.
15 *
16 * This code is derived from software contributed to The NetBSD Foundation
17 * by Hubert Feyrer <hubert@feyrer.de>.
18 *
19 * Redistribution and use in source and binary forms, with or without
20 * modification, are permitted provided that the following conditions
21 * are met:
22 * 1. Redistributions of source code must retain the above copyright
23 *    notice, this list of conditions and the following disclaimer.
24 * 2. Redistributions in binary form must reproduce the above copyright
25 *    notice, this list of conditions and the following disclaimer in the
26 *    documentation and/or other materials provided with the distribution.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
29 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
32 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38 * POSSIBILITY OF SUCH DAMAGE.
39 */
40
41#ifdef NETBSD
42#include <db.h>
43#else
44#include <nbcompat/db.h>
45#endif
46#if HAVE_ERR_H
47#include <err.h>
48#endif
49#if HAVE_ERRNO_H
50#include <errno.h>
51#endif
52#if HAVE_FCNTL_H
53#include <fcntl.h>
54#endif
55#if HAVE_STDARG_H
56#include <stdarg.h>
57#endif
58#if HAVE_STDIO_H
59#include <stdio.h>
60#endif
61#if HAVE_STRING_H
62#include <string.h>
63#endif
64
65#include "lib.h"
66
67#define PKGDB_FILE	"pkgdb.byfile.db"	/* indexed by filename */
68
69/*
70 * Where we put logging information by default if PKG_DBDIR is unset.
71 */
72#ifndef DEF_LOG_DIR
73#define DEF_LOG_DIR		"/var/db/pkg"
74#endif
75
76/* just in case we change the environment variable name */
77#define PKG_DBDIR		"PKG_DBDIR"
78
79static DB   *pkgdbp;
80static char pkgdb_dir_default[] = DEF_LOG_DIR;
81static char *pkgdb_dir = pkgdb_dir_default;
82static int pkgdb_dir_prio = 0;
83
84/*
85 *  Return name of cache file in the buffer that was passed.
86 */
87char *
88pkgdb_get_database(void)
89{
90	return xasprintf("%s/%s", pkgdb_get_dir(), PKGDB_FILE);
91}
92
93/*
94 *  Open the pkg-database
95 *  Return value:
96 *   1: everything ok
97 *   0: error
98 */
99int
100pkgdb_open(int mode)
101{
102	BTREEINFO info;
103	char *cachename;
104
105	/* try our btree format first */
106	info.flags = 0;
107	info.cachesize = 2*1024*1024;
108	info.maxkeypage = 0;
109	info.minkeypage = 0;
110	info.psize = 4096;
111	info.compare = NULL;
112	info.prefix = NULL;
113	info.lorder = 0;
114	cachename = pkgdb_get_database();
115	pkgdbp = (DB *) dbopen(cachename,
116	    (mode == ReadOnly) ? O_RDONLY : O_RDWR | O_CREAT,
117	    0644, DB_BTREE, (void *) &info);
118	free(cachename);
119	return (pkgdbp != NULL);
120}
121
122/*
123 * Close the pkg database
124 */
125void
126pkgdb_close(void)
127{
128	if (pkgdbp != NULL) {
129		(void) (*pkgdbp->close) (pkgdbp);
130		pkgdbp = NULL;
131	}
132}
133
134/*
135 * Store value "val" with key "key" in database
136 * Return value is as from ypdb_store:
137 *  0: ok
138 *  1: key already present
139 * -1: some other error, see errno
140 */
141int
142pkgdb_store(const char *key, const char *val)
143{
144	DBT     keyd, vald;
145
146	if (pkgdbp == NULL)
147		return -1;
148
149	keyd.data = __UNCONST(key);
150	keyd.size = strlen(key) + 1;
151	vald.data = __UNCONST(val);
152	vald.size = strlen(val) + 1;
153
154	if (keyd.size > MaxPathSize || vald.size > MaxPathSize)
155		return -1;
156
157	return (*pkgdbp->put) (pkgdbp, &keyd, &vald, R_NOOVERWRITE);
158}
159
160/*
161 * Recall value for given key
162 * Return value:
163 *  NULL if some error occurred or value for key not found (check errno!)
164 *  String for "value" else
165 */
166char   *
167pkgdb_retrieve(const char *key)
168{
169	DBT     keyd, vald;
170	int     status;
171	char	*eos;
172	static int corruption_warning;
173
174	if (pkgdbp == NULL)
175		return NULL;
176
177	keyd.data = __UNCONST(key);
178	keyd.size = strlen(key) + 1;
179	errno = 0;		/* to be sure it's 0 if the key doesn't match anything */
180
181	vald.data = (void *)NULL;
182	vald.size = 0;
183	status = (*pkgdbp->get) (pkgdbp, &keyd, &vald, 0);
184	if (status)
185		return NULL;
186	eos = memchr(vald.data, 0, vald.size);
187	if (eos == NULL || eos + 1 != (char *)vald.data + vald.size) {
188		if (!corruption_warning) {
189			warnx("pkgdb corrupted, please run ``pkg_admin rebuild''");
190			corruption_warning = 1;
191		}
192		return NULL;
193	}
194
195	return vald.data;
196}
197
198/* dump contents of the database to stdout */
199int
200pkgdb_dump(void)
201{
202	DBT     key;
203	DBT	val;
204	int	type;
205
206	if (pkgdb_open(ReadOnly)) {
207		for (type = R_FIRST ; (*pkgdbp->seq)(pkgdbp, &key, &val, type) == 0 ; type = R_NEXT) {
208			printf("file: %.*s pkg: %.*s\n",
209				(int) key.size, (char *) key.data,
210				(int) val.size, (char *) val.data);
211		}
212		pkgdb_close();
213		return 0;
214	} else
215		return -1;
216}
217
218/*
219 *  Remove data set from pkgdb
220 *  Return value as ypdb_delete:
221 *   0: everything ok
222 *   1: key not present
223 *  -1: some error occurred (see errno)
224 */
225int
226pkgdb_remove(const char *key)
227{
228	DBT     keyd;
229
230	if (pkgdbp == NULL)
231		return -1;
232
233	keyd.data = __UNCONST(key);
234	keyd.size = strlen(key) + 1;
235	if (keyd.size > MaxPathSize)
236		return -1;
237
238	return (*pkgdbp->del) (pkgdbp, &keyd, 0);
239}
240
241/*
242 *  Remove any entry from the cache which has a data field of `pkg'.
243 *  Return value:
244 *   1: everything ok
245 *   0: error
246 */
247int
248pkgdb_remove_pkg(const char *pkg)
249{
250	DBT     data;
251	DBT     key;
252	int	type;
253	int	ret;
254	size_t	cc;
255	char	*cachename;
256
257	if (pkgdbp == NULL) {
258		return 0;
259	}
260	cachename = pkgdb_get_database();
261	cc = strlen(pkg);
262	for (ret = 1, type = R_FIRST; (*pkgdbp->seq)(pkgdbp, &key, &data, type) == 0 ; type = R_NEXT) {
263		if ((cc + 1) == data.size && strncmp(data.data, pkg, cc) == 0) {
264			if (Verbose) {
265				printf("Removing file `%s' from %s\n", (char *)key.data, cachename);
266			}
267			switch ((*pkgdbp->del)(pkgdbp, &key, 0)) {
268			case -1:
269				warn("Error removing `%s' from %s", (char *)key.data, cachename);
270				ret = 0;
271				break;
272			case 1:
273				warn("Key `%s' not present in %s", (char *)key.data, cachename);
274				ret = 0;
275				break;
276
277			}
278		}
279	}
280	free(cachename);
281	return ret;
282}
283
284/*
285 *  Return the location of the package reference counts database directory.
286 */
287char *
288pkgdb_refcount_dir(void)
289{
290	static char buf[MaxPathSize];
291	char *tmp;
292
293	if ((tmp = getenv(PKG_REFCOUNT_DBDIR_VNAME)) != NULL)
294		strlcpy(buf, tmp, sizeof(buf));
295	else
296		snprintf(buf, sizeof(buf), "%s.refcount", pkgdb_get_dir());
297	return buf;
298}
299
300/*
301 *  Return directory where pkgdb is stored
302 */
303const char *
304pkgdb_get_dir(void)
305{
306
307	return pkgdb_dir;
308}
309
310/*
311 *  Set the first place we look for where pkgdb is stored.
312 */
313void
314pkgdb_set_dir(const char *dir, int prio)
315{
316
317	if (prio < pkgdb_dir_prio)
318		return;
319
320	pkgdb_dir_prio = prio;
321
322	if (dir == pkgdb_dir)
323		return;
324	if (pkgdb_dir != pkgdb_dir_default)
325		free(pkgdb_dir);
326	pkgdb_dir = xstrdup(dir);
327}
328
329char *
330pkgdb_pkg_dir(const char *pkg)
331{
332	return xasprintf("%s/%s", pkgdb_get_dir(), pkg);
333}
334
335char *
336pkgdb_pkg_file(const char *pkg, const char *file)
337{
338	return xasprintf("%s/%s/%s", pkgdb_get_dir(), pkg, file);
339}
340