1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1996,2008 Oracle.  All rights reserved.
5 *
6 * $Id: ex_dbclient.c,v 12.7 2008/01/08 20:58:23 bostic Exp $
7 */
8
9#include <sys/types.h>
10
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14#include <unistd.h>
15
16#include <db.h>
17
18#define	DATABASE_HOME	"database"
19
20#define	DATABASE	"access.db"
21
22int	db_clientrun __P((DB_ENV *, const char *));
23int	ex_dbclient __P((const char *));
24int	ex_dbclient_run __P((const char *, FILE *, const char *, const char *));
25int	main __P((int, char *[]));
26
27/*
28 * An example of a program creating/configuring a Berkeley DB environment.
29 */
30int
31main(argc, argv)
32	int argc;
33	char *argv[];
34{
35	const char *home;
36
37	if (argc != 2) {
38		fprintf(stderr, "Usage: %s hostname\n", argv[0]);
39		return (EXIT_FAILURE);
40	}
41
42	/*
43	 * All of the shared database files live in DATABASE_HOME, but
44	 * data files will live in CONFIG_DATA_DIR.
45	 */
46	home = DATABASE_HOME;
47	return (ex_dbclient_run(home,
48	    stderr, argv[1], argv[0]) == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
49}
50
51int
52ex_dbclient(host)
53	const char *host;
54{
55	const char *home;
56	const char *progname = "ex_dbclient";		/* Program name. */
57	int ret;
58
59	/*
60	 * All of the shared database files live in DATABASE_HOME, but
61	 * data files will live in CONFIG_DATA_DIR.
62	 */
63	home = DATABASE_HOME;
64
65	if ((ret = ex_dbclient_run(home, stderr, host, progname)) != 0)
66		return (ret);
67
68	return (0);
69}
70
71int
72ex_dbclient_run(home, errfp, host, progname)
73	const char *home, *host, *progname;
74	FILE *errfp;
75{
76	DB_ENV *dbenv;
77	int ret, retry;
78
79	/*
80	 * Create an environment object and initialize it for error
81	 * reporting.
82	 */
83	if ((ret = db_env_create(&dbenv, DB_RPCCLIENT)) != 0) {
84		fprintf(errfp, "%s: %s\n", progname, db_strerror(ret));
85		return (1);
86	}
87	retry = 0;
88loop:
89	while (retry < 5) {
90		/*
91		 * Set the server host we are talking to.
92		 */
93		if ((ret = dbenv->set_rpc_server(dbenv, NULL, host, 10000,
94		    10000, 0)) != 0) {
95			fprintf(stderr, "Try %d: DB_ENV->set_rpc_server: %s\n",
96			    retry, db_strerror(ret));
97			retry++;
98			sleep(15);
99		} else
100			break;
101	}
102
103	if (retry >= 5) {
104		fprintf(stderr,
105		    "DB_ENV->set_rpc_server: %s\n", db_strerror(ret));
106		dbenv->close(dbenv, 0);
107		return (1);
108	}
109	/*
110	 * We want to specify the shared memory buffer pool cachesize,
111	 * but everything else is the default.
112	 */
113	if ((ret = dbenv->set_cachesize(dbenv, 0, 64 * 1024, 0)) != 0) {
114		dbenv->err(dbenv, ret, "set_cachesize");
115		dbenv->close(dbenv, 0);
116		return (1);
117	}
118	/*
119	 * We have multiple processes reading/writing these files, so
120	 * we need concurrency control and a shared buffer pool, but
121	 * not logging or transactions.
122	 */
123	if ((ret = dbenv->open(dbenv, home,
124	    DB_CREATE | DB_INIT_LOCK | DB_INIT_MPOOL, 0)) != 0) {
125		dbenv->err(dbenv, ret, "environment open: %s", home);
126		dbenv->close(dbenv, 0);
127		if (ret == DB_NOSERVER)
128			goto loop;
129		return (1);
130	}
131
132	ret = db_clientrun(dbenv, progname);
133	printf("db_clientrun returned %d\n", ret);
134	if (ret == DB_NOSERVER)
135		goto loop;
136
137	/* Close the handle. */
138	if ((ret = dbenv->close(dbenv, 0)) != 0) {
139		fprintf(stderr, "DB_ENV->close: %s\n", db_strerror(ret));
140		return (1);
141	}
142	return (0);
143}
144
145int
146db_clientrun(dbenv, progname)
147	DB_ENV *dbenv;
148	const char *progname;
149{
150	DB *dbp;
151	DBT key, data;
152	u_int32_t len;
153	int ret;
154	char *p, *t, buf[1024], rbuf[1024];
155
156	/* Remove the previous database. */
157
158	/* Create and initialize database object, open the database. */
159	if ((ret = db_create(&dbp, dbenv, 0)) != 0) {
160		fprintf(stderr,
161		    "%s: db_create: %s\n", progname, db_strerror(ret));
162		return (ret);
163	}
164	if ((ret = dbp->set_pagesize(dbp, 1024)) != 0) {
165		dbp->err(dbp, ret, "set_pagesize");
166		goto err1;
167	}
168	if ((ret = dbp->open(dbp,
169	    NULL, DATABASE, NULL, DB_BTREE, DB_CREATE, 0664)) != 0) {
170		dbp->err(dbp, ret, "%s: open", DATABASE);
171		goto err1;
172	}
173
174	/*
175	 * Insert records into the database, where the key is the user
176	 * input and the data is the user input in reverse order.
177	 */
178	memset(&key, 0, sizeof(DBT));
179	memset(&data, 0, sizeof(DBT));
180	for (;;) {
181		printf("input> ");
182		fflush(stdout);
183		if (fgets(buf, sizeof(buf), stdin) == NULL)
184			break;
185		if ((len = strlen(buf)) <= 1)
186			continue;
187		for (t = rbuf, p = buf + (len - 2); p >= buf;)
188			*t++ = *p--;
189		*t++ = '\0';
190
191		key.data = buf;
192		data.data = rbuf;
193		data.size = key.size = len - 1;
194
195		switch (ret =
196		    dbp->put(dbp, NULL, &key, &data, DB_NOOVERWRITE)) {
197		case 0:
198			break;
199		default:
200			dbp->err(dbp, ret, "DB->put");
201			if (ret != DB_KEYEXIST)
202				goto err1;
203			break;
204		}
205		memset(&data, 0, sizeof(DBT));
206		switch (ret = dbp->get(dbp, NULL, &key, &data, 0)) {
207		case 0:
208			printf("%.*s : %.*s\n",
209			    (int)key.size, (char *)key.data,
210			    (int)data.size, (char *)data.data);
211			break;
212		default:
213			dbp->err(dbp, ret, "DB->get");
214			break;
215		}
216	}
217	if ((ret = dbp->close(dbp, 0)) != 0) {
218		fprintf(stderr,
219		    "%s: DB->close: %s\n", progname, db_strerror(ret));
220		return (1);
221	}
222	return (0);
223
224err1:	(void)dbp->close(dbp, 0);
225	return (ret);
226}
227