Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
Merge branch 'master' of github.com:pkgng/pkgng
Matthew Seaman committed 13 years ago
commit 4e36617dfdb484b3a141816367cba350ead48972
parent 0f369e1
13 files changed +678 -48
modified AUTHORS
@@ -5,6 +5,9 @@ Julien Laffaye <jlaffaye@FreeBSD.org>

Contributors:

+
All contributors can be seen on github:
+
https://github.com/pkgng/pkgng/graphs/contributors
+

Philippe Pepiot <phil@philpep.org>
Will Andrews <will@FreeBSD.org>
Marin Atanasov Nikolov <dnaeon@gmail.com>
modified libpkg/Makefile
@@ -11,6 +11,7 @@ SHLIB_MAJOR= 0
#gr_utils.c has to be deleted as soon as it goes in base
SRCS=		backup.c \
		dns_utils.c \
+
		elfhints.c \
		fetch.c \
		packing.c \
		pkg.c \
@@ -46,7 +47,6 @@ CFLAGS+= -std=c99
CFLAGS+=	-I${.CURDIR} \
		-I${.CURDIR}/../external/sqlite \
		-I${.CURDIR}/../external/libyaml/include
-
STATIC_CFLAGS+=	-DSTATIC_LINKAGE
LDADD+=		-L${.OBJDIR}/../external/sqlite \
		-L${.OBJDIR}/../external/libyaml \
		-lsqlite3 \
added libpkg/elfhints.c
@@ -0,0 +1,502 @@
+
/*-
+
 * Copyright (c) 1998 John D. Polstra
+
 * Copyright (c) 2012 Matthew Seaman <matthew@FreeBSD.org>
+
 * All rights reserved.
+
 *
+
 * 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 AUTHOR 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 AUTHOR 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.
+
 *
+
 * $FreeBSD: stable/8/sbin/ldconfig/elfhints.c 76224 2001-05-02 23:56:21Z obrien $
+
 */
+

+
#include <sys/param.h>
+
#include <sys/mman.h>
+
#include <sys/stat.h>
+
#include <sys/queue.h>
+

+
#include <assert.h>
+
#include <ctype.h>
+
#include <dirent.h>
+
#include <elf-hints.h>
+
#include <err.h>
+
#include <errno.h>
+
#include <fcntl.h>
+
#include <stdio.h>
+
#include <stdlib.h>
+
#include <string.h>
+
#include <unistd.h>
+

+
#include "pkg.h"
+
#include "private/ldconfig.h"
+

+
#define MAXDIRS		1024		/* Maximum directories in path */
+
#define MAXFILESIZE	(16*1024)	/* Maximum hints file size */
+

+
struct shlib_list_entry {
+
	STAILQ_ENTRY(shlib_list_entry) next;
+
	const char *name;
+
	char path[];
+
};
+

+
STAILQ_HEAD(shlib_list, shlib_list_entry);
+

+
static int	shlib_list_add(struct shlib_list *shlib_list, const char *dir,
+
			       const char *shlib_file);
+
static int	scan_dirs_for_shlibs(struct shlib_list *shlib_list, int numdirs,
+
				     const char **dirlist);
+
static void	add_dir(const char *, const char *, int);
+
static void	read_dirs_from_file(const char *, const char *);
+
static void	read_elf_hints(const char *, int);
+
static void	write_elf_hints(const char *);
+

+
static const char	*dirs[MAXDIRS];
+
static int		 ndirs;
+
int			 insecure;
+

+
/* Known shlibs on the standard system search path.  Persistent,
+
   common to all applications */
+
static struct shlib_list shlibs;
+

+
/* Known shlibs on the specific RPATH or RUNPATH of one binary.
+
   Evanescent. */
+
static struct shlib_list rpath;
+

+
void
+
shlib_list_init(void)
+
{
+
	STAILQ_INIT(&shlibs);
+
}
+

+
void
+
rpath_list_init(void)
+
{
+
	STAILQ_INIT(&rpath);
+
}
+

+
static int
+
shlib_list_add(struct shlib_list *shlib_list, const char *dir,
+
    const char *shlib_file)
+
{
+
	struct shlib_list_entry	*sl;
+
	size_t	path_len, dir_len;
+

+
	path_len = strlen(dir) + strlen(shlib_file) + 2;
+

+
	sl = calloc(1, sizeof(struct shlib_list_entry) + path_len);
+
	if (sl == NULL) {
+
		warnx("Out of memory");
+
		return (EPKG_FATAL);
+
	}
+

+
	strlcat(sl->path, dir, path_len);
+
	dir_len = strlcat(sl->path, "/", path_len);
+
	strlcat(sl->path, shlib_file, path_len);
+
	
+
	sl->name = sl->path + dir_len;
+

+
	STAILQ_INSERT_TAIL(shlib_list, sl, next);
+

+
	return (EPKG_OK);
+
}
+

+
const char *
+
shlib_list_find_by_name(const char *shlib_file)
+
{
+
	struct shlib_list_entry *sl;
+

+
	assert(!STAILQ_EMPTY(&shlibs));
+

+
	STAILQ_FOREACH(sl, &rpath, next) {
+
		if (strcmp(sl->name, shlib_file) == 0)
+
			return (sl->path);
+
	}
+
	STAILQ_FOREACH(sl, &shlibs, next) {
+
		if (strcmp(sl->name, shlib_file) == 0)
+
			return (sl->path);
+
	}
+
	return (NULL);
+
}
+

+
void
+
shlib_list_free()
+
{
+
	struct shlib_list_entry *sl1, *sl2;
+

+
	sl1 = STAILQ_FIRST(&shlibs);
+
	while (sl1 != NULL) {
+
		sl2 = STAILQ_NEXT(sl1, next);
+
		free(sl1);
+
		sl1 = sl2;
+
	}
+
	STAILQ_INIT(&shlibs);
+
}
+

+
void
+
rpath_list_free()
+
{
+
	struct shlib_list_entry *sl1, *sl2;
+

+
	sl1 = STAILQ_FIRST(&rpath);
+
	while (sl1 != NULL) {
+
		sl2 = STAILQ_NEXT(sl1, next);
+
		free(sl1);
+
		sl1 = sl2;
+
	}
+
	STAILQ_INIT(&rpath);
+
}
+

+
static void
+
add_dir(const char *hintsfile, const char *name, int trusted)
+
{
+
	struct stat 	stbuf;
+
	int		i;
+

+
	/* Do some security checks */
+
	if (!trusted && !insecure) {
+
		if (stat(name, &stbuf) == -1) {
+
			warn("%s", name);
+
			return;
+
		}
+
		if (stbuf.st_uid != 0) {
+
			warnx("%s: ignoring directory not owned by root", name);
+
			return;
+
		}
+
		if ((stbuf.st_mode & S_IWOTH) != 0) {
+
			warnx("%s: ignoring world-writable directory", name);
+
			return;
+
		}
+
		if ((stbuf.st_mode & S_IWGRP) != 0) {
+
			warnx("%s: ignoring group-writable directory", name);
+
			return;
+
		}
+
	}
+

+
	for (i = 0;  i < ndirs;  i++)
+
		if (strcmp(dirs[i], name) == 0)
+
			return;
+
	if (ndirs >= MAXDIRS)
+
		errx(1, "\"%s\": Too many directories in path", hintsfile);
+
	dirs[ndirs++] = name;
+
}
+

+
static int
+
scan_dirs_for_shlibs(struct shlib_list *shlib_list, int numdirs,
+
    const char **dirlist)
+
{
+
	int	i;
+

+
	for (i = 0;  i < numdirs;  i++) {
+
		DIR		*dirp;
+
		struct dirent	*dp;
+

+
		if ((dirp = opendir(dirlist[i])) == NULL)
+
			continue;
+
		while ((dp = readdir(dirp)) != NULL) {
+
			int		 len;
+
			int		 ret;
+
			const char	*vers;
+

+
			/* Only regular files and sym-links */
+
			if (dp->d_type != DT_REG && dp->d_type != DT_LNK)
+
				continue;
+

+
			/* Name can't be shorter than "libx.so" */
+
			if ((len = strlen(dp->d_name)) < 7 ||
+
			    strncmp(dp->d_name, "lib", 3) != 0)
+
				continue;
+
			vers = dp->d_name + len;
+
			while (vers > dp->d_name && isdigit(*(vers-1)))
+
				vers--;
+
			if (vers == dp->d_name + len) {
+
				if (strncmp(vers - 3, ".so", 3) != 0)
+
					continue;
+
			} else if (vers < dp->d_name + 4 ||
+
			    strncmp(vers - 4, ".so.", 4) != 0)
+
				continue;
+

+
			/* We have a valid shared library name. */
+
			ret = shlib_list_add(shlib_list, dirlist[i], dp->d_name);
+
			if (ret != EPKG_OK) {
+
				closedir(dirp);
+
				return ret;
+
			}
+
		}
+
		closedir(dirp);
+
	}
+
	return 0;
+
}
+

+
int shlib_list_from_rpath(const char *rpath_str)
+
{
+
	const char    **dirlist;
+
	char	       *buf;
+
	size_t		buflen;
+
	int		i, numdirs;
+
	int		ret;
+
	const char     *c;
+
	
+
	numdirs = 1;
+
	for (c = rpath_str; *c != '\0'; c++)
+
		if (*c == ':')
+
			numdirs++;
+
	buflen = numdirs * sizeof(char *) + strlen(rpath_str) + 1;
+
	dirlist = calloc(1, buflen);
+
	if (dirlist == NULL) {
+
		warnx("Out of memory");
+
		return (EPKG_FATAL);
+
	}
+
	buf = (char *)dirlist + numdirs * sizeof(char *);
+
	strcpy(buf, rpath_str);
+

+
	i = 0;
+
	while ((c = strsep(&buf, ":")) != NULL) {
+
		if (strlen(c) > 0)
+
			dirlist[i++] = c;
+
	}
+

+
	assert(i <= numdirs);
+

+
	ret = scan_dirs_for_shlibs(&rpath, i, dirlist);
+

+
	free(dirlist);
+

+
	return (ret);
+
}
+

+
int 
+
shlib_list_from_elf_hints(const char *hintsfile)
+
{
+
	read_elf_hints(hintsfile, 1);
+

+
	return (scan_dirs_for_shlibs(&shlibs, ndirs, dirs));
+
}
+

+
void
+
list_elf_hints(const char *hintsfile)
+
{
+
	int	i;
+
	int	nlibs;
+

+
	read_elf_hints(hintsfile, 1);
+
	printf("%s:\n", hintsfile);
+
	printf("\tsearch directories:");
+
	for (i = 0;  i < ndirs;  i++)
+
		printf("%c%s", i == 0 ? ' ' : ':', dirs[i]);
+
	printf("\n");
+

+
	nlibs = 0;
+
	for (i = 0;  i < ndirs;  i++) {
+
		DIR		*dirp;
+
		struct dirent	*dp;
+

+
		if ((dirp = opendir(dirs[i])) == NULL)
+
			continue;
+
		while ((dp = readdir(dirp)) != NULL) {
+
			int		 len;
+
			int		 namelen;
+
			const char	*name;
+
			const char	*vers;
+

+
			/* Name can't be shorter than "libx.so.0" */
+
			if ((len = strlen(dp->d_name)) < 9 ||
+
			    strncmp(dp->d_name, "lib", 3) != 0)
+
				continue;
+
			name = dp->d_name + 3;
+
			vers = dp->d_name + len;
+
			while (vers > dp->d_name && isdigit(*(vers-1)))
+
				vers--;
+
			if (vers == dp->d_name + len)
+
				continue;
+
			if (vers < dp->d_name + 4 ||
+
			    strncmp(vers - 4, ".so.", 4) != 0)
+
				continue;
+

+
			/* We have a valid shared library name. */
+
			namelen = (vers - 4) - name;
+
			printf("\t%d:-l%.*s.%s => %s/%s\n", nlibs,
+
			    namelen, name, vers, dirs[i], dp->d_name);
+
			nlibs++;
+
		}
+
		closedir(dirp);
+
	}
+
}
+

+
static void
+
read_dirs_from_file(const char *hintsfile, const char *listfile)
+
{
+
	FILE	*fp;
+
	char	 buf[MAXPATHLEN];
+
	int	 linenum;
+

+
	if ((fp = fopen(listfile, "r")) == NULL)
+
		err(1, "%s", listfile);
+

+
	linenum = 0;
+
	while (fgets(buf, sizeof buf, fp) != NULL) {
+
		char	*cp, *sp;
+

+
		linenum++;
+
		cp = buf;
+
		/* Skip leading white space. */
+
		while (isspace(*cp))
+
			cp++;
+
		if (*cp == '#' || *cp == '\0')
+
			continue;
+
		sp = cp;
+
		/* Advance over the directory name. */
+
		while (!isspace(*cp) && *cp != '\0')
+
			cp++;
+
		/* Terminate the string and skip trailing white space. */
+
		if (*cp != '\0') {
+
			*cp++ = '\0';
+
			while (isspace(*cp))
+
				cp++;
+
		}
+
		/* Now we had better be at the end of the line. */
+
		if (*cp != '\0')
+
			warnx("%s:%d: trailing characters ignored",
+
			    listfile, linenum);
+

+
		if ((sp = strdup(sp)) == NULL)
+
			errx(1, "Out of memory");
+
		add_dir(hintsfile, sp, 0);
+
	}
+

+
	fclose(fp);
+
}
+

+
static void
+
read_elf_hints(const char *hintsfile, int must_exist)
+
{
+
	int	 		 fd;
+
	struct stat		 s;
+
	void			*mapbase;
+
	struct elfhints_hdr	*hdr;
+
	char			*strtab;
+
	char			*dirlist;
+
	char			*p;
+

+
	if ((fd = open(hintsfile, O_RDONLY)) == -1) {
+
		if (errno == ENOENT && !must_exist)
+
			return;
+
		err(1, "Cannot open \"%s\"", hintsfile);
+
	}
+
	if (fstat(fd, &s) == -1)
+
		err(1, "Cannot stat \"%s\"", hintsfile);
+
	if (s.st_size > MAXFILESIZE)
+
		errx(1, "\"%s\" is unreasonably large", hintsfile);
+
	/*
+
	 * We use a read-write, private mapping so that we can null-terminate
+
	 * some strings in it without affecting the underlying file.
+
	 */
+
	mapbase = mmap(NULL, s.st_size, PROT_READ|PROT_WRITE,
+
	    MAP_PRIVATE, fd, 0);
+
	if (mapbase == MAP_FAILED)
+
		err(1, "Cannot mmap \"%s\"", hintsfile);
+
	close(fd);
+

+
	hdr = (struct elfhints_hdr *)mapbase;
+
	if (hdr->magic != ELFHINTS_MAGIC)
+
		errx(1, "\"%s\": invalid file format", hintsfile);
+
	if (hdr->version != 1)
+
		errx(1, "\"%s\": unrecognized file version (%d)", hintsfile,
+
		    hdr->version);
+

+
	strtab = (char *)mapbase + hdr->strtab;
+
	dirlist = strtab + hdr->dirlist;
+

+
	if (*dirlist != '\0')
+
		while ((p = strsep(&dirlist, ":")) != NULL)
+
			add_dir(hintsfile, p, 1);
+
}
+

+
void
+
update_elf_hints(const char *hintsfile, int argc, char **argv, int merge)
+
{
+
	int	i;
+

+
	if (merge)
+
		read_elf_hints(hintsfile, 0);
+
	for (i = 0;  i < argc;  i++) {
+
		struct stat	s;
+

+
		if (stat(argv[i], &s) == -1)
+
			warn("warning: %s", argv[i]);
+
		else if (S_ISREG(s.st_mode))
+
			read_dirs_from_file(hintsfile, argv[i]);
+
		else
+
			add_dir(hintsfile, argv[i], 0);
+
	}
+
	write_elf_hints(hintsfile);
+
}
+

+
static void
+
write_elf_hints(const char *hintsfile)
+
{
+
	struct elfhints_hdr	 hdr;
+
	char			*tempname;
+
	int			 fd;
+
	FILE			*fp;
+
	int			 i;
+

+
	if (asprintf(&tempname, "%s.XXXXXX", hintsfile) == -1)
+
		errx(1, "Out of memory");
+
	if ((fd = mkstemp(tempname)) ==  -1)
+
		err(1, "mkstemp(%s)", tempname);
+
	if (fchmod(fd, 0444) == -1)
+
		err(1, "fchmod(%s)", tempname);
+
	if ((fp = fdopen(fd, "wb")) == NULL)
+
		err(1, "fdopen(%s)", tempname);
+

+
	hdr.magic = ELFHINTS_MAGIC;
+
	hdr.version = 1;
+
	hdr.strtab = sizeof hdr;
+
	hdr.strsize = 0;
+
	hdr.dirlist = 0;
+
	memset(hdr.spare, 0, sizeof hdr.spare);
+

+
	/* Count up the size of the string table. */
+
	if (ndirs > 0) {
+
		hdr.strsize += strlen(dirs[0]);
+
		for (i = 1;  i < ndirs;  i++)
+
			hdr.strsize += 1 + strlen(dirs[i]);
+
	}
+
	hdr.dirlistlen = hdr.strsize;
+
	hdr.strsize++;	/* For the null terminator */
+

+
	/* Write the header. */
+
	if (fwrite(&hdr, 1, sizeof hdr, fp) != sizeof hdr)
+
		err(1, "%s: write error", tempname);
+
	/* Write the strings. */
+
	if (ndirs > 0) {
+
		if (fputs(dirs[0], fp) == EOF)
+
			err(1, "%s: write error", tempname);
+
		for (i = 1;  i < ndirs;  i++)
+
			if (fprintf(fp, ":%s", dirs[i]) < 0)
+
				err(1, "%s: write error", tempname);
+
	}
+
	if (putc('\0', fp) == EOF || fclose(fp) == EOF)
+
		err(1, "%s: write error", tempname);
+

+
	if (rename(tempname, hintsfile) == -1)
+
		err(1, "rename %s to %s", tempname, hintsfile);
+
	free(tempname);
+
}
modified libpkg/pkg.c
@@ -240,6 +240,28 @@ pkg_get2(struct pkg const *const pkg, ...)
	return (ret);
}

+
const char *
+
pkg_name(struct pkg const *const pkg)
+
{
+
	assert(pkg != NULL);
+

+
	if (pkg->fields[PKG_NAME] != NULL)
+
		return (sbuf_get(pkg->fields[PKG_NAME]));
+
	else
+
		return (NULL);
+
}
+

+
const char *
+
pkg_version(struct pkg const *const pkg)
+
{
+
	assert(pkg != NULL);
+

+
	if (pkg->fields[PKG_VERSION] != NULL)
+
		return (sbuf_get(pkg->fields[PKG_VERSION]));
+
	else
+
		return (NULL);
+
}
+

static void
pkg_set_repourl(struct pkg *pkg, const char *str)
{
modified libpkg/pkg.h
@@ -362,6 +362,13 @@ pkg_t pkg_type(struct pkg const * const);
int pkg_get2(struct pkg const *const, ...);
#define pkg_get(pkg, ...) pkg_get2(pkg, __VA_ARGS__, -1)

+
/**
+
 * Specific getters for simple attributes.
+
 * @return NULL-terminated string.
+
 */
+
const char *pkg_name(struct pkg const *const pkg);
+
const char *pkg_version(struct pkg const *const pkg);
+

int pkg_list_is_empty(struct pkg *, pkg_list);
/**
 * Iterates over the dependencies of the package.
modified libpkg/pkg_elf.c
@@ -30,52 +30,45 @@
#include <sys/elf_common.h>
#include <sys/stat.h>

-
#include <ctype.h>
#include <assert.h>
-
#include <fcntl.h>
+
#include <ctype.h>
#include <dlfcn.h>
+
#include <elf-hints.h>
+
#include <err.h>
+
#include <fcntl.h>
#include <gelf.h>
#include <link.h>
#include <stdbool.h>
-
#include <unistd.h>
#include <string.h>
+
#include <unistd.h>

#include "pkg.h"
#include "private/pkg.h"
#include "private/event.h"
#include "private/elf_tables.h"
+
#include "private/ldconfig.h"
+

+
/* FFR: when we support installing a 32bit package on a 64bit host */
+
#define _PATH_ELF32_HINTS       "/var/run/ld-elf32.so.hints"

static int
filter_system_shlibs(const char *name, char *path, size_t pathlen)
{
-
	void *handle;
-
	Link_map *map;
-

-
#ifdef STATIC_LINKAGE
-
	/* Can't use dlopen() in a statically linked program */
-
	return (EPKG_END);
-
#endif
+
	const char *shlib_path;

-
	if ((handle = dlopen(name, RTLD_LAZY)) == NULL) {
-
		pkg_emit_error("accessing shared library %s failed -- %s",
-
		    name, dlerror());
+
	shlib_path = shlib_list_find_by_name(name);
+
	if (shlib_path == NULL) {
		return (EPKG_FATAL);
	}

-
	dlinfo(handle, RTLD_DI_LINKMAP, &map);
-

	/* match /lib, /lib32, /usr/lib and /usr/lib32 */
-
	if (strncmp(map->l_name, "/lib", 4) == 0 ||
-
	    strncmp(map->l_name, "/usr/lib", 7) == 0) {
-
		/* ignore libs from base */
-
		dlclose(handle);
-
		return (EPKG_END);
-
	}
+
	if (strncmp(shlib_path, "/lib", 4) == 0 ||
+
	    strncmp(shlib_path, "/usr/lib", 7) == 0)
+
		return (EPKG_END); /* ignore libs from base */

	if (path != NULL)
-
		strncpy(path, map->l_name, pathlen);
+
		strncpy(path, shlib_path, pathlen);

-
	dlclose(handle);
	return (EPKG_OK);
} 

@@ -100,6 +93,8 @@ add_shlibs_to_pkg(__unused void *actdata, struct pkg *pkg, const char *name)
	case EPKG_END:		/* A system library */
		return (EPKG_OK);
	default:
+
		warnx("(%s-%s) shared library %s not found", pkg_name(pkg),
+
		      pkg_version(pkg), name);
		return (EPKG_FATAL);
	}
}
@@ -126,6 +121,8 @@ test_depends(void *actdata, struct pkg *pkg, const char *name)
	case EPKG_END:		/* A system library */
		return (EPKG_OK);
	default:
+
		warnx("(%s-%s) shared library %s not found", pkg_name(pkg),
+
		      pkg_version(pkg), name);
		return (EPKG_FATAL);
	}

@@ -163,7 +160,7 @@ test_depends(void *actdata, struct pkg *pkg, const char *name)

static int
analyse_elf(struct pkg *pkg, const char *fpath, 
-
	    int (action)(void *, struct pkg *, const char *), void *actdata)
+
    int (action)(void *, struct pkg *, const char *), void *actdata)
{
	Elf *e = NULL;
	GElf_Ehdr elfhdr;
@@ -275,6 +272,30 @@ analyse_elf(struct pkg *pkg, const char *fpath,

	data = elf_getdata(dynamic, NULL);

+
	/* First, scan through the data from the .dynamic section to
+
	   find any RPATH or RUNPATH settings.  These are colon
+
	   separated paths to prepend to the ld.so search paths from
+
	   the ELF hints file.  These always seem to come right after
+
	   the NEEDED entries */
+

+
	rpath_list_init();
+
	for (dynidx = 0; dynidx < numdyn; dynidx++) {
+
		if ((dyn = gelf_getdyn(data, dynidx, &dyn_mem)) == NULL) {
+
			ret = EPKG_FATAL;
+
			pkg_emit_error("getdyn() failed for %s: %s", fpath,
+
			    elf_errmsg(-1));
+
			goto cleanup;
+
		}
+

+
		if (dyn->d_tag != DT_RPATH && dyn->d_tag != DT_RUNPATH)
+
			continue;
+

+
		shlib_list_from_rpath(elf_strptr(e, sh_link, dyn->d_un.d_val));
+
		break;
+
	}
+

+
	/* Now find all of the NEEDED shared libraries */
+

	for (dynidx = 0; dynidx < numdyn; dynidx++) {
		if ((dyn = gelf_getdyn(data, dynidx, &dyn_mem)) == NULL) {
			ret = EPKG_FATAL;
@@ -290,6 +311,8 @@ analyse_elf(struct pkg *pkg, const char *fpath,
	}

cleanup:
+
	rpath_list_free();
+

	if (e != NULL)
		elf_end(e);
	close(fd);
@@ -345,6 +368,14 @@ pkg_analyse_files(struct pkgdb *db, struct pkg *pkg)
	else
		action = do_nothing;

+
	if (autodeps || shlibs) {
+
		shlib_list_init();
+

+
		ret = shlib_list_from_elf_hints(_PATH_ELF_HINTS);
+
		if (ret != EPKG_OK)
+
			goto cleanup;
+
	}
+

	/* Assume no architecture dependence, for contradiction */
	if (developer)
		pkg->flags &= ~(PKG_CONTAINS_ELF_OBJECTS |
@@ -356,19 +387,25 @@ pkg_analyse_files(struct pkgdb *db, struct pkg *pkg)
		ret = analyse_elf(pkg, fpath, action, db);
		if (developer) {
			if (ret != EPKG_OK && ret != EPKG_END)
-
				return (ret);
+
				goto cleanup;
			analyse_fpath(pkg, fpath);
		}
	}

-
	return (EPKG_OK);
+
	ret = EPKG_OK;
+

+
cleanup:
+
	if (autodeps || shlibs)
+
		shlib_list_free();
+

+
	return (ret);
}

int
pkg_register_shlibs(struct pkg *pkg)
{
-
	struct pkg_file *file = NULL;
-
	bool shlibs;
+
	struct pkg_file        *file = NULL;
+
	bool			shlibs;

	pkg_config_bool(PKG_CONFIG_SHLIBS, &shlibs);

@@ -380,9 +417,16 @@ pkg_register_shlibs(struct pkg *pkg)
	if (elf_version(EV_CURRENT) == EV_NONE)
		return (EPKG_FATAL);

+
	shlib_list_init();
+
	if (shlib_list_from_elf_hints(_PATH_ELF_HINTS) != EPKG_OK) {
+
		shlib_list_free();
+
		return (EPKG_FATAL);
+
	}
+

	while(pkg_files(pkg, &file) == EPKG_OK)
		analyse_elf(pkg, pkg_file_path(file), add_shlibs_to_pkg, NULL);

+
	shlib_list_free();
	return (EPKG_OK);
}

modified libpkg/pkgdb.c
@@ -3358,7 +3358,7 @@ pkgdb_vset(struct pkgdb *db, int64_t id, va_list ap)
		[PKG_SET_DEPORIGIN] =
		    "UPDATE deps SET origin=?1, "
		    "name=(SELECT name FROM packages WHERE origin=?1), "
-
		    "version=(SELECT version FROM packages WHERE origin=?1), "
+
		    "version=(SELECT version FROM packages WHERE origin=?1) "
		    "WHERE package_id=?2 AND origin=?3",
		[PKG_SET_ORIGIN]    =
		    "UPDATE packages SET origin=?1 WHERE id=?2",
added libpkg/private/ldconfig.h
@@ -0,0 +1,50 @@
+
/*-
+
 * Copyright (c) 1998 John D. Polstra
+
 * All rights reserved.
+
 *
+
 * 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 AUTHOR 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 AUTHOR 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.
+
 *
+
 * $FreeBSD: stable/8/sbin/ldconfig/ldconfig.h 92882 2002-03-21 13:14:21Z imp $
+
 */
+

+
#ifndef LDCONFIG_H
+
#define LDCONFIG_H 1
+

+
#include <sys/cdefs.h>
+
#include <sys/queue.h>
+

+
extern int	insecure;	/* -i flag, needed here for elfhints.c */
+

+
__BEGIN_DECLS
+
void		shlib_list_init(void);
+
void		rpath_list_init(void);
+
const char     *shlib_list_find_by_name(const char *);
+
void		shlib_list_free(void);
+
void		rpath_list_free(void);
+
int		shlib_list_from_elf_hints(const char *);
+
int		shlib_list_from_rpath(const char *);
+

+
void		list_elf_hints(const char *);
+
void		update_elf_hints(const char *, int, char **, int);
+
__END_DECLS
+

+
#endif
modified pkg-static/Makefile
@@ -1,6 +1,5 @@
PROG=pkg-static

-
CFLAGS+=	-DSTATIC_LINKAGE
STATIC_PKGNG=	yes
NO_SHARED?=	yes
NO_MAN=		yes
modified pkg/pkg-install.8
@@ -116,7 +116,8 @@ Don't auto update repository catalogues with
.Xr pkg-update 8 .
Use the locally cached copies only.
.It Fl n
-
Dry-run mode.  The list of changes to packages is always printed, but
+
Dry-run mode.
+
The list of changes to packages is always printed, but
no changes are actually made.
.It Fl q
Force quiet output, except when
modified pkg/pkg-query.8
@@ -15,7 +15,7 @@
.\"     @(#)pkg.8
.\" $FreeBSD$
.\"
-
.Dd April 25, 2012
+
.Dd July 18, 2012
.Dt PKG-QUERY 8
.Os
.Sh NAME
@@ -163,8 +163,6 @@ Expands to the list of license(s) for the matched package.
Expands to the list of users needed by the matched package.
.It Cm \&%G
Expands to the list of groups needed by the matched package.
-
.It Cm \&%S
-
Expands to the list of scripts for the matching packages - install, deinstall, etc.
.It Cm \&%B
Expands to the list of shared libraries used by programs from the matched package.
.El
modified pkg/pkg-search.8
@@ -61,7 +61,7 @@ The following options are supported by
Search for packages with comment text matching
.Ar pattern .
Equivalent to
-
.Fl "S comment" . 
+
.Fl "S comment" .
.It Fl D
Display the list of packages depended on by each matched package.
Equivalent to
@@ -77,7 +77,7 @@ should be an exact match against the search field.
.It Fl f
Show ``full'' information about the package.
Equivalent to
-
.Fl "M full" . 
+
.Fl "M full" .
.It Fl g
Treat
.Ar pattern
@@ -92,7 +92,7 @@ Several different fields from the repository catalogue database may be
used to search on, or to generate the label, as indicated by the
.Ar label
argument.
-
See the 
+
See the
.Qq Sx Search and Label Options
section for details.
If unspecified,
@@ -104,7 +104,8 @@ option.
Modify the output by adding an additional field to the result.
Multiple fields can be added by using additional
.Fl M Ar mod
-
flags.  See the
+
flags.
+
See the
.Qq Sx Output Modifier Options
section for details.
.It Fl o
@@ -115,7 +116,7 @@ Equivalent to
.It Fl p
Display the package installation prefix for each matched package.
Equivalent to
-
.Fl "M prefix" . 
+
.Fl "M prefix" .
.It Fl q
Be ``quiet''.
Produce less output.
@@ -129,7 +130,7 @@ By default all known repository catalogues are searched.
Specify the field to search the repository catalogue on.
If unspecified, searches on
.Ar pkg-name
-
unless the search term contains a 
+
unless the search term contains a
.Sy /
character, when it searches on port
.Ar origin .
@@ -142,7 +143,7 @@ sections for more details.
.It Fl s
Display the installed size of matched packages.
Equivalent to
-
.Fl "M size" . 
+
.Fl "M size" .
.It Fl X
Treat
.Ar pattern
@@ -152,7 +153,8 @@ or ending anchor terms are used.
.It Fl x
Treat
.Ar pattern
-
as a regular expression.  This is the default.
+
as a regular expression.
+
This is the default.
Matches any substring of the search field unless explicit beginning
or ending anchor terms are used.
.El
@@ -229,7 +231,8 @@ options, then each output field will be tagged with the field name.
.Bl -tag -width 2n
.It Sy arch
The architecture string indicating what OS version and CPU architecture
-
the package is suitable for.  For example,
+
the package is suitable for.
+
For example,
.Ar freebsd:9:x86:64
indicates a package suitable for FreeBSD 9.x running on an amd64 processor,
while
@@ -306,7 +309,7 @@ If the package does not have any options to set, nothing will be
output for this field, including suppressing the tag name when
multiple output fields are requested.
.It Sy pkg-size
-
Display the size of the compressed package tarball, ie. how much would
+
Display the size of the compressed package tarball, i.e. how much would
need to be downloaded from the repository.
.It Sy prefix
Display the installation prefix for the package, usually
@@ -316,7 +319,7 @@ Displays the repository label and the corresponding base Url for the
repository.
In multi-repo mode, the repository label and URL are one of the pairs
defined in
-
.Fa pkg.conf .  
+
.Fa pkg.conf .
In normal mode the label is always ``remote'', and the URL is the
value of
.Cm PACKAGESITE .
@@ -333,7 +336,7 @@ multiple output fields are requested.
If the package contains dynamically linked FreeBSD ELF binaries,
display a list of all of the shared libraries other than those from
the base system required for those binaries to run.
-
Shared libraries for foreign (eg. Linux) binaries run
+
Shared libraries for foreign (e.g. Linux) binaries run
under emulation will not be displayed.
If the package does not require any shared libraries, nothing will be
output for this field including suppressing the tag name when multiple
@@ -349,7 +352,7 @@ Display the general URL, if any, for the project developing the
software used in the package.
This is extracted from the
.Fa pkg-descr
-
file in the port. 
+
file in the port.
.El
.Pp
Any unambiguous prefix of the modifier name may be used on the command
modified pkg/pkg.8
@@ -198,6 +198,7 @@ command first appeared in
.An Will Andrews Aq will@FreeBSD.org
.An Marin Atanasov Nikolov Aq dnaeon@gmail.com
.An Bryan Drewery Aq bryan@shatow.net
+
.An Matthew Seaman Aq matthew@FreeBSD.org
.\" ---------------------------------------------------------------------------
.Sh BUGS
See the issue tracker at