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