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
79 static DB *pkgdbp;
80 static char pkgdb_dir_default[] = DEF_LOG_DIR;
81 static char *pkgdb_dir = pkgdb_dir_default;
82 static int pkgdb_dir_prio = 0;
83
84 /*
85 * Return name of cache file in the buffer that was passed.
86 */
87 char *
pkgdb_get_database(void)88 pkgdb_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 */
99 int
pkgdb_open(int mode)100 pkgdb_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 */
125 void
pkgdb_close(void)126 pkgdb_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 */
141 int
pkgdb_store(const char * key,const char * val)142 pkgdb_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 */
166 char *
pkgdb_retrieve(const char * key)167 pkgdb_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 */
199 int
pkgdb_dump(void)200 pkgdb_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 */
225 int
pkgdb_remove(const char * key)226 pkgdb_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 */
247 int
pkgdb_remove_pkg(const char * pkg)248 pkgdb_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 */
287 char *
pkgdb_refcount_dir(void)288 pkgdb_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 */
303 const char *
pkgdb_get_dir(void)304 pkgdb_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 */
313 void
pkgdb_set_dir(const char * dir,int prio)314 pkgdb_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
329 char *
pkgdb_pkg_dir(const char * pkg)330 pkgdb_pkg_dir(const char *pkg)
331 {
332 return xasprintf("%s/%s", pkgdb_get_dir(), pkg);
333 }
334
335 char *
pkgdb_pkg_file(const char * pkg,const char * file)336 pkgdb_pkg_file(const char *pkg, const char *file)
337 {
338 return xasprintf("%s/%s/%s", pkgdb_get_dir(), pkg, file);
339 }
340