Home | History | Annotate | Line # | Download | only in lib
      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 (at) 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 *
     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
     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
    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
    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   *
    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
    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
    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
    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 *
    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 *
    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
    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 *
    353 pkgdb_pkg_dir(const char *pkg)
    354 {
    355 	return xasprintf("%s/%s", pkgdb_get_dir(), pkg);
    356 }
    357 
    358 char *
    359 pkgdb_pkg_file(const char *pkg, const char *file)
    360 {
    361 	return xasprintf("%s/%s/%s", pkgdb_get_dir(), pkg, file);
    362 }
    363