144926Smckusick /*
244926Smckusick  * Copyright (c) 1990 Jan-Simon Pendry
344926Smckusick  * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
444926Smckusick  * Copyright (c) 1990 The Regents of the University of California.
544926Smckusick  * All rights reserved.
644926Smckusick  *
744926Smckusick  * This code is derived from software contributed to Berkeley by
844926Smckusick  * Jan-Simon Pendry at Imperial College, London.
944926Smckusick  *
1044926Smckusick  * %sccs.include.redist.c%
1144926Smckusick  *
12*49687Spendry  *	@(#)mk-amd-map.c	5.4 (Berkeley) 05/12/91
13*49687Spendry  *
14*49687Spendry  * $Id: mk-amd-map.c,v 5.2.1.4 91/05/07 22:18:47 jsp Alpha $
1544926Smckusick  */
1644926Smckusick 
1744926Smckusick /*
1844926Smckusick  * Convert a file map into an ndbm map
1944926Smckusick  */
2044926Smckusick 
2144926Smckusick #ifndef lint
2244926Smckusick char copyright[] = "\
2344926Smckusick @(#)Copyright (c) 1990 Jan-Simon Pendry\n\
2444926Smckusick @(#)Copyright (c) 1990 Imperial College of Science, Technology & Medicine\n\
2544926Smckusick @(#)Copyright (c) 1990 The Regents of the University of California.\n\
2644926Smckusick @(#)All rights reserved.\n";
2744926Smckusick #endif /* not lint */
2844926Smckusick 
2944926Smckusick #ifndef lint
30*49687Spendry static char rcsid[] = "$Id: mk-amd-map.c,v 5.2.1.4 91/05/07 22:18:47 jsp Alpha $";
31*49687Spendry static char sccsid[] = "@(#)mk-amd-map.c	5.4 (Berkeley) 05/12/91";
3244926Smckusick #endif /* not lint */
3344926Smckusick 
3444926Smckusick #include "am.h"
3544926Smckusick 
3647533Spendry #ifndef SIGINT
3747533Spendry #include <signal.h>
3847533Spendry #endif
3944926Smckusick 
4044926Smckusick #ifdef OS_HAS_NDBM
4144926Smckusick #define HAS_DATABASE
4244926Smckusick #include <ndbm.h>
4344926Smckusick 
4444926Smckusick #define create_database(name) dbm_open(name, O_RDWR|O_CREAT, 0444)
4544926Smckusick 
4644926Smckusick static int store_data(db, k, v)
4744926Smckusick voidp db;
4844926Smckusick char *k, *v;
4944926Smckusick {
5044926Smckusick 	datum key, val;
5144926Smckusick 
5244926Smckusick 	key.dptr = k; val.dptr = v;
5344926Smckusick 	key.dsize = strlen(k) + 1;
5444926Smckusick 	val.dsize = strlen(v) + 1;
5544926Smckusick 	return dbm_store((DBM *) db, key, val, DBM_INSERT);
5644926Smckusick }
5744926Smckusick 
5844926Smckusick #endif /* OS_HAS_NDBM */
5944926Smckusick 
6044926Smckusick #ifdef HAS_DATABASE
6144926Smckusick #include <fcntl.h>
6244926Smckusick #include <ctype.h>
6344926Smckusick 
6444926Smckusick static int read_line(buf, size, fp)
6544926Smckusick char *buf;
6644926Smckusick int size;
6744926Smckusick FILE *fp;
6844926Smckusick {
6944926Smckusick 	int done = 0;
7044926Smckusick 
7144926Smckusick 	do {
7244926Smckusick 		while (fgets(buf, size, fp)) {
7344926Smckusick 			int len = strlen(buf);
7444926Smckusick 			done += len;
7544926Smckusick 			if (len > 1 && buf[len-2] == '\\' &&
7644926Smckusick 					buf[len-1] == '\n') {
7744926Smckusick 				int ch;
7844926Smckusick 				buf += len - 2;
7944926Smckusick 				size -= len - 2;
80*49687Spendry 				*buf = '\n'; buf[1] = '\0';
8144926Smckusick 				/*
8244926Smckusick 				 * Skip leading white space on next line
8344926Smckusick 				 */
8444926Smckusick 				while ((ch = getc(fp)) != EOF &&
8544926Smckusick 					isascii(ch) && isspace(ch))
8644926Smckusick 						;
8744926Smckusick 				(void) ungetc(ch, fp);
8844926Smckusick 			} else {
8944926Smckusick 				return done;
9044926Smckusick 			}
9144926Smckusick 		}
9244926Smckusick 	} while (size > 0 && !feof(fp));
9344926Smckusick 
9444926Smckusick 	return done;
9544926Smckusick }
9644926Smckusick 
9744926Smckusick /*
9844926Smckusick  * Read through a map
9944926Smckusick  */
10044926Smckusick static int read_file(fp, map, db)
10144926Smckusick FILE *fp;
10244926Smckusick char *map;
10344926Smckusick voidp db;
10444926Smckusick {
10544926Smckusick 	char key_val[2048];
10644926Smckusick 	int chuck = 0;
10744926Smckusick 	int line_no = 0;
10844926Smckusick 	int errs = 0;
10944926Smckusick 
11044926Smckusick 	while (read_line(key_val, sizeof(key_val), fp)) {
11144926Smckusick 		char *kp;
11244926Smckusick 		char *cp;
11344926Smckusick 		char *hash;
11444926Smckusick 		int len = strlen(key_val);
11544926Smckusick 		line_no++;
11644926Smckusick 
11744926Smckusick 		/*
11844926Smckusick 		 * Make sure we got the whole line
11944926Smckusick 		 */
12044926Smckusick 		if (key_val[len-1] != '\n') {
12144926Smckusick 			fprintf(stderr, "line %d in \"%s\" is too long", line_no, map);
12244926Smckusick 			chuck = 1;
12344926Smckusick 		} else {
12444926Smckusick 			key_val[len-1] = '\0';
12544926Smckusick 		}
12644926Smckusick 
12744926Smckusick 		/*
12844926Smckusick 		 * Strip comments
12944926Smckusick 		 */
13044926Smckusick 		hash = strchr(key_val, '#');
13144926Smckusick 		if (hash)
13244926Smckusick 			*hash = '\0';
13344926Smckusick 
13444926Smckusick 		/*
13544926Smckusick 		 * Find start of key
13644926Smckusick 		 */
13744926Smckusick 		for (kp = key_val; *kp && isascii(*kp) && isspace(*kp); kp++)
13844926Smckusick 			;
13944926Smckusick 
14044926Smckusick 		/*
14144926Smckusick 		 * Ignore blank lines
14244926Smckusick 		 */
14344926Smckusick 		if (!*kp)
14444926Smckusick 			goto again;
14544926Smckusick 
14644926Smckusick 		/*
14744926Smckusick 		 * Find end of key
14844926Smckusick 		 */
14944926Smckusick 		for (cp = kp; *cp&&(!isascii(*cp)||!isspace(*cp)); cp++)
15044926Smckusick 			;
15144926Smckusick 
15244926Smckusick 		/*
15344926Smckusick 		 * Check whether key matches, or whether
15444926Smckusick 		 * the entry is a wildcard entry.
15544926Smckusick 		 */
15644926Smckusick 		if (*cp)
15744926Smckusick 			*cp++ = '\0';
15844926Smckusick 		while (*cp && isascii(*cp) && isspace(*cp))
15944926Smckusick 			cp++;
16044926Smckusick 		if (*kp == '+') {
16144926Smckusick 			fprintf(stderr, "Can't interpolate %s\n", kp);
16244926Smckusick 			errs++;
16344926Smckusick 		} else if (*cp) {
16447533Spendry 			if (db) {
16547533Spendry 				if (store_data(db, kp, cp) < 0) {
16647533Spendry 					fprintf(stderr, "Could store %s -> %s\n", kp, cp);
16747533Spendry 					errs++;
16847533Spendry 				}
16947533Spendry 			} else {
17047533Spendry 				printf("%s\t%s\n", kp, cp);
17144926Smckusick 			}
17244926Smckusick 		} else {
17344926Smckusick 			fprintf(stderr, "%s: line %d has no value field", map, line_no);
17444926Smckusick 			errs++;
17544926Smckusick 		}
17644926Smckusick 
17744926Smckusick again:
17844926Smckusick 		/*
17944926Smckusick 		 * If the last read didn't get a whole line then
18044926Smckusick 		 * throw away the remainder before continuing...
18144926Smckusick 		 */
18244926Smckusick 		if (chuck) {
18344926Smckusick 			while (fgets(key_val, sizeof(key_val), fp) &&
18444926Smckusick 				!strchr(key_val, '\n'))
18544926Smckusick 					;
18644926Smckusick 			chuck = 0;
18744926Smckusick 		}
18844926Smckusick 	}
18944926Smckusick 	return errs;
19044926Smckusick }
19144926Smckusick 
19247533Spendry static int remove_file(f)
19344926Smckusick char *f;
19444926Smckusick {
19544926Smckusick 	if (unlink(f) < 0 && errno != ENOENT)
19644926Smckusick 		return -1;
19744926Smckusick 	return 0;
19844926Smckusick }
19944926Smckusick 
20044926Smckusick main(argc, argv)
20144926Smckusick int argc;
20244926Smckusick char *argv[];
20344926Smckusick {
20444926Smckusick 	FILE *mapf;
20544926Smckusick 	char *map;
20644926Smckusick 	int rc = 0;
20744926Smckusick 	DBM *mapd;
208*49687Spendry 	static char maptmp[] = "dbmXXXXXX";
20944926Smckusick 	char maptpag[16], maptdir[16];
21044926Smckusick 	char *mappag, *mapdir;
21144926Smckusick 	int len;
21244926Smckusick 	char *sl;
21347533Spendry 	int printit = 0;
21447533Spendry 	int usage = 0;
21547533Spendry 	int ch;
21647533Spendry 	extern int optind;
21744926Smckusick 
21847533Spendry 	while ((ch = getopt(argc, argv, "p")) != EOF)
21947533Spendry 	switch (ch) {
22047533Spendry 	case 'p':
22147533Spendry 		printit = 1;
22247533Spendry 		break;
22347533Spendry 	default:
22447533Spendry 		usage++;
22547533Spendry 		break;
22647533Spendry 	}
22747533Spendry 
22847533Spendry 	if (usage || optind != (argc - 1)) {
22947533Spendry 		fputs("Usage: mk-amd-map [-p] file-map\n", stderr);
23044926Smckusick 		exit(1);
23144926Smckusick 	}
23244926Smckusick 
23347533Spendry 	map = argv[optind];
23444926Smckusick 	sl = strrchr(map, '/');
23544926Smckusick 	if (sl) {
23644926Smckusick 		*sl = '\0';
23744926Smckusick 		if (chdir(map) < 0) {
23844926Smckusick 			fputs("Can't chdir to ", stderr);
23944926Smckusick 			perror(map);
24044926Smckusick 			exit(1);
24144926Smckusick 		}
24244926Smckusick 		map = sl + 1;
24344926Smckusick 	}
24447533Spendry 
24547533Spendry 	if (!printit) {
24647533Spendry 		len = strlen(map);
24747533Spendry 		mappag = (char *) malloc(len + 5);
24847533Spendry 		mapdir = (char *) malloc(len + 5);
24947533Spendry 		if (!mappag || !mapdir) {
25047533Spendry 			perror("mk-amd-map: malloc");
25147533Spendry 			exit(1);
25247533Spendry 		}
25347533Spendry 		mktemp(maptmp);
25447533Spendry 		sprintf(maptpag, "%s.pag", maptmp);
25547533Spendry 		sprintf(maptdir, "%s.dir", maptmp);
25647533Spendry 		if (remove_file(maptpag) < 0 || remove_file(maptdir) < 0) {
25747533Spendry 			fprintf(stderr, "Can't remove existing temporary files; %s and", maptpag);
25847533Spendry 			perror(maptdir);
25947533Spendry 			exit(1);
26047533Spendry 		}
26144926Smckusick 	}
26247533Spendry 
26344926Smckusick 	mapf =  fopen(map, "r");
26447533Spendry 	if (mapf && !printit)
26544926Smckusick 		mapd = create_database(maptmp);
26644926Smckusick 	else
26744926Smckusick 		mapd = 0;
26847533Spendry 
26944926Smckusick #ifndef DEBUG
27044926Smckusick 	signal(SIGINT, SIG_IGN);
27147533Spendry #endif
27247533Spendry 
27347533Spendry 	if (mapd || printit) {
27444926Smckusick 		int error = read_file(mapf, map, mapd);
27544926Smckusick 		(void) fclose(mapf);
27647533Spendry 		if (printit) {
27747533Spendry 			if (error) {
27847533Spendry 				fprintf(stderr, "Error creating ndbm map for %s\n", map);
27947533Spendry 				rc = 1;
28047533Spendry 			}
28147533Spendry 		} else {
28247533Spendry 			if (error) {
28347533Spendry 				fprintf(stderr, "Error reading source file  %s\n", map);
28447533Spendry 				rc = 1;
28547533Spendry 			} else {
28647533Spendry 				sprintf(mappag, "%s.pag", map);
28747533Spendry 				sprintf(mapdir, "%s.dir", map);
28847533Spendry 				if (rename(maptpag, mappag) < 0) {
28947533Spendry 					fprintf(stderr, "Couldn't rename %s to ", maptpag);
29047533Spendry 					perror(mappag);
29147533Spendry 					/* Throw away the temporary map */
29247533Spendry 					unlink(maptpag);
29347533Spendry 					unlink(maptdir);
29447533Spendry 					rc = 1;
29547533Spendry 				} else if (rename(maptdir, mapdir) < 0) {
29647533Spendry 					fprintf(stderr, "Couldn't rename %s to ", maptdir);
29747533Spendry 					perror(mapdir);
29847533Spendry 					/* Put the .pag file back */
29947533Spendry 					rename(mappag, maptpag);
30047533Spendry 					/* Throw away remaining part of original map */
30147533Spendry 					unlink(mapdir);
30247533Spendry 					fprintf(stderr,
30347533Spendry 						"WARNING: existing map \"%s.{dir,pag}\" destroyed\n",
30447533Spendry 						map);
30547533Spendry 					rc = 1;
30647533Spendry 				}
30747533Spendry 			}
30844926Smckusick 		}
30944926Smckusick 	} else {
31044926Smckusick 		fprintf(stderr, "Can't open \"%s.{dir,pag}\" for ", map);
31144926Smckusick 		perror("writing");
31244926Smckusick 		rc = 1;
31344926Smckusick 	}
31444926Smckusick 	exit(rc);
31544926Smckusick }
31644926Smckusick #else
31744926Smckusick main()
31844926Smckusick {
31947533Spendry 	fputs("mk-amd-map: This system does not support hashed database files\n", stderr);
32047533Spendry 	exit(1);
32144926Smckusick }
32244926Smckusick #endif /* HAS_DATABASE */
323