From ca6ef852f9944ad31e8a136f7faf71da2c5fb57f Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Mon, 30 Mar 2009 18:48:15 +0200 Subject: New feature: files verification 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 , thanks for your work! Signed-off-by: Dan McGee --- contrib/bash_completion | 2 ++ contrib/zsh_completion | 1 + doc/pacman.8.txt | 8 ++++- src/pacman/conf.h | 1 + src/pacman/pacman.c | 7 +++- src/pacman/query.c | 85 ++++++++++++++++++++++++++++++++++++++++++------- 6 files changed, 91 insertions(+), 13 deletions(-) diff --git a/contrib/bash_completion b/contrib/bash_completion index 11f021c8..65135cfd 100644 --- a/contrib/bash_completion +++ b/contrib/bash_completion @@ -183,6 +183,7 @@ _pacman () search) mod="${mod}s" ;; upgrades) mod="${mod}u" ;; cascade) mod="${mod}c" ;; + check) mod="${mod}k" ;; dbonly) mod="${mod}k" ;; nosave) mod="${mod}n" ;; recursive) mod="${mod}s" ;; @@ -294,6 +295,7 @@ _pacman () -g --groups \ -h --help \ -i --info \ + -k --check \ -l --list \ -m --foreign \ -o --owns \ diff --git a/contrib/zsh_completion b/contrib/zsh_completion index e1273184..2f43d9b2 100644 --- a/contrib/zsh_completion +++ b/contrib/zsh_completion @@ -50,6 +50,7 @@ _pacman_opts_query_modifiers=( '-e[List packages explicitly installed]' '-i[View package information]' '-ii[View package information including backup files]' + '-k[Check package files]' '-l[List package contents]' '-m[List installed packages not found in sync db(s)]' '-t[List packages not required by any package]' diff --git a/doc/pacman.8.txt b/doc/pacman.8.txt index af85a15e..b56ad6b5 100644 --- a/doc/pacman.8.txt +++ b/doc/pacman.8.txt @@ -196,6 +196,11 @@ 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 or filter flags are not provided, + check all installed packages. + *-l, \--list*:: List all files owned by a given package. Multiple packages can be specified on the command line. @@ -220,7 +225,8 @@ Query Options[[QO]] names and not version, group, and description information; owns will only show package names instead of "file is owned by pkg" messages; group will only show package names and omit group names; list will only show - files and omit package names; a bare query will only show package names + files and omit package names; check will only show pairs of package names + and missing files; a bare query will only show package names rather than names and versions. *-s, \--search* <'regexp'>:: diff --git a/src/pacman/conf.h b/src/pacman/conf.h index 39802ca8..6523d490 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 7f864891..48d45ad1 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 query the package that owns \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 49972028..23be7524 100644 --- a/src/pacman/query.c +++ b/src/pacman/query.c @@ -309,8 +309,60 @@ 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_fprintf(stderr, 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_fprintf(stderr, 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) { + printf("%s %s\n", pkgname, f); + } else { + pm_printf(PM_LOG_WARNING, "%s: missing %s (%s)\n", + pkgname, f, strerror(errno)); + } + errors++; + } + } + + if(!config->quiet) { + 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 +377,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 +416,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 +430,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 +450,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 +462,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) { -- cgit v1.2.3-24-g4f1b