subst.c revision 45e338f5332a54295893dba2e32cc093d1316f60
144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o/*
244339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o * subst.c --- substitution program
344339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o *
444339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o * Subst is used as a quicky program to do @ substitutions
5efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o *
644339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o */
744339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o
844339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o#include <stdio.h>
944339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o#include <errno.h>
1044339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o#include <stdlib.h>
1144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o#include <unistd.h>
1244339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o#include <string.h>
1344339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o#include <ctype.h>
14dd60705665b916c9f67c3bbf86aa6bb620a14ecdTheodore Ts'o#include <sys/types.h>
15dd60705665b916c9f67c3bbf86aa6bb620a14ecdTheodore Ts'o#include <sys/stat.h>
16f932ed925c3bc8f253240d43c7f8e6edd3aa4d5fMatthias Andree#include <time.h>
17dd60705665b916c9f67c3bbf86aa6bb620a14ecdTheodore Ts'o#include <utime.h>
1844339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o
1944339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o#ifdef HAVE_GETOPT_H
2044339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o#include <getopt.h>
21691d3353c21a9c8c38d57440808ad7a53827b7dcTheodore Ts'o#else
22691d3353c21a9c8c38d57440808ad7a53827b7dcTheodore Ts'oextern char *optarg;
23691d3353c21a9c8c38d57440808ad7a53827b7dcTheodore Ts'oextern int optind;
2444339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o#endif
2544339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o
2644339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o
2744339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'ostruct subst_entry {
2844339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	char *name;
2944339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	char *value;
3044339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	struct subst_entry *next;
3144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o};
3244339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o
3344339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'ostruct subst_entry *subst_table = 0;
3444339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o
3544339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'ostatic int add_subst(char *name, char *value)
3644339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o{
3744339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	struct subst_entry	*ent = 0;
3844339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	int	retval;
39efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
4044339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	retval = ENOMEM;
4145d2161466e32b3e67115951ab1eb7eef25c218aTheodore Ts'o	ent = (struct subst_entry *) malloc(sizeof(struct subst_entry));
4244339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	if (!ent)
4344339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		goto fail;
4445d2161466e32b3e67115951ab1eb7eef25c218aTheodore Ts'o	ent->name = (char *) malloc(strlen(name)+1);
4544339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	if (!ent->name)
4644339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		goto fail;
4745d2161466e32b3e67115951ab1eb7eef25c218aTheodore Ts'o	ent->value = (char *) malloc(strlen(value)+1);
4844339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	if (!ent->value)
4944339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		goto fail;
5044339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	strcpy(ent->name, name);
5144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	strcpy(ent->value, value);
5244339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	ent->next = subst_table;
5344339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	subst_table = ent;
5444339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	return 0;
5544339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'ofail:
5644339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	if (ent) {
5745e338f5332a54295893dba2e32cc093d1316f60Jim Meyering		free(ent->name);
5845e338f5332a54295893dba2e32cc093d1316f60Jim Meyering		free(ent->value);
5944339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		free(ent);
6044339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	}
6144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	return retval;
6244339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o}
6344339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o
6444339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'ostatic struct subst_entry *fetch_subst_entry(char *name)
6544339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o{
6644339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	struct subst_entry *ent;
6744339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o
6844339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	for (ent = subst_table; ent; ent = ent->next) {
6944339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		if (strcmp(name, ent->name) == 0)
7044339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			break;
7144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	}
7244339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	return ent;
7344339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o}
7444339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o
75e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o/*
76e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o * Given the starting and ending position of the replacement name,
77e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o * check to see if it is valid, and pull it out if it is.
78e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o */
79544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'ostatic char *get_subst_symbol(const char *begin, size_t len, char prefix)
80e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o{
81e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	static char replace_name[128];
82e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	char *cp, *start;
83e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o
84e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	start = replace_name;
85e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	if (prefix)
86e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		*start++ = prefix;
87e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o
88e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	if (len > sizeof(replace_name)-2)
89e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		return NULL;
90e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	memcpy(start, begin, len);
91e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	start[len] = 0;
92efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
93e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	/*
947822c1d410a1c6e98f8367de7593ca6e52df1f37Theodore Ts'o	 * The substitution variable must all be in the of [0-9A-Za-z_].
95e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	 * If it isn't, this must be an invalid symbol name.
96e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	 */
97e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	for (cp = start; *cp; cp++) {
98e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		if (!(*cp >= 'a' && *cp <= 'z') &&
99e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		    !(*cp >= 'A' && *cp <= 'Z') &&
1007822c1d410a1c6e98f8367de7593ca6e52df1f37Theodore Ts'o		    !(*cp >= '0' && *cp <= '9') &&
101e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		    !(*cp == '_'))
102e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o			return NULL;
103e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	}
104e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	return (replace_name);
105e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o}
106e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o
107e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'ostatic void replace_string(char *begin, char *end, char *newstr)
108e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o{
109e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	int	replace_len, len;
110e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o
111e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	replace_len = strlen(newstr);
112e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	len = end - begin;
113913c4e9f1445cd8e10b9342def39eee2a29dcfd0Theodore Ts'o	if (replace_len == 0)
114913c4e9f1445cd8e10b9342def39eee2a29dcfd0Theodore Ts'o		memmove(begin, end+1, strlen(end)+1);
115913c4e9f1445cd8e10b9342def39eee2a29dcfd0Theodore Ts'o	else if (replace_len != len+1)
116e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		memmove(end+(replace_len-len-1), end,
117e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o			strlen(end)+1);
118e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	memcpy(begin, newstr, replace_len);
119e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o}
120e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o
12144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'ostatic void substitute_line(char *line)
12244339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o{
123cdceb0496f7ae23f685a409ab070f3431bcad520Theodore Ts'o	char	*ptr, *name_ptr, *end_ptr;
12444339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	struct subst_entry *ent;
125e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	char	*replace_name;
126544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	size_t	len;
12744339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o
128e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	/*
129e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	 * Expand all @FOO@ substitutions
130e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	 */
13144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	ptr = line;
13244339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	while (ptr) {
13344339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		name_ptr = strchr(ptr, '@');
13444339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		if (!name_ptr)
135e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o			break;	/* No more */
136e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		if (*(++name_ptr) == '@') {
137e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o			/*
138e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o			 * Handle tytso@@mit.edu --> tytso@mit.edu
139e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o			 */
140e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o			memmove(name_ptr-1, name_ptr, strlen(name_ptr)+1);
141e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o			ptr = name_ptr+1;
142e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o			continue;
143e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		}
144e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		end_ptr = strchr(name_ptr, '@');
14544339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		if (!end_ptr)
14644339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			break;
147e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		len = end_ptr - name_ptr;
148e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		replace_name = get_subst_symbol(name_ptr, len, 0);
149e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		if (!replace_name) {
150e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o			ptr = name_ptr;
151e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o			continue;
152e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		}
15344339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		ent = fetch_subst_entry(replace_name);
15444339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		if (!ent) {
155efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o			fprintf(stderr, "Unfound expansion: '%s'\n",
15644339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o				replace_name);
15744339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			ptr = end_ptr + 1;
15844339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			continue;
15944339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		}
16044339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o#if 0
16144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		fprintf(stderr, "Replace name = '%s' with '%s'\n",
16244339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		       replace_name, ent->value);
16344339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o#endif
164e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		ptr = name_ptr-1;
165e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		replace_string(ptr, end_ptr, ent->value);
16698224fbc1db8387da1fe0fd1bb3be25c18be2e98Theodore Ts'o		if ((ent->value[0] == '@') &&
16798224fbc1db8387da1fe0fd1bb3be25c18be2e98Theodore Ts'o		    (strlen(replace_name) == strlen(ent->value)-2) &&
168efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o		    !strncmp(replace_name, ent->value+1,
16998224fbc1db8387da1fe0fd1bb3be25c18be2e98Theodore Ts'o			     strlen(ent->value)-2))
17098224fbc1db8387da1fe0fd1bb3be25c18be2e98Theodore Ts'o			/* avoid an infinite loop */
17198224fbc1db8387da1fe0fd1bb3be25c18be2e98Theodore Ts'o			ptr += strlen(ent->value);
172e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	}
173e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	/*
174e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	 * Now do a second pass to expand ${FOO}
175e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	 */
176e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	ptr = line;
177e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	while (ptr) {
178e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		name_ptr = strchr(ptr, '$');
179e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		if (!name_ptr)
180e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o			break;	/* No more */
181e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		if (*(++name_ptr) != '{') {
182e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o			ptr = name_ptr;
183e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o			continue;
184e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		}
185e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		name_ptr++;
186e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		end_ptr = strchr(name_ptr, '}');
187e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		if (!end_ptr)
188e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o			break;
189e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		len = end_ptr - name_ptr;
190e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		replace_name = get_subst_symbol(name_ptr, len, '$');
191e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		if (!replace_name) {
192e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o			ptr = name_ptr;
193e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o			continue;
194efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o		}
195e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		ent = fetch_subst_entry(replace_name);
196e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		if (!ent) {
197e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o			ptr = end_ptr + 1;
198e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o			continue;
199e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		}
200e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o#if 0
201e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		fprintf(stderr, "Replace name = '%s' with '%s'\n",
202e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		       replace_name, ent->value);
203e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o#endif
204e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		ptr = name_ptr-2;
205e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		replace_string(ptr, end_ptr, ent->value);
20644339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	}
20744339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o}
20844339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o
20944339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'ostatic void parse_config_file(FILE *f)
21044339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o{
21144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	char	line[2048];
21244339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	char	*cp, *ptr;
21344339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o
21444339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	while (!feof(f)) {
21544339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		memset(line, 0, sizeof(line));
21644339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		if (fgets(line, sizeof(line), f) == NULL)
21744339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			break;
21844339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		/*
21944339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		 * Strip newlines and comments.
22044339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		 */
22144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		cp = strchr(line, '\n');
22244339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		if (cp)
22344339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			*cp = 0;
22444339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		cp = strchr(line, '#');
22544339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		if (cp)
22644339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			*cp = 0;
22744339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		/*
22844339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		 * Skip trailing and leading whitespace
22944339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		 */
23044339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		for (cp = line + strlen(line) - 1; cp >= line; cp--) {
23144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			if (*cp == ' ' || *cp == '\t')
23244339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o				*cp = 0;
23344339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			else
23444339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o				break;
23544339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		}
23644339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		cp = line;
23744339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		while (*cp && isspace(*cp))
23844339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			cp++;
23944339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		ptr = cp;
24044339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		/*
24144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		 * Skip empty lines
24244339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		 */
24344339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		if (*ptr == 0)
24444339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			continue;
24544339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		/*
24644339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		 * Ignore future extensions
24744339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		 */
248e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		if (*ptr == '@')
24944339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			continue;
25044339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		/*
25144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		 * Parse substitutions
25244339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		 */
25344339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		for (cp = ptr; *cp; cp++)
25444339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			if (isspace(*cp))
25544339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o				break;
25644339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		*cp = 0;
25744339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		for (cp++; *cp; cp++)
25844339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			if (!isspace(*cp))
25944339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o				break;
26044339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o#if 0
261913c4e9f1445cd8e10b9342def39eee2a29dcfd0Theodore Ts'o		printf("Substitute: '%s' for '%s'\n", ptr, cp ? cp : "<NULL>");
26244339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o#endif
26344339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		add_subst(ptr, cp);
26444339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	}
26544339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o}
26644339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o
26744339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o/*
26844339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o * Return 0 if the files are different, 1 if the files are the same.
26944339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o */
27044339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'ostatic int compare_file(const char *outfn, const char *newfn)
27144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o{
27245d2161466e32b3e67115951ab1eb7eef25c218aTheodore Ts'o	FILE	*old_f, *new_f;
27344339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	char	oldbuf[2048], newbuf[2048], *oldcp, *newcp;
27444339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	int	retval;
27544339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o
27645d2161466e32b3e67115951ab1eb7eef25c218aTheodore Ts'o	old_f = fopen(outfn, "r");
27745d2161466e32b3e67115951ab1eb7eef25c218aTheodore Ts'o	if (!old_f)
27844339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		return 0;
27945d2161466e32b3e67115951ab1eb7eef25c218aTheodore Ts'o	new_f = fopen(newfn, "r");
280f1d6a0797b13c1b1c364ab4ee9b500e5455aeeebBrian Behlendorf	if (!new_f) {
281f1d6a0797b13c1b1c364ab4ee9b500e5455aeeebBrian Behlendorf		fclose(old_f);
28244339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		return 0;
283f1d6a0797b13c1b1c364ab4ee9b500e5455aeeebBrian Behlendorf	}
28444339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o
28544339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	while (1) {
28645d2161466e32b3e67115951ab1eb7eef25c218aTheodore Ts'o		oldcp = fgets(oldbuf, sizeof(oldbuf), old_f);
28745d2161466e32b3e67115951ab1eb7eef25c218aTheodore Ts'o		newcp = fgets(newbuf, sizeof(newbuf), new_f);
28844339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		if (!oldcp && !newcp) {
28944339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			retval = 1;
29044339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			break;
29144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		}
29244339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		if (!oldcp || !newcp || strcmp(oldbuf, newbuf)) {
29344339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			retval = 0;
29444339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			break;
29544339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		}
29644339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	}
29745d2161466e32b3e67115951ab1eb7eef25c218aTheodore Ts'o	fclose(old_f);
29845d2161466e32b3e67115951ab1eb7eef25c218aTheodore Ts'o	fclose(new_f);
29944339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	return retval;
30044339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o}
30144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o
30244339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o
30344339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o
30444339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'oint main(int argc, char **argv)
30544339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o{
30644339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	char	line[2048];
30744339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	int	c;
30844339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	FILE	*in, *out;
30944339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	char	*outfn = NULL, *newfn = NULL;
31044339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	int	verbose = 0;
311dd60705665b916c9f67c3bbf86aa6bb620a14ecdTheodore Ts'o	int	adjust_timestamp = 0;
312dd60705665b916c9f67c3bbf86aa6bb620a14ecdTheodore Ts'o	struct stat stbuf;
313dd60705665b916c9f67c3bbf86aa6bb620a14ecdTheodore Ts'o	struct utimbuf ut;
314efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
315dd60705665b916c9f67c3bbf86aa6bb620a14ecdTheodore Ts'o	while ((c = getopt (argc, argv, "f:tv")) != EOF) {
31644339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		switch (c) {
31744339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		case 'f':
31844339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			in = fopen(optarg, "r");
31944339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			if (!in) {
32044339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o				perror(optarg);
32144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o				exit(1);
32244339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			}
32344339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			parse_config_file(in);
32444339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			fclose(in);
32544339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			break;
326dd60705665b916c9f67c3bbf86aa6bb620a14ecdTheodore Ts'o		case 't':
327dd60705665b916c9f67c3bbf86aa6bb620a14ecdTheodore Ts'o			adjust_timestamp++;
328dd60705665b916c9f67c3bbf86aa6bb620a14ecdTheodore Ts'o			break;
32944339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		case 'v':
33044339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			verbose++;
33144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			break;
33244339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		default:
333efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o			fprintf(stderr, "%s: [-f config-file] [file]\n",
33444339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o				argv[0]);
33544339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			break;
33644339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		}
33744339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	}
33844339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	if (optind < argc) {
33944339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		in = fopen(argv[optind], "r");
34044339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		if (!in) {
34144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			perror(argv[optind]);
34244339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			exit(1);
34344339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		}
34444339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		optind++;
34544339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	} else
34644339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		in = stdin;
347efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
34844339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	if (optind < argc) {
34944339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		outfn = argv[optind];
35045d2161466e32b3e67115951ab1eb7eef25c218aTheodore Ts'o		newfn = (char *) malloc(strlen(outfn)+20);
35144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		if (!newfn) {
35244339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			fprintf(stderr, "Memory error!  Exiting.\n");
35344339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			exit(1);
35444339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		}
35544339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		strcpy(newfn, outfn);
35644339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		strcat(newfn, ".new");
35744339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		out = fopen(newfn, "w");
35844339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		if (!out) {
35944339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			perror(newfn);
36044339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			exit(1);
36144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		}
36244339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	} else {
36344339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		out = stdout;
36444339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		outfn = 0;
36544339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	}
366efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
36744339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	while (!feof(in)) {
36844339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		if (fgets(line, sizeof(line), in) == NULL)
36944339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			break;
37044339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		substitute_line(line);
37144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		fputs(line, out);
37244339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	}
37344339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	fclose(in);
37444339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	fclose(out);
37544339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	if (outfn) {
3763f5ef9642bc08bf2a9088a0ec58ec9b0abadf0a6Andreas Dilger		struct stat st;
37744339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		if (compare_file(outfn, newfn)) {
37844339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			if (verbose)
37944339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o				printf("No change, keeping %s.\n", outfn);
380dd60705665b916c9f67c3bbf86aa6bb620a14ecdTheodore Ts'o			if (adjust_timestamp) {
381dd60705665b916c9f67c3bbf86aa6bb620a14ecdTheodore Ts'o				if (stat(outfn, &stbuf) == 0) {
382dd60705665b916c9f67c3bbf86aa6bb620a14ecdTheodore Ts'o					if (verbose)
383dd60705665b916c9f67c3bbf86aa6bb620a14ecdTheodore Ts'o						printf("Updating modtime for %s\n", outfn);
384dd60705665b916c9f67c3bbf86aa6bb620a14ecdTheodore Ts'o					ut.actime = stbuf.st_atime;
385dd60705665b916c9f67c3bbf86aa6bb620a14ecdTheodore Ts'o					ut.modtime = time(0);
386dd60705665b916c9f67c3bbf86aa6bb620a14ecdTheodore Ts'o					if (utime(outfn, &ut) < 0)
387dd60705665b916c9f67c3bbf86aa6bb620a14ecdTheodore Ts'o						perror("utime");
388dd60705665b916c9f67c3bbf86aa6bb620a14ecdTheodore Ts'o				}
389dd60705665b916c9f67c3bbf86aa6bb620a14ecdTheodore Ts'o			}
39044339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			unlink(newfn);
39144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		} else {
39244339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			if (verbose)
39344339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o				printf("Creating or replacing %s.\n", outfn);
39444339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			rename(newfn, outfn);
39544339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		}
3963f5ef9642bc08bf2a9088a0ec58ec9b0abadf0a6Andreas Dilger		/* set read-only to alert user it is a generated file */
3973f5ef9642bc08bf2a9088a0ec58ec9b0abadf0a6Andreas Dilger		if (stat(outfn, &st) == 0)
3983f5ef9642bc08bf2a9088a0ec58ec9b0abadf0a6Andreas Dilger			chmod(outfn, st.st_mode & ~0222);
39944339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	}
40044339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	return (0);
40144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o}
40244339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o
40344339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o
404