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: /
Date: Fri, 28 Dec 2018 09:08:16
Message-Id: 1545988045.16e7280ec40c26f586f0db62f0d63960dd42a3d0.grobian@gentoo
1 commit: 16e7280ec40c26f586f0db62f0d63960dd42a3d0
2 Author: Sam Besselink <sambesselink <AT> planet <DOT> nl>
3 AuthorDate: Wed Oct 24 22:30:31 2018 +0000
4 Commit: Fabian Groffen <grobian <AT> gentoo <DOT> org>
5 CommitDate: Fri Dec 28 09:07:25 2018 +0000
6 URL: https://gitweb.gentoo.org/proj/portage-utils.git/commit/?id=16e7280e
7
8 Refactor: use successive fail branches
9
10 Signed-off-by: Fabian Groffen <grobian <AT> gentoo.org>
11
12 qcheck.c | 231 ++++++++++++++++++++++++++++++++++-----------------------------
13 1 file changed, 126 insertions(+), 105 deletions(-)
14
15 diff --git a/qcheck.c b/qcheck.c
16 index 8a83466..7b6e58c 100644
17 --- a/qcheck.c
18 +++ b/qcheck.c
19 @@ -50,8 +50,8 @@ struct qcheck_opt_state {
20 static int
21 qcheck_process_contents(q_vdb_pkg_ctx *pkg_ctx, struct qcheck_opt_state *state)
22 {
23 - int fd;
24 - FILE *fp, *fpx;
25 + int fd_contents;
26 + FILE *fp_contents, *fp_contents_update;
27 const char *catname = pkg_ctx->cat_ctx->name;
28 const char *pkgname = pkg_ctx->name;
29 size_t num_files, num_files_ok, num_files_unknown, num_files_ignored;
30 @@ -61,28 +61,30 @@ qcheck_process_contents(q_vdb_pkg_ctx *pkg_ctx, struct qcheck_opt_state *state)
31 int cp_argc, cpm_argc;
32 char **cp_argv, **cpm_argv;
33
34 - fpx = NULL;
35 + fp_contents_update = NULL;
36
37 - fd = q_vdb_pkg_openat(pkg_ctx, "CONTENTS", O_RDONLY|O_CLOEXEC, 0);
38 - if (fd == -1)
39 + /* Open contents */
40 + fd_contents = q_vdb_pkg_openat(pkg_ctx, "CONTENTS", O_RDONLY|O_CLOEXEC, 0);
41 + if (fd_contents == -1)
42 return EXIT_SUCCESS;
43 - if (fstat(fd, &cst)) {
44 - close(fd);
45 + if (fstat(fd_contents, &cst)) {
46 + close(fd_contents);
47 return EXIT_SUCCESS;
48 }
49 - if ((fp = fdopen(fd, "r")) == NULL) {
50 - close(fd);
51 + if ((fp_contents = fdopen(fd_contents, "r")) == NULL) {
52 + close(fd_contents);
53 return EXIT_SUCCESS;
54 }
55
56 + /* Open contents_update, if needed */
57 num_files = num_files_ok = num_files_unknown = num_files_ignored = 0;
58 qcprintf("%sing %s%s/%s%s ...\n",
59 (state->qc_update ? "Updat" : "Check"),
60 GREEN, catname, pkgname, NORM);
61 if (state->qc_update) {
62 - fpx = q_vdb_pkg_fopenat_rw(pkg_ctx, "CONTENTS~");
63 - if (fpx == NULL) {
64 - fclose(fp);
65 + fp_contents_update = q_vdb_pkg_fopenat_rw(pkg_ctx, "CONTENTS~");
66 + if (fp_contents_update == NULL) {
67 + fclose(fp_contents);
68 warnp("unable to fopen(%s/%s, w)", pkgname, "CONTENTS~");
69 return EXIT_FAILURE;
70 }
71 @@ -94,21 +96,23 @@ qcheck_process_contents(q_vdb_pkg_ctx *pkg_ctx, struct qcheck_opt_state *state)
72 }
73
74 buffer = line = NULL;
75 - while (getline(&line, &linelen, fp) != -1) {
76 - contents_entry *e;
77 + while (getline(&line, &linelen, fp_contents) != -1) {
78 + contents_entry *entry;
79 free(buffer);
80 buffer = xstrdup(line);
81 - e = contents_parse_line(line);
82 - if (!e)
83 +
84 + entry = contents_parse_line(line);
85 +
86 + if (!entry)
87 continue;
88
89 - /* run our little checks */
90 + /* run initial checks */
91 ++num_files;
92 if (array_cnt(state->regex_arr)) {
93 size_t n;
94 regex_t *regex;
95 array_for_each(state->regex_arr, n, regex)
96 - if (!regexec(regex, e->name, 0, NULL, 0))
97 + if (!regexec(regex, entry->name, 0, NULL, 0))
98 break;
99 if (n < array_cnt(state->regex_arr)) {
100 --num_files;
101 @@ -116,142 +120,159 @@ qcheck_process_contents(q_vdb_pkg_ctx *pkg_ctx, struct qcheck_opt_state *state)
102 continue;
103 }
104 }
105 - if (fstatat(pkg_ctx->cat_ctx->ctx->portroot_fd, e->name + 1, &st, AT_SYMLINK_NOFOLLOW)) {
106 + if (fstatat(pkg_ctx->cat_ctx->ctx->portroot_fd, entry->name + 1, &st, AT_SYMLINK_NOFOLLOW)) {
107 /* make sure file exists */
108 if (state->chk_afk) {
109 if (errno == ENOENT)
110 - qcprintf(" %sAFK%s: %s\n", RED, NORM, e->name);
111 + qcprintf(" %sAFK%s: %s\n", RED, NORM, entry->name);
112 else
113 - qcprintf(" %sERROR (%s)%s: %s\n", RED, strerror(errno), NORM, e->name);
114 + qcprintf(" %sERROR (%s)%s: %s\n", RED, strerror(errno), NORM, entry->name);
115 } else {
116 --num_files;
117 ++num_files_ignored;
118 if (state->qc_update)
119 - fputs(buffer, fpx);
120 + fputs(buffer, fp_contents_update);
121 }
122 continue;
123 }
124 - if (e->digest && S_ISREG(st.st_mode)) {
125 - if (!state->chk_config_protect) {
126 - /* handle CONFIG_PROTECT-ed files */
127 - int i;
128 - /* if it's in CONFIG_PROTECT_MASK, check it like normal */
129 - for (i = 1; i < cpm_argc; ++i)
130 - if (strncmp(cpm_argv[i], e->name, strlen(cpm_argv[i])) == 0)
131 - break;
132 - if (i == cpm_argc) {
133 - /* not explicitly masked, so if it's protected */
134 - for (i = 1; i < cp_argc; ++i)
135 - if (strncmp(cp_argv[i], e->name, strlen(cp_argv[i])) == 0)
136 - goto cfg_protected;
137 - }
138 +
139 + /* Handle CONFIG_PROTECT-ed files */
140 + if (!state->chk_config_protect) {
141 + int i;
142 + /* If in CONFIG_PROTECT_MASK, handle like normal */
143 + for (i = 1; i < cpm_argc; ++i)
144 + if (strncmp(cpm_argv[i], entry->name, strlen(cpm_argv[i])) == 0)
145 + break;
146 + if (i == cpm_argc) {
147 + /* Not explicitly masked, so it's protected */
148 + for (i = 1; i < cp_argc; ++i)
149 + if (strncmp(cp_argv[i], entry->name, strlen(cp_argv[i])) == 0) {
150 + num_files_ok++;
151 + continue;
152 + }
153 }
154 + }
155 +
156 + /* For certain combinations of flags and filetypes, a file
157 + * won't get checks and should be ignored */
158 + if (!state->chk_mtime && entry->type == CONTENTS_SYM) {
159 + --num_files;
160 + ++num_files_ignored;
161 + if (state->qc_update)
162 + fputs(buffer, fp_contents_update);
163
164 - /* validate digest (handles MD5 / SHA1) */
165 + continue;
166 + }
167 +
168 + /* Digest checks only work on regular files
169 + * Note: We don't check for state->chk_hash when entering
170 + * but rather in digest-check #3, because we only succeed
171 + * tests/qcheck/list04.good if when chk_hash is false, we
172 + * do check hashes, but only print mismatched digests as
173 + * 'ignored file'. */
174 + if (entry->digest && S_ISREG(st.st_mode)) {
175 + /* Validate digest (handles MD5 / SHA1)
176 + * Digest-check 1/3:
177 + * Should we check digests? */
178 + char *f_digest;
179 uint8_t hash_algo;
180 - char *hashed_file;
181 - hash_cb_t hash_cb = state->undo_prelink ? hash_cb_prelink_undo : hash_cb_default;
182 - switch (strlen(e->digest)) {
183 + switch (strlen(entry->digest)) {
184 case 32: hash_algo = HASH_MD5; break;
185 case 40: hash_algo = HASH_SHA1; break;
186 default: hash_algo = 0; break;
187 }
188 +
189 if (!hash_algo) {
190 if (state->chk_hash) {
191 - qcprintf(" %sUNKNOWN DIGEST%s: '%s' for '%s'\n", RED, NORM, e->digest, e->name);
192 + qcprintf(" %sUNKNOWN DIGEST%s: '%s' for '%s'\n", RED, NORM, entry->digest, entry->name);
193 ++num_files_unknown;
194 } else {
195 --num_files;
196 ++num_files_ignored;
197 if (state->qc_update)
198 - fputs(buffer, fpx);
199 + fputs(buffer, fp_contents_update);
200 }
201 continue;
202 }
203 - hashed_file = (char *)hash_file_at_cb(pkg_ctx->cat_ctx->ctx->portroot_fd, e->name + 1, hash_algo, hash_cb);
204 - if (!hashed_file) {
205 +
206 + hash_cb_t hash_cb = state->undo_prelink ? hash_cb_prelink_undo : hash_cb_default;
207 + f_digest = (char *)hash_file_at_cb(pkg_ctx->cat_ctx->ctx->portroot_fd, entry->name + 1, hash_algo, hash_cb);
208 +
209 + /* Digest-check 2/3:
210 + * Can we get a digest of the file? */
211 + if (!f_digest) {
212 ++num_files_unknown;
213 - free(hashed_file);
214 - if (state->qc_update) {
215 - fputs(buffer, fpx);
216 - if (!verbose)
217 - continue;
218 - }
219 - qcprintf(" %sPERM %4o%s: %s\n", RED, (unsigned int)(st.st_mode & 07777), NORM, e->name);
220 + free(f_digest);
221 +
222 + if (state->qc_update)
223 + fputs(buffer, fp_contents_update);
224 +
225 + if (verbose)
226 + qcprintf(" %sPERM %4o%s: %s\n", RED, (unsigned int)(st.st_mode & 07777), NORM, entry->name);
227 +
228 continue;
229 - } else if (strcmp(e->digest, hashed_file)) {
230 + }
231 +
232 + /* Digest-check 3/3:
233 + * Does the digest equal what portage recorded? */
234 + if (strcmp(entry->digest, f_digest) != 0) {
235 if (state->chk_hash) {
236 - const char *digest_disp;
237 if (state->qc_update)
238 - fprintf(fpx, "obj %s %s %"PRIu64"\n", e->name, hashed_file, (uint64_t)st.st_mtime);
239 + fprintf(fp_contents_update, "obj %s %s %"PRIu64"\n", entry->name, f_digest, (uint64_t)st.st_mtime);
240 +
241 + const char *digest_disp;
242 switch (hash_algo) {
243 - case HASH_MD5: digest_disp = "MD5"; break;
244 - case HASH_SHA1: digest_disp = "SHA1"; break;
245 - default: digest_disp = "UNK"; break;
246 + case HASH_MD5: digest_disp = "MD5"; break;
247 + case HASH_SHA1: digest_disp = "SHA1"; break;
248 + default: digest_disp = "UNK"; break;
249 }
250 - qcprintf(" %s%s-DIGEST%s: %s", RED, digest_disp, NORM, e->name);
251 +
252 + qcprintf(" %s%s-DIGEST%s: %s", RED, digest_disp, NORM, entry->name);
253 if (verbose)
254 - qcprintf(" (recorded '%s' != actual '%s')", e->digest, hashed_file);
255 + qcprintf(" (recorded '%s' != actual '%s')", entry->digest, f_digest);
256 qcprintf("\n");
257 } else {
258 --num_files;
259 ++num_files_ignored;
260 if (state->qc_update)
261 - fputs(buffer, fpx);
262 + fputs(buffer, fp_contents_update);
263 }
264 - free(hashed_file);
265 +
266 + free(f_digest);
267 continue;
268 - } else if (e->mtime && e->mtime != st.st_mtime) {
269 - if (state->chk_mtime) {
270 - qcprintf(" %sMTIME%s: %s", RED, NORM, e->name);
271 - if (verbose)
272 - qcprintf(" (recorded '%"PRIu64"' != actual '%"PRIu64"')", (uint64_t)e->mtime, (uint64_t)st.st_mtime);
273 - qcprintf("\n");
274 + }
275
276 - /* This can only be an obj, dir and sym have no digest */
277 - if (state->qc_update)
278 - fprintf(fpx, "obj %s %s %"PRIu64"\n", e->name, e->digest, (uint64_t)st.st_mtime);
279 + free(f_digest);
280 + }
281 +
282 + /* Validate mtimes */
283 + if (state->chk_mtime && entry->mtime && entry->mtime != st.st_mtime) {
284 + qcprintf(" %sMTIME%s: %s", RED, NORM, entry->name);
285 + if (verbose)
286 + qcprintf(" (recorded '%"PRIu64"' != actual '%"PRIu64"')", (uint64_t)entry->mtime, (uint64_t)st.st_mtime);
287 + qcprintf("\n");
288 +
289 + /* Update mtime */
290 + if (state->qc_update) {
291 + if (entry->type == CONTENTS_SYM) {
292 + fprintf(fp_contents_update, "sym %s -> %s %"PRIu64"\n", entry->name, entry->sym_target, (uint64_t)st.st_mtime);
293 } else {
294 - --num_files;
295 - ++num_files_ignored;
296 - if (state->qc_update)
297 - fputs(buffer, fpx);
298 + fprintf(fp_contents_update, "obj %s %s %"PRIu64"\n", entry->name, entry->digest, (uint64_t)st.st_mtime);
299 }
300 - free(hashed_file);
301 - continue;
302 - } else {
303 - if (state->qc_update)
304 - fputs(buffer, fpx);
305 - free(hashed_file);
306 }
307 - } else if (e->mtime && e->mtime != st.st_mtime) {
308 - if (state->chk_mtime) {
309 - qcprintf(" %sMTIME%s: %s", RED, NORM, e->name);
310 - if (verbose)
311 - qcprintf(" (recorded '%"PRIu64"' != actual '%"PRIu64"')",
312 - (uint64_t)e->mtime, (uint64_t)st.st_mtime);
313 - qcprintf("\n");
314
315 - /* This can only be a sym */
316 - if (state->qc_update)
317 - fprintf(fpx, "sym %s -> %s %"PRIu64"\n", e->name, e->sym_target, (uint64_t)st.st_mtime);
318 - } else {
319 - --num_files;
320 - ++num_files_ignored;
321 - if (state->qc_update)
322 - fputs(buffer, fpx);
323 - }
324 continue;
325 - } else {
326 - if (state->qc_update)
327 - fputs(buffer, fpx);
328 }
329 - cfg_protected:
330 - ++num_files_ok;
331 +
332 + /* Success! */
333 + if (state->qc_update)
334 + fputs(buffer, fp_contents_update);
335 +
336 + num_files_ok++;
337 }
338 free(line);
339 free(buffer);
340 - fclose(fp);
341 + fclose(fp_contents);
342
343 if (!state->chk_config_protect) {
344 freeargv(cp_argc, cp_argv);
345 @@ -259,13 +280,13 @@ qcheck_process_contents(q_vdb_pkg_ctx *pkg_ctx, struct qcheck_opt_state *state)
346 }
347
348 if (state->qc_update) {
349 - if (fchown(fd, cst.st_uid, cst.st_gid)) {
350 + if (fchown(fd_contents, cst.st_uid, cst.st_gid)) {
351 /* meh */;
352 }
353 - if (fchmod(fd, cst.st_mode)) {
354 + if (fchmod(fd_contents, cst.st_mode)) {
355 /* meh */;
356 }
357 - fclose(fpx);
358 + fclose(fp_contents_update);
359 if (renameat(pkg_ctx->fd, "CONTENTS~", pkg_ctx->fd, "CONTENTS"))
360 unlinkat(pkg_ctx->fd, "CONTENTS~", 0);
361 if (!verbose)