Branch data Line data Source code
1 : : /*-
2 : : * Copyright (c) 2011-2016 Baptiste Daroussin <bapt@FreeBSD.org>
3 : : * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
4 : : * Copyright (c) 2011-2012 Marin Atanasov Nikolov <dnaeon@gmail.com>
5 : : * Copyright (c) 2013 Matthew Seaman <matthew@FreeBSD.org>
6 : : * Copyright (c) 2013-2016 Vsevolod Stakhov <vsevolod@FreeBSD.org>
7 : : * All rights reserved.
8 : : *
9 : : * Redistribution and use in source and binary forms, with or without
10 : : * modification, are permitted provided that the following conditions
11 : : * are met:
12 : : * 1. Redistributions of source code must retain the above copyright
13 : : * notice, this list of conditions and the following disclaimer
14 : : * in this position and unchanged.
15 : : * 2. Redistributions in binary form must reproduce the above copyright
16 : : * notice, this list of conditions and the following disclaimer in the
17 : : * documentation and/or other materials provided with the distribution.
18 : : *
19 : : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
20 : : * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 : : * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 : : * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
23 : : * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 : : * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 : : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 : : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 : : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 : : * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 : : */
30 : :
31 : : #ifdef HAVE_CONFIG_H
32 : : #include "pkg_config.h"
33 : : #endif
34 : :
35 : : #include <bsd_compat.h>
36 : :
37 : : #include <sys/param.h>
38 : : #include <sys/mount.h>
39 : : #include <sys/types.h>
40 : :
41 : : #include <archive.h>
42 : : #include <archive_entry.h>
43 : : #include <assert.h>
44 : : #include <errno.h>
45 : : #ifdef HAVE_LIBUTIL_H
46 : : #include <libutil.h>
47 : : #endif
48 : : #include <search.h>
49 : : #include <stdbool.h>
50 : : #include <stdlib.h>
51 : : #include <string.h>
52 : : #include <sys/wait.h>
53 : : #include <ctype.h>
54 : :
55 : : #ifdef HAVE_SYS_STATFS_H
56 : : #include <sys/statfs.h>
57 : : #endif
58 : : #if defined(HAVE_SYS_STATVFS_H)
59 : : #include <sys/statvfs.h>
60 : : #endif
61 : :
62 : : #include "pkg.h"
63 : : #include "private/event.h"
64 : : #include "private/pkg.h"
65 : : #include "private/pkgdb.h"
66 : : #include "private/pkg_jobs.h"
67 : : #include "kvec.h"
68 : :
69 : : extern struct pkg_ctx ctx;
70 : :
71 : : static int pkg_jobs_installed_local_pkg(struct pkg_jobs *j, struct pkg *pkg);
72 : : static int pkg_jobs_find_upgrade(struct pkg_jobs *j, const char *pattern, match_t m);
73 : : static int pkg_jobs_fetch(struct pkg_jobs *j);
74 : : static bool new_pkg_version(struct pkg_jobs *j);
75 : : static int pkg_jobs_check_conflicts(struct pkg_jobs *j);
76 : : struct pkg_jobs_locked {
77 : : int (*locked_pkg_cb)(struct pkg *, void *);
78 : : void *context;
79 : : };
80 : : static __thread struct pkg_jobs_locked *pkgs_job_lockedpkg;
81 : :
82 : : #define IS_DELETE(j) ((j)->type == PKG_JOBS_DEINSTALL || (j)->type == PKG_JOBS_AUTOREMOVE)
83 : :
84 : : int
85 : 611 : pkg_jobs_new(struct pkg_jobs **j, pkg_jobs_t t, struct pkgdb *db)
86 : : {
87 [ + - ]: 611 : assert(db != NULL);
88 : :
89 : 611 : *j = xcalloc(1, sizeof(struct pkg_jobs));
90 : :
91 : 611 : (*j)->universe = pkg_jobs_universe_new(*j);
92 : :
93 [ + - ]: 611 : if ((*j)->universe == NULL) {
94 : 0 : free(*j);
95 : 0 : return (EPKG_FATAL);
96 : : }
97 : :
98 : 611 : (*j)->db = db;
99 : 611 : (*j)->type = t;
100 : 611 : (*j)->solved = 0;
101 : 611 : (*j)->pinning = true;
102 : 611 : (*j)->flags = PKG_FLAG_NONE;
103 : 611 : (*j)->conservative = pkg_object_bool(pkg_config_get("CONSERVATIVE_UPGRADE"));
104 : :
105 : 611 : return (EPKG_OK);
106 : 611 : }
107 : :
108 : : void
109 : 611 : pkg_jobs_set_flags(struct pkg_jobs *j, pkg_flags flags)
110 : : {
111 : 611 : j->flags = flags;
112 : 611 : }
113 : :
114 : : int
115 : 13 : pkg_jobs_set_repository(struct pkg_jobs *j, const char *ident)
116 : : {
117 [ - + ]: 13 : if ((pkg_repo_find(ident)) == NULL) {
118 : 0 : pkg_emit_error("Unknown repository: %s", ident);
119 : 0 : return (EPKG_FATAL);
120 : : }
121 : :
122 : 13 : j->reponame = ident;
123 : :
124 : 13 : return (EPKG_OK);
125 : 13 : }
126 : :
127 : : int
128 : 0 : pkg_jobs_set_destdir(struct pkg_jobs *j, const char *dir)
129 : : {
130 [ # # ]: 0 : if (dir == NULL)
131 : 0 : return (EPKG_FATAL);
132 : :
133 : 0 : j->destdir = dir;
134 : :
135 : 0 : return (EPKG_OK);
136 : 0 : }
137 : :
138 : : const char*
139 : 521 : pkg_jobs_destdir(struct pkg_jobs *j)
140 : : {
141 : 521 : return (j->destdir);
142 : : }
143 : :
144 : : static void
145 : 482 : pkg_jobs_pattern_free(struct job_pattern *jp)
146 : : {
147 : 482 : free(jp->pattern);
148 : 482 : free(jp->path);
149 : 482 : free(jp);
150 : 482 : }
151 : :
152 : : void
153 : 635 : pkg_jobs_request_free(struct pkg_job_request *req)
154 : : {
155 : : struct pkg_job_request_item *it, *tmp;
156 : :
157 [ + - ]: 635 : if (req != NULL) {
158 [ + + + + ]: 1319 : DL_FOREACH_SAFE(req->item, it, tmp) {
159 : 684 : free(it);
160 : 684 : }
161 : :
162 : 635 : free(req);
163 : 635 : }
164 : 635 : }
165 : :
166 : : void
167 : 611 : pkg_jobs_free(struct pkg_jobs *j)
168 : : {
169 : : pkghash_it it;
170 : :
171 [ - + ]: 611 : if (j == NULL)
172 : 0 : return;
173 : :
174 : 611 : it = pkghash_iterator(j->request_add);
175 [ + + ]: 1097 : while (pkghash_next(&it))
176 : 486 : pkg_jobs_request_free(it.value);
177 : 611 : pkghash_destroy(j->request_add);
178 : 611 : j->request_add = NULL;
179 : :
180 : 611 : it = pkghash_iterator(j->request_delete);
181 [ + + ]: 760 : while (pkghash_next(&it))
182 : 149 : pkg_jobs_request_free(it.value);
183 : 611 : pkghash_destroy(j->request_delete);
184 : 611 : j->request_delete = NULL;
185 : :
186 : 611 : pkg_jobs_universe_free(j->universe);
187 [ + + + + : 1402 : LL_FREE(j->jobs, free);
+ - # # #
# # # ]
188 [ + + + + : 1093 : LL_FREE(j->patterns, pkg_jobs_pattern_free);
+ - # # #
# # # ]
189 : 611 : free(j);
190 : 611 : }
191 : :
192 : : static bool
193 : 371 : pkg_jobs_maybe_match_file(struct job_pattern *jp, const char *pattern)
194 : : {
195 : : const char *dot_pos;
196 : : char *pkg_path;
197 : :
198 [ + - ]: 371 : assert(jp != NULL);
199 [ - + ]: 371 : assert(pattern != NULL);
200 : :
201 : 371 : dot_pos = strrchr(pattern, '.');
202 [ + + ]: 371 : if (dot_pos != NULL) {
203 : : /*
204 : : * Compare suffix with .txz or .tbz
205 : : */
206 : 220 : dot_pos ++;
207 [ + + + - ]: 228 : if (strcmp(dot_pos, "pkg") == 0 ||
208 [ + - ]: 8 : strcmp(dot_pos, "tzst") == 0 ||
209 [ + - ]: 8 : strcmp(dot_pos, "txz") == 0 ||
210 [ + - ]: 8 : strcmp(dot_pos, "tbz") == 0 ||
211 [ + - ]: 8 : strcmp(dot_pos, "tgz") == 0 ||
212 : 8 : strcmp(dot_pos, "tar") == 0) {
213 [ + - ]: 212 : if ((pkg_path = realpath(pattern, NULL)) != NULL) {
214 : : /* Dot pos is one character after the dot */
215 : 212 : int len = dot_pos - pattern;
216 : :
217 : 212 : pkg_debug(1, "Jobs> Adding file: %s", pattern);
218 : 212 : jp->flags |= PKG_PATTERN_FLAG_FILE;
219 : 212 : jp->path = pkg_path;
220 : 212 : jp->pattern = xmalloc(len);
221 : 212 : strlcpy(jp->pattern, pattern, len);
222 : :
223 : 212 : return (true);
224 : : }
225 : 0 : }
226 : 8 : }
227 [ + - ]: 151 : else if (strcmp(pattern, "-") == 0) {
228 : : /*
229 : : * Read package from stdin
230 : : */
231 : 0 : jp->flags = PKG_PATTERN_FLAG_FILE;
232 : 0 : jp->path = xstrdup(pattern);
233 : 0 : jp->pattern = xstrdup(pattern);
234 : 0 : }
235 : :
236 : 159 : return (false);
237 : 371 : }
238 : :
239 : : int
240 : 474 : pkg_jobs_add(struct pkg_jobs *j, match_t match, char **argv, int argc)
241 : : {
242 : : struct job_pattern *jp;
243 : 474 : int i = 0;
244 : :
245 [ - + ]: 474 : if (j->solved) {
246 : 0 : pkg_emit_error("The job has already been solved. "
247 : : "Impossible to append new elements");
248 : 0 : return (EPKG_FATAL);
249 : : }
250 : :
251 [ + + ]: 952 : for (i = 0; i < argc; i++) {
252 : 478 : jp = xcalloc(1, sizeof(struct job_pattern));
253 [ + + + + ]: 478 : if (j->type == PKG_JOBS_DEINSTALL ||
254 : 371 : !pkg_jobs_maybe_match_file(jp, argv[i])) {
255 : 266 : jp->pattern = xstrdup(argv[i]);
256 : 266 : jp->match = match;
257 : 266 : }
258 [ + + - + ]: 478 : LL_APPEND(j->patterns, jp);
259 : 478 : }
260 : :
261 [ + + - + ]: 474 : if (argc == 0 && match == MATCH_ALL) {
262 : 4 : jp = xcalloc(1, sizeof(struct job_pattern));
263 : 4 : jp->pattern = NULL;
264 : 4 : jp->match = match;
265 [ + - # # ]: 4 : LL_APPEND(j->patterns, jp);
266 : 4 : }
267 : :
268 : 474 : return (EPKG_OK);
269 : 474 : }
270 : :
271 : : bool
272 : 826 : pkg_jobs_iter(struct pkg_jobs *jobs, void **iter,
273 : : struct pkg **new, struct pkg **old,
274 : : int *type)
275 : : {
276 : : struct pkg_solved *s;
277 [ + - ]: 826 : assert(iter != NULL);
278 [ + - ]: 826 : if (jobs->jobs == NULL) {
279 : 0 : return (false);
280 : : }
281 [ + + ]: 826 : if (*iter == NULL) {
282 : 305 : s = jobs->jobs;
283 : 305 : }
284 [ + + ]: 521 : else if (*iter == jobs->jobs) {
285 : 305 : return (false);
286 : : }
287 : : else {
288 : 216 : s = *iter;
289 : : }
290 : 521 : *new = s->items[0]->pkg;
291 [ + + ]: 521 : *old = s->items[1] ? s->items[1]->pkg : NULL;
292 : 521 : *type = s->type;
293 [ + + ]: 521 : *iter = s->next ? s->next : jobs->jobs;
294 : 521 : return (true);
295 : 826 : }
296 : :
297 : : static struct pkg_job_request_item*
298 : 381 : pkg_jobs_add_req_from_universe(pkghash **head, struct pkg_job_universe_item *un,
299 : : bool local, bool automatic)
300 : : {
301 : : struct pkg_job_request *req;
302 : : struct pkg_job_request_item *nit;
303 : : struct pkg_job_universe_item *uit;
304 : 381 : bool new_req = false;
305 : :
306 [ + - ]: 381 : assert(un != NULL);
307 : 381 : req = pkghash_get_value(*head, un->pkg->uid);
308 : :
309 [ + + ]: 381 : if (req == NULL) {
310 : 308 : req = xcalloc(1, sizeof(*req));
311 : 308 : new_req = true;
312 : 308 : req->automatic = automatic;
313 : 308 : pkg_debug(4, "add new uid %s to the request", un->pkg->uid);
314 : 308 : }
315 : : else {
316 [ + + ]: 73 : if (req->item->unit == un) {
317 : : /* We have exactly the same request, skip it */
318 : 20 : return (req->item);
319 : : }
320 : : }
321 : :
322 [ + + ]: 1081 : DL_FOREACH(un, uit) {
323 [ + + + + ]: 1177 : if ((uit->pkg->type == PKG_INSTALLED && local) ||
324 [ + + ]: 651 : (uit->pkg->type != PKG_INSTALLED && !local)) {
325 : 457 : nit = xcalloc(1, sizeof(*nit));
326 : 457 : nit->pkg = uit->pkg;
327 : 457 : nit->unit = uit;
328 [ + + ]: 457 : DL_APPEND(req->item, nit);
329 : 457 : }
330 : 1108 : }
331 : :
332 [ + + ]: 361 : if (new_req) {
333 [ + + ]: 308 : if (req->item != NULL) {
334 [ + + - + ]: 326 : pkghash_safe_add(*head, un->pkg->uid, req, NULL);
335 : 278 : }
336 : : else {
337 : 30 : free(req);
338 : 30 : return (NULL);
339 : : }
340 : 278 : }
341 : :
342 : 331 : return (req->item);
343 : 381 : }
344 : :
345 : : static struct pkg_job_request_item*
346 : 361 : pkg_jobs_add_req(struct pkg_jobs *j, struct pkg *pkg)
347 : : {
348 : : pkghash **head;
349 : : struct pkg_job_request *req;
350 : : struct pkg_job_request_item *nit;
351 : : struct pkg_job_universe_item *un;
352 : : int rc;
353 : :
354 [ + - ]: 361 : assert(pkg != NULL);
355 : :
356 [ + + + + ]: 361 : if (!IS_DELETE(j)) {
357 : 212 : head = &j->request_add;
358 [ - + ]: 212 : assert(pkg->type != PKG_INSTALLED);
359 : 212 : }
360 : : else {
361 : 149 : head = &j->request_delete;
362 [ + - ]: 149 : assert(pkg->type == PKG_INSTALLED);
363 : : }
364 : :
365 : 722 : pkg_debug(4, "universe: add package %s-%s to the request", pkg->name,
366 : 361 : pkg->version);
367 : 361 : rc = pkg_jobs_universe_add_pkg(j->universe, pkg, false, &un);
368 : :
369 [ - + ]: 361 : if (rc == EPKG_END) {
370 : : /*
371 : : * This means that we have a package in the universe with the same
372 : : * digest. In turn, that means that two upgrade candidates are equal,
373 : : * we thus won't do anything with this item, as it is definitely useless
374 : : */
375 : 0 : req = pkghash_get_value(*head, pkg->uid);
376 [ # # ]: 0 : if (req != NULL) {
377 [ # # ]: 0 : DL_FOREACH(req->item, nit) {
378 [ # # ]: 0 : if (nit->unit == un)
379 : 0 : return (nit);
380 : 0 : }
381 : 0 : }
382 : : else {
383 : : /*
384 : : * We need to add request chain from the universe chain
385 : : */
386 [ # # ]: 0 : return (pkg_jobs_add_req_from_universe(head, un, IS_DELETE(j), false));
387 : : }
388 : :
389 : 0 : return (NULL);
390 : : }
391 [ - + ]: 361 : else if (rc == EPKG_FATAL) {
392 : : /*
393 : : * Something bad has happened
394 : : */
395 : 0 : return (NULL);
396 : : }
397 : :
398 [ - + ]: 361 : if (pkg->locked) {
399 : 0 : pkg_emit_locked(pkg);
400 : 0 : return (NULL);
401 : : }
402 : :
403 : 361 : req = pkghash_get_value(*head, pkg->uid);
404 : :
405 : 361 : nit = xcalloc(1, sizeof(*nit));
406 : 361 : nit->pkg = pkg;
407 : 361 : nit->unit = un;
408 : :
409 [ - + ]: 361 : if (req == NULL) {
410 : : /* Allocate new unique request item */
411 : 361 : req = xcalloc(1, sizeof(*req));
412 [ + + - + ]: 373 : pkghash_safe_add(*head, pkg->uid, req, NULL);
413 : 361 : }
414 : :
415 : : /* Append candidate to the list of candidates */
416 [ - + ]: 361 : DL_APPEND(req->item, nit);
417 : :
418 : 361 : return (nit);
419 : 361 : }
420 : :
421 : : /*
422 : : * Post-process add request and handle flags:
423 : : * upgrade - search for upgrades for dependencies and add them to the request
424 : : * force - all upgrades are forced
425 : : * reverse - try to upgrade reverse deps as well
426 : : */
427 : : static void
428 : : pkg_jobs_process_add_request(struct pkg_jobs *j)
429 : : {
430 : : bool force = j->flags & PKG_FLAG_FORCE,
431 : : reverse = j->flags & PKG_FLAG_RECURSIVE,
432 : : upgrade = j->type == PKG_JOBS_UPGRADE;
433 : : struct pkg_job_request *req;
434 : : struct pkg_job_request_item *it;
435 : : struct pkg_job_universe_item *un, *cur;
436 : : struct pkg_dep *d;
437 : : struct pkg *lp;
438 : : int (*deps_func)(const struct pkg *pkg, struct pkg_dep **d);
439 : : kvec_t(struct pkg_job_universe_item *) to_process;
440 : : pkghash_it hit;
441 : :
442 : : if (!upgrade && !reverse)
443 : : return;
444 : :
445 : : kv_init(to_process);
446 : : hit = pkghash_iterator(j->request_add);
447 : : while (pkghash_next(&hit)) {
448 : : req = hit.value;
449 : : it = req->item;
450 : :
451 : : if (reverse)
452 : : deps_func = pkg_rdeps;
453 : : else
454 : : deps_func = pkg_deps;
455 : :
456 : : d = NULL;
457 : : /*
458 : : * Here we get deps of local packages only since we are pretty sure
459 : : * that they are completely expanded
460 : : */
461 : : lp = pkg_jobs_universe_get_local(j->universe,
462 : : it->pkg->uid, 0);
463 : : while (lp != NULL && deps_func(lp, &d) == EPKG_OK) {
464 : : /*
465 : : * Do not add duplicated upgrade candidates
466 : : */
467 : : if (pkghash_get(j->request_add, d->uid))
468 : : continue;
469 : :
470 : : pkg_debug(4, "adding dependency %s to request", d->uid);
471 : : lp = pkg_jobs_universe_get_local(j->universe,
472 : : d->uid, 0);
473 : : /*
474 : : * Here we need to check whether specific remote package
475 : : * is newer than a local one
476 : : */
477 : : un = pkg_jobs_universe_get_upgrade_candidates(j->universe,
478 : : d->uid, lp, force, NULL);
479 : : if (un == NULL)
480 : : continue;
481 : :
482 : : cur = un->prev;
483 : : while (cur != un) {
484 : : if (cur->pkg->type != PKG_INSTALLED) {
485 : : kv_push(typeof(un), to_process, un);
486 : : break;
487 : : }
488 : : cur = cur->prev;
489 : : }
490 : : }
491 : : }
492 : :
493 : : /* Add all items to the request */
494 : : for (int i = 0; i < kv_size(to_process); i++) {
495 : : un = kv_A(to_process, i);
496 : : pkg_jobs_add_req_from_universe(&j->request_add, un, false, true);
497 : : }
498 : : /* Now recursively process all items checked */
499 : : if (kv_size(to_process) > 0)
500 : : pkg_jobs_process_add_request(j);
501 : :
502 : : kv_destroy(to_process);
503 : : }
504 : :
505 : : /*
506 : : * For delete request we merely check rdeps and force flag
507 : : */
508 : : static int
509 : 141 : pkg_jobs_process_delete_request(struct pkg_jobs *j)
510 : : {
511 : 141 : bool force = j->flags & PKG_FLAG_FORCE;
512 : : struct pkg_job_request *req;
513 : 141 : struct pkg_dep *d = NULL;
514 : : struct pkg *lp;
515 : 141 : int rc = EPKG_OK;
516 : : kvec_t(struct pkg *) to_process;
517 : : pkghash_it it;
518 : :
519 [ + + ]: 141 : if (force)
520 : 46 : return (EPKG_OK);
521 : :
522 : 95 : kv_init(to_process);
523 : : /*
524 : : * Need to add also all reverse deps here
525 : : */
526 : 95 : it = pkghash_iterator(j->request_delete);
527 [ + + ]: 194 : while (pkghash_next(&it)) {
528 : 99 : req = it.value;
529 : 99 : d = NULL;
530 [ - + ]: 99 : while (pkg_rdeps(req->item->pkg, &d) == EPKG_OK) {
531 [ # # ]: 0 : if (pkghash_get(j->request_delete, d->uid))
532 : 0 : continue;
533 : :
534 : 0 : lp = pkg_jobs_universe_get_local(j->universe, d->uid, 0);
535 [ # # ]: 0 : if (lp) {
536 [ # # ]: 0 : if (lp->locked) {
537 : 0 : pkg_emit_error("%s is locked, "
538 : 0 : "cannot delete %s", lp->name,
539 : 0 : req->item->pkg->name);
540 : 0 : rc = EPKG_FATAL;
541 : 0 : }
542 [ # # # # ]: 0 : kv_push(typeof(lp), to_process, lp);
543 : 0 : }
544 : : }
545 : : }
546 : :
547 [ - + ]: 95 : if (rc == EPKG_FATAL)
548 : 0 : return (rc);
549 : :
550 [ - + ]: 95 : for (int i = 0; i < kv_size(to_process); i++) {
551 : 0 : lp = kv_A(to_process, i);
552 [ # # ]: 0 : if (pkg_jobs_add_req(j, lp) == NULL) {
553 : 0 : kv_destroy(to_process);
554 : 0 : return (EPKG_FATAL);
555 : : }
556 : 0 : }
557 [ + - ]: 95 : if (kv_size(to_process) > 0)
558 : 0 : rc = pkg_jobs_process_delete_request(j);
559 : 95 : kv_destroy(to_process);
560 : :
561 : 95 : return (rc);
562 : 141 : }
563 : :
564 : : static int
565 : 738 : pkg_jobs_set_execute_priority(struct pkg_jobs *j, struct pkg_solved *solved)
566 : : {
567 : : struct pkg_solved *ts;
568 : :
569 [ + + + + ]: 738 : if (solved->type == PKG_SOLVED_UPGRADE && solved->items[1]->pkg->conflicts != NULL) {
570 : : /*
571 : : * We have an upgrade request that has some conflicting packages, therefore
572 : : * update priorities of local packages and try to update priorities of remote ones
573 : : */
574 [ - + ]: 8 : if (solved->items[0]->priority == 0)
575 : 8 : pkg_jobs_update_conflict_priority(j->universe, solved);
576 : :
577 [ + - ]: 8 : if (solved->items[1]->priority > solved->items[0]->priority) {
578 : : /*
579 : : * Split conflicting upgrade request into delete -> upgrade request
580 : : */
581 : 8 : ts = xcalloc(1, sizeof(struct pkg_solved));
582 : 8 : ts->type = PKG_SOLVED_UPGRADE_REMOVE;
583 : 8 : ts->items[0] = solved->items[1];
584 : 8 : solved->items[1] = NULL;
585 : 8 : solved->type = PKG_SOLVED_UPGRADE_INSTALL;
586 [ + - ]: 8 : DL_APPEND(j->jobs, ts);
587 : 8 : j->count++;
588 : 8 : pkg_debug(2, "split upgrade request for %s",
589 : 8 : ts->items[0]->pkg->uid);
590 : 8 : return (EPKG_CONFLICT);
591 : : }
592 : 0 : }
593 [ + + ]: 730 : else if (solved->type == PKG_SOLVED_DELETE) {
594 [ + + ]: 176 : if (solved->items[0]->priority == 0)
595 : 160 : pkg_jobs_update_universe_priority(j->universe, solved->items[0],
596 : : PKG_PRIORITY_UPDATE_DELETE);
597 : 176 : }
598 [ + + ]: 554 : else if (solved->items[0]->priority == 0) {
599 : 482 : pkg_jobs_update_universe_priority(j->universe, solved->items[0],
600 : : PKG_PRIORITY_UPDATE_REQUEST);
601 : 482 : }
602 : :
603 : 730 : return (EPKG_OK);
604 : 738 : }
605 : :
606 : : static bool
607 : 160 : pkg_jobs_is_delete(struct pkg_solved *req)
608 : : {
609 [ + + ]: 160 : return (req->type == PKG_SOLVED_DELETE ||
610 : 48 : req->type == PKG_SOLVED_UPGRADE_REMOVE);
611 : : }
612 : :
613 : : static int
614 : 264 : pkg_jobs_sort_priority(struct pkg_solved *r1, struct pkg_solved *r2)
615 : : {
616 [ + + ]: 264 : if (r1->items[0]->priority == r2->items[0]->priority) {
617 [ + + + - ]: 52 : if (pkg_jobs_is_delete(r1) && !pkg_jobs_is_delete(r2))
618 : 0 : return (-1);
619 [ + + - + ]: 52 : if (pkg_jobs_is_delete(r2) && !pkg_jobs_is_delete(r1))
620 : 0 : return (1);
621 : :
622 : 52 : return (0);
623 : : }
624 : 212 : return (r2->items[0]->priority - r1->items[0]->priority);
625 : 264 : }
626 : :
627 : : static void
628 : 542 : pkg_jobs_set_priorities(struct pkg_jobs *j)
629 : : {
630 : 542 : struct pkg_solved *req;
631 : :
632 : : iter_again:
633 [ + + ]: 1292 : LL_FOREACH(j->jobs, req) {
634 : 742 : req->items[0]->priority = 0;
635 [ + + ]: 742 : if (req->items[1] != NULL)
636 : 144 : req->items[1]->priority = 0;
637 : 742 : }
638 [ + + ]: 1280 : LL_FOREACH(j->jobs, req) {
639 [ + + ]: 738 : if (pkg_jobs_set_execute_priority(j, req) == EPKG_CONFLICT)
640 : 8 : goto iter_again;
641 : 730 : }
642 : :
643 [ + - + + : 3084 : DL_SORT(j->jobs, pkg_jobs_sort_priority);
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + ]
644 : 542 : }
645 : :
646 : :
647 : : /**
648 : : * Test whether package specified is automatic with all its rdeps
649 : : * @param j
650 : : * @param p
651 : : * @return
652 : : */
653 : : static bool
654 : 34 : pkg_jobs_test_automatic(struct pkg_jobs *j, struct pkg *p)
655 : : {
656 : 34 : struct pkg_dep *d = NULL;
657 : : struct pkg_job_universe_item *unit;
658 : : struct pkg *npkg;
659 : 34 : bool ret = true;
660 : :
661 [ + - - + ]: 34 : while (pkg_rdeps(p, &d) == EPKG_OK && ret) {
662 : 0 : unit = pkg_jobs_universe_find(j->universe, d->uid);
663 [ # # ]: 0 : if (unit != NULL) {
664 [ # # ]: 0 : if (!unit->pkg->automatic) {
665 : 0 : return (false);
666 : : }
667 : 0 : npkg = unit->pkg;
668 : 0 : }
669 : : else {
670 : 0 : npkg = pkg_jobs_universe_get_local(j->universe, d->uid,
671 : : PKG_LOAD_BASIC|PKG_LOAD_RDEPS|PKG_LOAD_ANNOTATIONS);
672 [ # # ]: 0 : if (npkg == NULL)
673 : 0 : return (false);
674 [ # # ]: 0 : if (!npkg->automatic) {
675 : : /*
676 : : * Safe to free, as d->uid is not in the universe
677 : : */
678 : 0 : pkg_free(npkg);
679 : 0 : return (false);
680 : : }
681 [ # # ]: 0 : if (pkg_jobs_universe_process(j->universe, npkg) != EPKG_OK)
682 : 0 : return (false);
683 : : }
684 : :
685 : 0 : ret = pkg_jobs_test_automatic(j, npkg);
686 : : }
687 : :
688 : 34 : return (ret);
689 : 34 : }
690 : :
691 : :
692 : :
693 : : static bool
694 : 478 : new_pkg_version(struct pkg_jobs *j)
695 : : {
696 : : struct pkg *p;
697 : 478 : const char *uid = "pkg";
698 : : pkg_flags old_flags;
699 : 478 : bool ret = false;
700 : : struct pkg_job_universe_item *nit, *cit;
701 : :
702 : : /* Disable -f for pkg self-check, and restore at end. */
703 : 478 : old_flags = j->flags;
704 : 478 : j->flags &= ~(PKG_FLAG_FORCE|PKG_FLAG_RECURSIVE);
705 : :
706 : : /* determine local pkgng */
707 : 478 : p = pkg_jobs_universe_get_local(j->universe, uid, 0);
708 : :
709 [ + + ]: 478 : if (p == NULL) {
710 : 442 : uid = "pkg-devel";
711 : 442 : p = pkg_jobs_universe_get_local(j->universe, uid, 0);
712 : 442 : }
713 : :
714 : : /* you are using git version skip */
715 [ + + ]: 478 : if (p == NULL) {
716 : 442 : ret = false;
717 : 442 : goto end;
718 : : }
719 : :
720 : : /* Use maximum priority for pkg */
721 [ + + ]: 49 : if (pkg_jobs_find_upgrade(j, uid, MATCH_EXACT) == EPKG_OK) {
722 : : /*
723 : : * Now we can have *potential* upgrades, but we can have a situation,
724 : : * when our upgrade candidate comes from another repo
725 : : */
726 : 13 : nit = pkg_jobs_universe_find(j->universe, uid);
727 : :
728 [ - + ]: 13 : if (nit) {
729 [ - + ]: 26 : DL_FOREACH(nit, cit) {
730 [ + + ]: 26 : if (pkg_version_change_between (cit->pkg, p) == PKG_UPGRADE) {
731 : : /* We really have newer version which is not installed */
732 : 13 : ret = true;
733 : 13 : break;
734 : : }
735 : 13 : }
736 : 13 : }
737 : 13 : }
738 : :
739 : : end:
740 : 478 : j->flags = old_flags;
741 : :
742 : 478 : return (ret);
743 : : }
744 : :
745 : : static int
746 : 424 : pkg_jobs_process_remote_pkg(struct pkg_jobs *j, struct pkg *rp,
747 : : struct pkg_job_request_item **req, int with_version)
748 : : {
749 : : struct pkg_job_universe_item *nit, *cur;
750 : 424 : struct pkg_job_request_item *nrit = NULL;
751 : 424 : struct pkg *lp = NULL;
752 : 424 : struct pkg_dep *rdep = NULL;
753 : :
754 [ + - ]: 424 : if (rp->digest == NULL) {
755 [ # # ]: 0 : if (pkg_checksum_calculate(rp, j->db, false, true, false) != EPKG_OK) {
756 : 0 : return (EPKG_FATAL);
757 : : }
758 : 0 : }
759 [ + + ]: 424 : if (j->type != PKG_JOBS_FETCH) {
760 : 420 : lp = pkg_jobs_universe_get_local(j->universe, rp->uid, 0);
761 [ + + + - ]: 420 : if (lp && lp->locked)
762 : 0 : return (EPKG_LOCKED);
763 : 420 : }
764 : :
765 : 848 : nit = pkg_jobs_universe_get_upgrade_candidates(j->universe, rp->uid, lp,
766 : 424 : j->flags & PKG_FLAG_FORCE,
767 [ + + ]: 424 : with_version != 0 ? rp->version : NULL);
768 : :
769 [ + + ]: 424 : if (nit != NULL) {
770 : 381 : nrit = pkg_jobs_add_req_from_universe(&j->request_add, nit, false, false);
771 : :
772 [ + - ]: 381 : if (req != NULL)
773 : 0 : *req = nrit;
774 : :
775 [ + - ]: 381 : if (j->flags & PKG_FLAG_UPGRADE_VULNERABLE) {
776 : : /* Set the proper reason */
777 [ # # ]: 0 : DL_FOREACH(nit, cur) {
778 [ # # ]: 0 : if (cur->pkg->type != PKG_INSTALLED) {
779 : 0 : free(cur->pkg->reason);
780 : 0 : xasprintf(&cur->pkg->reason, "vulnerability found");
781 : 0 : }
782 : 0 : }
783 : : /* Also process all rdeps recursively */
784 [ # # ]: 0 : while (pkg_rdeps(nrit->pkg, &rdep) == EPKG_OK) {
785 : 0 : lp = pkg_jobs_universe_get_local(j->universe, rdep->uid, 0);
786 : :
787 [ # # ]: 0 : if (lp) {
788 : 0 : (void)pkg_jobs_process_remote_pkg(j, lp, NULL, 0);
789 : 0 : }
790 : : }
791 : 0 : }
792 : 381 : }
793 : :
794 [ + + - + ]: 424 : if (nrit == NULL && lp)
795 : 73 : return (EPKG_INSTALLED);
796 : :
797 : 351 : return (nrit != NULL ? EPKG_OK : EPKG_FATAL);
798 : 424 : }
799 : :
800 : : static bool
801 : 0 : pkg_jobs_has_replacement(struct pkg_jobs *j, const char *uid)
802 : : {
803 : : struct pkg_job_replace *cur;
804 : :
805 [ # # ]: 0 : LL_FOREACH(j->universe->uid_replaces, cur) {
806 [ # # ]: 0 : if (strcmp (cur->new_uid, uid) == 0) {
807 : 0 : return (true);
808 : : }
809 : 0 : }
810 : :
811 : 0 : return (false);
812 : 0 : }
813 : :
814 : : static int
815 : 0 : pkg_jobs_try_remote_candidate(struct pkg_jobs *j, const char *cond, const char *pattern,
816 : : const char *uid, match_t m)
817 : : {
818 : 0 : struct pkg *p = NULL;
819 : : struct pkgdb_it *it;
820 : 0 : unsigned flags = PKG_LOAD_BASIC|PKG_LOAD_OPTIONS|PKG_LOAD_DEPS|
821 : : PKG_LOAD_REQUIRES|PKG_LOAD_PROVIDES|
822 : : PKG_LOAD_SHLIBS_REQUIRED|PKG_LOAD_SHLIBS_PROVIDED|
823 : : PKG_LOAD_ANNOTATIONS|PKG_LOAD_CONFLICTS;
824 : 0 : int rc = EPKG_FATAL;
825 : 0 : xstring *qmsg = NULL;
826 : : struct pkg_job_universe_item *unit;
827 : :
828 [ # # ]: 0 : if ((it = pkgdb_repo_query_cond(j->db, cond, pattern, m, j->reponame)) == NULL)
829 : 0 : return (EPKG_FATAL);
830 : :
831 [ # # # # ]: 0 : while (it != NULL && pkgdb_it_next(it, &p, flags) == EPKG_OK) {
832 [ # # ]: 0 : xstring_renew(qmsg);
833 [ # # ]: 0 : if (pkg_jobs_has_replacement(j, p->uid)) {
834 : 0 : pkg_debug(1, "replacement %s is already used", p->uid);
835 : 0 : continue;
836 : : }
837 : :
838 : 0 : fprintf(qmsg->fp, "%s has no direct installation candidates, change it to "
839 : 0 : "%s? ", uid, p->uid);
840 : 0 : fflush(qmsg->fp);
841 [ # # ]: 0 : if (pkg_emit_query_yesno(true, qmsg->buf)) {
842 : : /* Change the origin of the local package */
843 : 0 : pkg_validate(p, j->db);
844 : 0 : unit = pkg_jobs_universe_find(j->universe, uid);
845 [ # # ]: 0 : if (unit != NULL)
846 : 0 : pkg_jobs_universe_change_uid(j->universe, unit,
847 : 0 : p->uid, false);
848 : : else
849 : 0 : assert(0);
850 : :
851 : 0 : rc = EPKG_OK;
852 : 0 : pkg_jobs_process_remote_pkg(j, p, NULL, 0);
853 [ # # ]: 0 : if (rc == EPKG_OK) {
854 : : /* Avoid freeing */
855 : 0 : p = NULL;
856 : 0 : }
857 : 0 : break;
858 : : }
859 : : }
860 : :
861 : :
862 : 0 : pkg_free(p);
863 : :
864 : 0 : xstring_free(qmsg);
865 : 0 : pkgdb_it_free(it);
866 : :
867 : 0 : return (rc);
868 : 0 : }
869 : :
870 : : static int
871 : 0 : pkg_jobs_guess_upgrade_candidate(struct pkg_jobs *j, const char *pattern)
872 : : {
873 : :
874 : 0 : int rc = EPKG_FATAL;
875 : 0 : const char *pos, *opattern = pattern;
876 : : char *cpy;
877 : : size_t len, olen;
878 : :
879 : : /* First of all, try to search a package with the same name */
880 : 0 : pos = strchr(pattern, '/');
881 [ # # # # ]: 0 : if (pos != NULL && pos[1] != '\0') {
882 [ # # # # ]: 0 : if (pkg_jobs_try_remote_candidate(j, pos + 1, NULL, opattern, MATCH_EXACT)
883 : 0 : == EPKG_OK)
884 : 0 : return (EPKG_OK);
885 : :
886 : 0 : pos ++;
887 : 0 : } else {
888 : 0 : pos = pattern;
889 : : }
890 : :
891 : : /* Figure, if we have any numbers at the end of the package */
892 : 0 : olen = strlen(pos);
893 : 0 : len = olen;
894 [ # # ]: 0 : while (len > 0) {
895 [ # # # # ]: 0 : if (isdigit(pos[len - 1]) || pos[len - 1] == '.')
896 : 0 : len --;
897 : : else
898 : 0 : break;
899 : : }
900 : :
901 [ # # ]: 0 : if (olen != len) {
902 : : /* Try exact pattern without numbers */
903 : 0 : cpy = xmalloc(len + 1);
904 : 0 : strlcpy(cpy, pos, len + 1);
905 [ # # ]: 0 : if (pkg_jobs_try_remote_candidate(j, cpy, NULL, opattern, MATCH_EXACT) != EPKG_OK) {
906 : 0 : free(cpy);
907 : 0 : cpy = sqlite3_mprintf(" WHERE name REGEXP ('^' || %.*Q || '[0-9.]*$')",
908 : 0 : len, pos);
909 : :
910 [ # # # # ]: 0 : if (pkg_jobs_try_remote_candidate(j, cpy, opattern, NULL, MATCH_ALL)
911 : 0 : == EPKG_OK)
912 : 0 : rc = EPKG_OK;
913 : 0 : sqlite3_free(cpy);
914 : 0 : }
915 : : else {
916 : 0 : free(cpy);
917 : 0 : rc = EPKG_OK;
918 : : }
919 : 0 : }
920 : :
921 : 0 : return (rc);
922 : 0 : }
923 : :
924 : : static int
925 : 335 : pkg_jobs_find_upgrade(struct pkg_jobs *j, const char *pattern, match_t m)
926 : : {
927 : 335 : struct pkg *p = NULL;
928 : : struct pkgdb_it *it;
929 : 335 : bool checklocal, found = false;
930 : 335 : int rc = EPKG_FATAL;
931 : : int with_version;
932 : 335 : struct pkg_dep *rdep = NULL;
933 : 335 : unsigned flags = PKG_LOAD_BASIC|PKG_LOAD_OPTIONS|PKG_LOAD_DEPS|
934 : : PKG_LOAD_REQUIRES|PKG_LOAD_PROVIDES|
935 : : PKG_LOAD_SHLIBS_REQUIRED|PKG_LOAD_SHLIBS_PROVIDED|
936 : : PKG_LOAD_ANNOTATIONS|PKG_LOAD_CONFLICTS;
937 : 335 : struct pkg_job_universe_item *unit = NULL;
938 : :
939 [ + - ]: 335 : if ((it = pkgdb_repo_query(j->db, pattern, m, j->reponame)) == NULL)
940 : 0 : rc = EPKG_FATAL;
941 : :
942 : : /*
943 : : * MATCH_EXACT is handled at a higher level, so that we can complain if a
944 : : * specific upgrade was requested without the package being locally installed.
945 : : *
946 : : * MATCH_ALL is a non-issue, because we will not get that from pkg-upgrade
947 : : * anyways.
948 : :
949 : : * Pattern matches are the main target, as the above query may grab packages
950 : : * that are not installed that we can ignore.
951 : : */
952 [ + + + + ]: 335 : checklocal = j->type == PKG_JOBS_UPGRADE && m != MATCH_EXACT && m != MATCH_ALL;
953 [ - + + + ]: 775 : while (it != NULL && pkgdb_it_next(it, &p, flags) == EPKG_OK) {
954 [ + + + + ]: 440 : if (checklocal && pkg_jobs_installed_local_pkg(j, p) != EPKG_OK)
955 : 16 : continue;
956 [ + - ]: 424 : if (pattern != NULL) {
957 : 424 : with_version = strcmp(p->name, pattern);
958 : 424 : } else {
959 : 0 : with_version = 0;
960 : : }
961 : 424 : rc = pkg_jobs_process_remote_pkg(j, p, NULL, with_version);
962 [ + - ]: 424 : if (rc == EPKG_FATAL)
963 : 0 : break;
964 [ + + ]: 424 : else if (rc == EPKG_OK)
965 : 351 : found = true;
966 : :
967 : 424 : p = NULL;
968 : : }
969 : :
970 : 335 : pkgdb_it_free(it);
971 : :
972 [ + + + + ]: 335 : if (!found && rc != EPKG_INSTALLED) {
973 : : /*
974 : : * Here we need to ensure that this package has no
975 : : * reverse deps installed
976 : : */
977 : 4 : p = pkg_jobs_universe_get_local(j->universe, pattern,
978 : : PKG_LOAD_BASIC|PKG_LOAD_RDEPS);
979 [ - + ]: 4 : if (p == NULL)
980 : 4 : return (EPKG_FATAL);
981 : :
982 [ # # ]: 0 : while(pkg_rdeps(p, &rdep) == EPKG_OK) {
983 : : struct pkg *rdep_package;
984 : :
985 : 0 : rdep_package = pkg_jobs_universe_get_local(j->universe, rdep->uid,
986 : : PKG_LOAD_BASIC);
987 [ # # ]: 0 : if (rdep_package != NULL)
988 : 0 : return (EPKG_END);
989 : : }
990 : :
991 : 0 : pkg_debug(2, "non-automatic package with pattern %s has not been found in "
992 : 0 : "remote repo", pattern);
993 : 0 : rc = pkg_jobs_universe_add_pkg(j->universe, p, false, &unit);
994 [ # # ]: 0 : if (rc == EPKG_OK) {
995 : 0 : rc = pkg_jobs_guess_upgrade_candidate(j, pattern);
996 : 0 : }
997 : 0 : }
998 : :
999 : 331 : return (rc);
1000 : 335 : }
1001 : :
1002 : : static int
1003 : 56 : pkg_jobs_check_local_pkg(struct pkg_jobs *j, struct job_pattern *jp)
1004 : : {
1005 : : struct pkgdb_it *it;
1006 : 56 : struct pkg *pkg = NULL;
1007 : 56 : int rc = EPKG_OK;
1008 : :
1009 : 56 : it = pkgdb_query(j->db, jp->pattern, jp->match);
1010 [ + - ]: 56 : if (it != NULL) {
1011 [ + + ]: 56 : if (pkgdb_it_next(it, &pkg, PKG_LOAD_BASIC|PKG_LOAD_ANNOTATIONS) != EPKG_OK)
1012 : 16 : rc = EPKG_FATAL;
1013 : : else
1014 : 40 : pkg_free(pkg);
1015 : :
1016 : 56 : pkgdb_it_free(it);
1017 : 56 : }
1018 : : else {
1019 : 0 : rc = EPKG_FATAL;
1020 : : }
1021 : :
1022 : 56 : return (rc);
1023 : : }
1024 : :
1025 : : static int
1026 : 28 : pkg_jobs_installed_local_pkg(struct pkg_jobs *j, struct pkg *pkg)
1027 : : {
1028 : : struct job_pattern jfp;
1029 : :
1030 : 28 : jfp.match = MATCH_EXACT;
1031 : 28 : jfp.pattern = pkg->name;
1032 : 28 : return (pkg_jobs_check_local_pkg(j, &jfp));
1033 : : }
1034 : :
1035 : : static int
1036 : 363 : pkg_jobs_find_remote_pattern(struct pkg_jobs *j, struct job_pattern *jp)
1037 : : {
1038 : 363 : int rc = EPKG_OK;
1039 : 363 : struct pkg *pkg = NULL;
1040 : 363 : struct pkg_manifest_key *keys = NULL;
1041 : : struct pkg_job_request *req;
1042 : :
1043 [ + + ]: 363 : if (!(jp->flags & PKG_PATTERN_FLAG_FILE)) {
1044 [ + + + + ]: 151 : if (j->type == PKG_JOBS_UPGRADE && jp->match == MATCH_EXACT) {
1045 : : /*
1046 : : * For upgrade patterns we must ensure that a local package is
1047 : : * installed as well. This only works if we're operating on an
1048 : : * exact match, as we otherwise don't know exactly what packages
1049 : : * are in store for us.
1050 : : */
1051 [ + - ]: 28 : if (pkg_jobs_check_local_pkg(j, jp) != EPKG_OK) {
1052 : 0 : pkg_emit_error("%s is not installed, therefore upgrade is impossible",
1053 : 0 : jp->pattern);
1054 : 0 : return (EPKG_NOTINSTALLED);
1055 : : }
1056 : 28 : }
1057 : 151 : rc = pkg_jobs_find_upgrade(j, jp->pattern, jp->match);
1058 : 151 : }
1059 : : else {
1060 : 212 : pkg_manifest_keys_new(&keys);
1061 [ - + ]: 212 : if (pkg_open(&pkg, jp->path, keys, PKG_OPEN_MANIFEST_ONLY) != EPKG_OK) {
1062 : 0 : rc = EPKG_FATAL;
1063 [ - + ]: 212 : } else if (pkg_validate(pkg, j->db) == EPKG_OK) {
1064 [ - + # # ]: 212 : if (j->type == PKG_JOBS_UPGRADE && pkg_jobs_installed_local_pkg(j, pkg) != EPKG_OK) {
1065 : 0 : pkg_emit_error("%s is not installed, therefore upgrade is impossible",
1066 : 0 : pkg->name);
1067 : 0 : pkg_manifest_keys_free(keys);
1068 : 0 : return (EPKG_NOTINSTALLED);
1069 : : }
1070 : 212 : pkg->type = PKG_FILE;
1071 : 212 : pkg_jobs_add_req(j, pkg);
1072 : :
1073 : 212 : req = pkghash_get_value(j->request_add, pkg->uid);
1074 [ - + ]: 212 : if (req != NULL)
1075 : 212 : req->item->jp = jp;
1076 : 212 : }
1077 : : else {
1078 : 0 : pkg_emit_error("cannot load %s: invalid format",
1079 : 0 : jp->pattern);
1080 : 0 : rc = EPKG_FATAL;
1081 : : }
1082 : 212 : pkg_manifest_keys_free(keys);
1083 : : }
1084 : :
1085 : 363 : return (rc);
1086 : 363 : }
1087 : :
1088 : : bool
1089 : 301 : pkg_jobs_need_upgrade(struct pkg *rp, struct pkg *lp)
1090 : : {
1091 : : int ret, ret1, ret2;
1092 : 301 : struct pkg_option *lo = NULL, *ro = NULL;
1093 : 301 : struct pkg_dep *ld = NULL, *rd = NULL;
1094 : 301 : struct pkg_conflict *lc = NULL, *rc = NULL;
1095 : : pkghash_it it1, it2;
1096 : :
1097 : : /* If no local package, then rp is obviously need to be added */
1098 [ + - ]: 301 : if (lp == NULL)
1099 : 0 : return true;
1100 : :
1101 : : /* Do not upgrade locked packages */
1102 [ - + ]: 301 : if (lp->locked) {
1103 : 0 : pkg_emit_locked(lp);
1104 : 0 : return (false);
1105 : : }
1106 : :
1107 [ + - + - : 301 : if (lp->digest != NULL && rp->digest != NULL &&
+ + ]
1108 : 301 : strcmp(lp->digest, rp->digest) == 0) {
1109 : : /* Remote and local packages has the same digest, hence they are the same */
1110 : 80 : return (false);
1111 : : }
1112 : : /*
1113 : : * XXX: for a remote package we also need to check whether options
1114 : : * are compatible.
1115 : : */
1116 : 221 : ret = pkg_version_cmp(lp->version, rp->version);
1117 [ + + ]: 221 : if (ret > 0)
1118 : 10 : return (false);
1119 [ + + ]: 211 : else if (ret < 0)
1120 : 135 : return (true);
1121 : :
1122 : : /* Compare archs */
1123 [ - + ]: 76 : if (strcmp (lp->arch, rp->arch) != 0) {
1124 : 0 : free(rp->reason);
1125 : 0 : xasprintf(&rp->reason, "ABI changed: '%s' -> '%s'",
1126 : 0 : lp->arch, rp->arch);
1127 [ # # ]: 0 : assert(rp->reason != NULL);
1128 : 0 : return (true);
1129 : : }
1130 : :
1131 : : /* compare options */
1132 : 76 : for (;;) {
1133 : 76 : ret1 = pkg_options(rp, &ro);
1134 : 76 : ret2 = pkg_options(lp, &lo);
1135 [ + - ]: 76 : if (ret1 != ret2) {
1136 : 0 : free(rp->reason);
1137 [ # # ]: 0 : if (ro == NULL)
1138 : 0 : xasprintf(&rp->reason, "option removed: %s",
1139 : 0 : lo->key);
1140 [ # # ]: 0 : else if (lo == NULL)
1141 : 0 : xasprintf(&rp->reason, "option added: %s",
1142 : 0 : ro->key);
1143 : : else
1144 : 0 : xasprintf(&rp->reason, "option changed: %s",
1145 : 0 : ro->key);
1146 [ # # ]: 0 : assert(rp->reason != NULL);
1147 : 0 : return (true);
1148 : : }
1149 [ + + ]: 76 : if (ret1 == EPKG_OK) {
1150 [ + - - + ]: 4 : if (strcmp(lo->key, ro->key) != 0 ||
1151 : 4 : strcmp(lo->value, ro->value) != 0) {
1152 : 4 : free(rp->reason);
1153 : 4 : xasprintf(&rp->reason, "options changed");
1154 : 4 : return (true);
1155 : : }
1156 : 0 : }
1157 : : else
1158 : 72 : break;
1159 : : }
1160 : :
1161 : : /* What about the direct deps */
1162 : 92 : for (;;) {
1163 : 92 : ret1 = pkg_deps(rp, &rd);
1164 : 92 : ret2 = pkg_deps(lp, &ld);
1165 [ + + ]: 92 : if (ret1 != ret2) {
1166 : 4 : free(rp->reason);
1167 [ + - ]: 4 : if (rd == NULL)
1168 : 0 : xasprintf(&rp->reason, "direct dependency removed: %s",
1169 : 0 : ld->name);
1170 [ - + ]: 4 : else if (ld == NULL)
1171 : 8 : xasprintf(&rp->reason, "direct dependency added: %s",
1172 : 4 : rd->name);
1173 : : else
1174 : 0 : xasprintf(&rp->reason, "direct dependency changed: %s",
1175 : 0 : rd->name);
1176 [ - + ]: 4 : assert (rp->reason != NULL);
1177 : 4 : return (true);
1178 : : }
1179 [ + + ]: 88 : if (ret1 == EPKG_OK) {
1180 [ + + + + ]: 40 : if ((strcmp(rd->name, ld->name) != 0) ||
1181 : 32 : (strcmp(rd->origin, ld->origin) != 0)) {
1182 : 20 : free(rp->reason);
1183 : 40 : xasprintf(&rp->reason, "direct dependency changed: %s",
1184 : 20 : rd->name);
1185 [ + - ]: 20 : assert (rp->reason != NULL);
1186 : 20 : return (true);
1187 : : }
1188 : 20 : }
1189 : : else
1190 : 48 : break;
1191 : : }
1192 : :
1193 : : /* Conflicts */
1194 : 48 : for (;;) {
1195 : 48 : ret1 = pkg_conflicts(rp, &rc);
1196 : 48 : ret2 = pkg_conflicts(lp, &lc);
1197 [ + - ]: 48 : if (ret1 != ret2) {
1198 : 0 : free(rp->reason);
1199 : 0 : rp->reason = xstrdup("direct conflict changed");
1200 : 0 : return (true);
1201 : : }
1202 [ - + ]: 48 : if (ret1 == EPKG_OK) {
1203 [ # # ]: 0 : if (strcmp(rc->uid, lc->uid) != 0) {
1204 : 0 : free(rp->reason);
1205 : 0 : rp->reason = xstrdup("direct conflict changed");
1206 : 0 : return (true);
1207 : : }
1208 : 0 : }
1209 : : else
1210 : 48 : break;
1211 : : }
1212 : :
1213 : : /* Provides */
1214 : 48 : it1 = pkghash_iterator(rp->provides);
1215 : 48 : it2 = pkghash_iterator(lp->provides);
1216 : 48 : for (;;) {
1217 : 48 : ret1 = pkghash_next(&it1);
1218 : 48 : ret2 = pkghash_next(&it2);
1219 [ + - ]: 48 : if (ret1 != ret2) {
1220 : 0 : free(rp->reason);
1221 : 0 : rp->reason = xstrdup("provides changed");
1222 : 0 : return (true);
1223 : : }
1224 [ - + ]: 48 : if (ret1) {
1225 [ # # ]: 0 : if (strcmp(it1.key, it2.key) != 0) {
1226 : 0 : free(rp->reason);
1227 : 0 : rp->reason = xstrdup("provides changed");
1228 : 0 : return (true);
1229 : : }
1230 : 0 : }
1231 : : else
1232 : 48 : break;
1233 : : }
1234 : : /* Requires */
1235 : 48 : it1 = pkghash_iterator(rp->requires);
1236 : 48 : it2 = pkghash_iterator(lp->requires);
1237 : 48 : for (;;) {
1238 : 48 : ret1 = pkghash_next(&it1);
1239 : 48 : ret2 = pkghash_next(&it2);
1240 [ + - ]: 48 : if (ret1 != ret2) {
1241 : 0 : free(rp->reason);
1242 : 0 : rp->reason = xstrdup("requires changed");
1243 : 0 : return (true);
1244 : : }
1245 [ + + ]: 48 : if (ret1) {
1246 [ - + ]: 8 : if (strcmp(it1.key, it2.key) != 0) {
1247 : 8 : free(rp->reason);
1248 : 8 : rp->reason = xstrdup("requires changed");
1249 : 8 : return (true);
1250 : : }
1251 : 0 : }
1252 : : else
1253 : 40 : break;
1254 : : }
1255 : :
1256 : : /* Finish by the shlibs */
1257 : 40 : it1 = pkghash_iterator(rp->shlibs_provided);
1258 : 40 : it2 = pkghash_iterator(lp->shlibs_provided);
1259 : 48 : for (;;) {
1260 : 48 : ret1 = pkghash_next(&it1);
1261 : 48 : ret2 = pkghash_next(&it2);
1262 [ + - ]: 48 : if (ret1 != ret2) {
1263 : 0 : free(rp->reason);
1264 : 0 : rp->reason = xstrdup("provided shared library changed");
1265 : 0 : return (true);
1266 : : }
1267 [ + + ]: 48 : if (ret1) {
1268 [ + - ]: 8 : if (strcmp(it1.key, it2.key) != 0) {
1269 : 0 : free(rp->reason);
1270 : 0 : rp->reason = xstrdup("provided shared library changed");
1271 : 0 : pkg_debug(1, "provided shlib changed %s -> %s",
1272 : 0 : it2.key, it1.key);
1273 : 0 : return (true);
1274 : : }
1275 : 8 : }
1276 : : else
1277 : 40 : break;
1278 : : }
1279 : :
1280 : 40 : it1 = pkghash_iterator(rp->shlibs_required);
1281 : 40 : it2 = pkghash_iterator(lp->shlibs_required);
1282 : 40 : for (;;) {
1283 : 40 : ret1 = pkghash_next(&it1);
1284 : 40 : ret2 = pkghash_next(&it2);
1285 [ + - ]: 40 : if (ret1 != ret2) {
1286 : 0 : free(rp->reason);
1287 : 0 : rp->reason = xstrdup("needed shared library changed");
1288 : 0 : return (true);
1289 : : }
1290 [ + + ]: 40 : if (ret1) {
1291 [ - + ]: 4 : if (strcmp(it1.key, it2.key) != 0) {
1292 : 4 : free(rp->reason);
1293 : 4 : rp->reason = xstrdup("needed shared library changed");
1294 : 4 : pkg_debug(1, "Required shlib changed %s -> %s",
1295 : 4 : it2.key, it1.key);
1296 : 4 : return (true);
1297 : : }
1298 : 0 : }
1299 : : else
1300 : 36 : break;
1301 : : }
1302 : :
1303 : 36 : return (false);
1304 : 301 : }
1305 : :
1306 : : static void
1307 : 481 : pkg_jobs_propagate_automatic(struct pkg_jobs *j)
1308 : : {
1309 : : struct pkg_job_universe_item *unit, *cur, *local;
1310 : : struct pkg_job_request *req;
1311 : : bool automatic;
1312 : : pkghash_it it;
1313 : :
1314 : 481 : it = pkghash_iterator(j->universe->items);
1315 [ + + ]: 1272 : while (pkghash_next(&it)) {
1316 : 791 : unit = (struct pkg_job_universe_item *)it.value;
1317 [ + + ]: 791 : if (unit->next == NULL) {
1318 : : /*
1319 : : * For packages that are alone in the installation list
1320 : : * we search them in the corresponding request
1321 : : */
1322 : 528 : req = pkghash_get_value(j->request_add, unit->pkg->uid);
1323 [ + + + + ]: 528 : if ((req == NULL || req->automatic) &&
1324 : 528 : unit->pkg->type != PKG_INSTALLED) {
1325 : 140 : automatic = true;
1326 : 140 : pkg_debug(2, "set automatic flag for %s", unit->pkg->uid);
1327 : 140 : unit->pkg->automatic = automatic;
1328 : 140 : }
1329 : : else {
1330 [ + + ]: 388 : if (j->type == PKG_JOBS_INSTALL) {
1331 : 294 : unit->pkg->automatic = false;
1332 : 294 : }
1333 : : }
1334 : 528 : }
1335 : : else {
1336 : : /*
1337 : : * For packages that are in the conflict chain we need to inherit
1338 : : * automatic flag from the local package
1339 : : */
1340 : 263 : local = NULL;
1341 : 263 : automatic = false;
1342 [ + + ]: 303 : LL_FOREACH(unit, cur) {
1343 [ + + ]: 283 : if (cur->pkg->type == PKG_INSTALLED) {
1344 : 243 : local = cur;
1345 : 243 : automatic = local->pkg->automatic;
1346 : 243 : break;
1347 : : }
1348 : 40 : }
1349 [ + + ]: 263 : if (local != NULL) {
1350 [ + + ]: 785 : LL_FOREACH(unit, cur) {
1351 : : /*
1352 : : * Propagate automatic from local package
1353 : : */
1354 [ + + ]: 542 : if (cur->pkg->type != PKG_INSTALLED) {
1355 : 299 : cur->pkg->automatic = automatic;
1356 : 299 : }
1357 : 542 : }
1358 : 243 : }
1359 : : else {
1360 : : /*
1361 : : * For packages that are not unique, we might still have
1362 : : * a situation when we need to set automatic for all
1363 : : * non-local packages
1364 : : *
1365 : : * See #1374
1366 : : */
1367 : 20 : req = pkghash_get_value(j->request_add, unit->pkg->uid);
1368 [ + - - + ]: 20 : if ((req == NULL || req->automatic)) {
1369 : 0 : automatic = true;
1370 : 0 : pkg_debug(2, "set automatic flag for %s", unit->pkg->uid);
1371 [ # # ]: 0 : LL_FOREACH(unit, cur) {
1372 : 0 : cur->pkg->automatic = automatic;
1373 : 0 : }
1374 : 0 : }
1375 : : }
1376 : : }
1377 : : }
1378 : 481 : }
1379 : :
1380 : : static struct pkg_job_request *
1381 : 115 : pkg_jobs_find_deinstall_request(struct pkg_job_universe_item *item,
1382 : : struct pkg_jobs *j, int rec_level)
1383 : : {
1384 : : struct pkg_job_request *found;
1385 : : struct pkg_job_universe_item *dep_item;
1386 : 115 : struct pkg_dep *d = NULL;
1387 : 115 : struct pkg *pkg = item->pkg;
1388 : :
1389 [ - + ]: 115 : if (rec_level > 128) {
1390 : 0 : pkg_debug(2, "cannot find deinstall request after 128 iterations for %s,"
1391 : 0 : "circular dependency maybe", pkg->uid);
1392 : 0 : return (NULL);
1393 : : }
1394 : :
1395 : 115 : found = pkghash_get_value(j->request_delete, pkg->uid);
1396 [ + - ]: 115 : if (found == NULL) {
1397 [ # # ]: 0 : while (pkg_deps(pkg, &d) == EPKG_OK) {
1398 : 0 : dep_item = pkg_jobs_universe_find(j->universe, d->uid);
1399 [ # # ]: 0 : if (dep_item) {
1400 : 0 : found = pkg_jobs_find_deinstall_request(dep_item, j, rec_level + 1);
1401 [ # # ]: 0 : if (found)
1402 : 0 : return (found);
1403 : 0 : }
1404 : : }
1405 : 0 : }
1406 : : else {
1407 : 115 : return (found);
1408 : : }
1409 : :
1410 : 0 : return (NULL);
1411 : 115 : }
1412 : :
1413 : : static void
1414 : 111 : pkg_jobs_set_deinstall_reasons(struct pkg_jobs *j)
1415 : : {
1416 : : struct pkg_solved *sit;
1417 : : struct pkg_job_request *jreq;
1418 : : struct pkg *req_pkg, *pkg;
1419 : :
1420 [ + + ]: 226 : LL_FOREACH(j->jobs, sit) {
1421 : 115 : jreq = pkg_jobs_find_deinstall_request(sit->items[0], j, 0);
1422 [ + - + - ]: 115 : if (jreq != NULL && jreq->item->unit != sit->items[0]) {
1423 : 0 : req_pkg = jreq->item->pkg;
1424 : 0 : pkg = sit->items[0]->pkg;
1425 : : /* Set the reason */
1426 : 0 : free(pkg->reason);
1427 : 0 : pkg_asprintf(&pkg->reason, "depends on %n-%v", req_pkg, req_pkg);
1428 : 0 : }
1429 : 115 : }
1430 : 111 : }
1431 : :
1432 : : static int
1433 : 0 : comp(const void *a, const void *b)
1434 : : {
1435 : 0 : const struct pkg *pa = a;
1436 : 0 : const struct pkg *pb = b;
1437 : :
1438 : 0 : return strcmp(pa->name, pb->name);
1439 : : }
1440 : :
1441 : : static int
1442 : 111 : jobs_solve_deinstall(struct pkg_jobs *j)
1443 : : {
1444 : : struct job_pattern *jp;
1445 : 111 : struct pkg *pkg = NULL;
1446 : : struct pkgdb_it *it;
1447 [ + + ]: 222 : LL_FOREACH(j->patterns, jp) {
1448 [ + - ]: 111 : if ((it = pkgdb_query(j->db, jp->pattern, jp->match)) == NULL)
1449 : 0 : return (EPKG_FATAL);
1450 : :
1451 [ + - ]: 111 : if (pkgdb_it_count(it) == 0) {
1452 : 0 : pkg_emit_notice("No packages matched for pattern '%s'\n", jp->pattern);
1453 : 0 : }
1454 : :
1455 [ + + + + ]: 230 : while (pkgdb_it_next(it, &pkg,
1456 : 230 : PKG_LOAD_BASIC|PKG_LOAD_RDEPS|PKG_LOAD_DEPS|PKG_LOAD_ANNOTATIONS) == EPKG_OK) {
1457 [ + + ]: 119 : if(pkg->locked) {
1458 [ - + ]: 4 : if (tsearch(pkg, &j->lockedpkgs, comp) == NULL) {
1459 : 0 : return (EPKG_FATAL);
1460 : : }
1461 : 4 : }
1462 : : else {
1463 : 115 : pkg_jobs_add_req(j, pkg);
1464 : : }
1465 : 119 : pkg = NULL;
1466 : : }
1467 : 111 : pkgdb_it_free(it);
1468 : 111 : }
1469 : :
1470 : 111 : j->solved = 1;
1471 : :
1472 : 111 : return (pkg_jobs_process_delete_request(j));
1473 : 111 : }
1474 : :
1475 : : static int
1476 : 30 : jobs_solve_autoremove(struct pkg_jobs *j)
1477 : : {
1478 : 30 : struct pkg *pkg = NULL;
1479 : : struct pkgdb_it *it;
1480 : :
1481 [ + - ]: 30 : if ((it = pkgdb_query_cond(j->db, " WHERE automatic=1 AND vital=0 ", NULL, MATCH_ALL)) == NULL)
1482 : 0 : return (EPKG_FATAL);
1483 : :
1484 [ + + + + ]: 64 : while (pkgdb_it_next(it, &pkg,
1485 : : PKG_LOAD_BASIC|PKG_LOAD_RDEPS|PKG_LOAD_DEPS|PKG_LOAD_ANNOTATIONS)
1486 : 64 : == EPKG_OK) {
1487 [ - + ]: 34 : if(pkg->locked) {
1488 : 0 : pkg_emit_locked(pkg);
1489 : 0 : }
1490 [ - + ]: 34 : else if (pkg_jobs_test_automatic(j, pkg)) {
1491 [ + - ]: 34 : assert(pkg_jobs_add_req(j, pkg));
1492 : 34 : }
1493 : :
1494 : 34 : pkg = NULL;
1495 : : }
1496 : 30 : pkgdb_it_free(it);
1497 : :
1498 : 30 : j->solved = true;
1499 : 30 : pkg_jobs_process_delete_request(j);
1500 : :
1501 : 30 : return (EPKG_OK);
1502 : 30 : }
1503 : :
1504 : : struct pkg_jobs_install_candidate {
1505 : : int64_t id;
1506 : : struct pkg_jobs_install_candidate *next;
1507 : : };
1508 : :
1509 : : static struct pkg_jobs_install_candidate *
1510 : 140 : pkg_jobs_new_candidate(struct pkg *pkg)
1511 : : {
1512 : : struct pkg_jobs_install_candidate *n;
1513 : :
1514 : 140 : n = xmalloc(sizeof(*n));
1515 : 140 : n->id = pkg->id;
1516 : 140 : return (n);
1517 : : }
1518 : :
1519 : : static bool
1520 : 190 : pkg_jobs_check_remote_candidate(struct pkg_jobs *j, struct pkg *pkg)
1521 : : {
1522 : : struct pkgdb_it *it;
1523 : 190 : struct pkg *p = NULL;
1524 : :
1525 : : /* If we have no digest, we need to check this package */
1526 [ + - ]: 190 : if (pkg->digest == NULL)
1527 : 0 : return (true);
1528 : :
1529 : 190 : it = pkgdb_repo_query(j->db, pkg->uid, MATCH_EXACT, j->reponame);
1530 [ - + ]: 190 : if (it != NULL) {
1531 : : /*
1532 : : * If we have the same package in a remote repo, it is not an
1533 : : * installation candidate
1534 : : */
1535 : 190 : int npkg = 0;
1536 : :
1537 [ + + ]: 394 : while (pkgdb_it_next(it, &p, PKG_LOAD_BASIC) == EPKG_OK) {
1538 : : /*
1539 : : * Check package with the same uid and explore whether digest
1540 : : * has been changed
1541 : : */
1542 [ + + ]: 204 : if (strcmp(p->digest, pkg->digest) != 0)
1543 : 140 : npkg ++;
1544 : :
1545 : 204 : pkg_free(p);
1546 : 204 : p = NULL;
1547 : : }
1548 : :
1549 : 190 : pkgdb_it_free(it);
1550 : :
1551 [ + + ]: 190 : if (npkg == 0)
1552 : 50 : return (false);
1553 : 140 : }
1554 : :
1555 : 140 : return (true);
1556 : 190 : }
1557 : :
1558 : : static struct pkg_jobs_install_candidate *
1559 : 94 : pkg_jobs_find_install_candidates(struct pkg_jobs *j, size_t *count)
1560 : : {
1561 : 94 : struct pkg *pkg = NULL;
1562 : : struct pkgdb_it *it;
1563 : 94 : struct pkg_jobs_install_candidate *candidates = NULL, *c;
1564 : :
1565 [ - + ]: 94 : if ((it = pkgdb_query(j->db, NULL, MATCH_ALL)) == NULL)
1566 : 0 : return (NULL);
1567 : :
1568 [ + + ]: 284 : while (pkgdb_it_next(it, &pkg, PKG_LOAD_BASIC) == EPKG_OK) {
1569 [ + - + + ]: 190 : if ((j->flags & PKG_FLAG_FORCE) ||
1570 : 190 : pkg_jobs_check_remote_candidate(j, pkg)) {
1571 : 140 : c = pkg_jobs_new_candidate(pkg);
1572 : 140 : LL_PREPEND(candidates, c);
1573 : 140 : (*count)++;
1574 : 140 : }
1575 : 190 : pkg_free(pkg);
1576 : 190 : pkg = NULL;
1577 : : }
1578 : 94 : pkgdb_it_free(it);
1579 : :
1580 : 94 : return (candidates);
1581 : 94 : }
1582 : :
1583 : : static int
1584 : 94 : jobs_solve_full_upgrade(struct pkg_jobs *j)
1585 : : {
1586 : 94 : struct pkg *pkg = NULL;
1587 : 94 : size_t jcount = 0;
1588 : 94 : size_t elt_num = 0;
1589 : : char sqlbuf[256];
1590 : : struct pkg_jobs_install_candidate *candidates, *c;
1591 : : struct pkg_job_request *req;
1592 : : struct pkgdb_it *it;
1593 : : pkghash_it hit;
1594 : 94 : unsigned flags = PKG_LOAD_BASIC|PKG_LOAD_OPTIONS|PKG_LOAD_DEPS|PKG_LOAD_REQUIRES|
1595 : : PKG_LOAD_SHLIBS_REQUIRED|PKG_LOAD_ANNOTATIONS|PKG_LOAD_CONFLICTS;
1596 : :
1597 : 94 : candidates = pkg_jobs_find_install_candidates(j, &jcount);
1598 : :
1599 : 94 : pkg_emit_progress_start("Checking for upgrades (%zd candidates)",
1600 : 94 : jcount);
1601 : :
1602 [ + + ]: 234 : LL_FOREACH(candidates, c) {
1603 : 140 : pkg_emit_progress_tick(++elt_num, jcount);
1604 : 280 : sqlite3_snprintf(sizeof(sqlbuf), sqlbuf, " WHERE id=%" PRId64,
1605 : 140 : c->id);
1606 [ - + ]: 140 : if ((it = pkgdb_query_cond(j->db, sqlbuf, NULL, MATCH_ALL)) == NULL)
1607 : 0 : return (EPKG_FATAL);
1608 : :
1609 : 140 : pkg = NULL;
1610 [ + + ]: 280 : while (pkgdb_it_next(it, &pkg, flags) == EPKG_OK) {
1611 : : /* Do not test we ignore what doesn't exists remotely */
1612 : 140 : pkg_jobs_find_upgrade(j, pkg->uid, MATCH_EXACT);
1613 : : }
1614 : 140 : pkg_free(pkg);
1615 : 140 : pkgdb_it_free(it);
1616 : 140 : }
1617 : 94 : pkg_emit_progress_tick(jcount, jcount);
1618 [ + + + + : 234 : LL_FREE(candidates, free);
- + # # #
# # # ]
1619 : :
1620 : 94 : pkg_emit_progress_start("Processing candidates (%zd candidates)",
1621 : 94 : jcount);
1622 : 94 : elt_num = 0;
1623 : :
1624 : 94 : hit = pkghash_iterator(j->request_add);
1625 [ + + ]: 208 : while (pkghash_next(&hit)) {
1626 : 114 : req = hit.value;
1627 : 114 : pkg_emit_progress_tick(++elt_num, jcount);
1628 : 114 : pkg_jobs_universe_process(j->universe, req->item->pkg);
1629 : : }
1630 : 94 : pkg_emit_progress_tick(jcount, jcount);
1631 : :
1632 : 94 : pkg_jobs_universe_process_upgrade_chains(j);
1633 : :
1634 : 94 : return (EPKG_OK);
1635 : 94 : }
1636 : :
1637 : : static int
1638 : 355 : jobs_solve_partial_upgrade(struct pkg_jobs *j)
1639 : : {
1640 : : struct job_pattern *jp;
1641 : : struct pkg_job_request *req;
1642 : 355 : bool error_found = false;
1643 : : int retcode;
1644 : : pkghash_it it;
1645 : :
1646 [ + + ]: 718 : LL_FOREACH(j->patterns, jp) {
1647 : 363 : retcode = pkg_jobs_find_remote_pattern(j, jp);
1648 [ + - ]: 363 : if (retcode == EPKG_FATAL) {
1649 : 0 : pkg_emit_error("No packages available to %s matching '%s' "
1650 : : "have been found in the "
1651 : : "repositories",
1652 : 0 : (j->type == PKG_JOBS_UPGRADE) ? "upgrade" : "install",
1653 : 0 : jp->pattern);
1654 : : /* delay the return to be sure we print a message for all issues */
1655 [ # # ]: 0 : if ((j->flags & PKG_FLAG_UPGRADE_VULNERABLE) == 0)
1656 : 0 : error_found = true;
1657 : 0 : }
1658 [ + - ]: 363 : if (retcode == EPKG_LOCKED) {
1659 : 0 : return (retcode);
1660 : : }
1661 : 363 : }
1662 [ - + ]: 355 : if (error_found)
1663 : 0 : return (EPKG_FATAL);
1664 : : /*
1665 : : * Here we have not selected the proper candidate among all
1666 : : * possible choices.
1667 : : * Hence, we want to perform this procedure now to ensure that
1668 : : * we are processing the correct packages.
1669 : : */
1670 : 355 : pkg_jobs_universe_process_upgrade_chains(j);
1671 : : /*
1672 : : * Need to iterate request one more time to recurse depends
1673 : : */
1674 : :
1675 : 355 : it = pkghash_iterator(j->request_add);
1676 [ + + ]: 710 : while (pkghash_next(&it)) {
1677 : 359 : req = it.value;
1678 : 359 : retcode = pkg_jobs_universe_process(j->universe, req->item->pkg);
1679 [ + + ]: 359 : if (retcode != EPKG_OK)
1680 : 4 : return (retcode);
1681 : : }
1682 : 351 : return (EPKG_OK);
1683 : 355 : }
1684 : :
1685 : : static int
1686 : 498 : jobs_solve_install_upgrade(struct pkg_jobs *j)
1687 : : {
1688 : : struct pkg_job_request *req;
1689 : 498 : int retcode = 0;
1690 : : pkghash_it it;
1691 : :
1692 : : /* Check for new pkg. Skip for 'upgrade -F'. */
1693 [ + - - + ]: 976 : if (((j->flags & PKG_FLAG_SKIP_INSTALL) == 0 &&
1694 [ + + ]: 498 : (j->flags & PKG_FLAG_DRY_RUN) == 0) &&
1695 : 478 : (j->flags & PKG_FLAG_PKG_VERSION_TEST) == PKG_FLAG_PKG_VERSION_TEST)
1696 [ + + ]: 478 : if (new_pkg_version(j)) {
1697 : 13 : j->flags &= ~PKG_FLAG_PKG_VERSION_TEST;
1698 : 13 : j->conservative = false;
1699 : 13 : j->pinning = false;
1700 : 13 : pkg_emit_newpkgversion();
1701 : 13 : goto order;
1702 : : }
1703 : :
1704 [ + + + - ]: 485 : if (j->patterns == NULL && j->type == PKG_JOBS_INSTALL) {
1705 : 0 : pkg_emit_error("no patterns are specified for install job");
1706 : 0 : return (EPKG_FATAL);
1707 : : }
1708 : :
1709 [ + + ]: 485 : if (j->solved == 0) {
1710 [ + + ]: 449 : if (j->patterns == NULL) {
1711 : 94 : retcode = jobs_solve_full_upgrade(j);
1712 [ + - ]: 94 : if (retcode != EPKG_OK)
1713 : 0 : return (retcode);
1714 : 94 : } else {
1715 : 355 : retcode = jobs_solve_partial_upgrade(j);
1716 [ + + ]: 355 : if (retcode != EPKG_OK)
1717 : 4 : return (retcode);
1718 : : }
1719 : 445 : }
1720 : : else {
1721 : : /*
1722 : : * If we have tried to solve request, then we just want to re-add all
1723 : : * request packages to the universe to find out any potential conflicts
1724 : : */
1725 : 36 : it = pkghash_iterator(j->request_add);
1726 [ + + ]: 104 : while (pkghash_next(&it)) {
1727 : 68 : req = it.value;
1728 : 68 : pkg_jobs_universe_process(j->universe, req->item->pkg);
1729 : : }
1730 : : }
1731 : :
1732 : : #if 0
1733 : : /* XXX: check if we can safely remove this function */
1734 : : pkg_jobs_process_add_request(j);
1735 : : #endif
1736 [ - + ]: 481 : if (pkg_conflicts_request_resolve(j) != EPKG_OK) {
1737 : 0 : pkg_emit_error("Cannot resolve conflicts in a request");
1738 : 0 : return (EPKG_FATAL);
1739 : : }
1740 : :
1741 : 481 : pkg_jobs_propagate_automatic(j);
1742 : :
1743 : : order:
1744 : :
1745 : 494 : j->solved ++;
1746 : :
1747 : 494 : return (EPKG_OK);
1748 : 498 : }
1749 : :
1750 : : static int
1751 : 8 : jobs_solve_fetch(struct pkg_jobs *j)
1752 : : {
1753 : : struct job_pattern *jp;
1754 : 8 : struct pkg *pkg = NULL;
1755 : : struct pkgdb_it *it;
1756 : : struct pkg_job_request *req;
1757 : : pkghash_it hit;
1758 : : pkg_error_t rc;
1759 : :
1760 [ - + ]: 8 : if ((j->flags & PKG_FLAG_UPGRADES_FOR_INSTALLED) == PKG_FLAG_UPGRADES_FOR_INSTALLED) {
1761 [ # # ]: 0 : if ((it = pkgdb_query(j->db, NULL, MATCH_ALL)) == NULL)
1762 : 0 : return (EPKG_FATAL);
1763 : :
1764 [ # # ]: 0 : while (pkgdb_it_next(it, &pkg, PKG_LOAD_BASIC) == EPKG_OK) {
1765 [ # # ]: 0 : if(pkg->locked) {
1766 : 0 : pkg_emit_locked(pkg);
1767 : 0 : }
1768 : : else {
1769 : : /* Do not test we ignore what doesn't exists remotely */
1770 : 0 : pkg_jobs_find_upgrade(j, pkg->uid, MATCH_EXACT);
1771 : : }
1772 : 0 : pkg = NULL;
1773 : : }
1774 : 0 : pkgdb_it_free(it);
1775 : 0 : } else {
1776 [ + + ]: 16 : LL_FOREACH(j->patterns, jp) {
1777 : : /* TODO: use repository priority here */
1778 [ + + ]: 8 : if (pkg_jobs_find_upgrade(j, jp->pattern, jp->match) == EPKG_FATAL)
1779 : 4 : pkg_emit_error("No packages matching '%s' have been found in the "
1780 : 4 : "repositories", jp->pattern);
1781 : 8 : }
1782 : 8 : hit = pkghash_iterator(j->request_add);
1783 [ + + ]: 8 : while (pkghash_next(&hit)) {
1784 : 4 : req = hit.value;
1785 : 4 : rc = pkg_jobs_universe_process(j->universe, req->item->pkg);
1786 [ - + ]: 4 : if (rc != EPKG_OK)
1787 : 4 : return (rc);
1788 : : }
1789 : : }
1790 : :
1791 : 4 : j->solved ++;
1792 : :
1793 : 4 : return (EPKG_OK);
1794 : 8 : }
1795 : :
1796 : : static void
1797 : 639 : pkg_jobs_apply_replacements(struct pkg_jobs *j)
1798 : : {
1799 : : struct pkg_job_replace *r;
1800 : : static const char sql[] = ""
1801 : : "UPDATE packages SET name=?1 "
1802 : : " WHERE name=?2;" ;
1803 : : sqlite3_stmt *stmt;
1804 : : int ret;
1805 : :
1806 : 639 : pkg_debug(4, "jobs: running '%s'", sql);
1807 : 639 : ret = sqlite3_prepare_v2(j->db->sqlite, sql, -1, &stmt, NULL);
1808 [ + - ]: 639 : if (ret != SQLITE_OK) {
1809 : 0 : ERROR_SQLITE(j->db->sqlite, sql);
1810 : 0 : return;
1811 : : }
1812 : :
1813 [ - + ]: 639 : LL_FOREACH(j->universe->uid_replaces, r) {
1814 : 0 : pkg_debug(4, "changing uid %s -> %s", r->old_uid, r->new_uid);
1815 : 0 : sqlite3_bind_text(stmt, 1, r->new_uid, -1, SQLITE_TRANSIENT);
1816 : 0 : sqlite3_bind_text(stmt, 2, r->old_uid, -1, SQLITE_TRANSIENT);
1817 : :
1818 [ # # ]: 0 : if (sqlite3_step(stmt) != SQLITE_DONE)
1819 : 0 : ERROR_STMT_SQLITE(j->db->sqlite, stmt);
1820 : :
1821 : 0 : sqlite3_reset(stmt);
1822 : 0 : }
1823 : :
1824 : 639 : sqlite3_finalize(stmt);
1825 : 639 : }
1826 : :
1827 : : static int
1828 : 0 : solve_with_external_cudf_solver(struct pkg_jobs *j, const char *solver)
1829 : : {
1830 : : int ret, pstatus;
1831 : : FILE *spipe[2];
1832 : : pid_t pchild;
1833 : :
1834 : 0 : pchild = process_spawn_pipe(spipe, solver);
1835 [ # # ]: 0 : if (pchild == -1)
1836 : 0 : return (EPKG_FATAL);
1837 : :
1838 : 0 : ret = pkg_jobs_cudf_emit_file(j, j->type, spipe[1]);
1839 : 0 : fclose(spipe[1]);
1840 : :
1841 [ # # ]: 0 : if (ret == EPKG_OK)
1842 : 0 : ret = pkg_jobs_cudf_parse_output(j, spipe[0]);
1843 : :
1844 : 0 : fclose(spipe[0]);
1845 : 0 : waitpid(pchild, &pstatus, WNOHANG);
1846 : :
1847 : 0 : return (ret);
1848 : 0 : }
1849 : :
1850 : : static int
1851 : 0 : solve_with_external_sat_solver(struct pkg_solve_problem *pb, const char *solver)
1852 : : {
1853 : : int ret, pstatus;
1854 : : FILE *spipe[2];
1855 : : pid_t pchild;
1856 : :
1857 : 0 : pchild = process_spawn_pipe(spipe, solver);
1858 [ # # ]: 0 : if (pchild == -1)
1859 : 0 : return (EPKG_FATAL);
1860 : :
1861 : 0 : ret = pkg_solve_dimacs_export(pb, spipe[1]);
1862 : 0 : fclose(spipe[1]);
1863 : :
1864 [ # # ]: 0 : if (ret == EPKG_OK)
1865 : 0 : ret = pkg_solve_parse_sat_output(spipe[0], pb);
1866 : :
1867 : 0 : fclose(spipe[0]);
1868 : 0 : waitpid(pchild, &pstatus, WNOHANG);
1869 : :
1870 : 0 : return (ret);
1871 : 0 : }
1872 : :
1873 : : static int
1874 : 639 : solve_with_sat_solver(struct pkg_jobs *j)
1875 : : {
1876 : 639 : const char *sat_solver = pkg_object_string(pkg_config_get("SAT_SOLVER"));
1877 : : struct pkg_solve_problem *problem;
1878 : : const char *dotfile;
1879 : 639 : FILE *dot = NULL;
1880 : : int ret;
1881 : :
1882 : 639 : pkg_jobs_universe_process_upgrade_chains(j);
1883 : 639 : problem = pkg_solve_jobs_to_sat(j);
1884 [ + - ]: 639 : if (problem == NULL) {
1885 : 0 : pkg_emit_error("cannot convert job to SAT problem");
1886 : 0 : j->solved = 0;
1887 : 0 : return (EPKG_FATAL);
1888 : : }
1889 : :
1890 [ - + ]: 639 : if (sat_solver != NULL)
1891 : 0 : return (solve_with_external_sat_solver(problem, sat_solver));
1892 : :
1893 [ + - + - ]: 1278 : if ((dotfile = pkg_object_string(pkg_config_get("DOT_FILE")))
1894 : 639 : != NULL) {
1895 : 0 : dot = fopen(dotfile, "we");
1896 : :
1897 [ # # ]: 0 : if (dot == NULL) {
1898 : 0 : pkg_emit_errno("fopen", dotfile);
1899 : 0 : }
1900 : 0 : }
1901 : :
1902 : 639 : ret = pkg_solve_sat_problem(problem);
1903 [ - + ]: 639 : if (ret == EPKG_AGAIN) {
1904 : 0 : pkg_solve_problem_free(problem);
1905 : 0 : return (solve_with_sat_solver(j));
1906 : : }
1907 : :
1908 [ - + ]: 639 : if (ret == EPKG_FATAL) {
1909 : 0 : pkg_emit_error("cannot solve job using SAT solver");
1910 : 0 : pkg_solve_problem_free(problem);
1911 : 0 : j->solved = 0;
1912 : 0 : } else {
1913 : 639 : ret = pkg_solve_sat_to_jobs(problem);
1914 : : }
1915 : :
1916 [ + - + - ]: 1278 : if ((dotfile = pkg_object_string(pkg_config_get("DOT_FILE")))
1917 : 639 : != NULL) {
1918 : 0 : dot = fopen(dotfile, "we");
1919 : :
1920 [ # # ]: 0 : if (dot == NULL) {
1921 : 0 : pkg_emit_errno("fopen", dotfile);
1922 : 0 : } else {
1923 : 0 : pkg_solve_dot_export(problem, dot);
1924 : 0 : fclose(dot);
1925 : : }
1926 : 0 : }
1927 : 639 : pkg_solve_problem_free(problem);
1928 : :
1929 : 639 : return (ret);
1930 : 639 : }
1931 : :
1932 : : int
1933 : 647 : pkg_jobs_solve(struct pkg_jobs *j)
1934 : : {
1935 : : int ret;
1936 : : struct pkg_solved *job;
1937 : : const char *cudf_solver;
1938 : :
1939 : 647 : pkgdb_begin_solver(j->db);
1940 : :
1941 [ + + + - : 647 : switch (j->type) {
+ ]
1942 : : case PKG_JOBS_AUTOREMOVE:
1943 : 30 : ret = jobs_solve_autoremove(j);
1944 : 30 : break;
1945 : : case PKG_JOBS_DEINSTALL:
1946 : 111 : ret = jobs_solve_deinstall(j);
1947 : 111 : break;
1948 : : case PKG_JOBS_UPGRADE:
1949 : : case PKG_JOBS_INSTALL:
1950 : 498 : ret = jobs_solve_install_upgrade(j);
1951 : 498 : break;
1952 : : case PKG_JOBS_FETCH:
1953 : 8 : ret = jobs_solve_fetch(j);
1954 : 8 : break;
1955 : : default:
1956 : 0 : pkgdb_end_solver(j->db);
1957 : 0 : return (EPKG_FATAL);
1958 : : }
1959 : :
1960 : 647 : cudf_solver = pkg_object_string(pkg_config_get("CUDF_SOLVER"));
1961 : :
1962 [ + + ]: 647 : if (ret == EPKG_OK) {
1963 [ - + ]: 639 : if (cudf_solver != NULL) {
1964 : 0 : ret = solve_with_external_cudf_solver(j, cudf_solver);
1965 : 0 : } else {
1966 : 639 : ret = solve_with_sat_solver(j);
1967 : : }
1968 : 639 : }
1969 : :
1970 [ + + + - ]: 647 : if (j->type == PKG_JOBS_DEINSTALL && j->solved)
1971 : 111 : pkg_jobs_set_deinstall_reasons(j);
1972 : :
1973 : 647 : pkgdb_end_solver(j->db);
1974 : :
1975 [ + + ]: 647 : if (ret != EPKG_OK)
1976 : 8 : return (ret);
1977 : :
1978 : 639 : pkg_jobs_apply_replacements(j);
1979 : :
1980 : : /* Check if we need to fetch and re-run the solver */
1981 [ + + ]: 1514 : DL_FOREACH(j->jobs, job) {
1982 : : struct pkg *p;
1983 : :
1984 : 879 : p = job->items[0]->pkg;
1985 [ + + ]: 879 : if (p->type != PKG_REMOTE)
1986 : 401 : continue;
1987 : :
1988 [ + + + + ]: 956 : if (pkgdb_ensure_loaded(j->db, p, PKG_LOAD_FILES|PKG_LOAD_DIRS)
1989 : 478 : == EPKG_FATAL) {
1990 : 4 : j->need_fetch = true;
1991 : 4 : break;
1992 : : }
1993 : 474 : }
1994 : :
1995 [ + + + + : 639 : if (j->solved == 1 && !j->need_fetch && j->type != PKG_JOBS_FETCH) {
+ + ]
1996 : : int rc;
1997 : 595 : bool has_conflicts = false;
1998 : 595 : do {
1999 : 631 : j->conflicts_registered = 0;
2000 : 631 : rc = pkg_jobs_check_conflicts(j);
2001 [ + + ]: 631 : if (rc == EPKG_CONFLICT) {
2002 : : /* Cleanup results */
2003 [ + + + + : 132 : LL_FREE(j->jobs, free);
- + # # #
# # # ]
2004 : 36 : j->jobs = NULL;
2005 : 36 : j->count = 0;
2006 : 36 : has_conflicts = true;
2007 : 36 : pkg_jobs_solve(j);
2008 : 36 : }
2009 [ + - + + ]: 595 : else if (rc == EPKG_OK && !has_conflicts) {
2010 : 559 : break;
2011 : : }
2012 [ + + ]: 72 : } while (j->conflicts_registered > 0);
2013 : 595 : }
2014 : :
2015 : 639 : return (ret);
2016 : 647 : }
2017 : :
2018 : : int
2019 : 603 : pkg_jobs_count(struct pkg_jobs *j)
2020 : : {
2021 [ + - ]: 603 : assert(j != NULL);
2022 : :
2023 : 603 : return (j->count);
2024 : : }
2025 : :
2026 : : int
2027 : 283 : pkg_jobs_total(struct pkg_jobs *j)
2028 : : {
2029 [ + - ]: 283 : assert(j != NULL);
2030 : :
2031 : 283 : return (j->total);
2032 : : }
2033 : :
2034 : : pkg_jobs_t
2035 : 305 : pkg_jobs_type(struct pkg_jobs *j)
2036 : : {
2037 [ + - ]: 305 : assert(j != NULL);
2038 : :
2039 : 305 : return (j->type);
2040 : : }
2041 : :
2042 : : static int
2043 : 538 : pkg_jobs_handle_install(struct pkg_solved *ps, struct pkg_jobs *j,
2044 : : struct pkg_manifest_key *keys)
2045 : : {
2046 : : struct pkg *new, *old;
2047 : : struct pkg_job_request *req;
2048 : : char path[MAXPATHLEN], *target;
2049 : 538 : int flags = 0;
2050 : 538 : int retcode = EPKG_FATAL;
2051 : :
2052 [ + + ]: 538 : old = ps->items[1] ? ps->items[1]->pkg : NULL;
2053 : 538 : new = ps->items[0]->pkg;
2054 : :
2055 : 538 : req = pkghash_get_value(j->request_add, new->uid);
2056 [ + + + + : 538 : if (req != NULL && req->item->jp != NULL &&
+ - ]
2057 : 212 : (req->item->jp->flags & PKG_PATTERN_FLAG_FILE)) {
2058 : : /*
2059 : : * We have package as a file, set special repository name
2060 : : */
2061 : 212 : target = req->item->jp->path;
2062 : 212 : free(new->reponame);
2063 : 212 : new->reponame = xstrdup("local file");
2064 : 212 : }
2065 : : else {
2066 : 326 : pkg_snprintf(path, sizeof(path), "%R", new);
2067 [ - + ]: 326 : if (*path != '/')
2068 : 326 : pkg_repo_cached_name(new, path, sizeof(path));
2069 : 326 : target = path;
2070 : : }
2071 : :
2072 [ + + ]: 538 : if (old != NULL)
2073 : 132 : new->old_version = xstrdup(old->version);
2074 : :
2075 [ + + ]: 538 : if ((j->flags & PKG_FLAG_FORCE) == PKG_FLAG_FORCE)
2076 : 189 : flags |= PKG_ADD_FORCE;
2077 [ + - ]: 538 : if ((j->flags & PKG_FLAG_NOSCRIPT) == PKG_FLAG_NOSCRIPT)
2078 : 0 : flags |= PKG_ADD_NOSCRIPT;
2079 [ + - ]: 538 : if ((j->flags & PKG_FLAG_FORCE_MISSING) == PKG_FLAG_FORCE_MISSING)
2080 : 0 : flags |= PKG_ADD_FORCE_MISSING;
2081 : 538 : flags |= PKG_ADD_UPGRADE;
2082 [ + + ]: 538 : if (ps->type == PKG_SOLVED_UPGRADE_INSTALL)
2083 : 8 : flags |= PKG_ADD_SPLITTED_UPGRADE;
2084 [ + + - + ]: 538 : if (new->automatic || (j->flags & PKG_FLAG_AUTOMATIC) == PKG_FLAG_AUTOMATIC)
2085 : 108 : flags |= PKG_ADD_AUTOMATIC;
2086 : :
2087 [ + + ]: 538 : if (old != NULL)
2088 : 132 : retcode = pkg_add_upgrade(j->db, target, flags, keys, NULL, new, old);
2089 : : else
2090 : 406 : retcode = pkg_add_from_remote(j->db, target, flags, keys, NULL, new);
2091 : :
2092 : 538 : return (retcode);
2093 : : }
2094 : :
2095 : : static int
2096 : 542 : pkg_jobs_execute(struct pkg_jobs *j)
2097 : : {
2098 : 542 : struct pkg *p = NULL;
2099 : : struct pkg_solved *ps;
2100 : 542 : struct pkg_manifest_key *keys = NULL;
2101 : 542 : int flags = 0;
2102 : 542 : int retcode = EPKG_FATAL;
2103 : : pkg_plugin_hook_t pre, post;
2104 : : struct trigger *cleanup_triggers;
2105 : :
2106 : 542 : cleanup_triggers = triggers_load(true);
2107 [ + + ]: 542 : if (j->type == PKG_JOBS_INSTALL) {
2108 : 303 : pre = PKG_PLUGIN_HOOK_PRE_INSTALL;
2109 : 303 : post = PKG_PLUGIN_HOOK_POST_INSTALL;
2110 : 303 : }
2111 [ + + ]: 239 : else if (j->type == PKG_JOBS_UPGRADE) {
2112 : 111 : pre = PKG_PLUGIN_HOOK_PRE_UPGRADE;
2113 : 111 : post = PKG_PLUGIN_HOOK_POST_UPGRADE;
2114 : 111 : }
2115 [ + + ]: 128 : else if (j->type == PKG_JOBS_AUTOREMOVE){
2116 : 21 : pre = PKG_PLUGIN_HOOK_PRE_AUTOREMOVE;
2117 : 21 : post = PKG_PLUGIN_HOOK_POST_AUTOREMOVE;
2118 : 21 : }
2119 : : else {
2120 : 107 : pre = PKG_PLUGIN_HOOK_PRE_DEINSTALL;
2121 : 107 : post = PKG_PLUGIN_HOOK_POST_DEINSTALL;
2122 : : }
2123 : :
2124 [ - + ]: 542 : if (j->flags & PKG_FLAG_SKIP_INSTALL)
2125 : 0 : return (EPKG_OK);
2126 : :
2127 [ + + ]: 542 : if ((j->flags & PKG_FLAG_FORCE) == PKG_FLAG_FORCE)
2128 : 222 : flags |= PKG_DELETE_FORCE;
2129 : :
2130 [ + - ]: 542 : if ((j->flags & PKG_FLAG_NOSCRIPT) == PKG_FLAG_NOSCRIPT)
2131 : 0 : flags |= PKG_DELETE_NOSCRIPT;
2132 : :
2133 : 542 : retcode = pkgdb_upgrade_lock(j->db, PKGDB_LOCK_ADVISORY,
2134 : : PKGDB_LOCK_EXCLUSIVE);
2135 [ - + ]: 542 : if (retcode != EPKG_OK)
2136 : 0 : return (retcode);
2137 : :
2138 : 542 : pkg_plugins_hook_run(pre, j, j->db);
2139 : :
2140 : 542 : p = NULL;
2141 : 542 : pkg_manifest_keys_new(&keys);
2142 : :
2143 : 542 : pkg_jobs_set_priorities(j);
2144 : :
2145 [ + + ]: 1252 : DL_FOREACH(j->jobs, ps) {
2146 [ + + - + : 722 : switch (ps->type) {
- ]
2147 : : case PKG_SOLVED_DELETE:
2148 : : case PKG_SOLVED_UPGRADE_REMOVE:
2149 : 184 : p = ps->items[0]->pkg;
2150 [ + + + + : 184 : if (ps->type == PKG_SOLVED_DELETE && p->vital && ((flags & PKG_DELETE_FORCE) == 0)) {
+ + ]
2151 : 4 : pkg_emit_error("Cannot delete vital package: %s!", p->name);
2152 : 4 : pkg_emit_error("If you are sure you want to remove %s, ", p->name);
2153 : 4 : pkg_emit_error("unset the 'vital' flag with: pkg set -v 0 %s", p->name);
2154 : 4 : retcode = EPKG_FATAL;
2155 : 4 : goto cleanup;
2156 : : }
2157 [ + + + + ]: 192 : if (ps->type == PKG_SOLVED_DELETE &&
2158 [ + + ]: 172 : (strcmp(p->name, "pkg") == 0 ||
2159 : 160 : strcmp(p->name, "pkg-devel") == 0) &&
2160 : 12 : (flags & PKG_DELETE_FORCE) == 0) {
2161 [ + + ]: 8 : if (j->patterns->match == MATCH_ALL) {
2162 : 4 : continue;
2163 : : } else {
2164 : 4 : pkg_emit_error("Cannot delete pkg itself without force flag");
2165 : 4 : retcode = EPKG_FATAL;
2166 : 4 : goto cleanup;
2167 : : }
2168 : : }
2169 : : /*
2170 : : * Assume that in upgrade we can remove packages with rdeps as
2171 : : * in further they will be upgraded correctly.
2172 : : */
2173 [ + + ]: 172 : if (j->type == PKG_JOBS_UPGRADE)
2174 : 40 : retcode = pkg_delete(p, j->db, flags | PKG_DELETE_CONFLICT);
2175 : : else
2176 : 132 : retcode = pkg_delete(p, j->db, flags);
2177 [ + - ]: 172 : if (retcode != EPKG_OK)
2178 : 0 : goto cleanup;
2179 : 172 : break;
2180 : : case PKG_SOLVED_INSTALL:
2181 : : case PKG_SOLVED_UPGRADE_INSTALL:
2182 : 406 : retcode = pkg_jobs_handle_install(ps, j, keys);
2183 [ + + ]: 406 : if (retcode != EPKG_OK)
2184 : 4 : goto cleanup;
2185 : 402 : break;
2186 : : case PKG_SOLVED_UPGRADE:
2187 : 132 : retcode = pkg_jobs_handle_install(ps, j, keys);
2188 [ + - ]: 132 : if (retcode != EPKG_OK)
2189 : 0 : goto cleanup;
2190 : 132 : break;
2191 : : case PKG_SOLVED_FETCH:
2192 : 0 : retcode = EPKG_FATAL;
2193 : 0 : pkg_emit_error("internal error: bad job type");
2194 : 0 : goto cleanup;
2195 : : break;
2196 : : }
2197 : :
2198 : 706 : }
2199 : :
2200 : 530 : pkg_plugins_hook_run(post, j, j->db);
2201 : 530 : triggers_execute(cleanup_triggers);
2202 : :
2203 : : cleanup:
2204 : 542 : pkgdb_release_lock(j->db, PKGDB_LOCK_EXCLUSIVE);
2205 : 542 : pkg_manifest_keys_free(keys);
2206 : :
2207 : 542 : return (retcode);
2208 : 542 : }
2209 : :
2210 : : int
2211 : 542 : pkg_jobs_apply(struct pkg_jobs *j)
2212 : : {
2213 : : int rc;
2214 : 542 : bool has_conflicts = false;
2215 : :
2216 [ + - ]: 542 : if (!j->solved) {
2217 : 0 : pkg_emit_error("The jobs hasn't been solved");
2218 : 0 : return (EPKG_FATAL);
2219 : : }
2220 : :
2221 [ + - - ]: 542 : switch (j->type) {
2222 : : case PKG_JOBS_INSTALL:
2223 : : case PKG_JOBS_UPGRADE:
2224 : : case PKG_JOBS_DEINSTALL:
2225 : : case PKG_JOBS_AUTOREMOVE:
2226 [ + + ]: 542 : if (j->need_fetch) {
2227 : 4 : pkg_plugins_hook_run(PKG_PLUGIN_HOOK_PRE_FETCH, j, j->db);
2228 : 4 : rc = pkg_jobs_fetch(j);
2229 : 4 : pkg_plugins_hook_run(PKG_PLUGIN_HOOK_POST_FETCH, j, j->db);
2230 [ - + ]: 4 : if (rc == EPKG_OK) {
2231 : : /* Check local conflicts in the first run */
2232 [ + - ]: 4 : if (j->solved == 1) {
2233 : 4 : do {
2234 : 4 : j->conflicts_registered = 0;
2235 : 4 : rc = pkg_jobs_check_conflicts(j);
2236 [ - + ]: 4 : if (rc == EPKG_CONFLICT) {
2237 : : /* Cleanup results */
2238 [ # # # # : 0 : LL_FREE(j->jobs, free);
# # # # #
# # # ]
2239 : 0 : j->jobs = NULL;
2240 : 0 : j->count = 0;
2241 : 0 : has_conflicts = true;
2242 : 0 : rc = pkg_jobs_solve(j);
2243 : 0 : }
2244 [ + - + - ]: 4 : else if (rc == EPKG_OK && !has_conflicts) {
2245 : 4 : rc = pkg_jobs_execute(j);
2246 : 4 : break;
2247 : : }
2248 [ # # ]: 0 : } while (j->conflicts_registered > 0);
2249 : :
2250 [ - + ]: 4 : if (has_conflicts) {
2251 [ # # ]: 0 : if (j->conflicts_registered == 0)
2252 : 0 : pkg_jobs_set_priorities(j);
2253 : :
2254 : 0 : return (EPKG_CONFLICT);
2255 : : }
2256 : 4 : }
2257 : : else {
2258 : : /* Not the first run, conflicts are resolved already */
2259 : 0 : rc = pkg_jobs_execute(j);
2260 : : }
2261 : 4 : }
2262 : 4 : }
2263 : : else {
2264 : 538 : rc = pkg_jobs_execute(j);
2265 : : }
2266 : :
2267 : 542 : break;
2268 : : case PKG_JOBS_FETCH:
2269 : 0 : pkg_plugins_hook_run(PKG_PLUGIN_HOOK_PRE_FETCH, j, j->db);
2270 : 0 : rc = pkg_jobs_fetch(j);
2271 : 0 : pkg_plugins_hook_run(PKG_PLUGIN_HOOK_POST_FETCH, j, j->db);
2272 : 0 : break;
2273 : : default:
2274 : 0 : rc = EPKG_FATAL;
2275 : 0 : pkg_emit_error("bad jobs argument");
2276 : 0 : break;
2277 : : }
2278 : :
2279 : 542 : return (rc);
2280 : 542 : }
2281 : :
2282 : :
2283 : : static int
2284 : 4 : pkg_jobs_fetch(struct pkg_jobs *j)
2285 : : {
2286 : 4 : struct pkg *p = NULL;
2287 : : struct pkg_solved *ps;
2288 : : struct stat st;
2289 : 4 : int64_t dlsize = 0, fs_avail = -1;
2290 : 4 : const char *cachedir = NULL;
2291 : : char cachedpath[MAXPATHLEN];
2292 : 4 : bool mirror = (j->flags & PKG_FLAG_FETCH_MIRROR) ? true : false;
2293 : :
2294 : :
2295 [ - + # # ]: 4 : if (j->destdir == NULL || !mirror)
2296 : 4 : cachedir = ctx.cachedir;
2297 : : else
2298 : 0 : cachedir = j->destdir;
2299 : :
2300 : : /* check for available size to fetch */
2301 [ + + ]: 8 : DL_FOREACH(j->jobs, ps) {
2302 [ + - - + ]: 4 : if (ps->type != PKG_SOLVED_DELETE && ps->type != PKG_SOLVED_UPGRADE_REMOVE) {
2303 : 4 : p = ps->items[0]->pkg;
2304 [ - + ]: 4 : if (p->type != PKG_REMOTE)
2305 : 0 : continue;
2306 : :
2307 [ - + ]: 4 : if (mirror) {
2308 : 0 : snprintf(cachedpath, sizeof(cachedpath),
2309 : 0 : "%s/%s", cachedir, p->repopath);
2310 : 0 : }
2311 : : else
2312 : 4 : pkg_repo_cached_name(p, cachedpath, sizeof(cachedpath));
2313 : :
2314 [ - + ]: 4 : if (stat(cachedpath, &st) == -1)
2315 : 4 : dlsize += p->pkgsize;
2316 : : else
2317 : 0 : dlsize += p->pkgsize - st.st_size;
2318 : 4 : }
2319 : 4 : }
2320 : :
2321 [ + - ]: 4 : if (dlsize == 0)
2322 : 0 : return (EPKG_OK);
2323 : :
2324 : : #ifdef HAVE_FSTATFS
2325 : : struct statfs fs;
2326 [ + + ]: 8 : while (statfs(cachedir, &fs) == -1) {
2327 [ + - ]: 4 : if (errno == ENOENT) {
2328 [ + - ]: 4 : if (mkdirs(cachedir) != EPKG_OK)
2329 : 0 : return (EPKG_FATAL);
2330 : 4 : } else {
2331 : 0 : pkg_emit_errno("statfs", cachedir);
2332 : 0 : return (EPKG_FATAL);
2333 : : }
2334 : : }
2335 : 4 : fs_avail = fs.f_bsize * (int64_t)fs.f_bavail;
2336 : : #elif defined(HAVE_SYS_STATVFS_H)
2337 : : struct statvfs fs;
2338 : : while (statvfs(cachedir, &fs) == -1) {
2339 : : if (errno == ENOENT) {
2340 : : if (mkdirs(cachedir) != EPKG_OK)
2341 : : return (EPKG_FATAL);
2342 : : } else {
2343 : : pkg_emit_errno("statvfs", cachedir);
2344 : : return (EPKG_FATAL);
2345 : : }
2346 : : }
2347 : : fs_avail = fs.f_bsize * (int64_t)fs.f_bavail;
2348 : : #endif
2349 : :
2350 [ + - + - ]: 4 : if (fs_avail != -1 && dlsize > fs_avail) {
2351 : : char dlsz[9], fsz[9];
2352 : :
2353 : 0 : humanize_number(dlsz, sizeof(dlsz), dlsize, "B",
2354 : : HN_AUTOSCALE, HN_IEC_PREFIXES);
2355 : 0 : humanize_number(fsz, sizeof(fsz), fs_avail, "B",
2356 : : HN_AUTOSCALE, HN_IEC_PREFIXES);
2357 : 0 : pkg_emit_error("Not enough space in %s, needed %s available %s",
2358 : 0 : cachedir, dlsz, fsz);
2359 : 0 : return (EPKG_FATAL);
2360 : : }
2361 : :
2362 [ - + ]: 4 : if ((j->flags & PKG_FLAG_DRY_RUN) == PKG_FLAG_DRY_RUN)
2363 : 0 : return (EPKG_OK); /* don't download anything */
2364 : :
2365 : : /* Fetch */
2366 [ + + ]: 8 : DL_FOREACH(j->jobs, ps) {
2367 [ + - - + ]: 4 : if (ps->type != PKG_SOLVED_DELETE && ps->type != PKG_SOLVED_UPGRADE_REMOVE) {
2368 : 4 : p = ps->items[0]->pkg;
2369 [ - + ]: 4 : if (p->type != PKG_REMOTE)
2370 : 0 : continue;
2371 : :
2372 [ - + ]: 4 : if (mirror) {
2373 [ # # ]: 0 : if (pkg_repo_mirror_package(p, cachedir) != EPKG_OK)
2374 : 0 : return (EPKG_FATAL);
2375 : 0 : }
2376 : : else {
2377 [ + - ]: 4 : if (pkg_repo_fetch_package(p) != EPKG_OK)
2378 : 0 : return (EPKG_FATAL);
2379 : : }
2380 : 4 : }
2381 : 4 : }
2382 : :
2383 : 4 : return (EPKG_OK);
2384 : 4 : }
2385 : :
2386 : : static int
2387 : 635 : pkg_jobs_check_conflicts(struct pkg_jobs *j)
2388 : : {
2389 : : struct pkg_solved *ps;
2390 : 635 : struct pkg *p = NULL;
2391 : 635 : int ret = EPKG_OK, res, added = 0;
2392 : :
2393 : 635 : pkg_emit_integritycheck_begin();
2394 : 635 : j->conflicts_registered = 0;
2395 : :
2396 [ + + ]: 1514 : DL_FOREACH(j->jobs, ps) {
2397 [ + + - + ]: 879 : if (ps->type == PKG_SOLVED_DELETE || ps->type == PKG_SOLVED_UPGRADE_REMOVE) {
2398 : 189 : continue;
2399 : : }
2400 : : else {
2401 : 690 : p = ps->items[0]->pkg;
2402 : :
2403 [ + + ]: 690 : if (p->type == PKG_REMOTE)
2404 : 478 : pkgdb_ensure_loaded(j->db, p, PKG_LOAD_FILES|PKG_LOAD_DIRS);
2405 : : }
2406 [ - + ]: 690 : if ((res = pkg_conflicts_append_chain(ps->items[0], j)) != EPKG_OK)
2407 : 0 : ret = res;
2408 : : else
2409 : 690 : added ++;
2410 : 690 : }
2411 : :
2412 : 635 : pkg_debug(1, "check integrity for %d items added", added);
2413 : :
2414 : 635 : pkg_emit_integritycheck_finished(j->conflicts_registered);
2415 [ + + ]: 635 : if (j->conflicts_registered > 0)
2416 : 36 : ret = EPKG_CONFLICT;
2417 : :
2418 : 635 : return (ret);
2419 : : }
2420 : :
2421 : : bool
2422 : 111 : pkg_jobs_has_lockedpkgs(struct pkg_jobs *j)
2423 : : {
2424 : :
2425 : 111 : return j->lockedpkgs ? true : false;
2426 : : }
2427 : :
2428 : : static void
2429 : 4 : pkg_jobs_visit_lockedpkgs(const void * node, VISIT v, int i __unused)
2430 : : {
2431 : :
2432 [ + - + - ]: 4 : if (v == postorder || v == leaf) {
2433 : 8 : pkgs_job_lockedpkg->locked_pkg_cb(*(struct pkg **)node,
2434 : 4 : pkgs_job_lockedpkg->context);
2435 : 4 : }
2436 : 4 : }
2437 : :
2438 : : void
2439 : 4 : pkg_jobs_iter_lockedpkgs(struct pkg_jobs *j, locked_pkgs_cb cb, void * ctx)
2440 : : {
2441 : : struct pkg_jobs_locked foo;
2442 : :
2443 : 4 : foo.locked_pkg_cb = cb;
2444 : 4 : foo.context = ctx;
2445 : 4 : pkgs_job_lockedpkg = &foo;
2446 : :
2447 : 4 : twalk(j->lockedpkgs, pkg_jobs_visit_lockedpkgs);
2448 : 4 : }
|