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