[pacman-dev] [PATCH] New feature: files verification
Dan McGee
dan at archlinux.org
Tue Jul 21 23:58:26 EDT 2009
This implements FS#13877. Add a new option "-Qk" which checks if all of the
files for a given package (or packages) are really on the system (i.e. not
accidentally deleted). This can be combined with filters and other display
options. It also respects both the --quiet and --verbose flags to give
varying levels of output.
Based on the original patch by Charly Coste <changaco at laposte.net>, thanks
for your work!
Signed-off-by: Dan McGee <dan at archlinux.org>
---
Some additional notes and example output:
dmcgee at galway ~/projects/pacman (master)
$ ./src/pacman/pacman -Qkq
wpa_supplicant /etc/wpa_supplicant.conf
dmcgee at galway ~/projects/pacman (master)
$ ./src/pacman/pacman -Qk
wpa_supplicant: missing /etc/wpa_supplicant.conf (No such file or directory)
wpa_supplicant: 22 total, 1 missing file(s)
$ ./src/pacman/pacman -Qkmv
Root : /
Conf File : /etc/pacman.conf
DB Path : /var/lib/pacman/
Cache Dirs: /var/cache/pacman/pkg/ /home/makepkg/packages/
Lock File : /var/lib/pacman/db.lck
Log File : /var/log/pacman.log
Targets : None
bjfilter: 5 total, 0 missing file(s)
clearlooks: 51 total, 0 missing file(s)
ebtables: 37 total, 0 missing file(s)
icc: 1729 total, 0 missing file(s)
intel-compilers-common: 104 total, 0 missing file(s)
jre_beta: 825 total, 0 missing file(s)
kcachegrind: 60 total, 0 missing file(s)
libcnbj: 36 total, 0 missing file(s)
metasploit3: 16330 total, 0 missing file(s)
mixxx: 2072 total, 0 missing file(s)
munin-node: 159 total, 0 missing file(s)
picasa-beta: 1133 total, 0 missing file(s)
pstocanonbj: 24 total, 0 missing file(s)
python-markdown: 65 total, 0 missing file(s)
rng-tools: 15 total, 0 missing file(s)
tkinfo: 9 total, 0 missing file(s)
weka: 11 total, 0 missing file(s)
OK, that last one looks a bit silly with the paths at the top, doesn't it. Any
ideas? I'd be fine with showing the 0 errors lines all the time, it would just
require some grep foo for people to screen those out. That way, you can do
things like this (note that the output is slightly edited from what this patch
will produce, it is showing the output even with 0 missing files):
'''''
$ ./src/pacman/pacman -Qiik pacman-git
Name : pacman-git
Version : 20090715-1
URL : http://www.archlinux.org/pacman/
Licenses : GPL
Groups : None
Provides : pacman=3.2.2
Depends On : gcc-libs bash libarchive>=2.6.0 libfetch
pacman-mirrorlist
Optional Deps : fakeroot: for makepkg usage as normal user
python: for rankmirrors script usage
Required By : pacman-contrib pkgstats
Conflicts With : pacman
Replaces : None
Installed Size : 2036.00 K
Packager : Dan McGee <dan at archlinux.org>
Architecture : x86_64
Build Date : Wed 15 Jul 2009 09:15:00 PM CDT
Install Date : Wed 15 Jul 2009 11:40:07 PM CDT
Install Reason : Explicitly installed
Install Script : No
Description : A library-based package manager with dependency support
Backup Files:
MODIFIED /etc/pacman.conf
MODIFIED /etc/makepkg.conf
pacman-git: 114 total, 0 missing file(s)
'''''
-Dan
doc/pacman.8.txt | 4 ++
src/pacman/conf.h | 1 +
src/pacman/pacman.c | 7 ++++-
src/pacman/query.c | 83 ++++++++++++++++++++++++++++++++++++++++++++-------
4 files changed, 83 insertions(+), 12 deletions(-)
diff --git a/doc/pacman.8.txt b/doc/pacman.8.txt
index af85a15..ccff167 100644
--- a/doc/pacman.8.txt
+++ b/doc/pacman.8.txt
@@ -196,6 +196,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 39802ca..6523d49 100644
--- a/src/pacman/conf.h
+++ b/src/pacman/conf.h
@@ -51,6 +51,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 7f86489..48d45ad 100644
--- a/src/pacman/pacman.c
+++ b/src/pacman/pacman.c
@@ -108,6 +108,7 @@ static void usage(int op, const char * const myname)
printf(_(" -e, --explicit list packages explicitly installed [filter]\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) [filter]\n"));
printf(_(" -o, --owns <file> query the package that owns <file>\n"));
@@ -345,6 +346,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'},
@@ -473,7 +475,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 4997202..b70c713 100644
--- a/src/pacman/query.c
+++ b/src/pacman/query.c
@@ -309,8 +309,58 @@ static int filter(pmpkg_t *pkg)
return(1);
}
-static void display(pmpkg_t *pkg)
+/* Loop through the packages. For each package,
+ * loop through files to check if they exist. */
+static int check(pmpkg_t *pkg)
{
+ alpm_list_t *i;
+ const char *root;
+ int allfiles = 0, errors = 0;
+ size_t rootlen;
+ char f[PATH_MAX];
+
+ 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(1);
+ }
+ strcpy(f, root);
+
+ const char *pkgname = alpm_pkg_get_name(pkg);
+ for(i = alpm_pkg_get_files(pkg); i; i = alpm_list_next(i)) {
+ struct stat st;
+ const char *path = alpm_list_getdata(i);
+
+ if(rootlen + 1 + strlen(path) > PATH_MAX) {
+ pm_printf(PM_LOG_WARNING, _("file path too long\n"));
+ continue;
+ }
+ strcpy(f + rootlen, path);
+ allfiles++;
+ /* use lstat to prevent errors from symlinks */
+ if(lstat(f, &st) != 0) {
+ if(config->quiet) {
+ fprintf(stderr, "%s %s\n", pkgname, f);
+ } else {
+ fprintf(stderr, "%s: missing %s (%s)\n", pkgname, f, strerror(errno));
+ }
+ errors++;
+ }
+ }
+
+ if((errors > 0 && !config->quiet) || config->verbose) {
+ printf("%s: %d total, %d missing file(s)\n", pkgname, allfiles, errors);
+ }
+
+ return(errors != 0 ? 1 : 0);
+}
+
+static int display(pmpkg_t *pkg)
+{
+ int ret = 0;
+
if(config->op_q_info) {
if(config->op_q_isfile) {
/* omit info that isn't applicable for a file package */
@@ -325,19 +375,25 @@ static void display(pmpkg_t *pkg)
if(config->op_q_changelog) {
dump_pkg_changelog(pkg);
}
- if(!config->op_q_info && !config->op_q_list && !config->op_q_changelog) {
+ if(config->op_q_check) {
+ ret = check(pkg);
+ }
+ if(!config->op_q_info && !config->op_q_list
+ && !config->op_q_changelog && !config->op_q_check) {
if (!config->quiet) {
printf("%s %s\n", alpm_pkg_get_name(pkg), alpm_pkg_get_version(pkg));
} else {
printf("%s\n", alpm_pkg_get_name(pkg));
}
}
+ return(ret);
}
int pacman_query(alpm_list_t *targets)
{
int ret = 0;
alpm_list_t *i;
+ pmpkg_t *pkg = NULL;
/* First: operations that do not require targets */
@@ -358,12 +414,12 @@ int pacman_query(alpm_list_t *targets)
alpm_list_t *sync_dbs = alpm_option_get_syncdbs();
if(sync_dbs == NULL || alpm_list_count(sync_dbs) == 0) {
pm_printf(PM_LOG_ERROR, _("no usable package repositories configured.\n"));
- return(-1);
+ return(1);
}
}
/* 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,12 +428,15 @@ 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);
+ int value = display(pkg);
+ if(value != 0) {
+ ret = 1;
+ }
}
}
- return(0);
+ return(ret);
}
/* Second: operations that require target(s) */
@@ -389,10 +448,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);
@@ -402,12 +460,15 @@ int pacman_query(alpm_list_t *targets)
if(pkg == NULL) {
pm_fprintf(stderr, PM_LOG_ERROR, _("package \"%s\" not found\n"), strname);
- ret++;
+ ret = 1;
continue;
}
if(filter(pkg)) {
- display(pkg);
+ int value = display(pkg);
+ if(value != 0) {
+ ret = 1;
+ }
}
if(config->op_q_isfile) {
--
1.6.3.3
More information about the pacman-dev
mailing list