XBPS Library API 20250713
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
31#include "xbps/xbps_array.h"
32#include "xbps_api_impl.h"
33
34static int
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;
41 const char *repopkgver, *repopkgname;
42 char *buf;
43
44 assert(xhp);
45 assert(array);
46 assert(pkg_repod);
47
48 pkg_cflicts = xbps_dictionary_get(pkg_repod, "conflicts");
49 if (xbps_array_count(pkg_cflicts) == 0)
50 return 0;
51
52 ttype = xbps_transaction_pkg_type(pkg_repod);
53 if (ttype == XBPS_TRANS_HOLD || ttype == XBPS_TRANS_REMOVE)
54 return 0;
55
56 trans_cflicts = xbps_dictionary_get(xhp->transd, "conflicts");
57 if (!xbps_dictionary_get_cstring_nocopy(pkg_repod, "pkgver", &repopkgver))
58 abort();
59 if (!xbps_dictionary_get_cstring_nocopy(pkg_repod, "pkgname", &repopkgname))
60 abort();
61
62 for (unsigned int i = 0; i < xbps_array_count(pkg_cflicts); i++) {
63 const char *pkgver = NULL, *pkgname = NULL, *cfpkg = NULL;
64
65 if (!xbps_array_get_cstring_nocopy(pkg_cflicts, i, &cfpkg))
66 abort();
67
68 /*
69 * Check if current pkg conflicts with an installed package.
70 */
71 if ((pkgd = xbps_pkgdb_get_pkg(xhp, cfpkg)) ||
72 (pkgd = xbps_pkgdb_get_virtualpkg(xhp, cfpkg))) {
73 /* If the conflicting pkg is on hold, ignore it */
74 if (xbps_dictionary_get(pkgd, "hold"))
75 continue;
76
77 /* Ignore itself */
78 if (!xbps_dictionary_get_cstring_nocopy(pkgd, "pkgname", &pkgname))
79 abort();
80 if (strcmp(pkgname, repopkgname) == 0) {
81 continue;
82 }
83 if (!xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver))
84 abort();
85 /*
86 * If there's a pkg for the conflict in transaction,
87 * ignore it.
88 */
89 if ((tpkgd = xbps_find_pkg_in_array(array, pkgname, 0))) {
90 ttype = xbps_transaction_pkg_type(tpkgd);
91 if (ttype == XBPS_TRANS_INSTALL ||
92 ttype == XBPS_TRANS_UPDATE ||
93 ttype == XBPS_TRANS_REMOVE ||
94 ttype == XBPS_TRANS_HOLD) {
95 continue;
96 }
97 }
98 xbps_dbg_printf("found conflicting installed "
99 "pkg %s with pkg in transaction %s "
100 "(matched by %s [trans])\n", pkgver, repopkgver, cfpkg);
101 buf = xbps_xasprintf("CONFLICT: %s with "
102 "installed pkg %s (matched by %s)",
103 repopkgver, pkgver, cfpkg);
104 if (!xbps_array_add_cstring(trans_cflicts, buf))
105 return xbps_error_oom();
106 continue;
107 }
108 /*
109 * Check if current pkg conflicts with any pkg in transaction.
110 */
111 if ((pkgd = xbps_find_pkg_in_array(array, cfpkg, 0)) ||
112 (pkgd = xbps_find_virtualpkg_in_array(xhp, array, cfpkg, 0))) {
113 /* ignore pkgs to be removed or on hold */
114 ttype = xbps_transaction_pkg_type(pkgd);
115 if (ttype == XBPS_TRANS_REMOVE || ttype == XBPS_TRANS_HOLD)
116 continue;
117 /* ignore itself */
118 if (!xbps_dictionary_get_cstring_nocopy(pkgd, "pkgname", &pkgname))
119 abort();
120 if (strcmp(pkgname, repopkgname) == 0)
121 continue;
122 if (!xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver))
123 break;
124 xbps_dbg_printf("found conflicting pkgs in "
125 "transaction %s <-> %s (matched by %s [trans])\n",
126 pkgver, repopkgver, cfpkg);
127 buf = xbps_xasprintf("CONFLICT: %s with "
128 "%s in transaction (matched by %s)",
129 repopkgver, pkgver, cfpkg);
130 if (!buf)
131 return xbps_error_oom();
132 if (!xbps_array_add_cstring_nocopy(trans_cflicts, buf))
133 return xbps_error_oom();
134 continue;
135 }
136 }
137 return 0;
138}
139
140static int
141pkgdb_conflicts_cb(struct xbps_handle *xhp, xbps_object_t obj,
142 const char *key UNUSED, void *arg, bool *done UNUSED)
143{
144 xbps_array_t pkg_cflicts, trans_cflicts, pkgs = arg;
145 xbps_dictionary_t pkgd;
146 xbps_trans_type_t ttype;
147 const char *repopkgver, *repopkgname;
148 char *buf;
149
150 pkg_cflicts = xbps_dictionary_get(obj, "conflicts");
151 if (xbps_array_count(pkg_cflicts) == 0)
152 return 0;
153
154 if (!xbps_dictionary_get_cstring_nocopy(obj, "pkgver", &repopkgver))
155 abort();
156 if (!xbps_dictionary_get_cstring_nocopy(obj, "pkgname", &repopkgname))
157 abort();
158
159 // XXX: this should really be a hashtable/dictionary lookup
160 /* if a pkg is in the transaction, ignore the one from pkgdb */
161 if (xbps_find_pkg_in_array(pkgs, repopkgname, 0))
162 return 0;
163
164 trans_cflicts = xbps_dictionary_get(xhp->transd, "conflicts");
165
166 for (unsigned int i = 0; i < xbps_array_count(pkg_cflicts); i++) {
167 const char *pkgver = NULL, *pkgname = NULL, *cfpkg = NULL;
168
169 if (!xbps_array_get_cstring_nocopy(pkg_cflicts, i, &cfpkg))
170 abort();
171
172 if ((pkgd = xbps_find_pkg_in_array(pkgs, cfpkg, 0)) ||
173 (pkgd = xbps_find_virtualpkg_in_array(xhp, pkgs, cfpkg, 0))) {
174 /* ignore pkgs to be removed or on hold */
175 ttype = xbps_transaction_pkg_type(pkgd);
176 if (ttype == XBPS_TRANS_REMOVE || ttype == XBPS_TRANS_HOLD) {
177 continue;
178 }
179 /* ignore itself */
180 if (!xbps_dictionary_get_cstring_nocopy(pkgd, "pkgname", &pkgname))
181 abort();
182 if (strcmp(pkgname, repopkgname) == 0) {
183 continue;
184 }
185 if (!xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver))
186 abort();
187 xbps_dbg_printf("found conflicting pkgs in "
188 "transaction %s <-> %s (matched by %s [pkgdb])\n",
189 pkgver, repopkgver, cfpkg);
190 buf = xbps_xasprintf("CONFLICT: %s with "
191 "%s in transaction (matched by %s)",
192 repopkgver, pkgver, cfpkg);
193 if (!buf)
194 return xbps_error_oom();
195 if (!xbps_array_add_cstring_nocopy(trans_cflicts, buf))
196 return xbps_error_oom();
197 continue;
198 }
199 }
200 return 0;
201}
202
203int HIDDEN
204xbps_transaction_check_conflicts(struct xbps_handle *xhp, xbps_array_t pkgs)
205{
206 xbps_array_t array;
207 int r;
208
209 /* find conflicts in transaction */
210 for (unsigned int i = 0; i < xbps_array_count(pkgs); i++) {
211 r = pkg_conflicts_trans(xhp, pkgs, xbps_array_get(pkgs, i));
212 if (r < 0)
213 return r;
214 }
215
216 /* find conflicts in pkgdb */
217 r = xbps_pkgdb_foreach_cb_multi(xhp, pkgdb_conflicts_cb, pkgs);
218 if (r < 0)
219 return r;
220 else if (r > 0)
221 return -r;
222
223 array = xbps_dictionary_get(xhp->transd, "conflicts");
224 if (xbps_array_count(array) == 0)
225 xbps_dictionary_remove(xhp->transd, "conflicts");
226
227 return 0;
228}
xbps_dictionary_t transd
Definition xbps.h:597
Generic XBPS structure handler for initialization.
Definition xbps.h:560
#define xbps_error_oom()
Log out of memory condition.
Definition xbps.h:776
void xbps_dbg_printf(const char *fmt,...)
Prints debug messages to stderr.
Definition log.c:72
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:380
xbps_dictionary_t xbps_pkgdb_get_virtualpkg(struct xbps_handle *xhp, const char *pkg)
Definition pkgdb.c:415
xbps_dictionary_t xbps_pkgdb_get_pkg(struct xbps_handle *xhp, const char *pkg)
Definition pkgdb.c:401
xbps_trans_type_t xbps_transaction_pkg_type(xbps_dictionary_t pkg_repod)
xbps_trans_type_t
Definition xbps.h:1390
char * xbps_xasprintf(const char *fmt,...) __attribute__((format(printf