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