Tue Oct 7 01:32:51 2008 UTC ()
Fail with a non-zero exit code if deleting a non-existant key.
Fixes bug introduced in rev 1.15, and reported in PR 39710 from Juan RP.

Don't display various warnings in delete if -q.
Suggested in PR 39710.

Add some sanity enforcing abort()s.


(lukem)
diff -r1.20 -r1.21 src/usr.bin/db/db.c

cvs diff -r1.20 -r1.21 src/usr.bin/db/db.c (switch to unified diff)

--- src/usr.bin/db/db.c 2008/09/05 07:55:33 1.20
+++ src/usr.bin/db/db.c 2008/10/07 01:32:51 1.21
@@ -1,707 +1,716 @@ @@ -1,707 +1,716 @@
1/* $NetBSD: db.c,v 1.20 2008/09/05 07:55:33 lukem Exp $ */ 1/* $NetBSD: db.c,v 1.21 2008/10/07 01:32:51 lukem Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 2002-2008 The NetBSD Foundation, Inc. 4 * Copyright (c) 2002-2008 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to The NetBSD Foundation 7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Luke Mewburn of Wasabi Systems. 8 * by Luke Mewburn of Wasabi Systems.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright 15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the 16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution. 17 * documentation and/or other materials provided with the distribution.
18 * 18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 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 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 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 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 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE. 29 * POSSIBILITY OF SUCH DAMAGE.
30 */ 30 */
31 31
32#include <sys/cdefs.h> 32#include <sys/cdefs.h>
33#ifndef lint 33#ifndef lint
34#ifdef __RCSID 34#ifdef __RCSID
35__RCSID("$NetBSD: db.c,v 1.20 2008/09/05 07:55:33 lukem Exp $"); 35__RCSID("$NetBSD: db.c,v 1.21 2008/10/07 01:32:51 lukem Exp $");
36#endif /* __RCSID */ 36#endif /* __RCSID */
37#endif /* not lint */ 37#endif /* not lint */
38 38
39#include <db.h> 
40#include <ctype.h> 39#include <ctype.h>
 40#include <db.h>
41#include <err.h> 41#include <err.h>
42#include <fcntl.h> 42#include <fcntl.h>
43#include <limits.h> 43#include <limits.h>
44#include <stdio.h> 44#include <stdio.h>
45#include <stdlib.h> 45#include <stdlib.h>
46#include <string.h> 46#include <string.h>
47#include <unistd.h> 47#include <unistd.h>
48#include <vis.h> 48#include <vis.h>
49 49
50 50
51typedef enum { 51typedef enum {
52 F_WRITE = 1<<0, 52 F_WRITE = 1<<0,
53 F_DELETE = 1<<1, 53 F_DELETE = 1<<1,
54 F_SHOW_KEY = 1<<2, 54 F_SHOW_KEY = 1<<2,
55 F_SHOW_VALUE = 1<<3, 55 F_SHOW_VALUE = 1<<3,
56 F_QUIET = 1<<10, 56 F_QUIET = 1<<10,
57 F_IGNORECASE = 1<<11, 57 F_IGNORECASE = 1<<11,
58 F_ENDIAN_BIG = 1<<12, 58 F_ENDIAN_BIG = 1<<12,
59 F_ENDIAN_LITTLE = 1<<13, 59 F_ENDIAN_LITTLE = 1<<13,
60 F_NO_NUL = 1<<14, 60 F_NO_NUL = 1<<14,
61 F_CREATENEW = 1<<20, 61 F_CREATENEW = 1<<20,
62 F_DUPLICATES = 1<<21, 62 F_DUPLICATES = 1<<21,
63 F_REPLACE = 1<<22, 63 F_REPLACE = 1<<22,
64 F_ENCODE_KEY = 1<<23, 64 F_ENCODE_KEY = 1<<23,
65 F_ENCODE_VAL = 1<<24, 65 F_ENCODE_VAL = 1<<24,
66 F_DECODE_KEY = 1<<25, 66 F_DECODE_KEY = 1<<25,
67 F_DECODE_VAL = 1<<26, 67 F_DECODE_VAL = 1<<26,
68} flags_t; 68} flags_t;
69 69
70int main(int, char *[]); 70int main(int, char *[]);
71void db_print(DBT *, DBT *); 71void db_print(DBT *, DBT *);
72int db_dump(void); 72int db_dump(void);
73int db_del(char *); 73int db_del(char *);
74int db_get(char *); 74int db_get(char *);
75int db_put(char *, char *); 75int db_put(char *, char *);
76int parseline(FILE *, const char *, char **, char **); 76int parseline(FILE *, const char *, char **, char **);
77int encode_data(size_t, char *, char **); 77int encode_data(size_t, char *, char **);
78int decode_data(char *, char **); 78int decode_data(char *, char **);
79void parse_encode_decode_arg(const char *, int); 79void parse_encode_decode_arg(const char *, int);
80int parse_encode_option(char **); 80int parse_encode_option(char **);
81void usage(void); 81void usage(void);
82 82
83flags_t flags = 0; 83flags_t flags = 0;
84DB *db; 84DB *db;
85const char *outputsep = "\t"; 85const char *outputsep = "\t";
86int visflags = 0; 86int visflags = 0;
87const char *extra_echars = NULL; 87const char *extra_echars = NULL;
88 88
89int 89int
90main(int argc, char *argv[]) 90main(int argc, char *argv[])
91{ 91{
92 struct { 92 struct {
93 char *file; 93 char *file;
94 char *type; 94 char *type;
95 DBTYPE dbtype; 95 DBTYPE dbtype;
96 void *info; 96 void *info;
97 int flags; 97 int flags;
98 mode_t mode; 98 mode_t mode;
99 unsigned int pagesize; 99 unsigned int pagesize;
100 } oi; 100 } oi;
101 BTREEINFO btreeinfo; 101 BTREEINFO btreeinfo;
102 HASHINFO hashinfo; 102 HASHINFO hashinfo;
103 FILE *infp; 103 FILE *infp;
104 const char *infile, *fieldsep; 104 const char *infile, *fieldsep;
105 char *p, *key, *val; 105 char *p, *key, *val;
106 int ch, rv; 106 int ch, rv;
107 long lval; 107 long lval;
108 108
109 setprogname(argv[0]); 109 setprogname(argv[0]);
110 110
111 infile = NULL; 111 infile = NULL;
112 fieldsep = " "; 112 fieldsep = " ";
113 infp = NULL; 113 infp = NULL;
114 memset(&oi, 0, sizeof(oi)); 114 memset(&oi, 0, sizeof(oi));
115 oi.mode = 0644; 115 oi.mode = 0644;
116 oi.pagesize = 4096; 116 oi.pagesize = 4096;
117 117
118 /* parse arguments */ 118 /* parse arguments */
119 while ( (ch = getopt(argc, argv, 119 while ( (ch = getopt(argc, argv,
120 "CDdE:F:f:iKm:NO:P:qRS:T:U:VwX:")) != -1) { 120 "CDdE:F:f:iKm:NO:P:qRS:T:U:VwX:")) != -1) {
121 switch (ch) { 121 switch (ch) {
122 122
123 case 'C': 123 case 'C':
124 flags |= F_CREATENEW; 124 flags |= F_CREATENEW;
125 break; 125 break;
126 126
127 case 'D': 127 case 'D':
128 flags |= F_DUPLICATES; 128 flags |= F_DUPLICATES;
129 break; 129 break;
130 130
131 case 'd': 131 case 'd':
132 flags |= F_DELETE; 132 flags |= F_DELETE;
133 break; 133 break;
134 134
135 case 'E': 135 case 'E':
136 if (! optarg[0] || optarg[1]) 136 if (! optarg[0] || optarg[1])
137 goto badendian; 137 goto badendian;
138 switch (toupper((int)optarg[0])) { 138 switch (toupper((int)optarg[0])) {
139 case 'B': 139 case 'B':
140 flags |= F_ENDIAN_BIG; 140 flags |= F_ENDIAN_BIG;
141 break; 141 break;
142 case 'L': 142 case 'L':
143 flags |= F_ENDIAN_LITTLE; 143 flags |= F_ENDIAN_LITTLE;
144 break; 144 break;
145 case 'H': 145 case 'H':
146 flags &= ~(F_ENDIAN_BIG | F_ENDIAN_LITTLE); 146 flags &= ~(F_ENDIAN_BIG | F_ENDIAN_LITTLE);
147 break; 147 break;
148 default: 148 default:
149 badendian: 149 badendian:
150 errx(1, "Bad endian `%s'", optarg); 150 errx(1, "Bad endian `%s'", optarg);
151 } 151 }
152 break; 152 break;
153 153
154 case 'F': 154 case 'F':
155 if (! optarg[0]) 155 if (! optarg[0])
156 errx(1, "Invalid field separator `%s'", 156 errx(1, "Invalid field separator `%s'",
157 optarg); 157 optarg);
158 fieldsep = optarg; 158 fieldsep = optarg;
159 break; 159 break;
160 160
161 case 'f': 161 case 'f':
162 infile = optarg; 162 infile = optarg;
163 break; 163 break;
164 164
165 case 'i': 165 case 'i':
166 flags |= F_IGNORECASE; 166 flags |= F_IGNORECASE;
167 break; 167 break;
168 168
169 case 'K': 169 case 'K':
170 flags |= F_SHOW_KEY; 170 flags |= F_SHOW_KEY;
171 break; 171 break;
172 172
173 case 'm': 173 case 'm':
174 lval = strtol(optarg, &p, 8); 174 lval = strtol(optarg, &p, 8);
175 if (p == optarg || *p != '\0') 175 if (p == optarg || *p != '\0')
176 errx(1, "Invalid octal number `%s'", optarg); 176 errx(1, "Invalid octal number `%s'", optarg);
177 if (lval < 0 || lval > 07777) 177 if (lval < 0 || lval > 07777)
178 errx(1, "Invalid mode `%s'", optarg); 178 errx(1, "Invalid mode `%s'", optarg);
179 oi.mode = (mode_t)lval; 179 oi.mode = (mode_t)lval;
180 break; 180 break;
181 181
182 case 'N': 182 case 'N':
183 flags |= F_NO_NUL; 183 flags |= F_NO_NUL;
184 break; 184 break;
185 185
186 case 'O': 186 case 'O':
187 outputsep = optarg; 187 outputsep = optarg;
188 break; 188 break;
189 189
190 case 'P': 190 case 'P':
191 lval = strtol(optarg, &p, 10); 191 lval = strtol(optarg, &p, 10);
192 if (p == optarg || *p != '\0') 192 if (p == optarg || *p != '\0')
193 errx(1, "Invalid pagesize `%s'", optarg); 193 errx(1, "Invalid pagesize `%s'", optarg);
194 if (lval < 0 || lval >= UINT_MAX) 194 if (lval < 0 || lval >= UINT_MAX)
195 errx(1, "Pagesize `%s' out of range", optarg); 195 errx(1, "Pagesize `%s' out of range", optarg);
196 oi.pagesize = (unsigned int)lval; 196 oi.pagesize = (unsigned int)lval;
197 break; 197 break;
198 198
199 case 'q': 199 case 'q':
200 flags |= F_QUIET; 200 flags |= F_QUIET;
201 break; 201 break;
202 202
203 case 'R': 203 case 'R':
204 flags |= F_REPLACE; 204 flags |= F_REPLACE;
205 break; 205 break;
206 206
207 case 'S': 207 case 'S':
208 parse_encode_decode_arg(optarg, 1 /* encode */); 208 parse_encode_decode_arg(optarg, 1 /* encode */);
209 if (! (flags & (F_ENCODE_KEY | F_ENCODE_VAL))) 209 if (! (flags & (F_ENCODE_KEY | F_ENCODE_VAL)))
210 errx(1, "Invalid encoding argument `%s'", 210 errx(1, "Invalid encoding argument `%s'",
211 optarg); 211 optarg);
212 break; 212 break;
213 213
214 case 'T': 214 case 'T':
215 visflags = parse_encode_option(&optarg); 215 visflags = parse_encode_option(&optarg);
216 if (! visflags) 216 if (! visflags)
217 errx(1, "Invalid encoding/decoding option `%s'", 217 errx(1, "Invalid encoding/decoding option `%s'",
218 optarg); 218 optarg);
219 break; 219 break;
220 220
221 case 'U': 221 case 'U':
222 parse_encode_decode_arg(optarg, 0 /* decode */); 222 parse_encode_decode_arg(optarg, 0 /* decode */);
223 if (! (flags & (F_DECODE_KEY | F_DECODE_VAL))) 223 if (! (flags & (F_DECODE_KEY | F_DECODE_VAL)))
224 errx(1, "Invalid decoding argument `%s'", 224 errx(1, "Invalid decoding argument `%s'",
225 optarg); 225 optarg);
226 break; 226 break;
227 227
228 case 'V': 228 case 'V':
229 flags |= F_SHOW_VALUE; 229 flags |= F_SHOW_VALUE;
230 break; 230 break;
231 231
232 case 'w': 232 case 'w':
233 flags |= F_WRITE; 233 flags |= F_WRITE;
234 break; 234 break;
235 235
236 case 'X': 236 case 'X':
237 extra_echars = optarg; 237 extra_echars = optarg;
238 break; 238 break;
239 239
240 default: 240 default:
241 usage(); 241 usage();
242 242
243 } 243 }
244 } 244 }
245 argc -= optind; 245 argc -= optind;
246 argv += optind; 246 argv += optind;
247 247
248 /* validate arguments */ 248 /* validate arguments */
249 if (argc < 2) 249 if (argc < 2)
250 usage(); 250 usage();
251 oi.type = argv[0]; 251 oi.type = argv[0];
252 oi.file = argv[1]; 252 oi.file = argv[1];
253 argc -= 2; 253 argc -= 2;
254 argv += 2; 254 argv += 2;
255 255
256 if (flags & F_WRITE) { 256 if (flags & F_WRITE) {
257 if (flags & (F_SHOW_KEY | F_SHOW_VALUE | F_DELETE)) 257 if (flags & (F_SHOW_KEY | F_SHOW_VALUE | F_DELETE))
258 usage(); 258 usage();
259 if ((!infile && argc < 2) || (argc % 2)) 259 if ((!infile && argc < 2) || (argc % 2))
260 usage(); 260 usage();
261 if (0 != (visflags & ~(VIS_HTTPSTYLE))) 261 if (0 != (visflags & ~(VIS_HTTPSTYLE)))
262 errx(1, "Unsupported decoding option provided to -T"); 262 errx(1, "Unsupported decoding option provided to -T");
263 oi.flags = O_RDWR | O_CREAT | O_EXLOCK; 263 oi.flags = O_RDWR | O_CREAT | O_EXLOCK;
264 if (flags & F_CREATENEW) 264 if (flags & F_CREATENEW)
265 oi.flags |= O_TRUNC; 265 oi.flags |= O_TRUNC;
266 } else if (flags & F_DELETE) { 266 } else if (flags & F_DELETE) {
267 if (flags & (F_SHOW_KEY | F_SHOW_VALUE | F_WRITE)) 267 if (flags & (F_SHOW_KEY | F_SHOW_VALUE | F_WRITE))
268 usage(); 268 usage();
269 if (!infile && argc < 1) 269 if (!infile && argc < 1)
270 usage(); 270 usage();
271 if (0 != (visflags & ~(VIS_HTTPSTYLE))) 271 if (0 != (visflags & ~(VIS_HTTPSTYLE)))
272 errx(1, "Unsupported decoding option provided to -T"); 272 errx(1, "Unsupported decoding option provided to -T");
273 oi.flags = O_RDWR | O_CREAT | O_EXLOCK; 273 oi.flags = O_RDWR | O_CREAT | O_EXLOCK;
274 } else { 274 } else {
275 if (! (flags & (F_SHOW_KEY | F_SHOW_VALUE))) 275 if (! (flags & (F_SHOW_KEY | F_SHOW_VALUE)))
276 flags |= (F_SHOW_KEY | F_SHOW_VALUE); 276 flags |= (F_SHOW_KEY | F_SHOW_VALUE);
277 oi.flags = O_RDONLY | O_SHLOCK; 277 oi.flags = O_RDONLY | O_SHLOCK;
278 } 278 }
279 279
280 /* validate oi.type */ 280 /* validate oi.type */
281 if (strcmp(oi.type, "btree") == 0) { 281 if (strcmp(oi.type, "btree") == 0) {
282 memset(&btreeinfo, 0, sizeof(btreeinfo)); 282 memset(&btreeinfo, 0, sizeof(btreeinfo));
283 if (flags & F_ENDIAN_BIG) 283 if (flags & F_ENDIAN_BIG)
284 btreeinfo.lorder = 4321; 284 btreeinfo.lorder = 4321;
285 else if (flags & F_ENDIAN_LITTLE) 285 else if (flags & F_ENDIAN_LITTLE)
286 btreeinfo.lorder = 1234; 286 btreeinfo.lorder = 1234;
287 if (flags & F_DUPLICATES) 287 if (flags & F_DUPLICATES)
288 btreeinfo.flags = R_DUP; 288 btreeinfo.flags = R_DUP;
289 btreeinfo.psize = oi.pagesize; 289 btreeinfo.psize = oi.pagesize;
290 btreeinfo.cachesize = 1024 * 1024; 290 btreeinfo.cachesize = 1024 * 1024;
291 oi.info = &btreeinfo; 291 oi.info = &btreeinfo;
292 oi.dbtype = DB_BTREE; 292 oi.dbtype = DB_BTREE;
293 } else if (strcmp(oi.type, "hash") == 0) { 293 } else if (strcmp(oi.type, "hash") == 0) {
294 memset(&hashinfo, 0, sizeof(hashinfo)); 294 memset(&hashinfo, 0, sizeof(hashinfo));
295 if (flags & F_ENDIAN_BIG) 295 if (flags & F_ENDIAN_BIG)
296 hashinfo.lorder = 4321; 296 hashinfo.lorder = 4321;
297 else if (flags & F_ENDIAN_LITTLE) 297 else if (flags & F_ENDIAN_LITTLE)
298 hashinfo.lorder = 1234; 298 hashinfo.lorder = 1234;
299 hashinfo.bsize = oi.pagesize; 299 hashinfo.bsize = oi.pagesize;
300 hashinfo.cachesize = 1024 * 1024; 300 hashinfo.cachesize = 1024 * 1024;
301 oi.info = &hashinfo; 301 oi.info = &hashinfo;
302 oi.dbtype = DB_HASH; 302 oi.dbtype = DB_HASH;
303 } else { 303 } else {
304 warnx("Unknown database type `%s'", oi.type); 304 warnx("Unknown database type `%s'", oi.type);
305 usage(); 305 usage();
306 } 306 }
307 307
308 if (infile) { 308 if (infile) {
309 if (strcmp(infile, "-") == 0) 309 if (strcmp(infile, "-") == 0)
310 infp = stdin; 310 infp = stdin;
311 else if ((infp = fopen(infile, "r")) == NULL) 311 else if ((infp = fopen(infile, "r")) == NULL)
312 err(1, "Opening input file `%s'", infile); 312 err(1, "Opening input file `%s'", infile);
313 } 313 }
314 314
315 /* open database */ 315 /* open database */
316 db = dbopen(oi.file, oi.flags, oi.mode, oi.dbtype, oi.info); 316 db = dbopen(oi.file, oi.flags, oi.mode, oi.dbtype, oi.info);
317 if (db == NULL) 317 if (db == NULL)
318 err(1, "Opening database `%s'", oi.file); 318 err(1, "Opening database `%s'", oi.file);
319 319
320 320
321 /* manipulate database */ 321 /* manipulate database */
322 rv = 0; 322 rv = 0;
323 if (flags & F_WRITE) { /* write entries */ 323 if (flags & F_WRITE) { /* write entries */
324 for (ch = 0; ch < argc; ch += 2) 324 for (ch = 0; ch < argc; ch += 2)
325 if ((rv = db_put(argv[ch], argv[ch+1]))) 325 if ((rv = db_put(argv[ch], argv[ch+1])))
326 goto cleanup; 326 goto cleanup;
327 if (infp) { 327 if (infp) {
328 while (parseline(infp, fieldsep, &key, &val)) { 328 while (parseline(infp, fieldsep, &key, &val)) {
329 if ((rv = db_put(key, val))) 329 if ((rv = db_put(key, val)))
330 goto cleanup; 330 goto cleanup;
331 } 331 }
332 if (ferror(infp)) { 332 if (ferror(infp)) {
333 warnx("Reading `%s'", infile); 333 warnx("Reading `%s'", infile);
334 goto cleanup; 334 goto cleanup;
335 } 335 }
336 } 336 }
337 } else if (!infp && argc == 0) { /* read all */ 337 } else if (!infp && argc == 0) { /* read all */
338 db_dump(); 338 db_dump();
339 } else { /* read/delete specific */ 339 } else { /* read/delete specific */
340 int (*dbop)(char *); 340 int (*dbop)(char *);
341 341
342 if (flags & F_DELETE) 342 if (flags & F_DELETE)
343 dbop = db_del; 343 dbop = db_del;
344 else 344 else
345 dbop = db_get; 345 dbop = db_get;
346 for (ch = 0; ch < argc; ch++) { 346 for (ch = 0; ch < argc; ch++) {
347 if ((rv = dbop(argv[ch]))) 347 if ((rv = dbop(argv[ch])))
348 goto cleanup; 348 goto cleanup;
349 } 349 }
350 if (infp) { 350 if (infp) {
351 while (parseline(infp, fieldsep, &key, NULL)) { 351 while (parseline(infp, fieldsep, &key, NULL)) {
352 if ((rv = dbop(key))) 352 if ((rv = dbop(key)))
353 goto cleanup; 353 goto cleanup;
354 } 354 }
355 if (ferror(infp)) { 355 if (ferror(infp)) {
356 warnx("Reading `%s'", infile); 356 warnx("Reading `%s'", infile);
357 goto cleanup; 357 goto cleanup;
358 } 358 }
359 } 359 }
360 } 360 }
361 361
362 /* close database */ 362 /* close database */
363 cleanup: 363 cleanup:
364 if (db->close(db) == -1) 364 if (db->close(db) == -1)
365 err(1, "Closing database `%s'", oi.file); 365 err(1, "Closing database `%s'", oi.file);
366 if (infp) 366 if (infp)
367 fclose(infp); 367 fclose(infp);
368 return (rv); 368 return (rv);
369} 369}
370 370
371void 371void
372db_print(DBT *key, DBT *val) 372db_print(DBT *key, DBT *val)
373{ 373{
374 int len; 374 int len;
375 char *data; 375 char *data;
376 376
377#define MINUSNUL(x) ((x) > 0 ? (x) - (flags & F_NO_NUL ? 0 : 1) : 0) 377#define MINUSNUL(x) ((x) > 0 ? (x) - (flags & F_NO_NUL ? 0 : 1) : 0)
378 378
379 if (flags & F_SHOW_KEY) { 379 if (flags & F_SHOW_KEY) {
380 if (flags & F_ENCODE_KEY) { 380 if (flags & F_ENCODE_KEY) {
381 len = encode_data(MINUSNUL(key->size), 381 len = encode_data(MINUSNUL(key->size),
382 (char *)key->data, &data); 382 (char *)key->data, &data);
383 } else { 383 } else {
384 len = (int)MINUSNUL(key->size); 384 len = (int)MINUSNUL(key->size);
385 data = (char *)key->data; 385 data = (char *)key->data;
386 } 386 }
387 printf("%.*s", len, data); 387 printf("%.*s", len, data);
388 } 388 }
389 if ((flags & F_SHOW_KEY) && (flags & F_SHOW_VALUE)) 389 if ((flags & F_SHOW_KEY) && (flags & F_SHOW_VALUE))
390 printf("%s", outputsep); 390 printf("%s", outputsep);
391 if (flags & F_SHOW_VALUE) { 391 if (flags & F_SHOW_VALUE) {
392 if (flags & F_ENCODE_VAL) { 392 if (flags & F_ENCODE_VAL) {
393 len = encode_data(MINUSNUL(val->size), 393 len = encode_data(MINUSNUL(val->size),
394 (char *)val->data, &data); 394 (char *)val->data, &data);
395 } else { 395 } else {
396 len = (int)MINUSNUL(val->size); 396 len = (int)MINUSNUL(val->size);
397 data = (char *)val->data; 397 data = (char *)val->data;
398 } 398 }
399 printf("%.*s", len, data); 399 printf("%.*s", len, data);
400 } 400 }
401 printf("\n"); 401 printf("\n");
402} 402}
403 403
404int 404int
405db_dump(void) 405db_dump(void)
406{ 406{
407 DBT key, val; 407 DBT key, val;
408 int rv; 408 int rv;
409 409
410 while ((rv = db->seq(db, &key, &val, R_NEXT)) == 0) 410 while ((rv = db->seq(db, &key, &val, R_NEXT)) == 0)
411 db_print(&key, &val); 411 db_print(&key, &val);
412 if (rv == -1) 412 if (rv == -1)
413 warn("Error dumping database"); 413 warn("Error dumping database");
414 return (rv == 1 ? 0 : 1); 414 return (rv == 1 ? 0 : 1);
415} 415}
416 416
417static void 417static void
418db_makekey(DBT *key, char *keystr, int downcase, int decode) 418db_makekey(DBT *key, char *keystr, int downcase, int decode)
419{ 419{
420 char *p, *ks; 420 char *p, *ks;
421 int klen; 421 int klen;
422 422
423 memset(key, 0, sizeof(*key)); 423 memset(key, 0, sizeof(*key));
424 if (decode) { 424 if (decode) {
425 if ((klen = decode_data(keystr, &ks)) == -1) 425 if ((klen = decode_data(keystr, &ks)) == -1)
426 errx(1, "Invalid escape sequence in `%s'", keystr); 426 errx(1, "Invalid escape sequence in `%s'", keystr);
427 } else { 427 } else {
428 klen = strlen(keystr); 428 klen = strlen(keystr);
429 ks = keystr; 429 ks = keystr;
430 } 430 }
431 key->data = ks; 431 key->data = ks;
432 key->size = klen + (flags & F_NO_NUL ? 0 : 1); 432 key->size = klen + (flags & F_NO_NUL ? 0 : 1);
433 if (downcase && (flags & F_IGNORECASE)) { 433 if (downcase && (flags & F_IGNORECASE)) {
434 for (p = ks; *p; p++) 434 for (p = ks; *p; p++)
435 if (isupper((int)*p)) 435 if (isupper((int)*p))
436 *p = tolower((int)*p); 436 *p = tolower((int)*p);
437 } 437 }
438} 438}
439 439
440int 440int
441db_del(char *keystr) 441db_del(char *keystr)
442{ 442{
443 DBT key; 443 DBT key;
444 int r = 0; 444 int r;
445 445
446 db_makekey(&key, keystr, 1, (flags & F_DECODE_KEY ? 1 : 0)); 446 db_makekey(&key, keystr, 1, (flags & F_DECODE_KEY ? 1 : 0));
447 switch (db->del(db, &key, 0)) { 447 r = db->del(db, &key, 0);
 448 switch (r) {
448 case -1: 449 case -1:
449 warn("Error deleting key `%s'", keystr); 450 if (! (flags & F_QUIET))
 451 warn("Error deleting key `%s'", keystr);
450 r = 1; 452 r = 1;
451 break; 453 break;
452 case 0: 454 case 0:
453 if (! (flags & F_QUIET)) 455 if (! (flags & F_QUIET))
454 printf("Deleted key `%s'\n", keystr); 456 printf("Deleted key `%s'\n", keystr);
455 break; 457 break;
456 case 1: 458 case 1:
457 warnx("Unknown key `%s'", keystr); 459 if (! (flags & F_QUIET))
 460 warnx("Unknown key `%s'", keystr);
458 break; 461 break;
 462 default:
 463 abort();
459 } 464 }
460 if (flags & F_DECODE_KEY) 465 if (flags & F_DECODE_KEY)
461 free(key.data); 466 free(key.data);
462 return (r); 467 return (r);
463} 468}
464 469
465int 470int
466db_get(char *keystr) 471db_get(char *keystr)
467{ 472{
468 DBT key, val; 473 DBT key, val;
469 char *wantkey; 474 char *wantkey;
470 int r, found; 475 int r, found;
471 u_int seqflags; 476 u_int seqflags;
472 477
473 db_makekey(&key, keystr, 1, (flags & F_DECODE_KEY ? 1 : 0)); 478 db_makekey(&key, keystr, 1, (flags & F_DECODE_KEY ? 1 : 0));
474 wantkey = strdup(key.data); 479 wantkey = strdup(key.data);
475 if (wantkey == NULL) 480 if (wantkey == NULL)
476 err(1, "Cannot allocate key buffer"); 481 err(1, "Cannot allocate key buffer");
477 482
478 found = 0; 483 found = 0;
479 seqflags = R_CURSOR; 484 seqflags = R_CURSOR;
480 while ((r = db->seq(db, &key, &val, seqflags)) == 0) { 485 while ((r = db->seq(db, &key, &val, seqflags)) == 0) {
481 if (strcmp((char *)key.data, wantkey) != 0) { 486 if (strcmp((char *)key.data, wantkey) != 0) {
482 r = 1; 487 r = 1;
483 break; 488 break;
484 } 489 }
485 seqflags = R_NEXT; 490 seqflags = R_NEXT;
486 found++; 491 found++;
487 db_print(&key, &val); 492 db_print(&key, &val);
488 if (! (flags & F_DUPLICATES)) 493 if (! (flags & F_DUPLICATES))
489 break; 494 break;
490 } 495 }
491 496
492 switch (r) { 497 switch (r) {
493 case -1: 498 case -1:
494 warn("Error reading key `%s'", keystr); 499 warn("Error reading key `%s'", keystr);
495 r = 1; 500 r = 1;
496 break; 501 break;
497 case 0: 502 case 0:
498 break; 503 break;
499 case 1: 504 case 1:
500 if (found) { 505 if (found) {
501 r = 0; 506 r = 0;
502 break; 507 break;
503 } 508 }
504 if (! (flags & F_QUIET)) { 509 if (! (flags & F_QUIET)) {
505 warnx("Unknown key `%s'", keystr); 510 warnx("Unknown key `%s'", keystr);
506 } 511 }
507 break; 512 break;
 513 default:
 514 abort();
508 } 515 }
509 if (flags & F_DECODE_KEY) 516 if (flags & F_DECODE_KEY)
510 free(key.data); 517 free(key.data);
511 free(wantkey); 518 free(wantkey);
512 return (r); 519 return (r);
513} 520}
514 521
515int 522int
516db_put(char *keystr, char *valstr) 523db_put(char *keystr, char *valstr)
517{ 524{
518 DBT key, val; 525 DBT key, val;
519 int r = 0; 526 int r = 0;
520 527
521 db_makekey(&key, keystr, 1, (flags & F_DECODE_KEY ? 1 : 0)); 528 db_makekey(&key, keystr, 1, (flags & F_DECODE_KEY ? 1 : 0));
522 db_makekey(&val, valstr, 0, (flags & F_DECODE_VAL ? 1 : 0)); 529 db_makekey(&val, valstr, 0, (flags & F_DECODE_VAL ? 1 : 0));
523 switch (db->put(db, &key, &val, 530 r = db->put(db, &key, &val, (flags & F_REPLACE) ? 0 : R_NOOVERWRITE);
524 (flags & F_REPLACE) ? 0 : R_NOOVERWRITE)) { 531 switch (r) {
525 case -1: 532 case -1:
526 warn("Error writing key `%s'", keystr); 533 warn("Error writing key `%s'", keystr);
527 r = 1; 534 r = 1;
528 break; 535 break;
529 case 0: 536 case 0:
530 if (! (flags & F_QUIET)) 537 if (! (flags & F_QUIET))
531 printf("Added key `%s'\n", keystr); 538 printf("Added key `%s'\n", keystr);
532 break; 539 break;
533 case 1: 540 case 1:
534 if (! (flags & F_QUIET)) 541 if (! (flags & F_QUIET))
535 warnx("Key `%s' already exists", keystr); 542 warnx("Key `%s' already exists", keystr);
536 break; 543 break;
 544 default:
 545 abort();
537 } 546 }
538 if (flags & F_DECODE_KEY) 547 if (flags & F_DECODE_KEY)
539 free(key.data); 548 free(key.data);
540 if (flags & F_DECODE_VAL) 549 if (flags & F_DECODE_VAL)
541 free(val.data); 550 free(val.data);
542 return (r); 551 return (r);
543} 552}
544 553
545int 554int
546parseline(FILE *fp, const char *sep, char **kp, char **vp) 555parseline(FILE *fp, const char *sep, char **kp, char **vp)
547{ 556{
548 size_t len; 557 size_t len;
549 char *key, *val; 558 char *key, *val;
550 559
551 key = fgetln(fp, &len); 560 key = fgetln(fp, &len);
552 if (key == NULL) /* end of file, or error */ 561 if (key == NULL) /* end of file, or error */
553 return (0); 562 return (0);
554 563
555 if (key[len-1] == '\n') /* check for \n at EOL */ 564 if (key[len-1] == '\n') /* check for \n at EOL */
556 key[--len] = '\0'; 565 key[--len] = '\0';
557 else 566 else
558 return (0); 567 return (0);
559 568
560 *kp = key; 569 *kp = key;
561 if (vp == NULL) /* don't split if don't want value */ 570 if (vp == NULL) /* don't split if don't want value */
562 return (1); 571 return (1);
563 if ((val = strstr(key, sep)) == NULL) 572 if ((val = strstr(key, sep)) == NULL)
564 val = key + len; 573 val = key + len;
565 else { 574 else {
566 *val = '\0'; 575 *val = '\0';
567 val += strlen(sep); 576 val += strlen(sep);
568 } 577 }
569 *vp = val; 578 *vp = val;
570 return (1); 579 return (1);
571} 580}
572 581
573int 582int
574encode_data(size_t len, char *data, char **edata) 583encode_data(size_t len, char *data, char **edata)
575{ 584{
576 static char *buf = NULL; 585 static char *buf = NULL;
577 char *nbuf; 586 char *nbuf;
578 static size_t buflen = 0; 587 static size_t buflen = 0;
579 size_t elen; 588 size_t elen;
580 589
581 elen = 1 + (len * 4); 590 elen = 1 + (len * 4);
582 if (elen > buflen) { 591 if (elen > buflen) {
583 if ((nbuf = realloc(buf, elen)) == NULL) 592 if ((nbuf = realloc(buf, elen)) == NULL)
584 err(1, "Cannot allocate encoding buffer"); 593 err(1, "Cannot allocate encoding buffer");
585 buf = nbuf; 594 buf = nbuf;
586 buflen = elen; 595 buflen = elen;
587 } 596 }
588 *edata = buf; 597 *edata = buf;
589 if (extra_echars) { 598 if (extra_echars) {
590 return (strsvisx(buf, data, len, visflags, extra_echars)); 599 return (strsvisx(buf, data, len, visflags, extra_echars));
591 } else { 600 } else {
592 return (strvisx(buf, data, len, visflags)); 601 return (strvisx(buf, data, len, visflags));
593 } 602 }
594} 603}
595 604
596int 605int
597decode_data(char *data, char **ddata) 606decode_data(char *data, char **ddata)
598{ 607{
599 char *buf; 608 char *buf;
600 609
601 if ((buf = malloc(strlen(data) + 1)) == NULL) 610 if ((buf = malloc(strlen(data) + 1)) == NULL)
602 err(1, "Cannot allocate decoding buffer"); 611 err(1, "Cannot allocate decoding buffer");
603 *ddata = buf; 612 *ddata = buf;
604 return (strunvisx(buf, data, (visflags & VIS_HTTPSTYLE))); 613 return (strunvisx(buf, data, (visflags & VIS_HTTPSTYLE)));
605} 614}
606 615
607void 616void
608parse_encode_decode_arg(const char *arg, int encode) 617parse_encode_decode_arg(const char *arg, int encode)
609{ 618{
610 if (! arg[0] || arg[1]) 619 if (! arg[0] || arg[1])
611 return; 620 return;
612 if (arg[0] == 'k' || arg[0] == 'b') { 621 if (arg[0] == 'k' || arg[0] == 'b') {
613 if (encode) 622 if (encode)
614 flags |= F_ENCODE_KEY; 623 flags |= F_ENCODE_KEY;
615 else 624 else
616 flags |= F_DECODE_KEY; 625 flags |= F_DECODE_KEY;
617 } 626 }
618 if (arg[0] == 'v' || arg[0] == 'b') { 627 if (arg[0] == 'v' || arg[0] == 'b') {
619 if (encode) 628 if (encode)
620 flags |= F_ENCODE_VAL; 629 flags |= F_ENCODE_VAL;
621 else 630 else
622 flags |= F_DECODE_VAL; 631 flags |= F_DECODE_VAL;
623 } 632 }
624 return; 633 return;
625} 634}
626 635
627int 636int
628parse_encode_option(char **arg) 637parse_encode_option(char **arg)
629{ 638{
630 int r = 0; 639 int r = 0;
631 int encmask = ~(VIS_CSTYLE | VIS_HTTPSTYLE | VIS_OCTAL); 640 int encmask = ~(VIS_CSTYLE | VIS_HTTPSTYLE | VIS_OCTAL);
632 641
633 for(; **arg; (*arg)++) { 642 for(; **arg; (*arg)++) {
634 switch (**arg) { 643 switch (**arg) {
635 case 'b': 644 case 'b':
636 r |= VIS_NOSLASH; 645 r |= VIS_NOSLASH;
637 break; 646 break;
638 case 'c': 647 case 'c':
639 r &= encmask; 648 r &= encmask;
640 r |= VIS_CSTYLE; 649 r |= VIS_CSTYLE;
641 break; 650 break;
642 case 'h': 651 case 'h':
643 r &= encmask; 652 r &= encmask;
644 r |= VIS_HTTPSTYLE; 653 r |= VIS_HTTPSTYLE;
645 break; 654 break;
646 case 'o': 655 case 'o':
647 r &= encmask; 656 r &= encmask;
648 r |= VIS_OCTAL; 657 r |= VIS_OCTAL;
649 break; 658 break;
650 case 's': 659 case 's':
651 r |= VIS_SAFE; 660 r |= VIS_SAFE;
652 break; 661 break;
653 case 't': 662 case 't':
654 r |= VIS_TAB; 663 r |= VIS_TAB;
655 break; 664 break;
656 case 'w': 665 case 'w':
657 r |= VIS_WHITE; 666 r |= VIS_WHITE;
658 break; 667 break;
659 default: 668 default:
660 return (0); 669 return (0);
661 break; 670 break;
662 } 671 }
663 } 672 }
664 return (r); 673 return (r);
665} 674}
666 675
667void 676void
668usage(void) 677usage(void)
669{ 678{
670 const char *p = getprogname(); 679 const char *p = getprogname();
671 680
672 fprintf(stderr, 681 fprintf(stderr,
673"usage: %s [-KiNqV] [-E endian] [-f infile] [-O outsep] [-S visitem]\n" 682"usage: %s [-KiNqV] [-E endian] [-f infile] [-O outsep] [-S visitem]\n"
674" [-T visspec] [-X extravis] type dbfile [key [...]]\n" 683" [-T visspec] [-X extravis] type dbfile [key [...]]\n"
675" %s -d [-iNq] [-E endian] [-f infile] [-T visspec] [-U unvisitem]\n" 684" %s -d [-iNq] [-E endian] [-f infile] [-T visspec] [-U unvisitem]\n"
676" type dbfile [key [...]]\n" 685" type dbfile [key [...]]\n"
677" %s -w [-CDiNqR] [-E endian] [-F isep] [-f infile] [-m mode]\n" 686" %s -w [-CDiNqR] [-E endian] [-F isep] [-f infile] [-m mode]\n"
678" [-P pagesize] [-T visspec] [-U unvisitem]\n" 687" [-P pagesize] [-T visspec] [-U unvisitem]\n"
679" type dbfile [key value [...]]\n" 688" type dbfile [key value [...]]\n"
680 ,p ,p ,p ); 689 ,p ,p ,p );
681 fprintf(stderr, 690 fprintf(stderr,
682"Supported modes:\n" 691"Supported modes:\n"
683" read keys [default]\n" 692" read keys [default]\n"
684" -d delete keys\n" 693" -d delete keys\n"
685" -w write (add) keys/values\n" 694" -w write (add) keys/values\n"
686"Supported options:\n" 695"Supported options:\n"
687" -C create empty (truncated) database\n" 696" -C create empty (truncated) database\n"
688" -D allow duplicates\n" 697" -D allow duplicates\n"
689" -E endian database endian: `B'ig, `L'ittle, `H'ost [default: H]\n" 698" -E endian database endian: `B'ig, `L'ittle, `H'ost [default: H]\n"
690" -F isep input field separator string [default: a space]\n" 699" -F isep input field separator string [default: a space]\n"
691" -f infile file of keys (read|delete) or keys/vals (write)\n" 700" -f infile file of keys (read|delete) or keys/vals (write)\n"
692" -i ignore case of key by converting to lower case\n" 701" -i ignore case of key by converting to lower case\n"
693" -K print key\n" 702" -K print key\n"
694" -m mode mode of created database [default: 0644]\n" 703" -m mode mode of created database [default: 0644]\n"
695" -N don't NUL terminate key\n" 704" -N don't NUL terminate key\n"
696" -O outsep output field separator string [default: a tab]\n" 705" -O outsep output field separator string [default: a tab]\n"
697" -P pagesize database page size [default: 4096]\n" 706" -P pagesize database page size [default: 4096]\n"
698" -q quiet operation (missing keys aren't errors)\n" 707" -q quiet operation (missing keys aren't errors)\n"
699" -R replace existing keys\n" 708" -R replace existing keys\n"
700" -S visitem items to strvis(3) encode: 'k'ey, 'v'alue, 'b'oth\n" 709" -S visitem items to strvis(3) encode: 'k'ey, 'v'alue, 'b'oth\n"
701" -T visspec options to control -S and -U; like vis(1) options\n" 710" -T visspec options to control -S and -U; like vis(1) options\n"
702" -U unvisitem items to strunvis(3) decode: 'k'ey, 'v'alue, 'b'oth\n" 711" -U unvisitem items to strunvis(3) decode: 'k'ey, 'v'alue, 'b'oth\n"
703" -V print value\n" 712" -V print value\n"
704" -X extravis extra characters to encode with -S\n" 713" -X extravis extra characters to encode with -S\n"
705 ); 714 );
706 exit(1); 715 exit(1);
707} 716}