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
main(argc,argv)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
lockfile(fd)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