1 /* $NetBSD: t_db_hash_seq.c,v 1.4 2020/09/07 00:28:44 mrg 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 #include <sys/cdefs.h> 32 __RCSID("$NetBSD: t_db_hash_seq.c,v 1.4 2020/09/07 00:28:44 mrg Exp $"); 33 34 #include <sys/types.h> 35 #include <sys/socket.h> 36 #include <db.h> 37 #include <stdio.h> 38 #include <string.h> 39 #include <errno.h> 40 #include <stdlib.h> 41 #include <fcntl.h> 42 #include <syslog.h> 43 #include <netinet/in.h> 44 45 #define ATF 46 47 struct conf { 48 struct sockaddr_storage c_ss; 49 int c_lmask; 50 int c_port; 51 int c_proto; 52 int c_family; 53 int c_uid; 54 int c_nfail; 55 char c_name[128]; 56 int c_rmask; 57 int c_duration; 58 }; 59 60 struct dbinfo { 61 int count; 62 time_t last; 63 char id[64]; 64 }; 65 66 #ifdef ATF 67 #include <atf-c.h> 68 69 #define DO_ERR(msg, ...) ATF_REQUIRE_MSG(0, msg, __VA_ARGS__) 70 #define DO_WARNX(msg, ...) ATF_REQUIRE_MSG(0, msg, __VA_ARGS__) 71 #else 72 #include <err.h> 73 74 #define DO_ERR(fmt, ...) err(EXIT_FAILURE, fmt, __VA_ARGS__) 75 #define DO_WARNX(fmt, ...) warnx(fmt, __VA_ARGS__) 76 #endif 77 78 #define DO_DEBUG(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__) 79 80 static HASHINFO openinfo = { 81 4096, /* bsize */ 82 32, /* ffactor */ 83 256, /* nelem */ 84 8 * 1024 * 1024,/* cachesize */ 85 NULL, /* hash() */ 86 0 /* lorder */ 87 }; 88 89 static int debug = 0; 90 91 static int 92 state_close(DB *db) 93 { 94 if (db == NULL) 95 return -1; 96 if ((*db->close)(db) == -1) 97 DO_ERR("%s: can't close db", __func__); 98 return 0; 99 } 100 101 static DB * 102 state_open(const char *dbname, int flags, mode_t perm) 103 { 104 DB *db; 105 106 db = dbopen(dbname, flags, perm, DB_HASH, &openinfo); 107 if (db == NULL) { 108 if (errno == ENOENT && (flags & O_CREAT) == 0) 109 return NULL; 110 DO_ERR("%s: can't open `%s'", __func__, 111 dbname ? dbname : "<memory>"); 112 } 113 return db; 114 } 115 116 static int 117 state_sizecheck(const DBT *t) 118 { 119 if (sizeof(struct conf) == t->size) 120 return 0; 121 DO_WARNX("Key size mismatch %zu != %zu", sizeof(struct conf), t->size); 122 return 0; 123 } 124 125 static int 126 state_del(DB *db, const struct conf *c) 127 { 128 int rv; 129 DBT k; 130 131 if (db == NULL) 132 return -1; 133 134 k.data = __UNCONST(c); 135 k.size = sizeof(*c); 136 137 switch (rv = (*db->del)(db, &k, 1)) { 138 case 0: 139 case 1: 140 if (debug > 1) { 141 DO_DEBUG("%s: returns %d", __func__, rv); 142 (*db->sync)(db, 0); 143 } 144 return 0; 145 default: 146 DO_ERR("%s: failed", __func__); 147 return -1; 148 } 149 } 150 151 #if 0 152 static int 153 state_get(DB *db, const struct conf *c, struct dbinfo *dbi) 154 { 155 int rv; 156 DBT k, v; 157 158 if (db == NULL) 159 return -1; 160 161 k.data = __UNCONST(c); 162 k.size = sizeof(*c); 163 164 switch (rv = (*db->get)(db, &k, &v, 0)) { 165 case 0: 166 case 1: 167 if (rv) 168 memset(dbi, 0, sizeof(*dbi)); 169 else 170 memcpy(dbi, v.data, sizeof(*dbi)); 171 if (debug > 1) 172 DO_DEBUG("%s: returns %d", __func__, rv); 173 return 0; 174 default: 175 DO_ERR("%s: failed", __func__); 176 return -1; 177 } 178 } 179 #endif 180 181 static int 182 state_put(DB *db, const struct conf *c, const struct dbinfo *dbi) 183 { 184 int rv; 185 DBT k, v; 186 187 if (db == NULL) 188 return -1; 189 190 k.data = __UNCONST(c); 191 k.size = sizeof(*c); 192 v.data = __UNCONST(dbi); 193 v.size = sizeof(*dbi); 194 195 switch (rv = (*db->put)(db, &k, &v, 0)) { 196 case 0: 197 if (debug > 1) { 198 DO_DEBUG("%s: returns %d", __func__, rv); 199 (*db->sync)(db, 0); 200 } 201 return 0; 202 case 1: 203 errno = EEXIST; 204 /*FALLTHROUGH*/ 205 default: 206 DO_ERR("%s: failed", __func__); 207 } 208 } 209 210 static int 211 state_iterate(DB *db, struct conf *c, struct dbinfo *dbi, unsigned int first) 212 { 213 int rv; 214 DBT k, v; 215 216 if (db == NULL) 217 return -1; 218 219 first = first ? R_FIRST : R_NEXT; 220 221 switch (rv = (*db->seq)(db, &k, &v, first)) { 222 case 0: 223 if (state_sizecheck(&k) == -1) 224 return -1; 225 memcpy(c, k.data, sizeof(*c)); 226 memcpy(dbi, v.data, sizeof(*dbi)); 227 if (debug > 1) 228 DO_DEBUG("%s: returns %d", __func__, rv); 229 return 1; 230 case 1: 231 if (debug > 1) 232 DO_DEBUG("%s: returns %d", __func__, rv); 233 return 0; 234 default: 235 DO_ERR("%s: failed", __func__); 236 return -1; 237 } 238 } 239 240 #define MAXB 100 241 242 static int 243 testdb(int skip) 244 { 245 size_t i; 246 int f; 247 char flag[MAXB]; 248 DB *db; 249 struct conf c; 250 struct dbinfo d; 251 252 db = state_open(NULL, O_RDWR|O_CREAT|O_TRUNC, 0600); 253 if (db == NULL) 254 DO_ERR("%s: cannot open `%s'", __func__, "foo"); 255 256 memset(&c, 0, sizeof(c)); 257 memset(&d, 0, sizeof(d)); 258 memset(flag, 0, sizeof(flag)); 259 260 for (i = 0; i < __arraycount(flag); i++) { 261 c.c_port = i; 262 state_put(db, &c, &d); 263 } 264 265 for (f = 1, i = 0; state_iterate(db, &c, &d, f) == 1; f = 0, i++) { 266 if (debug > 1) 267 DO_DEBUG("%zu %d\n", i, c.c_port); 268 if (flag[c.c_port]) 269 DO_WARNX("Already visited %d", c.c_port); 270 flag[c.c_port] = 1; 271 if (skip == 0 || c.c_port % skip != 0) 272 continue; 273 state_del(db, &c); 274 } 275 state_close(db); 276 for (i = 0; i < __arraycount(flag); i++) { 277 if (flag[i] == 0) 278 DO_WARNX("Not visited %zu", i); 279 } 280 return 0; 281 } 282 283 #ifndef ATF 284 int 285 main(int argc, char *argv[]) 286 { 287 return testdb(6); 288 } 289 #else 290 291 ATF_TC(test_hash_del_none); 292 ATF_TC_HEAD(test_hash_del_none, tc) 293 { 294 atf_tc_set_md_var(tc, "descr", "Check sequential scan of hash tables deleting none"); 295 } 296 297 ATF_TC_BODY(test_hash_del_none, tc) 298 { 299 testdb(0); 300 } 301 302 ATF_TC(test_hash_del_all); 303 ATF_TC_HEAD(test_hash_del_all, tc) 304 { 305 atf_tc_set_md_var(tc, "descr", "Check sequential scan of hash tables deleting all"); 306 } 307 308 ATF_TC_BODY(test_hash_del_all, tc) 309 { 310 testdb(1); 311 } 312 313 ATF_TC(test_hash_del_alt); 314 ATF_TC_HEAD(test_hash_del_alt, tc) 315 { 316 atf_tc_set_md_var(tc, "descr", "Check sequential scan of hash tables alternating deletets"); 317 } 318 319 ATF_TC_BODY(test_hash_del_alt, tc) 320 { 321 testdb(2); 322 } 323 324 ATF_TC(test_hash_del_every_7); 325 ATF_TC_HEAD(test_hash_del_every_7, tc) 326 { 327 atf_tc_set_md_var(tc, "descr", "Check sequential scan of hash tables deleting every 7 elements"); 328 } 329 330 ATF_TC_BODY(test_hash_del_every_7, tc) 331 { 332 testdb(7); 333 } 334 335 ATF_TP_ADD_TCS(tp) 336 { 337 ATF_TP_ADD_TC(tp, test_hash_del_none); 338 ATF_TP_ADD_TC(tp, test_hash_del_all); 339 ATF_TP_ADD_TC(tp, test_hash_del_alt); 340 ATF_TP_ADD_TC(tp, test_hash_del_every_7); 341 342 return atf_no_error(); 343 } 344 #endif 345