Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/pkg
Path: blob/main/libpkg/backup.c
2065 views
1
/*-
2
* Copyright (c) 2011-2020 Baptiste Daroussin <[email protected]>
3
* Copyright (c) 2012 Matthew Seaman <[email protected]>
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
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
if (ncols != 1)
50
return (-1); /* ABORT! */
51
52
*(off_t *)ps = strtoll(coltext[0], NULL, 10);
53
54
return (0);
55
}
56
57
static int
58
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
assert(src != NULL);
68
assert(dst != NULL);
69
70
ret = sqlite3_exec(dst, "PRAGMA main.locking_mode=EXCLUSIVE;"
71
"BEGIN IMMEDIATE;COMMIT;", NULL, NULL, &errmsg);
72
if (ret != SQLITE_OK)
73
goto out_error;
74
75
ret = sqlite3_exec(dst, "PRAGMA page_size", ps_cb, &page_size, &errmsg);
76
if (ret != SQLITE_OK)
77
goto out_error;
78
79
b = sqlite3_backup_init(dst, "main", src, "main");
80
81
pkg_emit_progress_start(NULL);
82
do {
83
ret = sqlite3_backup_step(b, NPAGES);
84
total = sqlite3_backup_pagecount(b);
85
done = total - sqlite3_backup_remaining(b);
86
pkg_emit_progress_tick(done, total);
87
88
if (ret != SQLITE_OK && ret != SQLITE_DONE ) {
89
if (ret == SQLITE_BUSY) {
90
sqlite3_sleep(250);
91
} else {
92
ERROR_SQLITE(dst, "backup step");
93
break;
94
}
95
}
96
} while(done < total);
97
98
ret = sqlite3_backup_finish(b);
99
pkg_emit_progress_tick(total, total);
100
101
sqlite3_exec(dst, "PRAGMA main.locking_mode=NORMAL;"
102
"BEGIN IMMEDIATE;COMMIT;", NULL, NULL, &errmsg);
103
104
if (ret == SQLITE_OK)
105
return (EPKG_OK);
106
107
out_error:
108
pkg_emit_error("sqlite error -- %s", errmsg);
109
sqlite3_free(errmsg);
110
return (EPKG_FATAL);
111
}
112
113
int
114
pkgdb_dump(struct pkgdb *db, const char *dest)
115
{
116
sqlite3 *backup;
117
int ret;
118
int destdbfd;
119
int savedfd;
120
char *dup, *dir;
121
122
dup = xstrdup(dest);
123
dir = get_dirname(dup);
124
destdbfd = open(dir, O_DIRECTORY|O_CLOEXEC);
125
if (destdbfd == -1)
126
pkg_fatal_errno("Unable to access '%s'", dir);
127
128
savedfd = pkg_get_dbdirfd();
129
ctx.pkg_dbdirfd = destdbfd;
130
ret = sqlite3_open(dest, &backup);
131
free(dup);
132
free(dir);
133
134
if (ret != SQLITE_OK) {
135
ERROR_SQLITE(backup, "sqlite3_open");
136
sqlite3_close(backup);
137
return (EPKG_FATAL);
138
}
139
140
pkg_emit_backup();
141
ret = copy_database(db->sqlite, backup);
142
143
sqlite3_close(backup);
144
ctx.pkg_dbdirfd = savedfd;
145
close(savedfd);
146
147
return (ret);
148
}
149
150
int
151
pkgdb_load(struct pkgdb *db, const char *src)
152
{
153
sqlite3 *restore;
154
int ret;
155
156
if (eaccess(src, R_OK))
157
pkg_fatal_errno("Unable to access '%s'", src);
158
159
ret = sqlite3_open(src, &restore);
160
161
if (ret != SQLITE_OK) {
162
ERROR_SQLITE(restore, "sqlite3_open");
163
sqlite3_close(restore);
164
return (EPKG_FATAL);
165
}
166
167
pkg_emit_restore();
168
ret = copy_database(restore, db->sqlite);
169
170
sqlite3_close(restore);
171
172
return (ret);
173
}
174
175