Gentoo Archives: gentoo-commits

From: Fabian Groffen <grobian@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/portage-utils:master commit in: tests/qcheck/, /
Date: Sat, 09 Apr 2022 11:32:58
Message-Id: 1649503950.ede72d3cf08df8ffe7e59c4819d9a6c84ab1659f.grobian@gentoo
1 commit: ede72d3cf08df8ffe7e59c4819d9a6c84ab1659f
2 Author: Fabian Groffen <grobian <AT> gentoo <DOT> org>
3 AuthorDate: Sat Apr 9 11:17:39 2022 +0000
4 Commit: Fabian Groffen <grobian <AT> gentoo <DOT> org>
5 CommitDate: Sat Apr 9 11:32:30 2022 +0000
6 URL: https://gitweb.gentoo.org/proj/portage-utils.git/commit/?id=ede72d3c
7
8 qcheck: fix config-protect check, bug #837188
9
10 ensure we break out of the config-protect directories loop, instead of
11 just skipping one directory, such that we don't produce bogus amounts of
12 files, and also don't check despite we were told not to check (-P)
13
14 Bug: https://bugs.gentoo.org/837188
15 Signed-off-by: Fabian Groffen <grobian <AT> gentoo.org>
16
17 qcheck.c | 253 ++++++++++++++++++++++++++++-------------------
18 tests/qcheck/list05.good | 2 +-
19 tests/qcheck/list07.good | 2 +-
20 3 files changed, 156 insertions(+), 101 deletions(-)
21
22 diff --git a/qcheck.c b/qcheck.c
23 index 9d9a86c..813c1f7 100644
24 --- a/qcheck.c
25 +++ b/qcheck.c
26 @@ -1,5 +1,5 @@
27 /*
28 - * Copyright 2005-2020 Gentoo Foundation
29 + * Copyright 2005-2022 Gentoo Foundation
30 * Distributed under the terms of the GNU General Public License v2
31 *
32 * Copyright 2005-2010 Ned Ludd - <solar@g.o>
33 @@ -74,30 +74,30 @@ static int
34 qcheck_cb(tree_pkg_ctx *pkg_ctx, void *priv)
35 {
36 struct qcheck_opt_state *state = priv;
37 - FILE *fp_contents_update;
38 - size_t num_files;
39 - size_t num_files_ok;
40 - size_t num_files_unknown;
41 - size_t num_files_ignored;
42 - struct stat st;
43 - char *buffer;
44 - char *line;
45 - char *savep;
46 - int cp_argc;
47 - int cpm_argc;
48 - char **cp_argv;
49 - char **cpm_argv;
50 - depend_atom *atom;
51 -
52 - fp_contents_update = NULL;
53 -
54 - /* Open contents */
55 + struct stat st;
56 + depend_atom *atom;
57 + FILE *fp_contents_update = NULL;
58 + size_t num_files = 0;
59 + size_t num_files_ok = 0;
60 + size_t num_files_unknown = 0;
61 + size_t num_files_ignored = 0;
62 + char *buffer;
63 + char *line;
64 + char *savep;
65 + char *eprefix = NULL;
66 + size_t eprefix_len = 0;
67 + int cp_argc;
68 + int cpm_argc;
69 + char **cp_argv;
70 + char **cpm_argv;
71 +
72 + /* get CONTENTS from meta */
73 line = tree_pkg_meta_get(pkg_ctx, CONTENTS);
74 if (line == NULL)
75 return EXIT_FAILURE;
76
77 atom = tree_get_atom(pkg_ctx, false);
78 - num_files = num_files_ok = num_files_unknown = num_files_ignored = 0;
79 +
80 qcprintf("%sing %s ...\n",
81 (state->qc_update ? "Updat" : "Check"),
82 atom_format(state->fmt, atom));
83 @@ -124,6 +124,10 @@ qcheck_cb(tree_pkg_ctx *pkg_ctx, void *priv)
84 if (!state->chk_config_protect) {
85 makeargv(config_protect, &cp_argc, &cp_argv);
86 makeargv(config_protect_mask, &cpm_argc, &cpm_argv);
87 +
88 + eprefix = tree_pkg_meta_get(pkg_ctx, EPREFIX);
89 + if (eprefix != NULL)
90 + eprefix_len = strlen(eprefix);
91 }
92
93 buffer = NULL;
94 @@ -136,8 +140,9 @@ qcheck_cb(tree_pkg_ctx *pkg_ctx, void *priv)
95 if (!entry)
96 continue;
97
98 - /* run initial checks */
99 - ++num_files;
100 + num_files++;
101 +
102 + /* handle skips */
103 if (array_cnt(state->regex_arr)) {
104 size_t n;
105 regex_t *regex;
106 @@ -145,15 +150,55 @@ qcheck_cb(tree_pkg_ctx *pkg_ctx, void *priv)
107 if (!regexec(regex, entry->name, 0, NULL, 0))
108 break;
109 if (n < array_cnt(state->regex_arr)) {
110 - --num_files;
111 - ++num_files_ignored;
112 + num_files--;
113 + num_files_ignored++;
114 + if (verbose)
115 + qcprintf(" %sSKIP%s %s: matches regex\n",
116 + YELLOW, NORM, entry->name);
117 + if (state->qc_update)
118 + fprintf(fp_contents_update, "%s\n", buffer);
119 continue;
120 }
121 }
122 +
123 + /* handle CONFIG_PROTECT-ed files */
124 + if (!state->chk_config_protect) {
125 + int i;
126 + char *p;
127 +
128 + /* compute path without EPREFIX */
129 + p = entry->name;
130 + if (strlen(p) > eprefix_len)
131 + p += eprefix_len;
132 +
133 + /* if in CONFIG_PROTECT_MASK, handle like normal */
134 + for (i = 1; i < cpm_argc; ++i) {
135 + if (strncmp(cpm_argv[i], p, strlen(cpm_argv[i])) == 0)
136 + break;
137 + }
138 + if (i == cpm_argc) {
139 + /* not explicitly unmasked, check if it's protected */
140 + for (i = 1; i < cp_argc; ++i) {
141 + if (strncmp(cp_argv[i], p, strlen(cp_argv[i])) == 0) {
142 + num_files--;
143 + num_files_ignored++;
144 + if (verbose)
145 + qcprintf(" %sSKIP%s %s: protected via %s\n",
146 + YELLOW, NORM, entry->name, cp_argv[i]);
147 + if (state->qc_update)
148 + fprintf(fp_contents_update, "%s\n", buffer);
149 + break;
150 + }
151 + }
152 + if (i != cp_argc)
153 + continue;
154 + }
155 + }
156 +
157 + /* check file existence */
158 if (fstatat(pkg_ctx->cat_ctx->ctx->portroot_fd, entry->name + 1,
159 - &st, AT_SYMLINK_NOFOLLOW))
160 + &st, AT_SYMLINK_NOFOLLOW) != 0)
161 {
162 - /* make sure file exists */
163 if (state->chk_afk) {
164 if (errno == ENOENT)
165 qcprintf(" %sAFK%s: %s\n", RED, NORM, entry->name);
166 @@ -161,42 +206,27 @@ qcheck_cb(tree_pkg_ctx *pkg_ctx, void *priv)
167 qcprintf(" %sERROR (%s)%s: %s\n", RED,
168 strerror(errno), NORM, entry->name);
169 } else {
170 - --num_files;
171 - ++num_files_ignored;
172 + num_files--;
173 + num_files_ignored++;
174 + if (verbose)
175 + qcprintf(" %sSKIP%s %s: %s\n",
176 + YELLOW, NORM, entry->name, strerror(errno));
177 if (state->qc_update)
178 fprintf(fp_contents_update, "%s\n", buffer);
179 }
180 continue;
181 }
182
183 - /* Handle CONFIG_PROTECT-ed files */
184 - if (!state->chk_config_protect) {
185 - int i;
186 - /* If in CONFIG_PROTECT_MASK, handle like normal */
187 - for (i = 1; i < cpm_argc; ++i)
188 - if (strncmp(cpm_argv[i], entry->name, strlen(cpm_argv[i])) == 0)
189 - break;
190 - if (i == cpm_argc) {
191 - /* Not explicitly masked, so it's protected */
192 - for (i = 1; i < cp_argc; ++i) {
193 - if (strncmp(cp_argv[i], entry->name,
194 - strlen(cp_argv[i])) == 0)
195 - {
196 - num_files_ok++;
197 - continue;
198 - }
199 - }
200 - }
201 - }
202 -
203 - /* For certain combinations of flags and filetypes, a file
204 + /* for certain combinations of flags and filetypes, a file
205 * won't get checks and should be ignored */
206 if (!state->chk_mtime && entry->type == CONTENTS_SYM) {
207 - --num_files;
208 - ++num_files_ignored;
209 + num_files--;
210 + num_files_ignored++;
211 + if (verbose)
212 + qcprintf(" %sSKIP%s %s: symlink and no mtime check\n",
213 + YELLOW, NORM, entry->name);
214 if (state->qc_update)
215 fprintf(fp_contents_update, "%s\n", buffer);
216 -
217 continue;
218 }
219
220 @@ -207,31 +237,36 @@ qcheck_cb(tree_pkg_ctx *pkg_ctx, void *priv)
221 * do check hashes, but only print mismatched digests as
222 * 'ignored file'. */
223 if (entry->digest && S_ISREG(st.st_mode)) {
224 + char *f_digest;
225 + int hash_algo;
226 +
227 /* Validate digest (handles MD5 / SHA1)
228 * Digest-check 1/3:
229 - * Should we check digests? */
230 - char *f_digest;
231 - uint8_t hash_algo;
232 + * should we check digests? */
233 switch (strlen(entry->digest)) {
234 - case 32: hash_algo = HASH_MD5; break;
235 - case 40: hash_algo = HASH_SHA1; break;
236 - default: hash_algo = 0; break;
237 + case 32: hash_algo = (int)HASH_MD5; break;
238 + case 40: hash_algo = (int)HASH_SHA1; break;
239 + default: hash_algo = 0; break;
240 }
241
242 - if (!hash_algo) {
243 + if (hash_algo == 0) {
244 if (state->chk_hash) {
245 qcprintf(" %sUNKNOWN DIGEST%s: '%s' for '%s'\n",
246 - RED, NORM, entry->digest, entry->name);
247 - ++num_files_unknown;
248 + RED, NORM, entry->digest, entry->name);
249 + num_files_unknown++;
250 } else {
251 - --num_files;
252 - ++num_files_ignored;
253 + num_files--;
254 + num_files_ignored++;
255 + if (verbose)
256 + qcprintf(" %sSKIP%s %s: unknown digest\n",
257 + YELLOW, NORM, entry->name);
258 if (state->qc_update)
259 fprintf(fp_contents_update, "%s\n", buffer);
260 }
261 continue;
262 }
263
264 + /* compute hash for file */
265 hash_cb_t hash_cb =
266 state->undo_prelink ? hash_cb_prelink_undo : NULL;
267 f_digest = hash_file_at_cb(
268 @@ -239,45 +274,51 @@ qcheck_cb(tree_pkg_ctx *pkg_ctx, void *priv)
269 entry->name + 1, hash_algo, hash_cb);
270
271 /* Digest-check 2/3:
272 - * Can we get a digest of the file? */
273 - if (!f_digest) {
274 - ++num_files_unknown;
275 + * do we have digest of the file? */
276 + if (f_digest == NULL) {
277 + num_files_unknown++;
278
279 if (state->qc_update)
280 fprintf(fp_contents_update, "%s\n", buffer);
281
282 if (verbose)
283 qcprintf(" %sPERM %4o%s: %s\n",
284 - RED, (unsigned int)(st.st_mode & 07777),
285 - NORM, entry->name);
286 + RED, (unsigned int)(st.st_mode & 07777),
287 + NORM, entry->name);
288
289 continue;
290 }
291
292 /* Digest-check 3/3:
293 - * Does the digest equal what portage recorded? */
294 + * does the digest equal what portage recorded? */
295 if (strcmp(entry->digest, f_digest) != 0) {
296 if (state->chk_hash) {
297 + const char *digest_disp;
298 +
299 if (state->qc_update)
300 - fprintf(fp_contents_update, "obj %s %s %"PRIu64"\n",
301 - entry->name, f_digest, (uint64_t)st.st_mtime);
302 + fprintf(fp_contents_update, "obj %s %s %llu\n",
303 + entry->name, f_digest,
304 + (long long int)st.st_mtime);
305
306 - const char *digest_disp;
307 switch (hash_algo) {
308 - case HASH_MD5: digest_disp = "MD5"; break;
309 - case HASH_SHA1: digest_disp = "SHA1"; break;
310 - default: digest_disp = "UNK"; break;
311 + case HASH_MD5: digest_disp = "MD5"; break;
312 + case HASH_SHA1: digest_disp = "SHA1"; break;
313 + default: digest_disp = "UNK"; break;
314 }
315
316 qcprintf(" %s%s-DIGEST%s: %s",
317 - RED, digest_disp, NORM, entry->name);
318 + RED, digest_disp, NORM, entry->name);
319 if (verbose)
320 qcprintf(" (recorded '%s' != actual '%s')",
321 - entry->digest, f_digest);
322 + entry->digest, f_digest);
323 qcprintf("\n");
324 } else {
325 - --num_files;
326 - ++num_files_ignored;
327 + num_files--;
328 + num_files_ignored++;
329 + if (verbose)
330 + qcprintf(" %sSKIP%s %s: digest mismatch "
331 + "but check disabled\n",
332 + YELLOW, NORM, entry->name);
333 if (state->qc_update)
334 fprintf(fp_contents_update, "%s\n", buffer);
335 }
336 @@ -286,30 +327,44 @@ qcheck_cb(tree_pkg_ctx *pkg_ctx, void *priv)
337 }
338 }
339
340 - /* Validate mtimes */
341 - if (state->chk_mtime && entry->mtime && entry->mtime != st.st_mtime) {
342 - qcprintf(" %sMTIME%s: %s", RED, NORM, entry->name);
343 - if (verbose)
344 - qcprintf(" (recorded '%"PRIu64"' != actual '%"PRIu64"')",
345 - (uint64_t)entry->mtime, (uint64_t)st.st_mtime);
346 - qcprintf("\n");
347 -
348 - /* Update mtime */
349 - if (state->qc_update) {
350 - if (entry->type == CONTENTS_SYM) {
351 - fprintf(fp_contents_update, "sym %s -> %s %"PRIu64"\n",
352 - entry->name, entry->sym_target,
353 - (uint64_t)st.st_mtime);
354 - } else {
355 - fprintf(fp_contents_update, "obj %s %s %"PRIu64"\n",
356 - entry->name, entry->digest, (uint64_t)st.st_mtime);
357 + /* validate mtimes */
358 + if (entry->mtime && entry->mtime != st.st_mtime) {
359 + if (state->chk_mtime) {
360 + qcprintf(" %sMTIME%s: %s", RED, NORM, entry->name);
361 + if (verbose)
362 + qcprintf(" (recorded '%llu' != actual '%llu')",
363 + (long long int)entry->mtime,
364 + (long long int)st.st_mtime);
365 + qcprintf("\n");
366 +
367 + /* Update mtime */
368 + if (state->qc_update) {
369 + if (entry->type == CONTENTS_SYM) {
370 + fprintf(fp_contents_update, "sym %s -> %s %llu\n",
371 + entry->name, entry->sym_target,
372 + (long long int)st.st_mtime);
373 + } else {
374 + fprintf(fp_contents_update, "obj %s %s %llu\n",
375 + entry->name, entry->digest,
376 + (long long int)st.st_mtime);
377 + }
378 }
379 - }
380
381 - continue;
382 + continue;
383 + } else {
384 + num_files--;
385 + num_files_ignored++;
386 + if (verbose)
387 + qcprintf(" %sSKIP%s %s: mtime mismatch "
388 + "but check disabled\n",
389 + YELLOW, NORM, entry->name);
390 + if (state->qc_update)
391 + fprintf(fp_contents_update, "%s\n", buffer);
392 + continue;
393 + }
394 }
395
396 - /* Success! */
397 + /* success! */
398 if (state->qc_update)
399 fprintf(fp_contents_update, "%s\n", buffer);
400
401
402 diff --git a/tests/qcheck/list05.good b/tests/qcheck/list05.good
403 index 688c177..bb1e169 100644
404 --- a/tests/qcheck/list05.good
405 +++ b/tests/qcheck/list05.good
406 @@ -6,6 +6,6 @@ Checking a-b/pkg ...
407 AFK: /missing-dir
408 AFK: /missing-dir/missing-file
409 AFK: /missing-dir/missing-sym
410 - * 4 out of 11 files are good (2 files were ignored)
411 + * 3 out of 10 files are good (3 files were ignored)
412 Checking virtual/pkg ...
413 * 0 out of 0 files are good
414
415 diff --git a/tests/qcheck/list07.good b/tests/qcheck/list07.good
416 index 847b0b5..c80a073 100644
417 --- a/tests/qcheck/list07.good
418 +++ b/tests/qcheck/list07.good
419 @@ -1,4 +1,4 @@
420 Checking a-b/pkg ...
421 - * 4 out of 4 files are good (9 files were ignored)
422 + * 3 out of 3 files are good (10 files were ignored)
423 Checking virtual/pkg ...
424 * 0 out of 0 files are good