Line data Source code
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 *
62 208 : pkgdb_get_pattern_query(const char *pattern, match_t match)
63 : {
64 208 : char *checkorigin = NULL;
65 208 : char *checkuid = NULL;
66 208 : const char *comp = NULL;
67 :
68 208 : if (pattern != NULL) {
69 176 : checkuid = strchr(pattern, '~');
70 176 : if (checkuid == NULL)
71 176 : checkorigin = strchr(pattern, '/');
72 : }
73 :
74 208 : switch (match) {
75 : case MATCH_ALL:
76 32 : comp = "";
77 32 : break;
78 : case MATCH_EXACT:
79 141 : if (pkgdb_case_sensitive()) {
80 0 : if (checkuid == NULL) {
81 0 : if (checkorigin == NULL)
82 0 : comp = " WHERE name = ?1 "
83 : "OR (name = SPLIT_VERSION('name', ?1) AND "
84 : " version = SPLIT_VERSION('version', ?1))";
85 : else
86 0 : comp = " WHERE origin = ?1";
87 : } else {
88 0 : comp = " WHERE name = ?1";
89 : }
90 : } else {
91 141 : if (checkuid == NULL) {
92 141 : if (checkorigin == NULL)
93 140 : 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 1 : comp = " WHERE origin = ?1 COLLATE NOCASE";
98 : } else {
99 0 : comp = " WHERE name = ?1 COLLATE NOCASE";
100 : }
101 : }
102 141 : break;
103 : case MATCH_GLOB:
104 5 : if (checkuid == NULL) {
105 5 : if (checkorigin == NULL)
106 5 : comp = " WHERE name GLOB ?1 "
107 : "OR name || '-' || version GLOB ?1";
108 : else
109 0 : comp = " WHERE origin GLOB ?1";
110 : } else {
111 0 : comp = " WHERE name = ?1";
112 : }
113 5 : break;
114 : case MATCH_REGEX:
115 0 : if (checkuid == NULL) {
116 0 : if (checkorigin == NULL)
117 0 : comp = " WHERE name REGEXP ?1 "
118 : "OR name || '-' || version REGEXP ?1";
119 : else
120 0 : comp = " WHERE origin REGEXP ?1";
121 : } else {
122 0 : comp = " WHERE name = ?1";
123 : }
124 0 : break;
125 : case MATCH_CONDITION:
126 30 : comp = pattern;
127 30 : break;
128 : case MATCH_FTS:
129 0 : if (checkorigin == NULL)
130 0 : comp = " WHERE id IN (SELECT id FROM pkg_search WHERE name MATCH ?1)";
131 : else
132 0 : comp = " WHERE id IN (SELECT id FROM pkg_search WHERE origin MATCH ?1)";
133 0 : break;
134 : }
135 :
136 208 : return (comp);
137 : }
138 :
139 : struct pkgdb_it *
140 142 : pkgdb_query(struct pkgdb *db, const char *pattern, match_t match)
141 : {
142 : char sql[BUFSIZ];
143 : sqlite3_stmt *stmt;
144 142 : const char *comp = NULL;
145 :
146 142 : assert(db != NULL);
147 :
148 142 : if (match != MATCH_ALL && (pattern == NULL || pattern[0] == '\0'))
149 0 : return (NULL);
150 :
151 142 : comp = pkgdb_get_pattern_query(pattern, match);
152 :
153 142 : sqlite3_snprintf(sizeof(sql), sql,
154 : "SELECT id, origin, name, name as uniqueid, "
155 : "version, comment, desc, "
156 : "message, arch, maintainer, www, "
157 : "prefix, flatsize, licenselogic, automatic, "
158 : "locked, time, manifestdigest "
159 : "FROM packages AS p%s "
160 : "ORDER BY p.name;", comp);
161 :
162 142 : pkg_debug(4, "Pkgdb: running '%s'", sql);
163 142 : if (sqlite3_prepare_v2(db->sqlite, sql, -1, &stmt, NULL) != SQLITE_OK) {
164 0 : ERROR_SQLITE(db->sqlite, sql);
165 0 : return (NULL);
166 : }
167 :
168 142 : if (match != MATCH_ALL && match != MATCH_CONDITION)
169 96 : sqlite3_bind_text(stmt, 1, pattern, -1, SQLITE_TRANSIENT);
170 :
171 142 : return (pkgdb_it_new_sqlite(db, stmt, PKG_INSTALLED, PKGDB_IT_FLAG_ONCE));
172 : }
173 :
174 : struct pkgdb_it *
175 1 : pkgdb_query_which(struct pkgdb *db, const char *path, bool glob)
176 : {
177 : sqlite3_stmt *stmt;
178 : char sql[BUFSIZ];
179 :
180 1 : assert(db != NULL);
181 :
182 1 : if (path == NULL)
183 0 : return (NULL);
184 :
185 1 : sqlite3_snprintf(sizeof(sql), sql,
186 : "SELECT p.id, p.origin, p.name, p.name as uniqueid, "
187 : "p.version, p.comment, p.desc, "
188 : "p.message, p.arch, p.maintainer, p.www, "
189 : "p.prefix, p.flatsize, p.time "
190 : "FROM packages AS p "
191 : "LEFT JOIN files AS f ON p.id = f.package_id "
192 : "WHERE f.path %s ?1 GROUP BY p.id;", glob ? "GLOB" : "=");
193 :
194 1 : pkg_debug(4, "Pkgdb: running '%s'", sql);
195 1 : if (sqlite3_prepare_v2(db->sqlite, sql, -1, &stmt, NULL) != SQLITE_OK) {
196 0 : ERROR_SQLITE(db->sqlite, sql);
197 0 : return (NULL);
198 : }
199 :
200 1 : sqlite3_bind_text(stmt, 1, path, -1, SQLITE_TRANSIENT);
201 :
202 1 : return (pkgdb_it_new_sqlite(db, stmt, PKG_INSTALLED, PKGDB_IT_FLAG_ONCE));
203 : }
204 :
205 : struct pkgdb_it *
206 0 : pkgdb_query_shlib_require(struct pkgdb *db, const char *shlib)
207 : {
208 : sqlite3_stmt *stmt;
209 0 : const char sql[] = ""
210 : "SELECT p.id, p.origin, p.name, p.name as uniqueid, "
211 : "p.version, p.comment, p.desc, "
212 : "p.message, p.arch, p.maintainer, p.www, "
213 : "p.prefix, p.flatsize, p.time "
214 : "FROM packages AS p, pkg_shlibs_required AS ps, shlibs AS s "
215 : "WHERE p.id = ps.package_id "
216 : "AND ps.shlib_id = s.id "
217 : "AND s.name = ?1;";
218 :
219 0 : assert(db != NULL);
220 :
221 0 : pkg_debug(4, "Pkgdb: running '%s'", sql);
222 0 : if (sqlite3_prepare_v2(db->sqlite, sql, -1, &stmt, NULL) != SQLITE_OK) {
223 0 : ERROR_SQLITE(db->sqlite, sql);
224 0 : return (NULL);
225 : }
226 :
227 0 : sqlite3_bind_text(stmt, 1, shlib, -1, SQLITE_TRANSIENT);
228 :
229 0 : return (pkgdb_it_new_sqlite(db, stmt, PKG_INSTALLED, PKGDB_IT_FLAG_ONCE));
230 : }
231 :
232 : struct pkgdb_it *
233 0 : pkgdb_query_shlib_provide(struct pkgdb *db, const char *shlib)
234 : {
235 : sqlite3_stmt *stmt;
236 0 : const char sql[] = ""
237 : "SELECT p.id, p.origin, p.name, p.name as uniqueid, "
238 : "p.version, p.comment, p.desc, "
239 : "p.message, p.arch, p.maintainer, p.www, "
240 : "p.prefix, p.flatsize, p.time "
241 : "FROM packages AS p, pkg_shlibs_provided AS ps, shlibs AS s "
242 : "WHERE p.id = ps.package_id "
243 : "AND ps.shlib_id = s.id "
244 : "AND s.name = ?1;";
245 :
246 0 : assert(db != NULL);
247 :
248 0 : pkg_debug(4, "Pkgdb: running '%s'", sql);
249 0 : if (sqlite3_prepare_v2(db->sqlite, sql, -1, &stmt, NULL) != SQLITE_OK) {
250 0 : ERROR_SQLITE(db->sqlite, sql);
251 0 : return (NULL);
252 : }
253 :
254 0 : sqlite3_bind_text(stmt, 1, shlib, -1, SQLITE_TRANSIENT);
255 :
256 0 : return (pkgdb_it_new_sqlite(db, stmt, PKG_INSTALLED, PKGDB_IT_FLAG_ONCE));
257 : }
258 :
259 : struct pkgdb_it *
260 0 : pkgdb_query_require(struct pkgdb *db, const char *req)
261 : {
262 : sqlite3_stmt *stmt;
263 0 : const char sql[] = ""
264 : "SELECT p.id, p.origin, p.name, p.name as uniqueid, "
265 : "p.version, p.comment, p.desc, "
266 : "p.message, p.arch, p.maintainer, p.www, "
267 : "p.prefix, p.flatsize, p.time "
268 : "FROM packages AS p, pkg_requires AS ps, requires AS s "
269 : "WHERE p.id = ps.package_id "
270 : "AND ps.require_id = s.id "
271 : "AND s.require = ?1;";
272 :
273 0 : assert(db != NULL);
274 :
275 0 : pkg_debug(4, "Pkgdb: running '%s'", sql);
276 0 : if (sqlite3_prepare_v2(db->sqlite, sql, -1, &stmt, NULL) != SQLITE_OK) {
277 0 : ERROR_SQLITE(db->sqlite, sql);
278 0 : return (NULL);
279 : }
280 :
281 0 : sqlite3_bind_text(stmt, 1, req, -1, SQLITE_TRANSIENT);
282 :
283 0 : return (pkgdb_it_new_sqlite(db, stmt, PKG_INSTALLED, PKGDB_IT_FLAG_ONCE));
284 : }
285 :
286 : struct pkgdb_it *
287 5 : pkgdb_query_provide(struct pkgdb *db, const char *req)
288 : {
289 : sqlite3_stmt *stmt;
290 5 : const char sql[] = ""
291 : "SELECT p.id, p.origin, p.name, p.name as uniqueid, "
292 : "p.version, p.comment, p.desc, "
293 : "p.message, p.arch, p.maintainer, p.www, "
294 : "p.prefix, p.flatsize, p.time "
295 : "FROM packages AS p, pkg_provides AS ps, provides AS s "
296 : "WHERE p.id = ps.package_id "
297 : "AND ps.provide_id = s.id "
298 : "AND s.provide = ?1;";
299 :
300 5 : assert(db != NULL);
301 :
302 5 : pkg_debug(4, "Pkgdb: running '%s'", sql);
303 5 : if (sqlite3_prepare_v2(db->sqlite, sql, -1, &stmt, NULL) != SQLITE_OK) {
304 0 : ERROR_SQLITE(db->sqlite, sql);
305 0 : return (NULL);
306 : }
307 :
308 5 : sqlite3_bind_text(stmt, 1, req, -1, SQLITE_TRANSIENT);
309 :
310 5 : return (pkgdb_it_new_sqlite(db, stmt, PKG_INSTALLED, PKGDB_IT_FLAG_ONCE));
311 : }
312 :
313 : struct pkgdb_it *
314 50 : pkgdb_repo_query(struct pkgdb *db, const char *pattern, match_t match,
315 : const char *repo)
316 : {
317 : struct pkgdb_it *it;
318 : struct pkg_repo_it *rit;
319 : struct _pkg_repo_list_item *cur;
320 :
321 50 : it = pkgdb_it_new_repo(db);
322 50 : if (it == NULL)
323 0 : return (NULL);
324 :
325 100 : LL_FOREACH(db->repos, cur) {
326 50 : if (repo == NULL || strcasecmp(cur->repo->name, repo) == 0) {
327 50 : rit = cur->repo->ops->query(cur->repo, pattern, match);
328 50 : if (rit != NULL)
329 50 : pkgdb_it_repo_attach(it, rit);
330 : }
331 : }
332 :
333 50 : return (it);
334 : }
335 :
336 : struct pkgdb_it *
337 0 : pkgdb_repo_shlib_require(struct pkgdb *db, const char *require, const char *repo)
338 : {
339 : struct pkgdb_it *it;
340 : struct pkg_repo_it *rit;
341 : struct _pkg_repo_list_item *cur;
342 :
343 0 : it = pkgdb_it_new_repo(db);
344 0 : if (it == NULL)
345 0 : return (NULL);
346 :
347 0 : LL_FOREACH(db->repos, cur) {
348 0 : if (repo == NULL || strcasecmp(cur->repo->name, repo) == 0) {
349 0 : if (cur->repo->ops->shlib_required != NULL) {
350 0 : rit = cur->repo->ops->shlib_required(cur->repo, require);
351 0 : if (rit != NULL)
352 0 : pkgdb_it_repo_attach(it, rit);
353 : }
354 : }
355 : }
356 :
357 0 : return (it);
358 : }
359 :
360 : struct pkgdb_it *
361 0 : pkgdb_repo_shlib_provide(struct pkgdb *db, const char *require, const char *repo)
362 : {
363 : struct pkgdb_it *it;
364 : struct pkg_repo_it *rit;
365 : struct _pkg_repo_list_item *cur;
366 :
367 0 : it = pkgdb_it_new_repo(db);
368 0 : if (it == NULL)
369 0 : return (NULL);
370 :
371 0 : LL_FOREACH(db->repos, cur) {
372 0 : if (repo == NULL || strcasecmp(cur->repo->name, repo) == 0) {
373 0 : if (cur->repo->ops->shlib_required != NULL) {
374 0 : rit = cur->repo->ops->shlib_provided(cur->repo, require);
375 0 : if (rit != NULL)
376 0 : pkgdb_it_repo_attach(it, rit);
377 : }
378 : }
379 : }
380 :
381 0 : return (it);
382 : }
383 :
384 : struct pkgdb_it *
385 0 : pkgdb_repo_require(struct pkgdb *db, const char *require, const char *repo)
386 : {
387 : struct pkgdb_it *it;
388 : struct pkg_repo_it *rit;
389 : struct _pkg_repo_list_item *cur;
390 :
391 0 : it = pkgdb_it_new_repo(db);
392 0 : if (it == NULL)
393 0 : return (NULL);
394 :
395 0 : LL_FOREACH(db->repos, cur) {
396 0 : if (repo == NULL || strcasecmp(cur->repo->name, repo) == 0) {
397 0 : if (cur->repo->ops->required != NULL) {
398 0 : rit = cur->repo->ops->required(cur->repo, require);
399 0 : if (rit != NULL)
400 0 : pkgdb_it_repo_attach(it, rit);
401 : }
402 : }
403 : }
404 :
405 0 : return (it);
406 : }
407 :
408 : struct pkgdb_it *
409 5 : pkgdb_repo_provide(struct pkgdb *db, const char *require, const char *repo)
410 : {
411 : struct pkgdb_it *it;
412 : struct pkg_repo_it *rit;
413 : struct _pkg_repo_list_item *cur;
414 :
415 5 : it = pkgdb_it_new_repo(db);
416 5 : if (it == NULL)
417 0 : return (NULL);
418 :
419 10 : LL_FOREACH(db->repos, cur) {
420 5 : if (repo == NULL || strcasecmp(cur->repo->name, repo) == 0) {
421 5 : if (cur->repo->ops->required != NULL) {
422 5 : rit = cur->repo->ops->provided(cur->repo, require);
423 5 : if (rit != NULL)
424 5 : pkgdb_it_repo_attach(it, rit);
425 : }
426 : }
427 : }
428 :
429 5 : return (it);
430 : }
431 : struct pkgdb_it *
432 0 : pkgdb_repo_search(struct pkgdb *db, const char *pattern, match_t match,
433 : pkgdb_field field, pkgdb_field sort, const char *repo)
434 : {
435 : struct pkgdb_it *it;
436 : struct pkg_repo_it *rit;
437 : struct _pkg_repo_list_item *cur;
438 :
439 0 : it = pkgdb_it_new_repo(db);
440 0 : if (it == NULL)
441 0 : return (NULL);
442 :
443 0 : LL_FOREACH(db->repos, cur) {
444 0 : if (repo == NULL || strcasecmp(cur->repo->name, repo) == 0) {
445 0 : if (cur->repo->ops->search != NULL) {
446 0 : rit = cur->repo->ops->search(cur->repo, pattern, match,
447 : field, sort);
448 0 : if (rit != NULL)
449 0 : pkgdb_it_repo_attach(it, rit);
450 : }
451 : }
452 : }
453 :
454 0 : return (it);
455 : }
|