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