1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2007 Diomidis Spinellis 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 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 AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 */ 29 30 #include <sys/types.h> 31 #include <sys/acct.h> 32 33 #include <ctype.h> 34 #include <err.h> 35 #include <errno.h> 36 #include <db.h> 37 #include <fcntl.h> 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <string.h> 41 #include <limits.h> 42 43 #include "extern.h" 44 45 /* Key used to store the version of the database data elements. */ 46 static char VERSION_KEY[] = "\0VERSION"; 47 48 /* 49 * Create the in-memory database, *mdb. 50 * If iflag is not set, fill-in mdb with the records of the disk-based 51 * database dbname. 52 * Upgrade old-version records by calling v1_to_v2. 53 * Return 0 if OK, -1 on error. 54 */ 55 int 56 db_copy_in(DB **mdb, const char *dbname, const char *uname, BTREEINFO *bti, 57 int (*v1_to_v2)(DBT *key, DBT *data)) 58 { 59 DBT key, data; 60 DB *ddb; 61 int error, rv, version; 62 63 if ((*mdb = dbopen(NULL, O_RDWR, 0, DB_BTREE, bti)) == NULL) 64 return (-1); 65 66 if (iflag) 67 return (0); 68 69 if ((ddb = dbopen(dbname, O_RDONLY, 0, DB_BTREE, bti)) == NULL) { 70 if (errno == ENOENT) 71 return (0); 72 warn("retrieving %s summary", uname); 73 db_destroy(*mdb, uname); 74 return (-1); 75 } 76 77 error = 0; 78 79 /* Obtain/set version. */ 80 version = 1; 81 key.data = (void*)&VERSION_KEY; 82 key.size = sizeof(VERSION_KEY); 83 84 rv = DB_GET(ddb, &key, &data, 0); 85 if (rv < 0) { 86 warn("get version key from %s stats", uname); 87 error = -1; 88 goto closeout; 89 } else if (rv == 0) { /* It's there; verify version. */ 90 if (data.size != sizeof(version)) { 91 warnx("invalid version size %zd in %s", 92 data.size, uname); 93 error = -1; 94 goto closeout; 95 } 96 memcpy(&version, data.data, data.size); 97 if (version != 2) { 98 warnx("unsupported version %d in %s", 99 version, uname); 100 error = -1; 101 goto closeout; 102 } 103 } 104 105 for (rv = DB_SEQ(ddb, &key, &data, R_FIRST); rv == 0; 106 rv = DB_SEQ(ddb, &key, &data, R_NEXT)) { 107 108 /* See if this is a version record. */ 109 if (key.size == sizeof(VERSION_KEY) && 110 memcmp(key.data, VERSION_KEY, sizeof(VERSION_KEY)) == 0) 111 continue; 112 113 /* Convert record from v1, if needed. */ 114 if (version == 1 && v1_to_v2(&key, &data) < 0) { 115 warn("converting %s stats", uname); 116 error = -1; 117 goto closeout; 118 } 119 120 /* Copy record to the in-memory database. */ 121 if ((rv = DB_PUT(*mdb, &key, &data, 0)) < 0) { 122 warn("initializing %s stats", uname); 123 error = -1; 124 goto closeout; 125 } 126 } 127 if (rv < 0) { 128 warn("retrieving %s summary", uname); 129 error = -1; 130 } 131 132 closeout: 133 if (DB_CLOSE(ddb) < 0) { 134 warn("closing %s summary", uname); 135 error = -1; 136 } 137 138 if (error) 139 db_destroy(*mdb, uname); 140 return (error); 141 } 142 143 /* 144 * Save the in-memory database mdb to the disk database dbname. 145 * Return 0 if OK, -1 on error. 146 */ 147 int 148 db_copy_out(DB *mdb, const char *dbname, const char *uname, BTREEINFO *bti) 149 { 150 DB *ddb; 151 DBT key, data; 152 int error, rv, version; 153 154 if ((ddb = dbopen(dbname, O_RDWR|O_CREAT|O_TRUNC, 0644, 155 DB_BTREE, bti)) == NULL) { 156 warn("creating %s summary", uname); 157 return (-1); 158 } 159 160 error = 0; 161 162 for (rv = DB_SEQ(mdb, &key, &data, R_FIRST); 163 rv == 0; rv = DB_SEQ(mdb, &key, &data, R_NEXT)) { 164 if ((rv = DB_PUT(ddb, &key, &data, 0)) < 0) { 165 warn("saving %s summary", uname); 166 error = -1; 167 goto out; 168 } 169 } 170 if (rv < 0) { 171 warn("retrieving %s stats", uname); 172 error = -1; 173 } 174 175 out: 176 /* Add a version record. */ 177 key.data = (void*)&VERSION_KEY; 178 key.size = sizeof(VERSION_KEY); 179 version = 2; 180 data.data = &version; 181 data.size = sizeof(version); 182 if ((rv = DB_PUT(ddb, &key, &data, 0)) < 0) { 183 warn("add version record to %s stats", uname); 184 error = -1; 185 } else if (rv == 1) { 186 warnx("duplicate version record in %s stats", uname); 187 error = -1; 188 } 189 190 if (DB_SYNC(ddb, 0) < 0) { 191 warn("syncing %s summary", uname); 192 error = -1; 193 } 194 if (DB_CLOSE(ddb) < 0) { 195 warn("closing %s summary", uname); 196 error = -1; 197 } 198 return error; 199 } 200 201 void 202 db_destroy(DB *db, const char *uname) 203 { 204 if (DB_CLOSE(db) < 0) 205 warn("destroying %s stats", uname); 206 } 207