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 : : #define dbg(x, ...) pkg_dbg(PKG_DBG_UNIVERSE, x, __VA_ARGS__)
29 : :
30 : : #include <sys/param.h>
31 : : #include <sys/types.h>
32 : :
33 : : #include <assert.h>
34 : : #include <errno.h>
35 : : #ifdef HAVE_LIBUTIL_H
36 : : #include <libutil.h>
37 : : #endif
38 : : #include <stdbool.h>
39 : : #include <stdlib.h>
40 : : #include <string.h>
41 : : #include <ctype.h>
42 : :
43 : : #include "pkg.h"
44 : : #include "private/event.h"
45 : : #include "private/pkg.h"
46 : : #include "private/pkgdb.h"
47 : : #include "private/pkg_jobs.h"
48 : : #include "tllist.h"
49 : :
50 : : #define IS_DELETE(j) ((j)->type == PKG_JOBS_DEINSTALL || (j)->type == PKG_JOBS_AUTOREMOVE)
51 : :
52 : : struct pkg *
53 : 636 : pkg_jobs_universe_get_local(struct pkg_jobs_universe *universe,
54 : : const char *uid, unsigned flag)
55 : : {
56 : 636 : struct pkg *pkg = NULL;
57 : : struct pkgdb_it *it;
58 : : struct pkg_job_universe_item *unit, *cur, *found;
59 : :
60 [ + + ]: 636 : if (flag == 0) {
61 : 631 : flag = PKG_LOAD_BASIC|PKG_LOAD_DEPS|PKG_LOAD_RDEPS|PKG_LOAD_OPTIONS|
62 : : PKG_LOAD_REQUIRES|PKG_LOAD_PROVIDES|
63 : : PKG_LOAD_SHLIBS_REQUIRED|PKG_LOAD_SHLIBS_PROVIDED|PKG_LOAD_ANNOTATIONS|
64 : : PKG_LOAD_CONFLICTS;
65 : 631 : }
66 : :
67 : 636 : unit = pkghash_get_value(universe->items, uid);
68 [ + + ]: 636 : if (unit != NULL) {
69 : : /* Search local in a universe chain */
70 : 232 : cur = unit;
71 : 232 : found = NULL;
72 : 242 : do {
73 [ + + - + ]: 242 : if (cur->pkg->type == PKG_INSTALLED || cur->pkg->type == PKG_GROUP_INSTALLED) {
74 : 108 : found = cur;
75 : 108 : break;
76 : : }
77 : 134 : cur = cur->prev;
78 [ + + ]: 134 : } while (cur != unit);
79 : :
80 [ + + - + ]: 232 : if (found && found->pkg->type == PKG_INSTALLED) {
81 : 108 : pkgdb_ensure_loaded(universe->j->db, unit->pkg, flag);
82 : 108 : return (unit->pkg);
83 : : }
84 : 124 : }
85 : :
86 : : /* XX TODO query local groups */
87 [ + - ]: 528 : if ((it = pkgdb_query(universe->j->db, uid, MATCH_INTERNAL)) == NULL)
88 : 0 : return (NULL);
89 : :
90 [ + + ]: 528 : if (pkgdb_it_next(it, &pkg, flag) != EPKG_OK)
91 : 439 : pkg = NULL;
92 : :
93 : 528 : pkgdb_it_free(it);
94 : :
95 : 528 : return (pkg);
96 : 636 : }
97 : :
98 : : static pkg_chain_t *
99 : 42 : pkg_jobs_universe_get_remote(struct pkg_jobs_universe *universe,
100 : : const char *uid, unsigned flag)
101 : : {
102 : 42 : struct pkg *pkg = NULL;
103 : 42 : pkg_chain_t *result = NULL;
104 : : struct pkgdb_it *it;
105 : : struct pkg_job_universe_item *unit, *cur, *found;
106 : :
107 [ - + ]: 42 : if (flag == 0) {
108 : 42 : flag = PKG_LOAD_BASIC|PKG_LOAD_DEPS|PKG_LOAD_OPTIONS|
109 : : PKG_LOAD_PROVIDES|PKG_LOAD_REQUIRES|
110 : : PKG_LOAD_SHLIBS_REQUIRED|PKG_LOAD_SHLIBS_PROVIDED|
111 : : PKG_LOAD_ANNOTATIONS|PKG_LOAD_CONFLICTS;
112 : 42 : }
113 : :
114 : 42 : unit = pkghash_get_value(universe->items, uid);
115 [ - + # # ]: 42 : if (unit != NULL && unit->pkg->type != PKG_INSTALLED) {
116 : : /* Search local in a universe chain */
117 : 0 : cur = unit;
118 : 0 : found = NULL;
119 : 0 : do {
120 [ # # ]: 0 : if (cur->pkg->type != PKG_INSTALLED) {
121 : 0 : found = cur;
122 : 0 : break;
123 : : }
124 : 0 : cur = cur->prev;
125 [ # # ]: 0 : } while (cur != unit);
126 : :
127 [ # # ]: 0 : if (found) {
128 : : /* Assume processed */
129 : 0 : return (NULL);
130 : : }
131 : 0 : }
132 : :
133 [ + - + - : 126 : if ((it = pkgdb_repo_query2(universe->j->db, uid, MATCH_INTERNAL,
+ - ]
134 : 84 : universe->j->reponames)) == NULL)
135 : 0 : return (NULL);
136 : :
137 [ + + ]: 97 : while (pkgdb_it_next(it, &pkg, flag) == EPKG_OK) {
138 [ + + ]: 55 : if (result == NULL)
139 : 38 : result = xcalloc(1, sizeof(pkg_chain_t));
140 [ + + + + : 55 : tll_push_front(*result, pkg);
+ - - + +
+ ]
141 : 55 : pkg = NULL;
142 : : }
143 : :
144 : 42 : pkgdb_it_free(it);
145 : :
146 : 42 : return (result);
147 : 42 : }
148 : :
149 : : /**
150 : : * Check whether a package is in the universe already or add it
151 : : * @return item or NULL
152 : : */
153 : : int
154 : 495 : pkg_jobs_universe_add_pkg(struct pkg_jobs_universe *universe, struct pkg *pkg,
155 : : bool force __unused, struct pkg_job_universe_item **found)
156 : : {
157 : 495 : struct pkg_job_universe_item *item, *seen, *tmp = NULL;
158 : :
159 : 495 : pkg_validate(pkg, universe->j->db);
160 : :
161 [ + + ]: 495 : if (pkg->digest == NULL) {
162 : 1 : dbg(3, "no digest found for package %s (%s-%s)",
163 : : pkg->uid, pkg->name, pkg->version);
164 [ - + ]: 1 : if (pkg_checksum_calculate(pkg, universe->j->db, false, true, false) != EPKG_OK) {
165 [ # # ]: 0 : if (found != NULL)
166 : 0 : *found = NULL;
167 : 0 : return (EPKG_FATAL);
168 : : }
169 : 1 : }
170 : :
171 : 495 : seen = pkghash_get_value(universe->seen, pkg->digest);
172 [ + + ]: 495 : if (seen) {
173 : 198 : bool same_package = false;
174 : :
175 [ + + ]: 230 : DL_FOREACH(seen, tmp) {
176 [ + + + + : 213 : if (tmp->pkg == pkg || (tmp->pkg->type == pkg->type &&
+ + ]
177 : 17 : STREQ(tmp->pkg->digest, pkg->digest))) {
178 [ + + ]: 187 : if (tmp->pkg->reponame != NULL) {
179 [ + + ]: 113 : if (STREQ(tmp->pkg->reponame, pkg->reponame)) {
180 : 107 : same_package = true;
181 : 107 : break;
182 : : }
183 : 6 : } else {
184 : 74 : same_package = true;
185 : 74 : break;
186 : : }
187 : 6 : }
188 : 32 : }
189 : :
190 [ + + ]: 198 : if (same_package) {
191 [ + + ]: 181 : if (found != NULL) {
192 : 180 : *found = seen;
193 : 180 : }
194 : :
195 : 181 : return (EPKG_END);
196 : : }
197 : 17 : }
198 : :
199 [ - + ]: 314 : if (pkg_is_locked(pkg)) {
200 : 0 : return (EPKG_LOCKED);
201 : : }
202 : :
203 : 314 : dbg(2, "add new %s pkg: %s, (%s-%s:%s)",
204 : : (pkg->type == PKG_INSTALLED ? "local" : "remote"), pkg->uid,
205 : : pkg->name, pkg->version, pkg->digest);
206 : :
207 : 314 : item = xcalloc(1, sizeof (struct pkg_job_universe_item));
208 : 314 : item->pkg = pkg;
209 : :
210 : 314 : tmp = pkghash_get_value(universe->items, pkg->uid);
211 [ + + ]: 314 : if (tmp == NULL) {
212 [ + + - + ]: 309 : pkghash_safe_add(universe->items, pkg->uid, item, NULL);
213 : 235 : item->inhash = true;
214 : 235 : }
215 : :
216 [ + + ]: 314 : DL_APPEND(tmp, item);
217 : :
218 [ + + ]: 314 : if (seen == NULL)
219 [ + + - + ]: 433 : pkghash_safe_add(universe->seen, item->pkg->digest, item, NULL);
220 : :
221 : 314 : universe->nitems++;
222 : :
223 [ + + ]: 314 : if (found != NULL)
224 : 150 : *found = item;
225 : :
226 : 314 : return (EPKG_OK);
227 : 495 : }
228 : :
229 : : #define DEPS_FLAG_REVERSE 0x1 << 1
230 : : #define DEPS_FLAG_MIRROR 0x1 << 2
231 : : #define DEPS_FLAG_FORCE_LOCAL 0x1 << 3
232 : : #define DEPS_FLAG_FORCE_MISSING 0x1 << 4
233 : : #define DEPS_FLAG_FORCE_UPGRADE 0x1 << 5
234 : :
235 : : static int
236 : 455 : pkg_jobs_universe_process_deps(struct pkg_jobs_universe *universe,
237 : : struct pkg *pkg, unsigned flags)
238 : : {
239 : 455 : struct pkg_dep *d = NULL;
240 : : int (*deps_func)(const struct pkg *pkg, struct pkg_dep **d);
241 : : int rc;
242 : : struct pkg_job_universe_item *unit;
243 : : struct pkg *npkg, *rpkg, *lpkg;
244 : 455 : pkg_chain_t *rpkgs = NULL;
245 : 455 : bool found = false;
246 : :
247 : 455 : rpkg = NULL;
248 : :
249 [ + + ]: 455 : if (flags & DEPS_FLAG_REVERSE) {
250 : 251 : dbg(4, "Processing rdeps for %s (%s)", pkg->uid, pkg->type == PKG_INSTALLED ? "installed" : "remote");
251 [ + + ]: 251 : if (pkg->type != PKG_INSTALLED) {
252 : 172 : lpkg = pkg_jobs_universe_get_local(universe, pkg->uid, 0);
253 [ + + - + ]: 172 : if (lpkg != NULL && lpkg != pkg)
254 : 55 : return (pkg_jobs_universe_process_deps(universe, lpkg, flags));
255 : 117 : }
256 : 196 : deps_func = pkg_rdeps;
257 : 196 : }
258 : : else {
259 : 204 : dbg(4, "Processing deps for %s", pkg->uid);
260 : 204 : deps_func = pkg_deps;
261 : : }
262 : :
263 [ + + ]: 495 : while (deps_func(pkg, &d) == EPKG_OK) {
264 : 97 : dbg(4, "Processing *deps for %s: %s", pkg->uid, d->uid);
265 [ + + ]: 97 : if (pkghash_get(universe->items, d->uid) != NULL)
266 : 55 : continue;
267 : :
268 : 42 : rpkgs = NULL;
269 : 42 : npkg = NULL;
270 [ + + ]: 42 : if (!(flags & DEPS_FLAG_MIRROR)) {
271 : 38 : npkg = pkg_jobs_universe_get_local(universe, d->uid, 0);
272 : 38 : }
273 : :
274 [ - + ]: 42 : if (!(flags & DEPS_FLAG_FORCE_LOCAL)) {
275 : :
276 : : /* Check for remote dependencies */
277 : 42 : rpkgs = pkg_jobs_universe_get_remote(universe, d->uid, 0);
278 : 42 : }
279 : :
280 [ + + + + ]: 42 : if (npkg == NULL && rpkgs == NULL) {
281 : 2 : pkg_emit_error("%s has a missing dependency: %s",
282 : 2 : pkg->name, d->name);
283 : :
284 [ - + ]: 2 : if (flags & DEPS_FLAG_FORCE_MISSING) {
285 : 0 : continue;
286 : : }
287 : :
288 : 2 : return (EPKG_FATAL);
289 : : }
290 : :
291 [ + + ]: 40 : if (npkg != NULL) {
292 [ + - ]: 11 : if (pkg_jobs_universe_process_item(universe, npkg, &unit) != EPKG_OK) {
293 : 0 : continue;
294 : : }
295 : 11 : }
296 : :
297 [ + + ]: 40 : if (rpkgs == NULL)
298 : 2 : continue;
299 : : /*
300 : : * When processing deps, we should first try to select a dependency
301 : : * from the same repo.
302 : : * Otherwise, we would have ping-pong of dependencies instead of
303 : : * the situation when this behaviour is handled by
304 : : * CONSERVATIVE_UPGRADES.
305 : : *
306 : : * Important notes here:
307 : : * 1. We are looking for packages that are dependencies of a package
308 : : * `pkg`
309 : : * 2. Now if `pkg` belongs to repo `r` and `rpkg` belongs to repo
310 : : * `r` then we just select it.
311 : : * 3. If `rpkg` is not found in `r` we just scan all packages
312 : : */
313 : :
314 : : /*
315 : : * XXX: this is the proper place to expand flexible dependencies
316 : : */
317 : :
318 : 38 : found = false;
319 : : /* Iteration one */
320 [ + - + + : 50 : tll_foreach(*rpkgs, rit) {
+ + ]
321 : 44 : rpkg = rit->item;
322 : :
323 [ + + - + : 44 : if (pkg->reponame && rpkg->reponame &&
+ + ]
324 : 35 : STREQ(pkg->reponame, rpkg->reponame)) {
325 : 32 : found = true;
326 : 32 : break;
327 : : }
328 : 12 : }
329 : :
330 : : /* Fallback if a dependency is not found in the same repo */
331 [ + + ]: 38 : if (!found) {
332 [ + - + + : 15 : tll_foreach(*rpkgs, rit) {
+ + ]
333 : 9 : rpkg = rit->item;
334 : :
335 [ - + ]: 9 : if (npkg != NULL) {
336 : : /* Set reason for upgrades */
337 [ + + ]: 9 : if (!pkg_jobs_need_upgrade(rpkg, npkg))
338 : 6 : continue;
339 : : /* Save automatic flag */
340 : 3 : rpkg->automatic = npkg->automatic;
341 : 3 : }
342 : :
343 : 3 : rc = pkg_jobs_universe_process_item(universe, rpkg, NULL);
344 : :
345 : : /* Special case if we cannot find any package */
346 [ - + # # ]: 3 : if (npkg == NULL && rc != EPKG_OK) {
347 [ # # # # : 0 : tll_free(*rpkgs);
# # ]
348 : 0 : free(rpkgs);
349 : 0 : return (rc);
350 : : }
351 : 3 : }
352 : 6 : }
353 : : else {
354 [ + - ]: 32 : assert (rpkg != NULL);
355 : :
356 [ + + ]: 32 : if (npkg != NULL) {
357 : : /* Set reason for upgrades */
358 [ + + ]: 3 : if (!pkg_jobs_need_upgrade(rpkg, npkg))
359 : 2 : continue;
360 : : /* Save automatic flag */
361 : 1 : rpkg->automatic = npkg->automatic;
362 : 1 : }
363 : :
364 : 30 : rc = pkg_jobs_universe_process_item(universe, rpkg, NULL);
365 [ + + + - ]: 30 : if (npkg == NULL && rc != EPKG_OK) {
366 [ # # # # : 0 : tll_free(*rpkgs);
# # ]
367 : 0 : free(rpkgs);
368 : 0 : return (rc);
369 : : }
370 : : }
371 : :
372 [ + - + + : 87 : tll_free(*rpkgs);
+ + ]
373 : 36 : free(rpkgs);
374 : : }
375 : :
376 : 398 : return (EPKG_OK);
377 : 455 : }
378 : :
379 : : static int
380 : 30 : pkg_jobs_universe_handle_provide(struct pkg_jobs_universe *universe,
381 : : struct pkgdb_it *it, const char *name, bool is_shlib, struct pkg *parent __unused)
382 : : {
383 : : struct pkg_job_universe_item *unit;
384 : : struct pkg_job_provide *pr, *prhead;
385 : : struct pkg *npkg, *rpkg;
386 : : int rc;
387 : 30 : unsigned flags = PKG_LOAD_BASIC|PKG_LOAD_OPTIONS|PKG_LOAD_DEPS|
388 : : PKG_LOAD_REQUIRES|PKG_LOAD_PROVIDES|
389 : : PKG_LOAD_SHLIBS_REQUIRED|PKG_LOAD_SHLIBS_PROVIDED|
390 : : PKG_LOAD_ANNOTATIONS|PKG_LOAD_CONFLICTS;
391 : :
392 : 30 : rpkg = NULL;
393 : :
394 : 30 : prhead = pkghash_get_value(universe->provides, name);
395 [ + + ]: 39 : while (pkgdb_it_next(it, &rpkg, flags) == EPKG_OK) {
396 : : /* Check for local packages */
397 [ + + ]: 9 : if ((unit = pkghash_get_value(universe->items, rpkg->uid)) != NULL) {
398 : : /* Remote provide is newer, so we can add it */
399 [ - + - + ]: 8 : if (pkg_jobs_universe_process_item(universe, rpkg,
400 : 4 : &unit) != EPKG_OK) {
401 : 0 : continue;
402 : : }
403 : :
404 : 4 : rpkg = NULL;
405 : 4 : }
406 : : else {
407 : : /* Maybe local package has just been not added */
408 : 5 : npkg = pkg_jobs_universe_get_local(universe, rpkg->uid, 0);
409 [ + - ]: 5 : if (npkg != NULL) {
410 [ # # # # ]: 0 : if (pkg_jobs_universe_process_item(universe, npkg,
411 : 0 : &unit) != EPKG_OK) {
412 : 0 : return (EPKG_FATAL);
413 : : }
414 [ # # # # ]: 0 : if (pkg_jobs_universe_process_item(universe, rpkg,
415 : 0 : &unit) != EPKG_OK) {
416 : 0 : continue;
417 : : }
418 [ # # ]: 0 : if (unit != NULL)
419 : 0 : rpkg = NULL;
420 : 0 : }
421 : : }
422 : :
423 : : /* Skip seen packages */
424 [ + + ]: 9 : if (unit == NULL) {
425 [ + - ]: 5 : if (rpkg->digest == NULL) {
426 : 0 : dbg(3, "no digest found for package %s", rpkg->uid);
427 [ # # # # : 0 : if (pkg_checksum_calculate(rpkg,
# # ]
428 : 0 : universe->j->db, false, true, false) != EPKG_OK) {
429 : 0 : return (EPKG_FATAL);
430 : : }
431 : 0 : }
432 : 5 : rc = pkg_jobs_universe_process_item(universe, rpkg,
433 : : &unit);
434 : :
435 [ - + ]: 5 : if (rc != EPKG_OK) {
436 : 0 : return (rc);
437 : : }
438 : :
439 : : /* Reset package to avoid freeing */
440 : 5 : rpkg = NULL;
441 : 5 : }
442 : :
443 : 9 : pr = xcalloc (1, sizeof (*pr));
444 : 9 : pr->un = unit;
445 : 9 : pr->provide = name;
446 : 9 : pr->is_shlib = is_shlib;
447 : :
448 [ - + ]: 9 : if (prhead == NULL) {
449 [ - + ]: 9 : DL_APPEND(prhead, pr);
450 [ + + - + ]: 10 : pkghash_safe_add(universe->provides, pr->provide,
451 : : prhead, NULL);
452 : 9 : dbg(4, "add new provide %s-%s(%s) for require %s",
453 : : pr->un->pkg->name, pr->un->pkg->version,
454 : : pr->un->pkg->type == PKG_INSTALLED ? "l" : "r",
455 : : pr->provide);
456 : 9 : } else {
457 [ # # ]: 0 : DL_APPEND(prhead, pr);
458 : 0 : dbg(4, "append provide %s-%s(%s) for require %s",
459 : : pr->un->pkg->name, pr->un->pkg->version,
460 : : pr->un->pkg->type == PKG_INSTALLED ? "l" : "r",
461 : : pr->provide);
462 : : }
463 : : }
464 : :
465 : 30 : return (EPKG_OK);
466 : 30 : }
467 : :
468 : : static int
469 : 196 : pkg_jobs_universe_process_shlibs(struct pkg_jobs_universe *universe,
470 : : struct pkg *pkg)
471 : : {
472 : : struct pkgdb_it *it;
473 : : int rc;
474 : :
475 [ + + + + : 204 : tll_foreach(pkg->shlibs_required, s) {
+ + ]
476 [ + + ]: 8 : if (pkghash_get(universe->provides, s->item) != NULL)
477 : 1 : continue;
478 : :
479 : : /* Check for local provides */
480 : 7 : it = pkgdb_query_shlib_provide(universe->j->db, s->item);
481 [ - + ]: 7 : if (it != NULL) {
482 : 14 : rc = pkg_jobs_universe_handle_provide(universe, it,
483 : 7 : s->item, true, pkg);
484 : 7 : pkgdb_it_free(it);
485 : :
486 [ + - ]: 7 : if (rc != EPKG_OK) {
487 : 0 : dbg(1, "cannot find local packages that provide library %s "
488 : : "required for %s",
489 : : s->item, pkg->name);
490 : 0 : }
491 : 7 : }
492 : : /* Not found, search in the repos */
493 : 14 : it = pkgdb_repo_shlib_provide(universe->j->db,
494 : 7 : s->item, universe->j->reponames);
495 : :
496 [ - + ]: 7 : if (it != NULL) {
497 : 7 : rc = pkg_jobs_universe_handle_provide(universe, it, s->item, true, pkg);
498 : 7 : pkgdb_it_free(it);
499 : :
500 [ + - ]: 7 : if (rc != EPKG_OK) {
501 : 0 : dbg(1, "cannot find remote packages that provide library %s "
502 : : "required for %s",
503 : : s->item, pkg->name);
504 : 0 : }
505 : 7 : }
506 : 7 : }
507 : :
508 : 196 : return (EPKG_OK);
509 : : }
510 : :
511 : : static int
512 : 196 : pkg_jobs_universe_process_provides_requires(struct pkg_jobs_universe *universe,
513 : : struct pkg *pkg)
514 : : {
515 : : struct pkgdb_it *it;
516 : : int rc;
517 : :
518 [ + + + + : 209 : tll_foreach(pkg->requires, r) {
- + ]
519 [ + + ]: 13 : if (pkghash_get(universe->provides, r->item) != NULL)
520 : 5 : continue;
521 : :
522 : : /* Check for local provides */
523 : 8 : it = pkgdb_query_provide(universe->j->db, r->item);
524 [ - + ]: 8 : if (it != NULL) {
525 : 8 : rc = pkg_jobs_universe_handle_provide(universe, it, r->item, false, pkg);
526 : 8 : pkgdb_it_free(it);
527 : :
528 [ + - ]: 8 : if (rc != EPKG_OK) {
529 : 0 : dbg(1, "cannot find local packages that provide %s "
530 : : "required for %s",
531 : : r->item, pkg->name);
532 : 0 : }
533 : 8 : }
534 : :
535 : : /* Not found, search in the repos */
536 : 16 : it = pkgdb_repo_provide(universe->j->db,
537 : 8 : r->item, universe->j->reponames);
538 : :
539 [ - + ]: 8 : if (it != NULL) {
540 : 8 : rc = pkg_jobs_universe_handle_provide(universe, it, r->item, false, pkg);
541 : 8 : pkgdb_it_free(it);
542 : :
543 [ + - ]: 8 : if (rc != EPKG_OK) {
544 : 0 : dbg(1, "cannot find remote packages that provide %s "
545 : : "required for %s",
546 : : r->item, pkg->name);
547 : 0 : return (rc);
548 : : }
549 : 8 : }
550 : 8 : }
551 : :
552 : 196 : return (EPKG_OK);
553 : 196 : }
554 : :
555 : : int
556 : 234 : pkg_jobs_universe_process_item(struct pkg_jobs_universe *universe, struct pkg *pkg,
557 : : struct pkg_job_universe_item **result)
558 : : {
559 : 234 : unsigned flags = 0, job_flags;
560 : 234 : int rc = EPKG_OK;
561 : 234 : pkg_jobs_t type = universe->j->type;
562 : : struct pkg_job_universe_item *found;
563 : :
564 : 234 : dbg(4, "Processing item %s\n", pkg->uid);
565 : :
566 : 234 : job_flags = universe->j->flags;
567 : :
568 : : /*
569 : : * Add pkg itself. If package is already seen then we check the `processed`
570 : : * flag that means that we have already tried to check our universe
571 : : */
572 : 234 : rc = pkg_jobs_universe_add_pkg(universe, pkg, false, &found);
573 [ - + ]: 234 : if (rc == EPKG_CONFLICT)
574 : 0 : return (rc);
575 : :
576 [ + + ]: 234 : if (result)
577 : 35 : *result = found;
578 : :
579 [ + + ]: 234 : if (rc == EPKG_END) {
580 [ + + ]: 180 : if (found->processed)
581 : 29 : return (EPKG_OK);
582 : 151 : }
583 [ - + ]: 54 : else if (rc != EPKG_OK) {
584 : 0 : return (rc);
585 : : }
586 : :
587 : 205 : found->processed = true;
588 : :
589 : : /* Convert jobs flags to dependency logical flags */
590 [ + - ]: 205 : if (job_flags & PKG_FLAG_FORCE_MISSING)
591 : 0 : flags |= DEPS_FLAG_FORCE_MISSING;
592 : :
593 [ + + + - : 205 : switch(type) {
- - ]
594 : : case PKG_JOBS_FETCH:
595 [ + + ]: 8 : if (job_flags & PKG_FLAG_RECURSIVE) {
596 : 7 : flags |= DEPS_FLAG_MIRROR;
597 : : /* For fetch jobs we worry about depends only */
598 : 7 : rc = pkg_jobs_universe_process_deps(universe, pkg, flags);
599 : 7 : }
600 : 205 : break;
601 : : case PKG_JOBS_INSTALL:
602 : : case PKG_JOBS_UPGRADE:
603 : : /* Handle depends */
604 : 197 : rc = pkg_jobs_universe_process_deps(universe, pkg, flags);
605 [ + + ]: 197 : if (rc != EPKG_OK)
606 : 1 : return (rc);
607 : : /* Handle reverse depends */
608 : 392 : rc = pkg_jobs_universe_process_deps(universe, pkg,
609 : 196 : flags|DEPS_FLAG_REVERSE);
610 [ - + ]: 196 : if (rc != EPKG_OK)
611 : 0 : return (rc);
612 : : /* Provides/requires */
613 : 196 : rc = pkg_jobs_universe_process_shlibs(universe, pkg);
614 [ - + ]: 196 : if (rc != EPKG_OK)
615 : 0 : return (rc);
616 : 196 : rc = pkg_jobs_universe_process_provides_requires(universe, pkg);
617 [ - + ]: 196 : if (rc != EPKG_OK)
618 : 0 : return (rc);
619 : 196 : break;
620 : : case PKG_JOBS_AUTOREMOVE:
621 : 0 : rc = pkg_jobs_universe_process_deps(universe, pkg, flags);
622 [ # # ]: 0 : if (rc != EPKG_OK)
623 : 0 : return (rc);
624 : 0 : rc = pkg_jobs_universe_process_shlibs(universe, pkg);
625 [ # # ]: 0 : if (rc != EPKG_OK)
626 : 0 : return (rc);
627 : 0 : rc = pkg_jobs_universe_process_provides_requires(universe, pkg);
628 [ # # ]: 0 : if (rc != EPKG_OK)
629 : 0 : return (rc);
630 : 0 : break;
631 : : /* XXX */
632 : : break;
633 : : case PKG_JOBS_DEINSTALL:
634 : : /* For delete jobs we worry only about local reverse deps */
635 : 0 : flags |= DEPS_FLAG_REVERSE|DEPS_FLAG_FORCE_LOCAL;
636 [ # # ]: 0 : if (job_flags & PKG_FLAG_RECURSIVE) {
637 : 0 : rc = pkg_jobs_universe_process_deps(universe, pkg, flags);
638 [ # # ]: 0 : if (rc != EPKG_OK)
639 : 0 : return (rc);
640 : 0 : rc = pkg_jobs_universe_process_shlibs(universe, pkg);
641 [ # # ]: 0 : if (rc != EPKG_OK)
642 : 0 : return (rc);
643 : 0 : rc = pkg_jobs_universe_process_provides_requires(universe, pkg);
644 [ # # ]: 0 : if (rc != EPKG_OK)
645 : 0 : return (rc);
646 : 0 : break;
647 : : }
648 : 0 : break;
649 : : }
650 : :
651 : 204 : return (rc);
652 : 234 : }
653 : :
654 : : int
655 : 166 : pkg_jobs_universe_process(struct pkg_jobs_universe *universe,
656 : : struct pkg *pkg)
657 : : {
658 : 166 : return (pkg_jobs_universe_process_item(universe, pkg, NULL));
659 : : }
660 : :
661 : : static void
662 : 9 : pkg_jobs_universe_provide_free(struct pkg_job_provide *pr)
663 : : {
664 : : struct pkg_job_provide *cur, *tmp;
665 : :
666 [ + + - + : 18 : DL_FOREACH_SAFE(pr, cur, tmp) {
+ + ]
667 : 9 : free (cur);
668 : 9 : }
669 : 9 : }
670 : :
671 : : void
672 : 165 : pkg_jobs_universe_free(struct pkg_jobs_universe *universe)
673 : : {
674 : : struct pkg_job_universe_item *cur, *curtmp;
675 : : pkghash_it it;
676 : :
677 : 165 : it = pkghash_iterator(universe->items);
678 [ + + ]: 400 : while (pkghash_next(&it)) {
679 [ + + - + : 549 : LL_FOREACH_SAFE(it.value, cur, curtmp) {
+ + ]
680 : 314 : pkg_free(cur->pkg);
681 : 314 : free(cur);
682 : 314 : }
683 : : }
684 : 165 : pkghash_destroy(universe->items);
685 : 165 : universe->items = NULL;
686 : 165 : pkghash_destroy(universe->seen);
687 : 165 : universe->seen = NULL;
688 : 165 : it = pkghash_iterator(universe->provides);
689 [ + + ]: 174 : while (pkghash_next(&it))
690 : 9 : pkg_jobs_universe_provide_free(it.value);
691 : 165 : pkghash_destroy(universe->provides);
692 : 165 : free(universe);
693 : 165 : }
694 : :
695 : : struct pkg_jobs_universe *
696 : 165 : pkg_jobs_universe_new(struct pkg_jobs *j)
697 : : {
698 : : struct pkg_jobs_universe *universe;
699 : :
700 : 165 : universe = xcalloc(1, sizeof(struct pkg_jobs_universe));
701 : 165 : universe->j = j;
702 : :
703 : 165 : return (universe);
704 : : }
705 : :
706 : : struct pkg_job_universe_item *
707 : 13 : pkg_jobs_universe_find(struct pkg_jobs_universe *universe, const char *uid)
708 : : {
709 : 13 : return (pkghash_get_value(universe->items, uid));
710 : : }
711 : :
712 : : static struct pkg_job_universe_item *
713 : 83 : pkg_jobs_universe_select_max_ver(struct pkg_job_universe_item *chain)
714 : : {
715 : 83 : struct pkg_job_universe_item *cur, *res = NULL;
716 : 83 : bool found = false;
717 : : int r;
718 : :
719 [ + + ]: 246 : LL_FOREACH(chain, cur) {
720 [ + + ]: 163 : if (cur->pkg->type == PKG_INSTALLED)
721 : 48 : continue;
722 : :
723 [ + + ]: 115 : if (res != NULL) {
724 : 38 : r = pkg_version_change_between(cur->pkg, res->pkg);
725 [ - + ]: 38 : if (r == PKG_UPGRADE) {
726 : 0 : res = cur;
727 : 0 : found = true;
728 : 0 : }
729 [ + + ]: 38 : else if (r != PKG_REINSTALL) {
730 : : /*
731 : : * Actually the selected package is newer than some other
732 : : * packages in the chain
733 : : */
734 : 34 : found = true;
735 : 34 : }
736 : 38 : }
737 : : else {
738 : 77 : res = cur;
739 : : }
740 : 115 : }
741 : :
742 [ + + ]: 83 : return (found ? res : NULL);
743 : : }
744 : :
745 : : static struct pkg_job_universe_item *
746 : 74 : pkg_jobs_universe_select_max_prio(struct pkg_job_universe_item *chain)
747 : : {
748 : : struct pkg_repo *repo;
749 : 74 : unsigned int max_pri = 0;
750 : 74 : struct pkg_job_universe_item *cur, *res = NULL;
751 : :
752 [ + + ]: 202 : LL_FOREACH(chain, cur) {
753 [ + + ]: 128 : if (cur->pkg->type == PKG_INSTALLED)
754 : 33 : continue;
755 : :
756 [ - + ]: 95 : if (cur->pkg->reponame) {
757 : 95 : repo = pkg_repo_find(cur->pkg->reponame);
758 [ + - + + ]: 95 : if (repo && repo->priority > max_pri) {
759 : 6 : res = cur;
760 : 6 : max_pri = repo->priority;
761 : 6 : }
762 : 95 : }
763 : 95 : }
764 : :
765 : 74 : return (res);
766 : : }
767 : :
768 : : static struct pkg_job_universe_item *
769 : 62 : pkg_jobs_universe_select_same_repo(struct pkg_job_universe_item *chain,
770 : : struct pkg_job_universe_item *local, const char *assumed_reponame)
771 : : {
772 : 62 : struct pkg_repo *local_repo = NULL, *repo;
773 : 62 : struct pkg_job_universe_item *cur, *res = NULL;
774 : :
775 [ + - ]: 62 : if (!local) {
776 : :
777 [ # # ]: 0 : if (assumed_reponame) {
778 : 0 : local_repo = pkg_repo_find(assumed_reponame);
779 : 0 : }
780 : 0 : }
781 : : else {
782 [ - + ]: 62 : if (local->pkg->reponame) {
783 : 0 : local_repo = pkg_repo_find(local->pkg->reponame);
784 : 0 : }
785 : : else {
786 : 62 : const char *lrepo = pkg_kv_get(&local->pkg->annotations, "repository");
787 [ + + ]: 62 : if (lrepo) {
788 : 26 : local_repo = pkg_repo_find(lrepo);
789 : 26 : }
790 : : }
791 : : }
792 : :
793 [ + + ]: 62 : if (local_repo == NULL) {
794 : 46 : return (NULL);
795 : : }
796 : : else {
797 [ + + ]: 32 : LL_FOREACH(chain, cur) {
798 [ + + ]: 31 : if (cur->pkg->type == PKG_INSTALLED)
799 : 16 : continue;
800 : :
801 [ - + ]: 15 : if (cur->pkg->reponame) {
802 : 15 : repo = pkg_repo_find(cur->pkg->reponame);
803 [ + - ]: 15 : if (repo == local_repo) {
804 : 15 : res = cur;
805 : 15 : break;
806 : : }
807 : 0 : }
808 : 0 : }
809 : : }
810 : :
811 : 16 : return (res);
812 : 62 : }
813 : :
814 : : struct pkg_job_universe_item *
815 : 104 : pkg_jobs_universe_select_candidate(struct pkg_job_universe_item *chain,
816 : : struct pkg_job_universe_item *local, bool conservative,
817 : : const char *reponame, bool pinning)
818 : : {
819 : 104 : struct pkg_job_universe_item *res = NULL;
820 : :
821 [ + + ]: 104 : if (local == NULL) {
822 : : /* New package selection */
823 [ + - ]: 41 : if (conservative) {
824 : : /* Check same repo */
825 [ - + # # ]: 41 : if (reponame && pinning) {
826 : 0 : res = pkg_jobs_universe_select_same_repo(chain, NULL, reponame);
827 : 0 : }
828 : :
829 [ - + ]: 41 : if (res == NULL) {
830 : : /* Priority -> version */
831 : 41 : res = pkg_jobs_universe_select_max_prio(chain);
832 [ + + ]: 41 : if (res == NULL) {
833 : 35 : res = pkg_jobs_universe_select_max_ver(chain);
834 : 35 : }
835 : 41 : }
836 : 41 : }
837 : : else {
838 [ # # # # ]: 0 : if (reponame && pinning) {
839 : 0 : res = pkg_jobs_universe_select_same_repo(chain, NULL, reponame);
840 : 0 : }
841 : :
842 [ # # ]: 0 : if (res == NULL) {
843 : : /* Version -> priority */
844 : 0 : res = pkg_jobs_universe_select_max_ver(chain);
845 [ # # ]: 0 : if (res == NULL) {
846 : 0 : res = pkg_jobs_universe_select_max_prio(chain);
847 : 0 : }
848 : 0 : }
849 : : }
850 : 41 : }
851 : : else {
852 [ + + ]: 63 : if (conservative) {
853 : : /* same -> prio -> version */
854 [ - + ]: 48 : if (pinning)
855 : 48 : res = pkg_jobs_universe_select_same_repo(chain, local, reponame);
856 [ + + ]: 48 : if (res == NULL) {
857 : 33 : res = pkg_jobs_universe_select_max_prio(chain);
858 : 33 : }
859 [ + + ]: 48 : if (res == NULL) {
860 : 33 : res = pkg_jobs_universe_select_max_ver(chain);
861 : 33 : }
862 : 48 : }
863 : : else {
864 : : /* same -> version -> prio */
865 [ + + ]: 15 : if (pinning)
866 : 14 : res = pkg_jobs_universe_select_same_repo(chain, local, reponame);
867 [ - + ]: 15 : if (res == NULL) {
868 : 15 : res = pkg_jobs_universe_select_max_ver(chain);
869 : 15 : }
870 [ + - ]: 15 : if (res == NULL) {
871 : 0 : res = pkg_jobs_universe_select_max_prio(chain);
872 : 0 : }
873 : : }
874 : : }
875 : :
876 : : /* Fallback to any */
877 [ + + ]: 104 : return (res != NULL ? res : chain);
878 : : }
879 : :
880 : : void
881 : 303 : pkg_jobs_universe_process_upgrade_chains(struct pkg_jobs *j)
882 : : {
883 : : struct pkg_job_universe_item *unit, *cur, *local;
884 : : struct pkg_job_request *req;
885 : : struct pkg_job_request_item *rit, *rtmp;
886 : : pkghash_it it;
887 : :
888 : 303 : it = pkghash_iterator(j->universe->items);
889 [ + + ]: 728 : while (pkghash_next(&it)) {
890 : 425 : unsigned vercnt = 0;
891 : 425 : unit = (struct pkg_job_universe_item *)it.value;
892 : :
893 : 425 : req = pkghash_get_value(j->request_add, unit->pkg->uid);
894 [ + + ]: 425 : if (req == NULL) {
895 : : /* Not obviously requested */
896 : 122 : continue;
897 : : }
898 : :
899 : 303 : local = NULL;
900 [ + + ]: 781 : LL_FOREACH(unit, cur) {
901 [ + + ]: 478 : if (cur->pkg->type == PKG_INSTALLED)
902 : 120 : local = cur;
903 : 478 : vercnt ++;
904 : 478 : }
905 : :
906 [ + + + - ]: 303 : if (local != NULL && local->pkg->locked) {
907 : 0 : dbg(1, "removing %s from the request as it is locked",
908 : : local->pkg->uid);
909 : 0 : pkghash_del(j->request_add, req->item->pkg->uid);
910 : 0 : pkg_jobs_request_free(req);
911 : 0 : continue;
912 : : }
913 : :
914 [ + + ]: 303 : if (vercnt <= 1)
915 : 173 : continue;
916 : :
917 : : /*
918 : : * Here we have more than one upgrade candidate,
919 : : * if local == NULL, then we have two remote repos,
920 : : * if local != NULL, then we have unspecified upgrade path
921 : : */
922 : :
923 [ + + - + : 130 : if ((local == NULL && vercnt > 1) || (vercnt > 2)) {
+ + ]
924 : : /* Select the most recent or one of packages */
925 : : struct pkg_job_universe_item *selected;
926 : :
927 : 110 : selected = pkg_jobs_universe_select_candidate(unit, local,
928 : 55 : j->conservative, NULL, j->pinning);
929 : : /*
930 : : * Now remove all requests but selected from the requested
931 : : * candidates
932 : : */
933 [ + - ]: 55 : assert(selected != NULL);
934 : 55 : pkghash_del(j->request_add, req->item->pkg->uid);
935 : :
936 : : /*
937 : : * We also check if the selected package has different digest,
938 : : * and if it has the same digest we proceed only if we have a
939 : : * forced job
940 : : */
941 [ + + + + : 55 : if (local != NULL && STREQ(local->pkg->digest, selected->pkg->digest) &&
+ + ]
942 : 5 : (j->flags & PKG_FLAG_FORCE) == 0) {
943 : 1 : dbg(1, "removing %s from the request as it is the "
944 : : "same as local", selected->pkg->uid);
945 : 1 : continue;
946 : : }
947 : :
948 [ + + ]: 206 : LL_FOREACH(unit, cur) {
949 [ + + ]: 152 : if (cur == selected)
950 : 54 : continue;
951 : :
952 [ + + - + : 361 : DL_FOREACH_SAFE(req->item, rit, rtmp) {
+ + ]
953 [ + + ]: 263 : if (rit->unit == cur) {
954 [ - + + - : 82 : DL_DELETE(req->item, rit);
+ + + + ]
955 : 41 : free(rit);
956 : 41 : }
957 : 263 : }
958 : 98 : }
959 [ + - ]: 54 : if (req->item == NULL) {
960 : 0 : rit = xcalloc(1, sizeof(*rit));
961 : 0 : rit->pkg = selected->pkg;
962 : 0 : rit->unit = selected;
963 [ # # ]: 0 : DL_APPEND(req->item, rit);
964 : 0 : }
965 [ + - - + ]: 108 : pkghash_safe_add(j->request_add, selected->pkg->uid, req, NULL);
966 : 54 : }
967 : : }
968 : 303 : }
969 : :
970 : : struct pkg_job_universe_item*
971 : 123 : pkg_jobs_universe_get_upgrade_candidates(struct pkg_jobs_universe *universe,
972 : : const char *uid, struct pkg *lp, bool force, const char *version)
973 : : {
974 : 123 : struct pkg *pkg = NULL, *selected = lp;
975 : : struct pkgdb_it *it;
976 : : struct pkg_job_universe_item *unit, *ucur;
977 : 123 : int flag = PKG_LOAD_BASIC|PKG_LOAD_DEPS|PKG_LOAD_OPTIONS|
978 : : PKG_LOAD_REQUIRES|PKG_LOAD_PROVIDES|
979 : : PKG_LOAD_SHLIBS_REQUIRED|PKG_LOAD_SHLIBS_PROVIDED|
980 : : PKG_LOAD_ANNOTATIONS|PKG_LOAD_CONFLICTS;
981 : 123 : tll(struct pkg *) candidates = tll_init();
982 : :
983 : 123 : unit = pkghash_get_value(universe->items, uid);
984 [ + + ]: 123 : if (unit != NULL) {
985 : : /*
986 : : * If a unit has been found, we have already found the potential
987 : : * upgrade chain for it
988 : : */
989 [ + + ]: 31 : if (force) {
990 : : /*
991 : : * We also need to ensure that a chain contains remote packages
992 : : * in case of forced upgrade
993 : : */
994 [ + + ]: 6 : DL_FOREACH(unit, ucur) {
995 [ + + ]: 5 : if (ucur->pkg->type != PKG_INSTALLED) {
996 : 2 : return (unit);
997 : : }
998 : 3 : }
999 : 1 : }
1000 : : else {
1001 : 28 : return (unit);
1002 : : }
1003 : 1 : }
1004 : :
1005 [ + - + - : 279 : if ((it = pkgdb_repo_query2(universe->j->db, uid, MATCH_INTERNAL,
+ - ]
1006 : 186 : universe->j->reponames)) == NULL)
1007 : 0 : return (NULL);
1008 : :
1009 [ + + ]: 214 : while (pkgdb_it_next(it, &pkg, flag) == EPKG_OK) {
1010 : :
1011 [ + + + + ]: 121 : if (version != NULL && strcmp(pkg->version, version) != 0)
1012 : 2 : continue;
1013 : :
1014 [ + + ]: 119 : if (force) {
1015 : : /* Just add everything */
1016 : 7 : selected = pkg;
1017 : 7 : }
1018 : : else {
1019 [ + + + + ]: 184 : if (selected == lp &&
1020 [ + + ]: 106 : (lp == NULL || pkg_jobs_need_upgrade(pkg, lp)))
1021 : 78 : selected = pkg;
1022 [ + + ]: 34 : else if (pkg_version_change_between(pkg, selected) == PKG_UPGRADE)
1023 : 1 : selected = pkg;
1024 : : }
1025 [ + + + + : 119 : tll_push_front(candidates, pkg);
+ - - + +
+ ]
1026 : 119 : pkg = NULL;
1027 : : }
1028 : :
1029 : 93 : pkgdb_it_free(it);
1030 : :
1031 [ + + ]: 93 : if (lp != NULL) {
1032 : : /* Add local package to the universe as well */
1033 : 58 : pkg_jobs_universe_add_pkg(universe, lp, false, NULL);
1034 : 58 : }
1035 [ + + ]: 93 : if (selected != lp) {
1036 : : /* We need to add the whole chain of upgrade candidates */
1037 [ + - + + : 190 : tll_foreach(candidates, cit) {
+ + ]
1038 : 107 : pkg_jobs_universe_add_pkg(universe, cit->item, force, NULL);
1039 : 107 : }
1040 : 83 : }
1041 : : else {
1042 [ + - + + : 22 : tll_free_and_free(candidates, pkg_free);
+ + ]
1043 : 10 : return (NULL);
1044 : : }
1045 : :
1046 : 83 : unit = pkghash_get_value(universe->items, uid);
1047 [ + - + + : 190 : tll_free(candidates);
+ + ]
1048 : :
1049 : 83 : return (unit);
1050 : 123 : }
|