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