160107Sobrien/*- 248663Syokota * Copyright (c) 2007 Diomidis Spinellis 348663Syokota * All rights reserved. 448663Syokota * 548663Syokota * Redistribution and use in source and binary forms, with or without 648663Syokota * modification, are permitted provided that the following conditions 748663Syokota * are met: 848663Syokota * 1. Redistributions of source code must retain the above copyright 948663Syokota * notice, this list of conditions and the following disclaimer. 1048663Syokota * 2. Redistributions in binary form must reproduce the above copyright 1148663Syokota * notice, this list of conditions and the following disclaimer in the 1248663Syokota * documentation and/or other materials provided with the distribution. 1348663Syokota * 1448663Syokota * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1548663Syokota * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1648663Syokota * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1748663Syokota * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1848663Syokota * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1948663Syokota * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2048663Syokota * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2148663Syokota * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2248663Syokota * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2348663Syokota * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2461118Sroberto * SUCH DAMAGE. 2548663Syokota * 2648663Syokota */ 2748663Syokota 2848663Syokota#include <sys/cdefs.h> 2948663Syokota__FBSDID("$FreeBSD$"); 3048663Syokota 3148663Syokota#include <sys/types.h> 3248663Syokota#include <sys/acct.h> 3348663Syokota 3448663Syokota#include <ctype.h> 3548663Syokota#include <err.h> 3648663Syokota#include <errno.h> 3748663Syokota#include <db.h> 3848663Syokota#include <fcntl.h> 3948663Syokota#include <stdio.h> 4048663Syokota#include <stdlib.h> 4148663Syokota#include <string.h> 4248663Syokota#include <limits.h> 4348663Syokota 4448663Syokota#include "extern.h" 4548663Syokota 4648663Syokota/* Key used to store the version of the database data elements. */ 4748663Syokota#define VERSION_KEY "\0VERSION" 4848663Syokota 4948663Syokota/* 5048663Syokota * Create the in-memory database, *mdb. 5148663Syokota * If iflag is not set, fill-in mdb with the records of the disk-based 5248663Syokota * database dbname. 5348663Syokota * Upgrade old-version records by calling v1_to_v2. 5448663Syokota * Return 0 if OK, -1 on error. 5548663Syokota */ 5648663Syokotaint 5748663Syokotadb_copy_in(DB **mdb, const char *dbname, const char *uname, BTREEINFO *bti, 5848663Syokota int (*v1_to_v2)(DBT *key, DBT *data)) 5948663Syokota{ 6048663Syokota DBT key, data; 6148663Syokota DB *ddb; 6248663Syokota int error, rv, version; 6348663Syokota 6448663Syokota if ((*mdb = dbopen(NULL, O_RDWR, 0, DB_BTREE, bti)) == NULL) 6548663Syokota return (-1); 6648663Syokota 6748663Syokota if (iflag) 6848663Syokota return (0); 6948663Syokota 7048663Syokota if ((ddb = dbopen(dbname, O_RDONLY, 0, DB_BTREE, bti)) == NULL) { 7148663Syokota if (errno == ENOENT) 7248663Syokota return (0); 7348663Syokota warn("retrieving %s summary", uname); 7448663Syokota db_destroy(*mdb, uname); 7548663Syokota return (-1); 7648663Syokota } 7748663Syokota 7848663Syokota error = 0; 7948663Syokota 8048663Syokota /* Obtain/set version. */ 8148663Syokota version = 1; 8248663Syokota key.data = (void*)&VERSION_KEY; 8348663Syokota key.size = sizeof(VERSION_KEY); 8448663Syokota 8548663Syokota rv = DB_GET(ddb, &key, &data, 0); 8648663Syokota if (rv < 0) { 8748663Syokota warn("get version key from %s stats", uname); 8848663Syokota error = -1; 8948663Syokota goto closeout; 9048663Syokota } else if (rv == 0) { /* It's there; verify version. */ 9148663Syokota if (data.size != sizeof(version)) { 9248663Syokota warnx("invalid version size %zd in %s", 9348663Syokota data.size, uname); 9448663Syokota error = -1; 9548663Syokota goto closeout; 9648663Syokota } 9748663Syokota memcpy(&version, data.data, data.size); 9874119Sache if (version != 2) { 9948663Syokota warnx("unsupported version %d in %s", 10048663Syokota version, uname); 10148663Syokota error = -1; 10248663Syokota goto closeout; 10348663Syokota } 10448663Syokota } 10548663Syokota 10648663Syokota for (rv = DB_SEQ(ddb, &key, &data, R_FIRST); rv == 0; 10748663Syokota rv = DB_SEQ(ddb, &key, &data, R_NEXT)) { 10874119Sache 10948663Syokota /* See if this is a version record. */ 11048663Syokota if (key.size == sizeof(VERSION_KEY) && 11148663Syokota memcmp(key.data, VERSION_KEY, sizeof(VERSION_KEY)) == 0) 11248663Syokota continue; 11348663Syokota 11448663Syokota /* Convert record from v1, if needed. */ 11548663Syokota if (version == 1 && v1_to_v2(&key, &data) < 0) { 11648663Syokota warn("converting %s stats", uname); 11748663Syokota error = -1; 11848663Syokota goto closeout; 11948663Syokota } 12048663Syokota 12148663Syokota /* Copy record to the in-memory database. */ 12248663Syokota if ((rv = DB_PUT(*mdb, &key, &data, 0)) < 0) { 12348663Syokota warn("initializing %s stats", uname); 12448663Syokota error = -1; 12548663Syokota goto closeout; 12648663Syokota } 12748663Syokota } 12848663Syokota if (rv < 0) { 12948663Syokota warn("retrieving %s summary", uname); 13048663Syokota error = -1; 13148663Syokota } 13248663Syokota 13348663Syokotacloseout: 13448663Syokota if (DB_CLOSE(ddb) < 0) { 13548663Syokota warn("closing %s summary", uname); 13648663Syokota error = -1; 13748663Syokota } 13848663Syokota 13948663Syokota if (error) 140 db_destroy(*mdb, uname); 141 return (error); 142} 143 144/* 145 * Save the in-memory database mdb to the disk database dbname. 146 * Return 0 if OK, -1 on error. 147 */ 148int 149db_copy_out(DB *mdb, const char *dbname, const char *uname, BTREEINFO *bti) 150{ 151 DB *ddb; 152 DBT key, data; 153 int error, rv, version; 154 155 if ((ddb = dbopen(dbname, O_RDWR|O_CREAT|O_TRUNC, 0644, 156 DB_BTREE, bti)) == NULL) { 157 warn("creating %s summary", uname); 158 return (-1); 159 } 160 161 error = 0; 162 163 for (rv = DB_SEQ(mdb, &key, &data, R_FIRST); 164 rv == 0; rv = DB_SEQ(mdb, &key, &data, R_NEXT)) { 165 if ((rv = DB_PUT(ddb, &key, &data, 0)) < 0) { 166 warn("saving %s summary", uname); 167 error = -1; 168 goto out; 169 } 170 } 171 if (rv < 0) { 172 warn("retrieving %s stats", uname); 173 error = -1; 174 } 175 176out: 177 /* Add a version record. */ 178 key.data = (void*)&VERSION_KEY; 179 key.size = sizeof(VERSION_KEY); 180 version = 2; 181 data.data = &version; 182 data.size = sizeof(version); 183 if ((rv = DB_PUT(ddb, &key, &data, 0)) < 0) { 184 warn("add version record to %s stats", uname); 185 error = -1; 186 } else if (rv == 1) { 187 warnx("duplicate version record in %s stats", uname); 188 error = -1; 189 } 190 191 if (DB_SYNC(ddb, 0) < 0) { 192 warn("syncing %s summary", uname); 193 error = -1; 194 } 195 if (DB_CLOSE(ddb) < 0) { 196 warn("closing %s summary", uname); 197 error = -1; 198 } 199 return error; 200} 201 202void 203db_destroy(DB *db, const char *uname) 204{ 205 if (DB_CLOSE(db) < 0) 206 warn("destroying %s stats", uname); 207} 208