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