1169857Sdds/*- 2169857Sdds * Copyright (c) 2007 Diomidis Spinellis 3169857Sdds * All rights reserved. 4169857Sdds * 5169857Sdds * Redistribution and use in source and binary forms, with or without 6169857Sdds * modification, are permitted provided that the following conditions 7169857Sdds * are met: 8169857Sdds * 1. Redistributions of source code must retain the above copyright 9169857Sdds * notice, this list of conditions and the following disclaimer. 10169857Sdds * 2. Redistributions in binary form must reproduce the above copyright 11169857Sdds * notice, this list of conditions and the following disclaimer in the 12169857Sdds * documentation and/or other materials provided with the distribution. 13169857Sdds * 14169857Sdds * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15169857Sdds * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16169857Sdds * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17169857Sdds * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18169857Sdds * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19169857Sdds * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20169857Sdds * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21169857Sdds * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22169857Sdds * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23169857Sdds * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24169857Sdds * SUCH DAMAGE. 25169857Sdds * 26169857Sdds */ 27169857Sdds 28169857Sdds#include <sys/cdefs.h> 29169857Sdds__FBSDID("$FreeBSD: releng/10.3/usr.sbin/sa/db.c 228681 2011-12-18 01:08:25Z dim $"); 30169857Sdds 31169857Sdds#include <sys/types.h> 32169857Sdds#include <sys/acct.h> 33169857Sdds 34169857Sdds#include <ctype.h> 35169857Sdds#include <err.h> 36169857Sdds#include <errno.h> 37169857Sdds#include <db.h> 38169857Sdds#include <fcntl.h> 39169857Sdds#include <stdio.h> 40169857Sdds#include <stdlib.h> 41169857Sdds#include <string.h> 42169857Sdds#include <limits.h> 43169857Sdds 44169857Sdds#include "extern.h" 45169857Sdds 46169857Sdds/* Key used to store the version of the database data elements. */ 47169857Sdds#define VERSION_KEY "\0VERSION" 48169857Sdds 49169857Sdds/* 50169857Sdds * Create the in-memory database, *mdb. 51169857Sdds * If iflag is not set, fill-in mdb with the records of the disk-based 52169857Sdds * database dbname. 53169857Sdds * Upgrade old-version records by calling v1_to_v2. 54169857Sdds * Return 0 if OK, -1 on error. 55169857Sdds */ 56169857Sddsint 57169857Sddsdb_copy_in(DB **mdb, const char *dbname, const char *uname, BTREEINFO *bti, 58169857Sdds int (*v1_to_v2)(DBT *key, DBT *data)) 59169857Sdds{ 60169857Sdds DBT key, data; 61169857Sdds DB *ddb; 62169857Sdds int error, rv, version; 63169857Sdds 64169857Sdds if ((*mdb = dbopen(NULL, O_RDWR, 0, DB_BTREE, bti)) == NULL) 65169857Sdds return (-1); 66169857Sdds 67169857Sdds if (iflag) 68169857Sdds return (0); 69169857Sdds 70176433Sgrog if ((ddb = dbopen(dbname, O_RDONLY, 0, DB_BTREE, bti)) == NULL) { 71169857Sdds if (errno == ENOENT) 72169857Sdds return (0); 73169857Sdds warn("retrieving %s summary", uname); 74169857Sdds db_destroy(*mdb, uname); 75169857Sdds return (-1); 76169857Sdds } 77169857Sdds 78169857Sdds error = 0; 79169857Sdds 80169857Sdds /* Obtain/set version. */ 81169857Sdds version = 1; 82228681Sdim key.data = (void*)&VERSION_KEY; 83169857Sdds key.size = sizeof(VERSION_KEY); 84169857Sdds 85169857Sdds rv = DB_GET(ddb, &key, &data, 0); 86169857Sdds if (rv < 0) { 87169857Sdds warn("get version key from %s stats", uname); 88169857Sdds error = -1; 89169857Sdds goto closeout; 90169857Sdds } else if (rv == 0) { /* It's there; verify version. */ 91169857Sdds if (data.size != sizeof(version)) { 92173711Sjb warnx("invalid version size %zd in %s", 93169857Sdds data.size, uname); 94169857Sdds error = -1; 95169857Sdds goto closeout; 96169857Sdds } 97169857Sdds memcpy(&version, data.data, data.size); 98169857Sdds if (version != 2) { 99169857Sdds warnx("unsupported version %d in %s", 100169857Sdds version, uname); 101169857Sdds error = -1; 102169857Sdds goto closeout; 103169857Sdds } 104169857Sdds } 105169857Sdds 106169857Sdds for (rv = DB_SEQ(ddb, &key, &data, R_FIRST); rv == 0; 107169857Sdds rv = DB_SEQ(ddb, &key, &data, R_NEXT)) { 108169857Sdds 109169857Sdds /* See if this is a version record. */ 110169857Sdds if (key.size == sizeof(VERSION_KEY) && 111169857Sdds memcmp(key.data, VERSION_KEY, sizeof(VERSION_KEY)) == 0) 112169857Sdds continue; 113169857Sdds 114169857Sdds /* Convert record from v1, if needed. */ 115169857Sdds if (version == 1 && v1_to_v2(&key, &data) < 0) { 116169857Sdds warn("converting %s stats", uname); 117169857Sdds error = -1; 118169857Sdds goto closeout; 119169857Sdds } 120169857Sdds 121169857Sdds /* Copy record to the in-memory database. */ 122169857Sdds if ((rv = DB_PUT(*mdb, &key, &data, 0)) < 0) { 123169857Sdds warn("initializing %s stats", uname); 124169857Sdds error = -1; 125169857Sdds goto closeout; 126169857Sdds } 127169857Sdds } 128169857Sdds if (rv < 0) { 129169857Sdds warn("retrieving %s summary", uname); 130169857Sdds error = -1; 131169857Sdds } 132169857Sdds 133169857Sddscloseout: 134169857Sdds if (DB_CLOSE(ddb) < 0) { 135169857Sdds warn("closing %s summary", uname); 136169857Sdds error = -1; 137169857Sdds } 138169857Sdds 139169857Sdds if (error) 140169857Sdds db_destroy(*mdb, uname); 141169857Sdds return (error); 142169857Sdds} 143169857Sdds 144169857Sdds/* 145169857Sdds * Save the in-memory database mdb to the disk database dbname. 146169857Sdds * Return 0 if OK, -1 on error. 147169857Sdds */ 148169857Sddsint 149169857Sddsdb_copy_out(DB *mdb, const char *dbname, const char *uname, BTREEINFO *bti) 150169857Sdds{ 151169857Sdds DB *ddb; 152169857Sdds DBT key, data; 153169857Sdds int error, rv, version; 154169857Sdds 155169857Sdds if ((ddb = dbopen(dbname, O_RDWR|O_CREAT|O_TRUNC, 0644, 156169857Sdds DB_BTREE, bti)) == NULL) { 157169857Sdds warn("creating %s summary", uname); 158169857Sdds return (-1); 159169857Sdds } 160169857Sdds 161169857Sdds error = 0; 162169857Sdds 163169857Sdds for (rv = DB_SEQ(mdb, &key, &data, R_FIRST); 164169857Sdds rv == 0; rv = DB_SEQ(mdb, &key, &data, R_NEXT)) { 165169857Sdds if ((rv = DB_PUT(ddb, &key, &data, 0)) < 0) { 166169857Sdds warn("saving %s summary", uname); 167169857Sdds error = -1; 168169857Sdds goto out; 169169857Sdds } 170169857Sdds } 171169857Sdds if (rv < 0) { 172169857Sdds warn("retrieving %s stats", uname); 173169857Sdds error = -1; 174169857Sdds } 175169857Sdds 176169857Sddsout: 177169857Sdds /* Add a version record. */ 178228681Sdim key.data = (void*)&VERSION_KEY; 179169857Sdds key.size = sizeof(VERSION_KEY); 180169857Sdds version = 2; 181169857Sdds data.data = &version; 182169857Sdds data.size = sizeof(version); 183169857Sdds if ((rv = DB_PUT(ddb, &key, &data, 0)) < 0) { 184169857Sdds warn("add version record to %s stats", uname); 185169857Sdds error = -1; 186169857Sdds } else if (rv == 1) { 187169857Sdds warnx("duplicate version record in %s stats", uname); 188169857Sdds error = -1; 189169857Sdds } 190169857Sdds 191169857Sdds if (DB_SYNC(ddb, 0) < 0) { 192169857Sdds warn("syncing %s summary", uname); 193169857Sdds error = -1; 194169857Sdds } 195169857Sdds if (DB_CLOSE(ddb) < 0) { 196169857Sdds warn("closing %s summary", uname); 197169857Sdds error = -1; 198169857Sdds } 199169857Sdds return error; 200169857Sdds} 201169857Sdds 202169857Sddsvoid 203169857Sddsdb_destroy(DB *db, const char *uname) 204169857Sdds{ 205169857Sdds if (DB_CLOSE(db) < 0) 206169857Sdds warn("destroying %s stats", uname); 207169857Sdds} 208