Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
First step in the installation from the repo.
jlaffaye committed 14 years ago
commit 5f8a9d607f00082b94bc334421767b78ef473a77
parent 69ece35
9 files changed +462 -56
modified libpkg/Makefile
@@ -14,6 +14,7 @@ SRCS= pkg.c \
		pkg_delete.c \
		pkg_elf.c \
		pkg_error.c \
+
		pkg_jobs.c \
		pkg_manifest.c \
		pkg_ports.c \
		pkg_repo.c \
modified libpkg/pkg.h
@@ -15,6 +15,8 @@ struct pkg_option;
struct pkgdb;
struct pkgdb_it;

+
struct pkg_jobs;
+

typedef enum {
	PKGDB_DEFAULT=0,
	PKGDB_REMOTE
@@ -146,6 +148,8 @@ typedef enum {
typedef void (*fetch_cb)(void *data, const char *url, off_t total, off_t done,
						 time_t elapsed);

+
typedef void (*status_cb)(void *data, struct pkg *pkg);
+

/**
 * Allocate a new pkg.
 * Allocated pkg must be deallocated by pkg_free().
@@ -286,8 +290,6 @@ int pkg_setnewflatsize(struct pkg *pkg, int64_t size);
 */
int pkg_setnewpkgsize(struct pkg *pkg, int64_t size);

-

-

/**
 * Allocate a new struct pkg and add it to the deps of pkg.
 * @return An error code.
@@ -316,7 +318,6 @@ int pkg_adddir(struct pkg *pkg, const char *path);
 */
int pkg_addconflict(struct pkg *pkg, const char *glob);

-

/**
 * Allocate a new struct pkg_script and add it to the scripts of pkg.
 * @param path The path to the script on disk.
@@ -353,6 +354,7 @@ int pkg_load_manifest_file(struct pkg *pkg, const char *fpath);
 */
int pkg_emit_manifest(struct pkg *pkg, char **buf);

+
/* pkg_dep */
const char *pkg_dep_origin(struct pkg_dep *dep);
const char *pkg_dep_name(struct pkg_dep *dep);
const char *pkg_dep_version(struct pkg_dep *dep);
@@ -431,6 +433,13 @@ struct pkgdb_it * pkgdb_query(struct pkgdb *db, const char *pattern,
							  match_t type);

/**
+
 * Query the remote database.
+
 * @param db A pkgdb opened with PKGDB_REMOTE.
+
 * @warning Returns NULL on failure.
+
 */
+
struct pkg * pkgdb_query_remote(struct pkgdb *db, const char *pattern);
+

+
/**
 * 
 */
struct pkgdb_it *pkgdb_query_upgrades(struct pkgdb *db);
@@ -493,6 +502,38 @@ int pkgdb_compact(struct pkgdb *db);
int pkg_add(struct pkgdb *db, const char *path, struct pkg **pkg);

/**
+
 * Allocate a new pkg_jobs.
+
 * @param db A pkgdb open with PKGDB_REMOTE.
+
 * @return An error code.
+
 */
+
int pkg_jobs_new(struct pkg_jobs **jobs, struct pkgdb *db);
+

+
/**
+
 * Free a pkg_jobs
+
 */
+
void pkg_jobs_free(struct pkg_jobs *jobs);
+

+
/**
+
 * Add a pkg to the jobs queue.
+
 * @return An error code.
+
 */
+
int pkg_jobs_add(struct pkg_jobs *jobs, struct pkg *pkg);
+

+
/**
+
 * Iterates over the packages in the jobs queue.
+
 * @param pkg Must be set to NULL for the first call.
+
 * @return An error code.
+
 */
+
int pkg_jobs(struct pkg_jobs *jobs, struct pkg **pkg);
+

+
/**
+
 * Apply the jobs in the queue (fetch and install).
+
 * @return An error code.
+
 */
+
int pkg_jobs_apply(struct pkg_jobs *jobs, void *data, fetch_cb fcb,
+
				   status_cb scb);
+

+
/**
 * Archive formats options.
 */
typedef enum pkg_formats { TAR, TGZ, TBZ, TXZ } pkg_formats;
modified libpkg/pkg_config.c
@@ -43,9 +43,6 @@ load_config(void)
	}

	done = 1;
-

-
	if (p != NULL)
-
		properties_free(p);
}

const char *
added libpkg/pkg_jobs.c
@@ -0,0 +1,196 @@
+
#include <assert.h>
+
#include <err.h>
+
#include <stdlib.h>
+
#include <string.h>
+

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

+
int
+
pkg_jobs_new(struct pkg_jobs **j, struct pkgdb *db)
+
{
+
	if (db == NULL || db->type != PKGDB_REMOTE)
+
		return (ERROR_BAD_ARG("db"));
+

+
	if((*j = calloc(1, sizeof(struct pkg_jobs))) == NULL)
+
		err(1, "calloc()");
+

+
	STAILQ_INIT(&(*j)->jobs);
+
	LIST_INIT(&(*j)->nodes);
+
	(*j)->db = db;
+

+
	return (EPKG_OK);
+
}
+

+
void
+
pkg_jobs_free(struct pkg_jobs *j)
+
{
+
	struct pkg *p;
+

+
	while (!STAILQ_EMPTY(&j->jobs)) {
+
		p = STAILQ_FIRST(&j->jobs);
+
		STAILQ_REMOVE_HEAD(&j->jobs, next);
+
		pkg_free(p);
+
	}
+
	free(j);
+
}
+

+
int
+
pkg_jobs_add(struct pkg_jobs *j, struct pkg *pkg)
+
{
+
	if (j == NULL)
+
		return (ERROR_BAD_ARG("jobs"));
+
	if (pkg == NULL)
+
		return (ERROR_BAD_ARG("pkg"));
+

+
	STAILQ_INSERT_TAIL(&j->jobs, pkg, next);
+

+
	return (EPKG_OK);
+
}
+

+
int
+
pkg_jobs(struct pkg_jobs *j, struct pkg **pkg)
+
{
+
	if (j == NULL)
+
		return (ERROR_BAD_ARG("jobs"));
+

+
	pkg_jobs_resolv(j, 0);
+

+
	if (*pkg == NULL)
+
		*pkg = STAILQ_FIRST(&j->jobs);
+
	else
+
		*pkg = STAILQ_NEXT(*pkg, next);
+

+
	if (*pkg == NULL)
+
		return (EPKG_END);
+
	else
+
		return (EPKG_OK);
+
}
+

+
int
+
pkg_jobs_apply(struct pkg_jobs *j, void *data, fetch_cb fcb, status_cb scb)
+
{
+
	struct pkg *p = NULL;
+

+
	/* Fetch */
+
	while (pkg_jobs(j, &p) == EPKG_OK) {
+
		if (pkg_repo_fetch(p, data, fcb) != EPKG_OK)
+
			return (EPKG_FATAL);
+
	}
+
	(void)scb;
+
	return (EPKG_OK);
+
}
+

+
static struct pkg_jobs_node *
+
get_node(struct pkg_jobs *j, const char *name)
+
{
+
	struct pkg_jobs_node *n;
+

+
	/* XXX hashmap? */
+
	LIST_FOREACH(n, &j->nodes, entries) {
+
		if (strcmp(name, pkg_get(n->pkg, PKG_ORIGIN)) == 0) {
+
			return (n);
+
		}
+
	}
+

+
	n = calloc(1, sizeof(struct pkg_jobs_node));
+
	LIST_INSERT_HEAD(&j->nodes, n, entries);
+
	return (n);
+
}
+

+
static void
+
add_dep(struct pkg_jobs *j, struct pkg_jobs_node *n)
+
{
+
	struct pkg_dep *d = NULL;
+
	struct pkg_jobs_node *nd;
+

+
	while (pkg_deps(n->pkg, &d) != EPKG_END) {
+
		n->nrefs++;
+
		nd = get_node(j, pkg_dep_origin(d));
+

+
		if (nd->pkg == NULL) {
+
			/* XXX should query with origin */
+
			nd->pkg = pkgdb_query_remote(j->db, pkg_dep_origin(d));
+
			if (nd->pkg == NULL)
+
				err(1, "%s", pkg_error_string());
+
			add_dep(j, nd);
+
		}
+

+
		if (nd->parents_len == nd->parents_cap) {
+
			if (nd->parents_cap == 0)
+
				nd->parents_cap = 5;
+
			else
+
				nd->parents_cap *= 2;
+
			nd->parents = realloc(nd->parents, nd->parents_cap *
+
								  sizeof(struct pkg_jobs_node));
+
		}
+
		nd->parents[nd->parents_len] = n;
+
		nd->parents_len++;
+
	}
+
}
+

+
static void
+
remove_node(struct pkg_jobs *j, struct pkg_jobs_node *n)
+
{
+
	struct pkg_jobs_node *np;
+
	size_t i;
+

+
	assert(n->nrefs == 0);
+

+
	if (j->reverse == 1)
+
		STAILQ_INSERT_HEAD(&j->jobs, n->pkg, next);
+
	else
+
		STAILQ_INSERT_TAIL(&j->jobs, n->pkg, next);
+

+
	LIST_REMOVE(n, entries);
+

+
	for (i = 0; i < n->parents_len; i++) {
+
		np = n->parents[i];
+
		np->nrefs--;
+
	}
+
	free(n->parents);
+
	free(n);
+
}
+

+
int
+
pkg_jobs_resolv(struct pkg_jobs *j, int reverse)
+
{
+
	struct pkg_jobs_node *n, *tmp;
+
	struct pkg *p;
+

+
	if (j == NULL)
+
		return (ERROR_BAD_ARG("jobs"));
+

+
	if (j->resolved == 1)
+
		return (EPKG_OK);
+

+
	j->reverse = reverse;
+

+
	/* Create nodes and remove jobs form the queue */
+
	while (!STAILQ_EMPTY(&j->jobs)) {
+
		p = STAILQ_FIRST(&j->jobs);
+
		STAILQ_REMOVE_HEAD(&j->jobs, next);
+

+
		n = get_node(j, pkg_get(p, PKG_ORIGIN));
+

+
		n->pkg = p;
+
	}
+

+
	/* Add dependencies into nodes */
+
	LIST_FOREACH(n, &j->nodes, entries) {
+
		add_dep(j, n);
+
	}
+

+
	/* Resolv !*/
+
	do {
+
		LIST_FOREACH_SAFE(n, &j->nodes, entries, tmp) {
+
			if (n->nrefs == 0)
+
				remove_node(j, n);
+
		}
+
	} while (!LIST_EMPTY(&j->nodes));
+

+
	j->resolved = 1;
+
	return (EPKG_OK);
+
}
modified libpkg/pkg_private.h
@@ -37,6 +37,7 @@ struct pkg {
	int flags;
	int64_t rowid;
	pkg_t type;
+
	STAILQ_ENTRY(pkg) next;
};

struct pkg_dep {
@@ -74,6 +75,23 @@ struct pkg_option {
	STAILQ_ENTRY(pkg_option) next;
};

+
struct pkg_jobs {
+
	STAILQ_HEAD(jobs, pkg) jobs;
+
	LIST_HEAD(nodes, pkg_jobs_node) nodes;
+
	struct pkgdb *db;
+
	unsigned int resolved :1;
+
	unsigned int reverse :1;
+
};
+

+
struct pkg_jobs_node {
+
	struct pkg *pkg;
+
	size_t nrefs;
+
	struct pkg_jobs_node **parents; /* rdeps */
+
	size_t parents_len;
+
	size_t parents_cap;
+
	LIST_ENTRY(pkg_jobs_node) entries;
+
};
+

int pkg_open2(struct pkg **p, struct archive **a, struct archive_entry **ae, const char *path);
void pkg_freedeps(struct pkg *pkg);
void pkg_freerdeps(struct pkg *pkg);
@@ -101,6 +119,8 @@ void pkg_script_free(struct pkg_script *);
int pkg_option_new(struct pkg_option **);
void pkg_option_free(struct pkg_option *);

+
int pkg_jobs_resolv(struct pkg_jobs *jobs, int reverse);
+

struct packing;

int packing_init(struct packing **pack, const char *path, pkg_formats format);
modified libpkg/pkg_repo.c
@@ -13,7 +13,8 @@ pkg_repo_fetch(struct pkg *pkg, void *data, fetch_cb cb)
	char *url;
	int retcode = EPKG_OK;

-
	if ((pkg->type & PKG_REMOTE) != PKG_REMOTE)
+
	if ((pkg->type & PKG_REMOTE) != PKG_REMOTE &&
+
		(pkg->type & PKG_UPGRADE) != PKG_UPGRADE)
		return (ERROR_BAD_ARG("pkg"));

	snprintf(dest, sizeof(dest), "%s/%s", pkg_config("PKG_CACHEDIR"),
@@ -25,8 +26,11 @@ pkg_repo_fetch(struct pkg *pkg, void *data, fetch_cb cb)

	asprintf(&url, "%s/%s", pkg_config("PACKAGESITE"),
			 pkg_get(pkg, PKG_REPOPATH));
-
	pkg_fetch_file(url, dest, data, cb);
+

+
	retcode = pkg_fetch_file(url, dest, data, cb);
	free(url);
+
	if (retcode != EPKG_OK)
+
		goto cleanup;

	checksum:
	retcode = sha256_file(dest, cksum);
@@ -34,5 +38,9 @@ pkg_repo_fetch(struct pkg *pkg, void *data, fetch_cb cb)
		if (strcmp(cksum, pkg_get(pkg, PKG_CKSUM)))
			retcode = pkg_error_set(EPKG_FATAL, "failed checksum");

+
	cleanup:
+
	if (retcode != EPKG_OK)
+
		unlink(dest);
+

	return (retcode);
}
modified libpkg/pkgdb.c
@@ -356,9 +356,9 @@ pkgdb_it_next(struct pkgdb_it *it, struct pkg **pkg_p, int flags)
	switch (sqlite3_step(it->stmt)) {
	case SQLITE_ROW:
		if (*pkg_p == NULL)
-
			pkg_new(pkg_p, PKG_INSTALLED);
+
			pkg_new(pkg_p, it->type);
		else
-
			pkg_reset(*pkg_p, PKG_INSTALLED);
+
			pkg_reset(*pkg_p, it->type);
		pkg = *pkg_p;

		pkg->rowid = sqlite3_column_int64(it->stmt, 0);
@@ -375,7 +375,7 @@ pkgdb_it_next(struct pkgdb_it *it, struct pkg **pkg_p, int flags)
		pkg_set(pkg, PKG_PREFIX, sqlite3_column_text(it->stmt, 11));
		pkg_setflatsize(pkg, sqlite3_column_int64(it->stmt, 12));

-
		if (it->type == IT_UPGRADE) {
+
		if (it->type == PKG_UPGRADE) {
			pkg->type = PKG_UPGRADE;

			pkg_set(pkg, PKG_NEWVERSION, sqlite3_column_text(it->stmt, 13));
@@ -384,6 +384,10 @@ pkgdb_it_next(struct pkgdb_it *it, struct pkg **pkg_p, int flags)
			pkg_set(pkg, PKG_REPOPATH, sqlite3_column_text(it->stmt, 16));
		}

+
		/* load only for PKG_INSTALLED */
+
		if (it->type != PKG_INSTALLED)
+
			return (EPKG_OK);
+

		if (flags & PKG_LOAD_DEPS)
			if ((ret = pkgdb_loaddeps(it->db, pkg)) != EPKG_OK)
				return (ret);
@@ -498,7 +502,82 @@ pkgdb_query(struct pkgdb *db, const char *pattern, match_t match)
	if (match != MATCH_ALL)
		sqlite3_bind_text(stmt, 1, pattern, -1, SQLITE_TRANSIENT);

-
	return (pkgdb_it_new(db, stmt, IT_LOCAL));
+
	return (pkgdb_it_new(db, stmt, PKG_INSTALLED));
+
}
+

+
struct pkg *
+
pkgdb_query_remote(struct pkgdb *db, const char *pattern)
+
{
+
	sqlite3_stmt *stmt = NULL;
+
	sqlite3_stmt *stmt_deps = NULL;
+
	struct pkg *pkg = NULL;
+
	int ret;
+
	char sql[] = ""
+
		"SELECT p.rowid, p.origin, p.name, p.version, p.comment, p.desc, "
+
			"p.arch, p.osversion, p.maintainer, p.www, p.pkgsize, "
+
			"p.flatsize, p.cksum, p.path "
+
		"FROM remote.packages AS p "
+
		"WHERE p.origin = ?1";
+
	char sql_deps[] = ""
+
		"SELECT d.name, d.origin, d.version "
+
		"FROM remote.deps AS d "
+
		"WHERE d.package_id = ?1 "
+
			"AND NOT EXISTS (SELECT 1 FROM main.packages AS p "
+
			"WHERE p.origin = d.origin)";
+

+
	if (db == NULL || db->type != PKGDB_REMOTE) {
+
		ERROR_BAD_ARG("db");
+
		return (NULL);
+
	}
+

+
	if (sqlite3_prepare_v2(db->sqlite, sql, -1, &stmt, NULL) != SQLITE_OK) {
+
		ERROR_SQLITE(db->sqlite);
+
		return (NULL);
+
	}
+

+
	if (sqlite3_prepare_v2(db->sqlite, sql_deps, -1, &stmt_deps, NULL) != SQLITE_OK) {
+
		ERROR_SQLITE(db->sqlite);
+
		return (NULL);
+
	}
+
	sqlite3_bind_text(stmt, 1, pattern, -1, SQLITE_STATIC);
+

+
	ret = sqlite3_step(stmt);
+
	if (ret != SQLITE_ROW) {
+
		if (ret != SQLITE_DONE)
+
			ERROR_SQLITE(db->sqlite);
+
		goto cleanup;
+
	}
+

+
	pkg_new(&pkg, PKG_REMOTE);
+

+
	pkg->rowid = sqlite3_column_int64(stmt, 0);
+
	pkg_set(pkg, PKG_ORIGIN, sqlite3_column_text(stmt, 1));
+
	pkg_set(pkg, PKG_NAME, sqlite3_column_text(stmt, 2));
+
	pkg_set(pkg, PKG_VERSION, sqlite3_column_text(stmt, 3));
+
	pkg_set(pkg, PKG_COMMENT, sqlite3_column_text(stmt, 4));
+
	pkg_set(pkg, PKG_DESC, sqlite3_column_text(stmt, 5));
+
	pkg_set(pkg, PKG_ARCH, sqlite3_column_text(stmt, 6));
+
	pkg_set(pkg, PKG_OSVERSION, sqlite3_column_text(stmt, 7));
+
	pkg_set(pkg, PKG_MAINTAINER, sqlite3_column_text(stmt, 8));
+
	pkg_set(pkg, PKG_WWW, sqlite3_column_text(stmt, 9));
+
	pkg_setnewpkgsize(pkg, sqlite3_column_int64(stmt, 10));
+
	pkg_setnewflatsize(pkg, sqlite3_column_int64(stmt, 11));
+
	pkg_set(pkg, PKG_CKSUM, sqlite3_column_text(stmt, 12));
+
	pkg_set(pkg, PKG_REPOPATH, sqlite3_column_text(stmt, 13));
+

+
	sqlite3_bind_int64(stmt_deps, 1, pkg->rowid);
+
	while ((ret = sqlite3_step(stmt_deps)) == SQLITE_ROW) {
+
		pkg_adddep(pkg, sqlite3_column_text(stmt_deps, 0),
+
				   sqlite3_column_text(stmt_deps, 1),
+
				   sqlite3_column_text(stmt_deps, 2));
+
	}
+

+
	cleanup:
+
	if (stmt != NULL)
+
		sqlite3_finalize(stmt);
+
	if (stmt_deps != NULL)
+
		sqlite3_finalize(stmt_deps);
+
	return (pkg);
}

struct pkgdb_it *
@@ -520,7 +599,7 @@ pkgdb_query_which(struct pkgdb *db, const char *path)

	sqlite3_bind_text(stmt, 1, path, -1, SQLITE_TRANSIENT);

-
	return (pkgdb_it_new(db, stmt, IT_LOCAL));
+
	return (pkgdb_it_new(db, stmt, PKG_INSTALLED));
}

int
@@ -1254,7 +1333,7 @@ pkgdb_query_upgrades(struct pkgdb *db)
		return (NULL);
	}

-
	return (pkgdb_it_new(db, stmt, IT_UPGRADE));
+
	return (pkgdb_it_new(db, stmt, PKG_UPGRADE));
}

struct pkgdb_it *
@@ -1282,7 +1361,7 @@ pkgdb_query_downgrades(struct pkgdb *db)
		return (NULL);
	}

-
	return (pkgdb_it_new(db, stmt, IT_UPGRADE));
+
	return (pkgdb_it_new(db, stmt, PKG_UPGRADE));
}

struct pkgdb_it *
@@ -1302,5 +1381,5 @@ pkgdb_query_autoremove(struct pkgdb *db)
		return (NULL);
	}

-
	return (pkgdb_it_new(db, stmt, IT_LOCAL));
+
	return (pkgdb_it_new(db, stmt, PKG_INSTALLED));
}
modified libpkg/pkgdb.h
@@ -11,9 +11,6 @@ struct pkgdb {
	pkgdb_t type;
};

-
#define IT_LOCAL 0
-
#define IT_UPGRADE 1
-

struct pkgdb_it {
	struct pkgdb *db;
	sqlite3_stmt *stmt;
modified pkg/add.c
@@ -13,13 +13,11 @@
#include "add.h"

static void
-
fetch_status(void *data, const char *url, off_t total, off_t done, time_t elapsed)
+
fetch_status(__unused void *data, const char *url, off_t total, off_t done,
+
			 __unused time_t elapsed)
{
	unsigned int percent;

-
	data = NULL;
-
	elapsed = 0;
-

	percent = ((float)done / (float)total) * 100;
	printf("\rFetching %s... %d%%", url, percent);

@@ -35,56 +33,80 @@ is_url(const char *pattern)
	if (strncmp(pattern, "http://", 7) == 0 ||
		strncmp(pattern, "https://", 8) == 0 ||
		strncmp(pattern, "ftp://", 6) == 0)
-
		return (0);
+
		return (EPKG_OK);

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

-
void
-
usage_add(void)
+
static void
+
install_status(__unused void *data, struct pkg *pkg)
{
-
	fprintf(stderr, "usage: pkg add <pkg-name>\n");
-
	fprintf(stderr, "       pkg add <url>://<pkg-name>\n\n");
-
	fprintf(stderr, "For more information see 'pkg help add'.\n");
+
	printf("Installing %s-%s...\n", pkg_get(pkg, PKG_NAME),
+
		   pkg_get(pkg, PKG_VERSION));
}

-
int
-
exec_add(int argc, char **argv)
+
static int
+
add_from_repo(const char *name)
{
-
	struct pkgdb *db = NULL;
	struct pkg *pkg = NULL;
-
	char *file;
-
	const char *message;
-
	int retcode = 0;
+
	struct pkgdb *db = NULL;
+
	struct pkg_jobs *jobs = NULL;
+
	int retcode = EPKG_OK;

-
	if (argc != 2) {
-
		usage_add();
-
		return (-1);
+
	if (pkgdb_open(&db, PKGDB_REMOTE) != EPKG_OK) {
+
		pkg_error_warn("can not open database");
+
		retcode = EPKG_FATAL;
+
		goto cleanup;
	}

-
	if (geteuid() != 0) {
-
		warnx("adding packages can only be done as root");
-
		return (EX_NOPERM);
+
	if (pkg_jobs_new(&jobs, db) != EPKG_OK) {
+
		pkg_error_warn("pkg_jobs_new()");
+
		retcode = EPKG_FATAL;
+
		goto cleanup;
+
	}
+

+
	if ((pkg = pkgdb_query_remote(db, name)) == NULL) {
+
		retcode = pkg_error_number();
+
		pkg_error_warn("can query the database");
+
		goto cleanup;
	}

+
	pkg_jobs_add(jobs, pkg);
+

+
	/* print a summary before applying the jobs */
+
	pkg = NULL;
+
	printf("The following packages will be installed:\n");
+
	while (pkg_jobs(jobs, &pkg) == EPKG_OK) {
+
		printf("%s-%s\n", pkg_get(pkg, PKG_NAME), pkg_get(pkg, PKG_VERSION));
+
	}
+

+
	if (pkg_jobs_apply(jobs, NULL, fetch_status, install_status) != EPKG_OK)
+
		pkg_error_warn("can not install");
+

+
	cleanup:
+
	if (db != NULL)
+
		pkgdb_close(db);
+
	if (jobs != NULL)
+
		pkg_jobs_free(jobs);
+
	return (EPKG_OK);
+
}
+

+
static int
+
add_from_file(const char *file)
+
{
+
	struct pkgdb *db = NULL;
+
	struct pkg *pkg = NULL;
+
	const char *message;
+
	int retcode = EPKG_OK;
+

	if (pkgdb_open(&db, PKGDB_DEFAULT) != EPKG_OK) {
		pkg_error_warn("can not open database");
-
		return (1);
+
		retcode = EPKG_FATAL;
	}

-
	if (is_url(argv[1]) == 0) {
-
		asprintf(&file, "./%s", basename(argv[1]));
-
		if (pkg_fetch_file(argv[1], file, NULL, &fetch_status) != EPKG_OK) {
-
			pkg_error_warn("can not fetch %s", argv[1]);
-
			retcode = 1;
-
			goto cleanup;
-
		}
-
	} else
-
		file = argv[1];
-

	if (pkg_add(db, file, &pkg) != EPKG_OK) {
		pkg_error_warn("can not install %s", file);
-
		retcode = 1;
+
		retcode = EPKG_FATAL;
		goto cleanup;
	}

@@ -93,13 +115,58 @@ exec_add(int argc, char **argv)
		printf("%s", message);

	cleanup:
-

	if (db != NULL)
		pkgdb_close(db);
-

	if (pkg != NULL)
		pkg_free(pkg);

	return (retcode);
}

+
void
+
usage_add(void)
+
{
+
	fprintf(stderr, "usage: pkg add <pkg-name>\n");
+
	fprintf(stderr, "       pkg add <url>://<pkg-name>\n\n");
+
	fprintf(stderr, "For more information see 'pkg help add'.\n");
+
}
+

+
int
+
exec_add(int argc, char **argv)
+
{
+
	char *name;
+
	int retcode = 0;
+

+
	if (argc != 2) {
+
		usage_add();
+
		return (-1);
+
	}
+

+
	if (geteuid() != 0) {
+
		warnx("adding packages can only be done as root");
+
		return (EX_NOPERM);
+
	}
+

+
	if (is_url(argv[1]) == EPKG_OK) {
+
		asprintf(&name, "./%s", basename(argv[1]));
+
		if (pkg_fetch_file(argv[1], name, NULL, &fetch_status) != EPKG_OK) {
+
			pkg_error_warn("can not fetch %s", argv[1]);
+
			return (1);
+
		}
+
	} else
+
		name = argv[1];
+

+
	/* if it is a file  */
+
	if (name[0] == '/' || name[0] == '.') {
+
		if (access(name, F_OK) == 0) {
+
			retcode = add_from_file(name);
+
		} else {
+
			warn("%s", name);
+
		}
+
	} else {
+
		retcode = add_from_repo(name);
+
	}
+

+
	return (retcode == EPKG_OK ? 0 : 1);
+
}
+