]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/amd/mk-amd-map/mk-amd-map.c
MFC r308493, r308619: Update amd from am-utils 6.1.5 to 6.2.
[FreeBSD/stable/10.git] / contrib / amd / mk-amd-map / mk-amd-map.c
1 /*
2  * Copyright (c) 1997-2014 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. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  *
35  *
36  * File: am-utils/mk-amd-map/mk-amd-map.c
37  */
38
39 /*
40  * Convert a file map into an ndbm map
41  */
42
43 #ifdef HAVE_CONFIG_H
44 # include <config.h>
45 #endif /* HAVE_CONFIG_H */
46 #include <am_defs.h>
47
48 /* (libdb version 2) uses .db extensions but an old dbm API */
49 /* check for libgdbm to distinguish it from linux systems */
50 #if defined(DBM_SUFFIX) && !defined(HAVE_LIBGDBM)
51 # define HAVE_DB_SUFFIX
52 #endif /* not defined(DBM_SUFFIX) && !defined(HAVE_LIBGDBM) */
53
54 #ifdef HAVE_MAP_NDBM
55
56 static int
57 store_data(voidp db, char *k, char *v)
58 {
59   datum key, val;
60
61   key.dptr = k;
62   val.dptr = v;
63   key.dsize = strlen(k) + 1;
64   val.dsize = strlen(v) + 1;
65   return dbm_store((DBM *) db, key, val, DBM_INSERT);
66 }
67
68
69 /*
70  * Read one line from file.
71  */
72 static int
73 read_line(char *buf, int size, FILE *fp)
74 {
75   int done = 0;
76
77   do {
78     while (fgets(buf, size, fp)) {
79       int len = strlen(buf);
80
81       done += len;
82       if (len > 1 && buf[len - 2] == '\\' && buf[len - 1] == '\n') {
83         int ch;
84         buf += len - 2;
85         size -= len - 2;
86         *buf = '\n';
87         buf[1] = '\0';
88
89         /*
90          * Skip leading white space on next line
91          */
92         while ((ch = getc(fp)) != EOF && isascii((unsigned char)ch) && isspace((unsigned char)ch)) ;
93         (void) ungetc(ch, fp);
94       } else {
95         return done;
96       }
97     }
98   } while (size > 0 && !feof(fp));
99
100   return done;
101 }
102
103
104 /*
105  * Read through a map.
106  */
107 static int
108 read_file(FILE *fp, char *map, voidp db)
109 {
110   char key_val[2048];
111   int chuck = 0;
112   int line_no = 0;
113   int errs = 0;
114
115   while (read_line(key_val, 2048, fp)) {
116     char *kp;
117     char *cp;
118     char *hash;
119     int len = strlen(key_val);
120
121     line_no++;
122
123     /*
124      * Make sure we got the whole line
125      */
126     if (key_val[len - 1] != '\n') {
127       fprintf(stderr, "line %d in \"%s\" is too long", line_no, map);
128       chuck = 1;
129     } else {
130       key_val[len - 1] = '\0';
131     }
132
133     /*
134      * Strip comments
135      */
136     hash = strchr(key_val, '#');
137     if (hash)
138       *hash = '\0';
139
140     /*
141      * Find start of key
142      */
143     for (kp = key_val; *kp && isascii((unsigned char)*kp) && isspace((unsigned char)*kp); kp++) ;
144
145     /*
146      * Ignore blank lines
147      */
148     if (!*kp)
149       goto again;
150
151     /*
152      * Find end of key
153      */
154     for (cp = kp; *cp && (!isascii((unsigned char)*cp) || !isspace((unsigned char)*cp)); cp++) ;
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((unsigned char)*cp) && isspace((unsigned char)*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       chuck = 0;
190     }
191   }
192   return errs;
193 }
194
195
196 static int
197 remove_file(char *f)
198 {
199   if (unlink(f) < 0 && errno != ENOENT)
200     return -1;
201
202   return 0;
203 }
204
205
206 int
207 main(int argc, char *argv[])
208 {
209   FILE *mapf;                   /* the input file to read from */
210   int error;
211   char *mapsrc;
212   DBM *db = NULL;
213   static char maptmp[] = "dbmXXXXXX";
214 #ifdef HAVE_DB_SUFFIX
215   char maptdb[16];
216   char *map_name_db = (char *) NULL;
217 #else /* not HAVE_DB_SUFFIX */
218   char maptpag[16], maptdir[16];
219   char *map_name_pag = (char *) NULL, *map_name_dir = (char *) NULL;
220 #endif /* not HAVE_DB_SUFFIX */
221   size_t l = 0;
222   char *sl;
223   int printit = 0;
224   int usage = 0;
225   int ch;
226   extern int optind;
227
228   /* test options */
229   while ((ch = getopt(argc, argv, "p")) != -1)
230     switch (ch) {
231     case 'p':
232       printit = 1;
233       break;
234     default:
235       usage++;
236       break;
237     }
238
239   if (usage || optind != (argc - 1)) {
240     fputs("Usage: mk-amd-map [-p] file-map\n", stderr);
241     exit(1);
242   }
243   mapsrc = argv[optind];
244
245   /* test if can get to the map directory */
246   sl = strrchr(mapsrc, '/');
247   if (sl) {
248     *sl = '\0';
249     if (chdir(mapsrc) < 0) {
250       fputs("Can't chdir to ", stderr);
251       perror(mapsrc);
252       exit(1);
253     }
254     mapsrc = sl + 1;
255   }
256
257   /* open source file */
258   mapf = fopen(mapsrc, "r");
259   if (!mapf) {
260     fprintf(stderr, "cannot open source file ");
261     perror(mapsrc);
262     exit(1);
263   }
264
265 #ifndef DEBUG
266   signal(SIGINT, SIG_IGN);
267 #endif /* DEBUG */
268
269   if (!printit) {
270     /* enough space for ".db" or ".pag" or ".dir" appended */
271     l = strlen(mapsrc) + 5;
272 #ifdef HAVE_DB_SUFFIX
273     map_name_db = (char *) malloc(l);
274     error = (map_name_db == NULL);
275 #else /* not HAVE_DB_SUFFIX */
276     map_name_pag = (char *) malloc(l);
277     map_name_dir = (char *) malloc(l);
278     error = (map_name_pag == NULL || map_name_dir == NULL);
279 #endif /* not HAVE_DB_SUFFIX */
280     if (error) {
281       perror("mk-amd-map: malloc");
282       exit(1);
283     }
284
285 #ifdef HAVE_MKSTEMP
286     {
287       /*
288        * XXX: hack to avoid compiler complaints about mktemp not being
289        * secure, since we have to do a dbm_open on this anyway.  So use
290        * mkstemp if you can, and then close the fd, but we get a safe
291        * and unique file name.
292        */
293       int dummyfd;
294       dummyfd = mkstemp(maptmp);
295       if (dummyfd >= 0)
296         close(dummyfd);
297     }
298 #else /* not HAVE_MKSTEMP */
299     mktemp(maptmp);
300 #endif /* not HAVE_MKSTEMP */
301
302     /* remove existing temps (if any) */
303 #ifdef HAVE_DB_SUFFIX
304     xsnprintf(maptdb, sizeof(maptdb), "%s.db", maptmp);
305     if (remove_file(maptdb) < 0) {
306       fprintf(stderr, "Can't remove existing temporary file; ");
307       perror(maptdb);
308       exit(1);
309     }
310 #else /* not HAVE_DB_SUFFIX */
311     xsnprintf(maptpag, sizeof(maptpag), "%s.pag", maptmp);
312     xsnprintf(maptdir, sizeof(maptdir), "%s.dir", maptmp);
313     if (remove_file(maptpag) < 0 || remove_file(maptdir) < 0) {
314       fprintf(stderr, "Can't remove existing temporary files; %s and ", maptpag);
315       perror(maptdir);
316       exit(1);
317     }
318 #endif /* not HAVE_DB_SUFFIX */
319
320     db = dbm_open(maptmp, O_RDWR|O_CREAT|O_EXCL, 0444);
321     if (!db) {
322       fprintf(stderr, "cannot initialize temporary database: %s", maptmp);
323       exit(1);
324     }
325   }
326
327   /* print db to stdout or to temp database */
328   error = read_file(mapf, mapsrc, db);
329   fclose(mapf);
330   if (error) {
331     if (printit)
332       fprintf(stderr, "Error reading source file  %s\n", mapsrc);
333     else
334       fprintf(stderr, "Error creating database map for %s\n", mapsrc);
335     exit(1);
336   }
337
338   if (printit)
339     exit(0);                    /* nothing more to do */
340
341   /* if gets here, we wrote to a database */
342
343   dbm_close(db);
344   /* all went well */
345
346 #ifdef HAVE_DB_SUFFIX
347   /* sizeof(map_name_db) is malloc'ed above */
348   xsnprintf(map_name_db, l, "%s.db", mapsrc);
349   if (rename(maptdb, map_name_db) < 0) {
350     fprintf(stderr, "Couldn't rename %s to ", maptdb);
351     perror(map_name_db);
352     /* Throw away the temporary map */
353     unlink(maptdb);
354     exit(1);
355   }
356 #else /* not HAVE_DB_SUFFIX */
357   /* sizeof(map_name_{pag,dir}) are malloc'ed above */
358   xsnprintf(map_name_pag, l, "%s.pag", mapsrc);
359   xsnprintf(map_name_dir, l, "%s.dir", mapsrc);
360   if (rename(maptpag, map_name_pag) < 0) {
361     fprintf(stderr, "Couldn't rename %s to ", maptpag);
362     perror(map_name_pag);
363     /* Throw away the temporary map */
364     unlink(maptpag);
365     unlink(maptdir);
366     exit(1);
367   }
368   if (rename(maptdir, map_name_dir) < 0) {
369     fprintf(stderr, "Couldn't rename %s to ", maptdir);
370     perror(map_name_dir);
371     /* remove the (presumably bad) .pag file */
372     unlink(map_name_pag);
373     /* throw away remaining part of original map */
374     unlink(map_name_dir);
375     /* throw away the temporary map */
376     unlink(maptdir);
377     fprintf(stderr, "WARNING: existing map \"%s.{dir,pag}\" destroyed\n",
378             mapsrc);
379     exit(1);
380   }
381 #endif /* not HAVE_DB_SUFFIX */
382
383   exit(0);
384 }
385
386 #else /* not HAVE_MAP_NDBM */
387
388 int
389 main()
390 {
391   fputs("mk-amd-map: This system does not support hashed database files\n", stderr);
392   exit(1);
393 }
394
395 #endif /* not HAVE_MAP_NDBM */