XBPS Library API 20250624
The X Binary Package System
plist_find.c
1/*-
2 * Copyright (c) 2008-2016 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#include <fcntl.h>
32#include <dirent.h>
33#include <pthread.h>
34
35#include "xbps_api_impl.h"
36
37static xbps_dictionary_t
38get_pkg_in_array(xbps_array_t array, const char *str, xbps_trans_type_t tt, bool virtual)
39{
40 xbps_object_t obj;
41 xbps_object_iterator_t iter;
43 bool found = false;
44
45 assert(array);
46 assert(str);
47
48 iter = xbps_array_iterator(array);
49 if (!iter)
50 return NULL;
51
52 while ((obj = xbps_object_iterator_next(iter))) {
53 const char *pkgver = NULL;
54 char pkgname[XBPS_NAME_SIZE] = {0};
55
56 if (!xbps_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver)) {
57 continue;
58 }
59 if (virtual) {
60 /*
61 * Check if package pattern matches
62 * any virtual package version in dictionary.
63 */
64 found = xbps_match_virtual_pkg_in_dict(obj, str);
65 if (found)
66 break;
67 } else if (xbps_pkgpattern_version(str)) {
68 /* match by pattern against pkgver */
69 if (xbps_pkgpattern_match(pkgver, str)) {
70 found = true;
71 break;
72 }
73 } else if (xbps_pkg_version(str)) {
74 /* match by exact pkgver */
75 if (strcmp(str, pkgver) == 0) {
76 found = true;
77 break;
78 }
79 } else {
80 if (!xbps_pkg_name(pkgname, sizeof(pkgname), pkgver)) {
81 abort();
82 }
83 /* match by pkgname */
84 if (strcmp(pkgname, str) == 0) {
85 found = true;
86 break;
87 }
88 }
89 }
90 xbps_object_iterator_release(iter);
91
92 ttype = xbps_transaction_pkg_type(obj);
93 if (found && tt && (ttype != tt)) {
94 found = false;
95 }
96 if (!found) {
97 errno = ENOENT;
98 return NULL;
99 }
100 return obj;
101}
102
103xbps_dictionary_t HIDDEN
104xbps_find_pkg_in_array(xbps_array_t a, const char *s, xbps_trans_type_t tt)
105{
106 assert(xbps_object_type(a) == XBPS_TYPE_ARRAY);
107 assert(s);
108
109 return get_pkg_in_array(a, s, tt, false);
110}
111
112xbps_dictionary_t HIDDEN
113xbps_find_virtualpkg_in_array(struct xbps_handle *xhp,
114 xbps_array_t a,
115 const char *s,
117{
118 xbps_dictionary_t pkgd;
119 const char *vpkg;
120
121 assert(xhp);
122 assert(xbps_object_type(a) == XBPS_TYPE_ARRAY);
123 assert(s);
124
125 if ((vpkg = vpkg_user_conf(xhp, s))) {
126 if ((pkgd = get_pkg_in_array(a, vpkg, tt, true)))
127 return pkgd;
128 }
129
130 return get_pkg_in_array(a, s, tt, true);
131}
132
133static xbps_dictionary_t
134match_pkg_by_pkgver(xbps_dictionary_t repod, const char *p)
135{
136 xbps_dictionary_t d = NULL;
137 const char *pkgver = NULL;
138 char pkgname[XBPS_NAME_SIZE] = {0};
139
140 assert(repod);
141 assert(p);
142
143 /* exact match by pkgver */
144 if (!xbps_pkg_name(pkgname, sizeof(pkgname), p)) {
145 xbps_error_printf("invalid pkgver: %s\n", p);
146 errno = EINVAL;
147 return NULL;
148 }
149
150 d = xbps_dictionary_get(repod, pkgname);
151 if (!d) {
152 errno = ENOENT;
153 return NULL;
154 }
155 if (!xbps_dictionary_get_cstring_nocopy(d, "pkgver", &pkgver)) {
156 xbps_error_printf("missing `pkgver` property\n");
157 errno = EINVAL;
158 return NULL;
159 }
160 if (strcmp(pkgver, p) != 0) {
161 errno = ENOENT;
162 return NULL;
163 }
164
165 return d;
166}
167
168static xbps_dictionary_t
169match_pkg_by_pattern(xbps_dictionary_t repod, const char *p)
170{
171 xbps_dictionary_t d = NULL;
172 const char *pkgver = NULL;
173 char pkgname[XBPS_NAME_SIZE] = {0};
174
175 assert(repod);
176 assert(p);
177
178 /* match by pkgpattern in pkgver */
179 if (!xbps_pkgpattern_name(pkgname, sizeof(pkgname), p)) {
180 if (xbps_pkg_name(pkgname, sizeof(pkgname), p)) {
181 return match_pkg_by_pkgver(repod, p);
182 }
183 xbps_error_printf("invalid pkgpattern: %s\n", p);
184 errno = EINVAL;
185 return NULL;
186 }
187
188 d = xbps_dictionary_get(repod, pkgname);
189 if (!d) {
190 errno = ENOENT;
191 return NULL;
192 }
193 if (!xbps_dictionary_get_cstring_nocopy(d, "pkgver", &pkgver)) {
194 xbps_error_printf("missing `pkgver` property`\n");
195 errno = EINVAL;
196 return NULL;
197 }
198 if (!xbps_pkgpattern_match(pkgver, p)) {
199 errno = ENOENT;
200 return NULL;
201 }
202
203 return d;
204}
205
206const char HIDDEN *
207vpkg_user_conf(struct xbps_handle *xhp, const char *vpkg)
208{
209 char namebuf[XBPS_NAME_SIZE];
210 xbps_dictionary_t providers;
211 xbps_object_t obj;
212 xbps_object_iterator_t iter;
213 const char *pkg = NULL;
214 const char *pkgname;
215 bool found = false;
216 enum { PKGPATTERN, PKGVER, PKGNAME } match;
217
218 assert(vpkg);
219
220
221 if (xbps_pkgpattern_name(namebuf, sizeof(namebuf), vpkg)) {
222 match = PKGPATTERN;
223 pkgname = namebuf;
224 } else if (xbps_pkg_name(namebuf, sizeof(namebuf), vpkg)) {
225 match = PKGVER;
226 pkgname = namebuf;
227 } else {
228 match = PKGNAME;
229 pkgname = vpkg;
230 }
231
232 providers = xbps_dictionary_get(xhp->vpkgd, pkgname);
233 if (!providers)
234 return NULL;
235
236 iter = xbps_dictionary_iterator(providers);
237 assert(iter);
238
239 while ((obj = xbps_object_iterator_next(iter))) {
240 xbps_string_t rpkg;
241 char buf[XBPS_NAME_SIZE] = {0};
242 const char *vpkg_conf = NULL, *vpkgname = NULL;
243
244 vpkg_conf = xbps_dictionary_keysym_cstring_nocopy(obj);
245 rpkg = xbps_dictionary_get_keysym(providers, obj);
246 pkg = xbps_string_cstring_nocopy(rpkg);
247
248 if (xbps_pkg_version(vpkg_conf)) {
249 if (!xbps_pkg_name(buf, sizeof(buf), vpkg_conf)) {
250 abort();
251 }
252 vpkgname = buf;
253 } else {
254 vpkgname = vpkg_conf;
255 }
256
257 switch (match) {
258 case PKGPATTERN:
259 if (xbps_pkg_version(vpkg_conf)) {
260 if (!xbps_pkgpattern_match(vpkg_conf, vpkg)) {
261 continue;
262 }
263 } else {
264 xbps_warn_printf("invalid: %s\n", vpkg_conf);
265 }
266 break;
267 case PKGVER:
268 if (strcmp(buf, vpkgname) != 0) {
269 continue;
270 }
271 break;
272 case PKGNAME:
273 if (strcmp(vpkg, vpkgname) != 0) {
274 continue;
275 }
276 break;
277 }
278 xbps_dbg_printf("%s: vpkg_conf %s pkg %s vpkgname %s\n", __func__, vpkg_conf, pkg, vpkgname);
279 found = true;
280 break;
281 }
282 xbps_object_iterator_release(iter);
283
284 return found ? pkg : NULL;
285}
286
287xbps_dictionary_t HIDDEN
288xbps_find_virtualpkg_in_conf(struct xbps_handle *xhp,
289 xbps_dictionary_t d,
290 const char *pkg)
291{
292 xbps_object_iterator_t iter;
293 xbps_object_t obj;
294 xbps_dictionary_t providers;
295 xbps_dictionary_t pkgd = NULL;
296 const char *cur;
297
298 if (!xhp->vpkgd_conf)
299 return NULL;
300
301 providers = xbps_dictionary_get(xhp->vpkgd_conf, pkg);
302 if (!providers)
303 return NULL;
304
305 iter = xbps_dictionary_iterator(providers);
306 assert(iter);
307
308 while ((obj = xbps_object_iterator_next(iter))) {
309 xbps_string_t rpkg;
310 char buf[XBPS_NAME_SIZE] = {0};
311 const char *vpkg_conf = NULL, *vpkgname = NULL;
312
313 vpkg_conf = xbps_dictionary_keysym_cstring_nocopy(obj);
314 rpkg = xbps_dictionary_get_keysym(providers, obj);
315 cur = xbps_string_cstring_nocopy(rpkg);
316 assert(cur);
317 if (xbps_pkg_version(vpkg_conf)) {
318 if (!xbps_pkg_name(buf, sizeof(buf), vpkg_conf)) {
319 abort();
320 }
321 vpkgname = buf;
322 } else {
323 vpkgname = vpkg_conf;
324 }
325
326 if (xbps_pkgpattern_version(pkg)) {
327 if (xbps_pkg_version(vpkg_conf)) {
328 if (!xbps_pkgpattern_match(vpkg_conf, pkg)) {
329 continue;
330 }
331 } else {
332 char *vpkgver = xbps_xasprintf("%s-999999_1", vpkg_conf);
333 if (!xbps_pkgpattern_match(vpkgver, pkg)) {
334 free(vpkgver);
335 continue;
336 }
337 free(vpkgver);
338 }
339 } else if (xbps_pkg_version(pkg)) {
340 // XXX: this is the old behaviour of only matching pkgname's,
341 // this is kinda wrong when compared to matching patterns
342 // where all variants are tried.
343 if (!xbps_pkg_name(buf, sizeof(buf), pkg)) {
344 abort();
345 }
346 if (strcmp(buf, vpkgname)) {
347 continue;
348 }
349 } else {
350 if (strcmp(pkg, vpkgname)) {
351 continue;
352 }
353 }
354 xbps_dbg_printf("%s: found: %s %s %s\n", __func__, vpkg_conf, cur, vpkgname);
355
356 /* Try matching vpkg from configuration files */
358 pkgd = match_pkg_by_pattern(d, cur);
359 else if (xbps_pkg_version(cur))
360 pkgd = match_pkg_by_pkgver(d, cur);
361 else
362 pkgd = xbps_dictionary_get(d, cur);
363 break;
364 }
365 xbps_object_iterator_release(iter);
366
367 return pkgd;
368}
369
370xbps_dictionary_t HIDDEN
371xbps_find_virtualpkg_in_dict(struct xbps_handle *xhp,
372 xbps_dictionary_t d,
373 const char *pkg)
374{
375 xbps_object_t obj;
376 xbps_object_iterator_t iter;
377 xbps_dictionary_t pkgd = NULL;
378 const char *vpkg;
379
380 // XXX: this is bad, dict != pkgdb,
381 /* Try matching vpkg via xhp->vpkgd */
382 vpkg = vpkg_user_conf(xhp, pkg);
383 if (vpkg != NULL) {
384 if (xbps_pkgpattern_version(vpkg))
385 pkgd = match_pkg_by_pattern(d, vpkg);
386 else if (xbps_pkg_version(vpkg))
387 pkgd = match_pkg_by_pkgver(d, vpkg);
388 else
389 pkgd = xbps_dictionary_get(d, vpkg);
390
391 if (pkgd)
392 return pkgd;
393 }
394 /* ... otherwise match the first one in dictionary */
395 iter = xbps_dictionary_iterator(d);
396 assert(iter);
397
398 while ((obj = xbps_object_iterator_next(iter))) {
399 pkgd = xbps_dictionary_get_keysym(d, obj);
400 if (xbps_match_virtual_pkg_in_dict(pkgd, pkg)) {
401 xbps_object_iterator_release(iter);
402 return pkgd;
403 }
404 }
405 xbps_object_iterator_release(iter);
406
407 return NULL;
408}
409
410xbps_dictionary_t HIDDEN
411xbps_find_pkg_in_dict(xbps_dictionary_t d, const char *pkg)
412{
413 xbps_dictionary_t pkgd = NULL;
414
416 pkgd = match_pkg_by_pattern(d, pkg);
417 else if (xbps_pkg_version(pkg))
418 pkgd = match_pkg_by_pkgver(d, pkg);
419 else
420 pkgd = xbps_dictionary_get(d, pkg);
421
422 return pkgd;
423}
Generic XBPS structure handler for initialization.
Definition xbps.h:559
bool xbps_match_virtual_pkg_in_dict(xbps_dictionary_t pkgd, const char *str)
Definition plist_match.c:58
xbps_trans_type_t xbps_transaction_pkg_type(xbps_dictionary_t pkg_repod)
xbps_trans_type_t
Definition xbps.h:1331
char * xbps_xasprintf(const char *fmt,...) __attribute__((format(printf
const char * xbps_pkgpattern_version(const char *pattern)
Definition util.c:317
bool xbps_pkg_name(char *dst, size_t len, const char *pkg)
Definition util.c:253
int xbps_pkgpattern_match(const char *pkgver, const char *pattern)
Definition util.c:530
const char * xbps_pkg_version(const char *pkg)
Definition util.c:124
bool xbps_pkgpattern_name(char *dst, size_t len, const char *pattern)
Definition util.c:289