XBPS Library API 20240111
The X Binary Package System
transaction_check_revdeps.c
1/*-
2 * Copyright (c) 2013-2020 Juan Romero Pardines.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <stdbool.h>
29#include <errno.h>
30
31#include "xbps_api_impl.h"
32
33/*
34 * Verify reverse dependencies for packages in transaction.
35 * This will catch cases where a package update would break its reverse dependencies:
36 *
37 * - foo-1.0 is being updated to 2.0.
38 * - baz-1.1 depends on foo<2.0.
39 * - foo is updated to 2.0, hence baz-1.1 is currently broken.
40 *
41 * Abort transaction if such case is found.
42 */
43static bool
44check_virtual_pkgs(xbps_array_t mdeps,
45 xbps_dictionary_t trans_pkgd,
46 xbps_dictionary_t rev_pkgd)
47{
48 xbps_array_t rundeps;
49 xbps_array_t provides;
50 const char *pkgver, *vpkgver, *revpkgver, *pkgpattern;
51 char pkgname[XBPS_NAME_SIZE], vpkgname[XBPS_NAME_SIZE];
52 char *str = NULL;
53 bool matched = false;
54
55 pkgver = vpkgver = revpkgver = pkgpattern = NULL;
56 provides = xbps_dictionary_get(trans_pkgd, "provides");
57
58 for (unsigned int i = 0; i < xbps_array_count(provides); i++) {
59 xbps_dictionary_get_cstring_nocopy(trans_pkgd, "pkgver", &pkgver);
60 xbps_dictionary_get_cstring_nocopy(rev_pkgd, "pkgver", &revpkgver);
61 xbps_array_get_cstring_nocopy(provides, i, &vpkgver);
62
63 if (!xbps_pkg_name(vpkgname, sizeof(vpkgname), vpkgver)) {
64 break;
65 }
66
67 rundeps = xbps_dictionary_get(rev_pkgd, "run_depends");
68 for (unsigned int x = 0; x < xbps_array_count(rundeps); x++) {
69 xbps_array_get_cstring_nocopy(rundeps, x, &pkgpattern);
70
71 if ((!xbps_pkgpattern_name(pkgname, sizeof(pkgname), pkgpattern)) &&
72 (!xbps_pkg_name(pkgname, sizeof(pkgname), pkgpattern)))
73 continue;
74
75 if (strcmp(vpkgname, pkgname)) {
76 continue;
77 }
78 if (!strcmp(vpkgver, pkgpattern) ||
79 xbps_pkgpattern_match(vpkgver, pkgpattern)) {
80 continue;
81 }
82
83 str = xbps_xasprintf("%s broken, needs '%s' virtual pkg (got `%s')",
84 revpkgver, pkgpattern, vpkgver);
85 xbps_array_add_cstring(mdeps, str);
86 free(str);
87 matched = true;
88 }
89 }
90 return matched;
91}
92
93static void
94broken_pkg(xbps_array_t mdeps, const char *dep, const char *pkg)
95{
96 char *str;
97
98 str = xbps_xasprintf("%s in transaction breaks installed pkg `%s'", pkg, dep);
99 xbps_array_add_cstring(mdeps, str);
100 free(str);
101}
102
103bool HIDDEN
104xbps_transaction_check_revdeps(struct xbps_handle *xhp, xbps_array_t pkgs)
105{
106 xbps_array_t mdeps;
107 bool error = false;
108
109 mdeps = xbps_dictionary_get(xhp->transd, "missing_deps");
110
111 for (unsigned int i = 0; i < xbps_array_count(pkgs); i++) {
112 xbps_array_t pkgrdeps, rundeps;
113 xbps_dictionary_t revpkgd;
114 xbps_object_t obj;
115 xbps_trans_type_t ttype;
116 const char *pkgver = NULL, *revpkgver = NULL;
117 char pkgname[XBPS_NAME_SIZE] = {0};
118
119 obj = xbps_array_get(pkgs, i);
120 /*
121 * If pkg is on hold, pass to the next one.
122 */
123 ttype = xbps_transaction_pkg_type(obj);
124 if (ttype == XBPS_TRANS_HOLD) {
125 continue;
126 }
127 if (!xbps_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver)) {
128 error = true;
129 goto out;
130 }
131 if (!xbps_pkg_name(pkgname, sizeof(pkgname), pkgver)) {
132 error = true;
133 goto out;
134 }
135 /*
136 * if pkg in transaction is not installed,
137 * pass to next one.
138 */
139 if (xbps_pkg_is_installed(xhp, pkgname) == 0) {
140 continue;
141 }
142 /*
143 * If pkg is installed but does not have revdeps,
144 * pass to next one.
145 */
146 pkgrdeps = xbps_pkgdb_get_pkg_revdeps(xhp, pkgname);
147 if (!xbps_array_count(pkgrdeps)) {
148 continue;
149 }
150 /*
151 * If pkg is ignored, pass to the next one.
152 */
153 if (xbps_pkg_is_ignored(xhp, pkgver)) {
154 continue;
155 }
156
157 /*
158 * Time to validate revdeps for current pkg.
159 */
160 for (unsigned int x = 0; x < xbps_array_count(pkgrdeps); x++) {
161 const char *curpkgver = NULL;
162 char curdepname[XBPS_NAME_SIZE] = {0};
163 char curpkgname[XBPS_NAME_SIZE] = {0};
164 bool found = false;
165
166 if (!xbps_array_get_cstring_nocopy(pkgrdeps, x, &curpkgver)) {
167 error = true;
168 goto out;
169 }
170
171 if (!xbps_pkg_name(pkgname, sizeof(pkgname), curpkgver)) {
172 error = true;
173 goto out;
174 }
175
176 if ((revpkgd = xbps_find_pkg_in_array(pkgs, pkgname, 0))) {
177 if (xbps_transaction_pkg_type(revpkgd) == XBPS_TRANS_REMOVE)
178 continue;
179 }
180 if (revpkgd == NULL)
181 revpkgd = xbps_pkgdb_get_pkg(xhp, curpkgver);
182
183
184 xbps_dictionary_get_cstring_nocopy(revpkgd, "pkgver", &revpkgver);
185 /*
186 * If target pkg is being removed, all its revdeps
187 * will be broken unless those revdeps are also in
188 * the transaction.
189 */
190 if (ttype == XBPS_TRANS_REMOVE) {
191 if (xbps_dictionary_get(obj, "replaced")) {
192 continue;
193 }
194 if (xbps_find_pkg_in_array(pkgs, pkgname, XBPS_TRANS_REMOVE)) {
195 continue;
196 }
197 broken_pkg(mdeps, curpkgver, pkgver);
198 continue;
199 }
200 /*
201 * First try to match any supported virtual package.
202 */
203 if (check_virtual_pkgs(mdeps, obj, revpkgd)) {
204 continue;
205 }
206 /*
207 * Try to match real dependencies.
208 */
209 rundeps = xbps_dictionary_get(revpkgd, "run_depends");
210 /*
211 * Find out what dependency is it.
212 */
213 if (!xbps_pkg_name(curpkgname, sizeof(curpkgname), pkgver)) {
214 return false;
215 }
216
217 for (unsigned int j = 0; j < xbps_array_count(rundeps); j++) {
218 const char *curdep = NULL;
219
220 xbps_array_get_cstring_nocopy(rundeps, j, &curdep);
221 if ((!xbps_pkgpattern_name(curdepname, sizeof(curdepname), curdep)) &&
222 (!xbps_pkg_name(curdepname, sizeof(curdepname), curdep))) {
223 return false;
224 }
225 if (strcmp(curdepname, curpkgname) == 0) {
226 found = true;
227 break;
228 }
229 }
230
231 if (!found) {
232 continue;
233 }
234 if (xbps_match_pkgdep_in_array(rundeps, pkgver)) {
235 continue;
236 }
237 /*
238 * Installed package conflicts with package
239 * in transaction being updated, check
240 * if a new version of this conflicting package
241 * is in the transaction.
242 */
243 if (xbps_find_pkg_in_array(pkgs, pkgname, XBPS_TRANS_UPDATE)) {
244 continue;
245 }
246 broken_pkg(mdeps, curpkgver, pkgver);
247 }
248 }
249out:
250 if (!error) {
251 mdeps = xbps_dictionary_get(xhp->transd, "missing_deps");
252 if (xbps_array_count(mdeps) == 0)
253 xbps_dictionary_remove(xhp->transd, "missing_deps");
254 }
255 return error ? false : true;
256}
xbps_dictionary_t transd
Definition xbps.h:583
Generic XBPS structure handler for initialization.
Definition xbps.h:550
xbps_array_t xbps_pkgdb_get_pkg_revdeps(struct xbps_handle *xhp, const char *pkg)
Definition pkgdb.c:458
xbps_dictionary_t xbps_pkgdb_get_pkg(struct xbps_handle *xhp, const char *pkg)
Definition pkgdb.c:379
bool xbps_match_pkgdep_in_array(xbps_array_t array, const char *pkgver)
xbps_trans_type_t xbps_transaction_pkg_type(xbps_dictionary_t pkg_repod)
xbps_trans_type_t
Definition xbps.h:1320
char * xbps_xasprintf(const char *fmt,...) __attribute__((format(printf
bool xbps_pkg_name(char *dst, size_t len, const char *pkg)
Definition util.c:253
bool xbps_pkg_is_ignored(struct xbps_handle *xhp, const char *pkg)
Definition util.c:103
int xbps_pkg_is_installed(struct xbps_handle *xhp, const char *pkg)
Definition util.c:79
int xbps_pkgpattern_match(const char *pkgver, const char *pattern)
Definition util.c:530
bool xbps_pkgpattern_name(char *dst, size_t len, const char *pattern)
Definition util.c:289