#include <assert.h>
#include <fcntl.h>
#include <libgen.h>
#include <string.h>
#include <errno.h>
#include "pkg.h"
#include "private/event.h"
#include "private/pkg.h"
#include "private/pkgdb.h"
#include <bsd_compat.h>
#define NPAGES 4
static int
ps_cb(void *ps, int ncols, char **coltext, __unused char **colnames)
{
if (ncols != 1)
return (-1);
*(off_t *)ps = strtoll(coltext[0], NULL, 10);
return (0);
}
static int
copy_database(sqlite3 *src, sqlite3 *dst)
{
sqlite3_backup *b;
char *errmsg;
off_t total;
off_t done;
off_t page_size;
int ret;
assert(src != NULL);
assert(dst != NULL);
ret = sqlite3_exec(dst, "PRAGMA main.locking_mode=EXCLUSIVE;"
"BEGIN IMMEDIATE;COMMIT;", NULL, NULL, &errmsg);
if (ret != SQLITE_OK)
goto out_error;
ret = sqlite3_exec(dst, "PRAGMA page_size", ps_cb, &page_size, &errmsg);
if (ret != SQLITE_OK)
goto out_error;
b = sqlite3_backup_init(dst, "main", src, "main");
pkg_emit_progress_start(NULL);
do {
ret = sqlite3_backup_step(b, NPAGES);
total = sqlite3_backup_pagecount(b);
done = total - sqlite3_backup_remaining(b);
pkg_emit_progress_tick(done, total);
if (ret != SQLITE_OK && ret != SQLITE_DONE ) {
if (ret == SQLITE_BUSY) {
sqlite3_sleep(250);
} else {
ERROR_SQLITE(dst, "backup step");
break;
}
}
} while(done < total);
ret = sqlite3_backup_finish(b);
pkg_emit_progress_tick(total, total);
sqlite3_exec(dst, "PRAGMA main.locking_mode=NORMAL;"
"BEGIN IMMEDIATE;COMMIT;", NULL, NULL, &errmsg);
if (ret == SQLITE_OK)
return (EPKG_OK);
out_error:
pkg_emit_error("sqlite error -- %s", errmsg);
sqlite3_free(errmsg);
return (EPKG_FATAL);
}
int
pkgdb_dump(struct pkgdb *db, const char *dest)
{
sqlite3 *backup;
int ret;
int destdbfd;
int savedfd;
char *dup, *dir;
dup = xstrdup(dest);
dir = get_dirname(dup);
destdbfd = open(dir, O_DIRECTORY|O_CLOEXEC);
if (destdbfd == -1)
pkg_fatal_errno("Unable to access '%s'", dir);
savedfd = pkg_get_dbdirfd();
ctx.pkg_dbdirfd = destdbfd;
ret = sqlite3_open(dest, &backup);
free(dup);
free(dir);
if (ret != SQLITE_OK) {
ERROR_SQLITE(backup, "sqlite3_open");
sqlite3_close(backup);
return (EPKG_FATAL);
}
pkg_emit_backup();
ret = copy_database(db->sqlite, backup);
sqlite3_close(backup);
ctx.pkg_dbdirfd = savedfd;
close(savedfd);
return (ret);
}
int
pkgdb_load(struct pkgdb *db, const char *src)
{
sqlite3 *restore;
int ret;
if (eaccess(src, R_OK))
pkg_fatal_errno("Unable to access '%s'", src);
ret = sqlite3_open(src, &restore);
if (ret != SQLITE_OK) {
ERROR_SQLITE(restore, "sqlite3_open");
sqlite3_close(restore);
return (EPKG_FATAL);
}
pkg_emit_restore();
ret = copy_database(restore, db->sqlite);
sqlite3_close(restore);
return (ret);
}