summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--contrib/bash_completion2
-rw-r--r--contrib/zsh_completion1
-rw-r--r--doc/pacman.8.txt8
-rw-r--r--src/pacman/conf.h1
-rw-r--r--src/pacman/pacman.c7
-rw-r--r--src/pacman/query.c85
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 <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 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) {