Line data Source code
1 : /* Copyright (c) 2014, Vsevolod Stakhov
2 : * All rights reserved.
3 : *
4 : * Redistribution and use in source and binary forms, with or without
5 : * modification, are permitted provided that the following conditions are met:
6 : * * Redistributions of source code must retain the above copyright
7 : * notice, this list of conditions and the following disclaimer.
8 : * * Redistributions in binary form must reproduce the above copyright
9 : * notice, this list of conditions and the following disclaimer in the
10 : * documentation and/or other materials provided with the distribution.
11 : *
12 : * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
13 : * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14 : * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15 : * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
16 : * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17 : * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
18 : * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
19 : * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20 : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21 : * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22 : */
23 :
24 : #include <assert.h>
25 : #include <errno.h>
26 : #include <regex.h>
27 : #include <grp.h>
28 : #include <stdlib.h>
29 : #include <stdio.h>
30 : #include <stdbool.h>
31 : #include <string.h>
32 : #include <unistd.h>
33 : #include <libgen.h>
34 :
35 : #include <sqlite3.h>
36 :
37 : #include "pkg.h"
38 : #include "private/event.h"
39 : #include "private/pkg.h"
40 : #include "private/pkgdb.h"
41 : #include "private/utils.h"
42 : #include "binary.h"
43 :
44 : static struct pkg_repo_it* pkg_repo_binary_it_new(struct pkg_repo *repo,
45 : sqlite3_stmt *s, short flags);
46 : static int pkg_repo_binary_it_next(struct pkg_repo_it *it, struct pkg **pkg_p, unsigned flags);
47 : static void pkg_repo_binary_it_free(struct pkg_repo_it *it);
48 : static void pkg_repo_binary_it_reset(struct pkg_repo_it *it);
49 :
50 : static struct pkg_repo_it_ops pkg_repo_binary_it_ops = {
51 : .next = pkg_repo_binary_it_next,
52 : .free = pkg_repo_binary_it_free,
53 : .reset = pkg_repo_binary_it_reset
54 : };
55 :
56 : static struct pkg_repo_it*
57 71 : pkg_repo_binary_it_new(struct pkg_repo *repo, sqlite3_stmt *s, short flags)
58 : {
59 : struct pkg_repo_it *it;
60 : struct pkgdb fakedb;
61 :
62 71 : it = malloc(sizeof(*it));
63 71 : if (it == NULL) {
64 0 : pkg_emit_errno("malloc", "pkg_repo_it");
65 0 : sqlite3_finalize(s);
66 0 : return (NULL);
67 : }
68 :
69 71 : it->ops = &pkg_repo_binary_it_ops;
70 71 : it->flags = flags;
71 71 : it->repo = repo;
72 :
73 71 : fakedb.sqlite = PRIV_GET(repo);
74 71 : it->data = pkgdb_it_new_sqlite(&fakedb, s, PKG_REMOTE, flags);
75 :
76 71 : if (it->data == NULL) {
77 0 : free(it);
78 0 : return (NULL);
79 : }
80 :
81 71 : return (it);
82 : }
83 :
84 : static int
85 124 : pkg_repo_binary_it_next(struct pkg_repo_it *it, struct pkg **pkg_p, unsigned flags)
86 : {
87 124 : return (pkgdb_it_next(it->data, pkg_p, flags));
88 : }
89 :
90 : static void
91 71 : pkg_repo_binary_it_free(struct pkg_repo_it *it)
92 : {
93 71 : pkgdb_it_free(it->data);
94 71 : free(it);
95 71 : }
96 :
97 : static void
98 0 : pkg_repo_binary_it_reset(struct pkg_repo_it *it)
99 : {
100 0 : pkgdb_it_reset(it->data);
101 0 : }
102 :
103 : struct pkg_repo_it *
104 66 : pkg_repo_binary_query(struct pkg_repo *repo, const char *pattern, match_t match)
105 : {
106 66 : sqlite3 *sqlite = PRIV_GET(repo);
107 66 : sqlite3_stmt *stmt = NULL;
108 66 : struct sbuf *sql = NULL;
109 66 : const char *comp = NULL;
110 : int ret;
111 66 : char basesql[BUFSIZ] = ""
112 : "SELECT id, origin, name, name as uniqueid, version, comment, "
113 : "prefix, desc, arch, maintainer, www, "
114 : "licenselogic, flatsize, pkgsize, "
115 : "cksum, manifestdigest, path AS repopath, '%s' AS dbname "
116 : "FROM packages AS p";
117 :
118 66 : if (match != MATCH_ALL && (pattern == NULL || pattern[0] == '\0'))
119 0 : return (NULL);
120 :
121 66 : sql = sbuf_new_auto();
122 66 : comp = pkgdb_get_pattern_query(pattern, match);
123 66 : if (comp && comp[0])
124 50 : strlcat(basesql, comp, sizeof(basesql));
125 :
126 66 : sbuf_printf(sql, basesql, repo->name);
127 :
128 66 : sbuf_cat(sql, " ORDER BY name;");
129 66 : sbuf_finish(sql);
130 :
131 66 : pkg_debug(4, "Pkgdb: running '%s' query for %s", sbuf_data(sql),
132 : pattern == NULL ? "all": pattern);
133 66 : ret = sqlite3_prepare_v2(sqlite, sbuf_data(sql), sbuf_len(sql), &stmt,
134 : NULL);
135 66 : if (ret != SQLITE_OK) {
136 0 : ERROR_SQLITE(sqlite, sbuf_data(sql));
137 0 : sbuf_delete(sql);
138 0 : return (NULL);
139 : }
140 :
141 66 : sbuf_delete(sql);
142 :
143 66 : if (match != MATCH_ALL && match != MATCH_CONDITION)
144 50 : sqlite3_bind_text(stmt, 1, pattern, -1, SQLITE_TRANSIENT);
145 :
146 66 : return (pkg_repo_binary_it_new(repo, stmt, PKGDB_IT_FLAG_ONCE));
147 : }
148 :
149 : struct pkg_repo_it *
150 0 : pkg_repo_binary_shlib_provide(struct pkg_repo *repo, const char *require)
151 : {
152 : sqlite3_stmt *stmt;
153 0 : sqlite3 *sqlite = PRIV_GET(repo);
154 0 : struct sbuf *sql = NULL;
155 : int ret;
156 0 : const char basesql[] = ""
157 : "SELECT p.id, p.origin, p.name, p.version, p.comment, "
158 : "p.name as uniqueid, "
159 : "p.prefix, p.desc, p.arch, p.maintainer, p.www, "
160 : "p.licenselogic, p.flatsize, p.pkgsize, "
161 : "p.cksum, p.manifestdigest, p.path AS repopath, '%s' AS dbname "
162 : "FROM packages AS p INNER JOIN pkg_shlibs_provided AS ps ON "
163 : "p.id = ps.package_id "
164 : "WHERE ps.shlib_id IN (SELECT id FROM shlibs WHERE "
165 : "name BETWEEN ?1 AND ?1 || '.9');";
166 :
167 0 : sql = sbuf_new_auto();
168 0 : sbuf_printf(sql, basesql, repo->name);
169 :
170 0 : sbuf_finish(sql);
171 :
172 0 : pkg_debug(4, "Pkgdb: running '%s'", sbuf_data(sql));
173 0 : ret = sqlite3_prepare_v2(sqlite, sbuf_data(sql), -1, &stmt, NULL);
174 0 : if (ret != SQLITE_OK) {
175 0 : ERROR_SQLITE(sqlite, sbuf_data(sql));
176 0 : sbuf_delete(sql);
177 0 : return (NULL);
178 : }
179 :
180 0 : sbuf_delete(sql);
181 :
182 0 : sqlite3_bind_text(stmt, 1, require, -1, SQLITE_TRANSIENT);
183 :
184 0 : return (pkg_repo_binary_it_new(repo, stmt, PKGDB_IT_FLAG_ONCE));
185 : }
186 :
187 : struct pkg_repo_it *
188 5 : pkg_repo_binary_provide(struct pkg_repo *repo, const char *require)
189 : {
190 : sqlite3_stmt *stmt;
191 5 : sqlite3 *sqlite = PRIV_GET(repo);
192 5 : struct sbuf *sql = NULL;
193 : int ret;
194 5 : const char basesql[] = ""
195 : "SELECT p.id, p.origin, p.name, p.version, p.comment, "
196 : "p.name as uniqueid, "
197 : "p.prefix, p.desc, p.arch, p.maintainer, p.www, "
198 : "p.licenselogic, p.flatsize, p.pkgsize, "
199 : "p.cksum, p.manifestdigest, p.path AS repopath, '%s' AS dbname "
200 : "FROM packages AS p INNER JOIN pkg_provides AS ps ON "
201 : "p.id = ps.package_id "
202 : "WHERE ps.provide_id IN (SELECT id from provides WHERE "
203 : "provide = ?1 );";
204 :
205 5 : sql = sbuf_new_auto();
206 5 : sbuf_printf(sql, basesql, repo->name);
207 :
208 5 : sbuf_finish(sql);
209 :
210 5 : pkg_debug(4, "Pkgdb: running '%s'", sbuf_data(sql));
211 5 : ret = sqlite3_prepare_v2(sqlite, sbuf_data(sql), -1, &stmt, NULL);
212 5 : if (ret != SQLITE_OK) {
213 0 : ERROR_SQLITE(sqlite, sbuf_data(sql));
214 0 : sbuf_delete(sql);
215 0 : return (NULL);
216 : }
217 :
218 5 : sbuf_delete(sql);
219 :
220 5 : sqlite3_bind_text(stmt, 1, require, -1, SQLITE_TRANSIENT);
221 :
222 5 : return (pkg_repo_binary_it_new(repo, stmt, PKGDB_IT_FLAG_ONCE));
223 : }
224 :
225 : struct pkg_repo_it *
226 0 : pkg_repo_binary_shlib_require(struct pkg_repo *repo, const char *provide)
227 : {
228 : sqlite3_stmt *stmt;
229 0 : sqlite3 *sqlite = PRIV_GET(repo);
230 0 : struct sbuf *sql = NULL;
231 : int ret;
232 0 : const char basesql[] = ""
233 : "SELECT p.id, p.origin, p.name, p.version, p.comment, "
234 : "p.name as uniqueid, "
235 : "p.prefix, p.desc, p.arch, p.maintainer, p.www, "
236 : "p.licenselogic, p.flatsize, p.pkgsize, "
237 : "p.cksum, p.manifestdigest, p.path AS repopath, '%s' AS dbname "
238 : "FROM packages AS p INNER JOIN pkg_shlibs_required AS ps ON "
239 : "p.id = ps.package_id "
240 : "WHERE ps.shlib_id = (SELECT id FROM shlibs WHERE name=?1);";
241 :
242 0 : sql = sbuf_new_auto();
243 0 : sbuf_printf(sql, basesql, repo->name);
244 :
245 0 : sbuf_finish(sql);
246 :
247 0 : pkg_debug(4, "Pkgdb: running '%s'", sbuf_data(sql));
248 0 : ret = sqlite3_prepare_v2(sqlite, sbuf_data(sql), -1, &stmt, NULL);
249 0 : if (ret != SQLITE_OK) {
250 0 : ERROR_SQLITE(sqlite, sbuf_data(sql));
251 0 : sbuf_delete(sql);
252 0 : return (NULL);
253 : }
254 :
255 0 : sbuf_delete(sql);
256 :
257 0 : pkg_debug(1, "> loading provides");
258 0 : sqlite3_bind_text(stmt, 1, provide, -1, SQLITE_TRANSIENT);
259 :
260 0 : return (pkg_repo_binary_it_new(repo, stmt, PKGDB_IT_FLAG_ONCE));
261 : }
262 :
263 : struct pkg_repo_it *
264 0 : pkg_repo_binary_require(struct pkg_repo *repo, const char *provide)
265 : {
266 : sqlite3_stmt *stmt;
267 0 : sqlite3 *sqlite = PRIV_GET(repo);
268 0 : struct sbuf *sql = NULL;
269 : int ret;
270 0 : const char basesql[] = ""
271 : "SELECT p.id, p.origin, p.name, p.version, p.comment, "
272 : "p.name as uniqueid, "
273 : "p.prefix, p.desc, p.arch, p.maintainer, p.www, "
274 : "p.licenselogic, p.flatsize, p.pkgsize, "
275 : "p.cksum, p.manifestdigest, p.path AS repopath, '%s' AS dbname "
276 : "FROM packages AS p INNER JOIN pkg_requires AS ps ON "
277 : "p.id = ps.package_id "
278 : "WHERE ps.require_id = (SELECT id FROM requires WHERE require=?1);";
279 :
280 0 : sql = sbuf_new_auto();
281 0 : sbuf_printf(sql, basesql, repo->name);
282 :
283 0 : sbuf_finish(sql);
284 :
285 0 : pkg_debug(4, "Pkgdb: running '%s'", sbuf_data(sql));
286 0 : ret = sqlite3_prepare_v2(sqlite, sbuf_data(sql), -1, &stmt, NULL);
287 0 : if (ret != SQLITE_OK) {
288 0 : ERROR_SQLITE(sqlite, sbuf_data(sql));
289 0 : sbuf_delete(sql);
290 0 : return (NULL);
291 : }
292 :
293 0 : sbuf_delete(sql);
294 :
295 0 : sqlite3_bind_text(stmt, 1, provide, -1, SQLITE_TRANSIENT);
296 :
297 0 : return (pkg_repo_binary_it_new(repo, stmt, PKGDB_IT_FLAG_ONCE));
298 : }
299 : static const char *
300 0 : pkg_repo_binary_search_how(match_t match)
301 : {
302 0 : const char *how = NULL;
303 :
304 0 : switch (match) {
305 : case MATCH_ALL:
306 0 : how = NULL;
307 0 : break;
308 : case MATCH_EXACT:
309 0 : if (pkgdb_case_sensitive())
310 0 : how = "%s = ?1";
311 : else
312 0 : how = "%s = ?1 COLLATE NOCASE";
313 0 : break;
314 : case MATCH_GLOB:
315 0 : how = "%s GLOB ?1";
316 0 : break;
317 : case MATCH_REGEX:
318 0 : how = "%s REGEXP ?1";
319 0 : break;
320 : case MATCH_CONDITION:
321 : /* Should not be called by pkgdb_get_match_how(). */
322 0 : assert(0);
323 : break;
324 : case MATCH_FTS:
325 0 : how = "id IN (SELECT id FROM pkg_search WHERE %s MATCH ?1)";
326 0 : break;
327 : }
328 :
329 0 : return (how);
330 : }
331 :
332 : static int
333 0 : pkg_repo_binary_build_search_query(struct sbuf *sql, match_t match,
334 : pkgdb_field field, pkgdb_field sort)
335 : {
336 0 : const char *how = NULL;
337 0 : const char *what = NULL;
338 0 : const char *orderby = NULL;
339 :
340 0 : how = pkg_repo_binary_search_how(match);
341 :
342 0 : switch (field) {
343 : case FIELD_NONE:
344 0 : what = NULL;
345 0 : break;
346 : case FIELD_ORIGIN:
347 0 : what = "origin";
348 0 : break;
349 : case FIELD_NAME:
350 0 : what = "name";
351 0 : break;
352 : case FIELD_NAMEVER:
353 0 : what = "name || '-' || version";
354 0 : break;
355 : case FIELD_COMMENT:
356 0 : what = "comment";
357 0 : break;
358 : case FIELD_DESC:
359 0 : what = "desc";
360 0 : break;
361 : }
362 :
363 0 : if (what != NULL && how != NULL)
364 0 : sbuf_printf(sql, how, what);
365 :
366 0 : switch (sort) {
367 : case FIELD_NONE:
368 0 : orderby = NULL;
369 0 : break;
370 : case FIELD_ORIGIN:
371 0 : orderby = " ORDER BY origin";
372 0 : break;
373 : case FIELD_NAME:
374 0 : orderby = " ORDER BY name";
375 0 : break;
376 : case FIELD_NAMEVER:
377 0 : orderby = " ORDER BY name, version";
378 0 : break;
379 : case FIELD_COMMENT:
380 0 : orderby = " ORDER BY comment";
381 0 : break;
382 : case FIELD_DESC:
383 0 : orderby = " ORDER BY desc";
384 0 : break;
385 : }
386 :
387 0 : if (orderby != NULL)
388 0 : sbuf_cat(sql, orderby);
389 :
390 0 : return (EPKG_OK);
391 : }
392 :
393 : struct pkg_repo_it *
394 0 : pkg_repo_binary_search(struct pkg_repo *repo, const char *pattern, match_t match,
395 : pkgdb_field field, pkgdb_field sort)
396 : {
397 0 : sqlite3 *sqlite = PRIV_GET(repo);
398 0 : sqlite3_stmt *stmt = NULL;
399 0 : struct sbuf *sql = NULL;
400 : int ret;
401 0 : const char *multireposql = ""
402 : "SELECT id, origin, name, version, comment, "
403 : "prefix, desc, arch, maintainer, www, "
404 : "licenselogic, flatsize, pkgsize, "
405 : "cksum, path AS repopath, '%1$s' AS dbname, '%2$s' AS repourl "
406 : "FROM packages ";
407 :
408 0 : if (pattern == NULL || pattern[0] == '\0')
409 0 : return (NULL);
410 :
411 0 : sql = sbuf_new_auto();
412 0 : sbuf_printf(sql, multireposql, repo->name, repo->url);
413 :
414 : /* close the UNIONs and build the search query */
415 0 : sbuf_cat(sql, "WHERE ");
416 :
417 0 : pkg_repo_binary_build_search_query(sql, match, field, sort);
418 0 : sbuf_cat(sql, ";");
419 0 : sbuf_finish(sql);
420 :
421 0 : pkg_debug(4, "Pkgdb: running '%s'", sbuf_data(sql));
422 0 : ret = sqlite3_prepare_v2(sqlite, sbuf_data(sql), -1, &stmt, NULL);
423 0 : if (ret != SQLITE_OK) {
424 0 : ERROR_SQLITE(sqlite, sbuf_data(sql));
425 0 : sbuf_delete(sql);
426 0 : return (NULL);
427 : }
428 :
429 0 : sbuf_delete(sql);
430 :
431 0 : sqlite3_bind_text(stmt, 1, pattern, -1, SQLITE_TRANSIENT);
432 :
433 0 : return (pkg_repo_binary_it_new(repo, stmt, PKGDB_IT_FLAG_ONCE));
434 : }
435 :
436 : int
437 113 : pkg_repo_binary_ensure_loaded(struct pkg_repo *repo,
438 : struct pkg *pkg, unsigned flags)
439 : {
440 113 : sqlite3 *sqlite = PRIV_GET(repo);
441 113 : struct pkg_manifest_key *keys = NULL;
442 113 : struct pkg *cached = NULL;
443 : char path[MAXPATHLEN];
444 :
445 226 : if (pkg->type != PKG_INSTALLED &&
446 226 : (flags & (PKG_LOAD_FILES|PKG_LOAD_DIRS)) != 0 &&
447 113 : (pkg->flags & (PKG_LOAD_FILES|PKG_LOAD_DIRS)) == 0) {
448 : /*
449 : * Try to get that information from fetched package in cache
450 : */
451 26 : pkg_manifest_keys_new(&keys);
452 :
453 26 : if (pkg_repo_cached_name(pkg, path, sizeof(path)) != EPKG_OK)
454 0 : return (EPKG_FATAL);
455 :
456 26 : pkg_debug(1, "Binary> loading %s", path);
457 26 : if (pkg_open(&cached, path, keys, PKG_OPEN_TRY) != EPKG_OK) {
458 0 : pkg_free(cached);
459 0 : return (EPKG_FATAL);
460 : }
461 :
462 : /* Now move required elements to the provided package */
463 26 : pkg_list_free(pkg, PKG_FILES);
464 26 : pkg_list_free(pkg, PKG_DIRS);
465 26 : pkg->files = cached->files;
466 26 : pkg->dirs = cached->dirs;
467 26 : cached->files = NULL;
468 26 : cached->dirs = NULL;
469 :
470 26 : pkg_free(cached);
471 26 : pkg->flags |= (PKG_LOAD_FILES|PKG_LOAD_DIRS);
472 : }
473 :
474 113 : return (pkgdb_ensure_loaded_sqlite(sqlite, pkg, flags));
475 : }
476 :
477 :
478 : int64_t
479 0 : pkg_repo_binary_stat(struct pkg_repo *repo, pkg_stats_t type)
480 : {
481 0 : sqlite3 *sqlite = PRIV_GET(repo);
482 0 : sqlite3_stmt *stmt = NULL;
483 0 : int64_t stats = 0;
484 0 : struct sbuf *sql = NULL;
485 : int ret;
486 :
487 0 : sql = sbuf_new_auto();
488 :
489 0 : switch(type) {
490 : case PKG_STATS_LOCAL_COUNT:
491 0 : goto out;
492 : break;
493 : case PKG_STATS_LOCAL_SIZE:
494 0 : goto out;
495 : break;
496 : case PKG_STATS_REMOTE_UNIQUE:
497 0 : sbuf_printf(sql, "SELECT COUNT(id) FROM main.packages;");
498 0 : break;
499 : case PKG_STATS_REMOTE_COUNT:
500 0 : sbuf_printf(sql, "SELECT COUNT(id) FROM main.packages;");
501 0 : break;
502 : case PKG_STATS_REMOTE_SIZE:
503 0 : sbuf_printf(sql, "SELECT SUM(pkgsize) FROM main.packages;");
504 0 : break;
505 : case PKG_STATS_REMOTE_REPOS:
506 0 : goto out;
507 : break;
508 : }
509 :
510 0 : sbuf_finish(sql);
511 0 : pkg_debug(4, "binary_repo: running '%s'", sbuf_data(sql));
512 0 : ret = sqlite3_prepare_v2(sqlite, sbuf_data(sql), -1, &stmt, NULL);
513 0 : if (ret != SQLITE_OK) {
514 0 : ERROR_SQLITE(sqlite, sbuf_data(sql));
515 0 : goto out;
516 : }
517 :
518 0 : while (sqlite3_step(stmt) != SQLITE_DONE) {
519 0 : stats = sqlite3_column_int64(stmt, 0);
520 : }
521 :
522 : out:
523 0 : sbuf_free(sql);
524 0 : if (stmt != NULL)
525 0 : sqlite3_finalize(stmt);
526 :
527 0 : return (stats);
528 : }
|