XBPS Library API 20240111
The X Binary Package System
transaction_check_conflicts.c
1/*-
2 * Copyright (c) 2012-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
26#include <stdio.h>
27#include <stdbool.h>
28#include <stdlib.h>
29#include <string.h>
30#include <errno.h>
31
32#include "xbps_api_impl.h"
33
34static void
35pkg_conflicts_trans(struct xbps_handle *xhp, xbps_array_t array,
36 xbps_dictionary_t pkg_repod)
37{
38 xbps_array_t pkg_cflicts, trans_cflicts;
39 xbps_dictionary_t pkgd, tpkgd;
40 xbps_object_t obj;
41 xbps_object_iterator_t iter;
43 const char *cfpkg, *repopkgver, *repopkgname;
44 char *buf;
45
46 assert(xhp);
47 assert(array);
48 assert(pkg_repod);
49
50 pkg_cflicts = xbps_dictionary_get(pkg_repod, "conflicts");
51 if (xbps_array_count(pkg_cflicts) == 0) {
52 return;
53 }
54
55 ttype = xbps_transaction_pkg_type(pkg_repod);
56 if (ttype == XBPS_TRANS_HOLD || ttype == XBPS_TRANS_REMOVE) {
57 return;
58 }
59
60 trans_cflicts = xbps_dictionary_get(xhp->transd, "conflicts");
61 if (!xbps_dictionary_get_cstring_nocopy(pkg_repod, "pkgver", &repopkgver)) {
62 return;
63 }
64 if (!xbps_dictionary_get_cstring_nocopy(pkg_repod, "pkgname", &repopkgname)) {
65 return;
66 }
67
68 iter = xbps_array_iterator(pkg_cflicts);
69 assert(iter);
70
71 while ((obj = xbps_object_iterator_next(iter))) {
72 const char *pkgver = NULL, *pkgname = NULL;
73
74 cfpkg = xbps_string_cstring_nocopy(obj);
75
76 /*
77 * Check if current pkg conflicts with an installed package.
78 */
79 if ((pkgd = xbps_pkgdb_get_pkg(xhp, cfpkg)) ||
80 (pkgd = xbps_pkgdb_get_virtualpkg(xhp, cfpkg))) {
81 /* If the conflicting pkg is on hold, ignore it */
82 if (xbps_dictionary_get(pkgd, "hold"))
83 continue;
84
85 /* Ignore itself */
86 if (!xbps_dictionary_get_cstring_nocopy(pkgd, "pkgname", &pkgname)) {
87 break;
88 }
89 if (strcmp(pkgname, repopkgname) == 0) {
90 continue;
91 }
92 if (!xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver)) {
93 break;
94 }
95 /*
96 * If there's a pkg for the conflict in transaction,
97 * ignore it.
98 */
99 if ((tpkgd = xbps_find_pkg_in_array(array, pkgname, 0))) {
100 ttype = xbps_transaction_pkg_type(tpkgd);
101 if (ttype == XBPS_TRANS_INSTALL ||
102 ttype == XBPS_TRANS_UPDATE ||
103 ttype == XBPS_TRANS_REMOVE ||
104 ttype == XBPS_TRANS_HOLD) {
105 continue;
106 }
107 }
108 xbps_dbg_printf("found conflicting installed "
109 "pkg %s with pkg in transaction %s "
110 "(matched by %s [trans])\n", pkgver, repopkgver, cfpkg);
111 buf = xbps_xasprintf("CONFLICT: %s with "
112 "installed pkg %s (matched by %s)",
113 repopkgver, pkgver, cfpkg);
114 if (!xbps_match_string_in_array(trans_cflicts, buf))
115 xbps_array_add_cstring(trans_cflicts, buf);
116
117 free(buf);
118 continue;
119 }
120 /*
121 * Check if current pkg conflicts with any pkg in transaction.
122 */
123 if ((pkgd = xbps_find_pkg_in_array(array, cfpkg, 0)) ||
124 (pkgd = xbps_find_virtualpkg_in_array(xhp, array, cfpkg, 0))) {
125 /* ignore pkgs to be removed or on hold */
126 ttype = xbps_transaction_pkg_type(pkgd);
127 if (ttype == XBPS_TRANS_REMOVE || ttype == XBPS_TRANS_HOLD) {
128 continue;
129 }
130 /* ignore itself */
131 if (!xbps_dictionary_get_cstring_nocopy(pkgd, "pkgname", &pkgname)) {
132 break;
133 }
134 if (strcmp(pkgname, repopkgname) == 0) {
135 continue;
136 }
137 if (!xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver)) {
138 break;
139 }
140 xbps_dbg_printf("found conflicting pkgs in "
141 "transaction %s <-> %s (matched by %s [trans])\n",
142 pkgver, repopkgver, cfpkg);
143 buf = xbps_xasprintf("CONFLICT: %s with "
144 "%s in transaction (matched by %s)",
145 repopkgver, pkgver, cfpkg);
146 if (!xbps_match_string_in_array(trans_cflicts, buf))
147 xbps_array_add_cstring(trans_cflicts, buf);
148
149 free(buf);
150 continue;
151 }
152 }
153 xbps_object_iterator_release(iter);
154}
155
156static int
157pkgdb_conflicts_cb(struct xbps_handle *xhp, xbps_object_t obj,
158 const char *key UNUSED, void *arg, bool *done UNUSED)
159{
160 xbps_array_t pkg_cflicts, trans_cflicts, pkgs = arg;
161 xbps_dictionary_t pkgd;
162 xbps_object_t obj2;
163 xbps_object_iterator_t iter;
164 xbps_trans_type_t ttype;
165 const char *cfpkg, *repopkgver, *repopkgname;
166 char *buf;
167 int rv = 0;
168
169 pkg_cflicts = xbps_dictionary_get(obj, "conflicts");
170 if (xbps_array_count(pkg_cflicts) == 0)
171 return 0;
172
173 if (!xbps_dictionary_get_cstring_nocopy(obj, "pkgver", &repopkgver)) {
174 return EINVAL;
175 }
176 if (!xbps_dictionary_get_cstring_nocopy(obj, "pkgname", &repopkgname)) {
177 return EINVAL;
178 }
179
180 /* if a pkg is in the transaction, ignore the one from pkgdb */
181 if (xbps_find_pkg_in_array(pkgs, repopkgname, 0)) {
182 return 0;
183 }
184
185 trans_cflicts = xbps_dictionary_get(xhp->transd, "conflicts");
186 iter = xbps_array_iterator(pkg_cflicts);
187 assert(iter);
188
189 while ((obj2 = xbps_object_iterator_next(iter))) {
190 const char *pkgver = NULL, *pkgname = NULL;
191
192 cfpkg = xbps_string_cstring_nocopy(obj2);
193 if ((pkgd = xbps_find_pkg_in_array(pkgs, cfpkg, 0)) ||
194 (pkgd = xbps_find_virtualpkg_in_array(xhp, pkgs, cfpkg, 0))) {
195 /* ignore pkgs to be removed or on hold */
196 ttype = xbps_transaction_pkg_type(pkgd);
197 if (ttype == XBPS_TRANS_REMOVE || ttype == XBPS_TRANS_HOLD) {
198 continue;
199 }
200 /* ignore itself */
201 if (!xbps_dictionary_get_cstring_nocopy(pkgd, "pkgname", &pkgname)) {
202 rv = EINVAL;
203 break;
204 }
205 if (strcmp(pkgname, repopkgname) == 0) {
206 continue;
207 }
208 if (!xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver)) {
209 rv = EINVAL;
210 break;
211 }
212 xbps_dbg_printf("found conflicting pkgs in "
213 "transaction %s <-> %s (matched by %s [pkgdb])\n",
214 pkgver, repopkgver, cfpkg);
215 buf = xbps_xasprintf("CONFLICT: %s with "
216 "%s in transaction (matched by %s)",
217 repopkgver, pkgver, cfpkg);
218 if (!xbps_match_string_in_array(trans_cflicts, buf))
219 xbps_array_add_cstring(trans_cflicts, buf);
220
221 free(buf);
222 continue;
223 }
224 }
225 xbps_object_iterator_release(iter);
226 return rv;
227}
228
229bool HIDDEN
230xbps_transaction_check_conflicts(struct xbps_handle *xhp, xbps_array_t pkgs)
231{
232 xbps_array_t array;
233 unsigned int i;
234
235 /* find conflicts in transaction */
236 for (i = 0; i < xbps_array_count(pkgs); i++) {
237 pkg_conflicts_trans(xhp, pkgs, xbps_array_get(pkgs, i));
238 }
239 /* find conflicts in pkgdb */
240 if (xbps_pkgdb_foreach_cb_multi(xhp, pkgdb_conflicts_cb, pkgs) != 0) {
241 return false;
242 }
243
244 array = xbps_dictionary_get(xhp->transd, "conflicts");
245 if (xbps_array_count(array) == 0) {
246 xbps_dictionary_remove(xhp->transd, "conflicts");
247 }
248 return true;
249}
xbps_dictionary_t transd
Definition xbps.h:583
Generic XBPS structure handler for initialization.
Definition xbps.h:550
int xbps_pkgdb_foreach_cb_multi(struct xbps_handle *xhp, int(*fn)(struct xbps_handle *, xbps_object_t, const char *, void *, bool *), void *arg)
Definition pkgdb.c:361
xbps_dictionary_t xbps_pkgdb_get_virtualpkg(struct xbps_handle *xhp, const char *pkg)
Definition pkgdb.c:388
xbps_dictionary_t xbps_pkgdb_get_pkg(struct xbps_handle *xhp, const char *pkg)
Definition pkgdb.c:379
bool xbps_match_string_in_array(xbps_array_t array, const char *val)
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