[pacman-dev] [PATCH] New feature: files verification

changaco changaco at laposte.net
Mon Mar 30 17:51:50 EDT 2009


From ee827c85cb9c4cd42ff42d8d624923076d62459b Mon Sep 17 00:00:00 2001
From: Charly COSTE <changaco at laposte.net>
Date: Mon, 30 Mar 2009 18:48:15 +0200
Subject: [PATCH] New feature: files verification

A new option "-Qk" which checks if the files owned by a/some/all package(s) really are on the system (i.e. not accidentally deleted).

Signed-off-by: Charly COSTE <changaco at laposte.net>
---
 doc/pacman.8.txt    |    4 ++
 src/pacman/conf.h   |    1 +
 src/pacman/pacman.c |    7 +++-
 src/pacman/query.c  |  122 ++++++++++++++++++++++++++++++++++++++++++++++++---
 4 files changed, 126 insertions(+), 8 deletions(-)

diff --git a/doc/pacman.8.txt b/doc/pacman.8.txt
index c574872..f208816 100644
--- a/doc/pacman.8.txt
+++ b/doc/pacman.8.txt
@@ -181,6 +181,10 @@ Query Options[[QO]]
 	'\--info' or '-i' flags will also display the list of backup files and
 	their modification states.
 
+*-k \--check*::
+	Check that all files owned by the given package(s) are present on the
+	system. If packages are not specified, check all installed packages.
+
 *-l, \--list*::
 	List all files owned by a given package. Multiple packages can be
 	specified on the command line.
diff --git a/src/pacman/conf.h b/src/pacman/conf.h
index 466d983..50907db 100644
--- a/src/pacman/conf.h
+++ b/src/pacman/conf.h
@@ -50,6 +50,7 @@ typedef struct __config_t {
 	unsigned short op_q_search;
 	unsigned short op_q_changelog;
 	unsigned short op_q_upgrade;
+	unsigned short op_q_check;
 
 	unsigned short op_s_clean;
 	unsigned short op_s_downloadonly;
diff --git a/src/pacman/pacman.c b/src/pacman/pacman.c
index 59916d6..f6efce3 100644
--- a/src/pacman/pacman.c
+++ b/src/pacman/pacman.c
@@ -107,6 +107,7 @@ static void usage(int op, const char * const myname)
 			printf(_("  -e, --explicit       list all packages explicitly installed\n"));
 			printf(_("  -g, --groups         view all members of a package group\n"));
 			printf(_("  -i, --info           view package information (-ii for backup files)\n"));
+			printf(_("  -k, --check          check that the files owned by the package(s) are present\n"));
 			printf(_("  -l, --list           list the contents of the queried package\n"));
 			printf(_("  -m, --foreign        list installed packages not found in sync db(s)\n"));
 			printf(_("  -o, --owns <file>    query the package that owns <file>\n"));
@@ -343,6 +344,7 @@ static int parseargs(int argc, char *argv[])
 		{"help",       no_argument,       0, 'h'},
 		{"info",       no_argument,       0, 'i'},
 		{"dbonly",     no_argument,       0, 'k'},
+		{"check",      no_argument,       0, 'k'},
 		{"list",       no_argument,       0, 'l'},
 		{"foreign",    no_argument,       0, 'm'},
 		{"nosave",     no_argument,       0, 'n'},
@@ -471,7 +473,10 @@ static int parseargs(int argc, char *argv[])
 			case 'g': (config->group)++; break;
 			case 'h': config->help = 1; break;
 			case 'i': (config->op_q_info)++; (config->op_s_info)++; break;
-			case 'k': config->flags |= PM_TRANS_FLAG_DBONLY; break;
+			case 'k':
+				config->flags |= PM_TRANS_FLAG_DBONLY;
+				config->op_q_check = 1;
+				break;
 			case 'l': config->op_q_list = 1; break;
 			case 'm': config->op_q_foreign = 1; break;
 			case 'n': config->flags |= PM_TRANS_FLAG_NOSAVE; break;
diff --git a/src/pacman/query.c b/src/pacman/query.c
index 0d48638..c0d8df0 100644
--- a/src/pacman/query.c
+++ b/src/pacman/query.c
@@ -334,10 +334,102 @@ static void display(pmpkg_t *pkg)
 	}
 }
 
+static void check_display_progress(int j, int pkgs_n, const char *pkgname)
+{
+	char message[getcols()];
+	int len = snprintf(message, getcols(), "(%i/%i) %s %s ...", (int)j, (int)pkgs_n, _("checking"), pkgname);
+	fprintf(stderr, "\r%s %*s", message, getcols()-len-1, " ");
+	fflush(stderr);
+}
+
+/* Loop through the packages. For each package,
+ * loop through files to check if they exist. */
+static void check(alpm_list_t *pkgs)
+{
+	alpm_list_t *i, *files, *file, *damaged = NULL;
+	pmpkg_t *pkg;
+	const char *root;
+	int pkgs_n, j = 0, allfiles = 0;
+	size_t rootlen;
+	char f[PATH_MAX];
+	char tmp[PATH_MAX];
+
+	pkgs_n = alpm_list_count(pkgs);
+	root = alpm_option_get_root();
+	rootlen = strlen(root);
+	if(rootlen + 1 > PATH_MAX) {
+		/* we are in trouble here */
+		pm_printf(PM_LOG_ERROR, _("root path too long\n"));
+		return;
+	}
+	strcpy(f, root);
+	strcpy(tmp, root);
+	strcpy(tmp + rootlen, "tmp");
+	int tmplen = strlen(tmp);
+
+	for(i = pkgs; i; i = alpm_list_next(i)) {
+		j++;
+		pkg = alpm_list_getdata(i);
+		const char *pkgname = alpm_pkg_get_name(pkg);
+		files = alpm_pkg_get_files(pkg);
+		if(!config->quiet) {
+			check_display_progress(j, pkgs_n, pkgname);
+		}
+		for(file = files; file; file = alpm_list_next(file)){
+			struct stat st;
+			char *x = alpm_list_getdata(file);
+			if(rootlen + 1 + strlen(x) > PATH_MAX) {
+				pm_printf(PM_LOG_WARNING, _("file path too long\n"));
+				continue;
+			}
+			strcpy(f + rootlen, x);
+			allfiles++;
+			if(strncmp(f, tmp, tmplen)==0){
+				continue;
+			}
+			/* use lstat to prevent errors from symlinks */
+			if(lstat(f,&st) != 0) {
+				if(config->quiet) {
+					fprintf(stderr, "%s %s\n", pkgname, f);
+					fflush(stderr);
+				} else {
+					fprintf(stderr, "\r%s: %s %s\n", pkgname, _("Missing file"), f);
+					check_display_progress(j, pkgs_n, pkgname);
+					fflush(stderr);
+				}
+				if(alpm_list_find_ptr(damaged, pkgname) == NULL) {
+					damaged = alpm_list_add(damaged, (char*)pkgname);
+				}
+			}
+		}
+	}
+	if(!config->quiet) {
+		char message[getcols()];
+		int len = snprintf(message, getcols(), "%s: %i %s (%i %s)",
+					_("Check complete"), allfiles, _("files"), pkgs_n, _("packages"));
+		fprintf(stderr, "\r%s %*s\n", message, getcols()-len-1, " ");
+		fflush(stderr);
+	}
+	if(alpm_list_count(damaged) > 0) {
+		if(!config->quiet){
+			fprintf(stderr, "\r%s ", _("Damaged packages:"));
+			fflush(stderr);
+		}
+		for(i = damaged; i; i = alpm_list_next(i)) {
+			fprintf(stdout, "%s ", (char*)alpm_list_getdata(i));
+		}
+		fprintf(stdout, "\n");
+		fflush(stdout);
+	}
+
+	alpm_list_free(damaged);
+}
+
 int pacman_query(alpm_list_t *targets)
 {
 	int ret = 0;
-	alpm_list_t *i;
+	alpm_list_t *i, *pkgs = NULL;
+	pmpkg_t *pkg = NULL;
 
 	/* First: operations that do not require targets */
 
@@ -363,7 +455,7 @@ int pacman_query(alpm_list_t *targets)
 	}
 
 	/* operations on all packages in the local DB
-	 * valid: no-op (plain -Q), list, info
+	 * valid: no-op (plain -Q), list, info, check
 	 * invalid: isfile, owns */
 	if(targets == NULL) {
 		if(config->op_q_isfile || config->op_q_owns) {
@@ -372,11 +464,19 @@ int pacman_query(alpm_list_t *targets)
 		}
 
 		for(i = alpm_db_get_pkgcache(db_local); i; i = alpm_list_next(i)) {
-			pmpkg_t *pkg = alpm_list_getdata(i);
+			pkg = alpm_list_getdata(i);
 			if(filter(pkg)) {
-				display(pkg);
+				if(config->op_q_check) {
+					pkgs = alpm_list_add(pkgs, pkg);
+				} else {
+					display(pkg);
+				}
 			}
 		}
+		if(config->op_q_check){
+			check(pkgs);
+			alpm_list_free(pkgs);
+		}
 		return(0);
 	}
 
@@ -389,10 +489,9 @@ int pacman_query(alpm_list_t *targets)
 	}
 
 	/* operations on named packages in the local DB
-	 * valid: no-op (plain -Q), list, info */
+	 * valid: no-op (plain -Q), list, info, check */
 	for(i = targets; i; i = alpm_list_next(i)) {
 		char *strname = alpm_list_getdata(i);
-		pmpkg_t *pkg = NULL;
 
 		if(config->op_q_isfile) {
 			alpm_pkg_load(strname, 1, &pkg);
@@ -406,8 +505,13 @@ int pacman_query(alpm_list_t *targets)
 			continue;
 		}
 
+
 		if(filter(pkg)) {
-			display(pkg);
+			if(config->op_q_check) {
+				pkgs = alpm_list_add(pkgs, pkg);
+			} else {
+				display(pkg);
+			}
 		}
 
 		if(config->op_q_isfile) {
@@ -415,6 +519,10 @@ int pacman_query(alpm_list_t *targets)
 			pkg = NULL;
 		}
 	}
+	if(config->op_q_check){
+		check(pkgs);
+		alpm_list_free(pkgs);
+	}
 
 	return(ret);
 }
-- 
1.6.2.1




More information about the pacman-dev mailing list