2 * dselect - Debian package maintenance user interface
3 * pkgdepcon.cc - dependency and conflict resolution
5 * Copyright © 1995 Ian Jackson <ian@chiark.greenend.org.uk>
7 * This is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
28 #include <dpkg/dpkg.h>
29 #include <dpkg/dpkg-db.h>
34 static const int depdebug
= 1;
37 packagelist::useavailable(pkginfo
*pkg
)
39 if (pkg
->clientdata
&&
40 pkg
->clientdata
->selected
== pkginfo::want_install
&&
41 informative(pkg
,&pkg
->available
) &&
42 (!(pkg
->status
== pkginfo::stat_installed
||
43 pkg
->status
== pkginfo::stat_triggersawaited
||
44 pkg
->status
== pkginfo::stat_triggerspending
) ||
45 versioncompare(&pkg
->available
.version
,&pkg
->installed
.version
) > 0))
51 pkginfoperfile
*packagelist::findinfo(pkginfo
*pkg
) {
53 r
= useavailable(pkg
) ? &pkg
->available
: &pkg
->installed
;
55 fprintf(debug
,"packagelist[%p]::findinfo(%s) useavailable=%d\n",this,pkg
->name
,useavailable(pkg
));
60 int packagelist::checkdependers(pkginfo
*pkg
, int changemade
) {
61 struct deppossi
*possi
;
63 for (possi
= pkg
->available
.depended
; possi
; possi
= possi
->rev_next
) {
64 if (!useavailable(possi
->up
->up
))
66 changemade
= max(changemade
, resolvedepcon(possi
->up
));
68 for (possi
= pkg
->installed
.depended
; possi
; possi
= possi
->rev_next
) {
69 if (useavailable(possi
->up
->up
))
71 changemade
= max(changemade
, resolvedepcon(possi
->up
));
76 int packagelist::resolvesuggest() {
77 // We continually go around looking for things to change, but we may
78 // only change the `suggested' value if we also increase the `priority'
79 // Return 2 if we made a change due to a Recommended, Depends or Conficts,
80 // or 1 if we offered or made a change because of an Optional line.
82 fprintf(debug
,"packagelist[%p]::resolvesuggest()\n",this);
83 int changemade
, maxchangemade
;
88 for (index
=0; index
<nitems
; index
++) {
89 if (!table
[index
]->pkg
->name
) continue;
90 if (depdebug
&& debug
)
91 fprintf(debug
,"packagelist[%p]::resolvesuggest() loop[%i] %s / %d\n",
92 this, index
, table
[index
]->pkg
->name
, changemade
);
94 for (depends
= findinfo(table
[index
]->pkg
)->depends
;
96 depends
= depends
->next
) {
97 changemade
= max(changemade
, resolvedepcon(depends
));
99 changemade
= checkdependers(table
[index
]->pkg
,changemade
);
100 for (depends
= findinfo(table
[index
]->pkg
)->depends
;
102 depends
= depends
->next
) {
103 if (depends
->type
!= dep_provides
) continue;
104 changemade
= checkdependers(depends
->list
->ed
,changemade
);
106 if (depdebug
&& debug
)
107 fprintf(debug
,"packagelist[%p]::resolvesuggest() loop[%i] %s / -> %d\n",
108 this, index
, table
[index
]->pkg
->name
, changemade
);
110 if (!changemade
) break;
111 maxchangemade
= max(maxchangemade
, changemade
);
114 fprintf(debug
,"packagelist[%p]::resolvesuggest() done; maxchangemade=%d\n",
116 return maxchangemade
;
119 static int dep_update_best_to_change_stop(perpackagestate
*& best
, pkginfo
*trythis
) {
120 // There's no point trying to select a pure virtual package.
121 if (!trythis
->clientdata
) return 0;
123 if (depdebug
&& debug
)
124 fprintf(debug
,"update_best_to_change(best=%s{%d}, test=%s{%d});\n",
125 best
? best
->pkg
->name
: "", best
? (int)best
->spriority
: -1,
126 trythis
->name
, trythis
->clientdata
->spriority
);
128 // If the problem is caused by us deselecting one of these packages
129 // we should not try to select another one instead.
130 if (trythis
->clientdata
->spriority
== sp_deselecting
) return 1;
132 // If we haven't found anything yet then this is our best so far.
135 // If only one of the packages is available, use that one
136 if (!informative(trythis
,&trythis
->available
) &&
137 informative(best
->pkg
,&best
->pkg
->available
)) return 0;
138 if (informative(trythis
,&trythis
->available
) &&
139 !informative(best
->pkg
,&best
->pkg
->available
)) goto yes
;
141 // Select the package with the lowest priority (ie, the one of whom
142 // we were least sure we wanted it deselected).
143 if (trythis
->clientdata
->spriority
> best
->spriority
) return 0;
144 if (trythis
->clientdata
->spriority
< best
->spriority
) goto yes
;
146 // Pick the package with the must fundamental recommendation level.
147 if (trythis
->priority
> best
->pkg
->priority
) return 0;
148 if (trythis
->priority
< best
->pkg
->priority
) goto yes
;
150 // If we're still unsure we'll change the first one in the list.
154 if (depdebug
&& debug
) fprintf(debug
,"update_best_to_change(); yes\n");
156 best
=trythis
->clientdata
; return 0;
160 packagelist::deselect_one_of(pkginfo
*per
, pkginfo
*ped
, dependency
*dep
)
162 perpackagestate
*er
= per
->clientdata
;
163 perpackagestate
*ed
= ped
->clientdata
;
165 if (!er
|| !would_like_to_install(er
->selected
,per
) ||
166 !ed
|| !would_like_to_install(ed
->selected
,ped
)) return 0;
170 er
= per
->clientdata
; // these can be changed by add
173 if (depdebug
&& debug
)
174 fprintf(debug
,"packagelist[%p]::deselect_one_of(): er %s{%d} ed %s{%d} [%p]\n",
175 this, er
->pkg
->name
, er
->spriority
, ed
->pkg
->name
, ed
->spriority
, dep
);
177 perpackagestate
*best
;
179 // Try not keep packages needing reinstallation.
180 if (per
->eflag
& pkginfo::eflag_reinstreq
)
182 else if (ped
->eflag
& pkginfo::eflag_reinstreq
)
184 else if (er
->spriority
< ed
->spriority
) best
= er
; // We'd rather change the
185 else if (er
->spriority
> ed
->spriority
) best
= ed
; // one with the lowest priority.
186 // ... failing that the one with the highest priority
187 else if (er
->pkg
->priority
> ed
->pkg
->priority
)
189 else if (er
->pkg
->priority
< ed
->pkg
->priority
)
191 else best
= ed
; // ... failing that, the second
193 if (depdebug
&& debug
)
194 fprintf(debug
,"packagelist[%p]::deselect_one_of(): best %s{%d}\n",
195 this, best
->pkg
->name
, best
->spriority
);
197 if (best
->spriority
>= sp_deselecting
) return 0;
199 best
->pkg
->status
== pkginfo::stat_notinstalled
200 ? pkginfo::want_purge
: pkginfo::want_deinstall
; // FIXME: configurable.
201 best
->selected
= best
->suggested
;
202 best
->spriority
= sp_deselecting
;
207 int packagelist::resolvedepcon(dependency
*depends
) {
208 perpackagestate
*best
, *fixbyupgrade
;
209 deppossi
*possi
, *provider
;
212 if (depdebug
&& debug
) {
213 fprintf(debug
,"packagelist[%p]::resolvedepcon([%p] %s --%s-->",
214 this, depends
, depends
->up
->name
, relatestrings
[depends
->type
]);
215 for (possi
=depends
->list
; possi
; possi
=possi
->next
)
216 fprintf(debug
," %s",possi
->ed
->name
);
217 fprintf(debug
,"); (ing)->want=%s\n",
218 depends
->up
->clientdata
219 ? wantstrings
[depends
->up
->clientdata
->suggested
]
220 : "(no clientdata)");
223 if (!depends
->up
->clientdata
) return 0;
225 switch (depends
->type
) {
236 if (would_like_to_install(depends
->up
->clientdata
->selected
,depends
->up
) <= 0)
241 possi
= depends
->list
;
242 while (possi
&& !deppossatisfied(possi
, &fixbyupgrade
))
244 if (depdebug
&& debug
)
245 fprintf(debug
,"packagelist[%p]::resolvedepcon([%p]): depends found %s\n",
247 possi
? possi
->ed
->name
: "[none]");
250 // Ensures all in the recursive list; adds info strings; ups priorities
251 switch (depends
->type
) {
254 r
= add(depends
, dp_may
);
257 r
= add(depends
, dp_should
);
260 r
= add(depends
, dp_must
);
264 if (depdebug
&& debug
) fprintf(debug
,"packagelist[%p]::resolvedepcon([%p]): "
265 "fixbyupgrade %s\n", this,depends
,fixbyupgrade
->pkg
->name
);
269 for (possi
= depends
->list
;
271 possi
= possi
->next
) {
273 if (possi
->ed
->clientdata
) foundany
= 1;
274 if (dep_update_best_to_change_stop(best
, possi
->ed
)) goto mustdeselect
;
275 for (provider
= possi
->ed
->available
.depended
;
277 provider
= provider
->rev_next
) {
278 if (provider
->up
->type
!= dep_provides
) continue;
279 if (provider
->up
->up
->clientdata
) foundany
= 1;
280 if (dep_update_best_to_change_stop(best
, provider
->up
->up
)) goto mustdeselect
;
282 if (!foundany
) addunavailable(possi
);
285 if (depdebug
&& debug
) fprintf(debug
,"packagelist[%p]::resolvedepcon([%p]): "
286 "mustdeselect nobest\n", this,depends
);
290 if (depdebug
&& debug
)
291 fprintf(debug
,"packagelist[%p]::resolvedepcon([%p]): select best=%s{%d}\n",
292 this,depends
, best
->pkg
->name
, best
->spriority
);
293 if (best
->spriority
>= sp_selecting
) return r
;
294 /* Always select depends. Only select recommends if we got here because
295 * of a manually-initiated install request. */
296 if (depends
->type
!= dep_recommends
|| manual_install
) {
297 best
->selected
= best
->suggested
= pkginfo::want_install
;
298 best
->spriority
= sp_selecting
;
303 best
= depends
->up
->clientdata
;
304 if (depdebug
&& debug
)
305 fprintf(debug
,"packagelist[%p]::resolvedepcon([%p]): mustdeselect best=%s{%d}\n",
306 this,depends
, best
->pkg
->name
, best
->spriority
);
308 if (best
->spriority
>= sp_deselecting
) return r
;
309 /* Always remove depends, but never remove recommends. */
310 if (depends
->type
!= dep_recommends
) {
311 best
->selected
= best
->suggested
=
312 best
->pkg
->status
== pkginfo::stat_notinstalled
313 ? pkginfo::want_purge
: pkginfo::want_deinstall
; // FIXME: configurable
314 best
->spriority
= sp_deselecting
;
321 if (depdebug
&& debug
)
322 fprintf(debug
,"packagelist[%p]::resolvedepcon([%p]): conflict\n",
325 if (would_like_to_install(depends
->up
->clientdata
->selected
,depends
->up
) == 0)
328 if (depdebug
&& debug
)
329 fprintf(debug
,"packagelist[%p]::resolvedepcon([%p]): conflict installing 1\n",
332 if (!deppossatisfied(depends
->list
,0)) return 0;
334 if (depdebug
&& debug
)
335 fprintf(debug
,"packagelist[%p]::resolvedepcon([%p]): conflict satisfied - ouch\n",
338 if (depends
->up
!= depends
->list
->ed
) {
339 r
= deselect_one_of(depends
->up
, depends
->list
->ed
, depends
); if (r
) return r
;
341 for (provider
= depends
->list
->ed
->available
.depended
;
343 provider
= provider
->rev_next
) {
344 if (provider
->up
->type
!= dep_provides
) continue;
345 if (provider
->up
->up
== depends
->up
) continue; // conflicts & provides same thing
346 r
= deselect_one_of(depends
->up
, provider
->up
->up
, depends
); if (r
) return r
;
348 if (depdebug
&& debug
)
349 fprintf(debug
,"packagelist[%p]::resolvedepcon([%p]): no desel\n", this,depends
);
353 internerr("unknown deptype");
355 /* never reached, make gcc happy */
360 packagelist::deppossatisfied(deppossi
*possi
, perpackagestate
**fixbyupgrade
)
362 // `satisfied' here for Conflicts and Breaks means that the
363 // restriction is violated ie that the target package is wanted
365 pkginfo::pkgwant want
= pkginfo::want_purge
;
367 if (possi
->ed
->clientdata
) {
368 want
= possi
->ed
->clientdata
->selected
;
369 would
= would_like_to_install(want
,possi
->ed
);
374 if ((possi
->up
->type
== dep_conflicts
|| possi
->up
->type
== dep_breaks
)
375 ? possi
->up
->up
!= possi
->ed
&& would
!= 0
377 // If it's to be installed or left installed, then either it's of
378 // the right version, and therefore OK, or a version must have
379 // been specified, in which case we don't need to look at the rest
381 if (useavailable(possi
->ed
)) {
382 assert(want
== pkginfo::want_install
);
383 return versionsatisfied(&possi
->ed
->available
,possi
);
385 if (versionsatisfied(&possi
->ed
->installed
, possi
))
387 if (want
== pkginfo::want_hold
&& fixbyupgrade
&& !*fixbyupgrade
&&
388 versionsatisfied(&possi
->ed
->available
,possi
) &&
389 versioncompare(&possi
->ed
->available
.version
,
390 &possi
->ed
->installed
.version
) > 1)
391 *fixbyupgrade
= possi
->ed
->clientdata
;
395 if (possi
->verrel
!= dvr_none
)
399 for (provider
= possi
->ed
->installed
.depended
;
401 provider
= provider
->rev_next
) {
402 if (provider
->up
->type
== dep_provides
&&
403 provider
->up
->up
->clientdata
&&
404 !useavailable(provider
->up
->up
) &&
405 would_like_to_install(provider
->up
->up
->clientdata
->selected
,
409 for (provider
= possi
->ed
->available
.depended
;
411 provider
= provider
->rev_next
) {
412 if (provider
->up
->type
!= dep_provides
||
413 !provider
->up
->up
->clientdata
||
414 !would_like_to_install(provider
->up
->up
->clientdata
->selected
,
417 if (useavailable(provider
->up
->up
))
419 if (fixbyupgrade
&& !*fixbyupgrade
&&
420 (!(provider
->up
->up
->status
== pkginfo::stat_installed
||
421 provider
->up
->up
->status
== pkginfo::stat_triggerspending
||
422 provider
->up
->up
->status
== pkginfo::stat_triggersawaited
) ||
423 versioncompare(&provider
->up
->up
->available
.version
,
424 &provider
->up
->up
->installed
.version
) > 1))
425 *fixbyupgrade
= provider
->up
->up
->clientdata
;