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