Line data Source code
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 <sys/param.h>
25 : #include <sys/mount.h>
26 :
27 : #include <assert.h>
28 : #include <errno.h>
29 : #include <regex.h>
30 : #include <grp.h>
31 : #include <stdlib.h>
32 : #include <stdio.h>
33 : #include <stdbool.h>
34 : #include <string.h>
35 : #include <unistd.h>
36 : #include <libgen.h>
37 :
38 : #include <sqlite3.h>
39 :
40 : #include <bsd_compat.h>
41 :
42 : #ifdef HAVE_SYS_STATFS_H
43 : #include <sys/statfs.h>
44 : #elif defined(HAVE_SYS_STATVFS_H)
45 : #include <sys/statvfs.h>
46 : #endif
47 :
48 : #include "pkg.h"
49 : #include "private/event.h"
50 : #include "private/pkg.h"
51 : #include "private/pkgdb.h"
52 : #include "private/utils.h"
53 : #include "binary.h"
54 : #include "binary_private.h"
55 :
56 : static void
57 0 : sqlite_file_exists(sqlite3_context *ctx, int argc, sqlite3_value **argv)
58 : {
59 : char fpath[MAXPATHLEN];
60 0 : sqlite3 *db = sqlite3_context_db_handle(ctx);
61 0 : char *path = bsd_dirname(sqlite3_db_filename(db, "main"));
62 : char *cksum;
63 :
64 0 : if (argc != 2) {
65 0 : sqlite3_result_error(ctx, "file_exists needs two argument", -1);
66 0 : return;
67 : }
68 :
69 0 : snprintf(fpath, sizeof(fpath), "%s/%s", path, sqlite3_value_text(argv[0]));
70 :
71 0 : if (access(fpath, R_OK) == 0) {
72 0 : cksum = pkg_checksum_file(fpath, PKG_HASH_TYPE_SHA256_HEX);
73 0 : if (cksum && strcmp(cksum, sqlite3_value_text(argv[1])) == 0)
74 0 : sqlite3_result_int(ctx, 1);
75 : else
76 0 : sqlite3_result_int(ctx, 0);
77 0 : free(cksum);
78 : } else {
79 0 : sqlite3_result_int(ctx, 0);
80 : }
81 : }
82 :
83 : static int
84 16 : pkg_repo_binary_get_user_version(sqlite3 *sqlite, int *reposcver)
85 : {
86 : sqlite3_stmt *stmt;
87 : int retcode;
88 16 : const char *sql = "PRAGMA user_version;";
89 :
90 16 : if (sqlite3_prepare_v2(sqlite, sql, -1, &stmt, NULL) != SQLITE_OK) {
91 0 : ERROR_SQLITE(sqlite, sql);
92 0 : return (EPKG_FATAL);
93 : }
94 :
95 16 : if (sqlite3_step(stmt) == SQLITE_ROW) {
96 16 : *reposcver = sqlite3_column_int64(stmt, 0);
97 16 : retcode = EPKG_OK;
98 : } else {
99 0 : *reposcver = -1;
100 0 : retcode = EPKG_FATAL;
101 : }
102 16 : sqlite3_finalize(stmt);
103 16 : return (retcode);
104 : }
105 :
106 : static int
107 0 : pkg_repo_binary_set_version(sqlite3 *sqlite, int reposcver)
108 : {
109 0 : const char *sql = "PRAGMA user_version = %d;";
110 :
111 0 : if (sql_exec(sqlite, sql, reposcver) != EPKG_OK) {
112 0 : ERROR_SQLITE(sqlite, sql);
113 0 : return (EPKG_FATAL);
114 : }
115 :
116 0 : return (EPKG_OK);
117 : }
118 :
119 : static int
120 0 : pkg_repo_binary_apply_change(struct pkg_repo *repo, sqlite3 *sqlite,
121 : const struct repo_changes *repo_changes, const char *updown,
122 : int version, int *next_version)
123 : {
124 : const struct repo_changes *change;
125 0 : bool found = false, in_trans = false;
126 0 : int ret = EPKG_OK;
127 : char *errmsg;
128 :
129 0 : for (change = repo_changes; change->version != -1; change++) {
130 0 : if (change->version == version) {
131 0 : found = true;
132 0 : break;
133 : }
134 : }
135 0 : if (!found) {
136 0 : pkg_emit_error("Unable to %s \"%s\" repo schema "
137 : "version %d (target version %d) "
138 : "-- change not found", updown, repo->name, version,
139 : REPO_SCHEMA_VERSION);
140 0 : return (EPKG_FATAL);
141 : }
142 :
143 : /* begin transaction */
144 0 : if ((ret = pkgdb_transaction_begin_sqlite(sqlite, "SCHEMA")) == EPKG_OK)
145 0 : in_trans = true;
146 :
147 : /* apply change */
148 0 : if (ret == EPKG_OK) {
149 0 : pkg_debug(4, "Pkgdb: running '%s'", change->sql);
150 0 : ret = sqlite3_exec(sqlite, change->sql, NULL, NULL, &errmsg);
151 0 : if (ret != SQLITE_OK) {
152 0 : pkg_emit_error("sqlite: %s", errmsg);
153 0 : sqlite3_free(errmsg);
154 0 : ret = EPKG_FATAL;
155 : }
156 : }
157 :
158 : /* update repo user_version */
159 0 : if (ret == EPKG_OK) {
160 0 : *next_version = change->next_version;
161 0 : ret = pkg_repo_binary_set_version(sqlite, *next_version);
162 : }
163 :
164 : /* commit or rollback */
165 0 : if (in_trans) {
166 0 : if (ret != EPKG_OK)
167 0 : pkgdb_transaction_rollback_sqlite(sqlite, "SCHEMA");
168 :
169 0 : if (pkgdb_transaction_commit_sqlite(sqlite, "SCHEMA") != EPKG_OK)
170 0 : ret = EPKG_FATAL;
171 : }
172 :
173 0 : if (ret == EPKG_OK) {
174 0 : pkg_emit_notice("Repo \"%s\" %s schema %d to %d: %s",
175 : repo->name, updown, version,
176 : change->next_version, change->message);
177 : }
178 :
179 0 : return (ret);
180 : }
181 :
182 : static int
183 0 : pkg_repo_binary_upgrade(struct pkg_repo *repo, sqlite3 *sqlite, int current_version)
184 : {
185 : int version;
186 : int next_version;
187 0 : int ret = EPKG_OK;
188 :
189 0 : for (version = current_version;
190 : version < REPO_SCHEMA_VERSION;
191 0 : version = next_version) {
192 0 : ret = pkg_repo_binary_apply_change(repo, sqlite, repo_upgrades,
193 : "upgrade", version, &next_version);
194 0 : if (ret != EPKG_OK)
195 0 : break;
196 0 : pkg_debug(1, "Upgrading repo database schema from %d to %d",
197 : version, next_version);
198 : }
199 0 : return (ret);
200 : }
201 :
202 : static int
203 0 : pkg_repo_binary_downgrade(struct pkg_repo *repo, sqlite3 *sqlite, int current_version)
204 : {
205 : int version;
206 : int next_version;
207 0 : int ret = EPKG_OK;
208 :
209 0 : for (version = current_version;
210 : version > REPO_SCHEMA_VERSION;
211 0 : version = next_version) {
212 :
213 0 : ret = pkg_repo_binary_apply_change(repo, sqlite, repo_downgrades,
214 : "downgrade", version, &next_version);
215 0 : if (ret != EPKG_OK)
216 0 : break;
217 0 : pkg_debug(1, "Downgrading repo database schema from %d to %d",
218 : version, next_version);
219 : }
220 0 : return (ret);
221 : }
222 :
223 : int
224 16 : pkg_repo_binary_check_version(struct pkg_repo *repo, sqlite3 *sqlite)
225 : {
226 : int reposcver;
227 : int repomajor;
228 : int ret;
229 :
230 16 : if ((ret = pkg_repo_binary_get_user_version(sqlite, &reposcver))
231 : != EPKG_OK)
232 0 : return (ret); /* sqlite error */
233 :
234 : /*
235 : * If the local pkgng uses a repo schema behind that used to
236 : * create the repo, we may still be able use it for reading
237 : * (ie pkg install), but pkg repo can't do an incremental
238 : * update unless the actual schema matches the compiled in
239 : * schema version.
240 : *
241 : * Use a major - minor version schema: as the user_version
242 : * PRAGMA takes an integer version, encode this as MAJOR *
243 : * 1000 + MINOR.
244 : *
245 : * So long as the major versions are the same, the local pkgng
246 : * should be compatible with any repo created by a more recent
247 : * pkgng, although it may need some modification of the repo
248 : * schema
249 : */
250 :
251 : /* --- Temporary ---- Grandfather in the old repo schema
252 : version so this patch doesn't immediately invalidate all
253 : the repos out there */
254 :
255 16 : if (reposcver == 2)
256 0 : reposcver = 2000;
257 16 : if (reposcver == 3)
258 0 : reposcver = 2001;
259 :
260 16 : repomajor = reposcver / 1000;
261 :
262 16 : if (repomajor < REPO_SCHEMA_MAJOR) {
263 0 : pkg_emit_error("Repo %s (schema version %d) is too old - "
264 : "need at least schema %d", repo->name, reposcver,
265 : REPO_SCHEMA_MAJOR * 1000);
266 0 : return (EPKG_REPOSCHEMA);
267 : }
268 :
269 16 : if (repomajor > REPO_SCHEMA_MAJOR) {
270 0 : pkg_emit_error("Repo %s (schema version %d) is too new - "
271 : "we can accept at most schema %d", repo->name, reposcver,
272 : ((REPO_SCHEMA_MAJOR + 1) * 1000) - 1);
273 0 : return (EPKG_REPOSCHEMA);
274 : }
275 :
276 : /* This is a repo schema version we can work with */
277 :
278 16 : ret = EPKG_OK;
279 :
280 16 : if (reposcver < REPO_SCHEMA_VERSION) {
281 0 : if (sqlite3_db_readonly(sqlite, "main")) {
282 0 : pkg_emit_error("Repo %s needs schema upgrade from "
283 : "%d to %d but it is opened readonly", repo->name,
284 : reposcver, REPO_SCHEMA_VERSION);
285 0 : ret = EPKG_FATAL;
286 : } else
287 0 : ret = pkg_repo_binary_upgrade(repo, sqlite, reposcver);
288 16 : } else if (reposcver > REPO_SCHEMA_VERSION) {
289 0 : if (sqlite3_db_readonly(sqlite, "main")) {
290 0 : pkg_emit_error("Repo %s needs schema downgrade from "
291 : "%d to %d but it is opened readonly", repo->name,
292 : reposcver, REPO_SCHEMA_VERSION
293 : );
294 0 : ret = EPKG_FATAL;
295 : } else
296 0 : ret = pkg_repo_binary_downgrade(repo, sqlite, reposcver);
297 : }
298 :
299 16 : return (ret);
300 : }
301 :
302 : int
303 23 : pkg_repo_binary_open(struct pkg_repo *repo, unsigned mode)
304 : {
305 : char filepath[MAXPATHLEN];
306 23 : const char *dbdir = NULL;
307 23 : sqlite3 *sqlite = NULL;
308 : int flags;
309 : int64_t res;
310 : struct pkg_repo_it *it;
311 23 : struct pkg *pkg = NULL;
312 :
313 23 : sqlite3_initialize();
314 23 : dbdir = pkg_object_string(pkg_config_get("PKG_DBDIR"));
315 :
316 : /*
317 : * Fall back on unix-dotfile locking strategy if on a network filesystem
318 : */
319 : #if defined(HAVE_SYS_STATVFS_H) && defined(ST_LOCAL)
320 : struct statvfs stfs;
321 :
322 : if (statvfs(dbdir, &stfs) == 0) {
323 : if ((stfs.f_flag & ST_LOCAL) != ST_LOCAL)
324 : sqlite3_vfs_register(sqlite3_vfs_find("unix-dotfile"), 1);
325 : }
326 : #elif defined(HAVE_STATFS) && defined(MNT_LOCAL)
327 : struct statfs stfs;
328 :
329 23 : if (statfs(dbdir, &stfs) == 0) {
330 23 : if ((stfs.f_flags & MNT_LOCAL) != MNT_LOCAL)
331 0 : sqlite3_vfs_register(sqlite3_vfs_find("unix-dotfile"), 1);
332 : }
333 : #endif
334 :
335 23 : snprintf(filepath, sizeof(filepath), "%s/%s.meta",
336 : dbdir, pkg_repo_name(repo));
337 :
338 : /* Open metafile */
339 23 : if (access(filepath, R_OK) != -1) {
340 16 : if (pkg_repo_meta_load(filepath, &repo->meta) != EPKG_OK)
341 0 : return (EPKG_FATAL);
342 : }
343 :
344 23 : snprintf(filepath, sizeof(filepath), "%s/%s",
345 : dbdir, pkg_repo_binary_get_filename(pkg_repo_name(repo)));
346 :
347 : /* Always want read mode here */
348 23 : if (access(filepath, R_OK | mode) != 0)
349 7 : return (EPKG_ENOACCESS);
350 :
351 16 : flags = (mode & W_OK) != 0 ? SQLITE_OPEN_READWRITE : SQLITE_OPEN_READONLY;
352 16 : if (sqlite3_open_v2(filepath, &sqlite, flags, NULL) != SQLITE_OK)
353 0 : return (EPKG_FATAL);
354 :
355 : /* Sanitise sqlite database */
356 16 : if (get_pragma(sqlite, "SELECT count(name) FROM sqlite_master "
357 : "WHERE type='table' AND name='repodata';", &res, false) != EPKG_OK) {
358 0 : pkg_emit_error("Unable to query repository");
359 0 : sqlite3_close(sqlite);
360 0 : return (EPKG_FATAL);
361 : }
362 :
363 16 : if (res != 1) {
364 0 : pkg_emit_notice("Repository %s contains no repodata table, "
365 : "need to re-create database", repo->name);
366 0 : sqlite3_close(sqlite);
367 0 : return (EPKG_FATAL);
368 : }
369 :
370 : /* Check package site */
371 16 : char *req = sqlite3_mprintf("select count(key) from repodata "
372 : "WHERE key = \"packagesite\" and value = '%q'", pkg_repo_url(repo));
373 :
374 16 : res = 0;
375 16 : get_pragma(sqlite, req, &res, true);
376 16 : sqlite3_free(req);
377 16 : if (res != 1) {
378 0 : pkg_emit_notice("Repository %s has a wrong packagesite, need to "
379 : "re-create database", repo->name);
380 0 : sqlite3_close(sqlite);
381 0 : return (EPKG_FATAL);
382 : }
383 :
384 : /* Check version */
385 16 : if (pkg_repo_binary_check_version(repo, sqlite) != EPKG_OK) {
386 0 : pkg_emit_error("need to re-create repo %s to upgrade schema version",
387 : repo->name);
388 0 : sqlite3_close(sqlite);
389 0 : if (mode & W_OK)
390 0 : unlink(filepath);
391 0 : return (EPKG_REPOSCHEMA);
392 : }
393 :
394 16 : repo->priv = sqlite;
395 : /* Check digests format */
396 16 : if ((it = pkg_repo_binary_query(repo, NULL, MATCH_ALL)) == NULL)
397 0 : return (EPKG_OK);
398 :
399 16 : if (it->ops->next(it, &pkg, PKG_LOAD_BASIC) != EPKG_OK) {
400 7 : it->ops->free(it);
401 7 : return (EPKG_OK);
402 : }
403 9 : it->ops->free(it);
404 9 : if (pkg->digest == NULL || !pkg_checksum_is_valid(pkg->digest, strlen(pkg->digest))) {
405 0 : pkg_emit_notice("Repository %s has incompatible checksum format, need to "
406 : "re-create database", repo->name);
407 0 : pkg_free(pkg);
408 0 : sqlite3_close(sqlite);
409 0 : repo->priv = NULL;
410 0 : return (EPKG_FATAL);
411 : }
412 9 : pkg_free(pkg);
413 :
414 9 : return (EPKG_OK);
415 : }
416 :
417 : int
418 7 : pkg_repo_binary_create(struct pkg_repo *repo)
419 : {
420 : char filepath[MAXPATHLEN];
421 7 : const char *dbdir = NULL;
422 7 : sqlite3 *sqlite = NULL;
423 : int retcode;
424 :
425 7 : sqlite3_initialize();
426 7 : dbdir = pkg_object_string(pkg_config_get("PKG_DBDIR"));
427 :
428 7 : snprintf(filepath, sizeof(filepath), "%s/%s",
429 : dbdir, pkg_repo_binary_get_filename(pkg_repo_name(repo)));
430 : /* Should never ever happen */
431 7 : if (access(filepath, R_OK) == 0)
432 0 : return (EPKG_CONFLICT);
433 :
434 : /*
435 : * Fall back on unix-dotfile locking strategy if on a network filesystem
436 : */
437 : #if defined(HAVE_SYS_STATVFS_H) && defined(ST_LOCAL)
438 : struct statvfs stfs;
439 :
440 : if (statvfs(dbdir, &stfs) == 0) {
441 : if ((stfs.f_flag & ST_LOCAL) != ST_LOCAL)
442 : sqlite3_vfs_register(sqlite3_vfs_find("unix-dotfile"), 1);
443 : }
444 : #elif defined(HAVE_STATFS) && defined(MNT_LOCAL)
445 : struct statfs stfs;
446 :
447 7 : if (statfs(dbdir, &stfs) == 0) {
448 7 : if ((stfs.f_flags & MNT_LOCAL) != MNT_LOCAL)
449 0 : sqlite3_vfs_register(sqlite3_vfs_find("unix-dotfile"), 1);
450 : }
451 : #endif
452 :
453 : /* Open for read/write/create */
454 7 : if (sqlite3_open(filepath, &sqlite) != SQLITE_OK)
455 0 : return (EPKG_FATAL);
456 :
457 7 : retcode = sql_exec(sqlite, binary_repo_initsql, REPO_SCHEMA_VERSION);
458 :
459 7 : if (retcode == EPKG_OK) {
460 : sqlite3_stmt *stmt;
461 7 : const char sql[] = ""
462 : "INSERT OR REPLACE INTO repodata (key, value) "
463 : "VALUES (\"packagesite\", ?1);";
464 :
465 : /* register the packagesite */
466 7 : if (sql_exec(sqlite, "CREATE TABLE IF NOT EXISTS repodata ("
467 : " key TEXT UNIQUE NOT NULL,"
468 : " value TEXT NOT NULL"
469 : ");") != EPKG_OK) {
470 0 : pkg_emit_error("Unable to register the packagesite in the "
471 : "database");
472 0 : retcode = EPKG_FATAL;
473 0 : goto cleanup;
474 : }
475 :
476 7 : if (sqlite3_prepare_v2(sqlite, sql, -1, &stmt, NULL) != SQLITE_OK) {
477 0 : ERROR_SQLITE(sqlite, sql);
478 0 : retcode = EPKG_FATAL;
479 0 : goto cleanup;
480 : }
481 :
482 7 : sqlite3_bind_text(stmt, 1, pkg_repo_url(repo), -1, SQLITE_STATIC);
483 :
484 7 : if (sqlite3_step(stmt) != SQLITE_DONE) {
485 0 : ERROR_SQLITE(sqlite, sql);
486 0 : sqlite3_finalize(stmt);
487 0 : retcode = EPKG_FATAL;
488 0 : goto cleanup;
489 : }
490 :
491 7 : sqlite3_finalize(stmt);
492 : }
493 :
494 : cleanup:
495 7 : sqlite3_close(sqlite);
496 :
497 7 : return (retcode);
498 : }
499 :
500 : int
501 15 : pkg_repo_binary_init(struct pkg_repo *repo)
502 : {
503 15 : int retcode = EPKG_OK;
504 15 : sqlite3 *sqlite = PRIV_GET(repo);
505 :
506 15 : sqlite3_create_function(sqlite, "file_exists", 2, SQLITE_ANY, NULL,
507 : sqlite_file_exists, NULL, NULL);
508 15 : retcode = sql_exec(sqlite, "PRAGMA synchronous=default");
509 15 : if (retcode != EPKG_OK)
510 0 : return (retcode);
511 :
512 15 : retcode = sql_exec(sqlite, "PRAGMA foreign_keys=on");
513 15 : if (retcode != EPKG_OK)
514 0 : return (retcode);
515 :
516 15 : pkgdb_sqlcmd_init(sqlite, NULL, NULL);
517 :
518 15 : retcode = pkg_repo_binary_init_prstatements(sqlite);
519 15 : if (retcode != EPKG_OK)
520 0 : return (retcode);
521 :
522 15 : repo->priv = sqlite;
523 :
524 15 : return (EPKG_OK);
525 : }
526 :
527 : int
528 16 : pkg_repo_binary_close(struct pkg_repo *repo, bool commit)
529 : {
530 16 : int retcode = EPKG_OK;
531 16 : sqlite3 *sqlite = PRIV_GET(repo);
532 :
533 16 : if (sqlite == NULL)
534 0 : return (retcode);
535 :
536 16 : if (commit) {
537 0 : if (pkgdb_transaction_commit_sqlite(sqlite, NULL) != SQLITE_OK)
538 0 : retcode = EPKG_FATAL;
539 : }
540 :
541 16 : pkg_repo_binary_finalize_prstatements();
542 16 : sqlite3_free(sqlite);
543 :
544 16 : repo->priv = NULL;
545 :
546 16 : return (retcode);
547 : }
548 :
549 : int
550 16 : pkg_repo_binary_access(struct pkg_repo *repo, unsigned mode)
551 : {
552 : const pkg_object *o;
553 : const char *dbdir;
554 16 : int ret = EPKG_OK;
555 :
556 16 : o = pkg_config_get("PKG_DBDIR");
557 16 : dbdir = pkg_object_string(o);
558 :
559 16 : ret = pkgdb_check_access(mode, dbdir,
560 : pkg_repo_binary_get_filename(pkg_repo_name(repo)));
561 :
562 16 : return (ret);
563 : }
|