Branch data 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 : 2064 : 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 : 2064 : it = xmalloc(sizeof(*it));
63 : :
64 : 2064 : it->ops = &pkg_repo_binary_it_ops;
65 : 2064 : it->flags = flags;
66 : 2064 : it->repo = repo;
67 : :
68 [ + - ]: 2064 : fakedb.sqlite = PRIV_GET(repo);
69 : 2064 : it->data = pkgdb_it_new_sqlite(&fakedb, s, PKG_REMOTE, flags);
70 : :
71 [ + - ]: 2064 : if (it->data == NULL) {
72 : 0 : free(it);
73 : 0 : return (NULL);
74 : : }
75 : :
76 : 2064 : return (it);
77 : 2064 : }
78 : :
79 : : static int
80 : 3387 : pkg_repo_binary_it_next(struct pkg_repo_it *it, struct pkg **pkg_p, unsigned flags)
81 : : {
82 : 3387 : return (pkgdb_it_next(it->data, pkg_p, flags));
83 : : }
84 : :
85 : : static void
86 : 2064 : pkg_repo_binary_it_free(struct pkg_repo_it *it)
87 : : {
88 : 2064 : pkgdb_it_free(it->data);
89 : 2064 : free(it);
90 : 2064 : }
91 : :
92 : : static void
93 : 0 : pkg_repo_binary_it_reset(struct pkg_repo_it *it)
94 : : {
95 : 0 : pkgdb_it_reset(it->data);
96 : 0 : }
97 : :
98 : : struct pkg_repo_it *
99 : 2024 : pkg_repo_binary_query(struct pkg_repo *repo, const char *cond, const char *pattern, match_t match)
100 : : {
101 [ + - ]: 2024 : sqlite3 *sqlite = PRIV_GET(repo);
102 : 2024 : sqlite3_stmt *stmt = NULL;
103 : 2024 : char *sql = NULL;
104 : 2024 : const char *comp = NULL;
105 : 2024 : char basesql[] = ""
106 : : "SELECT id, origin, name, name as uniqueid, version, comment, "
107 : : "prefix, desc, arch, maintainer, www, "
108 : : "licenselogic, flatsize, pkgsize, "
109 : : "cksum, manifestdigest, path AS repopath, '%s' AS dbname "
110 : : "FROM packages AS p %s "
111 : : "%s%s%s "
112 : : "ORDER BY NAME;";
113 : :
114 [ + + + - : 2024 : if (match != MATCH_ALL && (pattern == NULL || pattern[0] == '\0'))
+ - ]
115 : 0 : return (NULL);
116 : :
117 : 2024 : comp = pkgdb_get_pattern_query(pattern, match);
118 [ + - ]: 2024 : if (comp == NULL)
119 : 0 : comp = "";
120 [ + + ]: 2024 : if (cond == NULL)
121 : 2004 : xasprintf(&sql, basesql, repo->name, comp, "", "", "");
122 : : else
123 : 40 : xasprintf(&sql, basesql, repo->name, comp,
124 : 20 : comp[0] != '\0' ? "AND (" : "WHERE (", cond + 7, ")");
125 : :
126 : 4048 : pkg_debug(4, "Pkgdb: running '%s' query for %s", sql,
127 [ + + ]: 2024 : pattern == NULL ? "all": pattern);
128 : 2024 : stmt = prepare_sql(sqlite, sql);
129 : 2024 : free(sql);
130 [ + - ]: 2024 : if (stmt == NULL)
131 : 0 : return (NULL);
132 : :
133 [ + + ]: 2024 : if (match != MATCH_ALL)
134 : 1223 : sqlite3_bind_text(stmt, 1, pattern, -1, SQLITE_TRANSIENT);
135 : :
136 : 2024 : return (pkg_repo_binary_it_new(repo, stmt, PKGDB_IT_FLAG_ONCE));
137 : 2024 : }
138 : :
139 : : struct pkg_repo_it *
140 : 4 : pkg_repo_binary_shlib_provide(struct pkg_repo *repo, const char *require)
141 : : {
142 : : sqlite3_stmt *stmt;
143 [ + - ]: 4 : sqlite3 *sqlite = PRIV_GET(repo);
144 : 4 : char *sql = NULL;
145 : 4 : const char basesql[] = ""
146 : : "SELECT p.id, p.origin, p.name, p.version, p.comment, "
147 : : "p.name as uniqueid, "
148 : : "p.prefix, p.desc, p.arch, p.maintainer, p.www, "
149 : : "p.licenselogic, p.flatsize, p.pkgsize, "
150 : : "p.cksum, p.manifestdigest, p.path AS repopath, '%s' AS dbname "
151 : : "FROM packages AS p INNER JOIN pkg_shlibs_provided AS ps ON "
152 : : "p.id = ps.package_id "
153 : : "WHERE ps.shlib_id IN (SELECT id FROM shlibs WHERE "
154 : : "name BETWEEN ?1 AND ?1 || '.9');";
155 : :
156 : 4 : xasprintf(&sql, basesql, repo->name);
157 : :
158 : 4 : pkg_debug(4, "Pkgdb: running '%s'", sql);
159 : 4 : stmt = prepare_sql(sqlite, sql);
160 : 4 : free(sql);
161 [ + - ]: 4 : if (stmt == NULL)
162 : 0 : return (NULL);
163 : :
164 : 4 : sqlite3_bind_text(stmt, 1, require, -1, SQLITE_TRANSIENT);
165 : :
166 : 4 : return (pkg_repo_binary_it_new(repo, stmt, PKGDB_IT_FLAG_ONCE));
167 : 4 : }
168 : :
169 : : struct pkg_repo_it *
170 : 20 : pkg_repo_binary_provide(struct pkg_repo *repo, const char *require)
171 : : {
172 : : sqlite3_stmt *stmt;
173 [ + - ]: 20 : sqlite3 *sqlite = PRIV_GET(repo);
174 : 20 : char *sql = NULL;
175 : 20 : const char basesql[] = ""
176 : : "SELECT p.id, p.origin, p.name, p.version, p.comment, "
177 : : "p.name as uniqueid, "
178 : : "p.prefix, p.desc, p.arch, p.maintainer, p.www, "
179 : : "p.licenselogic, p.flatsize, p.pkgsize, "
180 : : "p.cksum, p.manifestdigest, p.path AS repopath, '%s' AS dbname "
181 : : "FROM packages AS p INNER JOIN pkg_provides AS ps ON "
182 : : "p.id = ps.package_id "
183 : : "WHERE ps.provide_id IN (SELECT id from provides WHERE "
184 : : "provide = ?1 );";
185 : :
186 : 20 : xasprintf(&sql, basesql, repo->name);
187 : :
188 : 20 : pkg_debug(4, "Pkgdb: running '%s'", sql);
189 : 20 : stmt = prepare_sql(sqlite, sql);
190 : 20 : free(sql);
191 [ + - ]: 20 : if (stmt == NULL)
192 : 0 : return (NULL);
193 : :
194 : 20 : sqlite3_bind_text(stmt, 1, require, -1, SQLITE_TRANSIENT);
195 : :
196 : 20 : return (pkg_repo_binary_it_new(repo, stmt, PKGDB_IT_FLAG_ONCE));
197 : 20 : }
198 : :
199 : : struct pkg_repo_it *
200 : 0 : pkg_repo_binary_shlib_require(struct pkg_repo *repo, const char *provide)
201 : : {
202 : : sqlite3_stmt *stmt;
203 [ # # ]: 0 : sqlite3 *sqlite = PRIV_GET(repo);
204 : 0 : char *sql = NULL;
205 : 0 : const char basesql[] = ""
206 : : "SELECT p.id, p.origin, p.name, p.version, p.comment, "
207 : : "p.name as uniqueid, "
208 : : "p.prefix, p.desc, p.arch, p.maintainer, p.www, "
209 : : "p.licenselogic, p.flatsize, p.pkgsize, "
210 : : "p.cksum, p.manifestdigest, p.path AS repopath, '%s' AS dbname "
211 : : "FROM packages AS p INNER JOIN pkg_shlibs_required AS ps ON "
212 : : "p.id = ps.package_id "
213 : : "WHERE ps.shlib_id = (SELECT id FROM shlibs WHERE name=?1);";
214 : :
215 : 0 : xasprintf(&sql, basesql, repo->name);
216 : :
217 : 0 : pkg_debug(4, "Pkgdb: running '%s'", sql);
218 : 0 : stmt = prepare_sql(sqlite, sql);
219 : 0 : free(sql);
220 [ # # ]: 0 : if (stmt == NULL)
221 : 0 : return (NULL);
222 : :
223 : 0 : pkg_debug(1, "> loading provides");
224 : 0 : sqlite3_bind_text(stmt, 1, provide, -1, SQLITE_TRANSIENT);
225 : :
226 : 0 : return (pkg_repo_binary_it_new(repo, stmt, PKGDB_IT_FLAG_ONCE));
227 : 0 : }
228 : :
229 : : struct pkg_repo_it *
230 : 0 : pkg_repo_binary_require(struct pkg_repo *repo, const char *provide)
231 : : {
232 : : sqlite3_stmt *stmt;
233 [ # # ]: 0 : sqlite3 *sqlite = PRIV_GET(repo);
234 : 0 : char *sql = NULL;
235 : 0 : const char basesql[] = ""
236 : : "SELECT p.id, p.origin, p.name, p.version, p.comment, "
237 : : "p.name as uniqueid, "
238 : : "p.prefix, p.desc, p.arch, p.maintainer, p.www, "
239 : : "p.licenselogic, p.flatsize, p.pkgsize, "
240 : : "p.cksum, p.manifestdigest, p.path AS repopath, '%s' AS dbname "
241 : : "FROM packages AS p INNER JOIN pkg_requires AS ps ON "
242 : : "p.id = ps.package_id "
243 : : "WHERE ps.require_id = (SELECT id FROM requires WHERE require=?1);";
244 : :
245 : 0 : xasprintf(&sql, basesql, repo->name);
246 : :
247 : 0 : pkg_debug(4, "Pkgdb: running '%s'", sql);
248 : 0 : stmt = prepare_sql(sqlite, sql);
249 : 0 : free(sql);
250 [ # # ]: 0 : if (stmt == NULL)
251 : 0 : return (NULL);
252 : :
253 : 0 : sqlite3_bind_text(stmt, 1, provide, -1, SQLITE_TRANSIENT);
254 : :
255 : 0 : return (pkg_repo_binary_it_new(repo, stmt, PKGDB_IT_FLAG_ONCE));
256 : 0 : }
257 : : static const char *
258 : 16 : pkg_repo_binary_search_how(match_t match)
259 : : {
260 : 16 : const char *how = NULL;
261 : :
262 [ + - - - : 16 : switch (match) {
+ ]
263 : : case MATCH_ALL:
264 : 0 : how = NULL;
265 : 0 : break;
266 : : case MATCH_EXACT:
267 [ # # ]: 0 : if (pkgdb_case_sensitive())
268 : 0 : how = "%s = ?1";
269 : : else
270 : 0 : how = "%s = ?1 COLLATE NOCASE";
271 : 0 : break;
272 : : case MATCH_GLOB:
273 : 4 : how = "%s GLOB ?1";
274 : 4 : break;
275 : : case MATCH_REGEX:
276 : 12 : how = "%s REGEXP ?1";
277 : 12 : break;
278 : : }
279 : :
280 : 16 : return (how);
281 : : }
282 : :
283 : : static int
284 : 16 : pkg_repo_binary_build_search_query(xstring *sql, match_t match,
285 : : pkgdb_field field, pkgdb_field sort)
286 : : {
287 : 16 : const char *how = NULL;
288 : 16 : const char *what = NULL;
289 : 16 : const char *orderby = NULL;
290 : :
291 : 16 : how = pkg_repo_binary_search_how(match);
292 : :
293 [ - - + + : 16 : switch (field) {
- - - ]
294 : : case FIELD_NONE:
295 : 0 : what = NULL;
296 : 0 : break;
297 : : case FIELD_ORIGIN:
298 : 0 : what = "origin";
299 : 0 : break;
300 : : case FIELD_NAME:
301 : 4 : what = "name";
302 : 4 : break;
303 : : case FIELD_NAMEVER:
304 : 12 : what = "name || '-' || version";
305 : 12 : break;
306 : : case FIELD_COMMENT:
307 : 0 : what = "comment";
308 : 0 : break;
309 : : case FIELD_DESC:
310 : 0 : what = "desc";
311 : 0 : break;
312 : : }
313 : :
314 [ + - - + ]: 16 : if (what != NULL && how != NULL)
315 : 16 : fprintf(sql->fp, how, what);
316 : :
317 [ + - - + : 16 : switch (sort) {
- - - ]
318 : : case FIELD_NONE:
319 : 4 : orderby = NULL;
320 : 4 : break;
321 : : case FIELD_ORIGIN:
322 : 0 : orderby = " ORDER BY origin";
323 : 0 : break;
324 : : case FIELD_NAME:
325 : 0 : orderby = " ORDER BY name";
326 : 0 : break;
327 : : case FIELD_NAMEVER:
328 : 12 : orderby = " ORDER BY name, version";
329 : 12 : break;
330 : : case FIELD_COMMENT:
331 : 0 : orderby = " ORDER BY comment";
332 : 0 : break;
333 : : case FIELD_DESC:
334 : 0 : orderby = " ORDER BY desc";
335 : 0 : break;
336 : : }
337 : :
338 [ + + ]: 16 : if (orderby != NULL)
339 : 12 : fprintf(sql->fp, "%s", orderby);
340 : :
341 : 16 : return (EPKG_OK);
342 : : }
343 : :
344 : : struct pkg_repo_it *
345 : 16 : pkg_repo_binary_search(struct pkg_repo *repo, const char *pattern, match_t match,
346 : : pkgdb_field field, pkgdb_field sort)
347 : : {
348 [ + - ]: 16 : sqlite3 *sqlite = PRIV_GET(repo);
349 : 16 : sqlite3_stmt *stmt = NULL;
350 : 16 : xstring *sql = NULL;
351 : 16 : char *sqlcmd = NULL;
352 : 16 : const char *multireposql = ""
353 : : "SELECT id, origin, name, version, comment, "
354 : : "prefix, desc, arch, maintainer, www, "
355 : : "licenselogic, flatsize, pkgsize, "
356 : : "cksum, path AS repopath, '%1$s' AS dbname, '%2$s' AS repourl "
357 : : "FROM packages ";
358 : :
359 [ + - - + ]: 16 : if (pattern == NULL || pattern[0] == '\0')
360 : 0 : return (NULL);
361 : :
362 : 16 : sql = xstring_new();
363 : 16 : fprintf(sql->fp, multireposql, repo->name, repo->url);
364 : :
365 : : /* close the UNIONs and build the search query */
366 : 16 : fprintf(sql->fp, "%s", "WHERE ");
367 : :
368 : 16 : pkg_repo_binary_build_search_query(sql, match, field, sort);
369 : 16 : fprintf(sql->fp, "%s", ";");
370 : 16 : sqlcmd = xstring_get(sql);
371 : :
372 : 16 : pkg_debug(4, "Pkgdb: running '%s'", sqlcmd);
373 : 16 : stmt = prepare_sql(sqlite, sqlcmd);
374 : 16 : free(sqlcmd);
375 [ + - ]: 16 : if (stmt == NULL)
376 : 0 : return (NULL);
377 : :
378 : 16 : sqlite3_bind_text(stmt, 1, pattern, -1, SQLITE_TRANSIENT);
379 : :
380 : 16 : return (pkg_repo_binary_it_new(repo, stmt, PKGDB_IT_FLAG_ONCE));
381 : 16 : }
382 : :
383 : : int
384 : 1638 : pkg_repo_binary_ensure_loaded(struct pkg_repo *repo,
385 : : struct pkg *pkg, unsigned flags)
386 : : {
387 [ + - ]: 1638 : sqlite3 *sqlite = PRIV_GET(repo);
388 : 1638 : struct pkg_manifest_key *keys = NULL;
389 : 1638 : struct pkg *cached = NULL;
390 : : char path[MAXPATHLEN];
391 : :
392 [ + - + + ]: 3276 : if (pkg->type != PKG_INSTALLED &&
393 [ + - ]: 1638 : (flags & (PKG_LOAD_FILES|PKG_LOAD_DIRS)) != 0 &&
394 : 1638 : (pkg->flags & (PKG_LOAD_FILES|PKG_LOAD_DIRS)) == 0) {
395 : : /*
396 : : * Try to get that information from fetched package in cache
397 : : */
398 : 464 : pkg_manifest_keys_new(&keys);
399 : :
400 [ + + ]: 464 : if (pkg_repo_cached_name(pkg, path, sizeof(path)) != EPKG_OK)
401 : 4 : return (EPKG_FATAL);
402 : :
403 : 460 : pkg_debug(1, "Binary> loading %s", path);
404 [ - + ]: 460 : if (pkg_open(&cached, path, keys, PKG_OPEN_TRY) != EPKG_OK) {
405 : 0 : pkg_free(cached);
406 : 0 : return (EPKG_FATAL);
407 : : }
408 : :
409 : : /* Now move required elements to the provided package */
410 : 460 : pkg_list_free(pkg, PKG_FILES);
411 : 460 : pkg_list_free(pkg, PKG_DIRS);
412 : 460 : pkg->files = cached->files;
413 : 460 : pkg->filehash = cached->filehash;
414 : 460 : pkg->dirs = cached->dirs;
415 : 460 : pkg->dirhash = cached->dirhash;
416 : 460 : cached->files = NULL;
417 : 460 : cached->filehash = NULL;
418 : 460 : cached->dirs = NULL;
419 : 460 : cached->dirhash = NULL;
420 : :
421 : 460 : pkg_free(cached);
422 : 460 : pkg->flags |= (PKG_LOAD_FILES|PKG_LOAD_DIRS);
423 : 460 : }
424 : :
425 : 1634 : return (pkgdb_ensure_loaded_sqlite(sqlite, pkg, flags));
426 : 1638 : }
427 : :
428 : :
429 : : int64_t
430 : 0 : pkg_repo_binary_stat(struct pkg_repo *repo, pkg_stats_t type)
431 : : {
432 [ # # ]: 0 : sqlite3 *sqlite = PRIV_GET(repo);
433 : 0 : sqlite3_stmt *stmt = NULL;
434 : 0 : int64_t stats = 0;
435 : 0 : const char *sql = NULL;
436 : :
437 [ # # # # : 0 : switch(type) {
# ]
438 : : case PKG_STATS_LOCAL_COUNT:
439 : : case PKG_STATS_REMOTE_REPOS:
440 : : case PKG_STATS_LOCAL_SIZE:
441 : 0 : return (stats);
442 : : case PKG_STATS_REMOTE_UNIQUE:
443 : 0 : sql = "SELECT COUNT(id) FROM main.packages;";
444 : 0 : break;
445 : : case PKG_STATS_REMOTE_COUNT:
446 : 0 : sql = "SELECT COUNT(id) FROM main.packages;";
447 : 0 : break;
448 : : case PKG_STATS_REMOTE_SIZE:
449 : 0 : sql = "SELECT SUM(pkgsize) FROM main.packages;";
450 : 0 : break;
451 : : }
452 : :
453 : 0 : pkg_debug(4, "binary_repo: running '%s'", sql);
454 : 0 : stmt = prepare_sql(sqlite, sql);
455 : :
456 [ # # ]: 0 : if (stmt == NULL)
457 : 0 : return (stats);
458 : :
459 [ # # ]: 0 : while (sqlite3_step(stmt) != SQLITE_DONE) {
460 : 0 : stats = sqlite3_column_int64(stmt, 0);
461 : : }
462 : :
463 : 0 : sqlite3_finalize(stmt);
464 : :
465 : 0 : return (stats);
466 : 0 : }
|