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 76static DB *pkgdbp; 77static char pkgdb_dir_default[] = DEF_LOG_DIR; 78static char *pkgdb_dir = pkgdb_dir_default; 79static int pkgdb_dir_prio = 0; 80 81/* 82 * Return name of cache file in the buffer that was passed. 83 */ 84char * 85pkgdb_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 */ 96int 97pkgdb_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 */ 122void 123pkgdb_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 */ 138int 139pkgdb_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 */ 163char * 164pkgdb_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 */ 196int 197pkgdb_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 */ 222int 223pkgdb_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 */ 244int 245pkgdb_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 */ 284char * 285pkgdb_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 */ 300const char * 301pkgdb_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 */ 336void 337pkgdb_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 352char * 353pkgdb_pkg_dir(const char *pkg) 354{ 355 return xasprintf("%s/%s", pkgdb_get_dir(), pkg); 356} 357 358char * 359pkgdb_pkg_file(const char *pkg, const char *file) 360{ 361 return xasprintf("%s/%s/%s", pkgdb_get_dir(), pkg, file); 362} 363