Radish alpha
H
HardenedBSD Package Manager
Radicle
Git (anonymous pull)
Log in to clone via SSH
Create per-file shlib_list from RPATH or RUNPATH setting in a binary
Matthew Seaman committed 13 years ago
commit 3e1b8d4a7d1ba46f768d13565c63fee1ab80c93c
parent 6b025f48c0b98460114797945476c50578ea5a96
6 files changed +657 -28
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 \
added libpkg/elfhints.c
@@ -0,0 +1,505 @@
+
/*-
+
 * 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     *cc;
+
	char	       *c;
+
	
+
	numdirs = 1;
+
	for (cc = rpath_str; *cc != '\0'; cc++)
+
		if (*cc == ':')
+
			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 + buflen;
+
	strcpy(buf, rpath_str);
+

+
	i = 0;
+
	dirlist[i++] = buf;
+
	for (c = buf; *c != '\0'; c++)
+
		if (*c == ':') {
+
			*c = '\0';
+
			dirlist[i++] = c + 1;
+
		}
+

+
	assert(i == numdirs);
+

+
	ret = scan_dirs_for_shlibs(&rpath, numdirs, 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);
}

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