/ libpkg / backup.c
backup.c
  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  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 (faccessat(AT_FDCWD, src, R_OK, AT_EACCESS))
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  }