1 /*
2  * Copyright (c) 1990, 1993 Jan-Simon Pendry
3  * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
4  * Copyright (c) 1990, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Jan-Simon Pendry at Imperial College, London.
9  *
10  * %sccs.include.redist.c%
11  *
12  *	@(#)mk-amd-map.c	8.1 (Berkeley) 06/28/93
13  *
14  * $Id: mk-amd-map.c,v 5.2.2.1 1992/02/09 15:09:18 jsp beta $
15  */
16 
17 /*
18  * Convert a file map into an ndbm map
19  */
20 
21 #ifndef lint
22 char copyright[] = "\
23 @(#)Copyright (c) 1990, 1993 Jan-Simon Pendry\n\
24 @(#)Copyright (c) 1990 Imperial College of Science, Technology & Medicine\n\
25 @(#)Copyright (c) 1990, 1993\n\
26 	The Regents of the University of California.  All rights reserved.\n";
27 #endif /* not lint */
28 
29 #ifndef lint
30 static char rcsid[] = "$Id: mk-amd-map.c,v 5.2.2.1 1992/02/09 15:09:18 jsp beta $";
31 static char sccsid[] = "@(#)mk-amd-map.c	8.1 (Berkeley) 06/28/93";
32 #endif /* not lint */
33 
34 #include "am.h"
35 
36 #ifndef SIGINT
37 #include <signal.h>
38 #endif
39 
40 #ifdef OS_HAS_NDBM
41 #define HAS_DATABASE
42 #include <ndbm.h>
43 
44 #ifdef DBM_SUFFIX
45 #define USING_DB
46 #endif
47 
48 #define create_database(name) dbm_open(name, O_RDWR|O_CREAT, 0644)
49 
50 static int store_data(db, k, v)
51 voidp db;
52 char *k, *v;
53 {
54 	datum key, val;
55 
56 	key.dptr = k; val.dptr = v;
57 	key.dsize = strlen(k) + 1;
58 	val.dsize = strlen(v) + 1;
59 	return dbm_store((DBM *) db, key, val, DBM_INSERT);
60 }
61 
62 #endif /* OS_HAS_NDBM */
63 
64 #ifdef HAS_DATABASE
65 #include <fcntl.h>
66 #include <ctype.h>
67 
68 static int read_line(buf, size, fp)
69 char *buf;
70 int size;
71 FILE *fp;
72 {
73 	int done = 0;
74 
75 	do {
76 		while (fgets(buf, size, fp)) {
77 			int len = strlen(buf);
78 			done += len;
79 			if (len > 1 && buf[len-2] == '\\' &&
80 					buf[len-1] == '\n') {
81 				int ch;
82 				buf += len - 2;
83 				size -= len - 2;
84 				*buf = '\n'; buf[1] = '\0';
85 				/*
86 				 * Skip leading white space on next line
87 				 */
88 				while ((ch = getc(fp)) != EOF &&
89 					isascii(ch) && isspace(ch))
90 						;
91 				(void) ungetc(ch, fp);
92 			} else {
93 				return done;
94 			}
95 		}
96 	} while (size > 0 && !feof(fp));
97 
98 	return done;
99 }
100 
101 /*
102  * Read through a map
103  */
104 static int read_file(fp, map, db)
105 FILE *fp;
106 char *map;
107 voidp db;
108 {
109 	char key_val[2048];
110 	int chuck = 0;
111 	int line_no = 0;
112 	int errs = 0;
113 
114 	while (read_line(key_val, sizeof(key_val), fp)) {
115 		char *kp;
116 		char *cp;
117 		char *hash;
118 		int len = strlen(key_val);
119 		line_no++;
120 
121 		/*
122 		 * Make sure we got the whole line
123 		 */
124 		if (key_val[len-1] != '\n') {
125 			fprintf(stderr, "line %d in \"%s\" is too long", line_no, map);
126 			chuck = 1;
127 		} else {
128 			key_val[len-1] = '\0';
129 		}
130 
131 		/*
132 		 * Strip comments
133 		 */
134 		hash = strchr(key_val, '#');
135 		if (hash)
136 			*hash = '\0';
137 
138 		/*
139 		 * Find start of key
140 		 */
141 		for (kp = key_val; *kp && isascii(*kp) && isspace(*kp); kp++)
142 			;
143 
144 		/*
145 		 * Ignore blank lines
146 		 */
147 		if (!*kp)
148 			goto again;
149 
150 		/*
151 		 * Find end of key
152 		 */
153 		for (cp = kp; *cp&&(!isascii(*cp)||!isspace(*cp)); cp++)
154 			;
155 
156 		/*
157 		 * Check whether key matches, or whether
158 		 * the entry is a wildcard entry.
159 		 */
160 		if (*cp)
161 			*cp++ = '\0';
162 		while (*cp && isascii(*cp) && isspace(*cp))
163 			cp++;
164 		if (*kp == '+') {
165 			fprintf(stderr, "Can't interpolate %s\n", kp);
166 			errs++;
167 		} else if (*cp) {
168 			if (db) {
169 				if (store_data(db, kp, cp) < 0) {
170 					fprintf(stderr, "Could store %s -> %s\n", kp, cp);
171 					errs++;
172 				}
173 			} else {
174 				printf("%s\t%s\n", kp, cp);
175 			}
176 		} else {
177 			fprintf(stderr, "%s: line %d has no value field", map, line_no);
178 			errs++;
179 		}
180 
181 again:
182 		/*
183 		 * If the last read didn't get a whole line then
184 		 * throw away the remainder before continuing...
185 		 */
186 		if (chuck) {
187 			while (fgets(key_val, sizeof(key_val), fp) &&
188 				!strchr(key_val, '\n'))
189 					;
190 			chuck = 0;
191 		}
192 	}
193 	return errs;
194 }
195 
196 static int remove_file(f)
197 char *f;
198 {
199 	if (unlink(f) < 0 && errno != ENOENT)
200 		return -1;
201 	return 0;
202 }
203 
204 main(argc, argv)
205 int argc;
206 char *argv[];
207 {
208 	FILE *mapf;
209 	char *map;
210 	int rc = 0;
211 	DBM *mapd;
212 	static char maptmp[] = "dbmXXXXXX";
213 	char maptpag[16];
214 	char *mappag;
215 #ifndef USING_DB
216 	char maptdir[16];
217 	char *mapdir;
218 #endif
219 	int len;
220 	char *sl;
221 	int printit = 0;
222 	int usage = 0;
223 	int ch;
224 	extern int optind;
225 
226 	while ((ch = getopt(argc, argv, "p")) != EOF)
227 	switch (ch) {
228 	case 'p':
229 		printit = 1;
230 		break;
231 	default:
232 		usage++;
233 		break;
234 	}
235 
236 	if (usage || optind != (argc - 1)) {
237 		fputs("Usage: mk-amd-map [-p] file-map\n", stderr);
238 		exit(1);
239 	}
240 
241 	map = argv[optind];
242 	sl = strrchr(map, '/');
243 	if (sl) {
244 		*sl = '\0';
245 		if (chdir(map) < 0) {
246 			fputs("Can't chdir to ", stderr);
247 			perror(map);
248 			exit(1);
249 		}
250 		map = sl + 1;
251 	}
252 
253 	if (!printit) {
254 		len = strlen(map);
255 #ifdef USING_DB
256 		mappag = (char *) malloc(len + 5);
257 		if (!mappag) {
258 			perror("mk-amd-map: malloc");
259 			exit(1);
260 		}
261 		mktemp(maptmp);
262 		sprintf(maptpag, "%s%s", maptmp, DBM_SUFFIX);
263 		if (remove_file(maptpag) < 0) {
264 			fprintf(stderr, "Can't remove existing temporary file");
265 			perror(maptpag);
266 			exit(1);
267 		}
268 #else
269 		mappag = (char *) malloc(len + 5);
270 		mapdir = (char *) malloc(len + 5);
271 		if (!mappag || !mapdir) {
272 			perror("mk-amd-map: malloc");
273 			exit(1);
274 		}
275 		mktemp(maptmp);
276 		sprintf(maptpag, "%s.pag", maptmp);
277 		sprintf(maptdir, "%s.dir", maptmp);
278 		if (remove_file(maptpag) < 0 || remove_file(maptdir) < 0) {
279 			fprintf(stderr, "Can't remove existing temporary files; %s and", maptpag);
280 			perror(maptdir);
281 			exit(1);
282 		}
283 #endif
284 	}
285 
286 	mapf =  fopen(map, "r");
287 	if (mapf && !printit)
288 		mapd = create_database(maptmp);
289 	else
290 		mapd = 0;
291 
292 #ifndef DEBUG
293 	signal(SIGINT, SIG_IGN);
294 #endif
295 
296 	if (mapd || printit) {
297 		int error = read_file(mapf, map, mapd);
298 		if (mapd)
299 			dbm_close(mapd);
300 		(void) fclose(mapf);
301 		if (printit) {
302 			if (error) {
303 				fprintf(stderr, "Error creating ndbm map for %s\n", map);
304 				rc = 1;
305 			}
306 		} else {
307 			if (error) {
308 				fprintf(stderr, "Error reading source file  %s\n", map);
309 				rc = 1;
310 			} else {
311 #ifdef USING_DB
312 				sprintf(mappag, "%s%s", map, DBM_SUFFIX);
313 				if (rename(maptpag, mappag) < 0) {
314 					fprintf(stderr, "Couldn't rename %s to ", maptpag);
315 					perror(mappag);
316 					/* Throw away the temporary map */
317 					unlink(maptpag);
318 					rc = 1;
319 				}
320 #else
321 				sprintf(mappag, "%s.pag", map);
322 				sprintf(mapdir, "%s.dir", map);
323 				if (rename(maptpag, mappag) < 0) {
324 					fprintf(stderr, "Couldn't rename %s to ", maptpag);
325 					perror(mappag);
326 					/* Throw away the temporary map */
327 					unlink(maptpag);
328 					unlink(maptdir);
329 					rc = 1;
330 				} else if (rename(maptdir, mapdir) < 0) {
331 					fprintf(stderr, "Couldn't rename %s to ", maptdir);
332 					perror(mapdir);
333 					/* Put the .pag file back */
334 					rename(mappag, maptpag);
335 					/* Throw away remaining part of original map */
336 					unlink(mapdir);
337 					fprintf(stderr,
338 						"WARNING: existing map \"%s.{dir,pag}\" destroyed\n",
339 						map);
340 					rc = 1;
341 				}
342 #endif
343 			}
344 		}
345 	} else {
346 		fprintf(stderr, "Can't open \"%s.{dir,pag}\" for ", map);
347 		perror("writing");
348 		rc = 1;
349 	}
350 	exit(rc);
351 }
352 #else
353 main()
354 {
355 	fputs("mk-amd-map: This system does not support hashed database files\n", stderr);
356 	exit(1);
357 }
358 #endif /* HAS_DATABASE */
359