1 /* $NetBSD: t_db_hash_seq.c,v 1.2 2015/06/22 22:35: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 #include <sys/cdefs.h> 32 __RCSID("$NetBSD: t_db_hash_seq.c,v 1.2 2015/06/22 22:35:51 christos 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__, dbname); 111 } 112 return db; 113 } 114 115 static int 116 state_sizecheck(const DBT *t) 117 { 118 if (sizeof(struct conf) == t->size) 119 return 0; 120 DO_WARNX("Key size mismatch %zu != %zu", sizeof(struct conf), t->size); 121 return 0; 122 } 123 124 static int 125 state_del(DB *db, const struct conf *c) 126 { 127 int rv; 128 DBT k; 129 130 if (db == NULL) 131 return -1; 132 133 k.data = __UNCONST(c); 134 k.size = sizeof(*c); 135 136 switch (rv = (*db->del)(db, &k, 1)) { 137 case 0: 138 case 1: 139 if (debug > 1) { 140 DO_DEBUG("%s: returns %d", __func__, rv); 141 (*db->sync)(db, 0); 142 } 143 return 0; 144 default: 145 DO_ERR("%s: failed", __func__); 146 return -1; 147 } 148 } 149 150 #if 0 151 static int 152 state_get(DB *db, const struct conf *c, struct dbinfo *dbi) 153 { 154 int rv; 155 DBT k, v; 156 157 if (db == NULL) 158 return -1; 159 160 k.data = __UNCONST(c); 161 k.size = sizeof(*c); 162 163 switch (rv = (*db->get)(db, &k, &v, 0)) { 164 case 0: 165 case 1: 166 if (rv) 167 memset(dbi, 0, sizeof(*dbi)); 168 else 169 memcpy(dbi, v.data, sizeof(*dbi)); 170 if (debug > 1) 171 DO_DEBUG("%s: returns %d", __func__, rv); 172 return 0; 173 default: 174 DO_ERR("%s: failed", __func__); 175 return -1; 176 } 177 } 178 #endif 179 180 static int 181 state_put(DB *db, const struct conf *c, const struct dbinfo *dbi) 182 { 183 int rv; 184 DBT k, v; 185 186 if (db == NULL) 187 return -1; 188 189 k.data = __UNCONST(c); 190 k.size = sizeof(*c); 191 v.data = __UNCONST(dbi); 192 v.size = sizeof(*dbi); 193 194 switch (rv = (*db->put)(db, &k, &v, 0)) { 195 case 0: 196 if (debug > 1) { 197 DO_DEBUG("%s: returns %d", __func__, rv); 198 (*db->sync)(db, 0); 199 } 200 return 0; 201 case 1: 202 errno = EEXIST; 203 /*FALLTHROUGH*/ 204 default: 205 DO_ERR("%s: failed", __func__); 206 } 207 } 208 209 static int 210 state_iterate(DB *db, struct conf *c, struct dbinfo *dbi, unsigned int first) 211 { 212 int rv; 213 DBT k, v; 214 215 if (db == NULL) 216 return -1; 217 218 first = first ? R_FIRST : R_NEXT; 219 220 switch (rv = (*db->seq)(db, &k, &v, first)) { 221 case 0: 222 if (state_sizecheck(&k) == -1) 223 return -1; 224 memcpy(c, k.data, sizeof(*c)); 225 memcpy(dbi, v.data, sizeof(*dbi)); 226 if (debug > 1) 227 DO_DEBUG("%s: returns %d", __func__, rv); 228 return 1; 229 case 1: 230 if (debug > 1) 231 DO_DEBUG("%s: returns %d", __func__, rv); 232 return 0; 233 default: 234 DO_ERR("%s: failed", __func__); 235 return -1; 236 } 237 } 238 239 #define MAXB 100 240 241 static int 242 testdb(int skip) 243 { 244 size_t i; 245 int f; 246 char flag[MAXB]; 247 DB *db; 248 struct conf c; 249 struct dbinfo d; 250 251 db = state_open(NULL, O_RDWR|O_CREAT|O_TRUNC, 0600); 252 if (db == NULL) 253 DO_ERR("%s: cannot open `%s'", __func__, "foo"); 254 255 memset(&c, 0, sizeof(c)); 256 memset(&d, 0, sizeof(d)); 257 memset(flag, 0, sizeof(flag)); 258 259 for (i = 0; i < __arraycount(flag); i++) { 260 c.c_port = i; 261 state_put(db, &c, &d); 262 } 263 264 for (f = 1, i = 0; state_iterate(db, &c, &d, f) == 1; f = 0, i++) { 265 if (debug > 1) 266 DO_DEBUG("%zu %d\n", i, c.c_port); 267 if (flag[c.c_port]) 268 DO_WARNX("Already visited %d", c.c_port); 269 flag[c.c_port] = 1; 270 if (skip == 0 || c.c_port % skip != 0) 271 continue; 272 state_del(db, &c); 273 } 274 state_close(db); 275 for (i = 0; i < __arraycount(flag); i++) { 276 if (flag[i] == 0) 277 DO_WARNX("Not visited %zu", i); 278 } 279 return 0; 280 } 281 282 #ifndef ATF 283 int 284 main(int argc, char *argv[]) 285 { 286 return testdb(6); 287 } 288 #else 289 290 ATF_TC(test_hash_del_none); 291 ATF_TC_HEAD(test_hash_del_none, tc) 292 { 293 atf_tc_set_md_var(tc, "descr", "Check sequential scan of hash tables deleting none"); 294 } 295 296 ATF_TC_BODY(test_hash_del_none, tc) 297 { 298 testdb(0); 299 } 300 301 ATF_TC(test_hash_del_all); 302 ATF_TC_HEAD(test_hash_del_all, tc) 303 { 304 atf_tc_set_md_var(tc, "descr", "Check sequential scan of hash tables deleting all"); 305 } 306 307 ATF_TC_BODY(test_hash_del_all, tc) 308 { 309 testdb(1); 310 } 311 312 ATF_TC(test_hash_del_alt); 313 ATF_TC_HEAD(test_hash_del_alt, tc) 314 { 315 atf_tc_set_md_var(tc, "descr", "Check sequential scan of hash tables alternating deletets"); 316 } 317 318 ATF_TC_BODY(test_hash_del_alt, tc) 319 { 320 testdb(2); 321 } 322 323 ATF_TC(test_hash_del_every_7); 324 ATF_TC_HEAD(test_hash_del_every_7, tc) 325 { 326 atf_tc_set_md_var(tc, "descr", "Check sequential scan of hash tables deleting every 7 elements"); 327 } 328 329 ATF_TC_BODY(test_hash_del_every_7, tc) 330 { 331 testdb(7); 332 } 333 334 ATF_TP_ADD_TCS(tp) 335 { 336 ATF_TP_ADD_TC(tp, test_hash_del_none); 337 ATF_TP_ADD_TC(tp, test_hash_del_all); 338 ATF_TP_ADD_TC(tp, test_hash_del_alt); 339 ATF_TP_ADD_TC(tp, test_hash_del_every_7); 340 341 return 0; 342 } 343 #endif 344