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