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 53 static HASHINFO openinfo = { 54 4096, /* bsize */ 55 32, /* ffactor */ 56 256, /* nelem */ 57 8 * 1024 * 1024,/* cachesize */ 58 NULL, /* hash() */ 59 0 /* lorder */ 60 }; 61 62 int 63 state_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 74 DB * 75 state_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 92 static int 93 state_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 102 static void 103 dumpkey(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 113 int 114 state_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 139 int 140 state_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 167 int 168 state_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 197 int 198 state_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 231 int 232 state_sync(DB *db) 233 { 234 return (*db->sync)(db, 0); 235 } 236