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