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