Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
Initial commit 'pkg check'
Marin Atanasov Nikolov committed 14 years ago
commit 6fc65acfd86f0420eeb24ae6ad14a17a5413f1fc
parent 547ee73
4 files changed +302 -0
modified pkg/Makefile
@@ -3,6 +3,7 @@ SRCS= add.c \
		audit.c \
		autoremove.c \
		backup.c \
+
		check.c \
		clean.c \
		create.c \
		delete.c \
added pkg/check.c
@@ -0,0 +1,292 @@
+
#include <sys/param.h>
+
#include <sys/queue.h>
+

+
#include <err.h>
+
#include <assert.h>
+
#include <sysexits.h>
+
#include <stdbool.h>
+
#include <stdio.h>
+
#include <string.h>
+
#include <unistd.h>
+
#include <libutil.h>
+

+
#include <pkg.h>
+

+
#include "check.h"
+
#include "utils.h"
+

+
struct deps_entry {
+
	char *name;
+
	char *version;
+
	char *origin;
+
	STAILQ_ENTRY(deps_entry) next;
+
};
+

+
STAILQ_HEAD(deps_head, deps_entry);
+

+
static int check_deps(struct pkgdb *db, struct pkg *pkg, struct deps_head *dh);
+
static void add_missing_dep(struct pkg_dep *d, struct deps_head *dh);
+
static void deps_free(struct deps_head *dh);
+
static void fix_deps(struct pkgdb *db, struct deps_head *dh, int nbpkgs);
+
static void check_summary(struct pkgdb *db, struct deps_head *dh);
+

+
static int
+
check_deps(struct pkgdb *db, struct pkg *p, struct deps_head *dh)
+
{
+
	struct pkg *pkg = NULL;
+
	struct pkg_dep *dep = NULL;
+
	struct pkgdb_it *it = NULL;
+
	char *name, *version, *origin;
+
	int nbpkgs = 0;
+

+
	assert(db != NULL);
+
	assert(p != NULL);
+

+
	name = version = origin = NULL;
+
	pkg_get(p, PKG_NAME, &name, PKG_VERSION, &version, PKG_ORIGIN, &origin);
+

+
	while (pkg_deps(p, &dep) == EPKG_OK) {
+
		if ((it = pkgdb_query(db, pkg_dep_get(dep, PKG_DEP_ORIGIN), MATCH_EXACT)) == NULL)
+
			return (0);;
+
		
+
		/* do we have a missing dependency? */
+
		if (pkgdb_it_next(it, &pkg, PKG_LOAD_BASIC) != EPKG_OK) {
+
			printf("%s has a missing dependency: %s\n", origin,
+
					pkg_dep_get(dep, PKG_DEP_ORIGIN)),
+
			add_missing_dep(dep, dh);
+
			nbpkgs++;
+
		}
+

+
		pkgdb_it_free(it);
+
	}
+
	
+
	pkg_free(pkg);
+

+
	return (nbpkgs);
+
}
+

+
static void
+
add_missing_dep(struct pkg_dep *d, struct deps_head *dh)
+
{
+
	struct deps_entry *e = NULL;
+

+
	assert(d != NULL);
+

+
	if ((e = calloc(1, sizeof(struct deps_entry))) == NULL)
+
		err(1, "calloc(deps_entry)");
+

+
	e->name = strdup(pkg_dep_get(d, PKG_DEP_NAME));
+
	e->version = strdup(pkg_dep_get(d, PKG_DEP_VERSION));
+
	e->origin = strdup(pkg_dep_get(d, PKG_DEP_ORIGIN));
+

+
	STAILQ_INSERT_TAIL(dh, e, next);
+
}
+

+
static void
+
deps_free(struct deps_head *dh)
+
{
+
	struct deps_entry *e = NULL;
+

+
	while (!STAILQ_EMPTY(dh)) {
+
		e = STAILQ_FIRST(dh);
+
		STAILQ_REMOVE_HEAD(dh, next);
+
		free(e->name);
+
		free(e->version);
+
		free(e->origin);
+
		free(e);
+
	}
+
}
+

+
static void
+
fix_deps(struct pkgdb *db, struct deps_head *dh, int nbpkgs)
+
{
+
	struct pkg *pkg = NULL;
+
	struct pkgdb_it *it = NULL;
+
	struct pkg_jobs *jobs = NULL;
+
	struct deps_entry *e = NULL;
+
	char **pkgs = NULL;
+
	int64_t dlsize = 0;
+
	int64_t oldsize = 0, newsize = 0;
+
	char size[7];
+
	int i = 0;
+

+
	assert(db != NULL);
+
	assert(nbpkgs > 0);
+

+
	if ((pkgs = calloc(nbpkgs, MAXPATHLEN + 1)) == NULL)
+
		err(1, "calloc()");
+

+
	STAILQ_FOREACH(e, dh, next)
+
		pkgs[i++] = e->origin;
+

+
	if (pkg_jobs_new(&jobs, PKG_JOBS_INSTALL, db) != EPKG_OK)
+
		free(pkgs);
+

+
        if ((it = pkgdb_query_installs(db, MATCH_EXACT, nbpkgs, pkgs, NULL)) == NULL) {
+
		free(pkgs);
+
		pkg_jobs_free(jobs);
+
	}
+

+
        while (pkgdb_it_next(it, &pkg, PKG_LOAD_BASIC|PKG_LOAD_DEPS) == EPKG_OK) {
+
                pkg_jobs_add(jobs, pkg);
+
                pkg = NULL;
+
        }
+

+
        if (pkg_jobs_is_empty(jobs)) {
+
                printf("\n>>> Not able to find packages for installation.\n\n");
+
		return;
+
        }
+

+
        /* print a summary before applying the jobs */
+
        pkg = NULL;
+
        printf("The following packages will be installed:\n");
+

+
        while (pkg_jobs(jobs, &pkg) == EPKG_OK) {
+
                const char *name, *version, *newversion;
+
                int64_t flatsize, newflatsize, pkgsize;
+
                pkg_get(pkg, PKG_NEWVERSION, &newversion, PKG_NAME, &name,
+
                    PKG_VERSION, &version, PKG_FLATSIZE, &flatsize,
+
                    PKG_NEW_FLATSIZE, &newflatsize, PKG_NEW_PKGSIZE, &pkgsize);
+
                dlsize += pkgsize;
+
                if (newversion != NULL) {
+
                        printf("\tUpgrading %s: %s -> %s\n", name, version, newversion);
+
                        oldsize += flatsize;
+
                        newsize += flatsize;
+
                } else {
+
                        newsize += flatsize;
+
                        printf("\tInstalling %s: %s\n", name, version);
+
                }
+
        }
+

+
        if (oldsize > newsize) {
+
                newsize *= -1;
+
                humanize_number(size, sizeof(size), oldsize - newsize, "B", HN_AUTOSCALE, 0);
+
                printf("\nthe installation will save %s\n", size);
+
        } else {
+
                humanize_number(size, sizeof(size), newsize - oldsize, "B", HN_AUTOSCALE, 0);
+
                printf("\nthe installation will require %s more space\n", size);
+
        }
+
        humanize_number(size, sizeof(size), dlsize, "B", HN_AUTOSCALE, 0);
+
        printf("%s to be downloaded\n", size);
+

+
	pkg_jobs_apply(jobs, 0);
+

+
	free(pkgs);
+
	pkg_free(pkg);
+
	pkg_jobs_free(jobs);
+
	pkgdb_it_free(it);
+
}
+

+
static void
+
check_summary(struct pkgdb *db, struct deps_head *dh)
+
{
+
	struct deps_entry *e = NULL;
+
	struct pkg *pkg = NULL;
+
	struct pkgdb_it *it = NULL;
+
	bool fixed = true;
+

+
	assert(db != NULL);
+

+
	printf(">>> Summary of actions performed:\n\n");
+
		
+
	STAILQ_FOREACH(e, dh, next) {
+
		if ((it = pkgdb_query(db, e->origin, MATCH_EXACT)) == NULL)
+
			return;
+
		
+
		if (pkgdb_it_next(it, &pkg, PKG_LOAD_BASIC) != EPKG_OK) {
+
			fixed = false;
+
			printf("%s dependency failed to be fixed\n", e->origin);
+
		} else
+
			printf("%s dependency has been fixed\n", e->origin);
+

+
		pkgdb_it_free(it);
+
	}
+
	
+
	if (fixed) {
+
		printf("\n>>> Missing dependencies were fixed successfully.\n");
+
	} else {
+
		printf("\n>>> There are still missing dependencies.\n");
+
		printf(">>> You are advised to try fixing them manually.\n");
+
		printf("\n>>> Also make sure to check 'pkg updating' for known issues.\n");
+
	}
+

+
	pkg_free(pkg);
+
}
+

+
void
+
usage_check(void)
+
{
+
	fprintf(stderr, "usage: pkg check [-y]\n\n");
+
	fprintf(stderr, "For more information see 'pkg help check'.\n");
+
}
+

+
int
+
exec_check(int argc, char **argv)
+
{
+
	struct pkg *pkg = NULL;
+
	struct pkgdb_it *it = NULL;
+
	struct pkgdb *db = NULL;
+
	int retcode = EX_OK;
+
	int ch;
+
	bool yes = false;
+
	int nbpkgs = 0;
+

+
	struct deps_head dh = STAILQ_HEAD_INITIALIZER(dh);
+

+
	while ((ch = getopt(argc, argv, "y")) != -1) {
+
		switch (ch) {
+
			case 'y':
+
				yes = true;
+
				break;
+
			default:
+
				usage_check();
+
				return (EX_USAGE);
+
		}
+
	}
+
	argc -= optind;
+
	argv += optind;
+

+
	if (argc != 0) {
+
		usage_check();
+
		return (EX_USAGE);
+
	}
+

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

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

+
	if ((it = pkgdb_query(db, NULL, MATCH_ALL)) == NULL) {
+
		pkgdb_close(db);
+
		return (EX_IOERR);
+
	}
+

+
	/* check for missing dependencies */
+
	while (pkgdb_it_next(it, &pkg, PKG_LOAD_BASIC|PKG_LOAD_DEPS) == EPKG_OK) 
+
		nbpkgs += check_deps(db, pkg, &dh);
+

+
	if (nbpkgs > 0) {
+
		printf("\n>>> Missing package dependencies were detected.\n");
+

+
		if (yes == false) 
+
			pkg_config_bool(PKG_CONFIG_ASSUME_ALWAYS_YES, &yes);
+
		if (yes == false)
+
			yes = query_yesno("\nTry to fix the missing dependencies [y/N]: ");
+

+
		if (yes == true) {
+
			fix_deps(db, &dh, nbpkgs);
+
			check_summary(db, &dh);
+
		}
+
	}
+

+
	deps_free(&dh);
+
	pkg_free(pkg);
+
	pkgdb_it_free(it);
+
	pkgdb_close(db);
+

+
	return (retcode);
+
}
added pkg/check.h
@@ -0,0 +1,7 @@
+
#ifndef _CHECK_H
+
#define _CHECK_H
+

+
int exec_check(int, char **);
+
void usage_check(void);
+

+
#endif
modified pkg/main.c
@@ -16,6 +16,7 @@
#include "audit.h"
#include "autoremove.h"
#include "backup.h"
+
#include "check.h"
#include "clean.h"
#include "create.h"
#include "delete.h"
@@ -51,6 +52,7 @@ static struct commands {
	{ "audit", "Reports vulnerable packages", exec_audit, usage_audit},
	{ "autoremove", "Removes orphan packages", exec_autoremove, usage_autoremove},
	{ "backup", "Backup and restore the local package database", exec_backup, usage_backup},
+
	{ "check", "Check for missing dependencies and database consistency", exec_check, usage_check},
	{ "clean", "Cleans old packages from the cache", exec_clean, usage_clean},
	{ "create", "Creates software package distributions", exec_create, usage_create},
	{ "delete", "Deletes packages from the database and the system", exec_delete, usage_delete},