Branch data Line data Source code
1 : : /* Copyright (c) 2014, Vsevolod Stakhov
2 : : * All rights reserved.
3 : : *
4 : : * Redistribution and use in source and binary forms, with or without
5 : : * modification, are permitted provided that the following conditions are met:
6 : : * * Redistributions of source code must retain the above copyright
7 : : * notice, this list of conditions and the following disclaimer.
8 : : * * Redistributions in binary form must reproduce the above copyright
9 : : * notice, this list of conditions and the following disclaimer in the
10 : : * documentation and/or other materials provided with the distribution.
11 : : *
12 : : * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
13 : : * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14 : : * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15 : : * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
16 : : * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17 : : * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
18 : : * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
19 : : * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20 : : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21 : : * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22 : : */
23 : :
24 : : #ifdef HAVE_CONFIG_H
25 : : #include "pkg_config.h"
26 : : #endif
27 : :
28 : : #include <sys/param.h>
29 : : #include <sys/types.h>
30 : :
31 : : #include <assert.h>
32 : : #include <errno.h>
33 : : #ifdef HAVE_LIBUTIL_H
34 : : #include <libutil.h>
35 : : #endif
36 : : #include <stdbool.h>
37 : : #include <stdlib.h>
38 : : #include <string.h>
39 : : #include <ctype.h>
40 : :
41 : : #include "pkg.h"
42 : : #include "private/event.h"
43 : : #include "private/pkg.h"
44 : : #include "private/pkgdb.h"
45 : : #include "private/pkg_jobs.h"
46 : : #include "kvec.h"
47 : :
48 : : #define IS_DELETE(j) ((j)->type == PKG_JOBS_DEINSTALL || (j)->type == PKG_JOBS_AUTOREMOVE)
49 : :
50 : : typedef kvec_t(struct pkg *) pkg_chain_t;
51 : :
52 : : struct pkg *
53 : 2189 : pkg_jobs_universe_get_local(struct pkg_jobs_universe *universe,
54 : : const char *uid, unsigned flag)
55 : : {
56 : 2189 : struct pkg *pkg = NULL;
57 : : struct pkgdb_it *it;
58 : : struct pkg_job_universe_item *unit, *cur, *found;
59 : :
60 [ + + ]: 2189 : if (flag == 0) {
61 [ + - - + ]: 2185 : if (!IS_DELETE(universe->j))
62 : 2185 : flag = PKG_LOAD_BASIC|PKG_LOAD_DEPS|PKG_LOAD_RDEPS|PKG_LOAD_OPTIONS|
63 : : PKG_LOAD_REQUIRES|PKG_LOAD_PROVIDES|
64 : : PKG_LOAD_SHLIBS_REQUIRED|PKG_LOAD_SHLIBS_PROVIDED|PKG_LOAD_ANNOTATIONS|
65 : : PKG_LOAD_CONFLICTS;
66 : : else
67 : 0 : flag = PKG_LOAD_BASIC|PKG_LOAD_RDEPS|PKG_LOAD_DEPS|PKG_LOAD_ANNOTATIONS;
68 : 2185 : }
69 : :
70 : 2189 : unit = pkghash_get_value(universe->items, uid);
71 [ + + ]: 2189 : if (unit != NULL) {
72 : : /* Search local in a universe chain */
73 : 781 : cur = unit;
74 : 781 : found = NULL;
75 : 781 : do {
76 [ + + ]: 821 : if (cur->pkg->type == PKG_INSTALLED) {
77 : 347 : found = cur;
78 : 347 : break;
79 : : }
80 : 474 : cur = cur->prev;
81 [ + + ]: 474 : } while (cur != unit);
82 : :
83 [ + + ]: 781 : if (found) {
84 : 347 : pkgdb_ensure_loaded(universe->j->db, unit->pkg, flag);
85 : 347 : return (unit->pkg);
86 : : }
87 : 434 : }
88 : :
89 [ + - ]: 1842 : if ((it = pkgdb_query(universe->j->db, uid, MATCH_EXACT)) == NULL)
90 : 0 : return (NULL);
91 : :
92 [ + + ]: 1842 : if (pkgdb_it_next(it, &pkg, flag) != EPKG_OK)
93 : 1524 : pkg = NULL;
94 : :
95 : 1842 : pkgdb_it_free(it);
96 : :
97 : 1842 : return (pkg);
98 : 2189 : }
99 : :
100 : : static pkg_chain_t *
101 : 152 : pkg_jobs_universe_get_remote(struct pkg_jobs_universe *universe,
102 : : const char *uid, unsigned flag)
103 : : {
104 : 152 : struct pkg *pkg = NULL;
105 : 152 : pkg_chain_t *result = NULL;
106 : : struct pkgdb_it *it;
107 : : struct pkg_job_universe_item *unit, *cur, *found;
108 : :
109 [ - + ]: 152 : if (flag == 0) {
110 : 152 : flag = PKG_LOAD_BASIC|PKG_LOAD_DEPS|PKG_LOAD_OPTIONS|
111 : : PKG_LOAD_PROVIDES|PKG_LOAD_REQUIRES|
112 : : PKG_LOAD_SHLIBS_REQUIRED|PKG_LOAD_SHLIBS_PROVIDED|
113 : : PKG_LOAD_ANNOTATIONS|PKG_LOAD_CONFLICTS;
114 : 152 : }
115 : :
116 : 152 : unit = pkghash_get_value(universe->items, uid);
117 [ - + # # ]: 152 : if (unit != NULL && unit->pkg->type != PKG_INSTALLED) {
118 : : /* Search local in a universe chain */
119 : 0 : cur = unit;
120 : 0 : found = NULL;
121 : 0 : do {
122 [ # # ]: 0 : if (cur->pkg->type != PKG_INSTALLED) {
123 : 0 : found = cur;
124 : 0 : break;
125 : : }
126 : 0 : cur = cur->prev;
127 [ # # ]: 0 : } while (cur != unit);
128 : :
129 [ # # ]: 0 : if (found) {
130 : : /* Assume processed */
131 : 0 : return (NULL);
132 : : }
133 : 0 : }
134 : :
135 [ + - + - : 456 : if ((it = pkgdb_repo_query(universe->j->db, uid, MATCH_EXACT,
+ - ]
136 : 304 : universe->j->reponame)) == NULL)
137 : 0 : return (NULL);
138 : :
139 [ + + ]: 356 : while (pkgdb_it_next(it, &pkg, flag) == EPKG_OK) {
140 [ + + ]: 204 : if (result == NULL)
141 : 136 : result = xcalloc(1, sizeof(pkg_chain_t));
142 [ + + - + ]: 204 : kv_prepend(typeof(pkg), *result, pkg);
143 : 204 : pkg = NULL;
144 : : }
145 : :
146 : 152 : pkgdb_it_free(it);
147 : :
148 : 152 : return (result);
149 : 152 : }
150 : :
151 : : /**
152 : : * Check whether a package is in the universe already or add it
153 : : * @return item or NULL
154 : : */
155 : : int
156 : 1708 : pkg_jobs_universe_add_pkg(struct pkg_jobs_universe *universe, struct pkg *pkg,
157 : : bool force __unused, struct pkg_job_universe_item **found)
158 : : {
159 : 1708 : struct pkg_job_universe_item *item, *seen, *tmp = NULL;
160 : :
161 : 1708 : pkg_validate(pkg, universe->j->db);
162 : :
163 [ + + ]: 1708 : if (pkg->digest == NULL) {
164 : 4 : pkg_debug(3, "no digest found for package %s (%s-%s)",
165 : 4 : pkg->uid, pkg->name, pkg->version);
166 [ - + ]: 4 : if (pkg_checksum_calculate(pkg, universe->j->db, false, true, false) != EPKG_OK) {
167 : 0 : *found = NULL;
168 : 0 : return (EPKG_FATAL);
169 : : }
170 : 4 : }
171 : :
172 : 1708 : seen = pkghash_get_value(universe->seen, pkg->digest);
173 [ + + ]: 1708 : if (seen) {
174 : 660 : bool same_package = false;
175 : :
176 [ + + ]: 776 : DL_FOREACH(seen, tmp) {
177 [ + + + + : 714 : if (tmp->pkg == pkg || (tmp->pkg->type == pkg->type &&
+ + ]
178 : 61 : strcmp(tmp->pkg->digest, pkg->digest) == 0)) {
179 [ + + ]: 622 : if (tmp->pkg->reponame != NULL) {
180 [ + + ]: 369 : if (strcmp(tmp->pkg->reponame, pkg->reponame) == 0) {
181 : 345 : same_package = true;
182 : 345 : break;
183 : : }
184 : 24 : } else {
185 : 253 : same_package = true;
186 : 253 : break;
187 : : }
188 : 24 : }
189 : 116 : }
190 : :
191 [ + + ]: 660 : if (same_package) {
192 [ + + ]: 598 : if (found != NULL) {
193 : 593 : *found = seen;
194 : 593 : }
195 : :
196 : 598 : return (EPKG_END);
197 : : }
198 : 62 : }
199 : :
200 [ - + ]: 1110 : if (pkg_is_locked(pkg)) {
201 : 0 : return (EPKG_LOCKED);
202 : : }
203 : :
204 : 1110 : pkg_debug(2, "universe: add new %s pkg: %s, (%s-%s:%s)",
205 : 1110 : (pkg->type == PKG_INSTALLED ? "local" : "remote"), pkg->uid,
206 : 1110 : pkg->name, pkg->version, pkg->digest);
207 : :
208 : 1110 : item = xcalloc(1, sizeof (struct pkg_job_universe_item));
209 : 1110 : item->pkg = pkg;
210 : :
211 : 1110 : tmp = pkghash_get_value(universe->items, pkg->uid);
212 [ + + ]: 1110 : if (tmp == NULL) {
213 [ + + - + ]: 1089 : pkghash_safe_add(universe->items, pkg->uid, item, NULL);
214 : 845 : item->inhash = true;
215 : 845 : }
216 : :
217 [ + + ]: 1110 : DL_APPEND(tmp, item);
218 : :
219 [ + + ]: 1110 : if (seen == NULL)
220 [ + + - + ]: 1495 : pkghash_safe_add(universe->seen, item->pkg->digest, item, NULL);
221 : :
222 : 1110 : universe->nitems++;
223 : :
224 [ + + ]: 1110 : if (found != NULL)
225 : 541 : *found = item;
226 : :
227 : 1110 : return (EPKG_OK);
228 : 1708 : }
229 : :
230 : : #define DEPS_FLAG_REVERSE 0x1 << 1
231 : : #define DEPS_FLAG_MIRROR 0x1 << 2
232 : : #define DEPS_FLAG_FORCE_LOCAL 0x1 << 3
233 : : #define DEPS_FLAG_FORCE_MISSING 0x1 << 4
234 : : #define DEPS_FLAG_FORCE_UPGRADE 0x1 << 5
235 : :
236 : : static int
237 : 1541 : pkg_jobs_universe_process_deps(struct pkg_jobs_universe *universe,
238 : : struct pkg *pkg, unsigned flags)
239 : : {
240 : 1541 : struct pkg_dep *d = NULL;
241 : : int (*deps_func)(const struct pkg *pkg, struct pkg_dep **d);
242 : : int rc;
243 : : struct pkg_job_universe_item *unit;
244 : : struct pkg *npkg, *rpkg, *lpkg;
245 : 1541 : pkg_chain_t *rpkgs = NULL;
246 : 1541 : bool found = false;
247 : :
248 : 1541 : rpkg = NULL;
249 : :
250 [ + + ]: 1541 : if (flags & DEPS_FLAG_REVERSE) {
251 : 860 : pkg_debug(4, "Processing rdeps for %s (%s)", pkg->uid, pkg->type == PKG_INSTALLED ? "installed" : "remote");
252 [ + + ]: 860 : if (pkg->type != PKG_INSTALLED) {
253 : 593 : lpkg = pkg_jobs_universe_get_local(universe, pkg->uid, 0);
254 [ + + - + ]: 593 : if (lpkg != NULL && lpkg != pkg)
255 : 187 : return (pkg_jobs_universe_process_deps(universe, lpkg, flags));
256 : 406 : }
257 : 673 : deps_func = pkg_rdeps;
258 : 673 : }
259 : : else {
260 : 681 : pkg_debug(4, "Processing deps for %s", pkg->uid);
261 : 681 : deps_func = pkg_deps;
262 : : }
263 : :
264 [ + + ]: 1710 : while (deps_func(pkg, &d) == EPKG_OK) {
265 : 364 : pkg_debug(4, "Processing *deps for %s: %s", pkg->uid, d->uid);
266 [ + + ]: 364 : if (pkghash_get(universe->items, d->uid) != NULL)
267 : 212 : continue;
268 : :
269 : 152 : rpkgs = NULL;
270 : 152 : npkg = NULL;
271 [ + + ]: 152 : if (!(flags & DEPS_FLAG_MIRROR)) {
272 : 148 : npkg = pkg_jobs_universe_get_local(universe, d->uid, 0);
273 : 148 : }
274 : :
275 [ - + ]: 152 : if (!(flags & DEPS_FLAG_FORCE_LOCAL)) {
276 : :
277 : : /* Check for remote dependencies */
278 : 152 : rpkgs = pkg_jobs_universe_get_remote(universe, d->uid, 0);
279 : 152 : }
280 : :
281 [ + + + + ]: 152 : if (npkg == NULL && rpkgs == NULL) {
282 : 8 : pkg_emit_error("%s has a missing dependency: %s",
283 : 8 : pkg->name, d->name);
284 : :
285 [ - + ]: 8 : if (flags & DEPS_FLAG_FORCE_MISSING) {
286 : 0 : continue;
287 : : }
288 : :
289 : 8 : return (EPKG_FATAL);
290 : : }
291 : :
292 [ + + ]: 144 : if (npkg != NULL) {
293 [ + - ]: 40 : if (pkg_jobs_universe_process_item(universe, npkg, &unit) != EPKG_OK) {
294 : 0 : continue;
295 : : }
296 : 40 : }
297 : :
298 [ + + ]: 144 : if (rpkgs == NULL)
299 : 8 : continue;
300 : : /*
301 : : * When processing deps, we should first try to select a dependency
302 : : * from the same repo.
303 : : * Otherwise, we would have ping-pong of dependencies instead of
304 : : * the situation when this behaviour is handled by
305 : : * CONSERVATIVE_UPGRADES.
306 : : *
307 : : * Important notes here:
308 : : * 1. We are looking for packages that are dependencies of a package
309 : : * `pkg`
310 : : * 2. Now if `pkg` belongs to repo `r` and `rpkg` belongs to repo
311 : : * `r` then we just select it.
312 : : * 3. If `rpkg` is not found in `r` we just scan all packages
313 : : */
314 : :
315 : : /*
316 : : * XXX: this is the proper place to expand flexible dependencies
317 : : */
318 : :
319 : 136 : found = false;
320 : : /* Iteration one */
321 [ + + ]: 180 : for (int i = 0; i < kv_size(*rpkgs); i++) {
322 : 160 : rpkg = kv_A(*rpkgs, i);
323 : :
324 [ + + + - : 160 : if (pkg->reponame && rpkg->reponame &&
+ + ]
325 : 128 : strcmp (pkg->reponame, rpkg->reponame) == 0) {
326 : 116 : found = true;
327 : 116 : break;
328 : : }
329 : 44 : }
330 : :
331 : : /* Fallback if a dependency is not found in the same repo */
332 [ + + ]: 136 : if (!found) {
333 [ + + ]: 52 : for (int i = 0; i < kv_size(*rpkgs); i++) {
334 : 32 : rpkg = kv_A(*rpkgs, i);
335 : :
336 [ - + ]: 32 : if (npkg != NULL) {
337 : : /* Set reason for upgrades */
338 [ + + ]: 32 : if (!pkg_jobs_need_upgrade(rpkg, npkg))
339 : 24 : continue;
340 : : /* Save automatic flag */
341 : 8 : rpkg->automatic = npkg->automatic;
342 : 8 : }
343 : :
344 : 8 : rc = pkg_jobs_universe_process_item(universe, rpkg, NULL);
345 : :
346 : : /* Special case if we cannot find any package */
347 [ - + # # ]: 8 : if (npkg == NULL && rc != EPKG_OK) {
348 : 0 : kv_destroy(*rpkgs);
349 : 0 : free(rpkgs);
350 : 0 : return (rc);
351 : : }
352 : 8 : }
353 : 20 : }
354 : : else {
355 [ + - ]: 116 : assert (rpkg != NULL);
356 : :
357 [ + + ]: 116 : if (npkg != NULL) {
358 : : /* Set reason for upgrades */
359 [ + + ]: 12 : if (!pkg_jobs_need_upgrade(rpkg, npkg))
360 : 8 : continue;
361 : : /* Save automatic flag */
362 : 4 : rpkg->automatic = npkg->automatic;
363 : 4 : }
364 : :
365 : 108 : rc = pkg_jobs_universe_process_item(universe, rpkg, NULL);
366 [ + + + - ]: 108 : if (npkg == NULL && rc != EPKG_OK) {
367 : 0 : kv_destroy(*rpkgs);
368 : 0 : free(rpkgs);
369 : 0 : return (rc);
370 : : }
371 : : }
372 : :
373 : 128 : kv_destroy(*rpkgs);
374 : 128 : free(rpkgs);
375 : : }
376 : :
377 : 1346 : return (EPKG_OK);
378 : 1541 : }
379 : :
380 : : static int
381 : 48 : pkg_jobs_universe_handle_provide(struct pkg_jobs_universe *universe,
382 : : struct pkgdb_it *it, const char *name, bool is_shlib, struct pkg *parent __unused)
383 : : {
384 : : struct pkg_job_universe_item *unit;
385 : : struct pkg_job_provide *pr, *prhead;
386 : : struct pkg *npkg, *rpkg;
387 : : int rc;
388 : 48 : unsigned flags = PKG_LOAD_BASIC|PKG_LOAD_OPTIONS|PKG_LOAD_DEPS|
389 : : PKG_LOAD_REQUIRES|PKG_LOAD_PROVIDES|
390 : : PKG_LOAD_SHLIBS_REQUIRED|PKG_LOAD_SHLIBS_PROVIDED|
391 : : PKG_LOAD_ANNOTATIONS|PKG_LOAD_CONFLICTS;
392 : :
393 : 48 : rpkg = NULL;
394 : :
395 : 48 : prhead = pkghash_get_value(universe->provides, name);
396 [ + + ]: 72 : while (pkgdb_it_next(it, &rpkg, flags) == EPKG_OK) {
397 : : /* Check for local packages */
398 [ + + ]: 24 : if ((unit = pkghash_get_value(universe->items, rpkg->uid)) != NULL) {
399 : : /* Remote provide is newer, so we can add it */
400 [ - + - + ]: 32 : if (pkg_jobs_universe_process_item(universe, rpkg,
401 : 16 : &unit) != EPKG_OK) {
402 : 0 : continue;
403 : : }
404 : :
405 : 16 : rpkg = NULL;
406 : 16 : }
407 : : else {
408 : : /* Maybe local package has just been not added */
409 : 8 : npkg = pkg_jobs_universe_get_local(universe, rpkg->uid, 0);
410 [ + - ]: 8 : if (npkg != NULL) {
411 [ # # # # ]: 0 : if (pkg_jobs_universe_process_item(universe, npkg,
412 : 0 : &unit) != EPKG_OK) {
413 : 0 : return (EPKG_FATAL);
414 : : }
415 [ # # # # ]: 0 : if (pkg_jobs_universe_process_item(universe, rpkg,
416 : 0 : &unit) != EPKG_OK) {
417 : 0 : continue;
418 : : }
419 [ # # ]: 0 : if (unit != NULL)
420 : 0 : rpkg = NULL;
421 : 0 : }
422 : : }
423 : :
424 : : /* Skip seen packages */
425 [ + + ]: 24 : if (unit == NULL) {
426 [ + - ]: 8 : if (rpkg->digest == NULL) {
427 : 0 : pkg_debug(3, "no digest found for package %s", rpkg->uid);
428 [ # # # # : 0 : if (pkg_checksum_calculate(rpkg,
# # ]
429 : 0 : universe->j->db, false, true, false) != EPKG_OK) {
430 : 0 : return (EPKG_FATAL);
431 : : }
432 : 0 : }
433 : 8 : rc = pkg_jobs_universe_process_item(universe, rpkg,
434 : : &unit);
435 : :
436 [ + - ]: 8 : if (rc != EPKG_OK) {
437 : 0 : return (rc);
438 : : }
439 : :
440 : : /* Reset package to avoid freeing */
441 : 8 : rpkg = NULL;
442 : 8 : }
443 : :
444 : 24 : pr = xcalloc (1, sizeof (*pr));
445 : 24 : pr->un = unit;
446 : 24 : pr->provide = name;
447 : 24 : pr->is_shlib = is_shlib;
448 : :
449 [ - + ]: 24 : if (prhead == NULL) {
450 [ - + ]: 24 : DL_APPEND(prhead, pr);
451 [ + + - + ]: 28 : pkghash_safe_add(universe->provides, pr->provide,
452 : : prhead, NULL);
453 : 24 : pkg_debug (4, "universe: add new provide %s-%s(%s) for require %s",
454 : 24 : pr->un->pkg->name, pr->un->pkg->version,
455 : 24 : pr->un->pkg->type == PKG_INSTALLED ? "l" : "r",
456 : 24 : pr->provide);
457 : 24 : } else {
458 [ # # ]: 0 : DL_APPEND(prhead, pr);
459 : 0 : pkg_debug (4, "universe: append provide %s-%s(%s) for require %s",
460 : 0 : pr->un->pkg->name, pr->un->pkg->version,
461 : 0 : pr->un->pkg->type == PKG_INSTALLED ? "l" : "r",
462 : 0 : pr->provide);
463 : : }
464 : : }
465 : :
466 : 48 : return (EPKG_OK);
467 : 48 : }
468 : :
469 : : static int
470 : 673 : pkg_jobs_universe_process_shlibs(struct pkg_jobs_universe *universe,
471 : : struct pkg *pkg)
472 : : {
473 : : struct pkgdb_it *it;
474 : : int rc;
475 : : pkghash_it hit;
476 : :
477 : 673 : hit = pkghash_iterator(pkg->shlibs_required);
478 [ + + ]: 681 : while (pkghash_next(&hit)) {
479 [ + + ]: 8 : if (pkghash_get(universe->provides, hit.key) != NULL)
480 : 4 : continue;
481 : :
482 : : /* Check for local provides */
483 : 4 : it = pkgdb_query_shlib_provide(universe->j->db, hit.key);
484 [ - + ]: 4 : if (it != NULL) {
485 : 8 : rc = pkg_jobs_universe_handle_provide(universe, it,
486 : 4 : hit.key, true, pkg);
487 : 4 : pkgdb_it_free(it);
488 : :
489 [ + - ]: 4 : if (rc != EPKG_OK) {
490 : 0 : pkg_debug(1, "cannot find local packages that provide library %s "
491 : : "required for %s",
492 : 0 : hit.key, pkg->name);
493 : 0 : }
494 : 4 : }
495 : : /* Not found, search in the repos */
496 : 8 : it = pkgdb_repo_shlib_provide(universe->j->db,
497 : 4 : hit.key, universe->j->reponame);
498 : :
499 [ - + ]: 4 : if (it != NULL) {
500 : 4 : rc = pkg_jobs_universe_handle_provide(universe, it, hit.key, true, pkg);
501 : 4 : pkgdb_it_free(it);
502 : :
503 [ + - ]: 4 : if (rc != EPKG_OK) {
504 : 0 : pkg_debug(1, "cannot find remote packages that provide library %s "
505 : : "required for %s",
506 : 0 : hit.key, pkg->name);
507 : 0 : }
508 : 4 : }
509 : : }
510 : :
511 : 673 : return (EPKG_OK);
512 : : }
513 : :
514 : : static int
515 : 673 : pkg_jobs_universe_process_provides_requires(struct pkg_jobs_universe *universe,
516 : : struct pkg *pkg)
517 : : {
518 : : struct pkgdb_it *it;
519 : : int rc;
520 : : pkghash_it hit;
521 : :
522 : :
523 : 673 : hit = pkghash_iterator(pkg->requires);
524 [ + + ]: 713 : while(pkghash_next(&hit)) {
525 [ + + ]: 40 : if (pkghash_get(universe->provides, hit.key) != NULL)
526 : 20 : continue;
527 : :
528 : : /* Check for local provides */
529 : 20 : it = pkgdb_query_provide(universe->j->db, hit.key);
530 [ + - ]: 20 : if (it != NULL) {
531 : 20 : rc = pkg_jobs_universe_handle_provide(universe, it, hit.key, false, pkg);
532 : 20 : pkgdb_it_free(it);
533 : :
534 [ + - ]: 20 : if (rc != EPKG_OK) {
535 : 0 : pkg_debug(1, "cannot find local packages that provide %s "
536 : : "required for %s",
537 : 0 : hit.key, pkg->name);
538 : 0 : }
539 : 20 : }
540 : :
541 : : /* Not found, search in the repos */
542 : 40 : it = pkgdb_repo_provide(universe->j->db,
543 : 20 : hit.key, universe->j->reponame);
544 : :
545 [ - + ]: 20 : if (it != NULL) {
546 : 20 : rc = pkg_jobs_universe_handle_provide(universe, it, hit.key, false, pkg);
547 : 20 : pkgdb_it_free(it);
548 : :
549 [ + - ]: 20 : if (rc != EPKG_OK) {
550 : 0 : pkg_debug(1, "cannot find remote packages that provide %s "
551 : : "required for %s",
552 : 0 : hit.key, pkg->name);
553 : 0 : return (rc);
554 : : }
555 : 20 : }
556 : : }
557 : :
558 : 673 : return (EPKG_OK);
559 : 673 : }
560 : :
561 : : int
562 : 773 : pkg_jobs_universe_process_item(struct pkg_jobs_universe *universe, struct pkg *pkg,
563 : : struct pkg_job_universe_item **result)
564 : : {
565 : 773 : unsigned flags = 0, job_flags;
566 : 773 : int rc = EPKG_OK;
567 : 773 : pkg_jobs_t type = universe->j->type;
568 : : struct pkg_job_universe_item *found;
569 : :
570 : 773 : pkg_debug(4, "Processing item %s\n", pkg->uid);
571 : :
572 : 773 : job_flags = universe->j->flags;
573 : :
574 : : /*
575 : : * Add pkg itself. If package is already seen then we check the `processed`
576 : : * flag that means that we have already tried to check our universe
577 : : */
578 : 773 : rc = pkg_jobs_universe_add_pkg(universe, pkg, false, &found);
579 [ - + ]: 773 : if (rc == EPKG_CONFLICT)
580 : 0 : return (rc);
581 : :
582 [ + + ]: 773 : if (result)
583 : 112 : *result = found;
584 : :
585 [ + + ]: 773 : if (rc == EPKG_END) {
586 [ + + ]: 593 : if (found->processed)
587 : 92 : return (EPKG_OK);
588 : 501 : }
589 [ - + ]: 180 : else if (rc != EPKG_OK) {
590 : 0 : return (rc);
591 : : }
592 : :
593 : 681 : found->processed = true;
594 : :
595 : : /* Convert jobs flags to dependency logical flags */
596 [ + - ]: 681 : if (job_flags & PKG_FLAG_FORCE_MISSING)
597 : 0 : flags |= DEPS_FLAG_FORCE_MISSING;
598 : :
599 [ + - + - : 681 : switch(type) {
- ]
600 : : case PKG_JOBS_FETCH:
601 [ - + ]: 4 : if (job_flags & PKG_FLAG_RECURSIVE) {
602 : 4 : flags |= DEPS_FLAG_MIRROR;
603 : : /* For fetch jobs we worry about depends only */
604 : 4 : rc = pkg_jobs_universe_process_deps(universe, pkg, flags);
605 : 4 : }
606 : 4 : break;
607 : : case PKG_JOBS_INSTALL:
608 : : case PKG_JOBS_UPGRADE:
609 : : /* Handle depends */
610 : 677 : rc = pkg_jobs_universe_process_deps(universe, pkg, flags);
611 [ + + ]: 677 : if (rc != EPKG_OK)
612 : 4 : return (rc);
613 : : /* Handle reverse depends */
614 : 1346 : rc = pkg_jobs_universe_process_deps(universe, pkg,
615 : 673 : flags|DEPS_FLAG_REVERSE);
616 [ - + ]: 673 : if (rc != EPKG_OK)
617 : 0 : return (rc);
618 : : /* Provides/requires */
619 : 673 : rc = pkg_jobs_universe_process_shlibs(universe, pkg);
620 [ - + ]: 673 : if (rc != EPKG_OK)
621 : 0 : return (rc);
622 : 673 : rc = pkg_jobs_universe_process_provides_requires(universe, pkg);
623 [ + - ]: 673 : if (rc != EPKG_OK)
624 : 0 : return (rc);
625 : 673 : break;
626 : : case PKG_JOBS_AUTOREMOVE:
627 : : /* XXX */
628 : 0 : break;
629 : : case PKG_JOBS_DEINSTALL:
630 : : /* For delete jobs we worry only about local reverse deps */
631 : 0 : flags |= DEPS_FLAG_REVERSE|DEPS_FLAG_FORCE_LOCAL;
632 [ # # ]: 0 : if (job_flags & PKG_FLAG_RECURSIVE)
633 : 0 : rc = pkg_jobs_universe_process_deps(universe, pkg, flags);
634 : 0 : break;
635 : : }
636 : :
637 : 677 : return (rc);
638 : 773 : }
639 : :
640 : : int
641 : 545 : pkg_jobs_universe_process(struct pkg_jobs_universe *universe,
642 : : struct pkg *pkg)
643 : : {
644 : 545 : return (pkg_jobs_universe_process_item(universe, pkg, NULL));
645 : : }
646 : :
647 : : #define RECURSION_LIMIT 1024
648 : :
649 : : static void
650 : 894 : pkg_jobs_update_universe_item_priority(struct pkg_jobs_universe *universe,
651 : : struct pkg_job_universe_item *item, int priority,
652 : : enum pkg_priority_update_type type)
653 : : {
654 : 894 : struct pkg_dep *d = NULL;
655 : 894 : struct pkg_conflict *c = NULL;
656 : : struct pkg_job_universe_item *found, *cur, *it;
657 : : const char *is_local;
658 : : int maxpri;
659 : :
660 : : int (*deps_func)(const struct pkg *pkg, struct pkg_dep **d);
661 : : int (*rdeps_func)(const struct pkg *pkg, struct pkg_dep **d);
662 : :
663 [ - + ]: 894 : if (priority > RECURSION_LIMIT) {
664 : 0 : pkg_debug(1, "recursion limit has been reached, something is bad"
665 : : " with dependencies/conflicts graph");
666 : 0 : return;
667 : : }
668 [ + - ]: 894 : else if (priority + 10 > RECURSION_LIMIT) {
669 : 0 : pkg_debug(2, "approaching recursion limit at %d, while processing of"
670 : 0 : " package %s", priority, item->pkg->uid);
671 : 0 : }
672 : :
673 [ + + ]: 1897 : LL_FOREACH(item, it) {
674 [ + + + + ]: 1742 : if ((item->next != NULL || item->prev != NULL) &&
675 [ + + ]: 1023 : it->pkg->type != PKG_INSTALLED &&
676 [ + + ]: 763 : (type == PKG_PRIORITY_UPDATE_CONFLICT ||
677 : 719 : type == PKG_PRIORITY_UPDATE_DELETE)) {
678 : : /*
679 : : * We do not update priority of a remote part of conflict, as we know
680 : : * that remote packages should not contain conflicts (they should be
681 : : * resolved in request prior to calling of this function)
682 : : */
683 : 72 : pkg_debug(4, "skip update priority for %s-%s",
684 : 72 : it->pkg->uid, it->pkg->digest);
685 : 72 : continue;
686 : : }
687 [ - + ]: 951 : if (it->priority > priority)
688 : 0 : continue;
689 : :
690 : 951 : is_local = it->pkg->type == PKG_INSTALLED ? "local" : "remote";
691 : 951 : pkg_debug(2, "universe: update %s priority of %s(%s): %d -> %d, reason: %d",
692 : 951 : is_local, it->pkg->uid, it->pkg->version, it->priority, priority, type);
693 : 951 : it->priority = priority;
694 : :
695 [ + + ]: 951 : if (type == PKG_PRIORITY_UPDATE_DELETE) {
696 : : /*
697 : : * For delete requests we inverse deps and rdeps logic
698 : : */
699 : 176 : deps_func = pkg_rdeps;
700 : 176 : rdeps_func = pkg_deps;
701 : 176 : }
702 : : else {
703 : 775 : deps_func = pkg_deps;
704 : 775 : rdeps_func = pkg_rdeps;
705 : : }
706 : :
707 [ + + ]: 1163 : while (deps_func(it->pkg, &d) == EPKG_OK) {
708 : 212 : found = pkghash_get_value(universe->items, d->uid);
709 [ + - ]: 212 : if (found == NULL)
710 : 0 : continue;
711 [ + + ]: 452 : LL_FOREACH(found, cur) {
712 [ + + ]: 240 : if (cur->priority < priority + 1)
713 : 352 : pkg_jobs_update_universe_item_priority(universe, cur,
714 : 176 : priority + 1, type);
715 : 240 : }
716 : : }
717 : :
718 : 951 : d = NULL;
719 : 951 : maxpri = priority;
720 [ + + ]: 1102 : while (rdeps_func(it->pkg, &d) == EPKG_OK) {
721 : 151 : found = pkghash_get_value(universe->items, d->uid);
722 [ + + ]: 151 : if (found == NULL)
723 : 43 : continue;
724 [ + + ]: 284 : LL_FOREACH(found, cur) {
725 [ + + ]: 176 : if (cur->priority >= maxpri) {
726 : 20 : maxpri = cur->priority + 1;
727 : 20 : }
728 : 176 : }
729 : : }
730 [ + + ]: 951 : if (maxpri != priority) {
731 : 40 : pkg_jobs_update_universe_item_priority(universe, it,
732 : 20 : maxpri, type);
733 : 20 : return;
734 : : }
735 [ + + ]: 931 : if (it->pkg->type == PKG_INSTALLED)
736 : 240 : continue;
737 : :
738 [ + + ]: 767 : while (pkg_conflicts(it->pkg, &c) == EPKG_OK) {
739 : 76 : found = pkghash_get_value(universe->items, c->uid);
740 [ + + ]: 200 : LL_FOREACH(found, cur) {
741 [ + + ]: 124 : if (cur->pkg->type != PKG_INSTALLED)
742 : 48 : continue;
743 : : /*
744 : : * Move delete requests to be done before installing
745 : : */
746 [ + + ]: 76 : if (cur->priority <= it->priority)
747 : 112 : pkg_jobs_update_universe_item_priority(universe, cur,
748 : 56 : it->priority + 1, PKG_PRIORITY_UPDATE_CONFLICT);
749 : 76 : }
750 : : }
751 : 691 : }
752 : 894 : }
753 : :
754 : : void
755 : 8 : pkg_jobs_update_conflict_priority(struct pkg_jobs_universe *universe,
756 : : struct pkg_solved *req)
757 : : {
758 : 8 : struct pkg_conflict *c = NULL;
759 : 8 : struct pkg *lp = req->items[1]->pkg;
760 : 8 : struct pkg_job_universe_item *found, *cur, *rit = NULL;
761 : :
762 [ + + ]: 20 : while (pkg_conflicts(lp, &c) == EPKG_OK) {
763 : 12 : rit = NULL;
764 : 12 : found = pkghash_get_value(universe->items, c->uid);
765 [ + - ]: 12 : assert(found != NULL);
766 : :
767 [ - + ]: 16 : LL_FOREACH(found, cur) {
768 [ + + ]: 16 : if (cur->pkg->type != PKG_INSTALLED) {
769 : 12 : rit = cur;
770 : 12 : break;
771 : : }
772 : 4 : }
773 : :
774 [ + - ]: 12 : assert(rit != NULL);
775 [ + - ]: 12 : if (rit->priority >= req->items[1]->priority) {
776 : 0 : pkg_jobs_update_universe_item_priority(universe, req->items[1],
777 : 0 : rit->priority + 1, PKG_PRIORITY_UPDATE_CONFLICT);
778 : : /*
779 : : * Update priorities for a remote part as well
780 : : */
781 : 0 : pkg_jobs_update_universe_item_priority(universe, req->items[0],
782 : 0 : req->items[0]->priority, PKG_PRIORITY_UPDATE_REQUEST);
783 : 0 : }
784 : : }
785 : 8 : }
786 : :
787 : :
788 : : void
789 : 642 : pkg_jobs_update_universe_priority(struct pkg_jobs_universe *universe,
790 : : struct pkg_job_universe_item *it, enum pkg_priority_update_type type)
791 : : {
792 : 642 : pkg_jobs_update_universe_item_priority(universe, it, 0, type);
793 : 642 : }
794 : :
795 : : static void
796 : 24 : pkg_jobs_universe_provide_free(struct pkg_job_provide *pr)
797 : : {
798 : : struct pkg_job_provide *cur, *tmp;
799 : :
800 [ + + + + ]: 48 : DL_FOREACH_SAFE(pr, cur, tmp) {
801 : 24 : free (cur);
802 : 24 : }
803 : 24 : }
804 : :
805 : : static void
806 : 0 : pkg_jobs_universe_replacement_free(struct pkg_job_replace *r)
807 : : {
808 : 0 : free(r->new_uid);
809 : 0 : free(r->old_uid);
810 : 0 : free(r);
811 : 0 : }
812 : :
813 : : void
814 : 611 : pkg_jobs_universe_free(struct pkg_jobs_universe *universe)
815 : : {
816 : : struct pkg_job_universe_item *cur, *curtmp;
817 : : pkghash_it it;
818 : :
819 : 611 : it = pkghash_iterator(universe->items);
820 [ + + ]: 1456 : while (pkghash_next(&it)) {
821 [ + + + + ]: 1955 : LL_FOREACH_SAFE(it.value, cur, curtmp) {
822 : 1110 : pkg_free(cur->pkg);
823 : 1110 : free(cur);
824 : 1110 : }
825 : : }
826 : 611 : pkghash_destroy(universe->items);
827 : 611 : universe->items = NULL;
828 : 611 : pkghash_destroy(universe->seen);
829 : 611 : universe->seen = NULL;
830 : 611 : it = pkghash_iterator(universe->provides);
831 [ + + ]: 635 : while (pkghash_next(&it))
832 : 24 : pkg_jobs_universe_provide_free(it.value);
833 : 611 : pkghash_destroy(universe->provides);
834 [ + - + - : 611 : LL_FREE(universe->uid_replaces, pkg_jobs_universe_replacement_free);
# # # # #
# # # ]
835 : 611 : }
836 : :
837 : : struct pkg_jobs_universe *
838 : 611 : pkg_jobs_universe_new(struct pkg_jobs *j)
839 : : {
840 : : struct pkg_jobs_universe *universe;
841 : :
842 : 611 : universe = xcalloc(1, sizeof(struct pkg_jobs_universe));
843 : 611 : universe->j = j;
844 : :
845 : 611 : return (universe);
846 : : }
847 : :
848 : : struct pkg_job_universe_item *
849 : 41 : pkg_jobs_universe_find(struct pkg_jobs_universe *universe, const char *uid)
850 : : {
851 : 41 : return (pkghash_get_value(universe->items, uid));
852 : : }
853 : :
854 : : void
855 : 0 : pkg_jobs_universe_change_uid(struct pkg_jobs_universe *universe,
856 : : struct pkg_job_universe_item *unit,
857 : : const char *new_uid, bool update_rdeps)
858 : : {
859 : 0 : struct pkg_dep *rd = NULL, *d = NULL;
860 : : struct pkg_job_universe_item *found, *tmp;
861 : :
862 : : struct pkg *lp;
863 : : struct pkg_job_replace *replacement;
864 : :
865 [ # # ]: 0 : if (update_rdeps) {
866 : : /* For all rdeps update deps accordingly */
867 [ # # ]: 0 : while (pkg_rdeps(unit->pkg, &rd) == EPKG_OK) {
868 : 0 : found = pkg_jobs_universe_find(universe, rd->uid);
869 [ # # ]: 0 : if (found == NULL) {
870 : 0 : lp = pkg_jobs_universe_get_local(universe, rd->uid, 0);
871 : : /* XXX */
872 [ # # ]: 0 : assert(lp != NULL);
873 : 0 : pkg_jobs_universe_process_item(universe, lp, &found);
874 : 0 : }
875 : :
876 [ # # ]: 0 : if (found != NULL) {
877 [ # # ]: 0 : while (pkg_deps(found->pkg, &d) == EPKG_OK) {
878 [ # # ]: 0 : if (strcmp(d->uid, unit->pkg->uid) == 0) {
879 : 0 : free(d->uid);
880 : 0 : d->uid = xstrdup(new_uid);
881 : 0 : }
882 : : }
883 : 0 : }
884 : : }
885 : 0 : }
886 : :
887 : 0 : replacement = xcalloc(1, sizeof(*replacement));
888 : 0 : replacement->old_uid = xstrdup(unit->pkg->uid);
889 : 0 : replacement->new_uid = xstrdup(new_uid);
890 : 0 : LL_PREPEND(universe->uid_replaces, replacement);
891 : :
892 : 0 : tmp = pkghash_delete(universe->items, unit->pkg->uid);
893 [ # # ]: 0 : if (tmp != NULL)
894 : 0 : tmp->inhash = false;
895 : 0 : free(unit->pkg->uid);
896 : 0 : unit->pkg->uid = xstrdup(new_uid);
897 : :
898 : 0 : found = pkghash_get_value(universe->items, new_uid);
899 [ # # ]: 0 : if (found != NULL)
900 [ # # ]: 0 : DL_APPEND(found, unit);
901 : : else
902 [ # # # # ]: 0 : pkghash_safe_add(universe->items, new_uid, unit, NULL);
903 : :
904 : 0 : }
905 : :
906 : : static struct pkg_job_universe_item *
907 : 261 : pkg_jobs_universe_select_max_ver(struct pkg_job_universe_item *chain)
908 : : {
909 : 261 : struct pkg_job_universe_item *cur, *res = NULL;
910 : 261 : bool found = false;
911 : : int r;
912 : :
913 [ + + ]: 724 : LL_FOREACH(chain, cur) {
914 [ + + ]: 463 : if (cur->pkg->type == PKG_INSTALLED)
915 : 133 : continue;
916 : :
917 [ + + ]: 330 : if (res != NULL) {
918 : 93 : r = pkg_version_change_between(cur->pkg, res->pkg);
919 [ - + ]: 93 : if (r == PKG_UPGRADE) {
920 : 0 : res = cur;
921 : 0 : found = true;
922 : 0 : }
923 [ + + ]: 93 : else if (r != PKG_REINSTALL) {
924 : : /*
925 : : * Actually the selected package is newer than some other
926 : : * packages in the chain
927 : : */
928 : 77 : found = true;
929 : 77 : }
930 : 93 : }
931 : : else {
932 : 237 : res = cur;
933 : : }
934 : 330 : }
935 : :
936 [ + + ]: 261 : return (found ? res : NULL);
937 : : }
938 : :
939 : : static struct pkg_job_universe_item *
940 : 256 : pkg_jobs_universe_select_max_prio(struct pkg_job_universe_item *chain)
941 : : {
942 : : struct pkg_repo *repo;
943 : 256 : unsigned int max_pri = 0;
944 : 256 : struct pkg_job_universe_item *cur, *res = NULL;
945 : :
946 [ + + ]: 672 : LL_FOREACH(chain, cur) {
947 [ + + ]: 416 : if (cur->pkg->type == PKG_INSTALLED)
948 : 104 : continue;
949 : :
950 [ - + ]: 312 : if (cur->pkg->reponame) {
951 : 312 : repo = pkg_repo_find(cur->pkg->reponame);
952 [ + - + + ]: 312 : if (repo && repo->priority > max_pri) {
953 : 24 : res = cur;
954 : 24 : max_pri = repo->priority;
955 : 24 : }
956 : 312 : }
957 : 312 : }
958 : :
959 : 256 : return (res);
960 : : }
961 : :
962 : : static struct pkg_job_universe_item *
963 : 164 : pkg_jobs_universe_select_same_repo(struct pkg_job_universe_item *chain,
964 : : struct pkg_job_universe_item *local, const char *assumed_reponame)
965 : : {
966 : 164 : struct pkg_repo *local_repo = NULL, *repo;
967 : 164 : struct pkg_job_universe_item *cur, *res = NULL;
968 : :
969 [ + - ]: 164 : if (!local) {
970 : :
971 [ # # ]: 0 : if (assumed_reponame) {
972 : 0 : local_repo = pkg_repo_find(assumed_reponame);
973 : 0 : }
974 : 0 : }
975 : : else {
976 [ - + ]: 164 : if (local->pkg->reponame) {
977 : 0 : local_repo = pkg_repo_find(local->pkg->reponame);
978 : 0 : }
979 : : else {
980 : 164 : const char *lrepo = pkg_kv_get(&local->pkg->annotations, "repository");
981 [ + + ]: 164 : if (lrepo) {
982 : 80 : local_repo = pkg_repo_find(lrepo);
983 : 80 : }
984 : : }
985 : : }
986 : :
987 [ + + ]: 164 : if (local_repo == NULL) {
988 : 124 : return (NULL);
989 : : }
990 : : else {
991 [ + + ]: 80 : LL_FOREACH(chain, cur) {
992 [ + + ]: 76 : if (cur->pkg->type == PKG_INSTALLED)
993 : 40 : continue;
994 : :
995 [ - + ]: 36 : if (cur->pkg->reponame) {
996 : 36 : repo = pkg_repo_find(cur->pkg->reponame);
997 [ - + ]: 36 : if (repo == local_repo) {
998 : 36 : res = cur;
999 : 36 : break;
1000 : : }
1001 : 0 : }
1002 : 0 : }
1003 : : }
1004 : :
1005 : 40 : return (res);
1006 : 164 : }
1007 : :
1008 : : struct pkg_job_universe_item *
1009 : 321 : pkg_jobs_universe_select_candidate(struct pkg_job_universe_item *chain,
1010 : : struct pkg_job_universe_item *local, bool conservative,
1011 : : const char *reponame, bool pinning)
1012 : : {
1013 : 321 : struct pkg_job_universe_item *res = NULL;
1014 : :
1015 [ + + ]: 321 : if (local == NULL) {
1016 : : /* New package selection */
1017 [ + - ]: 152 : if (conservative) {
1018 : : /* Check same repo */
1019 [ - + # # ]: 152 : if (reponame && pinning) {
1020 : 0 : res = pkg_jobs_universe_select_same_repo(chain, NULL, reponame);
1021 : 0 : }
1022 : :
1023 [ - + ]: 152 : if (res == NULL) {
1024 : : /* Priority -> version */
1025 : 152 : res = pkg_jobs_universe_select_max_prio(chain);
1026 [ + + ]: 152 : if (res == NULL) {
1027 : 128 : res = pkg_jobs_universe_select_max_ver(chain);
1028 : 128 : }
1029 : 152 : }
1030 : 152 : }
1031 : : else {
1032 [ # # # # ]: 0 : if (reponame && pinning) {
1033 : 0 : res = pkg_jobs_universe_select_same_repo(chain, NULL, reponame);
1034 : 0 : }
1035 : :
1036 [ # # ]: 0 : if (res == NULL) {
1037 : : /* Version -> priority */
1038 : 0 : res = pkg_jobs_universe_select_max_ver(chain);
1039 [ # # ]: 0 : if (res == NULL) {
1040 : 0 : res = pkg_jobs_universe_select_max_prio(chain);
1041 : 0 : }
1042 : 0 : }
1043 : : }
1044 : 152 : }
1045 : : else {
1046 [ + + ]: 169 : if (conservative) {
1047 : : /* same -> prio -> version */
1048 [ - + ]: 140 : if (pinning)
1049 : 140 : res = pkg_jobs_universe_select_same_repo(chain, local, reponame);
1050 [ + + ]: 140 : if (res == NULL) {
1051 : 104 : res = pkg_jobs_universe_select_max_prio(chain);
1052 : 104 : }
1053 [ + + ]: 140 : if (res == NULL) {
1054 : 104 : res = pkg_jobs_universe_select_max_ver(chain);
1055 : 104 : }
1056 : 140 : }
1057 : : else {
1058 : : /* same -> version -> prio */
1059 [ + + ]: 29 : if (pinning)
1060 : 24 : res = pkg_jobs_universe_select_same_repo(chain, local, reponame);
1061 [ - + ]: 29 : if (res == NULL) {
1062 : 29 : res = pkg_jobs_universe_select_max_ver(chain);
1063 : 29 : }
1064 [ + - ]: 29 : if (res == NULL) {
1065 : 0 : res = pkg_jobs_universe_select_max_prio(chain);
1066 : 0 : }
1067 : : }
1068 : : }
1069 : :
1070 : : /* Fallback to any */
1071 [ + + ]: 321 : return (res != NULL ? res : chain);
1072 : : }
1073 : :
1074 : : void
1075 : 1088 : pkg_jobs_universe_process_upgrade_chains(struct pkg_jobs *j)
1076 : : {
1077 : : struct pkg_job_universe_item *unit, *cur, *local;
1078 : : struct pkg_job_request *req;
1079 : : struct pkg_job_request_item *rit, *rtmp;
1080 : : pkghash_it it;
1081 : :
1082 : 1088 : it = pkghash_iterator(j->universe->items);
1083 [ + + ]: 2600 : while (pkghash_next(&it)) {
1084 : 1512 : unsigned vercnt = 0;
1085 : 1512 : unit = (struct pkg_job_universe_item *)it.value;
1086 : :
1087 : 1512 : req = pkghash_get_value(j->request_add, unit->pkg->uid);
1088 [ + + ]: 1512 : if (req == NULL) {
1089 : : /* Not obviously requested */
1090 : 493 : continue;
1091 : : }
1092 : :
1093 : 1019 : local = NULL;
1094 [ + + ]: 2590 : LL_FOREACH(unit, cur) {
1095 [ + + ]: 1571 : if (cur->pkg->type == PKG_INSTALLED)
1096 : 407 : local = cur;
1097 : 1571 : vercnt ++;
1098 : 1571 : }
1099 : :
1100 [ + + + - ]: 1019 : if (local != NULL && local->pkg->locked) {
1101 : 0 : pkg_debug(1, "removing %s from the request as it is locked",
1102 : 0 : cur->pkg->uid);
1103 : 0 : pkghash_del(j->request_add, req->item->pkg->uid);
1104 : 0 : pkg_jobs_request_free(req);
1105 : 0 : continue;
1106 : : }
1107 : :
1108 [ + + ]: 1019 : if (vercnt <= 1)
1109 : 572 : continue;
1110 : :
1111 : : /*
1112 : : * Here we have more than one upgrade candidate,
1113 : : * if local == NULL, then we have two remote repos,
1114 : : * if local != NULL, then we have unspecified upgrade path
1115 : : */
1116 : :
1117 [ + + + + ]: 447 : if ((local == NULL && vercnt > 1) || (vercnt > 2)) {
1118 : : /* Select the most recent or one of packages */
1119 : : struct pkg_job_universe_item *selected;
1120 : :
1121 : 290 : selected = pkg_jobs_universe_select_candidate(unit, local,
1122 : 145 : j->conservative, NULL, j->pinning);
1123 : : /*
1124 : : * Now remove all requests but selected from the requested
1125 : : * candidates
1126 : : */
1127 [ + - ]: 145 : assert(selected != NULL);
1128 : 145 : pkghash_del(j->request_add, req->item->pkg->uid);
1129 : :
1130 : : /*
1131 : : * We also check if the selected package has different digest,
1132 : : * and if it has the same digest we proceed only if we have a
1133 : : * forced job
1134 : : */
1135 [ + + + + ]: 145 : if (local != NULL && strcmp(local->pkg->digest,
1136 [ + + + + ]: 210 : selected->pkg->digest) == 0 &&
1137 : 20 : (j->flags & PKG_FLAG_FORCE) == 0) {
1138 : 4 : pkg_debug (1, "removing %s from the request as it is the "
1139 : 4 : "same as local", selected->pkg->uid);
1140 : 4 : continue;
1141 : : }
1142 : :
1143 [ + + ]: 524 : LL_FOREACH(unit, cur) {
1144 [ + + ]: 383 : if (cur == selected)
1145 : 141 : continue;
1146 : :
1147 [ + + + + ]: 902 : DL_FOREACH_SAFE(req->item, rit, rtmp) {
1148 [ + + ]: 660 : if (rit->unit == cur) {
1149 [ + - - + : 236 : DL_DELETE(req->item, rit);
+ + + + ]
1150 : 118 : free(rit);
1151 : 118 : }
1152 : 660 : }
1153 : 242 : }
1154 [ + - ]: 141 : if (req->item == NULL) {
1155 : 0 : rit = xcalloc(1, sizeof(*rit));
1156 : 0 : rit->pkg = selected->pkg;
1157 : 0 : rit->unit = selected;
1158 [ # # ]: 0 : DL_APPEND(req->item, rit);
1159 : 0 : }
1160 [ + - + - ]: 282 : pkghash_safe_add(j->request_add, selected->pkg->uid, req, NULL);
1161 : 141 : }
1162 : : }
1163 : 1088 : }
1164 : :
1165 : : struct pkg_job_universe_item*
1166 : 424 : pkg_jobs_universe_get_upgrade_candidates(struct pkg_jobs_universe *universe,
1167 : : const char *uid, struct pkg *lp, bool force, const char *version)
1168 : : {
1169 : 424 : struct pkg *pkg = NULL, *selected = lp;
1170 : : struct pkgdb_it *it;
1171 : : struct pkg_job_universe_item *unit, *ucur;
1172 : 424 : int flag = PKG_LOAD_BASIC|PKG_LOAD_DEPS|PKG_LOAD_OPTIONS|
1173 : : PKG_LOAD_REQUIRES|PKG_LOAD_PROVIDES|
1174 : : PKG_LOAD_SHLIBS_REQUIRED|PKG_LOAD_SHLIBS_PROVIDED|
1175 : : PKG_LOAD_ANNOTATIONS|PKG_LOAD_CONFLICTS;
1176 : : kvec_t(struct pkg *) candidates;
1177 : :
1178 : 424 : unit = pkghash_get_value(universe->items, uid);
1179 [ + + ]: 424 : if (unit != NULL) {
1180 : : /*
1181 : : * If a unit has been found, we have already found the potential
1182 : : * upgrade chain for it
1183 : : */
1184 [ + + ]: 108 : if (force) {
1185 : : /*
1186 : : * We also need to ensure that a chain contains remote packages
1187 : : * in case of forced upgrade
1188 : : */
1189 [ + + ]: 26 : DL_FOREACH(unit, ucur) {
1190 [ + + ]: 21 : if (ucur->pkg->type != PKG_INSTALLED) {
1191 : 8 : return (unit);
1192 : : }
1193 : 13 : }
1194 : 5 : }
1195 : : else {
1196 : 95 : return (unit);
1197 : : }
1198 : 5 : }
1199 : :
1200 [ + - + - : 963 : if ((it = pkgdb_repo_query(universe->j->db, uid, MATCH_EXACT,
+ - ]
1201 : 642 : universe->j->reponame)) == NULL)
1202 : 0 : return (NULL);
1203 : :
1204 : 321 : kv_init(candidates);
1205 [ + + ]: 733 : while (pkgdb_it_next(it, &pkg, flag) == EPKG_OK) {
1206 : :
1207 [ + + + + ]: 412 : if (version != NULL && strcmp(pkg->version, version) != 0)
1208 : 8 : continue;
1209 : :
1210 [ + + ]: 404 : if (force) {
1211 : : /* Just add everything */
1212 : 25 : selected = pkg;
1213 : 25 : }
1214 : : else {
1215 [ + + + + ]: 636 : if (selected == lp &&
1216 [ + + ]: 355 : (lp == NULL || pkg_jobs_need_upgrade(pkg, lp)))
1217 : 261 : selected = pkg;
1218 [ + + ]: 118 : else if (pkg_version_change_between(pkg, selected) == PKG_UPGRADE)
1219 : 4 : selected = pkg;
1220 : : }
1221 [ + + - + ]: 404 : kv_prepend(typeof(pkg), candidates, pkg);
1222 : 404 : pkg = NULL;
1223 : : }
1224 : :
1225 : 321 : pkgdb_it_free(it);
1226 : :
1227 [ + + ]: 321 : if (lp != NULL) {
1228 : : /* Add local package to the universe as well */
1229 : 223 : pkg_jobs_universe_add_pkg(universe, lp, false, NULL);
1230 : 223 : }
1231 [ + + ]: 321 : if (selected != lp) {
1232 : : /* We need to add the whole chain of upgrade candidates */
1233 [ + + ]: 629 : for (int i = 0; i < kv_size(candidates); i++) {
1234 : 351 : pkg_jobs_universe_add_pkg(universe, kv_A(candidates, i), force, NULL);
1235 : 351 : }
1236 : 278 : }
1237 : : else {
1238 [ + + ]: 96 : while (kv_size(candidates) > 0)
1239 : 53 : pkg_free(kv_pop(candidates));
1240 : 43 : kv_destroy(candidates);
1241 : :
1242 : 43 : return (NULL);
1243 : : }
1244 : :
1245 : 278 : unit = pkghash_get_value(universe->items, uid);
1246 : 278 : kv_destroy(candidates);
1247 : :
1248 : 278 : return (unit);
1249 : 424 : }
|