1 /* Copyright 2000-2005 The Apache Software Foundation or its licensors, as
2 * applicable.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 /* This file came from the SDBM package (written by oz@nexus.yorku.ca).
17 * That package was under public domain. This file has been ported to
18 * APR, updated to ANSI C and other, newer idioms, and added to the Apache
19 * codebase under the above copyright and license.
20 */
21
22 /*
23 * testdbm: Simple APR dbm tester.
24 * Automatic test case: ./testdbm auto foo
25 * - Attempts to store and fetch values from the DBM.
26 *
27 * Run the program for more help.
28 */
29
30 #include "apr.h"
31 #include "apr_general.h"
32 #include "apr_pools.h"
33 #include "apr_errno.h"
34 #include "apr_getopt.h"
35 #include "apr_time.h"
36 #define APR_WANT_STRFUNC
37 #include "apr_want.h"
38
39 #if APR_HAVE_STDIO_H
40 #include <stdio.h>
41 #endif
42 #if APR_HAVE_UNISTD_H
43 #include <unistd.h>
44 #endif
45 #include <stdlib.h> /* for atexit(), malloc() */
46 #include <string.h>
47
48 #include "apr_dbm.h"
49
50 static const char *progname;
51 static int rflag;
52
53 #define DERROR 0
54 #define DLOOK 1
55
56 #define DDELETE 3
57 #define DCAT 4
58 #define DBUILD 5
59 #define DPRESS 6
60 #define DCREAT 7
61 #define DNAME 8
62 #define DTRUNC 9
63 #define DAUTO 10
64
65 #define LINEMAX 8192
66
67 typedef struct {
68 const char *sname;
69 int scode;
70 int flags;
71 } cmd;
72
73 static const cmd cmds[] = {
74
75 { "fetch", DLOOK, APR_DBM_READONLY },
76 { "get", DLOOK, APR_DBM_READONLY },
77 { "look", DLOOK, APR_DBM_READONLY },
78 { "add", DBUILD, APR_DBM_READWRITE },
79 { "insert", DBUILD, APR_DBM_READWRITE },
80 { "store", DBUILD, APR_DBM_READWRITE },
81 { "delete", DDELETE, APR_DBM_READWRITE },
82 { "remove", DDELETE, APR_DBM_READWRITE },
83 { "dump", DCAT, APR_DBM_READONLY },
84 { "list", DCAT, APR_DBM_READONLY },
85 { "cat", DCAT, APR_DBM_READONLY },
86 { "build", DBUILD, APR_DBM_RWCREATE }, /** this one creates the DB */
87 { "creat", DCREAT, APR_DBM_RWCREATE },
88 { "trunc", DTRUNC, APR_DBM_RWTRUNC },
89 { "new", DCREAT, APR_DBM_RWCREATE },
90 { "names", DNAME, APR_DBM_READONLY },
91 #if 0
92 {"squash", DPRESS, APR_DBM_READWRITE, },
93 {"compact", DPRESS, APR_DBM_READWRITE, },
94 {"compress", DPRESS, APR_DBM_READWRITE, },
95 #endif
96 { "auto", DAUTO, APR_DBM_RWCREATE },
97 };
98
99 #define CMD_SIZE (sizeof(cmds)/sizeof(cmd))
100
101 static void doit(const cmd *act, const char*type, const char *file, apr_pool_t *pool);
102 static const cmd *parse_command(const char *str);
103 static void prdatum(FILE *stream, apr_datum_t d);
104 static void oops(apr_dbm_t *dbm, apr_status_t rv, const char *s1,
105 const char *s2);
106 static void show_usage(void);
107
main(int argc,const char * const * argv)108 int main(int argc, const char * const * argv)
109 {
110 apr_pool_t *pool;
111 const cmd *act;
112 apr_getopt_t *os;
113 char optch;
114 const char *optarg;
115 const char*dbtype;
116
117 (void) apr_initialize();
118 apr_pool_create(&pool, NULL);
119 atexit(apr_terminate);
120
121 (void) apr_getopt_init(&os, pool, argc, argv);
122
123 progname = argv[0];
124 dbtype = "default";
125
126 while (apr_getopt(os, "Rt:", &optch, &optarg) == APR_SUCCESS) {
127 switch (optch) {
128 case 'R': /* raw processing */
129 rflag++;
130 break;
131 case 't':
132 dbtype = optarg;
133 break;
134 default:
135 show_usage();
136 fputs("unknown option.",stderr);
137 exit(-1);
138 break;
139 }
140 }
141
142 if (argc <= os->ind) {
143 show_usage();
144 fputs("Note: If you have no clue what this program is, start with:\n", stderr);
145 fputs(" ./testdbm auto foo\n", stderr);
146 fputs(" where foo is the DBM prefix.\n", stderr);
147 exit(-2);
148 }
149
150 if ((act = parse_command(argv[os->ind])) == NULL) {
151 show_usage();
152 fprintf(stderr, "unrecognized command: %s\n", argv[os->ind]);
153 exit(-3);
154 }
155
156 if (++os->ind >= argc) {
157 show_usage();
158 fputs("please supply a DB file to use (may be created)\n", stderr);
159 exit(-4);
160 }
161
162 doit(act, dbtype, argv[os->ind], pool);
163
164 apr_pool_destroy(pool);
165
166 return 0;
167 }
168
doit(const cmd * act,const char * type,const char * file,apr_pool_t * pool)169 static void doit(const cmd *act, const char*type, const char *file,
170 apr_pool_t *pool)
171 {
172 apr_status_t rv;
173 apr_datum_t key;
174 apr_datum_t val;
175 apr_dbm_t *db;
176 char *op;
177 int n;
178 char *line;
179 const char *use1;
180 const char *use2;
181 #ifdef TIME
182 long start;
183 extern long time();
184 #endif
185
186 rv = apr_dbm_open_ex(&db, type, file, act->flags, APR_OS_DEFAULT, pool);
187 if (rv != APR_SUCCESS)
188 oops(db, rv, "cannot open: %s", file);
189
190 line = (char *) apr_palloc(pool,LINEMAX);
191
192 switch (act->scode) {
193
194 case DLOOK:
195 while (fgets(line, LINEMAX, stdin) != NULL) {
196 n = strlen(line) - 1;
197 line[n] = 0;
198 if (n == 0)
199 break;
200
201 key.dptr = line;
202 key.dsize = n;
203 rv = apr_dbm_fetch(db, key, &val);
204 if (rv == APR_SUCCESS) {
205 prdatum(stdout, val);
206 putchar('\n');
207 continue;
208 }
209 prdatum(stderr, key);
210 fprintf(stderr, ": not found.\n");
211 }
212 break;
213
214 case DDELETE:
215 while (fgets(line, LINEMAX, stdin) != NULL) {
216 n = strlen(line) - 1;
217 line[n] = 0;
218 if (n == 0)
219 break;
220
221 key.dptr = line;
222 key.dsize = n;
223 if (apr_dbm_delete(db, key) != APR_SUCCESS) {
224 prdatum(stderr, key);
225 fprintf(stderr, ": not found.\n");
226 }
227 }
228 break;
229 case DCAT:
230 rv = apr_dbm_firstkey(db, &key);
231 if (rv != APR_SUCCESS)
232 oops(db, rv, "could not fetch first key: %s", file);
233
234 while (key.dptr != NULL) {
235 prdatum(stdout, key);
236 putchar('\t');
237 rv = apr_dbm_fetch(db, key, &val);
238 if (rv != APR_SUCCESS)
239 oops(db, rv, "apr_dbm_fetch", "failure");
240 prdatum(stdout, val);
241 putchar('\n');
242 rv = apr_dbm_nextkey(db, &key);
243 if (rv != APR_SUCCESS)
244 oops(db, rv, "NextKey", "failure");
245 }
246 break;
247 case DBUILD:
248 #ifdef TIME
249 start = time(0);
250 #endif
251 while (fgets(line, LINEMAX, stdin) != NULL) {
252 n = strlen(line) - 1;
253 line[n] = 0;
254 if (n == 0)
255 break;
256
257 key.dptr = line;
258 if ((op = strchr(line, '\t')) != 0) {
259 key.dsize = op - line;
260 *op++ = 0;
261 val.dptr = op;
262 val.dsize = line + n - op;
263 }
264 else
265 oops(NULL, APR_EGENERAL, "bad input: %s", line);
266
267 rv = apr_dbm_store(db, key, val);
268 if (rv != APR_SUCCESS) {
269 prdatum(stderr, key);
270 fprintf(stderr, ": ");
271 oops(db, rv, "store: %s", "failed");
272 }
273 }
274 #ifdef TIME
275 printf("done: %d seconds.\n", time(0) - start);
276 #endif
277 break;
278 case DPRESS:
279 break;
280 case DCREAT:
281 break;
282 case DTRUNC:
283 break;
284 case DNAME:
285 apr_dbm_get_usednames(pool, file, &use1, &use2);
286 fprintf(stderr, "%s %s\n", use1, use2);
287 break;
288 case DAUTO:
289 {
290 int i;
291 char *valdata = "0123456789";
292 fprintf(stderr, "Generating data: ");
293 for (i = 0; i < 10; i++) {
294 int j;
295 char c, keydata[10];
296 for (j = 0, c = 'A' + (i % 16); j < 10; j++, c++) {
297 keydata[j] = c;
298 }
299 key.dptr = keydata;
300 key.dsize = 10;
301 val.dptr = valdata;
302 val.dsize = 10;
303 rv = apr_dbm_store(db, key, val);
304 if (rv != APR_SUCCESS) {
305 prdatum(stderr, key);
306 fprintf(stderr, ": ");
307 oops(db, rv, "store: %s", "failed");
308 }
309 }
310 fputs("OK\n", stderr);
311 fputs("Testing existence/retrieval: ", stderr);
312 for (i = 0; i < 10; i++) {
313 int j;
314 char c, keydata[10];
315 for (j = 0, c = 'A' + (i % 16); j < 10; j++, c++) {
316 keydata[j] = c;
317 }
318 key.dptr = keydata;
319 key.dsize = 10;
320 if (!apr_dbm_exists(db, key)) {
321 prdatum(stderr, key);
322 oops(db, 0, "exists: %s", "failed");
323 }
324 rv = apr_dbm_fetch(db, key, &val);
325 if (rv != APR_SUCCESS || val.dsize != 10 ||
326 (strncmp(val.dptr, valdata, 10) != 0) ) {
327 prdatum(stderr, key);
328 fprintf(stderr, ": ");
329 oops(db, rv, "fetch: %s", "failed");
330 }
331 }
332 fputs("OK\n", stderr);
333 }
334 break;
335 }
336
337 apr_dbm_close(db);
338 }
339
parse_command(const char * str)340 static const cmd *parse_command(const char *str)
341 {
342 int i;
343
344 for (i = 0; i < CMD_SIZE; i++)
345 if (strcasecmp(cmds[i].sname, str) == 0)
346 return &cmds[i];
347
348 return NULL;
349 }
350
prdatum(FILE * stream,apr_datum_t d)351 static void prdatum(FILE *stream, apr_datum_t d)
352 {
353 int c;
354 const char *p = d.dptr;
355 int n = d.dsize;
356
357 while (n--) {
358 c = *p++ & 0377;
359 if (c & 0200) {
360 fprintf(stream, "M-");
361 c &= 0177;
362 }
363 if (c == 0177 || c < ' ')
364 fprintf(stream, "^%c", (c == 0177) ? '?' : c + '@');
365 else
366 putc(c, stream);
367 }
368 }
369
oops(apr_dbm_t * dbm,apr_status_t rv,const char * s1,const char * s2)370 static void oops(apr_dbm_t * dbm, apr_status_t rv, const char *s1,
371 const char *s2)
372 {
373 char errbuf[200];
374
375 if (progname) {
376 fprintf(stderr, "%s: ", progname);
377 }
378 fprintf(stderr, s1, s2);
379 fprintf(stderr, "\n");
380
381 if (rv != APR_SUCCESS) {
382 apr_strerror(rv, errbuf, sizeof(errbuf));
383 fprintf(stderr, "APR Error %d - %s\n", rv, errbuf);
384
385 if (dbm) {
386 apr_dbm_geterror(dbm, &rv, errbuf, sizeof(errbuf));
387 fprintf(stderr, "APR_DB Error %d - %s\n", rv, errbuf);
388 }
389 }
390 exit(1);
391 }
392
show_usage(void)393 static void show_usage(void)
394 {
395 int i;
396
397 if (!progname) {
398 progname = "testdbm";
399 }
400
401 fprintf(stderr, "%s [-t DBM-type] [-R] [commands] dbm-file-path\n",
402 progname);
403
404 fputs("Available DBM-types:", stderr);
405 #if APU_HAVE_GDBM
406 fputs(" GDBM", stderr);
407 #endif
408 #if APU_HAVE_NDBM
409 fputs(" NDBM", stderr);
410 #endif
411 #if APU_HAVE_SDBM
412 fputs(" SDBM", stderr);
413 #endif
414 #if APU_HAVE_DB
415 fputs(" DB", stderr);
416 #endif
417 fputs(" default\n", stderr);
418
419 fputs("Available commands:\n", stderr);
420 for (i = 0; i < CMD_SIZE; i++) {
421 fprintf(stderr, "%-8s%c", cmds[i].sname,
422 ((i + 1) % 6 == 0) ? '\n' : ' ');
423 }
424 fputs("\n", stderr);
425 }
426