1 /* 2 * Copyright (c) 1992 Eric P. Allman. 3 * Copyright (c) 1992, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * %sccs.include.redist.c% 7 */ 8 9 #ifndef lint 10 static char sccsid[] = "@(#)makemap.c 8.13 (Berkeley) 05/31/95"; 11 #endif /* not lint */ 12 13 #include <stdio.h> 14 #include <sysexits.h> 15 #include <sys/types.h> 16 #include <ctype.h> 17 #include <string.h> 18 #include <sys/errno.h> 19 #ifndef ISC_UNIX 20 # include <sys/file.h> 21 #endif 22 #include "useful.h" 23 #include "conf.h" 24 25 #ifdef NDBM 26 #include <ndbm.h> 27 #endif 28 29 #ifdef NEWDB 30 #include <db.h> 31 #endif 32 33 enum type { T_DBM, T_BTREE, T_HASH, T_ERR, T_UNKNOWN }; 34 35 union dbent 36 { 37 #ifdef NDBM 38 datum dbm; 39 #endif 40 #ifdef NEWDB 41 DBT db; 42 #endif 43 struct 44 { 45 char *data; 46 size_t size; 47 } xx; 48 }; 49 50 #define BUFSIZE 1024 51 52 main(argc, argv) 53 int argc; 54 char **argv; 55 { 56 char *progname; 57 bool inclnull = FALSE; 58 bool notrunc = FALSE; 59 bool allowreplace = FALSE; 60 bool allowdups = FALSE; 61 bool verbose = FALSE; 62 bool foldcase = TRUE; 63 int exitstat; 64 int opt; 65 char *typename; 66 char *mapname; 67 char *ext; 68 int lineno; 69 int st; 70 int mode; 71 enum type type; 72 int fd; 73 union 74 { 75 #ifdef NDBM 76 DBM *dbm; 77 #endif 78 #ifdef NEWDB 79 DB *db; 80 #endif 81 void *dbx; 82 } dbp; 83 union dbent key, val; 84 #ifdef NEWDB 85 BTREEINFO bti; 86 #endif 87 char ibuf[BUFSIZE]; 88 char fbuf[MAXNAME]; 89 extern char *optarg; 90 extern int optind; 91 extern bool lockfile(); 92 93 progname = argv[0]; 94 95 while ((opt = getopt(argc, argv, "Ndforv")) != EOF) 96 { 97 switch (opt) 98 { 99 case 'N': 100 inclnull = TRUE; 101 break; 102 103 case 'd': 104 allowdups = TRUE; 105 break; 106 107 case 'f': 108 foldcase = FALSE; 109 break; 110 111 case 'o': 112 notrunc = TRUE; 113 break; 114 115 case 'r': 116 allowreplace = TRUE; 117 break; 118 119 case 'v': 120 verbose = TRUE; 121 break; 122 123 default: 124 type = T_ERR; 125 break; 126 } 127 } 128 129 argc -= optind; 130 argv += optind; 131 if (argc != 2) 132 type = T_ERR; 133 else 134 { 135 typename = argv[0]; 136 mapname = argv[1]; 137 ext = NULL; 138 139 if (strcmp(typename, "dbm") == 0) 140 { 141 type = T_DBM; 142 } 143 else if (strcmp(typename, "btree") == 0) 144 { 145 type = T_BTREE; 146 ext = ".db"; 147 } 148 else if (strcmp(typename, "hash") == 0) 149 { 150 type = T_HASH; 151 ext = ".db"; 152 } 153 else 154 type = T_UNKNOWN; 155 } 156 157 switch (type) 158 { 159 case T_ERR: 160 fprintf(stderr, "Usage: %s [-N] [-d] [-f] [-o] [-r] [-v] type mapname\n", progname); 161 exit(EX_USAGE); 162 163 case T_UNKNOWN: 164 fprintf(stderr, "%s: Unknown database type %s\n", 165 progname, typename); 166 exit(EX_USAGE); 167 168 #ifndef NDBM 169 case T_DBM: 170 #endif 171 #ifndef NEWDB 172 case T_BTREE: 173 case T_HASH: 174 #endif 175 fprintf(stderr, "%s: Type %s not supported in this version\n", 176 progname, typename); 177 exit(EX_UNAVAILABLE); 178 179 #ifdef NEWDB 180 case T_BTREE: 181 bzero(&bti, sizeof bti); 182 if (allowdups) 183 bti.flags |= R_DUP; 184 break; 185 186 case T_HASH: 187 #endif 188 #ifdef NDBM 189 case T_DBM: 190 #endif 191 if (allowdups) 192 { 193 fprintf(stderr, "%s: Type %s does not support -d (allow dups)\n", 194 progname, typename); 195 exit(EX_UNAVAILABLE); 196 } 197 break; 198 } 199 200 /* 201 ** Adjust file names. 202 */ 203 204 if (ext != NULL) 205 { 206 int el, fl; 207 208 el = strlen(ext); 209 fl = strlen(mapname); 210 if (fl < el || strcmp(&mapname[fl - el], ext) != 0) 211 { 212 strcpy(fbuf, mapname); 213 strcat(fbuf, ext); 214 mapname = fbuf; 215 } 216 } 217 218 /* 219 ** Create the database. 220 */ 221 222 mode = O_RDWR; 223 #ifdef O_EXLOCK 224 mode |= O_EXLOCK; 225 #endif 226 if (!notrunc) 227 mode |= O_CREAT|O_TRUNC; 228 switch (type) 229 { 230 #ifdef NDBM 231 case T_DBM: 232 dbp.dbm = dbm_open(mapname, mode, 0644); 233 break; 234 #endif 235 236 #ifdef NEWDB 237 case T_HASH: 238 dbp.db = dbopen(mapname, mode, 0644, DB_HASH, NULL); 239 if (dbp.db != NULL) 240 { 241 # if OLD_NEWDB 242 (void) (*dbp.db->sync)(dbp.db); 243 # else 244 (void) (*dbp.db->sync)(dbp.db, 0); 245 # endif 246 } 247 break; 248 249 case T_BTREE: 250 dbp.db = dbopen(mapname, mode, 0644, DB_BTREE, &bti); 251 if (dbp.db != NULL) 252 { 253 # if OLD_NEWDB 254 (void) (*dbp.db->sync)(dbp.db); 255 # else 256 (void) (*dbp.db->sync)(dbp.db, 0); 257 # endif 258 } 259 break; 260 #endif 261 262 default: 263 fprintf(stderr, "%s: internal error: type %d\n", progname, type); 264 exit(EX_SOFTWARE); 265 } 266 267 if (dbp.dbx == NULL) 268 { 269 fprintf(stderr, "%s: cannot create type %s map %s\n", 270 progname, typename, mapname); 271 exit(EX_CANTCREAT); 272 } 273 274 #ifndef O_EXLOCK 275 switch (type) 276 { 277 # ifdef NDBM 278 case T_DBM: 279 fd = dbm_dirfno(dbp.dbm); 280 if (fd >= 0) 281 lockfile(fd); 282 break; 283 # endif 284 # ifdef NEWDB 285 case T_HASH: 286 case T_BTREE: 287 fd = dbp.db->fd(dbp.db); 288 if (fd >= 0) 289 lockfile(fd); 290 break; 291 # endif 292 } 293 #endif 294 295 /* 296 ** Copy the data 297 */ 298 299 lineno = 0; 300 exitstat = EX_OK; 301 while (fgets(ibuf, sizeof ibuf, stdin) != NULL) 302 { 303 register char *p; 304 305 lineno++; 306 307 /* 308 ** Parse the line. 309 */ 310 311 p = strchr(ibuf, '\n'); 312 if (p != NULL) 313 *p = '\0'; 314 else if (!feof(stdin)) 315 { 316 fprintf(stderr, "%s: %s: line %d: line too long (%d bytes max)\n", 317 progname, mapname, lineno, sizeof ibuf); 318 continue; 319 } 320 321 if (ibuf[0] == '\0' || ibuf[0] == '#') 322 continue; 323 if (isspace(ibuf[0])) 324 { 325 fprintf(stderr, "%s: %s: line %d: syntax error (leading space)\n", 326 progname, mapname, lineno); 327 continue; 328 } 329 key.xx.data = ibuf; 330 for (p = ibuf; *p != '\0' && !isspace(*p); p++) 331 { 332 if (foldcase && isupper(*p)) 333 *p = tolower(*p); 334 } 335 key.xx.size = p - key.xx.data; 336 if (inclnull) 337 key.xx.size++; 338 if (*p != '\0') 339 *p++ = '\0'; 340 while (isspace(*p)) 341 p++; 342 if (*p == '\0') 343 { 344 fprintf(stderr, "%s: %s: line %d: no RHS for LHS %s\n", 345 progname, mapname, lineno, key.xx.data); 346 continue; 347 } 348 val.xx.data = p; 349 val.xx.size = strlen(p); 350 if (inclnull) 351 val.xx.size++; 352 353 /* 354 ** Do the database insert. 355 */ 356 357 if (verbose) 358 { 359 printf("key=`%s', val=`%s'\n", key.xx.data, val.xx.data); 360 } 361 362 switch (type) 363 { 364 #ifdef NDBM 365 case T_DBM: 366 st = dbm_store(dbp.dbm, key.dbm, val.dbm, 367 allowreplace ? DBM_REPLACE : DBM_INSERT); 368 break; 369 #endif 370 371 #ifdef NEWDB 372 case T_BTREE: 373 case T_HASH: 374 st = (*dbp.db->put)(dbp.db, &key.db, &val.db, 375 allowreplace ? 0 : R_NOOVERWRITE); 376 break; 377 #endif 378 } 379 380 if (st < 0) 381 { 382 fprintf(stderr, "%s: %s: line %d: key %s: put error\n", 383 progname, mapname, lineno, key.xx.data); 384 perror(mapname); 385 exitstat = EX_IOERR; 386 } 387 else if (st > 0) 388 { 389 fprintf(stderr, "%s: %s: line %d: key %s: duplicate key\n", 390 progname, mapname, lineno, key.xx.data); 391 } 392 } 393 394 /* 395 ** Now close the database. 396 */ 397 398 switch (type) 399 { 400 #ifdef NDBM 401 case T_DBM: 402 dbm_close(dbp.dbm); 403 break; 404 #endif 405 406 #ifdef NEWDB 407 case T_HASH: 408 case T_BTREE: 409 if ((*dbp.db->close)(dbp.db) < 0) 410 { 411 fprintf(stderr, "%s: %s: error on close\n", 412 progname, mapname); 413 perror(mapname); 414 exitstat = EX_IOERR; 415 } 416 #endif 417 } 418 419 exit (exitstat); 420 } 421 /* 422 ** LOCKFILE -- lock a file using flock or (shudder) fcntl locking 423 ** 424 ** Parameters: 425 ** fd -- the file descriptor of the file. 426 ** 427 ** Returns: 428 ** TRUE if the lock was acquired. 429 ** FALSE otherwise. 430 */ 431 432 bool 433 lockfile(fd) 434 int fd; 435 { 436 # if !HASFLOCK 437 int action; 438 struct flock lfd; 439 extern int errno; 440 441 bzero(&lfd, sizeof lfd); 442 lfd.l_type = F_WRLCK; 443 action = F_SETLKW; 444 445 if (fcntl(fd, action, &lfd) >= 0) 446 return TRUE; 447 448 /* 449 ** On SunOS, if you are testing using -oQ/tmp/mqueue or 450 ** -oA/tmp/aliases or anything like that, and /tmp is mounted 451 ** as type "tmp" (that is, served from swap space), the 452 ** previous fcntl will fail with "Invalid argument" errors. 453 ** Since this is fairly common during testing, we will assume 454 ** that this indicates that the lock is successfully grabbed. 455 */ 456 457 if (errno == EINVAL) 458 return TRUE; 459 460 # else /* HASFLOCK */ 461 462 if (flock(fd, LOCK_EX) >= 0) 463 return TRUE; 464 465 # endif 466 467 return FALSE; 468 } 469