Radish alpha
H
HardenedBSD Package Manager
Radicle
Git (anonymous pull)
Log in to clone via SSH
Automatic registration of shlibs
Matthew Seaman committed 14 years ago
commit f0ee79395a7c6f71e980808a5bde239718513913
parent 6bc8e1ba00aaadbd4688837dbdbd210e6c0d10d5
4 files changed +201 -79
modified libpkg/pkg.h
@@ -400,20 +400,47 @@ int pkg_options(struct pkg *, struct pkg_option **option);
int pkg_shlibs(struct pkg *pkg, struct pkg_shlib **shlib);

/**
-
 * Iterate over all of the files within the package.  Determine which
-
 * are ELF format executables or shared objects, and extract the names
-
 * of any shared libraries those depend on.  If pkg_analyse_action is
-
 * PKG_ANALYSE_ADD_MISSING_DEPS, determine which (if any) package
-
 * supplied the shared library and add that package to the
-
 * dependencies of pkg if not already known.  If pkg_analyse_action
-
 * is PKG_ANALYSE_REGISTER_SHLIBS, register the names of all shared
-
 * libraries required by pkg files in the database.
+
 * Initialise the ELF libraries for pkg_register_shlibs_for_file() 
+
 * or pkg_analyse_one_file()
 * @return An error code
 */

-
typedef enum { PKG_ANALYSE_ADD_MISSING_DEPS, PKG_ANALYSE_REGISTER_SHLIBS } pkg_analyse_action;
+
int pkg_analyse_init(void);

-
int pkg_analyse_files(struct pkgdb *, struct pkg *, pkg_analyse_action);
+
/**
+
 * Register the shared libraries used by fname, which is one of the
+
 * files belonging to pkg.
+
 * @return An error code
+
 */
+

+
int pkg_register_shlibs_for_file(struct pkg *pkg, const char *fname);
+

+
/**
+
 * Iterate over all of the files within the package pkg, registering
+
 * the shared libraries used by each of them.
+
 * @return An error code
+
 */
+

+
int pkg_register_shlibs(struct pkg *pkg);
+

+
/**
+
 * Analyse one file fname, which belongs to package pkg.  If it is an
+
 * ELF format executable or shared library, ensure that all of the
+
 * packages providing shared objects used by the file are added to the
+
 * pkg dependency list.
+
 * @return An error code
+
 */
+

+
int pkg_analyse_one_file(struct pkgdb *db, struct pkg *pkg, const char *fname);
+

+
/**
+
 * Iterate over all of the files within the package pkg, ensuring the
+
 * dependency list contains all applicable packages providing the
+
 * shared objects used by pkg.
+
 * @return An error code
+
 */
+

+
int pkg_analyse_files(struct pkgdb *, struct pkg *);

/**
 * Generic setter for simple attributes.
modified libpkg/pkg_create.c
@@ -50,6 +50,8 @@ pkg_create_from_dir(struct pkg *pkg, const char *root, struct packing *pkg_archi
	struct stat st;
	char sha256[SHA256_DIGEST_LENGTH * 2 + 1];

+
	pkg_analyse_init();
+

	/*
	 * if the checksum is not provided in the manifest recompute it
	 */
@@ -65,6 +67,8 @@ pkg_create_from_dir(struct pkg *pkg, const char *root, struct packing *pkg_archi
			strlcpy(file->sum, sha256, sizeof(file->sum));
		}

+
		if (pkg_register_shlibs_for_file(pkg, fpath) != EPKG_OK)
+
			return (EPKG_FATAL);
	}

	pkg_emit_manifest(pkg, &m);
modified libpkg/pkg_elf.c
@@ -44,74 +44,86 @@
#include "private/elf_tables.h"

static int
-
add_forgotten_depends(struct pkgdb *db, struct pkg *pkg, const char *name)
+
register_shlibs(struct pkg *pkg, const char *namelist[])
{
-
	struct pkg_dep *dep = NULL;
-
	struct pkg *p = NULL;
-
	struct pkgdb_it *it = NULL;
-
	const char *pkgorigin, *pkgname, *pkgversion;
-
	Link_map *map;
-
	bool found = false;
-
	void *handle;
+
	struct pkg_shlib *s;
+
	const char **name;
+
	bool found;

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

-
	dlinfo(handle, RTLD_DI_LINKMAP, &map);
+
	assert(pkg != NULL);

-
	if ((it = pkgdb_query_which(db, map->l_name)) == NULL) {
-
		dlclose(handle);
-
		return (EPKG_OK); /* shlib not from any pkg */
-
	}
-
	if (pkgdb_it_next(it, &p, PKG_LOAD_BASIC) == EPKG_OK) {
+
	for (name = namelist; *name != NULL; name++) {
+
		s = NULL;
		found = false;
-
		pkg_get(pkg, PKG_ORIGIN, &pkgorigin);
-
		while (pkg_deps(pkg, &dep) == EPKG_OK) {
-
			if (strcmp(pkg_dep_get(dep, PKG_DEP_ORIGIN), pkgorigin) == 0) {
+
		while (pkg_shlibs(pkg, &s) == EPKG_OK) {
+
			if (strcmp(*name, pkg_shlib_name(s)) == 0) {
+
				/* already registered, but that's OK */
				found = true;
				break;
			}
		}
-
		if (!found) {
-
			pkg_get(p, PKG_ORIGIN, &pkgorigin, PKG_NAME, &pkgname, PKG_VERSION, &pkgversion);
-
			pkg_emit_error("adding forgotten depends (%s): %s-%s",
-
				       map->l_name, pkgname, pkgversion);
-
			pkg_adddep(pkg, pkgname, pkgorigin, pkgversion);
+
		if ( !found ) {
+
			pkg_shlib_new(&s);
+
			sbuf_set(&s->name, *name);
+
			STAILQ_INSERT_TAIL(&pkg->shlibs, s, next);
		}
-
		pkg_free(p);
	}
-
	dlclose(handle);
-
	pkgdb_it_free(it);
-

	return (EPKG_OK);
}

static int
-
register_shlibs(__unused struct pkgdb *db, struct pkg *pkg, const char *name)
+
add_forgotten_depends(struct pkgdb *db, struct pkg *pkg, const char *namelist[])
{
-
	struct pkg_shlib *s = NULL;
+
	struct pkg_dep *dep = NULL;
+
	struct pkgdb_it *it = NULL;
+
	struct pkg *d;
+
	Link_map *map;
+
	const char *deporigin, *depname, *depversion;
+
	const char **name;
+
	bool found;
+
	void *handle;

-
	assert(pkg != NULL);
-
	assert(name != NULL && name[0] != '\0');
+
	for (name = namelist; *name != NULL; name++) {
+
		handle = dlopen(*name, RTLD_LAZY);
+
		if (handle == NULL) {
+
			pkg_emit_error("accessing shared library %s failed -- %s", name, dlerror());
+
			return (EPKG_FATAL);
+
		}
+

+
		dlinfo(handle, RTLD_DI_LINKMAP, &map);

-
	while (pkg_shlibs(pkg, &s) == EPKG_OK) {
-
		if (strcmp(name, pkg_shlib_name(s)) == 0) {
-
			/* already registered, but that's OK */
-
			return (EPKG_OK);
+
		if ((it = pkgdb_query_which(db, map->l_name)) == NULL) {
+
			dlclose(handle);
+
			break; /* shlib not from any pkg */
		}
+
		d = NULL;
+
		if (pkgdb_it_next(it, &d, PKG_LOAD_BASIC) == EPKG_OK) {
+
			found = false;
+
			pkg_get(d, PKG_ORIGIN, &deporigin, PKG_NAME, &depname, PKG_VERSION, &depversion);
+

+
			dep = NULL;
+
			found = false;
+
			while (pkg_deps(pkg, &dep) == EPKG_OK) {
+
				if (strcmp(pkg_dep_get(dep, PKG_DEP_ORIGIN), deporigin) == 0) {
+
					found = true;
+
					break;
+
				}
+
			}
+
			if (!found) {
+
				pkg_emit_error("adding forgotten depends (%s): %s-%s",
+
					       map->l_name, depname, depversion);
+
				pkg_adddep(pkg, depname, deporigin, depversion);
+
			}
+
			pkg_free(d);
+
		}
+
		dlclose(handle);
+
		pkgdb_it_free(it);
	}
-
	pkg_shlib_new(&s);
-
	sbuf_set(&s->name, name);
-
	STAILQ_INSERT_TAIL(&pkg->shlibs, s, next);
	return (EPKG_OK);
}

static int
-
analyse_elf(struct pkgdb *db, struct pkg *pkg, const char *fpath,
-
	    int(*analyse_action)(struct pkgdb*, struct pkg*, const char*))
+
analyse_elf(const char *fpath, const char ***namelist) 
{
	Elf *e;
	Elf_Scn *scn = NULL;
@@ -121,74 +133,149 @@ analyse_elf(struct pkgdb *db, struct pkg *pkg, const char *fpath,

	size_t numdyn;
	size_t dynidx;
-
	char *name;
+
	const char **name;

	int fd;

	if ((fd = open(fpath, O_RDONLY, 0)) < 0)
		return (EPKG_FATAL);

-
	if (( e = elf_begin(fd, ELF_C_READ, NULL)) == NULL)
-
		return (EPKG_FATAL);
-

-
	if (elf_kind(e) != ELF_K_ELF)
+
	if (( e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
+
		close(fd);
		return (EPKG_FATAL);
+
	}
+
	if (elf_kind(e) != ELF_K_ELF) {
+
		close(fd);
+
		return (EPKG_END); /* Not an elf file: no results */
+
	}

	while (( scn = elf_nextscn(e, scn)) != NULL) {
-
		if (gelf_getshdr(scn, &shdr) != &shdr)
+
		if (gelf_getshdr(scn, &shdr) != &shdr) {
+
			close(fd);
			return (EPKG_FATAL);
-

+
		}
		if (shdr.sh_type == SHT_DYNAMIC)
			break;
	}

-
	if  (scn == NULL)
-
		return (EPKG_OK);
+
	if  (scn == NULL) {
+
		close(fd);
+
		return (EPKG_END); /* not dynamically linked: no results */
+
	}

	data = elf_getdata(scn, NULL);
	numdyn = shdr.sh_size / shdr.sh_entsize;

+
	if ( (*namelist = calloc(numdyn + 1, sizeof(**namelist))) == NULL ) {
+
		close(fd);
+
		return (EPKG_FATAL);
+
	}
+
	name = *namelist;
+

	for (dynidx = 0; dynidx < numdyn; dynidx++) {
-
		if ((dyn = gelf_getdyn(data, dynidx, &dyn_mem)) == NULL)
+
		if ((dyn = gelf_getdyn(data, dynidx, &dyn_mem)) == NULL) {
+
			close(fd);
			return (EPKG_FATAL);
+
		}

		if (dyn->d_tag != DT_NEEDED)
			continue;

-
		name = elf_strptr(e, shdr.sh_link, dyn->d_un.d_val);
-

-
		if (analyse_action(db, pkg, name) != EPKG_OK)
-
			break;			
+
		*name = elf_strptr(e, shdr.sh_link, dyn->d_un.d_val);
+
		name++;
	}
+

	pkg_free(p);
	if (e != NULL)
		elf_end(e);
+
	*name = NULL;
	close(fd);

	return (EPKG_OK);
+
}
+

+
int
+
pkg_analyse_init(void)
+
{
+
	if (elf_version(EV_CURRENT) == EV_NONE)
+
		return (EPKG_FATAL);
+
	return (EPKG_OK);
+
}

+
int
+
pkg_register_shlibs_for_file(struct pkg *pkg, const char *fname)
+
{
+
	const char **namelist = NULL;
+
	int ret = EPKG_OK;
+

+
	switch (analyse_elf(fname, &namelist)) {
+
		case EPKG_OK:
+
			ret = register_shlibs(pkg, namelist);
+
			break;
+
		case EPKG_END:
+
			break; /* File not dynamically linked  */
+
		case EPKG_FATAL:
+
			ret = EPKG_FATAL;
+
			break;
+
	}
+
	if (namelist != NULL)
+
		free(namelist);
+

+
	return (ret);
}

int
-
pkg_analyse_files(struct pkgdb *db, struct pkg *pkg, pkg_analyse_action action)
+
pkg_register_shlibs(struct pkg *pkg)
{
	struct pkg_file *file = NULL;
+
	int ret = EPKG_OK;

	if (elf_version(EV_CURRENT) == EV_NONE)
		return (EPKG_FATAL);

-
	switch (action) {
-
		case PKG_ANALYSE_ADD_MISSING_DEPS:
-
			while (pkg_files(pkg, &file) == EPKG_OK)
-
				analyse_elf(db, pkg, pkg_file_get(file, PKG_FILE_PATH), add_forgotten_depends);
+
	while (pkg_files(pkg, &file) == EPKG_OK) {
+
		if ((ret = pkg_register_shlibs_for_file(pkg, pkg_file_get(file, PKG_FILE_PATH))) != EPKG_OK)
			break;
-
		case PKG_ANALYSE_REGISTER_SHLIBS:
-
			while (pkg_files(pkg, &file) == EPKG_OK)
-
				analyse_elf(db, pkg, pkg_file_get(file, PKG_FILE_PATH), register_shlibs);
+
	}
+
	return (EPKG_OK);
+
}
+

+
int
+
pkg_analyse_one_file(struct pkgdb *db, struct pkg *pkg, const char *fname)
+
{
+
	const char **namelist = NULL;
+
	int ret = EPKG_OK;
+

+
	switch (analyse_elf(fname, &namelist)) {
+
		case EPKG_OK:
+
			ret = add_forgotten_depends(db, pkg, namelist);
+
			break;
+
		case EPKG_END:
+
			break; /* File not dynamically linked  */
+
		case EPKG_FATAL:
+
			ret = EPKG_FATAL;
			break;
	}
+
	if (namelist != NULL)
+
		free(namelist);

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

+
int
+
pkg_analyse_files(struct pkgdb *db, struct pkg *pkg)
+
{
+
	struct pkg_file *file = NULL;
+
	int ret = EPKG_OK;
+

+
	if (elf_version(EV_CURRENT) == EV_NONE)
+
		return (EPKG_FATAL);
+

+
	while (pkg_files(pkg, &file) == EPKG_OK) {
+
		if ((ret = pkg_analyse_one_file(db, pkg, pkg_file_get(file, PKG_FILE_PATH))) != EPKG_OK)
+
			break;
+
	}
+
	return (ret);
}

static const char *
modified pkg/register.c
@@ -199,12 +199,16 @@ exec_register(int argc, char **argv)
	if (plist != NULL)
		free(plist);

+
	if (pkg_register_shlibs(pkg) != EPKG_OK) {
+
		return (EX_IOERR);
+
	}
+

	if (pkgdb_open(&db, PKGDB_DEFAULT) != EPKG_OK) {
		return (EX_IOERR);
	}

	if (heuristic)
-
		pkg_analyse_files(db, pkg, PKG_ANALYSE_ADD_MISSING_DEPS);
+
		pkg_analyse_files(db, pkg);

	if (input_path != NULL) {
		pkg_copy_tree(pkg, input_path, "/");