mk-amd-map.c revision 42633
1/*
2 * Copyright (c) 1997-1998 Erez Zadok
3 * Copyright (c) 1990 Jan-Simon Pendry
4 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
5 * Copyright (c) 1990 The Regents of the University of California.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * Jan-Simon Pendry at Imperial College, London.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 *    must display the following acknowledgment:
21 *      This product includes software developed by the University of
22 *      California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 *    may be used to endorse or promote products derived from this software
25 *    without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
38 *
39 *      %W% (Berkeley) %G%
40 *
41 * $Id: mk-amd-map.c,v 1.5 1998/11/14 03:13:32 obrien Exp $
42 */
43
44/*
45 * Convert a file map into an ndbm map
46 */
47
48#ifdef HAVE_CONFIG_H
49# include <config.h>
50#endif /* HAVE_CONFIG_H */
51#include <am_defs.h>
52
53/* dummy variables */
54#if 0
55char *progname;
56pid_t mypid;
57serv_state amd_state;
58int foreground, orig_umask;
59int debug_flags;
60#endif
61char hostname[MAXHOSTNAMELEN];
62
63/* (libdb version 2) uses .db extensions but an old dbm API */
64/* check for libgdbm to distinguish it from linux systems */
65#if defined(DBM_SUFFIX) && !defined(HAVE_LIBGDBM)
66# define HAVE_DB_SUFFIX
67#endif /* not defined(DBM_SUFFIX) && !defined(HAVE_LIBGDBM) */
68
69#ifdef HAVE_MAP_NDBM
70
71static int
72store_data(voidp db, char *k, char *v)
73{
74  datum key, val;
75
76  key.dptr = k;
77  val.dptr = v;
78  key.dsize = strlen(k) + 1;
79  val.dsize = strlen(v) + 1;
80  return dbm_store((DBM *) db, key, val, DBM_INSERT);
81}
82
83
84/*
85 * Read one line from file.
86 */
87static int
88read_line(char *buf, int size, FILE *fp)
89{
90  int done = 0;
91
92  do {
93    while (fgets(buf, size, fp)) {
94      int len = strlen(buf);
95
96      done += len;
97      if (len > 1 && buf[len - 2] == '\\' && buf[len - 1] == '\n') {
98	int ch;
99	buf += len - 2;
100	size -= len - 2;
101	*buf = '\n';
102	buf[1] = '\0';
103
104	/*
105	 * Skip leading white space on next line
106	 */
107	while ((ch = getc(fp)) != EOF && isascii(ch) && isspace(ch)) ;
108	(void) ungetc(ch, fp);
109      } else {
110	return done;
111      }
112    }
113  } while (size > 0 && !feof(fp));
114
115  return done;
116}
117
118
119/*
120 * Read through a map.
121 */
122static int
123read_file(FILE *fp, char *map, voidp db)
124{
125  char key_val[2048];
126  int chuck = 0;
127  int line_no = 0;
128  int errs = 0;
129
130  while (read_line(key_val, 2048, fp)) {
131    char *kp;
132    char *cp;
133    char *hash;
134    int len = strlen(key_val);
135
136    line_no++;
137
138    /*
139     * Make sure we got the whole line
140     */
141    if (key_val[len - 1] != '\n') {
142      fprintf(stderr, "line %d in \"%s\" is too long", line_no, map);
143      chuck = 1;
144    } else {
145      key_val[len - 1] = '\0';
146    }
147
148    /*
149     * Strip comments
150     */
151    hash = strchr(key_val, '#');
152    if (hash)
153      *hash = '\0';
154
155    /*
156     * Find start of key
157     */
158    for (kp = key_val; *kp && isascii(*kp) && isspace((int)*kp); kp++) ;
159
160    /*
161     * Ignore blank lines
162     */
163    if (!*kp)
164      goto again;
165
166    /*
167     * Find end of key
168     */
169    for (cp = kp; *cp && (!isascii(*cp) || !isspace((int)*cp)); cp++) ;
170
171    /*
172     * Check whether key matches, or whether
173     * the entry is a wildcard entry.
174     */
175    if (*cp)
176      *cp++ = '\0';
177    while (*cp && isascii(*cp) && isspace((int)*cp))
178      cp++;
179    if (*kp == '+') {
180      fprintf(stderr, "Can't interpolate %s\n", kp);
181      errs++;
182    } else if (*cp) {
183      if (db) {
184	if (store_data(db, kp, cp) < 0) {
185	  fprintf(stderr, "Could store %s -> %s\n", kp, cp);
186	  errs++;
187	}
188      } else {
189	printf("%s\t%s\n", kp, cp);
190      }
191    } else {
192      fprintf(stderr, "%s: line %d has no value field", map, line_no);
193      errs++;
194    }
195
196  again:
197    /*
198     * If the last read didn't get a whole line then
199     * throw away the remainder before continuing...
200     */
201    if (chuck) {
202      while (fgets(key_val, sizeof(key_val), fp) &&
203	     !strchr(key_val, '\n')) ;
204      chuck = 0;
205    }
206  }
207  return errs;
208}
209
210
211static int
212remove_file(char *f)
213{
214  if (unlink(f) < 0 && errno != ENOENT)
215    return -1;
216
217  return 0;
218}
219
220
221int
222main(int argc, char *argv[])
223{
224  FILE *mapf;			/* the input file to read from */
225  int error;
226  char *mapsrc;
227  DBM *db = NULL;
228  static char maptmp[] = "dbmXXXXXX";
229#ifdef HAVE_DB_SUFFIX
230  char maptdb[16];
231  char *map_name_db = (char *) NULL;
232#else /* not HAVE_DB_SUFFIX */
233  char maptpag[16], maptdir[16];
234  char *map_name_pag = (char *) NULL, *map_name_dir = (char *) NULL;
235#endif /* not HAVE_DB_SUFFIX */
236  int len;
237  char *sl;
238  int printit = 0;
239  int usage = 0;
240  int ch;
241  extern int optind;
242
243  /* test options */
244  while ((ch = getopt(argc, argv, "p")) != -1)
245    switch (ch) {
246    case 'p':
247      printit = 1;
248      break;
249    default:
250      usage++;
251      break;
252    }
253
254  if (usage || optind != (argc - 1)) {
255    fputs("Usage: mk-amd-map [-p] file-map\n", stderr);
256    exit(1);
257  }
258  mapsrc = argv[optind];
259
260  /* test if can get to the map directory */
261  sl = strrchr(mapsrc, '/');
262  if (sl) {
263    *sl = '\0';
264    if (chdir(mapsrc) < 0) {
265      fputs("Can't chdir to ", stderr);
266      perror(mapsrc);
267      exit(1);
268    }
269    mapsrc = sl + 1;
270  }
271
272  /* open source file */
273  mapf = fopen(mapsrc, "r");
274  if (!mapf) {
275    fprintf(stderr, "cannot open source file ");
276    perror(mapsrc);
277    exit(1);
278  }
279
280#ifndef DEBUG
281  signal(SIGINT, SIG_IGN);
282#endif /* DEBUG */
283
284  if (!printit) {
285    len = strlen(mapsrc);
286#ifdef HAVE_DB_SUFFIX
287    map_name_db = (char *) malloc(len + 4);
288    error = (map_name_db == NULL);
289#else /* not HAVE_DB_SUFFIX */
290    map_name_pag = (char *) malloc(len + 5);
291    map_name_dir = (char *) malloc(len + 5);
292    error = (map_name_pag == NULL || map_name_dir == NULL);
293#endif /* not HAVE_DB_SUFFIX */
294    if (error) {
295      perror("mk-amd-map: malloc");
296      exit(1);
297    }
298
299    mktemp(maptmp);
300
301    /* remove existing temps (if any) */
302#ifdef HAVE_DB_SUFFIX
303    sprintf(maptdb, "%s.db", maptmp);
304    if (remove_file(maptdb) < 0) {
305      fprintf(stderr, "Can't remove existing temporary file; ");
306      perror(maptdb);
307      exit(1);
308    }
309#else /* not HAVE_DB_SUFFIX */
310    sprintf(maptpag, "%s.pag", maptmp);
311    sprintf(maptdir, "%s.dir", maptmp);
312    if (remove_file(maptpag) < 0 || remove_file(maptdir) < 0) {
313      fprintf(stderr, "Can't remove existing temporary files; %s and ", maptpag);
314      perror(maptdir);
315      exit(1);
316    }
317#endif /* not HAVE_DB_SUFFIX */
318
319    db = dbm_open(maptmp, O_RDWR|O_CREAT, 0444);
320    if (!db) {
321      fprintf(stderr, "cannot initialize temporary database: %s", maptmp);
322      exit(1);
323    }
324  }
325
326  /* print db to stdout or to temp database */
327  error = read_file(mapf, mapsrc, db);
328  fclose(mapf);
329  if (error) {
330    if (printit)
331      fprintf(stderr, "Error reading source file  %s\n", mapsrc);
332    else
333      fprintf(stderr, "Error creating database map for %s\n", mapsrc);
334    exit(1);
335  }
336
337  if (printit)
338    exit(0);			/* nothing more to do */
339
340  /* if gets here, we wrote to a database */
341
342  dbm_close(db);
343  /* all went well */
344
345#ifdef HAVE_DB_SUFFIX
346  sprintf(map_name_db, "%s.db", mapsrc);
347  if (rename(maptdb, map_name_db) < 0) {
348    fprintf(stderr, "Couldn't rename %s to ", maptdb);
349    perror(map_name_db);
350    /* Throw away the temporary map */
351    unlink(maptdb);
352    exit(1);
353  }
354#else /* not HAVE_DB_SUFFIX */
355  sprintf(map_name_pag, "%s.pag", mapsrc);
356  sprintf(map_name_dir, "%s.dir", mapsrc);
357  if (rename(maptpag, map_name_pag) < 0) {
358    fprintf(stderr, "Couldn't rename %s to ", maptpag);
359    perror(map_name_pag);
360    /* Throw away the temporary map */
361    unlink(maptpag);
362    unlink(maptdir);
363    exit(1);
364  }
365  if (rename(maptdir, map_name_dir) < 0) {
366    fprintf(stderr, "Couldn't rename %s to ", maptdir);
367    perror(map_name_dir);
368    /* remove the (presumably bad) .pag file */
369    unlink(map_name_pag);
370    /* throw away remaining part of original map */
371    unlink(map_name_dir);
372    /* throw away the temporary map */
373    unlink(maptdir);
374    fprintf(stderr, "WARNING: existing map \"%s.{dir,pag}\" destroyed\n",
375	    mapsrc);
376    exit(1);
377  }
378#endif /* not HAVE_DB_SUFFIX */
379
380  exit(0);
381}
382
383#else /* not HAVE_MAP_NDBM */
384
385int
386main()
387{
388  fputs("mk-amd-map: This system does not support hashed database files\n", stderr);
389  exit(1);
390}
391
392#endif /* not HAVE_MAP_NDBM */
393