From ee827c85cb9c4cd42ff42d8d624923076d62459b Mon Sep 17 00:00:00 2001 From: Charly COSTE <changaco@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@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