Line data Source code
1 : /*-
2 : * Copyright (c) 2011-2014 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 <libgen.h>
30 : #include <string.h>
31 : #include <errno.h>
32 :
33 : #include "pkg.h"
34 : #include "private/event.h"
35 : #include "private/pkg.h"
36 : #include "private/pkgdb.h"
37 :
38 : #include <bsd_compat.h>
39 :
40 : /* Number of pages to copy per call to sqlite3_backup_step()
41 : Default page size is 1024 bytes on Unix */
42 : #define NPAGES 4
43 :
44 : static int
45 0 : ps_cb(void *ps, int ncols, char **coltext, __unused char **colnames)
46 : {
47 : /* We should have exactly one row and one column of output */
48 0 : if (ncols != 1)
49 0 : return (-1); /* ABORT! */
50 :
51 0 : *(off_t *)ps = strtoll(coltext[0], NULL, 10);
52 :
53 0 : return (0);
54 : }
55 :
56 : static int
57 0 : copy_database(sqlite3 *src, sqlite3 *dst)
58 : {
59 : sqlite3_backup *b;
60 : char *errmsg;
61 : off_t total;
62 : off_t done;
63 : off_t page_size;
64 : int ret;
65 :
66 0 : assert(src != NULL);
67 0 : assert(dst != NULL);
68 :
69 0 : ret = sqlite3_exec(dst, "PRAGMA main.locking_mode=EXCLUSIVE;"
70 : "BEGIN IMMEDIATE;COMMIT;", NULL, NULL, &errmsg);
71 0 : if (ret != SQLITE_OK) {
72 0 : pkg_emit_error("sqlite error -- %s", errmsg);
73 0 : sqlite3_free(errmsg);
74 0 : return (EPKG_FATAL);
75 : }
76 :
77 0 : ret = sqlite3_exec(dst, "PRAGMA page_size", ps_cb, &page_size, &errmsg);
78 0 : if (ret != SQLITE_OK) {
79 0 : pkg_emit_error("sqlite error -- %s", errmsg);
80 0 : sqlite3_free(errmsg);
81 0 : return (EPKG_FATAL);
82 : }
83 :
84 0 : b = sqlite3_backup_init(dst, "main", src, "main");
85 :
86 0 : total = 0;
87 :
88 0 : pkg_emit_progress_start(NULL);
89 : do {
90 0 : ret = sqlite3_backup_step(b, NPAGES);
91 0 : total = sqlite3_backup_pagecount(b);
92 0 : done = total - sqlite3_backup_remaining(b);
93 0 : pkg_emit_progress_tick(done, total);
94 :
95 0 : if (ret != SQLITE_OK && ret != SQLITE_DONE ) {
96 0 : if (ret == SQLITE_BUSY) {
97 0 : sqlite3_sleep(250);
98 : } else {
99 0 : ERROR_SQLITE(dst, "backup step");
100 0 : break;
101 : }
102 : }
103 0 : } while(done < total);
104 :
105 0 : ret = sqlite3_backup_finish(b);
106 0 : pkg_emit_progress_tick(total, total);
107 :
108 0 : sqlite3_exec(dst, "PRAGMA main.locking_mode=NORMAL;"
109 : "BEGIN IMMEDIATE;COMMIT;", NULL, NULL, &errmsg);
110 :
111 0 : if (ret != SQLITE_OK) {
112 0 : pkg_emit_error("sqlite error -- %s", errmsg);
113 0 : sqlite3_free(errmsg);
114 0 : return (EPKG_FATAL);
115 : }
116 :
117 0 : return ret;
118 : }
119 :
120 : int
121 0 : pkgdb_dump(struct pkgdb *db, const char *dest)
122 : {
123 : sqlite3 *backup;
124 : int ret;
125 :
126 0 : if (eaccess(dest, W_OK)) {
127 0 : if (errno != ENOENT) {
128 0 : pkg_emit_error("eaccess(%s) -- %s", dest,
129 0 : strerror(errno));
130 0 : return (EPKG_FATAL);
131 : }
132 :
133 : /* Could we create the Sqlite DB file? */
134 0 : if (eaccess(bsd_dirname(dest), W_OK)) {
135 0 : pkg_emit_error("eaccess(%s) -- %s", bsd_dirname(dest),
136 0 : strerror(errno));
137 0 : return (EPKG_FATAL);
138 : }
139 : }
140 :
141 0 : ret = sqlite3_open(dest, &backup);
142 :
143 0 : if (ret != SQLITE_OK) {
144 0 : ERROR_SQLITE(backup, "sqlite3_open");
145 0 : sqlite3_close(backup);
146 0 : return (EPKG_FATAL);
147 : }
148 :
149 0 : pkg_emit_backup();
150 0 : ret = copy_database(db->sqlite, backup);
151 :
152 0 : sqlite3_close(backup);
153 :
154 0 : return (ret == SQLITE_OK? EPKG_OK : EPKG_FATAL);
155 : }
156 :
157 : int
158 0 : pkgdb_load(struct pkgdb *db, const char *src)
159 : {
160 : sqlite3 *restore;
161 : int ret;
162 :
163 0 : if (eaccess(src, R_OK)) {
164 0 : pkg_emit_error("eaccess(%s) -- %s", src, strerror(errno));
165 0 : return (EPKG_FATAL);
166 : }
167 :
168 0 : ret = sqlite3_open(src, &restore);
169 :
170 0 : if (ret != SQLITE_OK) {
171 0 : ERROR_SQLITE(restore, "sqlite3_open");
172 0 : sqlite3_close(restore);
173 0 : return (EPKG_FATAL);
174 : }
175 :
176 0 : pkg_emit_restore();
177 0 : ret = copy_database(restore, db->sqlite);
178 :
179 0 : sqlite3_close(restore);
180 :
181 0 : return (ret == SQLITE_OK? EPKG_OK : EPKG_FATAL);
182 : }
|