Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2014, Vsevolod Stakhov
3 : : * Copyright (c) 2024, Baptiste Daroussin
4 : : *
5 : : * Redistribution and use in source and binary forms, with or without
6 : : * modification, are permitted provided that the following conditions are met:
7 : : * * Redistributions of source code must retain the above copyright
8 : : * notice, this list of conditions and the following disclaimer.
9 : : * * Redistributions in binary form must reproduce the above copyright
10 : : * notice, this list of conditions and the following disclaimer in the
11 : : * documentation and/or other materials provided with the distribution.
12 : : *
13 : : * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
14 : : * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 : : * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16 : : * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
17 : : * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 : : * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 : : * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20 : : * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 : : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22 : : * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 : : */
24 : :
25 : : #include <sys/param.h>
26 : : #include <sys/mount.h>
27 : :
28 : : #include <assert.h>
29 : : #include <fcntl.h>
30 : : #include <regex.h>
31 : : #include <grp.h>
32 : : #include <stdlib.h>
33 : : #include <stdio.h>
34 : : #include <stdbool.h>
35 : : #include <string.h>
36 : : #include <unistd.h>
37 : : #include <libgen.h>
38 : :
39 : : #include <sqlite3.h>
40 : :
41 : : #include <bsd_compat.h>
42 : :
43 : : #include "pkg.h"
44 : : #include "private/event.h"
45 : : #include "private/pkg.h"
46 : : #include "private/pkgdb.h"
47 : : #include "private/utils.h"
48 : : #include "binary.h"
49 : : #include "binary_private.h"
50 : :
51 : : extern struct pkg_ctx ctx;
52 : :
53 : : static int
54 : 237 : pkg_repo_binary_get_user_version(sqlite3 *sqlite, int *reposcver)
55 : : {
56 : : sqlite3_stmt *stmt;
57 : : int retcode;
58 : 237 : const char *sql = "PRAGMA user_version;";
59 : :
60 [ - + ]: 237 : if (sqlite3_prepare_v2(sqlite, sql, -1, &stmt, NULL) != SQLITE_OK) {
61 : 0 : ERROR_SQLITE(sqlite, sql);
62 : 0 : return (EPKG_FATAL);
63 : : }
64 : :
65 [ + - ]: 237 : if (sqlite3_step(stmt) == SQLITE_ROW) {
66 : 237 : *reposcver = sqlite3_column_int64(stmt, 0);
67 : 237 : retcode = EPKG_OK;
68 : 237 : } else {
69 : 0 : *reposcver = -1;
70 : 0 : retcode = EPKG_FATAL;
71 : : }
72 : 237 : sqlite3_finalize(stmt);
73 : 237 : return (retcode);
74 : 237 : }
75 : :
76 : : int
77 : 237 : pkg_repo_binary_check_version(struct pkg_repo *repo, sqlite3 *sqlite)
78 : : {
79 : : int reposcver;
80 : : int repomajor;
81 : : int ret;
82 : :
83 [ - + - + ]: 474 : if ((ret = pkg_repo_binary_get_user_version(sqlite, &reposcver))
84 : 237 : != EPKG_OK)
85 : 0 : return (ret); /* sqlite error */
86 : :
87 : : /*
88 : : * If the local pkgng uses a repo schema behind that used to
89 : : * create the repo, we may still be able use it for reading
90 : : * (ie pkg install), but pkg repo can't do an incremental
91 : : * update unless the actual schema matches the compiled in
92 : : * schema version.
93 : : *
94 : : * Use a major - minor version schema: as the user_version
95 : : * PRAGMA takes an integer version, encode this as MAJOR *
96 : : * 1000 + MINOR.
97 : : *
98 : : * So long as the major versions are the same, the local pkgng
99 : : * should be compatible with any repo created by a more recent
100 : : * pkgng, although it may need some modification of the repo
101 : : * schema
102 : : */
103 : :
104 : : /* --- Temporary ---- Grandfather in the old repo schema
105 : : version so this patch doesn't immediately invalidate all
106 : : the repos out there */
107 : :
108 [ + - ]: 237 : if (reposcver == 2)
109 : 0 : reposcver = 2000;
110 [ + - ]: 237 : if (reposcver == 3)
111 : 0 : reposcver = 2001;
112 : :
113 : 237 : repomajor = reposcver / 1000;
114 : :
115 [ - + ]: 237 : if (repomajor < REPO_SCHEMA_MAJOR) {
116 : 0 : pkg_emit_error("Repo %s (schema version %d) is too old - "
117 : 0 : "need at least schema %d", repo->name, reposcver,
118 : : REPO_SCHEMA_MAJOR * 1000);
119 : 0 : return (EPKG_REPOSCHEMA);
120 : : }
121 : :
122 [ - + ]: 237 : if (repomajor > REPO_SCHEMA_MAJOR) {
123 : 0 : pkg_emit_error("Repo %s (schema version %d) is too new - "
124 : 0 : "we can accept at most schema %d", repo->name, reposcver,
125 : : ((REPO_SCHEMA_MAJOR + 1) * 1000) - 1);
126 : 0 : return (EPKG_REPOSCHEMA);
127 : : }
128 : :
129 : : /* This is a repo schema version we can work with */
130 : :
131 [ - + ]: 237 : if (reposcver != REPO_SCHEMA_VERSION)
132 : 0 : return (EPKG_REPOSCHEMA);
133 : 237 : return (EPKG_OK);
134 : 237 : }
135 : :
136 : : int
137 : 311 : pkg_repo_binary_open(struct pkg_repo *repo, unsigned mode)
138 : : {
139 : : const char *filepath;
140 : 311 : sqlite3 *sqlite = NULL;
141 : : int flags, dbdirfd, fd, reposfd, thisrepofd;
142 : : int64_t res;
143 : : struct pkg_repo_it *it;
144 : 311 : struct pkg *pkg = NULL;
145 : :
146 : 311 : sqlite3_initialize();
147 : :
148 : 311 : pkgdb_syscall_overload();
149 : :
150 : 311 : dbdirfd = pkg_get_dbdirfd();
151 : 311 : reposfd = pkg_get_reposdirfd();
152 : 311 : thisrepofd = openat(reposfd, repo->name, O_DIRECTORY|O_CLOEXEC);
153 [ + - ]: 311 : if (thisrepofd == -1) {
154 [ # # ]: 0 : if (mkdirat(reposfd, repo->name, 0755) == -1)
155 : 0 : return( EPKG_FATAL);
156 : 0 : thisrepofd = openat(reposfd, repo->name, O_DIRECTORY|O_CLOEXEC);
157 : 0 : }
158 : :
159 : : /* Open metafile */
160 [ + + ]: 311 : if ((fd = openat(thisrepofd, "meta", O_RDONLY)) != -1) {
161 [ + + ]: 240 : if (pkg_repo_meta_load(fd, &repo->meta) != EPKG_OK) {
162 : 3 : pkg_emit_error("Repository %s load error: "
163 : 3 : "meta file cannot be loaded", repo->name);
164 : 3 : close(fd);
165 : 3 : return (EPKG_FATAL);
166 : : }
167 : 237 : close(fd);
168 : 237 : }
169 : :
170 : 308 : filepath = pkg_repo_binary_get_filename(repo);
171 : :
172 : : /* Always want read mode here */
173 [ + + ]: 308 : if (faccessat(dbdirfd, filepath, R_OK | mode, 0) != 0) {
174 : 71 : return (EPKG_ENOACCESS);
175 : : }
176 : :
177 : 237 : flags = (mode & W_OK) != 0 ? SQLITE_OPEN_READWRITE : SQLITE_OPEN_READONLY;
178 [ - + ]: 237 : if (sqlite3_open_v2(filepath, &sqlite, flags, NULL) != SQLITE_OK) {
179 : 0 : pkgdb_nfs_corruption(sqlite);
180 : 0 : pkg_emit_error("Repository %s load error: "
181 : : "cannot open sqlite3 db: %s",
182 : 0 : pkg_repo_name(repo), sqlite3_errmsg(sqlite));
183 : 0 : return (EPKG_FATAL);
184 : : }
185 : :
186 : : /* Sanitise sqlite database */
187 [ - + - + ]: 474 : if (get_pragma(sqlite, "SELECT count(name) FROM sqlite_master "
188 : 237 : "WHERE type='table' AND name='repodata';", &res, false) != EPKG_OK) {
189 : 0 : pkg_emit_error("Repository %s load error: unable to query db",
190 : 0 : pkg_repo_name(repo));
191 : 0 : sqlite3_close(sqlite);
192 : 0 : return (EPKG_FATAL);
193 : : }
194 : :
195 [ - + ]: 237 : if (res != 1) {
196 : 0 : pkg_emit_error("Repository %s contains no repodata table, "
197 : 0 : "need to re-create database", repo->name);
198 : 0 : sqlite3_close(sqlite);
199 : 0 : return (EPKG_FATAL);
200 : : }
201 : :
202 : : /* Check package site */
203 : 237 : char *req = sqlite3_mprintf("select count(key) from repodata "
204 : 237 : "WHERE key = \"packagesite\" and value = '%q'", pkg_repo_url(repo));
205 : :
206 : 237 : res = 0;
207 : 237 : get_pragma(sqlite, req, &res, true);
208 : 237 : sqlite3_free(req);
209 [ - + ]: 237 : if (res != 1) {
210 : 0 : pkg_emit_error("Repository %s has a wrong packagesite, need to "
211 : 0 : "re-create database", repo->name);
212 : 0 : sqlite3_close(sqlite);
213 : 0 : return (EPKG_FATAL);
214 : : }
215 : :
216 : : /* Check version */
217 [ - + ]: 237 : if (pkg_repo_binary_check_version(repo, sqlite) != EPKG_OK) {
218 : 0 : pkg_emit_error("need to re-create repo %s to upgrade schema version",
219 : 0 : repo->name);
220 : 0 : sqlite3_close(sqlite);
221 [ # # ]: 0 : if (mode & W_OK)
222 : 0 : (void)unlinkat(dbdirfd, filepath, 0);
223 : 0 : return (EPKG_REPOSCHEMA);
224 : : }
225 : :
226 : 237 : repo->priv = sqlite;
227 : : /* Check digests format */
228 [ + - ]: 237 : if ((it = pkg_repo_binary_query(repo, NULL, NULL, MATCH_ALL)) == NULL)
229 : 0 : return (EPKG_OK);
230 : :
231 [ + + ]: 237 : if (it->ops->next(it, &pkg, PKG_LOAD_BASIC) != EPKG_OK) {
232 : 72 : it->ops->free(it);
233 : 72 : return (EPKG_OK);
234 : : }
235 : 165 : it->ops->free(it);
236 [ + - - + ]: 165 : if (pkg->digest == NULL || !pkg_checksum_is_valid(pkg->digest, strlen(pkg->digest))) {
237 : 0 : pkg_emit_error("Repository %s has incompatible checksum format, need to "
238 : 0 : "re-create database", repo->name);
239 : 0 : pkg_free(pkg);
240 : 0 : sqlite3_close(sqlite);
241 : 0 : repo->priv = NULL;
242 : 0 : return (EPKG_FATAL);
243 : : }
244 : 165 : pkg_free(pkg);
245 : :
246 : 165 : return (EPKG_OK);
247 : 311 : }
248 : :
249 : : int
250 : 72 : pkg_repo_binary_create(struct pkg_repo *repo)
251 : : {
252 : : const char *filepath;
253 : 72 : sqlite3 *sqlite = NULL;
254 : : int retcode, dbdirfd;
255 : :
256 : 72 : sqlite3_initialize();
257 : :
258 : 72 : dbdirfd = pkg_get_dbdirfd();
259 : 72 : filepath = pkg_repo_binary_get_filename(repo);
260 : : /* Should never ever happen */
261 [ + - ]: 72 : if (faccessat(dbdirfd, filepath, R_OK, 0) == 0)
262 : 0 : return (EPKG_CONFLICT);
263 : :
264 : 72 : pkgdb_syscall_overload();
265 : :
266 : : /* Open for read/write/create */
267 [ - + ]: 72 : if (sqlite3_open(filepath, &sqlite) != SQLITE_OK) {
268 : 0 : pkgdb_nfs_corruption(sqlite);
269 : 0 : return (EPKG_FATAL);
270 : : }
271 : :
272 : 72 : retcode = sql_exec(sqlite, binary_repo_initsql, REPO_SCHEMA_VERSION);
273 : :
274 [ - + ]: 144 : if (retcode == EPKG_OK) {
275 : : sqlite3_stmt *stmt;
276 : 72 : const char sql[] = ""
277 : : "INSERT OR REPLACE INTO repodata (key, value) "
278 : : "VALUES (\"packagesite\", ?1);";
279 : :
280 : : /* register the packagesite */
281 [ - + - + ]: 144 : if (sql_exec(sqlite, "CREATE TABLE IF NOT EXISTS repodata ("
282 : : " key TEXT UNIQUE NOT NULL,"
283 : : " value TEXT NOT NULL"
284 : 72 : ");") != EPKG_OK) {
285 : 0 : pkg_emit_error("Unable to register the packagesite in the "
286 : : "database");
287 : 0 : retcode = EPKG_FATAL;
288 : 0 : goto cleanup;
289 : : }
290 : :
291 [ - + ]: 72 : if (sqlite3_prepare_v2(sqlite, sql, -1, &stmt, NULL) != SQLITE_OK) {
292 : 0 : ERROR_SQLITE(sqlite, sql);
293 : 0 : retcode = EPKG_FATAL;
294 : 0 : goto cleanup;
295 : : }
296 : :
297 : 72 : sqlite3_bind_text(stmt, 1, pkg_repo_url(repo), -1, SQLITE_STATIC);
298 : :
299 [ - + ]: 72 : if (sqlite3_step(stmt) != SQLITE_DONE) {
300 : 0 : ERROR_STMT_SQLITE(sqlite, stmt);
301 : 0 : sqlite3_finalize(stmt);
302 : 0 : retcode = EPKG_FATAL;
303 : 0 : goto cleanup;
304 : : }
305 : :
306 : 72 : sqlite3_finalize(stmt);
307 : 72 : }
308 : :
309 : : cleanup:
310 : 72 : sqlite3_close(sqlite);
311 : :
312 : 72 : return (retcode);
313 : 72 : }
314 : :
315 : : int
316 : 177 : pkg_repo_binary_init(struct pkg_repo *repo)
317 : : {
318 : 177 : int retcode = EPKG_OK;
319 [ + - ]: 177 : sqlite3 *sqlite = PRIV_GET(repo);
320 : :
321 : 177 : retcode = sql_exec(sqlite, "PRAGMA journal_mode=TRUNCATE;");
322 [ - + ]: 177 : if (retcode != EPKG_OK)
323 : 0 : return (retcode);
324 : :
325 : 177 : retcode = sql_exec(sqlite, "PRAGMA synchronous=FULL");
326 [ - + ]: 177 : if (retcode != EPKG_OK)
327 : 0 : return (retcode);
328 : :
329 : 177 : retcode = sql_exec(sqlite, "PRAGMA foreign_keys=on");
330 [ - + ]: 177 : if (retcode != EPKG_OK)
331 : 0 : return (retcode);
332 : 177 : sql_exec(sqlite, "PRAGMA mmap_size=268435456;");
333 : :
334 : :
335 : 177 : pkgdb_sqlcmd_init(sqlite, NULL, NULL);
336 : :
337 : 177 : retcode = pkg_repo_binary_init_prstatements(sqlite);
338 [ - + ]: 177 : if (retcode != EPKG_OK)
339 : 0 : return (retcode);
340 : :
341 : 177 : repo->priv = sqlite;
342 : :
343 : 177 : return (EPKG_OK);
344 : 177 : }
345 : :
346 : : int
347 : 237 : pkg_repo_binary_close(struct pkg_repo *repo, bool commit)
348 : : {
349 : 237 : int retcode = EPKG_OK;
350 [ + - ]: 237 : sqlite3 *sqlite = PRIV_GET(repo);
351 : :
352 [ + - ]: 237 : if (sqlite == NULL)
353 : 0 : return (retcode);
354 : :
355 [ + - ]: 237 : if (commit) {
356 [ # # ]: 0 : if (pkgdb_transaction_commit_sqlite(sqlite, NULL) != SQLITE_OK)
357 : 0 : retcode = EPKG_FATAL;
358 : 0 : }
359 : :
360 : 237 : pkg_repo_binary_finalize_prstatements();
361 : 237 : sqlite3_close(sqlite);
362 : :
363 : 237 : repo->priv = NULL;
364 : :
365 : 237 : return (retcode);
366 : 237 : }
367 : :
368 : : int
369 : 274 : pkg_repo_binary_access(struct pkg_repo *repo, unsigned mode)
370 : : {
371 : 274 : int ret = EPKG_OK;
372 : :
373 : 548 : ret = pkgdb_check_access(mode,
374 : 274 : pkg_repo_binary_get_filename(repo));
375 : :
376 : 274 : return (ret);
377 : : }
|