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