Branch data Line data Source code
1 : : /*-
2 : : * Copyright (c) 2011-2020 Baptiste Daroussin <bapt@FreeBSD.org>
3 : : * Copyright (c) 2012 Matthew Seaman <matthew@FreeBSD.org>
4 : : * All rights reserved.
5 : : *
6 : : * Redistribution and use in source and binary forms, with or without
7 : : * modification, are permitted provided that the following conditions
8 : : * are met:
9 : : * 1. Redistributions of source code must retain the above copyright
10 : : * notice, this list of conditions and the following disclaimer
11 : : * in this position and unchanged.
12 : : * 2. Redistributions in binary form must reproduce the above copyright
13 : : * notice, this list of conditions and the following disclaimer in the
14 : : * documentation and/or other materials provided with the distribution.
15 : : *
16 : : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
17 : : * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 : : * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 : : * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
20 : : * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 : : * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 : : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 : : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 : : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 : : * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 : : */
27 : :
28 : : #include <assert.h>
29 : : #include <fcntl.h>
30 : : #include <libgen.h>
31 : : #include <string.h>
32 : : #include <errno.h>
33 : :
34 : : #include "pkg.h"
35 : : #include "private/event.h"
36 : : #include "private/pkg.h"
37 : : #include "private/pkgdb.h"
38 : :
39 : : #include <bsd_compat.h>
40 : :
41 : : /* Number of pages to copy per call to sqlite3_backup_step()
42 : : Default page size is 1024 bytes on Unix */
43 : : #define NPAGES 4
44 : :
45 : : static int
46 : 0 : ps_cb(void *ps, int ncols, char **coltext, __unused char **colnames)
47 : : {
48 : : /* We should have exactly one row and one column of output */
49 [ # # ]: 0 : if (ncols != 1)
50 : 0 : return (-1); /* ABORT! */
51 : :
52 : 0 : *(off_t *)ps = strtoll(coltext[0], NULL, 10);
53 : :
54 : 0 : return (0);
55 : 0 : }
56 : :
57 : : static int
58 : 0 : copy_database(sqlite3 *src, sqlite3 *dst)
59 : : {
60 : : sqlite3_backup *b;
61 : : char *errmsg;
62 : : off_t total;
63 : : off_t done;
64 : : off_t page_size;
65 : : int ret;
66 : :
67 [ # # ]: 0 : assert(src != NULL);
68 [ # # ]: 0 : assert(dst != NULL);
69 : :
70 : 0 : ret = sqlite3_exec(dst, "PRAGMA main.locking_mode=EXCLUSIVE;"
71 : : "BEGIN IMMEDIATE;COMMIT;", NULL, NULL, &errmsg);
72 [ # # ]: 0 : if (ret != SQLITE_OK) {
73 : 0 : pkg_emit_error("sqlite error -- %s", errmsg);
74 : 0 : sqlite3_free(errmsg);
75 : 0 : return (EPKG_FATAL);
76 : : }
77 : :
78 : 0 : ret = sqlite3_exec(dst, "PRAGMA page_size", ps_cb, &page_size, &errmsg);
79 [ # # ]: 0 : if (ret != SQLITE_OK) {
80 : 0 : pkg_emit_error("sqlite error -- %s", errmsg);
81 : 0 : sqlite3_free(errmsg);
82 : 0 : return (EPKG_FATAL);
83 : : }
84 : :
85 : 0 : b = sqlite3_backup_init(dst, "main", src, "main");
86 : :
87 : 0 : pkg_emit_progress_start(NULL);
88 : 0 : do {
89 : 0 : ret = sqlite3_backup_step(b, NPAGES);
90 : 0 : total = sqlite3_backup_pagecount(b);
91 : 0 : done = total - sqlite3_backup_remaining(b);
92 : 0 : pkg_emit_progress_tick(done, total);
93 : :
94 [ # # # # ]: 0 : if (ret != SQLITE_OK && ret != SQLITE_DONE ) {
95 [ # # ]: 0 : if (ret == SQLITE_BUSY) {
96 : 0 : sqlite3_sleep(250);
97 : 0 : } else {
98 : 0 : ERROR_SQLITE(dst, "backup step");
99 : 0 : break;
100 : : }
101 : 0 : }
102 [ # # ]: 0 : } while(done < total);
103 : :
104 : 0 : ret = sqlite3_backup_finish(b);
105 : 0 : pkg_emit_progress_tick(total, total);
106 : :
107 : 0 : sqlite3_exec(dst, "PRAGMA main.locking_mode=NORMAL;"
108 : : "BEGIN IMMEDIATE;COMMIT;", NULL, NULL, &errmsg);
109 : :
110 [ # # ]: 0 : if (ret != SQLITE_OK) {
111 : 0 : pkg_emit_error("sqlite error -- %s", errmsg);
112 : 0 : sqlite3_free(errmsg);
113 : 0 : return (EPKG_FATAL);
114 : : }
115 : :
116 : 0 : return ret;
117 : 0 : }
118 : :
119 : : int
120 : 0 : pkgdb_dump(struct pkgdb *db, const char *dest)
121 : : {
122 : : sqlite3 *backup;
123 : : int ret;
124 : : int destdbfd;
125 : : int savedfd;
126 : : char *d;
127 : :
128 : 0 : d = xstrdup(dest);
129 : 0 : d = get_dirname(d);
130 : 0 : destdbfd = open(d, O_DIRECTORY|O_CLOEXEC);
131 [ # # ]: 0 : if (destdbfd == -1)
132 : 0 : pkg_fatal_errno("Unable to access '%s'", d);
133 : :
134 : 0 : savedfd = pkg_get_dbdirfd();
135 : 0 : ctx.pkg_dbdirfd = destdbfd;
136 : 0 : ret = sqlite3_open(dest, &backup);
137 : 0 : free(d);
138 : :
139 [ # # ]: 0 : if (ret != SQLITE_OK) {
140 : 0 : ERROR_SQLITE(backup, "sqlite3_open");
141 : 0 : sqlite3_close(backup);
142 : 0 : return (EPKG_FATAL);
143 : : }
144 : :
145 : 0 : pkg_emit_backup();
146 : 0 : ret = copy_database(db->sqlite, backup);
147 : :
148 : 0 : sqlite3_close(backup);
149 : 0 : ctx.pkg_dbdirfd = savedfd;
150 : 0 : close(savedfd);
151 : :
152 : 0 : return (ret == SQLITE_OK? EPKG_OK : EPKG_FATAL);
153 : 0 : }
154 : :
155 : : int
156 : 0 : pkgdb_load(struct pkgdb *db, const char *src)
157 : : {
158 : : sqlite3 *restore;
159 : : int ret;
160 : :
161 [ # # ]: 0 : if (eaccess(src, R_OK)) {
162 : 0 : pkg_fatal_errno("Unable to access '%s'", src);
163 : 0 : }
164 : :
165 : 0 : ret = sqlite3_open(src, &restore);
166 : :
167 [ # # ]: 0 : if (ret != SQLITE_OK) {
168 : 0 : ERROR_SQLITE(restore, "sqlite3_open");
169 : 0 : sqlite3_close(restore);
170 : 0 : return (EPKG_FATAL);
171 : : }
172 : :
173 : 0 : pkg_emit_restore();
174 : 0 : ret = copy_database(restore, db->sqlite);
175 : :
176 : 0 : sqlite3_close(restore);
177 : :
178 : 0 : return (ret == SQLITE_OK? EPKG_OK : EPKG_FATAL);
179 : 0 : }
|