aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Frysinger <vapier@gentoo.org>2011-10-03 03:18:10 +0000
committerMike Frysinger <vapier@gentoo.org>2011-10-03 03:18:10 +0000
commit68df26c121ac53be83409bb5ff18d4484dbbe039 (patch)
tree68a3c46fd3cb58468f07fc13810ce6c6628b1a84 /qcheck.c
parentadd xregcomp helpers (diff)
downloadportage-utils-68df26c121ac53be83409bb5ff18d4484dbbe039.tar.gz
portage-utils-68df26c121ac53be83409bb5ff18d4484dbbe039.tar.bz2
portage-utils-68df26c121ac53be83409bb5ff18d4484dbbe039.zip
rewrite qcheck to use *at style funcs
Diffstat (limited to 'qcheck.c')
-rw-r--r--qcheck.c484
1 files changed, 263 insertions, 221 deletions
diff --git a/qcheck.c b/qcheck.c
index 1d6778f8..87aad5bf 100644
--- a/qcheck.c
+++ b/qcheck.c
@@ -1,7 +1,7 @@
/*
* Copyright 2005-2010 Gentoo Foundation
* Distributed under the terms of the GNU General Public License v2
- * $Header: /var/cvsroot/gentoo-projects/portage-utils/qcheck.c,v 1.49 2011/10/03 01:25:54 vapier Exp $
+ * $Header: /var/cvsroot/gentoo-projects/portage-utils/qcheck.c,v 1.50 2011/10/03 03:18:10 vapier Exp $
*
* Copyright 2005-2010 Ned Ludd - <solar@gentoo.org>
* Copyright 2005-2010 Mike Frysinger - <vapier@gentoo.org>
@@ -34,11 +34,11 @@ static const char * const qcheck_opts_help[] = {
"Undo prelink when calculating checksums",
COMMON_OPTS_HELP
};
-static const char qcheck_rcsid[] = "$Id: qcheck.c,v 1.49 2011/10/03 01:25:54 vapier Exp $";
+static const char qcheck_rcsid[] = "$Id: qcheck.c,v 1.50 2011/10/03 03:18:10 vapier Exp $";
#define qcheck_usage(ret) usage(ret, QCHECK_FLAGS, qcheck_long_opts, qcheck_opts_help, lookup_applet_idx("qcheck"))
-short bad_only = 0;
-#define qcprintf(fmt, args...) if (!bad_only) printf( _( fmt ), ## args)
+static bool bad_only = false;
+#define qcprintf(fmt, args...) if (!bad_only) printf(_(fmt), ## args)
static void qcheck_cleanup(regex_t **regex_head, const size_t regex_count)
{
@@ -54,21 +54,242 @@ static void qcheck_cleanup(regex_t **regex_head, const size_t regex_count)
free(regex_head);
}
+static int qcheck_process_contents(int portroot_fd, int pkg_fd,
+ const char *catname, const char *pkgname, regex_t **regex_head,
+ size_t regex_count, bool qc_update, bool chk_afk,
+ bool chk_hash, bool chk_mtime, bool undo_prelink)
+{
+ int fd;
+ FILE *fp, *fpx;
+ size_t num_files, num_files_ok, num_files_unknown, num_files_ignored;
+ char *buffer, *line;
+ size_t linelen;
+ struct stat st, cst;
+
+ fpx = NULL;
+
+ fd = openat(pkg_fd, "CONTENTS", O_RDONLY|O_CLOEXEC);
+ if (fd == -1)
+ return EXIT_SUCCESS;
+ if (fstat(fd, &cst)) {
+ close(fd);
+ return EXIT_SUCCESS;
+ }
+ if ((fp = fdopen(fd, "r")) == NULL) {
+ close(fd);
+ return EXIT_SUCCESS;
+ }
+
+ num_files = num_files_ok = num_files_unknown = num_files_ignored = 0;
+ qcprintf("%sing %s%s/%s%s ...\n",
+ (qc_update ? "Updat" : "Check"),
+ GREEN, catname, pkgname, NORM);
+ if (qc_update) {
+ fd = openat(pkg_fd, "CONTENTS~", O_RDWR|O_CLOEXEC|O_CREAT|O_TRUNC, 0644);
+ if (fd == -1 || (fpx = fdopen(fd, "w")) == NULL) {
+ fclose(fp);
+ warnp("unable to fopen(%s/%s, w)", pkgname, "CONTENTS~");
+ return EXIT_FAILURE;
+ }
+ }
+
+ buffer = line = NULL;
+ while (getline(&line, &linelen, fp) != -1) {
+ contents_entry *e;
+ free(buffer);
+ buffer = xstrdup(line);
+ e = contents_parse_line(line);
+ if (!e)
+ continue;
+
+ /* run our little checks */
+ ++num_files;
+ if (regex_count) {
+ size_t j;
+ for (j = 0; j < regex_count; ++j)
+ if (!regexec(regex_head[j], e->name, 0, NULL, 0))
+ break;
+ if (j < regex_count) {
+ --num_files;
+ ++num_files_ignored;
+ continue;
+ }
+ }
+ if (fstatat(portroot_fd, e->name + 1, &st, AT_SYMLINK_NOFOLLOW)) {
+ /* make sure file exists */
+ if (chk_afk) {
+ qcprintf(" %sAFK%s: %s\n", RED, NORM, e->name);
+ } else {
+ --num_files;
+ ++num_files_ignored;
+ if (qc_update)
+ fputs(buffer, fpx);
+ }
+ continue;
+ }
+ if (e->digest && S_ISREG(st.st_mode)) {
+ /* validate digest (handles MD5 / SHA1) */
+ uint8_t hash_algo;
+ char *hashed_file;
+ hash_cb_t hash_cb = undo_prelink ? hash_cb_prelink_undo : hash_cb_default;
+ switch (strlen(e->digest)) {
+ case 32: hash_algo = HASH_MD5; break;
+ case 40: hash_algo = HASH_SHA1; break;
+ default: hash_algo = 0; break;
+ }
+ if (!hash_algo) {
+ if (chk_hash) {
+ qcprintf(" %sUNKNOWN DIGEST%s: '%s' for '%s'\n", RED, NORM, e->digest, e->name);
+ ++num_files_unknown;
+ } else {
+ --num_files;
+ ++num_files_ignored;
+ if (qc_update)
+ fputs(buffer, fpx);
+ }
+ continue;
+ }
+ hashed_file = (char*)hash_file_cb(e->name, hash_algo, hash_cb);
+ if (!hashed_file) {
+ ++num_files_unknown;
+ free(hashed_file);
+ if (qc_update) {
+ fputs(buffer, fpx);
+ if (!verbose)
+ continue;
+ }
+ qcprintf(" %sPERM %4o%s: %s\n", RED, (unsigned int)(st.st_mode & 07777), NORM, e->name);
+ continue;
+ } else if (strcmp(e->digest, hashed_file)) {
+ if (chk_hash) {
+ const char *digest_disp;
+ if (qc_update)
+ fprintf(fpx, "obj %s %s %lu\n", e->name, hashed_file, st.st_mtime);
+ switch (hash_algo) {
+ case HASH_MD5: digest_disp = "MD5"; break;
+ case HASH_SHA1: digest_disp = "SHA1"; break;
+ default: digest_disp = "UNK"; break;
+ }
+ qcprintf(" %s%s-DIGEST%s: %s", RED, digest_disp, NORM, e->name);
+ if (verbose)
+ qcprintf(" (recorded '%s' != actual '%s')", e->digest, hashed_file);
+ qcprintf("\n");
+ } else {
+ --num_files;
+ ++num_files_ignored;
+ if (qc_update)
+ fputs(buffer, fpx);
+ }
+ free(hashed_file);
+ continue;
+ } else if (e->mtime && e->mtime != st.st_mtime) {
+ if (chk_mtime) {
+ qcprintf(" %sMTIME%s: %s", RED, NORM, e->name);
+ if (verbose)
+ qcprintf(" (recorded '%lu' != actual '%lu')", e->mtime, (unsigned long)st.st_mtime);
+ qcprintf("\n");
+
+ /* This can only be an obj, dir and sym have no digest */
+ if (qc_update)
+ fprintf(fpx, "obj %s %s %lu\n", e->name, e->digest, st.st_mtime);
+ } else {
+ --num_files;
+ ++num_files_ignored;
+ if (qc_update)
+ fputs(buffer, fpx);
+ }
+ free(hashed_file);
+ continue;
+ } else {
+ if (qc_update)
+ fputs(buffer, fpx);
+ free(hashed_file);
+ }
+ } else if (e->mtime && e->mtime != st.st_mtime) {
+ if (chk_mtime) {
+ qcprintf(" %sMTIME%s: %s", RED, NORM, e->name);
+ if (verbose)
+ qcprintf(" (recorded '%lu' != actual '%lu')", e->mtime, (unsigned long)st.st_mtime);
+ qcprintf("\n");
+
+ /* This can only be a sym */
+ if (qc_update)
+ fprintf(fpx, "sym %s -> %s %lu\n", e->name, e->sym_target, st.st_mtime);
+ } else {
+ --num_files;
+ ++num_files_ignored;
+ if (qc_update)
+ fputs(buffer, fpx);
+ }
+ continue;
+ } else {
+ if (qc_update)
+ fputs(buffer, fpx);
+ }
+ ++num_files_ok;
+ }
+ free(line);
+ free(buffer);
+ fclose(fp);
+
+ if (qc_update) {
+ if (fchown(fd, cst.st_uid, cst.st_gid))
+ /* meh */;
+ if (fchmod(fd, cst.st_mode))
+ /* meh */;
+ fclose(fpx);
+ if (renameat(pkg_fd, "CONTENTS~", pkg_fd, "CONTENTS"))
+ unlinkat(pkg_fd, "CONTENTS~", 0);
+ if (!verbose)
+ return EXIT_SUCCESS;
+ }
+ if (bad_only && num_files_ok != num_files) {
+ if (verbose)
+ printf("%s/%s\n", catname, pkgname);
+ else {
+ depend_atom *atom = NULL;
+ char *buf;
+ xasprintf(&buf, "%s/%s", catname, pkgname);
+ if ((atom = atom_explode(buf)) != NULL) {
+ printf("%s/%s\n", catname, atom->PN);
+ atom_implode(atom);
+ } else {
+ printf("%s/%s\n", catname, pkgname);
+ }
+ free(buf);
+ }
+ }
+ qcprintf(" %2$s*%1$s %3$s%4$zu%1$s out of %3$s%5$zu%1$s file%6$s are good",
+ NORM, BOLD, BLUE, num_files_ok, num_files,
+ (num_files > 1 ? "s" : ""));
+ if (num_files_unknown)
+ qcprintf(" (Unable to digest %2$s%3$zu%1$s file%4$s)",
+ NORM, BLUE, num_files_unknown,
+ (num_files_unknown > 1 ? "s" : ""));
+ if (num_files_ignored)
+ qcprintf(" (%2$s%3$zu%1$s file%4$s ignored)",
+ NORM, BLUE, num_files_ignored,
+ (num_files_ignored > 1 ? "s were" : " was"));
+ qcprintf("\n");
+
+ if (num_files_ok != num_files)
+ return EXIT_FAILURE;
+ else
+ return EXIT_SUCCESS;
+}
+
int qcheck_main(int argc, char **argv)
{
DIR *dir, *dirp;
int i, ret;
+ int portroot_fd, vdb_fd, cat_fd, pkg_fd;
struct dirent *dentry, *de;
- char search_all = 0;
- char qc_update = 0;
- char chk_afk = 1;
- char chk_hash = 1;
- char chk_mtime = 1;
+ bool search_all = 0;
+ bool qc_update = false;
+ bool chk_afk = true;
+ bool chk_hash = true;
+ bool chk_mtime = true;
bool undo_prelink = false;
- struct stat st;
- size_t num_files, num_files_ok, num_files_unknown, num_files_ignored;
- char buf[_Q_PATH_MAX], filename[_Q_PATH_MAX];
- char buffer[_Q_PATH_MAX];
regex_t **regex_head = NULL;
size_t regex_count = 0;
@@ -78,7 +299,7 @@ int qcheck_main(int argc, char **argv)
while ((i = GETOPT_LONG(QCHECK, qcheck, "")) != -1) {
switch (i) {
COMMON_GETOPTS_CASES(qcheck)
- case 'a': search_all = 1; break;
+ case 'a': search_all = true; break;
case 'e': exact = 1; break;
case 's': {
regex_head = xrealloc(regex_head, (regex_count + 1) * sizeof(*regex_head));
@@ -87,42 +308,47 @@ int qcheck_main(int argc, char **argv)
++regex_count;
}
break;
- case 'u': qc_update = 1; break;
- case 'A': chk_afk = 0; break;
- case 'B': bad_only = 1; break;
- case 'H': chk_hash = 0; break;
- case 'T': chk_mtime = 0; break;
+ case 'u': qc_update = true; break;
+ case 'A': chk_afk = false; break;
+ case 'B': bad_only = true; break;
+ case 'H': chk_hash = false; break;
+ case 'T': chk_mtime = false; break;
case 'p': undo_prelink = prelink_available(); break;
}
}
if ((argc == optind) && !search_all)
qcheck_usage(EXIT_FAILURE);
- snprintf(buf, sizeof(buf), "%s/%s", portroot, portvdb);
- xchdir(buf);
- if ((dir = opendir(".")) == NULL)
- errp("unable to read '.' !?");
+ portroot_fd = open(portroot, O_RDONLY|O_CLOEXEC);
+ if (portroot_fd == -1)
+ errp("unable to read %s !?", portroot);
+ vdb_fd = openat(portroot_fd, portvdb + 1, O_RDONLY|O_CLOEXEC);
+ if (vdb_fd == -1 || (dir = fdopendir(vdb_fd)) == NULL)
+ errp("unable to read %s !?", portvdb);
ret = EXIT_SUCCESS;
/* open /var/db/pkg */
while ((dentry = q_vdb_get_next_dir(dir))) {
- if (chdir(dentry->d_name) != 0)
+ cat_fd = openat(vdb_fd, dentry->d_name, O_RDONLY|O_CLOEXEC);
+ if (cat_fd == -1)
continue;
- if ((dirp = opendir(".")) == NULL)
+ if ((dirp = fdopendir(cat_fd)) == NULL) {
+ close(cat_fd);
continue;
+ }
/* open the cateogry */
while ((de = readdir(dirp)) != NULL) {
- FILE *fp, *fpx;
if (*de->d_name == '.')
continue;
- fp = fpx = NULL;
/* see if this cat/pkg is requested */
if (!search_all) {
+ char *buf = NULL;
for (i = optind; i < argc; ++i) {
- snprintf(buf, sizeof(buf), "%s/%s", dentry->d_name, de->d_name);
+ free(buf);
+ xasprintf(&buf, "%s/%s", dentry->d_name, de->d_name);
if (!exact) {
if (rematch(argv[i], buf, REG_EXTENDED) == 0)
break;
@@ -141,211 +367,27 @@ int qcheck_main(int argc, char **argv)
break;
if ((strcmp(argv[i], strstr(swap, "/") + 1) == 0) || (strcmp(argv[i], strstr(buf, "/") + 1) == 0))
break;
- }
+ }
}
+ free(buf);
if (i == argc)
continue;
}
- snprintf(buf, sizeof(buf), "%s%s/%s/%s/CONTENTS", portroot, portvdb, dentry->d_name, de->d_name);
- if ((fp = fopen(buf, "re")) == NULL)
+ pkg_fd = openat(cat_fd, de->d_name, O_RDONLY|O_CLOEXEC);
+ if (pkg_fd == -1)
continue;
- strncat(buf, "~", sizeof(buf)-strlen(buf)-1);
- num_files = num_files_ok = num_files_unknown = num_files_ignored = 0;
- qcprintf("%sing %s%s/%s%s ...\n",
- (qc_update ? "Updat" : "Check"),
- GREEN, dentry->d_name, de->d_name, NORM);
- if (qc_update) {
- if ((fpx = fopen(buf, "we")) == NULL) {
- fclose(fp);
- warnp("unable to fopen(%s, w)", buf);
- continue;
- }
- }
- while ((fgets(buf, sizeof(buf), fp)) != NULL) {
- contents_entry *e;
- /* safe. buf and buffer are the same size.. */
- strcpy(buffer, buf);
- e = contents_parse_line(buf);
- if (!e)
- continue;
- if (strcmp(portroot, "/") != 0) {
- snprintf(filename, sizeof(filename), "%s%s", portroot, e->name);
- e->name = filename;
- }
-
- /* run our little checks */
- ++num_files;
- if (regex_count) {
- size_t j;
- for (j = 0; j < regex_count; ++j)
- if (!regexec(regex_head[j], e->name, 0, NULL, 0))
- break;
- if (j < regex_count) {
- --num_files;
- ++num_files_ignored;
- continue;
- }
- }
- if (lstat(e->name, &st)) {
- /* make sure file exists */
- if (chk_afk) {
- qcprintf(" %sAFK%s: %s\n", RED, NORM, e->name);
- } else {
- --num_files;
- ++num_files_ignored;
- if (qc_update)
- fputs(buffer, fpx);
- }
- continue;
- }
- if (e->digest && S_ISREG(st.st_mode)) {
- /* validate digest (handles MD5 / SHA1) */
- uint8_t hash_algo;
- char *hashed_file;
- hash_cb_t hash_cb = undo_prelink ? hash_cb_prelink_undo : hash_cb_default;
- switch (strlen(e->digest)) {
- case 32: hash_algo = HASH_MD5; break;
- case 40: hash_algo = HASH_SHA1; break;
- default: hash_algo = 0; break;
- }
- if (!hash_algo) {
- if (chk_hash) {
- qcprintf(" %sUNKNOWN DIGEST%s: '%s' for '%s'\n", RED, NORM, e->digest, e->name);
- ++num_files_unknown;
- } else {
- --num_files;
- ++num_files_ignored;
- if (qc_update)
- fputs(buffer, fpx);
- }
- continue;
- }
- hashed_file = (char*)hash_file_cb(e->name, hash_algo, hash_cb);
- if (!hashed_file) {
- ++num_files_unknown;
- free(hashed_file);
- if (qc_update) {
- fputs(buffer, fpx);
- if (!verbose)
- continue;
- }
- qcprintf(" %sPERM %4o%s: %s\n", RED, (unsigned int)(st.st_mode & 07777), NORM, e->name);
- continue;
- } else if (strcmp(e->digest, hashed_file)) {
- if (chk_hash) {
- const char *digest_disp;
- if (qc_update)
- fprintf(fpx, "obj %s %s %lu\n", e->name, hashed_file, st.st_mtime);
- switch (hash_algo) {
- case HASH_MD5: digest_disp = "MD5"; break;
- case HASH_SHA1: digest_disp = "SHA1"; break;
- default: digest_disp = "UNK"; break;
- }
- qcprintf(" %s%s-DIGEST%s: %s", RED, digest_disp, NORM, e->name);
- if (verbose)
- qcprintf(" (recorded '%s' != actual '%s')", e->digest, hashed_file);
- qcprintf("\n");
- } else {
- --num_files;
- ++num_files_ignored;
- if (qc_update)
- fputs(buffer, fpx);
- }
- free(hashed_file);
- continue;
- } else if (e->mtime && e->mtime != st.st_mtime) {
- if (chk_mtime) {
- qcprintf(" %sMTIME%s: %s", RED, NORM, e->name);
- if (verbose)
- qcprintf(" (recorded '%lu' != actual '%lu')", e->mtime, (unsigned long)st.st_mtime);
- qcprintf("\n");
-
- /* This can only be an obj, dir and sym have no digest */
- if (qc_update)
- fprintf(fpx, "obj %s %s %lu\n", e->name, e->digest, st.st_mtime);
- } else {
- --num_files;
- ++num_files_ignored;
- if (qc_update)
- fputs(buffer, fpx);
- }
- free(hashed_file);
- continue;
- } else {
- if (qc_update)
- fputs(buffer, fpx);
- free(hashed_file);
- }
- } else if (e->mtime && e->mtime != st.st_mtime) {
- if (chk_mtime) {
- qcprintf(" %sMTIME%s: %s", RED, NORM, e->name);
- if (verbose)
- qcprintf(" (recorded '%lu' != actual '%lu')", e->mtime, (unsigned long)st.st_mtime);
- qcprintf("\n");
-
- /* This can only be a sym */
- if (qc_update)
- fprintf(fpx, "sym %s -> %s %lu\n", e->name, e->sym_target, st.st_mtime);
- } else {
- --num_files;
- ++num_files_ignored;
- if (qc_update)
- fputs(buffer, fpx);
- }
- continue;
- } else {
- if (qc_update)
- fputs(buffer, fpx);
- }
- ++num_files_ok;
- }
- fclose(fp);
- if (qc_update) {
- fclose(fpx);
- snprintf(buf, sizeof(buf), "%s%s/%s/%s/CONTENTS", portroot, portvdb,
- dentry->d_name, de->d_name);
- strcpy(buffer, buf);
- strncat(buffer, "~", sizeof(buffer)-strlen(buf)-1);
- rename(buffer, buf);
- if (!verbose)
- continue;
- }
- if (bad_only && num_files_ok != num_files) {
- if (verbose)
- printf("%s/%s\n", dentry->d_name, de->d_name);
- else {
- depend_atom *atom = NULL;
- snprintf(buf, sizeof(buf), "%s/%s", dentry->d_name, de->d_name);
- if ((atom = atom_explode(buf)) != NULL) {
- printf("%s/%s\n", dentry->d_name, atom->PN);
- atom_implode(atom);
- } else {
- printf("%s/%s\n", dentry->d_name, de->d_name);
- }
- }
- }
- qcprintf(" %2$s*%1$s %3$s%4$zu%1$s out of %3$s%5$zu%1$s file%6$s are good",
- NORM, BOLD, BLUE, num_files_ok, num_files,
- (num_files > 1 ? "s" : ""));
- if (num_files_unknown)
- qcprintf(" (Unable to digest %2$s%3$zu%1$s file%4$s)",
- NORM, BLUE, num_files_unknown,
- (num_files_unknown > 1 ? "s" : ""));
- if (num_files_ignored)
- qcprintf(" (%2$s%3$zu%1$s file%4$s ignored)",
- NORM, BLUE, num_files_ignored,
- (num_files_ignored > 1 ? "s were" : " was"));
- qcprintf("\n");
- if (num_files_ok != num_files)
- ret = EXIT_FAILURE;
+ ret = qcheck_process_contents(portroot_fd, pkg_fd,
+ dentry->d_name, de->d_name, regex_head, regex_count,
+ qc_update, chk_afk, chk_hash, chk_mtime, undo_prelink);
+ close(pkg_fd);
}
closedir(dirp);
- xchdir("..");
}
qcheck_cleanup(regex_head, regex_count);
+ close(portroot_fd);
return ret;
}