138494Sobrien/*
2174294Sobrien * Copyright (c) 1997-2006 Erez Zadok
338494Sobrien * Copyright (c) 1990 Jan-Simon Pendry
438494Sobrien * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
538494Sobrien * Copyright (c) 1990 The Regents of the University of California.
638494Sobrien * All rights reserved.
738494Sobrien *
838494Sobrien * This code is derived from software contributed to Berkeley by
938494Sobrien * Jan-Simon Pendry at Imperial College, London.
1038494Sobrien *
1138494Sobrien * Redistribution and use in source and binary forms, with or without
1238494Sobrien * modification, are permitted provided that the following conditions
1338494Sobrien * are met:
1438494Sobrien * 1. Redistributions of source code must retain the above copyright
1538494Sobrien *    notice, this list of conditions and the following disclaimer.
1638494Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1738494Sobrien *    notice, this list of conditions and the following disclaimer in the
1838494Sobrien *    documentation and/or other materials provided with the distribution.
1938494Sobrien * 3. All advertising materials mentioning features or use of this software
2042629Sobrien *    must display the following acknowledgment:
2138494Sobrien *      This product includes software developed by the University of
2238494Sobrien *      California, Berkeley and its contributors.
2338494Sobrien * 4. Neither the name of the University nor the names of its contributors
2438494Sobrien *    may be used to endorse or promote products derived from this software
2538494Sobrien *    without specific prior written permission.
2638494Sobrien *
2738494Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2838494Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2938494Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3038494Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
3138494Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3238494Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3338494Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3438494Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3538494Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3638494Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3738494Sobrien * SUCH DAMAGE.
3838494Sobrien *
3938494Sobrien *
40174294Sobrien * File: am-utils/amd/info_file.c
4138494Sobrien *
4238494Sobrien */
4338494Sobrien
4438494Sobrien/*
4538494Sobrien * Get info from file
4638494Sobrien */
4738494Sobrien
4838494Sobrien#ifdef HAVE_CONFIG_H
4938494Sobrien# include <config.h>
5038494Sobrien#endif /* HAVE_CONFIG_H */
5138494Sobrien#include <am_defs.h>
5238494Sobrien#include <amd.h>
5338494Sobrien
5438494Sobrien#define	MAX_LINE_LEN	1500
5538494Sobrien
5638494Sobrien/* forward declarations */
57174294Sobrienint file_init_or_mtime(mnt_map *m, char *map, time_t *tp);
5838494Sobrienint file_reload(mnt_map *m, char *map, void (*fn) (mnt_map *, char *, char *));
5938494Sobrienint file_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp);
6038494Sobrien
6138494Sobrien
6238494Sobrienstatic int
6382794Sobrienread_line(char *buf, int size, FILE *fp)
6438494Sobrien{
6538494Sobrien  int done = 0;
6638494Sobrien
6738494Sobrien  do {
6838494Sobrien    while (fgets(buf, size, fp)) {
6938494Sobrien      int len = strlen(buf);
7038494Sobrien      done += len;
7138494Sobrien      if (len > 1 && buf[len - 2] == '\\' &&
7238494Sobrien	  buf[len - 1] == '\n') {
7338494Sobrien	int ch;
7438494Sobrien	buf += len - 2;
7538494Sobrien	size -= len - 2;
7638494Sobrien	*buf = '\n';
7738494Sobrien	buf[1] = '\0';
7838494Sobrien	/*
7938494Sobrien	 * Skip leading white space on next line
8038494Sobrien	 */
8138494Sobrien	while ((ch = getc(fp)) != EOF &&
8238494Sobrien	       isascii(ch) && isspace(ch)) ;
8338494Sobrien	(void) ungetc(ch, fp);
8438494Sobrien      } else {
8538494Sobrien	return done;
8638494Sobrien      }
8738494Sobrien    }
88174294Sobrien  } while (size > 0 && !feof(fp) && !ferror(fp));
8938494Sobrien
9038494Sobrien  return done;
9138494Sobrien}
9238494Sobrien
9338494Sobrien
9438494Sobrien/*
9538494Sobrien * Try to locate a key in a file
9638494Sobrien */
9738494Sobrienstatic int
98174294Sobrienfile_search_or_reload(FILE *fp,
99174294Sobrien		      char *map,
100174294Sobrien		      char *key,
101174294Sobrien		      char **val,
102174294Sobrien		      mnt_map *m,
103174294Sobrien		      void (*fn) (mnt_map *m, char *, char *))
10438494Sobrien{
10538494Sobrien  char key_val[MAX_LINE_LEN];
10638494Sobrien  int chuck = 0;
10738494Sobrien  int line_no = 0;
10838494Sobrien
10938494Sobrien  while (read_line(key_val, sizeof(key_val), fp)) {
11038494Sobrien    char *kp;
11138494Sobrien    char *cp;
11238494Sobrien    char *hash;
11338494Sobrien    int len = strlen(key_val);
11438494Sobrien    line_no++;
11538494Sobrien
11638494Sobrien    /*
11738494Sobrien     * Make sure we got the whole line
11838494Sobrien     */
11938494Sobrien    if (key_val[len - 1] != '\n') {
12038494Sobrien      plog(XLOG_WARNING, "line %d in \"%s\" is too long", line_no, map);
12138494Sobrien      chuck = 1;
12238494Sobrien    } else {
12338494Sobrien      key_val[len - 1] = '\0';
12438494Sobrien    }
12538494Sobrien
12638494Sobrien    /*
12738494Sobrien     * Strip comments
12838494Sobrien     */
12938494Sobrien    hash = strchr(key_val, '#');
13038494Sobrien    if (hash)
13138494Sobrien      *hash = '\0';
13238494Sobrien
13338494Sobrien    /*
13438494Sobrien     * Find start of key
13538494Sobrien     */
13638494Sobrien    for (kp = key_val; *kp && isascii(*kp) && isspace((int)*kp); kp++) ;
13738494Sobrien
13838494Sobrien    /*
13938494Sobrien     * Ignore blank lines
14038494Sobrien     */
14138494Sobrien    if (!*kp)
14238494Sobrien      goto again;
14338494Sobrien
14438494Sobrien    /*
14538494Sobrien     * Find end of key
14638494Sobrien     */
14738494Sobrien    for (cp = kp; *cp && (!isascii(*cp) || !isspace((int)*cp)); cp++) ;
14838494Sobrien
14938494Sobrien    /*
15038494Sobrien     * Check whether key matches
15138494Sobrien     */
15238494Sobrien    if (*cp)
15338494Sobrien      *cp++ = '\0';
15438494Sobrien
15538494Sobrien    if (fn || (*key == *kp && STREQ(key, kp))) {
15638494Sobrien      while (*cp && isascii(*cp) && isspace((int)*cp))
15738494Sobrien	cp++;
15838494Sobrien      if (*cp) {
15938494Sobrien	/*
16038494Sobrien	 * Return a copy of the data
16138494Sobrien	 */
16238494Sobrien	char *dc = strdup(cp);
16338494Sobrien	if (fn) {
16438494Sobrien	  (*fn) (m, strdup(kp), dc);
16538494Sobrien	} else {
16638494Sobrien	  *val = dc;
16738494Sobrien	  dlog("%s returns %s", key, dc);
16838494Sobrien	}
16938494Sobrien	if (!fn)
17038494Sobrien	  return 0;
17138494Sobrien      } else {
17238494Sobrien	plog(XLOG_USER, "%s: line %d has no value field", map, line_no);
17338494Sobrien      }
17438494Sobrien    }
17538494Sobrien
17638494Sobrien  again:
17738494Sobrien    /*
17838494Sobrien     * If the last read didn't get a whole line then
17938494Sobrien     * throw away the remainder before continuing...
18038494Sobrien     */
18138494Sobrien    if (chuck) {
18238494Sobrien      while (fgets(key_val, sizeof(key_val), fp) &&
18338494Sobrien	     !strchr(key_val, '\n')) ;
18438494Sobrien      chuck = 0;
18538494Sobrien    }
18638494Sobrien  }
18738494Sobrien
18838494Sobrien  return fn ? 0 : ENOENT;
18938494Sobrien}
19038494Sobrien
19138494Sobrien
19238494Sobrienstatic FILE *
19338494Sobrienfile_open(char *map, time_t *tp)
19438494Sobrien{
19538494Sobrien  FILE *mapf = fopen(map, "r");
19638494Sobrien
19738494Sobrien  if (mapf && tp) {
19838494Sobrien    struct stat stb;
19938494Sobrien    if (fstat(fileno(mapf), &stb) < 0)
200174294Sobrien      *tp = clocktime(NULL);
20138494Sobrien    else
20238494Sobrien      *tp = stb.st_mtime;
20338494Sobrien  }
20438494Sobrien  return mapf;
20538494Sobrien}
20638494Sobrien
20738494Sobrien
20838494Sobrienint
209174294Sobrienfile_init_or_mtime(mnt_map *m, char *map, time_t *tp)
21038494Sobrien{
21138494Sobrien  FILE *mapf = file_open(map, tp);
21238494Sobrien
21338494Sobrien  if (mapf) {
21438494Sobrien    fclose(mapf);
21538494Sobrien    return 0;
21638494Sobrien  }
21738494Sobrien  return errno;
21838494Sobrien}
21938494Sobrien
22038494Sobrien
22138494Sobrienint
22238494Sobrienfile_reload(mnt_map *m, char *map, void (*fn) (mnt_map *, char *, char *))
22338494Sobrien{
22438494Sobrien  FILE *mapf = file_open(map, (time_t *) 0);
22538494Sobrien
22638494Sobrien  if (mapf) {
227174294Sobrien    int error = file_search_or_reload(mapf, map, 0, 0, m, fn);
22838494Sobrien    (void) fclose(mapf);
22938494Sobrien    return error;
23038494Sobrien  }
23138494Sobrien  return errno;
23238494Sobrien}
23338494Sobrien
23438494Sobrien
23538494Sobrienint
23638494Sobrienfile_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp)
23738494Sobrien{
23838494Sobrien  time_t t;
23938494Sobrien  FILE *mapf = file_open(map, &t);
24038494Sobrien
24138494Sobrien  if (mapf) {
24238494Sobrien    int error;
24338494Sobrien    if (*tp < t) {
24438494Sobrien      *tp = t;
24538494Sobrien      error = -1;
24638494Sobrien    } else {
247174294Sobrien      error = file_search_or_reload(mapf, map, key, pval, 0, 0);
24838494Sobrien    }
24938494Sobrien    (void) fclose(mapf);
25038494Sobrien    return error;
25138494Sobrien  }
25238494Sobrien  return errno;
25338494Sobrien}
254