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