343 lines
7.3 KiB
C
343 lines
7.3 KiB
C
/* $NetBSD: pkgdb.c,v 1.39 2010/04/20 21:22:38 joerg Exp $ */
|
|
|
|
#if HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
#ifndef __minix
|
|
#include <nbcompat.h>
|
|
#endif
|
|
#if HAVE_SYS_CDEFS_H
|
|
#include <sys/cdefs.h>
|
|
#endif
|
|
#ifndef __minix
|
|
__RCSID("$NetBSD: pkgdb.c,v 1.39 2010/04/20 21:22:38 joerg Exp $");
|
|
#endif
|
|
|
|
/*-
|
|
* Copyright (c) 1999-2010 The NetBSD Foundation, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This code is derived from software contributed to The NetBSD Foundation
|
|
* by Hubert Feyrer <hubert@feyrer.de>.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#if defined(NETBSD) || defined(__minix)
|
|
#include <db.h>
|
|
#else
|
|
#include <nbcompat/db.h>
|
|
#endif
|
|
#if HAVE_ERR_H
|
|
#include <err.h>
|
|
#endif
|
|
#if HAVE_ERRNO_H
|
|
#include <errno.h>
|
|
#endif
|
|
#if HAVE_FCNTL_H
|
|
#include <fcntl.h>
|
|
#endif
|
|
#if HAVE_STDARG_H
|
|
#include <stdarg.h>
|
|
#endif
|
|
#if HAVE_STDIO_H
|
|
#include <stdio.h>
|
|
#endif
|
|
#if HAVE_STRING_H
|
|
#include <string.h>
|
|
#endif
|
|
|
|
#include "lib.h"
|
|
|
|
#define PKGDB_FILE "pkgdb.byfile.db" /* indexed by filename */
|
|
|
|
/*
|
|
* Where we put logging information by default if PKG_DBDIR is unset.
|
|
*/
|
|
#ifndef DEF_LOG_DIR
|
|
#define DEF_LOG_DIR "/var/db/pkg"
|
|
#endif
|
|
|
|
/* just in case we change the environment variable name */
|
|
#define PKG_DBDIR "PKG_DBDIR"
|
|
|
|
static DB *pkgdbp;
|
|
static char pkgdb_dir_default[] = DEF_LOG_DIR;
|
|
static char *pkgdb_dir = pkgdb_dir_default;
|
|
static int pkgdb_dir_prio = 0;
|
|
|
|
/*
|
|
* Return name of cache file in the buffer that was passed.
|
|
*/
|
|
char *
|
|
pkgdb_get_database(void)
|
|
{
|
|
return xasprintf("%s/%s", pkgdb_get_dir(), PKGDB_FILE);
|
|
}
|
|
|
|
/*
|
|
* Open the pkg-database
|
|
* Return value:
|
|
* 1: everything ok
|
|
* 0: error
|
|
*/
|
|
int
|
|
pkgdb_open(int mode)
|
|
{
|
|
BTREEINFO info;
|
|
char *cachename;
|
|
|
|
/* try our btree format first */
|
|
info.flags = 0;
|
|
info.cachesize = 2*1024*1024;
|
|
info.maxkeypage = 0;
|
|
info.minkeypage = 0;
|
|
info.psize = 4096;
|
|
info.compare = NULL;
|
|
info.prefix = NULL;
|
|
info.lorder = 0;
|
|
cachename = pkgdb_get_database();
|
|
pkgdbp = (DB *) dbopen(cachename,
|
|
(mode == ReadOnly) ? O_RDONLY : O_RDWR | O_CREAT,
|
|
0644, DB_BTREE, (void *) &info);
|
|
free(cachename);
|
|
return (pkgdbp != NULL);
|
|
}
|
|
|
|
/*
|
|
* Close the pkg database
|
|
*/
|
|
void
|
|
pkgdb_close(void)
|
|
{
|
|
if (pkgdbp != NULL) {
|
|
(void) (*pkgdbp->close) (pkgdbp);
|
|
pkgdbp = NULL;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Store value "val" with key "key" in database
|
|
* Return value is as from ypdb_store:
|
|
* 0: ok
|
|
* 1: key already present
|
|
* -1: some other error, see errno
|
|
*/
|
|
int
|
|
pkgdb_store(const char *key, const char *val)
|
|
{
|
|
DBT keyd, vald;
|
|
|
|
if (pkgdbp == NULL)
|
|
return -1;
|
|
|
|
keyd.data = __UNCONST(key);
|
|
keyd.size = strlen(key) + 1;
|
|
vald.data = __UNCONST(val);
|
|
vald.size = strlen(val) + 1;
|
|
|
|
if (keyd.size > MaxPathSize || vald.size > MaxPathSize)
|
|
return -1;
|
|
|
|
return (*pkgdbp->put) (pkgdbp, &keyd, &vald, R_NOOVERWRITE);
|
|
}
|
|
|
|
/*
|
|
* Recall value for given key
|
|
* Return value:
|
|
* NULL if some error occurred or value for key not found (check errno!)
|
|
* String for "value" else
|
|
*/
|
|
char *
|
|
pkgdb_retrieve(const char *key)
|
|
{
|
|
DBT keyd, vald;
|
|
int status;
|
|
char *eos;
|
|
static int corruption_warning;
|
|
|
|
if (pkgdbp == NULL)
|
|
return NULL;
|
|
|
|
keyd.data = __UNCONST(key);
|
|
keyd.size = strlen(key) + 1;
|
|
errno = 0; /* to be sure it's 0 if the key doesn't match anything */
|
|
|
|
vald.data = (void *)NULL;
|
|
vald.size = 0;
|
|
status = (*pkgdbp->get) (pkgdbp, &keyd, &vald, 0);
|
|
if (status)
|
|
return NULL;
|
|
eos = memchr(vald.data, 0, vald.size);
|
|
if (eos == NULL || eos + 1 != (char *)vald.data + vald.size) {
|
|
if (!corruption_warning) {
|
|
warnx("pkgdb corrupted, please run ``pkg_admin rebuild''");
|
|
corruption_warning = 1;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
return vald.data;
|
|
}
|
|
|
|
/* dump contents of the database to stdout */
|
|
int
|
|
pkgdb_dump(void)
|
|
{
|
|
DBT key;
|
|
DBT val;
|
|
int type;
|
|
|
|
if (pkgdb_open(ReadOnly)) {
|
|
for (type = R_FIRST ; (*pkgdbp->seq)(pkgdbp, &key, &val, type) == 0 ; type = R_NEXT) {
|
|
printf("file: %.*s pkg: %.*s\n",
|
|
(int) key.size, (char *) key.data,
|
|
(int) val.size, (char *) val.data);
|
|
}
|
|
pkgdb_close();
|
|
return 0;
|
|
} else
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* Remove data set from pkgdb
|
|
* Return value as ypdb_delete:
|
|
* 0: everything ok
|
|
* 1: key not present
|
|
* -1: some error occurred (see errno)
|
|
*/
|
|
int
|
|
pkgdb_remove(const char *key)
|
|
{
|
|
DBT keyd;
|
|
|
|
if (pkgdbp == NULL)
|
|
return -1;
|
|
|
|
keyd.data = __UNCONST(key);
|
|
keyd.size = strlen(key) + 1;
|
|
if (keyd.size > MaxPathSize)
|
|
return -1;
|
|
|
|
return (*pkgdbp->del) (pkgdbp, &keyd, 0);
|
|
}
|
|
|
|
/*
|
|
* Remove any entry from the cache which has a data field of `pkg'.
|
|
* Return value:
|
|
* 1: everything ok
|
|
* 0: error
|
|
*/
|
|
int
|
|
pkgdb_remove_pkg(const char *pkg)
|
|
{
|
|
DBT data;
|
|
DBT key;
|
|
int type;
|
|
int ret;
|
|
size_t cc;
|
|
char *cachename;
|
|
|
|
if (pkgdbp == NULL) {
|
|
return 0;
|
|
}
|
|
cachename = pkgdb_get_database();
|
|
cc = strlen(pkg);
|
|
for (ret = 1, type = R_FIRST; (*pkgdbp->seq)(pkgdbp, &key, &data, type) == 0 ; type = R_NEXT) {
|
|
if ((cc + 1) == data.size && strncmp(data.data, pkg, cc) == 0) {
|
|
if (Verbose) {
|
|
printf("Removing file `%s' from %s\n", (char *)key.data, cachename);
|
|
}
|
|
switch ((*pkgdbp->del)(pkgdbp, &key, 0)) {
|
|
case -1:
|
|
warn("Error removing `%s' from %s", (char *)key.data, cachename);
|
|
ret = 0;
|
|
break;
|
|
case 1:
|
|
warn("Key `%s' not present in %s", (char *)key.data, cachename);
|
|
ret = 0;
|
|
break;
|
|
|
|
}
|
|
}
|
|
}
|
|
free(cachename);
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Return the location of the package reference counts database directory.
|
|
*/
|
|
char *
|
|
pkgdb_refcount_dir(void)
|
|
{
|
|
static char buf[MaxPathSize];
|
|
char *tmp;
|
|
|
|
if ((tmp = getenv(PKG_REFCOUNT_DBDIR_VNAME)) != NULL)
|
|
strlcpy(buf, tmp, sizeof(buf));
|
|
else
|
|
snprintf(buf, sizeof(buf), "%s.refcount", pkgdb_get_dir());
|
|
return buf;
|
|
}
|
|
|
|
/*
|
|
* Return directory where pkgdb is stored
|
|
*/
|
|
const char *
|
|
pkgdb_get_dir(void)
|
|
{
|
|
|
|
return pkgdb_dir;
|
|
}
|
|
|
|
/*
|
|
* Set the first place we look for where pkgdb is stored.
|
|
*/
|
|
void
|
|
pkgdb_set_dir(const char *dir, int prio)
|
|
{
|
|
|
|
if (prio < pkgdb_dir_prio)
|
|
return;
|
|
|
|
pkgdb_dir_prio = prio;
|
|
|
|
if (dir == pkgdb_dir)
|
|
return;
|
|
if (pkgdb_dir != pkgdb_dir_default)
|
|
free(pkgdb_dir);
|
|
pkgdb_dir = xstrdup(dir);
|
|
}
|
|
|
|
char *
|
|
pkgdb_pkg_dir(const char *pkg)
|
|
{
|
|
return xasprintf("%s/%s", pkgdb_get_dir(), pkg);
|
|
}
|
|
|
|
char *
|
|
pkgdb_pkg_file(const char *pkg, const char *file)
|
|
{
|
|
return xasprintf("%s/%s/%s", pkgdb_get_dir(), pkg, file);
|
|
}
|