XBPS Library API 20260501
The X Binary Package System
package_fulldeptree.c
1/*-
2 * Copyright (c) 2014-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#include "uthash.h"
34
35struct item;
36
37struct depn {
38 struct depn *dnext;
39 struct item *item;
40};
41
42struct item {
43 char *pkgn; /* hash key */
44 const char *pkgver;
45 xbps_array_t rdeps;
46 struct depn *dbase;
47 UT_hash_handle hh;
48};
49
50static struct item *items = NULL;
51static xbps_array_t result;
52
53static struct item *
54lookupItem(const char *pkgn)
55{
56 struct item *item = NULL;
57
58 assert(pkgn);
59
60 HASH_FIND_STR(items, pkgn, item);
61 return item;
62}
63
64static struct item *
65addItem(xbps_array_t rdeps, const char *pkgn, const char *pkgver)
66{
67 struct item *item = NULL;
68
69 assert(pkgn);
70 assert(pkgver);
71
72 HASH_FIND_STR(items, pkgn, item);
73 if (item)
74 return item;
75
76 item = malloc(sizeof(*item));
77 if (!item)
78 return NULL;
79 item->pkgn = strdup(pkgn);
80 if (!item->pkgn) {
81 free(item);
82 return NULL;
83 }
84 item->pkgver = pkgver;
85 item->rdeps = rdeps;
86 item->dbase = NULL;
87 HASH_ADD_KEYPTR(hh, items, item->pkgn, strlen(pkgn), item);
88
89 return item;
90}
91
92static void
93addDepn(struct item *item, struct item *xitem)
94{
95 struct depn *depn = calloc(1, sizeof(*depn));
96
97 assert(depn);
98 assert(item);
99 assert(xitem);
100
101 depn->item = item;
102 depn->dnext = xitem->dbase;
103 xitem->dbase = depn;
104}
105
106static int
107add_deps_recursive(struct item *item, bool first)
108{
109 struct depn *dep;
110 xbps_string_t str;
111
112 if (xbps_match_string_in_array(result, item->pkgver))
113 return 0;
114
115 for (dep = item->dbase; dep; dep = dep->dnext) {
116 int r = add_deps_recursive(dep->item, false);
117 if (r < 0)
118 return r;
119 }
120
121
122 if (first)
123 return 0;
124
125 str = xbps_string_create_cstring(item->pkgver);
126 if (!str)
127 return xbps_error_oom();
128
129 if (!xbps_array_add_first(result, str))
130 return xbps_error_oom();
131 xbps_object_release(str);
132 return 0;
133}
134
135static void
136cleanup(void)
137{
138 struct item *item, *itmp;
139
140 HASH_ITER(hh, items, item, itmp) {
141 HASH_DEL(items, item);
142 if (item->dbase)
143 free(item->dbase);
144 free(item->pkgn);
145 free(item);
146 }
147}
148
149/*
150 * Recursively calculate all dependencies.
151 */
152static struct item *
153ordered_depends(struct xbps_handle *xhp, xbps_dictionary_t pkgd, bool rpool,
154 size_t depth)
155{
156 xbps_array_t rdeps, provides;
157 xbps_string_t str;
158 struct item *item = NULL, *xitem = NULL;
159 const char *pkgver = NULL, *pkgname = NULL;
160
161 assert(xhp);
162 assert(pkgd);
163
164 rdeps = xbps_dictionary_get(pkgd, "run_depends");
165 provides = xbps_dictionary_get(pkgd, "provides");
166 xbps_dictionary_get_cstring_nocopy(pkgd, "pkgname", &pkgname);
167
168 item = lookupItem(pkgname);
169 if (item) {
170 int r = add_deps_recursive(item, depth == 0);
171 if (r < 0)
172 return NULL;
173 return item;
174 }
175
176 if (!xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver))
178
179 item = addItem(rdeps, pkgname, pkgver);
180 if (!item)
181 return NULL;
182
183 for (unsigned int i = 0; i < xbps_array_count(rdeps); i++) {
184 xbps_dictionary_t curpkgd;
185 const char *curdep = NULL;
186 char curdepname[XBPS_NAME_SIZE];
187
188 xbps_array_get_cstring_nocopy(rdeps, i, &curdep);
189 if (rpool) {
190 if ((curpkgd = xbps_rpool_get_pkg(xhp, curdep)) == NULL)
191 curpkgd = xbps_rpool_get_virtualpkg(xhp, curdep);
192 } else {
193 if ((curpkgd = xbps_pkgdb_get_pkg(xhp, curdep)) == NULL)
194 curpkgd = xbps_pkgdb_get_virtualpkg(xhp, curdep);
195 /* Ignore missing local runtime dependencies, because ignorepkg */
196 if (curpkgd == NULL)
197 continue;
198 }
199 if (curpkgd == NULL) {
200 /* package depends on missing dependencies */
201 xbps_dbg_printf("%s: missing dependency '%s'\n", pkgver, curdep);
202 errno = ENODEV;
203 return NULL;
204 }
205 if (!xbps_pkgpattern_name(curdepname, XBPS_NAME_SIZE, curdep) &&
206 !xbps_pkg_name(curdepname, XBPS_NAME_SIZE, curdep))
208
209 if (provides && xbps_match_pkgname_in_array(provides, curdepname)) {
210 xbps_dbg_printf("%s: ignoring dependency %s "
211 "already in provides\n", pkgver, curdep);
212 continue;
213 }
214 xitem = lookupItem(curdepname);
215 if (xitem) {
216 add_deps_recursive(xitem, false);
217 continue;
218 }
219 xitem = ordered_depends(xhp, curpkgd, rpool, depth+1);
220 if (!xitem)
221 return NULL;
222 addDepn(item, xitem);
223 }
224 /* all deps were processed, add item to head */
225 if (depth > 0 && !xbps_match_string_in_array(result, item->pkgver)) {
226 str = xbps_string_create_cstring(item->pkgver);
227 if (!str) {
229 return NULL;
230 }
231 xbps_array_add_first(result, str);
232 xbps_object_release(str);
233 }
234 return item;
235}
236
237xbps_array_t HIDDEN
238xbps_get_pkg_fulldeptree(struct xbps_handle *xhp, const char *pkg, bool rpool)
239{
240 xbps_dictionary_t pkgd;
241
242 result = xbps_array_create();
243 if (!result) {
245 return NULL;
246 }
247
248 if (rpool) {
249 if (((pkgd = xbps_rpool_get_pkg(xhp, pkg)) == NULL) &&
250 ((pkgd = xbps_rpool_get_virtualpkg(xhp, pkg)) == NULL))
251 return NULL;
252 } else {
253 if (((pkgd = xbps_pkgdb_get_pkg(xhp, pkg)) == NULL) &&
254 ((pkgd = xbps_pkgdb_get_virtualpkg(xhp, pkg)) == NULL))
255 return NULL;
256 }
257 if (ordered_depends(xhp, pkgd, rpool, 0) == NULL)
258 return NULL;
259
260 cleanup();
261 return result;
262}
Generic XBPS structure handler for initialization.
Definition xbps.h:560
#define xbps_unreachable()
Log and abort for code that should be unreachable.
Definition xbps.h:783
#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:67
xbps_dictionary_t xbps_pkgdb_get_virtualpkg(struct xbps_handle *xhp, const char *pkg)
Definition pkgdb.c:403
xbps_dictionary_t xbps_pkgdb_get_pkg(struct xbps_handle *xhp, const char *pkg)
Definition pkgdb.c:389
bool xbps_match_pkgname_in_array(xbps_array_t array, const char *pkgname)
bool xbps_match_string_in_array(xbps_array_t array, const char *val)
xbps_dictionary_t xbps_rpool_get_virtualpkg(struct xbps_handle *xhp, const char *pkg)
Definition rpool.c:323
xbps_dictionary_t xbps_rpool_get_pkg(struct xbps_handle *xhp, const char *pkg)
Definition rpool.c:329
bool xbps_pkg_name(char *dst, size_t len, const char *pkg)
Definition util.c:249
bool xbps_pkgpattern_name(char *dst, size_t len, const char *pattern)
Definition util.c:285