1 /* $NetBSD: pkgdb.c,v 1.6 2021/04/10 19:49:59 nia 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.6 2021/04/10 19:49:59 nia 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 PREFIX "/pkgdb"
74 #endif
75
76 static DB *pkgdbp;
77 static char pkgdb_dir_default[] = DEF_LOG_DIR;
78 static char *pkgdb_dir = pkgdb_dir_default;
79 static int pkgdb_dir_prio = 0;
80
81 /*
82 * Return name of cache file in the buffer that was passed.
83 */
84 char *
pkgdb_get_database(void)85 pkgdb_get_database(void)
86 {
87 return xasprintf("%s/%s", pkgdb_get_dir(), PKGDB_FILE);
88 }
89
90 /*
91 * Open the pkg-database
92 * Return value:
93 * 1: everything ok
94 * 0: error
95 */
96 int
pkgdb_open(int mode)97 pkgdb_open(int mode)
98 {
99 BTREEINFO info;
100 char *cachename;
101
102 /* try our btree format first */
103 info.flags = 0;
104 info.cachesize = 2*1024*1024;
105 info.maxkeypage = 0;
106 info.minkeypage = 0;
107 info.psize = 4096;
108 info.compare = NULL;
109 info.prefix = NULL;
110 info.lorder = 0;
111 cachename = pkgdb_get_database();
112 pkgdbp = (DB *) dbopen(cachename,
113 (mode == ReadOnly) ? O_RDONLY : O_RDWR | O_CREAT,
114 0644, DB_BTREE, (void *) &info);
115 free(cachename);
116 return (pkgdbp != NULL);
117 }
118
119 /*
120 * Close the pkg database
121 */
122 void
pkgdb_close(void)123 pkgdb_close(void)
124 {
125 if (pkgdbp != NULL) {
126 (void) (*pkgdbp->close) (pkgdbp);
127 pkgdbp = NULL;
128 }
129 }
130
131 /*
132 * Store value "val" with key "key" in database
133 * Return value is as from ypdb_store:
134 * 0: ok
135 * 1: key already present
136 * -1: some other error, see errno
137 */
138 int
pkgdb_store(const char * key,const char * val)139 pkgdb_store(const char *key, const char *val)
140 {
141 DBT keyd, vald;
142
143 if (pkgdbp == NULL)
144 return -1;
145
146 keyd.data = __UNCONST(key);
147 keyd.size = strlen(key) + 1;
148 vald.data = __UNCONST(val);
149 vald.size = strlen(val) + 1;
150
151 if (keyd.size > MaxPathSize || vald.size > MaxPathSize)
152 return -1;
153
154 return (*pkgdbp->put) (pkgdbp, &keyd, &vald, R_NOOVERWRITE);
155 }
156
157 /*
158 * Recall value for given key
159 * Return value:
160 * NULL if some error occurred or value for key not found (check errno!)
161 * String for "value" else
162 */
163 char *
pkgdb_retrieve(const char * key)164 pkgdb_retrieve(const char *key)
165 {
166 DBT keyd, vald;
167 int status;
168 char *eos;
169 static int corruption_warning;
170
171 if (pkgdbp == NULL)
172 return NULL;
173
174 keyd.data = __UNCONST(key);
175 keyd.size = strlen(key) + 1;
176 errno = 0; /* to be sure it's 0 if the key doesn't match anything */
177
178 vald.data = (void *)NULL;
179 vald.size = 0;
180 status = (*pkgdbp->get) (pkgdbp, &keyd, &vald, 0);
181 if (status)
182 return NULL;
183 eos = memchr(vald.data, 0, vald.size);
184 if (eos == NULL || eos + 1 != (char *)vald.data + vald.size) {
185 if (!corruption_warning) {
186 warnx("pkgdb corrupted, please run ``pkg_admin rebuild''");
187 corruption_warning = 1;
188 }
189 return NULL;
190 }
191
192 return vald.data;
193 }
194
195 /* dump contents of the database to stdout */
196 int
pkgdb_dump(void)197 pkgdb_dump(void)
198 {
199 DBT key;
200 DBT val;
201 int type;
202
203 if (pkgdb_open(ReadOnly)) {
204 for (type = R_FIRST ; (*pkgdbp->seq)(pkgdbp, &key, &val, type) == 0 ; type = R_NEXT) {
205 printf("file: %.*s pkg: %.*s\n",
206 (int) key.size, (char *) key.data,
207 (int) val.size, (char *) val.data);
208 }
209 pkgdb_close();
210 return 0;
211 } else
212 return -1;
213 }
214
215 /*
216 * Remove data set from pkgdb
217 * Return value as ypdb_delete:
218 * 0: everything ok
219 * 1: key not present
220 * -1: some error occurred (see errno)
221 */
222 int
pkgdb_remove(const char * key)223 pkgdb_remove(const char *key)
224 {
225 DBT keyd;
226
227 if (pkgdbp == NULL)
228 return -1;
229
230 keyd.data = __UNCONST(key);
231 keyd.size = strlen(key) + 1;
232 if (keyd.size > MaxPathSize)
233 return -1;
234
235 return (*pkgdbp->del) (pkgdbp, &keyd, 0);
236 }
237
238 /*
239 * Remove any entry from the cache which has a data field of `pkg'.
240 * Return value:
241 * 1: everything ok
242 * 0: error
243 */
244 int
pkgdb_remove_pkg(const char * pkg)245 pkgdb_remove_pkg(const char *pkg)
246 {
247 DBT data;
248 DBT key;
249 int type;
250 int ret;
251 size_t cc;
252 char *cachename;
253
254 if (pkgdbp == NULL) {
255 return 0;
256 }
257 cachename = pkgdb_get_database();
258 cc = strlen(pkg);
259 for (ret = 1, type = R_FIRST; (*pkgdbp->seq)(pkgdbp, &key, &data, type) == 0 ; type = R_NEXT) {
260 if ((cc + 1) == data.size && strncmp(data.data, pkg, cc) == 0) {
261 if (Verbose) {
262 printf("Removing file `%s' from %s\n", (char *)key.data, cachename);
263 }
264 switch ((*pkgdbp->del)(pkgdbp, &key, 0)) {
265 case -1:
266 warn("Error removing `%s' from %s", (char *)key.data, cachename);
267 ret = 0;
268 break;
269 case 1:
270 warn("Key `%s' not present in %s", (char *)key.data, cachename);
271 ret = 0;
272 break;
273
274 }
275 }
276 }
277 free(cachename);
278 return ret;
279 }
280
281 /*
282 * Return the location of the package reference counts database directory.
283 */
284 char *
pkgdb_refcount_dir(void)285 pkgdb_refcount_dir(void)
286 {
287 static char buf[MaxPathSize];
288 char *tmp;
289
290 if ((tmp = getenv(PKG_REFCOUNT_DBDIR_VNAME)) != NULL)
291 strlcpy(buf, tmp, sizeof(buf));
292 else
293 snprintf(buf, sizeof(buf), "%s.refcount", pkgdb_get_dir());
294 return buf;
295 }
296
297 /*
298 * Return directory where pkgdb is stored
299 */
300 const char *
pkgdb_get_dir(void)301 pkgdb_get_dir(void)
302 {
303
304 #ifdef NETBSD
305 /*
306 * NetBSD upgrade case.
307 * NetBSD used to ship pkg_install with /var/db/pkg as
308 * the default. We support continuing to install to
309 * this location.
310 *
311 * This is NetBSD-specific because we can't assume that
312 * /var/db/pkg is pkgsrc-owned on other systems (OpenBSD,
313 * FreeBSD...)
314 *
315 * XXX: once postinstall is taught to automatically
316 * handle migration, we can deprecate this behaviour.
317 */
318
319 #define PREVIOUS_LOG_DIR "/var/db/pkg"
320 static char pkgdb_dir_previous[] = PREVIOUS_LOG_DIR;
321
322 struct stat sb;
323 if (strcmp(pkgdb_dir, DEF_LOG_DIR) == 0 &&
324 stat(pkgdb_dir, &sb) == -1 && errno == ENOENT &&
325 stat(PREVIOUS_LOG_DIR, &sb) == 0) {
326 return pkgdb_dir_previous;
327 }
328 #endif
329
330 return pkgdb_dir;
331 }
332
333 /*
334 * Set the first place we look for where pkgdb is stored.
335 */
336 void
pkgdb_set_dir(const char * dir,int prio)337 pkgdb_set_dir(const char *dir, int prio)
338 {
339
340 if (prio < pkgdb_dir_prio)
341 return;
342
343 pkgdb_dir_prio = prio;
344
345 if (dir == pkgdb_dir)
346 return;
347 if (pkgdb_dir != pkgdb_dir_default)
348 free(pkgdb_dir);
349 pkgdb_dir = xstrdup(dir);
350 }
351
352 char *
pkgdb_pkg_dir(const char * pkg)353 pkgdb_pkg_dir(const char *pkg)
354 {
355 return xasprintf("%s/%s", pkgdb_get_dir(), pkg);
356 }
357
358 char *
pkgdb_pkg_file(const char * pkg,const char * file)359 pkgdb_pkg_file(const char *pkg, const char *file)
360 {
361 return xasprintf("%s/%s/%s", pkgdb_get_dir(), pkg, file);
362 }
363