Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2014, Vsevolod Stakhov
3 : : * Copyright (c) 2024, Baptiste Daroussin <bapt@FreeBSD.org>
4 : : * Copyright (c) 2023, Serenity Cyber Security, LLC
5 : : * Author: Gleb Popov <arrowd@FreeBSD.org>
6 : : *
7 : : * Redistribution and use in source and binary forms, with or without
8 : : * modification, are permitted provided that the following conditions are met:
9 : : * * Redistributions of source code must retain the above copyright
10 : : * notice, this list of conditions and the following disclaimer.
11 : : * * Redistributions in binary form must reproduce the above copyright
12 : : * notice, this list of conditions and the following disclaimer in the
13 : : * documentation and/or other materials provided with the distribution.
14 : : *
15 : : * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
16 : : * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 : : * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 : : * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
19 : : * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 : : * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 : : * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 : : * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 : : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 : : * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 : : */
26 : :
27 : : #include <assert.h>
28 : : #include <errno.h>
29 : : #include <regex.h>
30 : : #include <grp.h>
31 : : #include <stdlib.h>
32 : : #include <stdio.h>
33 : : #include <stdbool.h>
34 : : #include <string.h>
35 : : #include <unistd.h>
36 : : #include <libgen.h>
37 : : #include <fcntl.h>
38 : : #include <fnmatch.h>
39 : :
40 : : #include <sqlite3.h>
41 : :
42 : : #include "pkg.h"
43 : : #include "private/event.h"
44 : : #include "private/pkg.h"
45 : : #include "private/pkgdb.h"
46 : : #include "private/utils.h"
47 : : #include "binary.h"
48 : :
49 : : static struct pkg_repo_it* pkg_repo_binary_it_new(struct pkg_repo *repo,
50 : : sqlite3_stmt *s, short flags);
51 : :
52 : : struct pkg_repo_group {
53 : : size_t index;
54 : : ucl_object_t *groups;
55 : : };
56 : : static int pkg_repo_binary_it_next(struct pkg_repo_it *it, struct pkg **pkg_p, unsigned flags);
57 : : static void pkg_repo_binary_it_free(struct pkg_repo_it *it);
58 : : static void pkg_repo_binary_it_reset(struct pkg_repo_it *it);
59 : :
60 : : static int pkg_repo_binary_group_it_next(struct pkg_repo_it *it, struct pkg **pkg_p, unsigned flags);
61 : : static void pkg_repo_binary_group_it_free(struct pkg_repo_it *it);
62 : : static void pkg_repo_binary_group_it_reset(struct pkg_repo_it *it);
63 : :
64 : : static struct pkg_repo_it_ops pkg_repo_binary_it_ops = {
65 : : .next = pkg_repo_binary_it_next,
66 : : .free = pkg_repo_binary_it_free,
67 : : .reset = pkg_repo_binary_it_reset
68 : : };
69 : :
70 : : static struct pkg_repo_it_ops pkg_repo_binary_group_it_ops = {
71 : : .next = pkg_repo_binary_group_it_next,
72 : : .free = pkg_repo_binary_group_it_free,
73 : : .reset = pkg_repo_binary_group_it_reset
74 : : };
75 : :
76 : : static struct pkg_repo_it*
77 : 609 : pkg_repo_binary_it_new(struct pkg_repo *repo, sqlite3_stmt *s, short flags)
78 : : {
79 : : struct pkg_repo_it *it;
80 : : struct pkgdb fakedb;
81 : :
82 : 609 : it = xmalloc(sizeof(*it));
83 : :
84 : 609 : it->ops = &pkg_repo_binary_it_ops;
85 : 609 : it->flags = flags;
86 : 609 : it->repo = repo;
87 : :
88 [ + - ]: 609 : fakedb.sqlite = PRIV_GET(repo);
89 : 609 : it->data = pkgdb_it_new_sqlite(&fakedb, s, PKG_REMOTE, flags);
90 : :
91 [ + - ]: 609 : if (it->data == NULL) {
92 : 0 : free(it);
93 : 0 : return (NULL);
94 : : }
95 : :
96 : 609 : return (it);
97 : 609 : }
98 : :
99 : : static struct pkg_repo_it *
100 : 0 : pkg_repo_binary_group_it_new(struct pkg_repo *repo, ucl_object_t *matching)
101 : : {
102 : : struct pkg_repo_group *prg;
103 : : struct pkg_repo_it *it;
104 : :
105 : 0 : it = xcalloc(1, sizeof(*it));
106 : 0 : prg = xcalloc(1, sizeof(*prg));
107 : 0 : prg->groups = matching;
108 : 0 : it->repo = repo;
109 : 0 : it->ops = &pkg_repo_binary_group_it_ops;
110 : 0 : it->data = prg;
111 : :
112 : 0 : return (it);
113 : : }
114 : :
115 : : static int
116 : 1005 : pkg_repo_binary_it_next(struct pkg_repo_it *it, struct pkg **pkg_p, unsigned flags)
117 : : {
118 : 1005 : return (pkgdb_it_next(it->data, pkg_p, flags));
119 : : }
120 : :
121 : : static int
122 : 0 : pkg_repo_binary_group_it_next(struct pkg_repo_it *it, struct pkg **pkg_p, unsigned flags __unused)
123 : : {
124 : : int ret;
125 : : struct pkg_repo_group *prg;
126 : : const ucl_object_t *o, *el, *ar;
127 : 0 : ucl_object_iter_t oit = NULL;
128 : :
129 : 0 : prg = it->data;
130 [ # # ]: 0 : if (prg->index == ucl_array_size(prg->groups))
131 : 0 : return (EPKG_END);
132 : :
133 : 0 : el = ucl_array_find_index(prg->groups, prg->index);
134 : 0 : prg->index++;
135 : 0 : pkg_free(*pkg_p);
136 [ # # ]: 0 : if ((ret = pkg_new(pkg_p, PKG_GROUP_REMOTE)) != EPKG_OK)
137 : 0 : return (ret);
138 : 0 : o = ucl_object_find_key(el, "name");
139 : 0 : xasprintf(&(*pkg_p)->name, ucl_object_tostring(o));
140 : 0 : xasprintf(&(*pkg_p)->uid, "@%s", (*pkg_p)->name);
141 : 0 : o = ucl_object_find_key(el, "comment");
142 : 0 : xasprintf(&(*pkg_p)->comment, ucl_object_tostring(o));
143 : 0 : ar = ucl_object_find_key(el, "depends");
144 [ # # ]: 0 : while ((o = ucl_iterate_object(ar, &oit, true))) {
145 : 0 : pkg_adddep(*pkg_p, ucl_object_tostring(o), NULL, NULL, false);
146 : : }
147 : 0 : pkg_kv_add(&(*pkg_p)->annotations, "repository", it->repo->name, "annotation");
148 : :
149 : 0 : return (EPKG_OK);
150 : 0 : }
151 : :
152 : : static void
153 : 609 : pkg_repo_binary_it_free(struct pkg_repo_it *it)
154 : : {
155 : 609 : pkgdb_it_free(it->data);
156 : 609 : free(it);
157 : 609 : }
158 : :
159 : : static void
160 : 0 : pkg_repo_binary_group_it_free(struct pkg_repo_it *it)
161 : : {
162 : 0 : struct pkg_repo_group *prg = it->data;
163 : 0 : free(prg->groups);
164 : 0 : free(prg);
165 : 0 : free(it);
166 : 0 : }
167 : :
168 : : static void
169 : 0 : pkg_repo_binary_it_reset(struct pkg_repo_it *it)
170 : : {
171 : 0 : pkgdb_it_reset(it->data);
172 : 0 : }
173 : :
174 : : static void
175 : 0 : pkg_repo_binary_group_it_reset(struct pkg_repo_it *it)
176 : : {
177 : 0 : struct pkg_repo_group *prg = it->data;
178 : :
179 : 0 : prg->index = 0;
180 : 0 : }
181 : :
182 : : struct pkg_repo_it *
183 : 0 : pkg_repo_binary_groupquery(struct pkg_repo *repo, const char *pattern, match_t match)
184 : : {
185 : 0 : return (pkg_repo_binary_groupsearch(repo, pattern, match, FIELD_NAME));
186 : : }
187 : :
188 : : struct pkg_repo_it *
189 : 587 : pkg_repo_binary_query(struct pkg_repo *repo, const char *cond, const char *pattern, match_t match)
190 : : {
191 [ + - ]: 587 : sqlite3 *sqlite = PRIV_GET(repo);
192 : 587 : sqlite3_stmt *stmt = NULL;
193 : 587 : char *sql = NULL;
194 : 587 : const char *comp = NULL;
195 : 587 : const char basesql_quick[] = ""
196 : : "SELECT DISTINCT(p.id), origin, p.name, p.name as uniqueid, version, comment, "
197 : : "prefix, desc, arch, maintainer, www, "
198 : : "licenselogic, flatsize, pkgsize, "
199 : : "cksum, manifestdigest, path AS repopath, '%s' AS dbname "
200 : : "FROM packages as p "
201 : : " %s "
202 : : "%s%s%s "
203 : : "ORDER BY p.name;";
204 : 587 : const char basesql[] = ""
205 : : "WITH flavors AS "
206 : : " (SELECT package_id, value.annotation AS flavor FROM pkg_annotation "
207 : : " LEFT JOIN annotation tag ON pkg_annotation.tag_id = tag.annotation_id "
208 : : " LEFT JOIN annotation value ON pkg_annotation.value_id = value.annotation_id "
209 : : " WHERE tag.annotation = 'flavor') "
210 : :
211 : : "SELECT DISTINCT(p.id), origin, p.name, p.name as uniqueid, version, comment, "
212 : : "prefix, desc, arch, maintainer, www, "
213 : : "licenselogic, flatsize, pkgsize, "
214 : : "cksum, manifestdigest, path AS repopath, '%s' AS dbname "
215 : : "FROM packages as p "
216 : : "LEFT JOIN pkg_categories ON p.id = pkg_categories.package_id "
217 : : "LEFT JOIN categories ON categories.id = pkg_categories.category_id "
218 : : "LEFT JOIN flavors ON flavors.package_id = p.id "
219 : : " %s "
220 : : "%s%s%s "
221 : : "ORDER BY p.name;";
222 : :
223 [ + + ]: 587 : const char *bsql = (match == MATCH_INTERNAL) ? basesql_quick : basesql;
224 : :
225 [ + + + - : 587 : if (match != MATCH_ALL && (pattern == NULL || pattern[0] == '\0'))
- + ]
226 : 0 : return (NULL);
227 : :
228 : 587 : comp = pkgdb_get_pattern_query(pattern, match);
229 [ + - ]: 587 : if (comp == NULL)
230 : 0 : comp = "";
231 [ + + ]: 587 : if (cond == NULL)
232 : 582 : xasprintf(&sql, bsql, repo->name, comp, "", "", "");
233 : : else
234 : 10 : xasprintf(&sql, bsql, repo->name, comp,
235 : 5 : comp[0] != '\0' ? "AND (" : "WHERE ( ", cond + 7, " )");
236 : :
237 : 587 : stmt = prepare_sql(sqlite, sql);
238 : 587 : free(sql);
239 [ + - ]: 587 : if (stmt == NULL)
240 : 0 : return (NULL);
241 : :
242 [ + + ]: 587 : if (match != MATCH_ALL)
243 : 345 : sqlite3_bind_text(stmt, 1, pattern, -1, SQLITE_TRANSIENT);
244 : 587 : pkgdb_debug(4, stmt);
245 : :
246 : 587 : return (pkg_repo_binary_it_new(repo, stmt, PKGDB_IT_FLAG_ONCE));
247 : 587 : }
248 : :
249 : : struct pkg_repo_it *
250 : 5 : pkg_repo_binary_shlib_provide(struct pkg_repo *repo, const char *require)
251 : : {
252 : : sqlite3_stmt *stmt;
253 [ + - ]: 5 : sqlite3 *sqlite = PRIV_GET(repo);
254 : 5 : char *sql = NULL;
255 : 5 : const char basesql[] = ""
256 : : "SELECT p.id, p.origin, p.name, p.version, p.comment, "
257 : : "p.name as uniqueid, "
258 : : "p.prefix, p.desc, p.arch, p.maintainer, p.www, "
259 : : "p.licenselogic, p.flatsize, p.pkgsize, "
260 : : "p.cksum, p.manifestdigest, p.path AS repopath, '%s' AS dbname "
261 : : "FROM packages AS p INNER JOIN pkg_shlibs_provided AS ps ON "
262 : : "p.id = ps.package_id "
263 : : "WHERE ps.shlib_id IN (SELECT id FROM shlibs WHERE "
264 : : "name BETWEEN ?1 AND ?1 || '.9');";
265 : :
266 : 5 : xasprintf(&sql, basesql, repo->name);
267 : :
268 : 5 : stmt = prepare_sql(sqlite, sql);
269 : 5 : free(sql);
270 [ + - ]: 5 : if (stmt == NULL)
271 : 0 : return (NULL);
272 : :
273 : 5 : sqlite3_bind_text(stmt, 1, require, -1, SQLITE_TRANSIENT);
274 : 5 : pkgdb_debug(4, stmt);
275 : :
276 : 5 : return (pkg_repo_binary_it_new(repo, stmt, PKGDB_IT_FLAG_ONCE));
277 : 5 : }
278 : :
279 : : struct pkg_repo_it *
280 : 8 : pkg_repo_binary_provide(struct pkg_repo *repo, const char *require)
281 : : {
282 : : sqlite3_stmt *stmt;
283 [ + - ]: 8 : sqlite3 *sqlite = PRIV_GET(repo);
284 : 8 : char *sql = NULL;
285 : 8 : const char basesql[] = ""
286 : : "SELECT p.id, p.origin, p.name, p.version, p.comment, "
287 : : "p.name as uniqueid, "
288 : : "p.prefix, p.desc, p.arch, p.maintainer, p.www, "
289 : : "p.licenselogic, p.flatsize, p.pkgsize, "
290 : : "p.cksum, p.manifestdigest, p.path AS repopath, '%s' AS dbname "
291 : : "FROM packages AS p INNER JOIN pkg_provides AS ps ON "
292 : : "p.id = ps.package_id "
293 : : "WHERE ps.provide_id IN (SELECT id from provides WHERE "
294 : : "provide = ?1 );";
295 : :
296 : 8 : xasprintf(&sql, basesql, repo->name);
297 : :
298 : 8 : stmt = prepare_sql(sqlite, sql);
299 : 8 : free(sql);
300 [ + - ]: 8 : if (stmt == NULL)
301 : 0 : return (NULL);
302 : :
303 : 8 : sqlite3_bind_text(stmt, 1, require, -1, SQLITE_TRANSIENT);
304 : 8 : pkgdb_debug(4, stmt);
305 : :
306 : 8 : return (pkg_repo_binary_it_new(repo, stmt, PKGDB_IT_FLAG_ONCE));
307 : 8 : }
308 : :
309 : : struct pkg_repo_it *
310 : 0 : pkg_repo_binary_shlib_require(struct pkg_repo *repo, const char *provide)
311 : : {
312 : : sqlite3_stmt *stmt;
313 [ # # ]: 0 : sqlite3 *sqlite = PRIV_GET(repo);
314 : 0 : char *sql = NULL;
315 : 0 : const char basesql[] = ""
316 : : "SELECT p.id, p.origin, p.name, p.version, p.comment, "
317 : : "p.name as uniqueid, "
318 : : "p.prefix, p.desc, p.arch, p.maintainer, p.www, "
319 : : "p.licenselogic, p.flatsize, p.pkgsize, "
320 : : "p.cksum, p.manifestdigest, p.path AS repopath, '%s' AS dbname "
321 : : "FROM packages AS p INNER JOIN pkg_shlibs_required AS ps ON "
322 : : "p.id = ps.package_id "
323 : : "WHERE ps.shlib_id = (SELECT id FROM shlibs WHERE name=?1);";
324 : :
325 : 0 : xasprintf(&sql, basesql, repo->name);
326 : :
327 : 0 : stmt = prepare_sql(sqlite, sql);
328 : 0 : free(sql);
329 [ # # ]: 0 : if (stmt == NULL)
330 : 0 : return (NULL);
331 : :
332 : 0 : pkg_debug(1, "> loading provides");
333 : 0 : sqlite3_bind_text(stmt, 1, provide, -1, SQLITE_TRANSIENT);
334 : 0 : pkgdb_debug(4, stmt);
335 : :
336 : 0 : return (pkg_repo_binary_it_new(repo, stmt, PKGDB_IT_FLAG_ONCE));
337 : 0 : }
338 : :
339 : : struct pkg_repo_it *
340 : 0 : pkg_repo_binary_require(struct pkg_repo *repo, const char *provide)
341 : : {
342 : : sqlite3_stmt *stmt;
343 [ # # ]: 0 : sqlite3 *sqlite = PRIV_GET(repo);
344 : 0 : char *sql = NULL;
345 : 0 : const char basesql[] = ""
346 : : "SELECT p.id, p.origin, p.name, p.version, p.comment, "
347 : : "p.name as uniqueid, "
348 : : "p.prefix, p.desc, p.arch, p.maintainer, p.www, "
349 : : "p.licenselogic, p.flatsize, p.pkgsize, "
350 : : "p.cksum, p.manifestdigest, p.path AS repopath, '%s' AS dbname "
351 : : "FROM packages AS p INNER JOIN pkg_requires AS ps ON "
352 : : "p.id = ps.package_id "
353 : : "WHERE ps.require_id = (SELECT id FROM requires WHERE require=?1);";
354 : :
355 : 0 : xasprintf(&sql, basesql, repo->name);
356 : :
357 : 0 : stmt = prepare_sql(sqlite, sql);
358 : 0 : free(sql);
359 [ # # ]: 0 : if (stmt == NULL)
360 : 0 : return (NULL);
361 : :
362 : 0 : sqlite3_bind_text(stmt, 1, provide, -1, SQLITE_TRANSIENT);
363 : 0 : pkgdb_debug(4, stmt);
364 : :
365 : 0 : return (pkg_repo_binary_it_new(repo, stmt, PKGDB_IT_FLAG_ONCE));
366 : 0 : }
367 : :
368 : : static const char *
369 : 9 : pkg_repo_binary_search_how(match_t match)
370 : : {
371 : 9 : const char *how = NULL;
372 : :
373 [ - - - - : 9 : switch (match) {
+ + ]
374 : : case MATCH_ALL:
375 : 0 : how = "TRUE";
376 : 0 : break;
377 : : case MATCH_INTERNAL:
378 : 0 : how = "%s = ?1";
379 : 0 : break;
380 : : case MATCH_EXACT:
381 [ # # ]: 0 : if (pkgdb_case_sensitive())
382 : 0 : how = "%s = ?1";
383 : : else
384 : 0 : how = "%s = ?1 COLLATE NOCASE";
385 : 0 : break;
386 : : case MATCH_GLOB:
387 [ - + ]: 1 : if (pkgdb_case_sensitive())
388 : 0 : how = "%s GLOB ?1";
389 : : else
390 : 1 : how = "lower(%s) GLOB lower(?1)";
391 : 1 : break;
392 : : case MATCH_REGEX:
393 : 8 : how = "%s REGEXP ?1";
394 : 8 : break;
395 : : }
396 : :
397 : 9 : return (how);
398 : : }
399 : :
400 : : static int
401 : 9 : pkg_repo_binary_build_search_query(xstring *sql, match_t match,
402 : : pkgdb_field field, pkgdb_field sort)
403 : : {
404 : : const char *how;
405 : 9 : const char *what = NULL;
406 : 9 : const char *orderby = NULL;
407 : :
408 : 9 : how = pkg_repo_binary_search_how(match);
409 : :
410 [ - - + - : 9 : switch (field) {
- + - - ]
411 : : case FIELD_NONE:
412 : 0 : what = NULL;
413 : 0 : break;
414 : : case FIELD_ORIGIN:
415 : 0 : what = "categories.name || substr(origin, instr(origin, '/'))";
416 : 0 : break;
417 : : case FIELD_FLAVOR:
418 : 0 : what = "categories.name || substr(origin, instr(origin, '/')) || '@' || flavor";
419 : 0 : break;
420 : : case FIELD_NAME:
421 : 1 : what = "p.name";
422 : 1 : break;
423 : : case FIELD_NAMEVER:
424 : 8 : what = "p.name || '-' || version";
425 : 8 : break;
426 : : case FIELD_COMMENT:
427 : 0 : what = "comment";
428 : 0 : break;
429 : : case FIELD_DESC:
430 : 0 : what = "desc";
431 : 0 : break;
432 : : }
433 : :
434 [ + - - + ]: 9 : if (what != NULL && how != NULL)
435 : 9 : fprintf(sql->fp, how, what);
436 : :
437 [ - - - - : 9 : switch (sort) {
+ + - - ]
438 : : case FIELD_NONE:
439 : 1 : orderby = NULL;
440 : 1 : break;
441 : : case FIELD_ORIGIN:
442 : 0 : orderby = " ORDER BY origin";
443 : 0 : break;
444 : : case FIELD_FLAVOR:
445 : 0 : orderby = " ORDER BY p.name";
446 : : case FIELD_NAME:
447 : 0 : orderby = " ORDER BY p.name";
448 : 0 : break;
449 : : case FIELD_NAMEVER:
450 : 8 : orderby = " ORDER BY p.name, version";
451 : 8 : break;
452 : : case FIELD_COMMENT:
453 : 0 : orderby = " ORDER BY comment";
454 : 0 : break;
455 : : case FIELD_DESC:
456 : 0 : orderby = " ORDER BY desc";
457 : 0 : break;
458 : : }
459 : :
460 [ + + ]: 9 : if (orderby != NULL)
461 : 8 : fprintf(sql->fp, "%s", orderby);
462 : :
463 : 9 : return (EPKG_OK);
464 : : }
465 : :
466 : : struct pkg_repo_it *
467 : 9 : pkg_repo_binary_search(struct pkg_repo *repo, const char *pattern, match_t match,
468 : : pkgdb_field field, pkgdb_field sort)
469 : : {
470 [ + - ]: 9 : sqlite3 *sqlite = PRIV_GET(repo);
471 : 9 : sqlite3_stmt *stmt = NULL;
472 : 9 : xstring *sql = NULL;
473 : 9 : char *sqlcmd = NULL;
474 : 9 : const char *multireposql = ""
475 : : "WITH flavors AS "
476 : : " (SELECT package_id, value.annotation AS flavor FROM pkg_annotation "
477 : : " LEFT JOIN annotation tag ON pkg_annotation.tag_id = tag.annotation_id "
478 : : " LEFT JOIN annotation value ON pkg_annotation.value_id = value.annotation_id "
479 : : " WHERE tag.annotation = 'flavor') "
480 : : "SELECT DISTINCT p.id, origin, p.name, version, comment, "
481 : : "prefix, desc, arch, maintainer, www, "
482 : : "licenselogic, flatsize, pkgsize, "
483 : : "cksum, path AS repopath, '%1$s' AS dbname, '%2$s' AS repourl "
484 : : "FROM packages as p "
485 : : "LEFT JOIN pkg_categories ON p.id = pkg_categories.package_id "
486 : : "LEFT JOIN categories ON categories.id = pkg_categories.category_id "
487 : : "LEFT JOIN flavors ON flavors.package_id = p.id ";
488 : :
489 [ - + + - : 9 : if (match != MATCH_ALL && (pattern == NULL || pattern[0] == '\0'))
- + ]
490 : 0 : return (NULL);
491 : :
492 : 9 : sql = xstring_new();
493 : 9 : fprintf(sql->fp, multireposql, repo->name, repo->url);
494 : :
495 : : /* close the UNIONs and build the search query */
496 : 9 : fprintf(sql->fp, "%s", "WHERE ");
497 : :
498 : 9 : pkg_repo_binary_build_search_query(sql, match, field, sort);
499 : 9 : fprintf(sql->fp, "%s", ";");
500 : 9 : sqlcmd = xstring_get(sql);
501 : :
502 : 9 : stmt = prepare_sql(sqlite, sqlcmd);
503 : 9 : free(sqlcmd);
504 [ + - ]: 9 : if (stmt == NULL)
505 : 0 : return (NULL);
506 : :
507 : 9 : sqlite3_bind_text(stmt, 1, pattern, -1, SQLITE_TRANSIENT);
508 : 9 : pkgdb_debug(4, stmt);
509 : :
510 : 9 : return (pkg_repo_binary_it_new(repo, stmt, PKGDB_IT_FLAG_ONCE));
511 : 9 : }
512 : :
513 : : struct pkg_repo_it *
514 : 9 : pkg_repo_binary_groupsearch(struct pkg_repo *repo, const char *pattern, match_t match,
515 : : pkgdb_field field)
516 : : {
517 : : ucl_object_t *groups, *ar, *el;
518 : : const ucl_object_t *o;
519 : : const char *cmp;
520 : : struct ucl_parser *p;
521 : : int fd;
522 : 9 : regex_t *re = NULL;
523 : 9 : int flag = 0;
524 : 9 : bool in_comment = false;
525 : 9 : bool start_with = false;
526 : :
527 [ - + + - ]: 9 : switch (field) {
528 : : case FIELD_NAME:
529 : : case FIELD_NAMEVER:
530 : 9 : break;
531 : : case FIELD_COMMENT:
532 : 0 : in_comment = true;
533 : 0 : break;
534 : : default:
535 : : /* we cannot search in other fields */
536 : 0 : return (NULL);
537 : : }
538 : :
539 [ + + + - ]: 9 : if (repo->dfd == -1 && pkg_repo_open(repo) == EPKG_FATAL)
540 : 0 : return (NULL);
541 : 9 : fd = openat(repo->dfd, "groups.ucl", O_RDONLY|O_CLOEXEC);
542 [ + - ]: 9 : if (fd == -1)
543 : 0 : return (NULL);
544 : 9 : p = ucl_parser_new(0);
545 [ + - ]: 9 : if (!ucl_parser_add_fd(p, fd)) {
546 : 0 : pkg_emit_error("Error parsing groups for: %s'",
547 : 0 : repo->name);
548 : 0 : ucl_parser_free(p);
549 : 0 : close(fd);
550 : 0 : return (NULL);
551 : :
552 : : }
553 : 9 : groups = ucl_parser_get_object(p);
554 : 9 : ucl_parser_free(p);
555 : 9 : close(fd);
556 : :
557 [ - + ]: 9 : if (ucl_object_type(groups) != UCL_ARRAY) {
558 : 0 : ucl_object_unref(groups);
559 : 0 : return (NULL);
560 : : }
561 [ + - ]: 9 : if (*pattern == '@') {
562 : 0 : pattern++;
563 : 0 : start_with = true;
564 : 0 : }
565 : :
566 : 9 : ar = NULL;
567 [ - + ]: 9 : while (ucl_array_size(groups) > 0) {
568 : 0 : el = ucl_array_pop_first(groups);
569 [ # # ]: 0 : if (in_comment) {
570 : 0 : o = ucl_object_find_key(el, "comment");
571 : 0 : } else {
572 : 0 : o = ucl_object_find_key(el, "name");
573 : : }
574 [ # # ]: 0 : if (o == NULL) {
575 : 0 : ucl_object_unref(el);
576 : 0 : continue;
577 : : }
578 : 0 : cmp = ucl_object_tostring(o);
579 [ # # # # : 0 : switch (match) {
# # ]
580 : : case MATCH_ALL:
581 : 0 : break;
582 : : case MATCH_INTERNAL:
583 [ # # ]: 0 : if (!STREQ(cmp, pattern))
584 : 0 : continue;
585 : 0 : break;
586 : : case MATCH_EXACT:
587 [ # # ]: 0 : if (pkgdb_case_sensitive()) {
588 [ # # ]: 0 : if (!STREQ(cmp, pattern))
589 : 0 : continue;
590 : 0 : } else {
591 [ # # ]: 0 : if (!STRIEQ(cmp, pattern))
592 : 0 : continue;
593 : : }
594 : 0 : break;
595 : : case MATCH_GLOB:
596 [ # # ]: 0 : if (pkgdb_case_sensitive() != 0)
597 : 0 : flag = FNM_CASEFOLD;
598 [ # # ]: 0 : if (fnmatch(cmp, pattern, flag) == FNM_NOMATCH)
599 : 0 : continue;
600 : : case MATCH_REGEX:
601 [ # # ]: 0 : if (re == NULL) {
602 : 0 : char *newpattern = NULL;
603 : 0 : const char *pat = pattern;
604 : 0 : flag = REG_EXTENDED | REG_NOSUB;
605 [ # # ]: 0 : if (pkgdb_case_sensitive() != 0)
606 : 0 : flag |= REG_ICASE;
607 : 0 : re = xmalloc(sizeof(regex_t));
608 [ # # ]: 0 : if (start_with) {
609 : 0 : xasprintf(&newpattern, "^%s", pattern);
610 : 0 : pat = newpattern;
611 : 0 : }
612 [ # # ]: 0 : if (regcomp(re, pat, flag) != 0) {
613 : 0 : pkg_emit_error("Invalid regex: 'pattern'");
614 : 0 : ucl_object_unref(groups);
615 [ # # ]: 0 : if (ar != NULL)
616 : 0 : ucl_object_unref(ar);
617 : 0 : free(newpattern);
618 : 0 : return (NULL);
619 : : }
620 : 0 : free(newpattern);
621 : 0 : }
622 [ # # ]: 0 : if (regexec(re, cmp, 0, NULL, 0) == REG_NOMATCH)
623 : 0 : continue;
624 : 0 : }
625 [ # # ]: 0 : if (ar == NULL)
626 : 0 : ar = ucl_object_typed_new(UCL_ARRAY);
627 : 0 : ucl_array_append(ar, el);
628 : : }
629 : :
630 [ + - ]: 9 : if (re != NULL)
631 : 0 : regfree(re);
632 : 9 : ucl_object_unref(groups);
633 : :
634 [ - + ]: 9 : if (ar == NULL)
635 : 9 : return (NULL);
636 : :
637 : 0 : return (pkg_repo_binary_group_it_new(repo, ar));
638 : 9 : }
639 : :
640 : : int
641 : 504 : pkg_repo_binary_ensure_loaded(struct pkg_repo *repo,
642 : : struct pkg *pkg, unsigned flags)
643 : : {
644 [ + - ]: 504 : sqlite3 *sqlite = PRIV_GET(repo);
645 : 504 : struct pkg *cached = NULL;
646 : : char path[MAXPATHLEN];
647 : : int rc;
648 : :
649 [ - + ]: 504 : if (pkg->type == PKG_GROUP_REMOTE)
650 : 0 : return (EPKG_OK);
651 : 504 : flags &= PKG_LOAD_FILES|PKG_LOAD_DIRS;
652 : : /*
653 : : * If info is already present, done.
654 : : */
655 [ + + ]: 504 : if ((pkg->flags & flags) == flags) {
656 : 363 : return EPKG_OK;
657 : : }
658 [ - + ]: 141 : if (pkg->type == PKG_INSTALLED) {
659 : 0 : pkg_emit_error("cached package %s-%s: "
660 : : "attempting to load info from an installed package",
661 : 0 : pkg->name, pkg->version);
662 : 0 : return EPKG_FATAL;
663 : :
664 : : /* XXX If package is installed, get info from SQLite ??? */
665 : : rc = pkgdb_ensure_loaded_sqlite(sqlite, pkg, flags);
666 : : if (rc != EPKG_OK) {
667 : : return rc;
668 : : }
669 : : /* probably unnecessary */
670 : : if ((pkg->flags & flags) != flags) {
671 : : return EPKG_FATAL;
672 : : }
673 : : return rc;
674 : : }
675 : : /*
676 : : * Try to get that information from fetched package in cache
677 : : */
678 : :
679 [ + + ]: 141 : if (pkg_repo_cached_name(pkg, path, sizeof(path)) != EPKG_OK)
680 : 2 : return (EPKG_FATAL);
681 : :
682 : 139 : pkg_debug(1, "Binary> loading %s", path);
683 [ + + ]: 139 : if (pkg_open(&cached, path, PKG_OPEN_TRY) != EPKG_OK) {
684 : 2 : pkg_free(cached);
685 : 2 : return EPKG_FATAL;
686 : : }
687 : :
688 : : /* Now move required elements to the provided package */
689 : 137 : pkg_list_free(pkg, PKG_FILES);
690 : 137 : pkg_list_free(pkg, PKG_CONFIG_FILES);
691 : 137 : pkg_list_free(pkg, PKG_DIRS);
692 : 137 : pkg->files = cached->files;
693 : 137 : pkg->filehash = cached->filehash;
694 : 137 : pkg->config_files = cached->config_files;
695 : 137 : pkg->config_files_hash = cached->config_files_hash;
696 : 137 : pkg->dirs = cached->dirs;
697 : 137 : pkg->dirhash = cached->dirhash;
698 : 137 : cached->files = NULL;
699 : 137 : cached->filehash = NULL;
700 : 137 : cached->config_files = NULL;
701 : 137 : cached->config_files_hash = NULL;
702 : 137 : cached->dirs = NULL;
703 : 137 : cached->dirhash = NULL;
704 : :
705 : 137 : pkg_free(cached);
706 : 137 : pkg->flags |= flags;
707 : :
708 : 137 : return EPKG_OK;
709 : 504 : }
710 : :
711 : : int64_t
712 : 0 : pkg_repo_binary_stat(struct pkg_repo *repo, pkg_stats_t type)
713 : : {
714 [ # # ]: 0 : sqlite3 *sqlite = PRIV_GET(repo);
715 : 0 : sqlite3_stmt *stmt = NULL;
716 : 0 : int64_t stats = 0;
717 : 0 : const char *sql = NULL;
718 : :
719 [ # # # # : 0 : switch(type) {
# # # ]
720 : : case PKG_STATS_LOCAL_COUNT:
721 : : case PKG_STATS_REMOTE_REPOS:
722 : : case PKG_STATS_LOCAL_SIZE:
723 : 0 : return (stats);
724 : : case PKG_STATS_REMOTE_UNIQUE:
725 : 0 : sql = "SELECT COUNT(id) FROM main.packages;";
726 : 0 : break;
727 : : case PKG_STATS_REMOTE_COUNT:
728 : 0 : sql = "SELECT COUNT(id) FROM main.packages;";
729 : 0 : break;
730 : : case PKG_STATS_REMOTE_SIZE:
731 : 0 : sql = "SELECT SUM(pkgsize) FROM main.packages;";
732 : 0 : break;
733 : : }
734 : :
735 : 0 : pkg_debug(4, "binary_repo: running '%s'", sql);
736 : 0 : stmt = prepare_sql(sqlite, sql);
737 : :
738 [ # # ]: 0 : if (stmt == NULL)
739 : 0 : return (stats);
740 : :
741 [ # # ]: 0 : while (sqlite3_step(stmt) != SQLITE_DONE) {
742 : 0 : stats = sqlite3_column_int64(stmt, 0);
743 : : }
744 : :
745 : 0 : sqlite3_finalize(stmt);
746 : :
747 : 0 : return (stats);
748 : 0 : }
|