Radish alpha
H
HardenedBSD Package Manager
Radicle
Git (anonymous pull)
Log in to clone via SSH
begin of better error handling, add heuristic search on elf files to find forgotten deps
Baptiste Daroussin committed 15 years ago
commit 599f0d589f5baa63d444e084719578c21d8a7998
parent e18b9288fec1d60d1744e98b47dfabaf1cd816fc
6 files changed +164 -16
modified libpkg/Makefile
@@ -11,6 +11,7 @@ SRCS= pkg.c \
		pkg_create.c \
		pkg_conflict.c \
		pkg_delete.c \
+
		pkg_elf.c \
		pkg_exec.c \
		pkg_file.c \
		pkg_manifest.c \
@@ -31,7 +32,8 @@ LDADD+= -L${.CURDIR}/../external/sqlite \
		-lbz2 \
		-llzma \
		-lsbuf \
-
		-lfetch
+
		-lfetch \
+
		-lelf

DEBUG_FLAGS+=  -g
.if defined(PROFILE_BUILD)
modified libpkg/pkg.c
@@ -3,6 +3,7 @@
#include <archive.h>
#include <archive_entry.h>
#include <stdlib.h>
+
#include <errno.h>

#include "pkg.h"
#include "pkg_private.h"
@@ -41,6 +42,8 @@ pkg_get(struct pkg *pkg, pkg_attr attr) {
			return (sbuf_get(pkg->maintainer));
		case PKG_WWW:
			return (sbuf_get(pkg->www));
+
		case PKG_ERR:
+
			return (sbuf_get(pkg->err));
	}

	return (NULL);
@@ -49,8 +52,10 @@ pkg_get(struct pkg *pkg, pkg_attr attr) {
int
pkg_set(struct pkg *pkg, pkg_attr attr, const char *value)
{
-
	if (value == NULL)
-
		return (-1);
+
	if (value == NULL) {
+
		pkg_set(pkg, PKG_ERR, "Value can not be NULL");
+
		return (EPKG_FATAL);
+
	}

	switch (attr) {
		case PKG_NAME:
@@ -75,19 +80,24 @@ pkg_set(struct pkg *pkg, pkg_attr attr, const char *value)
			return (sbuf_set(&pkg->maintainer, value));
		case PKG_WWW:
			return (sbuf_set(&pkg->www, value));
+
		case PKG_ERR:
+
			return (sbuf_set(&pkg->err, value));
	}

-
	return (-1);
+
	return (EPKG_FATAL);
}

int
pkg_set_from_file(struct pkg *pkg, pkg_attr attr, const char *path)
{
	char *buf = NULL;
-
	int ret = 0;
+
	int ret = EPKG_OK;

-
	if (file_to_buffer(path, &buf) <= 0)
-
		return (-1);
+
	if (file_to_buffer(path, &buf) <= 0) {
+
		sbuf_reset(pkg->err);
+
		sbuf_printf(pkg->err, "Unable to read %s: %s\n", path, strerror(errno));
+
		return (EPKG_FATAL);
+
	}

	ret = pkg_set(pkg, attr, buf);

@@ -187,15 +197,14 @@ pkg_open(const char *path, struct pkg **pkg, int query_flags)
	archive_read_support_compression_all(a);
	archive_read_support_format_tar(a);

-
	if (archive_read_open_filename(a, path, 4096) != ARCHIVE_OK) {
-
		archive_read_finish(a);
-
		return (-1);
-
	}
+
	pkg_new(pkg);
+

+
	if (archive_read_open_filename(a, path, 4096) != ARCHIVE_OK)
+
		goto error;

	/* first path to check is the archive is corrupted bye the way retreive
	 * informations */

-
	pkg_new(pkg);
	(*pkg)->type = PKG_FILE;

	array_init(&(*pkg)->deps, 5);
@@ -232,11 +241,15 @@ pkg_open(const char *path, struct pkg **pkg, int query_flags)
	}

	if (ret != ARCHIVE_EOF)
-
		warn("Archive corrupted");
+
		goto error;

	archive_read_finish(a);
-

	return (0);
+

+
error:
+
	archive_read_finish(a);
+

+
	return (EPKG_FATAL);
}

#define EXTRACT_ARCHIVE_FLAGS  (ARCHIVE_EXTRACT_OWNER |ARCHIVE_EXTRACT_PERM| \
@@ -281,6 +294,8 @@ pkg_new(struct pkg **pkg)
	if ((*pkg = calloc(1, sizeof(struct pkg))) == NULL)
		err(EXIT_FAILURE, "calloc()");

+
	(*pkg)->err = sbuf_new_auto();
+

	return (0);
}

@@ -301,6 +316,7 @@ pkg_reset(struct pkg *pkg)
	sbuf_reset(pkg->osversion);
	sbuf_reset(pkg->maintainer);
	sbuf_reset(pkg->www);
+
	sbuf_reset(pkg->err);

	array_reset(&pkg->deps, &pkg_free_void);
	array_reset(&pkg->rdeps, &pkg_free_void);
@@ -328,6 +344,7 @@ pkg_free(struct pkg *pkg)
	sbuf_free(pkg->osversion);
	sbuf_free(pkg->maintainer);
	sbuf_free(pkg->www);
+
	sbuf_free(pkg->err);

	array_free(&pkg->deps, &pkg_free_void);
	array_free(&pkg->rdeps, &pkg_free_void);
modified libpkg/pkg.h
@@ -36,7 +36,8 @@ typedef enum {
	PKG_ARCH,
	PKG_OSVERSION,
	PKG_MAINTAINER,
-
	PKG_WWW
+
	PKG_WWW,
+
	PKG_ERR
} pkg_attr;

typedef enum {
@@ -56,6 +57,13 @@ typedef enum {
	PKG_UNEXEC
} pkg_exec_t;

+
typedef enum {
+
	EPKG_OK = 0,
+
	EPKG_END,
+
	EPKG_WARNING,
+
	EPKG_FATAL,
+
} pkg_error_t;
+

/* pkg */
int pkg_new(struct pkg **);
int pkg_open(const char *, struct pkg **, int);
@@ -63,6 +71,7 @@ pkg_t pkg_type(struct pkg *);
void pkg_reset(struct pkg *);
void pkg_free(struct pkg *);
const char *pkg_get(struct pkg *, pkg_attr);
+
#define pkg_errmsg(pkg) pkg_get(pkg, PKG_ERR)
struct pkg ** pkg_deps(struct pkg *);
struct pkg ** pkg_rdeps(struct pkg *);
struct pkg_file ** pkg_files(struct pkg *);
@@ -72,6 +81,7 @@ struct pkg_exec ** pkg_execs(struct pkg *);
struct pkg_option ** pkg_options(struct pkg *);

int pkg_resolvdeps(struct pkg *, struct pkgdb *db);
+
int pkg_analyse_files(struct pkgdb *, struct pkg *);
int pkg_extract(const char *filename);

/* pkg setters */
added libpkg/pkg_elf.c
@@ -0,0 +1,108 @@
+
#include <fcntl.h>
+
#include <dlfcn.h>
+
#include <gelf.h>
+
#include <link.h>
+
#include <stdbool.h>
+
#include <unistd.h>
+
#include <string.h>
+
#include <err.h>
+

+
#include "pkg.h"
+
#include "pkg_private.h"
+

+
static int
+
analyse_elf(struct pkgdb *db, struct pkg *pkg, const char *fpath)
+
{
+
	struct pkg **deps;
+
	struct pkg *p;
+
	struct pkgdb_it *it = NULL;
+
	Elf *e;
+
	Elf_Scn *scn = NULL;
+
	GElf_Shdr shdr;
+
	Elf_Data *data;
+
	GElf_Dyn *dyn, dyn_mem;
+
	size_t numdyn;
+
	size_t dynidx;
+
	void *handle;
+
	Link_map *map;
+
	char *name;
+
	bool found=false;
+

+
	int fd, i;
+

+
	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)
+
		return (EPKG_FATAL);
+

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

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

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

+
	pkg_new(&p);
+
	for (dynidx = 0; dynidx < numdyn; dynidx++) {
+
		if ((dyn = gelf_getdyn(data, dynidx, &dyn_mem)) == NULL)
+
			return (EPKG_FATAL);
+

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

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

+
		if (handle != NULL) {
+
			dlinfo(handle, RTLD_DI_LINKMAP, &map);
+
			if ((it = pkgdb_query_which(db, map->l_name)) == NULL)
+
				return (EPKG_FATAL);
+

+
			if (pkgdb_it_next_pkg(it, &pkg, PKG_BASIC) == 0) {
+
				found = false;
+
				if (( deps = pkg_deps(pkg) ) != NULL) {
+
					for (i = 0; deps[i]; i++) {
+
						if (strcmp(pkg_get(deps[i], PKG_ORIGIN), pkg_get(p, PKG_ORIGIN)) == 0)
+
							found = true;
+
					}
+
				}
+
				if (!found) {
+
					warnx("adding forgotten depends (%s): %s-%s", map->l_name, pkg_get(p, PKG_NAME), pkg_get(p, PKG_VERSION));
+
					pkg_adddep(pkg, pkg_get(p, PKG_NAME), pkg_get(p, PKG_ORIGIN), pkg_get(p, PKG_VERSION));
+
				}
+
			}
+
			dlclose(handle);
+
		}
+
		pkg_reset(p);
+
		pkgdb_it_free(it);
+
	}
+
	pkg_free(p);
+
	close(fd);
+

+
	return (EPKG_OK);
+

+
}
+

+
int
+
pkg_analyse_files(struct pkgdb *db, struct pkg *pkg)
+
{
+
	struct pkg_file **files;
+
	int i;
+

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

+
	if ((files = pkg_files(pkg)) != NULL)
+
		for (i = 0; files[i] != NULL ; i++)
+
			analyse_elf(db, pkg, pkg_file_path(files[i]));
+

+
	return (EPKG_OK);
+
}
modified libpkg/pkg_private.h
@@ -19,6 +19,7 @@ struct pkg {
	struct sbuf *osversion;
	struct sbuf *maintainer;
	struct sbuf *www;
+
	struct sbuf *err;
	struct array deps;
	struct array rdeps;
	struct array conflicts;
modified pkg/register.c
@@ -6,6 +6,7 @@
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
+
#include <stdbool.h>
#include <sys/utsname.h>
#include <regex.h>

@@ -34,13 +35,16 @@ exec_register(int argc, char **argv)
	char *v = NULL;
	char *arch = NULL;
	char *www = NULL;
+

	const char *desc = NULL;
	size_t size;

+
	bool heuristic = false;
+

	int ret = 0;

	pkg_new(&pkg);
-
	while ((ch = getopt(argc, argv, "vc:d:f:p:P:m:o:C:n:M:s:a:r:w:O:")) != -1) {
+
	while ((ch = getopt(argc, argv, "vHc:d:f:p:P:m:o:C:n:M:s:a:r:w:O:")) != -1) {
		switch (ch) {
			case 'v':
				/* IGNORE */
@@ -94,6 +98,9 @@ exec_register(int argc, char **argv)
			case 'O':
				ret += ports_parse_options(pkg, optarg);
				break;
+
			case 'H':
+
				heuristic = true;
+
				break;
			default:
				printf("%c\n", ch);
				usage_register();
@@ -158,6 +165,9 @@ exec_register(int argc, char **argv)
		return (-1);
	}

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

	pkgdb_register_pkg(db, pkg);
	pkgdb_close(db);
	pkg_free(pkg);