Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/pkg
Path: blob/main/libpkg/pkg_jobs_universe.c
2065 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
#ifdef HAVE_LIBUTIL_H
36
#include <libutil.h>
37
#endif
38
#include <stdbool.h>
39
#include <stdlib.h>
40
#include <string.h>
41
#include <ctype.h>
42
43
#include "pkg.h"
44
#include "private/event.h"
45
#include "private/pkg.h"
46
#include "private/pkgdb.h"
47
#include "private/pkg_jobs.h"
48
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, unit->pkg, flag);
81
return (unit->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
bool force __unused, 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, struct pkg *parent __unused)
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
/* Check for local packages */
396
if ((unit = pkghash_get_value(universe->items, rpkg->uid)) != NULL) {
397
/* Remote provide is newer, so we can add it */
398
if (pkg_jobs_universe_process_item(universe, rpkg,
399
&unit) != EPKG_OK) {
400
continue;
401
}
402
403
rpkg = NULL;
404
}
405
else {
406
/* Maybe local package has just been not added */
407
npkg = pkg_jobs_universe_get_local(universe, rpkg->uid, 0);
408
if (npkg != NULL) {
409
if (pkg_jobs_universe_process_item(universe, npkg,
410
&unit) != EPKG_OK) {
411
return (EPKG_FATAL);
412
}
413
if (pkg_jobs_universe_process_item(universe, rpkg,
414
&unit) != EPKG_OK) {
415
continue;
416
}
417
if (unit != NULL)
418
rpkg = NULL;
419
}
420
}
421
422
/* Skip seen packages */
423
if (unit == NULL) {
424
if (rpkg->digest == NULL) {
425
dbg(3, "no digest found for package %s", rpkg->uid);
426
if (pkg_checksum_calculate(rpkg,
427
universe->j->db, false, true, false) != EPKG_OK) {
428
return (EPKG_FATAL);
429
}
430
}
431
rc = pkg_jobs_universe_process_item(universe, rpkg,
432
&unit);
433
434
if (rc != EPKG_OK) {
435
return (rc);
436
}
437
438
/* Reset package to avoid freeing */
439
rpkg = NULL;
440
}
441
442
pr = xcalloc (1, sizeof (*pr));
443
pr->un = unit;
444
pr->provide = name;
445
pr->is_shlib = is_shlib;
446
447
if (prhead == NULL) {
448
DL_APPEND(prhead, pr);
449
pkghash_safe_add(universe->provides, pr->provide,
450
prhead, NULL);
451
dbg(4, "add new provide %s-%s(%s) for require %s",
452
pr->un->pkg->name, pr->un->pkg->version,
453
pr->un->pkg->type == PKG_INSTALLED ? "l" : "r",
454
pr->provide);
455
} else {
456
DL_APPEND(prhead, pr);
457
dbg(4, "append provide %s-%s(%s) for require %s",
458
pr->un->pkg->name, pr->un->pkg->version,
459
pr->un->pkg->type == PKG_INSTALLED ? "l" : "r",
460
pr->provide);
461
}
462
}
463
464
return (EPKG_OK);
465
}
466
467
static int
468
pkg_jobs_universe_process_shlibs(struct pkg_jobs_universe *universe,
469
struct pkg *pkg)
470
{
471
struct pkgdb_it *it;
472
int rc;
473
474
vec_foreach(pkg->shlibs_required, i) {
475
const char *s = pkg->shlibs_required.d[i];
476
if (charv_search(&universe->j->system_shlibs, s) != NULL)
477
continue;
478
if (pkghash_get(universe->provides, s) != NULL)
479
continue;
480
481
/* Check for local provides */
482
it = pkgdb_query_shlib_provide(universe->j->db, s);
483
if (it != NULL) {
484
rc = pkg_jobs_universe_handle_provide(universe, it,
485
s, true, pkg);
486
pkgdb_it_free(it);
487
488
if (rc != EPKG_OK) {
489
dbg(1, "cannot find local packages that provide library %s "
490
"required for %s",
491
s, pkg->name);
492
}
493
}
494
/* Not found, search in the repos */
495
it = pkgdb_repo_shlib_provide(universe->j->db,
496
s, universe->j->reponames);
497
498
if (it != NULL) {
499
rc = pkg_jobs_universe_handle_provide(universe, it, s, true, pkg);
500
pkgdb_it_free(it);
501
502
if (rc != EPKG_OK) {
503
dbg(1, "cannot find remote packages that provide library %s "
504
"required for %s",
505
s, pkg->name);
506
}
507
}
508
}
509
510
return (EPKG_OK);
511
}
512
513
static int
514
pkg_jobs_universe_process_provides_requires(struct pkg_jobs_universe *universe,
515
struct pkg *pkg)
516
{
517
struct pkgdb_it *it;
518
int rc;
519
520
vec_foreach(pkg->requires, i) {
521
const char *r = pkg->requires.d[i];
522
if (pkghash_get(universe->provides, r) != NULL)
523
continue;
524
525
/* Check for local provides */
526
it = pkgdb_query_provide(universe->j->db, r);
527
if (it != NULL) {
528
rc = pkg_jobs_universe_handle_provide(universe, it, r, false, pkg);
529
pkgdb_it_free(it);
530
531
if (rc != EPKG_OK) {
532
dbg(1, "cannot find local packages that provide %s "
533
"required for %s",
534
r, pkg->name);
535
}
536
}
537
538
/* Not found, search in the repos */
539
it = pkgdb_repo_provide(universe->j->db,
540
r, universe->j->reponames);
541
542
if (it != NULL) {
543
rc = pkg_jobs_universe_handle_provide(universe, it, r, false, pkg);
544
pkgdb_it_free(it);
545
546
if (rc != EPKG_OK) {
547
dbg(1, "cannot find remote packages that provide %s "
548
"required for %s",
549
r, pkg->name);
550
return (rc);
551
}
552
}
553
}
554
555
return (EPKG_OK);
556
}
557
558
int
559
pkg_jobs_universe_process_item(struct pkg_jobs_universe *universe, struct pkg *pkg,
560
struct pkg_job_universe_item **result)
561
{
562
unsigned flags = 0, job_flags;
563
int rc = EPKG_OK;
564
pkg_jobs_t type = universe->j->type;
565
struct pkg_job_universe_item *found;
566
567
dbg(4, "Processing item %s\n", pkg->uid);
568
569
job_flags = universe->j->flags;
570
571
/*
572
* Add pkg itself. If package is already seen then we check the `processed`
573
* flag that means that we have already tried to check our universe
574
*/
575
rc = pkg_jobs_universe_add_pkg(universe, pkg, false, &found);
576
if (rc == EPKG_CONFLICT)
577
return (rc);
578
579
if (result)
580
*result = found;
581
582
if (rc == EPKG_END) {
583
if (found->processed)
584
return (EPKG_OK);
585
}
586
else if (rc != EPKG_OK) {
587
return (rc);
588
}
589
590
found->processed = true;
591
592
/* Convert jobs flags to dependency logical flags */
593
if (job_flags & PKG_FLAG_FORCE_MISSING)
594
flags |= DEPS_FLAG_FORCE_MISSING;
595
596
switch(type) {
597
case PKG_JOBS_FETCH:
598
if (job_flags & PKG_FLAG_RECURSIVE) {
599
flags |= DEPS_FLAG_MIRROR;
600
/* For fetch jobs we worry about depends only */
601
rc = pkg_jobs_universe_process_deps(universe, pkg, flags);
602
}
603
break;
604
case PKG_JOBS_INSTALL:
605
case PKG_JOBS_UPGRADE:
606
/* Handle depends */
607
rc = pkg_jobs_universe_process_deps(universe, pkg, flags);
608
if (rc != EPKG_OK)
609
return (rc);
610
/* Handle reverse depends */
611
rc = pkg_jobs_universe_process_deps(universe, pkg,
612
flags|DEPS_FLAG_REVERSE);
613
if (rc != EPKG_OK)
614
return (rc);
615
/* Provides/requires */
616
rc = pkg_jobs_universe_process_shlibs(universe, pkg);
617
if (rc != EPKG_OK)
618
return (rc);
619
rc = pkg_jobs_universe_process_provides_requires(universe, pkg);
620
if (rc != EPKG_OK)
621
return (rc);
622
break;
623
case PKG_JOBS_AUTOREMOVE:
624
rc = pkg_jobs_universe_process_deps(universe, pkg, flags);
625
if (rc != EPKG_OK)
626
return (rc);
627
rc = pkg_jobs_universe_process_shlibs(universe, pkg);
628
if (rc != EPKG_OK)
629
return (rc);
630
rc = pkg_jobs_universe_process_provides_requires(universe, pkg);
631
if (rc != EPKG_OK)
632
return (rc);
633
break;
634
/* XXX */
635
break;
636
case PKG_JOBS_DEINSTALL:
637
/* For delete jobs we worry only about local reverse deps */
638
flags |= DEPS_FLAG_REVERSE|DEPS_FLAG_FORCE_LOCAL;
639
if (job_flags & PKG_FLAG_RECURSIVE) {
640
rc = pkg_jobs_universe_process_deps(universe, pkg, flags);
641
if (rc != EPKG_OK)
642
return (rc);
643
rc = pkg_jobs_universe_process_shlibs(universe, pkg);
644
if (rc != EPKG_OK)
645
return (rc);
646
rc = pkg_jobs_universe_process_provides_requires(universe, pkg);
647
if (rc != EPKG_OK)
648
return (rc);
649
break;
650
}
651
break;
652
}
653
654
return (rc);
655
}
656
657
int
658
pkg_jobs_universe_process(struct pkg_jobs_universe *universe,
659
struct pkg *pkg)
660
{
661
return (pkg_jobs_universe_process_item(universe, pkg, NULL));
662
}
663
664
static void
665
pkg_jobs_universe_provide_free(struct pkg_job_provide *pr)
666
{
667
struct pkg_job_provide *cur, *tmp;
668
669
DL_FOREACH_SAFE(pr, cur, tmp) {
670
free (cur);
671
}
672
}
673
674
void
675
pkg_jobs_universe_free(struct pkg_jobs_universe *universe)
676
{
677
struct pkg_job_universe_item *cur, *curtmp;
678
pkghash_it it;
679
680
it = pkghash_iterator(universe->items);
681
while (pkghash_next(&it)) {
682
LL_FOREACH_SAFE(it.value, cur, curtmp) {
683
pkg_free(cur->pkg);
684
free(cur);
685
}
686
}
687
pkghash_destroy(universe->items);
688
universe->items = NULL;
689
pkghash_destroy(universe->seen);
690
universe->seen = NULL;
691
it = pkghash_iterator(universe->provides);
692
while (pkghash_next(&it))
693
pkg_jobs_universe_provide_free(it.value);
694
pkghash_destroy(universe->provides);
695
free(universe);
696
}
697
698
struct pkg_jobs_universe *
699
pkg_jobs_universe_new(struct pkg_jobs *j)
700
{
701
struct pkg_jobs_universe *universe;
702
703
universe = xcalloc(1, sizeof(struct pkg_jobs_universe));
704
universe->j = j;
705
706
return (universe);
707
}
708
709
struct pkg_job_universe_item *
710
pkg_jobs_universe_find(struct pkg_jobs_universe *universe, const char *uid)
711
{
712
return (pkghash_get_value(universe->items, uid));
713
}
714
715
static struct pkg_job_universe_item *
716
pkg_jobs_universe_select_max_ver(struct pkg_job_universe_item *chain)
717
{
718
struct pkg_job_universe_item *cur, *res = NULL;
719
bool found = false;
720
int r;
721
722
LL_FOREACH(chain, cur) {
723
if (cur->pkg->type == PKG_INSTALLED)
724
continue;
725
726
if (res != NULL) {
727
r = pkg_version_change_between(cur->pkg, res->pkg);
728
if (r == PKG_UPGRADE) {
729
res = cur;
730
found = true;
731
}
732
else if (r != PKG_REINSTALL) {
733
/*
734
* Actually the selected package is newer than some other
735
* packages in the chain
736
*/
737
found = true;
738
}
739
}
740
else {
741
res = cur;
742
}
743
}
744
745
return (found ? res : NULL);
746
}
747
748
static struct pkg_job_universe_item *
749
pkg_jobs_universe_select_max_prio(struct pkg_job_universe_item *chain)
750
{
751
struct pkg_repo *repo;
752
unsigned int max_pri = 0;
753
struct pkg_job_universe_item *cur, *res = NULL;
754
755
LL_FOREACH(chain, cur) {
756
if (cur->pkg->type == PKG_INSTALLED)
757
continue;
758
759
if (cur->pkg->reponame) {
760
repo = pkg_repo_find(cur->pkg->reponame);
761
if (repo && repo->priority > max_pri) {
762
res = cur;
763
max_pri = repo->priority;
764
}
765
}
766
}
767
768
return (res);
769
}
770
771
static struct pkg_job_universe_item *
772
pkg_jobs_universe_select_same_repo(struct pkg_job_universe_item *chain,
773
struct pkg_job_universe_item *local, const char *assumed_reponame)
774
{
775
struct pkg_repo *local_repo = NULL, *repo;
776
struct pkg_job_universe_item *cur, *res = NULL;
777
778
if (!local) {
779
780
if (assumed_reponame) {
781
local_repo = pkg_repo_find(assumed_reponame);
782
}
783
}
784
else {
785
if (local->pkg->reponame) {
786
local_repo = pkg_repo_find(local->pkg->reponame);
787
}
788
else {
789
const char *lrepo = pkg_kv_get(&local->pkg->annotations, "repository");
790
if (lrepo) {
791
local_repo = pkg_repo_find(lrepo);
792
}
793
}
794
}
795
796
if (local_repo == NULL) {
797
return (NULL);
798
}
799
else {
800
LL_FOREACH(chain, cur) {
801
if (cur->pkg->type == PKG_INSTALLED)
802
continue;
803
804
if (cur->pkg->reponame) {
805
repo = pkg_repo_find(cur->pkg->reponame);
806
if (repo == local_repo) {
807
res = cur;
808
break;
809
}
810
}
811
}
812
}
813
814
return (res);
815
}
816
817
struct pkg_job_universe_item *
818
pkg_jobs_universe_select_candidate(struct pkg_job_universe_item *chain,
819
struct pkg_job_universe_item *local, bool conservative,
820
const char *reponame, bool pinning)
821
{
822
struct pkg_job_universe_item *res = NULL;
823
824
if (local == NULL) {
825
/* New package selection */
826
if (conservative) {
827
/* Check same repo */
828
if (reponame && pinning) {
829
res = pkg_jobs_universe_select_same_repo(chain, NULL, reponame);
830
}
831
832
if (res == NULL) {
833
/* Priority -> version */
834
res = pkg_jobs_universe_select_max_prio(chain);
835
if (res == NULL) {
836
res = pkg_jobs_universe_select_max_ver(chain);
837
}
838
}
839
}
840
else {
841
if (reponame && pinning) {
842
res = pkg_jobs_universe_select_same_repo(chain, NULL, reponame);
843
}
844
845
if (res == NULL) {
846
/* Version -> priority */
847
res = pkg_jobs_universe_select_max_ver(chain);
848
if (res == NULL) {
849
res = pkg_jobs_universe_select_max_prio(chain);
850
}
851
}
852
}
853
}
854
else {
855
if (conservative) {
856
/* same -> prio -> version */
857
if (pinning)
858
res = pkg_jobs_universe_select_same_repo(chain, local, reponame);
859
if (res == NULL) {
860
res = pkg_jobs_universe_select_max_prio(chain);
861
}
862
if (res == NULL) {
863
res = pkg_jobs_universe_select_max_ver(chain);
864
}
865
}
866
else {
867
/* same -> version -> prio */
868
if (pinning)
869
res = pkg_jobs_universe_select_same_repo(chain, local, reponame);
870
if (res == NULL) {
871
res = pkg_jobs_universe_select_max_ver(chain);
872
}
873
if (res == NULL) {
874
res = pkg_jobs_universe_select_max_prio(chain);
875
}
876
}
877
}
878
879
/* Fallback to any */
880
return (res != NULL ? res : chain);
881
}
882
883
void
884
pkg_jobs_universe_process_upgrade_chains(struct pkg_jobs *j)
885
{
886
struct pkg_job_universe_item *unit, *cur, *local;
887
struct pkg_job_request *req;
888
struct pkg_job_request_item *rit, *rtmp;
889
pkghash_it it;
890
891
it = pkghash_iterator(j->universe->items);
892
while (pkghash_next(&it)) {
893
unsigned vercnt = 0;
894
unit = (struct pkg_job_universe_item *)it.value;
895
896
req = pkghash_get_value(j->request_add, unit->pkg->uid);
897
if (req == NULL) {
898
/* Not obviously requested */
899
continue;
900
}
901
902
local = NULL;
903
LL_FOREACH(unit, cur) {
904
if (cur->pkg->type == PKG_INSTALLED)
905
local = cur;
906
vercnt ++;
907
}
908
909
if (local != NULL && local->pkg->locked) {
910
dbg(1, "removing %s from the request as it is locked",
911
local->pkg->uid);
912
pkghash_del(j->request_add, req->item->pkg->uid);
913
pkg_jobs_request_free(req);
914
continue;
915
}
916
917
if (vercnt <= 1)
918
continue;
919
920
/*
921
* Here we have more than one upgrade candidate,
922
* if local == NULL, then we have two remote repos,
923
* if local != NULL, then we have unspecified upgrade path
924
*/
925
926
if ((local == NULL && vercnt > 1) || (vercnt > 2)) {
927
/* Select the most recent or one of packages */
928
struct pkg_job_universe_item *selected;
929
930
selected = pkg_jobs_universe_select_candidate(unit, local,
931
j->conservative, NULL, j->pinning);
932
/*
933
* Now remove all requests but selected from the requested
934
* candidates
935
*/
936
assert(selected != NULL);
937
pkghash_del(j->request_add, req->item->pkg->uid);
938
939
/*
940
* We also check if the selected package has different digest,
941
* and if it has the same digest we proceed only if we have a
942
* forced job
943
*/
944
if (local != NULL && STREQ(local->pkg->digest, selected->pkg->digest) &&
945
(j->flags & PKG_FLAG_FORCE) == 0) {
946
dbg(1, "removing %s from the request as it is the "
947
"same as local", selected->pkg->uid);
948
continue;
949
}
950
951
LL_FOREACH(unit, cur) {
952
if (cur == selected)
953
continue;
954
955
DL_FOREACH_SAFE(req->item, rit, rtmp) {
956
if (rit->unit == cur) {
957
DL_DELETE(req->item, rit);
958
free(rit);
959
}
960
}
961
}
962
if (req->item == NULL) {
963
rit = xcalloc(1, sizeof(*rit));
964
rit->pkg = selected->pkg;
965
rit->unit = selected;
966
DL_APPEND(req->item, rit);
967
}
968
pkghash_safe_add(j->request_add, selected->pkg->uid, req, NULL);
969
}
970
}
971
}
972
973
struct pkg_job_universe_item*
974
pkg_jobs_universe_get_upgrade_candidates(struct pkg_jobs_universe *universe,
975
const char *uid, struct pkg *lp, bool force, const char *version)
976
{
977
struct pkg *pkg = NULL, *selected = lp;
978
struct pkgdb_it *it;
979
struct pkg_job_universe_item *unit, *ucur;
980
int flag = PKG_LOAD_BASIC|PKG_LOAD_DEPS|PKG_LOAD_OPTIONS|
981
PKG_LOAD_REQUIRES|PKG_LOAD_PROVIDES|
982
PKG_LOAD_SHLIBS_REQUIRED|PKG_LOAD_SHLIBS_PROVIDED|
983
PKG_LOAD_ANNOTATIONS|PKG_LOAD_CONFLICTS;
984
pkgs_t candidates = vec_init();
985
986
unit = pkghash_get_value(universe->items, uid);
987
if (unit != NULL) {
988
/*
989
* If a unit has been found, we have already found the potential
990
* upgrade chain for it
991
*/
992
if (force) {
993
/*
994
* We also need to ensure that a chain contains remote packages
995
* in case of forced upgrade
996
*/
997
DL_FOREACH(unit, ucur) {
998
if (ucur->pkg->type != PKG_INSTALLED) {
999
return (unit);
1000
}
1001
}
1002
}
1003
else {
1004
return (unit);
1005
}
1006
}
1007
1008
if ((it = pkgdb_repo_query2(universe->j->db, uid, MATCH_INTERNAL,
1009
universe->j->reponames)) == NULL)
1010
return (NULL);
1011
1012
while (pkgdb_it_next(it, &pkg, flag) == EPKG_OK) {
1013
1014
if (version != NULL && strcmp(pkg->version, version) != 0)
1015
continue;
1016
1017
if (force) {
1018
/* Just add everything */
1019
selected = pkg;
1020
}
1021
else {
1022
if (selected == lp &&
1023
(lp == NULL || pkg_jobs_need_upgrade(&universe->j->system_shlibs, pkg, lp)))
1024
selected = pkg;
1025
else if (pkg_version_change_between(pkg, selected) == PKG_UPGRADE)
1026
selected = pkg;
1027
}
1028
vec_push(&candidates, pkg);
1029
pkg = NULL;
1030
}
1031
1032
pkgdb_it_free(it);
1033
1034
if (lp != NULL) {
1035
/* Add local package to the universe as well */
1036
pkg_jobs_universe_add_pkg(universe, lp, false, NULL);
1037
}
1038
if (selected != lp) {
1039
/* We need to add the whole chain of upgrade candidates */
1040
vec_rforeach(candidates, i) {
1041
pkg_jobs_universe_add_pkg(universe, candidates.d[i], force, NULL);
1042
}
1043
}
1044
else {
1045
vec_free_and_free(&candidates, pkg_free);
1046
return (NULL);
1047
}
1048
1049
unit = pkghash_get_value(universe->items, uid);
1050
vec_free(&candidates);
1051
1052
return (unit);
1053
}
1054
1055