1 /*-
2  * Copyright (c) 2011-2012 Baptiste Daroussin <bapt@FreeBSD.org>
3  * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
4  * Copyright (c) 2011 Will Andrews <will@FreeBSD.org>
5  * Copyright (c) 2011 Philippe Pepiot <phil@philpep.org>
6  * Copyright (c) 2011-2012 Marin Atanasov Nikolov <dnaeon@gmail.com>
7  * Copyright (c) 2012-2013 Matthew Seaman <matthew@FreeBSD.org>
8  * Copyright (c) 2012 Bryan Drewery <bryan@shatow.net>
9  * Copyright (c) 2013 Gerald Pfeifer <gerald@pfeifer.com>
10  * Copyright (c) 2013-2014 Vsevolod Stakhov <vsevolod@FreeBSD.org>
11  * All rights reserved.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer
18  *    in this position and unchanged.
19  * 2. Redistributions in binary form must reproduce the above copyright
20  *    notice, this list of conditions and the following disclaimer in the
21  *    documentation and/or other materials provided with the distribution.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
24  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 #ifdef HAVE_CONFIG_H
36 #include "pkg_config.h"
37 #endif
38 
39 #include <assert.h>
40 #include <errno.h>
41 #include <regex.h>
42 #include <grp.h>
43 #ifdef HAVE_LIBUTIL_H
44 #include <libutil.h>
45 #endif
46 #include <stdlib.h>
47 #include <stdio.h>
48 #include <stdbool.h>
49 #include <string.h>
50 #include <unistd.h>
51 #include <signal.h>
52 
53 #include <sqlite3.h>
54 
55 #include "pkg.h"
56 #include "private/event.h"
57 #include "private/pkg.h"
58 #include "private/pkgdb.h"
59 #include "private/utils.h"
60 
61 const char *
pkgdb_get_pattern_query(const char * pattern,match_t match)62 pkgdb_get_pattern_query(const char *pattern, match_t match)
63 {
64 	char		*checkorigin = NULL;
65 	char		*checkuid = NULL;
66 	const char	*comp = NULL;
67 
68 	if (pattern != NULL) {
69 		checkuid = strchr(pattern, '~');
70 		if (checkuid == NULL)
71 			checkorigin = strchr(pattern, '/');
72 	}
73 
74 	switch (match) {
75 	case MATCH_ALL:
76 		comp = "";
77 		break;
78 	case MATCH_EXACT:
79 		if (pkgdb_case_sensitive()) {
80 			if (checkuid == NULL) {
81 				if (checkorigin == NULL)
82 					comp = " WHERE (name = ?1 "
83 					    "OR (name = SPLIT_VERSION('name', ?1) AND "
84 					    " version = SPLIT_VERSION('version', ?1)))";
85 				else
86 					comp = " WHERE origin = ?1";
87 			} else {
88 				comp = " WHERE name = ?1";
89 			}
90 		} else {
91 			if (checkuid == NULL) {
92 				if (checkorigin == NULL)
93 					comp = " WHERE (name = ?1 COLLATE NOCASE "
94 							"OR (name = SPLIT_VERSION('name', ?1) COLLATE NOCASE AND "
95 							" version = SPLIT_VERSION('version', ?1)))";
96 				else
97 					comp = " WHERE origin = ?1 COLLATE NOCASE";
98 			} else {
99 				comp = " WHERE name = ?1 COLLATE NOCASE";
100 			}
101 		}
102 		break;
103 	case MATCH_GLOB:
104 		if (checkuid == NULL) {
105 			if (checkorigin == NULL)
106 				comp = " WHERE (name GLOB ?1 "
107 					"OR name || '-' || version GLOB ?1)";
108 			else
109 				comp = " WHERE origin GLOB ?1";
110 		} else {
111 			comp = " WHERE name = ?1";
112 		}
113 		break;
114 	case MATCH_REGEX:
115 		if (checkuid == NULL) {
116 			if (checkorigin == NULL)
117 				comp = " WHERE (name REGEXP ?1 "
118 				    "OR name || '-' || version REGEXP ?1)";
119 			else
120 				comp = " WHERE origin REGEXP ?1";
121 		} else {
122 			comp = " WHERE name = ?1";
123 		}
124 		break;
125 	}
126 
127 	return (comp);
128 }
129 
130 struct pkgdb_it *
pkgdb_query_cond(struct pkgdb * db,const char * cond,const char * pattern,match_t match)131 pkgdb_query_cond(struct pkgdb *db, const char *cond, const char *pattern, match_t match)
132 {
133 	char		 sql[BUFSIZ];
134 	sqlite3_stmt	*stmt;
135 	const char	*comp = NULL;
136 
137 	assert(db != NULL);
138 
139 	if (match != MATCH_ALL && (pattern == NULL || pattern[0] == '\0'))
140 		return (NULL);
141 
142 	comp = pkgdb_get_pattern_query(pattern, match);
143 
144 	if (cond)
145 		sqlite3_snprintf(sizeof(sql), sql,
146 				"SELECT id, origin, name, name as uniqueid, "
147 					"version, comment, desc, "
148 					"message, arch, maintainer, www, "
149 					"prefix, flatsize, licenselogic, automatic, "
150 					"locked, time, manifestdigest, vital "
151 					"FROM packages AS p%s %s (%s) ORDER BY p.name;",
152 					comp, pattern == NULL ? "WHERE" : "AND", cond + 7);
153 	else
154 		sqlite3_snprintf(sizeof(sql), sql,
155 				"SELECT id, origin, name, name as uniqueid, "
156 					"version, comment, desc, "
157 					"message, arch, maintainer, www, "
158 					"prefix, flatsize, licenselogic, automatic, "
159 					"locked, time, manifestdigest, vital "
160 				"FROM packages AS p%s "
161 				"ORDER BY p.name;", comp);
162 
163 	pkg_debug(4, "Pkgdb: running '%s'", sql);
164 	if (sqlite3_prepare_v2(db->sqlite, sql, -1, &stmt, NULL) != SQLITE_OK) {
165 		ERROR_SQLITE(db->sqlite, sql);
166 		return (NULL);
167 	}
168 
169 	if (match != MATCH_ALL)
170 		sqlite3_bind_text(stmt, 1, pattern, -1, SQLITE_TRANSIENT);
171 
172 	return (pkgdb_it_new_sqlite(db, stmt, PKG_INSTALLED, PKGDB_IT_FLAG_ONCE));
173 }
174 
175 struct pkgdb_it *
pkgdb_query(struct pkgdb * db,const char * pattern,match_t match)176 pkgdb_query(struct pkgdb *db, const char *pattern, match_t match)
177 {
178 	return pkgdb_query_cond(db, NULL, pattern, match);
179 }
180 
181 bool
pkgdb_file_exists(struct pkgdb * db,const char * path)182 pkgdb_file_exists(struct pkgdb *db, const char *path)
183 {
184 	sqlite3_stmt	*stmt;
185 	char	sql[BUFSIZ];
186 	bool	ret = false;
187 
188 	assert(db != NULL);
189 
190 	if (path == NULL)
191 		return (false);
192 
193 	sqlite3_snprintf(sizeof(sql), sql,
194 	    "select path from files where path = ?1;");
195 	pkg_debug(4, "Pkgdb: running '%s'", sql);
196 
197 	if (sqlite3_prepare_v2(db->sqlite, sql, -1, &stmt, NULL) != SQLITE_OK) {
198 		ERROR_SQLITE(db->sqlite, sql);
199 	}
200 
201 	sqlite3_bind_text(stmt, 1, path, -1, SQLITE_TRANSIENT);
202 
203 	if (sqlite3_step(stmt) != SQLITE_DONE) {
204 		ret = true;
205 	}
206 
207 	sqlite3_finalize(stmt);
208 	return (ret);
209 }
210 
211 struct pkgdb_it *
pkgdb_query_which(struct pkgdb * db,const char * path,bool glob)212 pkgdb_query_which(struct pkgdb *db, const char *path, bool glob)
213 {
214 	sqlite3_stmt	*stmt;
215 	char	sql[BUFSIZ];
216 
217 	assert(db != NULL);
218 
219 	if (path == NULL)
220 		return (NULL);
221 
222 	sqlite3_snprintf(sizeof(sql), sql,
223 			"SELECT p.id, p.origin, p.name, p.name as uniqueid, "
224 			"p.version, p.comment, p.desc, "
225 			"p.message, p.arch, p.maintainer, p.www, "
226 			"p.prefix, p.flatsize, p.time "
227 			"FROM packages AS p "
228 			"LEFT JOIN files AS f ON p.id = f.package_id "
229 			"WHERE f.path %s ?1 GROUP BY p.id;", glob ? "GLOB" : "=");
230 
231 	pkg_debug(4, "Pkgdb: running '%s'", sql);
232 	if (sqlite3_prepare_v2(db->sqlite, sql, -1, &stmt, NULL) != SQLITE_OK) {
233 		ERROR_SQLITE(db->sqlite, sql);
234 		return (NULL);
235 	}
236 
237 	sqlite3_bind_text(stmt, 1, path, -1, SQLITE_TRANSIENT);
238 
239 	return (pkgdb_it_new_sqlite(db, stmt, PKG_INSTALLED, PKGDB_IT_FLAG_ONCE));
240 }
241 
242 struct pkgdb_it *
pkgdb_query_shlib_require(struct pkgdb * db,const char * shlib)243 pkgdb_query_shlib_require(struct pkgdb *db, const char *shlib)
244 {
245 	sqlite3_stmt	*stmt;
246 	const char	 sql[] = ""
247 		"SELECT p.id, p.origin, p.name, p.name as uniqueid, "
248 			"p.version, p.comment, p.desc, "
249 			"p.message, p.arch, p.maintainer, p.www, "
250 			"p.prefix, p.flatsize, p.time "
251 			"FROM packages AS p, pkg_shlibs_required AS ps, shlibs AS s "
252 			"WHERE p.id = ps.package_id "
253 				"AND ps.shlib_id = s.id "
254 				"AND s.name = ?1;";
255 
256 	assert(db != NULL);
257 
258 	pkg_debug(4, "Pkgdb: running '%s'", sql);
259 	if (sqlite3_prepare_v2(db->sqlite, sql, -1, &stmt, NULL) != SQLITE_OK) {
260 		ERROR_SQLITE(db->sqlite, sql);
261 		return (NULL);
262 	}
263 
264 	sqlite3_bind_text(stmt, 1, shlib, -1, SQLITE_TRANSIENT);
265 
266 	return (pkgdb_it_new_sqlite(db, stmt, PKG_INSTALLED, PKGDB_IT_FLAG_ONCE));
267 }
268 
269 struct pkgdb_it *
pkgdb_query_shlib_provide(struct pkgdb * db,const char * shlib)270 pkgdb_query_shlib_provide(struct pkgdb *db, const char *shlib)
271 {
272 	sqlite3_stmt	*stmt;
273 	const char	 sql[] = ""
274 		"SELECT p.id, p.origin, p.name, p.name as uniqueid, "
275 			"p.version, p.comment, p.desc, "
276 			"p.message, p.arch, p.maintainer, p.www, "
277 			"p.prefix, p.flatsize, p.manifestdigest, p.time "
278 			"FROM packages AS p, pkg_shlibs_provided AS ps, shlibs AS s "
279 			"WHERE p.id = ps.package_id "
280 				"AND ps.shlib_id = s.id "
281 				"AND s.name = ?1;";
282 
283 	assert(db != NULL);
284 
285 	pkg_debug(4, "Pkgdb: running '%s'", sql);
286 	if (sqlite3_prepare_v2(db->sqlite, sql, -1, &stmt, NULL) != SQLITE_OK) {
287 		ERROR_SQLITE(db->sqlite, sql);
288 		return (NULL);
289 	}
290 
291 	sqlite3_bind_text(stmt, 1, shlib, -1, SQLITE_TRANSIENT);
292 
293 	return (pkgdb_it_new_sqlite(db, stmt, PKG_INSTALLED, PKGDB_IT_FLAG_ONCE));
294 }
295 
296 struct pkgdb_it *
pkgdb_query_require(struct pkgdb * db,const char * req)297 pkgdb_query_require(struct pkgdb *db, const char *req)
298 {
299 	sqlite3_stmt	*stmt;
300 	const char	 sql[] = ""
301 		"SELECT p.id, p.origin, p.name, p.name as uniqueid, "
302 			"p.version, p.comment, p.desc, "
303 			"p.message, p.arch, p.maintainer, p.www, "
304 			"p.prefix, p.flatsize, p.time "
305 			"FROM packages AS p, pkg_requires AS ps, requires AS s "
306 			"WHERE p.id = ps.package_id "
307 				"AND ps.require_id = s.id "
308 				"AND s.require = ?1;";
309 
310 	assert(db != NULL);
311 
312 	pkg_debug(4, "Pkgdb: running '%s'", sql);
313 	if (sqlite3_prepare_v2(db->sqlite, sql, -1, &stmt, NULL) != SQLITE_OK) {
314 		ERROR_SQLITE(db->sqlite, sql);
315 		return (NULL);
316 	}
317 
318 	sqlite3_bind_text(stmt, 1, req, -1, SQLITE_TRANSIENT);
319 
320 	return (pkgdb_it_new_sqlite(db, stmt, PKG_INSTALLED, PKGDB_IT_FLAG_ONCE));
321 }
322 
323 struct pkgdb_it *
pkgdb_query_provide(struct pkgdb * db,const char * req)324 pkgdb_query_provide(struct pkgdb *db, const char *req)
325 {
326 	sqlite3_stmt	*stmt;
327 	const char	 sql[] = ""
328 		"SELECT p.id, p.origin, p.name, p.name as uniqueid, "
329 			"p.version, p.comment, p.desc, "
330 			"p.message, p.arch, p.maintainer, p.www, "
331 			"p.prefix, p.flatsize, p.time "
332 			"FROM packages AS p, pkg_provides AS ps, provides AS s "
333 			"WHERE p.id = ps.package_id "
334 				"AND ps.provide_id = s.id "
335 				"AND s.provide = ?1;";
336 
337 	assert(db != NULL);
338 
339 	pkg_debug(4, "Pkgdb: running '%s'", sql);
340 	if (sqlite3_prepare_v2(db->sqlite, sql, -1, &stmt, NULL) != SQLITE_OK) {
341 		ERROR_SQLITE(db->sqlite, sql);
342 		return (NULL);
343 	}
344 
345 	sqlite3_bind_text(stmt, 1, req, -1, SQLITE_TRANSIENT);
346 
347 	return (pkgdb_it_new_sqlite(db, stmt, PKG_INSTALLED, PKGDB_IT_FLAG_ONCE));
348 }
349 
350 struct pkgdb_it *
pkgdb_repo_query_cond(struct pkgdb * db,const char * cond,const char * pattern,match_t match,const char * repo)351 pkgdb_repo_query_cond(struct pkgdb *db, const char *cond, const char *pattern, match_t match,
352     const char *repo)
353 {
354 	struct pkgdb_it *it;
355 	struct pkg_repo_it *rit;
356 	struct _pkg_repo_list_item *cur;
357 
358 	it = pkgdb_it_new_repo(db);
359 	if (it == NULL)
360 		return (NULL);
361 
362 	LL_FOREACH(db->repos, cur) {
363 		if (repo == NULL || strcasecmp(cur->repo->name, repo) == 0) {
364 			rit = cur->repo->ops->query(cur->repo, cond, pattern, match);
365 			if (rit != NULL)
366 				pkgdb_it_repo_attach(it, rit);
367 		}
368 	}
369 
370 	return (it);
371 }
372 
pkgdb_repo_query(struct pkgdb * db,const char * pattern,match_t match,const char * repo)373 struct pkgdb_it *pkgdb_repo_query(struct pkgdb *db, const char *pattern,
374 	match_t match, const char *repo)
375 {
376 	return pkgdb_repo_query_cond(db, NULL, pattern, match, repo);
377 }
378 
379 struct pkgdb_it *
pkgdb_repo_shlib_require(struct pkgdb * db,const char * require,const char * repo)380 pkgdb_repo_shlib_require(struct pkgdb *db, const char *require, const char *repo)
381 {
382 	struct pkgdb_it *it;
383 	struct pkg_repo_it *rit;
384 	struct _pkg_repo_list_item *cur;
385 
386 	it = pkgdb_it_new_repo(db);
387 	if (it == NULL)
388 		return (NULL);
389 
390 	LL_FOREACH(db->repos, cur) {
391 		if (repo == NULL || strcasecmp(cur->repo->name, repo) == 0) {
392 			if (cur->repo->ops->shlib_required != NULL) {
393 				rit = cur->repo->ops->shlib_required(cur->repo, require);
394 				if (rit != NULL)
395 					pkgdb_it_repo_attach(it, rit);
396 			}
397 		}
398 	}
399 
400 	return (it);
401 }
402 
403 struct pkgdb_it *
pkgdb_repo_shlib_provide(struct pkgdb * db,const char * require,const char * repo)404 pkgdb_repo_shlib_provide(struct pkgdb *db, const char *require, const char *repo)
405 {
406 	struct pkgdb_it *it;
407 	struct pkg_repo_it *rit;
408 	struct _pkg_repo_list_item *cur;
409 
410 	it = pkgdb_it_new_repo(db);
411 	if (it == NULL)
412 		return (NULL);
413 
414 	LL_FOREACH(db->repos, cur) {
415 		if (repo == NULL || strcasecmp(cur->repo->name, repo) == 0) {
416 			if (cur->repo->ops->shlib_required != NULL) {
417 				rit = cur->repo->ops->shlib_provided(cur->repo, require);
418 				if (rit != NULL)
419 					pkgdb_it_repo_attach(it, rit);
420 			}
421 		}
422 	}
423 
424 	return (it);
425 }
426 
427 struct pkgdb_it *
pkgdb_repo_require(struct pkgdb * db,const char * require,const char * repo)428 pkgdb_repo_require(struct pkgdb *db, const char *require, const char *repo)
429 {
430 	struct pkgdb_it *it;
431 	struct pkg_repo_it *rit;
432 	struct _pkg_repo_list_item *cur;
433 
434 	it = pkgdb_it_new_repo(db);
435 	if (it == NULL)
436 		return (NULL);
437 
438 	LL_FOREACH(db->repos, cur) {
439 		if (repo == NULL || strcasecmp(cur->repo->name, repo) == 0) {
440 			if (cur->repo->ops->required != NULL) {
441 				rit = cur->repo->ops->required(cur->repo, require);
442 				if (rit != NULL)
443 					pkgdb_it_repo_attach(it, rit);
444 			}
445 		}
446 	}
447 
448 	return (it);
449 }
450 
451 struct pkgdb_it *
pkgdb_repo_provide(struct pkgdb * db,const char * require,const char * repo)452 pkgdb_repo_provide(struct pkgdb *db, const char *require, const char *repo)
453 {
454 	struct pkgdb_it *it;
455 	struct pkg_repo_it *rit;
456 	struct _pkg_repo_list_item *cur;
457 
458 	it = pkgdb_it_new_repo(db);
459 	if (it == NULL)
460 		return (NULL);
461 
462 	LL_FOREACH(db->repos, cur) {
463 		if (repo == NULL || strcasecmp(cur->repo->name, repo) == 0) {
464 			if (cur->repo->ops->required != NULL) {
465 				rit = cur->repo->ops->provided(cur->repo, require);
466 				if (rit != NULL)
467 					pkgdb_it_repo_attach(it, rit);
468 			}
469 		}
470 	}
471 
472 	return (it);
473 }
474 struct pkgdb_it *
pkgdb_repo_search(struct pkgdb * db,const char * pattern,match_t match,pkgdb_field field,pkgdb_field sort,const char * repo)475 pkgdb_repo_search(struct pkgdb *db, const char *pattern, match_t match,
476     pkgdb_field field, pkgdb_field sort, const char *repo)
477 {
478 	struct pkgdb_it *it;
479 	struct pkg_repo_it *rit;
480 	struct _pkg_repo_list_item *cur;
481 
482 	it = pkgdb_it_new_repo(db);
483 	if (it == NULL)
484 		return (NULL);
485 
486 	LL_FOREACH(db->repos, cur) {
487 		if (repo == NULL || strcasecmp(cur->repo->name, repo) == 0) {
488 			if (cur->repo->ops->search != NULL) {
489 				rit = cur->repo->ops->search(cur->repo, pattern, match,
490 					field, sort);
491 				if (rit != NULL)
492 					pkgdb_it_repo_attach(it, rit);
493 			}
494 		}
495 	}
496 
497 	return (it);
498 }
499