commit: 16e7280ec40c26f586f0db62f0d63960dd42a3d0
Author: Sam Besselink <sambesselink <AT> planet <DOT> nl>
AuthorDate: Wed Oct 24 22:30:31 2018 +0000
Commit: Fabian Groffen <grobian <AT> gentoo <DOT> org>
CommitDate: Fri Dec 28 09:07:25 2018 +0000
URL: https://gitweb.gentoo.org/proj/portage-utils.git/commit/?id=16e7280e
Refactor: use successive fail branches
Signed-off-by: Fabian Groffen <grobian <AT> gentoo.org>
qcheck.c | 231 ++++++++++++++++++++++++++++++++++-----------------------------
1 file changed, 126 insertions(+), 105 deletions(-)
diff --git a/qcheck.c b/qcheck.c
index 8a83466..7b6e58c 100644
--- a/qcheck.c
+++ b/qcheck.c
@@ -50,8 +50,8 @@ struct qcheck_opt_state {
static int
qcheck_process_contents(q_vdb_pkg_ctx *pkg_ctx, struct qcheck_opt_state *state)
{
- int fd;
- FILE *fp, *fpx;
+ int fd_contents;
+ FILE *fp_contents, *fp_contents_update;
const char *catname = pkg_ctx->cat_ctx->name;
const char *pkgname = pkg_ctx->name;
size_t num_files, num_files_ok, num_files_unknown, num_files_ignored;
@@ -61,28 +61,30 @@ qcheck_process_contents(q_vdb_pkg_ctx *pkg_ctx, struct
qcheck_opt_state *state)
int cp_argc, cpm_argc;
char **cp_argv, **cpm_argv;
- fpx = NULL;
+ fp_contents_update = NULL;
- fd = q_vdb_pkg_openat(pkg_ctx, "CONTENTS", O_RDONLY|O_CLOEXEC, 0);
- if (fd == -1)
+ /* Open contents */
+ fd_contents = q_vdb_pkg_openat(pkg_ctx, "CONTENTS", O_RDONLY|O_CLOEXEC,
0);
+ if (fd_contents == -1)
return EXIT_SUCCESS;
- if (fstat(fd, &cst)) {
- close(fd);
+ if (fstat(fd_contents, &cst)) {
+ close(fd_contents);
return EXIT_SUCCESS;
}
- if ((fp = fdopen(fd, "r")) == NULL) {
- close(fd);
+ if ((fp_contents = fdopen(fd_contents, "r")) == NULL) {
+ close(fd_contents);
return EXIT_SUCCESS;
}
+ /* Open contents_update, if needed */
num_files = num_files_ok = num_files_unknown = num_files_ignored = 0;
qcprintf("%sing %s%s/%s%s ...\n",
(state->qc_update ? "Updat" : "Check"),
GREEN, catname, pkgname, NORM);
if (state->qc_update) {
- fpx = q_vdb_pkg_fopenat_rw(pkg_ctx, "CONTENTS~");
- if (fpx == NULL) {
- fclose(fp);
+ fp_contents_update = q_vdb_pkg_fopenat_rw(pkg_ctx, "CONTENTS~");
+ if (fp_contents_update == NULL) {
+ fclose(fp_contents);
warnp("unable to fopen(%s/%s, w)", pkgname,
"CONTENTS~");
return EXIT_FAILURE;
}
@@ -94,21 +96,23 @@ qcheck_process_contents(q_vdb_pkg_ctx *pkg_ctx, struct
qcheck_opt_state *state)
}
buffer = line = NULL;
- while (getline(&line, &linelen, fp) != -1) {
- contents_entry *e;
+ while (getline(&line, &linelen, fp_contents) != -1) {
+ contents_entry *entry;
free(buffer);
buffer = xstrdup(line);
- e = contents_parse_line(line);
- if (!e)
+
+ entry = contents_parse_line(line);
+
+ if (!entry)
continue;
- /* run our little checks */
+ /* run initial checks */
++num_files;
if (array_cnt(state->regex_arr)) {
size_t n;
regex_t *regex;
array_for_each(state->regex_arr, n, regex)
- if (!regexec(regex, e->name, 0, NULL, 0))
+ if (!regexec(regex, entry->name, 0, NULL, 0))
break;
if (n < array_cnt(state->regex_arr)) {
--num_files;
@@ -116,142 +120,159 @@ qcheck_process_contents(q_vdb_pkg_ctx *pkg_ctx, struct
qcheck_opt_state *state)
continue;
}
}
- if (fstatat(pkg_ctx->cat_ctx->ctx->portroot_fd, e->name + 1,
&st, AT_SYMLINK_NOFOLLOW)) {
+ if (fstatat(pkg_ctx->cat_ctx->ctx->portroot_fd, entry->name +
1, &st, AT_SYMLINK_NOFOLLOW)) {
/* make sure file exists */
if (state->chk_afk) {
if (errno == ENOENT)
- qcprintf(" %sAFK%s: %s\n", RED, NORM,
e->name);
+ qcprintf(" %sAFK%s: %s\n", RED, NORM,
entry->name);
else
- qcprintf(" %sERROR (%s)%s: %s\n", RED,
strerror(errno), NORM, e->name);
+ qcprintf(" %sERROR (%s)%s: %s\n", RED,
strerror(errno), NORM, entry->name);
} else {
--num_files;
++num_files_ignored;
if (state->qc_update)
- fputs(buffer, fpx);
+ fputs(buffer, fp_contents_update);
}
continue;
}
- if (e->digest && S_ISREG(st.st_mode)) {
- if (!state->chk_config_protect) {
- /* handle CONFIG_PROTECT-ed files */
- int i;
- /* if it's in CONFIG_PROTECT_MASK, check it
like normal */
- for (i = 1; i < cpm_argc; ++i)
- if (strncmp(cpm_argv[i], e->name,
strlen(cpm_argv[i])) == 0)
- break;
- if (i == cpm_argc) {
- /* not explicitly masked, so if it's
protected */
- for (i = 1; i < cp_argc; ++i)
- if (strncmp(cp_argv[i],
e->name, strlen(cp_argv[i])) == 0)
- goto cfg_protected;
- }
+
+ /* Handle CONFIG_PROTECT-ed files */
+ if (!state->chk_config_protect) {
+ int i;
+ /* If in CONFIG_PROTECT_MASK, handle like normal */
+ for (i = 1; i < cpm_argc; ++i)
+ if (strncmp(cpm_argv[i], entry->name,
strlen(cpm_argv[i])) == 0)
+ break;
+ if (i == cpm_argc) {
+ /* Not explicitly masked, so it's protected */
+ for (i = 1; i < cp_argc; ++i)
+ if (strncmp(cp_argv[i], entry->name,
strlen(cp_argv[i])) == 0) {
+ num_files_ok++;
+ continue;
+ }
}
+ }
+
+ /* For certain combinations of flags and filetypes, a file
+ * won't get checks and should be ignored */
+ if (!state->chk_mtime && entry->type == CONTENTS_SYM) {
+ --num_files;
+ ++num_files_ignored;
+ if (state->qc_update)
+ fputs(buffer, fp_contents_update);
- /* validate digest (handles MD5 / SHA1) */
+ continue;
+ }
+
+ /* Digest checks only work on regular files
+ * Note: We don't check for state->chk_hash when entering
+ * but rather in digest-check #3, because we only succeed
+ * tests/qcheck/list04.good if when chk_hash is false, we
+ * do check hashes, but only print mismatched digests as
+ * 'ignored file'. */
+ if (entry->digest && S_ISREG(st.st_mode)) {
+ /* Validate digest (handles MD5 / SHA1)
+ * Digest-check 1/3:
+ * Should we check digests? */
+ char *f_digest;
uint8_t hash_algo;
- char *hashed_file;
- hash_cb_t hash_cb = state->undo_prelink ?
hash_cb_prelink_undo : hash_cb_default;
- switch (strlen(e->digest)) {
+ switch (strlen(entry->digest)) {
case 32: hash_algo = HASH_MD5; break;
case 40: hash_algo = HASH_SHA1; break;
default: hash_algo = 0; break;
}
+
if (!hash_algo) {
if (state->chk_hash) {
- qcprintf(" %sUNKNOWN DIGEST%s: '%s' for
'%s'\n", RED, NORM, e->digest, e->name);
+ qcprintf(" %sUNKNOWN DIGEST%s: '%s' for
'%s'\n", RED, NORM, entry->digest, entry->name);
++num_files_unknown;
} else {
--num_files;
++num_files_ignored;
if (state->qc_update)
- fputs(buffer, fpx);
+ fputs(buffer,
fp_contents_update);
}
continue;
}
- hashed_file = (char
*)hash_file_at_cb(pkg_ctx->cat_ctx->ctx->portroot_fd, e->name + 1, hash_algo,
hash_cb);
- if (!hashed_file) {
+
+ hash_cb_t hash_cb = state->undo_prelink ?
hash_cb_prelink_undo : hash_cb_default;
+ f_digest = (char
*)hash_file_at_cb(pkg_ctx->cat_ctx->ctx->portroot_fd, entry->name + 1,
hash_algo, hash_cb);
+
+ /* Digest-check 2/3:
+ * Can we get a digest of the file? */
+ if (!f_digest) {
++num_files_unknown;
- free(hashed_file);
- if (state->qc_update) {
- fputs(buffer, fpx);
- if (!verbose)
- continue;
- }
- qcprintf(" %sPERM %4o%s: %s\n", RED, (unsigned
int)(st.st_mode & 07777), NORM, e->name);
+ free(f_digest);
+
+ if (state->qc_update)
+ fputs(buffer, fp_contents_update);
+
+ if (verbose)
+ qcprintf(" %sPERM %4o%s: %s\n", RED,
(unsigned int)(st.st_mode & 07777), NORM, entry->name);
+
continue;
- } else if (strcmp(e->digest, hashed_file)) {
+ }
+
+ /* Digest-check 3/3:
+ * Does the digest equal what portage recorded? */
+ if (strcmp(entry->digest, f_digest) != 0) {
if (state->chk_hash) {
- const char *digest_disp;
if (state->qc_update)
- fprintf(fpx, "obj %s %s
%"PRIu64"\n", e->name, hashed_file, (uint64_t)st.st_mtime);
+ fprintf(fp_contents_update,
"obj %s %s %"PRIu64"\n", entry->name, f_digest, (uint64_t)st.st_mtime);
+
+ const char *digest_disp;
switch (hash_algo) {
- case HASH_MD5: digest_disp =
"MD5"; break;
- case HASH_SHA1: digest_disp =
"SHA1"; break;
- default: digest_disp =
"UNK"; break;
+ 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);
+
+ qcprintf(" %s%s-DIGEST%s: %s", RED,
digest_disp, NORM, entry->name);
if (verbose)
- qcprintf(" (recorded '%s' !=
actual '%s')", e->digest, hashed_file);
+ qcprintf(" (recorded '%s' !=
actual '%s')", entry->digest, f_digest);
qcprintf("\n");
} else {
--num_files;
++num_files_ignored;
if (state->qc_update)
- fputs(buffer, fpx);
+ fputs(buffer,
fp_contents_update);
}
- free(hashed_file);
+
+ free(f_digest);
continue;
- } else if (e->mtime && e->mtime != st.st_mtime) {
- if (state->chk_mtime) {
- qcprintf(" %sMTIME%s: %s", RED, NORM,
e->name);
- if (verbose)
- qcprintf(" (recorded
'%"PRIu64"' != actual '%"PRIu64"')", (uint64_t)e->mtime, (uint64_t)st.st_mtime);
- qcprintf("\n");
+ }
- /* This can only be an obj, dir and sym
have no digest */
- if (state->qc_update)
- fprintf(fpx, "obj %s %s
%"PRIu64"\n", e->name, e->digest, (uint64_t)st.st_mtime);
+ free(f_digest);
+ }
+
+ /* Validate mtimes */
+ if (state->chk_mtime && entry->mtime && entry->mtime !=
st.st_mtime) {
+ qcprintf(" %sMTIME%s: %s", RED, NORM, entry->name);
+ if (verbose)
+ qcprintf(" (recorded '%"PRIu64"' != actual
'%"PRIu64"')", (uint64_t)entry->mtime, (uint64_t)st.st_mtime);
+ qcprintf("\n");
+
+ /* Update mtime */
+ if (state->qc_update) {
+ if (entry->type == CONTENTS_SYM) {
+ fprintf(fp_contents_update, "sym %s ->
%s %"PRIu64"\n", entry->name, entry->sym_target, (uint64_t)st.st_mtime);
} else {
- --num_files;
- ++num_files_ignored;
- if (state->qc_update)
- fputs(buffer, fpx);
+ fprintf(fp_contents_update, "obj %s %s
%"PRIu64"\n", entry->name, entry->digest, (uint64_t)st.st_mtime);
}
- free(hashed_file);
- continue;
- } else {
- if (state->qc_update)
- fputs(buffer, fpx);
- free(hashed_file);
}
- } else if (e->mtime && e->mtime != st.st_mtime) {
- if (state->chk_mtime) {
- qcprintf(" %sMTIME%s: %s", RED, NORM, e->name);
- if (verbose)
- qcprintf(" (recorded '%"PRIu64"' !=
actual '%"PRIu64"')",
- (uint64_t)e->mtime,
(uint64_t)st.st_mtime);
- qcprintf("\n");
- /* This can only be a sym */
- if (state->qc_update)
- fprintf(fpx, "sym %s -> %s
%"PRIu64"\n", e->name, e->sym_target, (uint64_t)st.st_mtime);
- } else {
- --num_files;
- ++num_files_ignored;
- if (state->qc_update)
- fputs(buffer, fpx);
- }
continue;
- } else {
- if (state->qc_update)
- fputs(buffer, fpx);
}
- cfg_protected:
- ++num_files_ok;
+
+ /* Success! */
+ if (state->qc_update)
+ fputs(buffer, fp_contents_update);
+
+ num_files_ok++;
}
free(line);
free(buffer);
- fclose(fp);
+ fclose(fp_contents);
if (!state->chk_config_protect) {
freeargv(cp_argc, cp_argv);
@@ -259,13 +280,13 @@ qcheck_process_contents(q_vdb_pkg_ctx *pkg_ctx, struct
qcheck_opt_state *state)
}
if (state->qc_update) {
- if (fchown(fd, cst.st_uid, cst.st_gid)) {
+ if (fchown(fd_contents, cst.st_uid, cst.st_gid)) {
/* meh */;
}
- if (fchmod(fd, cst.st_mode)) {
+ if (fchmod(fd_contents, cst.st_mode)) {
/* meh */;
}
- fclose(fpx);
+ fclose(fp_contents_update);
if (renameat(pkg_ctx->fd, "CONTENTS~", pkg_ctx->fd, "CONTENTS"))
unlinkat(pkg_ctx->fd, "CONTENTS~", 0);
if (!verbose)