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