1/* $NetBSD: state.c,v 1.19 2016/09/26 19:43:43 christos Exp $ */ 2 3/*- 4 * Copyright (c) 2015 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Christos Zoulas. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31#ifdef HAVE_CONFIG_H 32#include "config.h" 33#endif 34 35#include <sys/cdefs.h> 36__RCSID("$NetBSD: state.c,v 1.19 2016/09/26 19:43:43 christos Exp $"); 37 38#include <sys/types.h> 39#include <sys/socket.h> 40#include <stdio.h> 41#include <string.h> 42#include <errno.h> 43#include <fcntl.h> 44#include <syslog.h> 45#include <netinet/in.h> 46 47#include "bl.h" 48#include "internal.h" 49#include "conf.h" 50#include "support.h" 51#include "state.h" 52 53static HASHINFO openinfo = { 54 4096, /* bsize */ 55 32, /* ffactor */ 56 256, /* nelem */ 57 8 * 1024 * 1024,/* cachesize */ 58 NULL, /* hash() */ 59 0 /* lorder */ 60}; 61 62int 63state_close(DB *db) 64{ 65 if (db == NULL) 66 return -1; 67 if ((*db->close)(db) == -1) { 68 (*lfun)(LOG_ERR, "%s: can't close db (%m)", __func__); 69 return -1; 70 } 71 return 0; 72} 73 74DB * 75state_open(const char *dbname, int flags, mode_t perm) 76{ 77 DB *db; 78 79#ifdef __APPLE__ 80 flags &= O_CREAT|O_EXCL|O_EXLOCK|O_NONBLOCK|O_RDONLY| 81 O_RDWR|O_SHLOCK|O_TRUNC; 82#endif 83 db = dbopen(dbname, flags, perm, DB_HASH, &openinfo); 84 if (db == NULL) { 85 if (errno == ENOENT && (flags & O_CREAT) == 0) 86 return NULL; 87 (*lfun)(LOG_ERR, "%s: can't open `%s' (%m)", __func__, dbname); 88 } 89 return db; 90} 91 92static int 93state_sizecheck(const DBT *t) 94{ 95 if (sizeof(struct conf) == t->size) 96 return 0; 97 (*lfun)(LOG_ERR, "Key size mismatch %zu != %zu", sizeof(struct conf), 98 t->size); 99 return -1; 100} 101 102static void 103dumpkey(const struct conf *k) 104{ 105 char buf[10240]; 106 blhexdump(buf, sizeof(buf), __func__, k, sizeof(*k)); 107 (*lfun)(LOG_DEBUG, "%s", buf); 108 (*lfun)(LOG_DEBUG, "%s: %s", __func__, 109 conf_print(buf, sizeof(buf), "", "", k)); 110 111} 112 113int 114state_del(DB *db, const struct conf *c) 115{ 116 int rv; 117 DBT k; 118 119 if (db == NULL) 120 return -1; 121 122 k.data = __UNCONST(c); 123 k.size = sizeof(*c); 124 125 switch (rv = (*db->del)(db, &k, 0)) { 126 case 0: 127 case 1: 128 if (debug > 1) { 129 (*lfun)(LOG_DEBUG, "%s: returns %d", __func__, rv); 130 (*db->sync)(db, 0); 131 } 132 return 0; 133 default: 134 (*lfun)(LOG_ERR, "%s: failed (%m)", __func__); 135 return -1; 136 } 137} 138 139int 140state_get(DB *db, const struct conf *c, struct dbinfo *dbi) 141{ 142 int rv; 143 DBT k, v; 144 145 if (db == NULL) 146 return -1; 147 148 k.data = __UNCONST(c); 149 k.size = sizeof(*c); 150 151 switch (rv = (*db->get)(db, &k, &v, 0)) { 152 case 0: 153 case 1: 154 if (rv) 155 memset(dbi, 0, sizeof(*dbi)); 156 else 157 memcpy(dbi, v.data, sizeof(*dbi)); 158 if (debug > 1) 159 (*lfun)(LOG_DEBUG, "%s: returns %d", __func__, rv); 160 return 0; 161 default: 162 (*lfun)(LOG_ERR, "%s: failed (%m)", __func__); 163 return -1; 164 } 165} 166 167int 168state_put(DB *db, const struct conf *c, const struct dbinfo *dbi) 169{ 170 int rv; 171 DBT k, v; 172 173 if (db == NULL) 174 return -1; 175 176 k.data = __UNCONST(c); 177 k.size = sizeof(*c); 178 v.data = __UNCONST(dbi); 179 v.size = sizeof(*dbi); 180 181 switch (rv = (*db->put)(db, &k, &v, 0)) { 182 case 0: 183 if (debug > 1) { 184 (*lfun)(LOG_DEBUG, "%s: returns %d", __func__, rv); 185 (*db->sync)(db, 0); 186 } 187 return 0; 188 case 1: 189 errno = EEXIST; 190 /*FALLTHROUGH*/ 191 default: 192 (*lfun)(LOG_ERR, "%s: failed (%m)", __func__); 193 return -1; 194 } 195} 196 197int 198state_iterate(DB *db, struct conf *c, struct dbinfo *dbi, unsigned int first) 199{ 200 int rv; 201 DBT k, v; 202 203 if (db == NULL) { 204 (*lfun)(LOG_ERR, "%s: called with no database file", __func__); 205 return -1; 206 } 207 208 first = first ? R_FIRST : R_NEXT; 209 210 switch (rv = (*db->seq)(db, &k, &v, first)) { 211 case 0: 212 if (state_sizecheck(&k) == -1) 213 return -1; 214 memcpy(c, k.data, sizeof(*c)); 215 if (debug > 2) 216 dumpkey(c); 217 memcpy(dbi, v.data, sizeof(*dbi)); 218 if (debug > 1) 219 (*lfun)(LOG_DEBUG, "%s: returns %d", __func__, rv); 220 return 1; 221 case 1: 222 if (debug > 1) 223 (*lfun)(LOG_DEBUG, "%s: returns %d", __func__, rv); 224 return 0; 225 default: 226 (*lfun)(LOG_ERR, "%s: failed (%m)", __func__); 227 return -1; 228 } 229} 230 231int 232state_sync(DB *db) 233{ 234 return (*db->sync)(db, 0); 235} 236