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