1 /* $NetBSD: state.c,v 1.3 2025/10/25 18:43:51 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 #ifdef HAVE_SYS_CDEFS_H 36 #include <sys/cdefs.h> 37 #endif 38 __RCSID("$NetBSD: state.c,v 1.3 2025/10/25 18:43:51 christos Exp $"); 39 40 #include <sys/types.h> 41 #include <sys/socket.h> 42 #include <stdio.h> 43 #include <string.h> 44 #include <errno.h> 45 #include <fcntl.h> 46 #include <syslog.h> 47 #include <netinet/in.h> 48 49 #include "bl.h" 50 #include "internal.h" 51 #include "conf.h" 52 #include "support.h" 53 #include "state.h" 54 55 static HASHINFO openinfo = { 56 4096, /* bsize */ 57 32, /* ffactor */ 58 256, /* nelem */ 59 8 * 1024 * 1024,/* cachesize */ 60 NULL, /* hash() */ 61 0 /* lorder */ 62 }; 63 64 int 65 state_close(DB *db) 66 { 67 if (db == NULL) 68 return -1; 69 if ((*db->close)(db) == -1) { 70 (*lfun)(LOG_ERR, "%s: can't close db (%m)", __func__); 71 return -1; 72 } 73 return 0; 74 } 75 76 DB * 77 state_open(const char *dbname, int flags, mode_t perm) 78 { 79 DB *db; 80 81 #ifdef __APPLE__ 82 flags &= O_CREAT|O_EXCL|O_EXLOCK|O_NONBLOCK|O_RDONLY| 83 O_RDWR|O_SHLOCK|O_TRUNC; 84 #endif 85 db = dbopen(dbname, flags, perm, DB_HASH, &openinfo); 86 if (db == NULL) { 87 if (errno == ENOENT && (flags & O_CREAT) == 0) 88 return NULL; 89 (*lfun)(LOG_ERR, "%s: can't open `%s' (%m)", __func__, dbname); 90 } 91 return db; 92 } 93 94 static int 95 state_sizecheck(const DBT *t) 96 { 97 if (sizeof(struct conf) == t->size) 98 return 0; 99 (*lfun)(LOG_ERR, "Key size mismatch %zu != %zu", sizeof(struct conf), 100 t->size); 101 return -1; 102 } 103 104 static void 105 dumpkey(const struct conf *k) 106 { 107 char buf[10240]; 108 blhexdump(buf, sizeof(buf), __func__, k, sizeof(*k)); 109 (*lfun)(LOG_DEBUG, "%s", buf); 110 (*lfun)(LOG_DEBUG, "%s: %s", __func__, 111 conf_print(buf, sizeof(buf), "", "", k)); 112 113 } 114 115 int 116 state_del(DB *db, const struct conf *c) 117 { 118 int rv; 119 DBT k; 120 121 if (db == NULL) 122 return -1; 123 124 k.data = __UNCONST(c); 125 k.size = sizeof(*c); 126 127 switch (rv = (*db->del)(db, &k, 0)) { 128 case 0: 129 case 1: 130 if (debug > 1) { 131 (*lfun)(LOG_DEBUG, "%s: returns %d", __func__, rv); 132 (*db->sync)(db, 0); 133 } 134 return rv; 135 default: 136 (*lfun)(LOG_ERR, "%s: failed (%m)", __func__); 137 return -1; 138 } 139 } 140 141 int 142 state_get(DB *db, const struct conf *c, struct dbinfo *dbi) 143 { 144 int rv; 145 DBT k, v; 146 147 if (db == NULL) 148 return -1; 149 150 k.data = __UNCONST(c); 151 k.size = sizeof(*c); 152 153 switch (rv = (*db->get)(db, &k, &v, 0)) { 154 case 0: 155 case 1: 156 if (rv) 157 memset(dbi, 0, sizeof(*dbi)); 158 else 159 memcpy(dbi, v.data, sizeof(*dbi)); 160 if (debug > 1) 161 (*lfun)(LOG_DEBUG, "%s: returns %d", __func__, rv); 162 return 0; 163 default: 164 (*lfun)(LOG_ERR, "%s: failed (%m)", __func__); 165 return -1; 166 } 167 } 168 169 int 170 state_put(DB *db, const struct conf *c, const struct dbinfo *dbi) 171 { 172 int rv; 173 DBT k, v; 174 175 if (db == NULL) 176 return -1; 177 178 k.data = __UNCONST(c); 179 k.size = sizeof(*c); 180 v.data = __UNCONST(dbi); 181 v.size = sizeof(*dbi); 182 183 switch (rv = (*db->put)(db, &k, &v, 0)) { 184 case 0: 185 if (debug > 1) { 186 (*lfun)(LOG_DEBUG, "%s: returns %d", __func__, rv); 187 (*db->sync)(db, 0); 188 } 189 return 0; 190 case 1: 191 errno = EEXIST; 192 /*FALLTHROUGH*/ 193 default: 194 (*lfun)(LOG_ERR, "%s: failed (%m)", __func__); 195 return -1; 196 } 197 } 198 199 int 200 state_iterate(DB *db, struct conf *c, struct dbinfo *dbi, unsigned int first) 201 { 202 int rv; 203 DBT k, v; 204 205 if (db == NULL) { 206 (*lfun)(LOG_ERR, "%s: called with no database file", __func__); 207 return -1; 208 } 209 210 first = first ? R_FIRST : R_NEXT; 211 212 switch (rv = (*db->seq)(db, &k, &v, first)) { 213 case 0: 214 if (state_sizecheck(&k) == -1) 215 return -1; 216 memcpy(c, k.data, sizeof(*c)); 217 if (debug > 2) 218 dumpkey(c); 219 memcpy(dbi, v.data, sizeof(*dbi)); 220 if (debug > 1) 221 (*lfun)(LOG_DEBUG, "%s: returns %d", __func__, rv); 222 return 1; 223 case 1: 224 if (debug > 1) 225 (*lfun)(LOG_DEBUG, "%s: returns %d", __func__, rv); 226 return 0; 227 default: 228 (*lfun)(LOG_ERR, "%s: failed (%m)", __func__); 229 return -1; 230 } 231 } 232 233 int 234 state_sync(DB *db) 235 { 236 return (*db->sync)(db, 0); 237 } 238