info_file.c revision 174294
1/*
2 * Copyright (c) 1997-2006 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 *
40 * File: am-utils/amd/info_file.c
41 *
42 */
43
44/*
45 * Get info from file
46 */
47
48#ifdef HAVE_CONFIG_H
49# include <config.h>
50#endif /* HAVE_CONFIG_H */
51#include <am_defs.h>
52#include <amd.h>
53
54#define	MAX_LINE_LEN	1500
55
56/* forward declarations */
57int file_init_or_mtime(mnt_map *m, char *map, time_t *tp);
58int file_reload(mnt_map *m, char *map, void (*fn) (mnt_map *, char *, char *));
59int file_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp);
60
61
62static int
63read_line(char *buf, int size, FILE *fp)
64{
65  int done = 0;
66
67  do {
68    while (fgets(buf, size, fp)) {
69      int len = strlen(buf);
70      done += len;
71      if (len > 1 && buf[len - 2] == '\\' &&
72	  buf[len - 1] == '\n') {
73	int ch;
74	buf += len - 2;
75	size -= len - 2;
76	*buf = '\n';
77	buf[1] = '\0';
78	/*
79	 * Skip leading white space on next line
80	 */
81	while ((ch = getc(fp)) != EOF &&
82	       isascii(ch) && isspace(ch)) ;
83	(void) ungetc(ch, fp);
84      } else {
85	return done;
86      }
87    }
88  } while (size > 0 && !feof(fp) && !ferror(fp));
89
90  return done;
91}
92
93
94/*
95 * Try to locate a key in a file
96 */
97static int
98file_search_or_reload(FILE *fp,
99		      char *map,
100		      char *key,
101		      char **val,
102		      mnt_map *m,
103		      void (*fn) (mnt_map *m, char *, char *))
104{
105  char key_val[MAX_LINE_LEN];
106  int chuck = 0;
107  int line_no = 0;
108
109  while (read_line(key_val, sizeof(key_val), fp)) {
110    char *kp;
111    char *cp;
112    char *hash;
113    int len = strlen(key_val);
114    line_no++;
115
116    /*
117     * Make sure we got the whole line
118     */
119    if (key_val[len - 1] != '\n') {
120      plog(XLOG_WARNING, "line %d in \"%s\" is too long", line_no, map);
121      chuck = 1;
122    } else {
123      key_val[len - 1] = '\0';
124    }
125
126    /*
127     * Strip comments
128     */
129    hash = strchr(key_val, '#');
130    if (hash)
131      *hash = '\0';
132
133    /*
134     * Find start of key
135     */
136    for (kp = key_val; *kp && isascii(*kp) && isspace((int)*kp); kp++) ;
137
138    /*
139     * Ignore blank lines
140     */
141    if (!*kp)
142      goto again;
143
144    /*
145     * Find end of key
146     */
147    for (cp = kp; *cp && (!isascii(*cp) || !isspace((int)*cp)); cp++) ;
148
149    /*
150     * Check whether key matches
151     */
152    if (*cp)
153      *cp++ = '\0';
154
155    if (fn || (*key == *kp && STREQ(key, kp))) {
156      while (*cp && isascii(*cp) && isspace((int)*cp))
157	cp++;
158      if (*cp) {
159	/*
160	 * Return a copy of the data
161	 */
162	char *dc = strdup(cp);
163	if (fn) {
164	  (*fn) (m, strdup(kp), dc);
165	} else {
166	  *val = dc;
167	  dlog("%s returns %s", key, dc);
168	}
169	if (!fn)
170	  return 0;
171      } else {
172	plog(XLOG_USER, "%s: line %d has no value field", map, line_no);
173      }
174    }
175
176  again:
177    /*
178     * If the last read didn't get a whole line then
179     * throw away the remainder before continuing...
180     */
181    if (chuck) {
182      while (fgets(key_val, sizeof(key_val), fp) &&
183	     !strchr(key_val, '\n')) ;
184      chuck = 0;
185    }
186  }
187
188  return fn ? 0 : ENOENT;
189}
190
191
192static FILE *
193file_open(char *map, time_t *tp)
194{
195  FILE *mapf = fopen(map, "r");
196
197  if (mapf && tp) {
198    struct stat stb;
199    if (fstat(fileno(mapf), &stb) < 0)
200      *tp = clocktime(NULL);
201    else
202      *tp = stb.st_mtime;
203  }
204  return mapf;
205}
206
207
208int
209file_init_or_mtime(mnt_map *m, char *map, time_t *tp)
210{
211  FILE *mapf = file_open(map, tp);
212
213  if (mapf) {
214    fclose(mapf);
215    return 0;
216  }
217  return errno;
218}
219
220
221int
222file_reload(mnt_map *m, char *map, void (*fn) (mnt_map *, char *, char *))
223{
224  FILE *mapf = file_open(map, (time_t *) 0);
225
226  if (mapf) {
227    int error = file_search_or_reload(mapf, map, 0, 0, m, fn);
228    (void) fclose(mapf);
229    return error;
230  }
231  return errno;
232}
233
234
235int
236file_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp)
237{
238  time_t t;
239  FILE *mapf = file_open(map, &t);
240
241  if (mapf) {
242    int error;
243    if (*tp < t) {
244      *tp = t;
245      error = -1;
246    } else {
247      error = file_search_or_reload(mapf, map, key, pval, 0, 0);
248    }
249    (void) fclose(mapf);
250    return error;
251  }
252  return errno;
253}
254