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
33e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic struct 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;
38efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
3945d2161466e32b3e67115951ab1eb7eef25c218aTheodore Ts'o	ent = (struct subst_entry *) malloc(sizeof(struct subst_entry));
4044339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	if (!ent)
4144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		goto fail;
4245d2161466e32b3e67115951ab1eb7eef25c218aTheodore Ts'o	ent->name = (char *) malloc(strlen(name)+1);
4344339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	if (!ent->name)
4444339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		goto fail;
4545d2161466e32b3e67115951ab1eb7eef25c218aTheodore Ts'o	ent->value = (char *) malloc(strlen(value)+1);
4644339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	if (!ent->value)
4744339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		goto fail;
4844339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	strcpy(ent->name, name);
4944339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	strcpy(ent->value, value);
5044339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	ent->next = subst_table;
5144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	subst_table = ent;
5244339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	return 0;
5344339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'ofail:
5444339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	if (ent) {
5545e338f5332a54295893dba2e32cc093d1316f60Jim Meyering		free(ent->name);
5644339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		free(ent);
5744339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	}
58e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	return ENOMEM;
5944339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o}
6044339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o
6144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'ostatic struct subst_entry *fetch_subst_entry(char *name)
6244339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o{
6344339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	struct subst_entry *ent;
6444339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o
6544339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	for (ent = subst_table; ent; ent = ent->next) {
6644339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		if (strcmp(name, ent->name) == 0)
6744339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			break;
6844339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	}
6944339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	return ent;
7044339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o}
7144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o
72e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o/*
73e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o * Given the starting and ending position of the replacement name,
74e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o * check to see if it is valid, and pull it out if it is.
75e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o */
76544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'ostatic char *get_subst_symbol(const char *begin, size_t len, char prefix)
77e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o{
78e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	static char replace_name[128];
79e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	char *cp, *start;
80e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o
81e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	start = replace_name;
82e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	if (prefix)
83e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		*start++ = prefix;
84e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o
85e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	if (len > sizeof(replace_name)-2)
86e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		return NULL;
87e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	memcpy(start, begin, len);
88e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	start[len] = 0;
89efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
90e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	/*
917822c1d410a1c6e98f8367de7593ca6e52df1f37Theodore Ts'o	 * The substitution variable must all be in the of [0-9A-Za-z_].
92e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	 * If it isn't, this must be an invalid symbol name.
93e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	 */
94e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	for (cp = start; *cp; cp++) {
95e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		if (!(*cp >= 'a' && *cp <= 'z') &&
96e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		    !(*cp >= 'A' && *cp <= 'Z') &&
977822c1d410a1c6e98f8367de7593ca6e52df1f37Theodore Ts'o		    !(*cp >= '0' && *cp <= '9') &&
98e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		    !(*cp == '_'))
99e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o			return NULL;
100e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	}
101e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	return (replace_name);
102e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o}
103e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o
104e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'ostatic void replace_string(char *begin, char *end, char *newstr)
105e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o{
106e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	int	replace_len, len;
107e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o
108e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	replace_len = strlen(newstr);
109e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	len = end - begin;
110913c4e9f1445cd8e10b9342def39eee2a29dcfd0Theodore Ts'o	if (replace_len == 0)
111913c4e9f1445cd8e10b9342def39eee2a29dcfd0Theodore Ts'o		memmove(begin, end+1, strlen(end)+1);
112913c4e9f1445cd8e10b9342def39eee2a29dcfd0Theodore Ts'o	else if (replace_len != len+1)
113e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		memmove(end+(replace_len-len-1), end,
114e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o			strlen(end)+1);
115e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	memcpy(begin, newstr, replace_len);
116e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o}
117e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o
11844339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'ostatic void substitute_line(char *line)
11944339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o{
120cdceb0496f7ae23f685a409ab070f3431bcad520Theodore Ts'o	char	*ptr, *name_ptr, *end_ptr;
12144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	struct subst_entry *ent;
122e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	char	*replace_name;
123544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	size_t	len;
12444339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o
125e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	/*
126e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	 * Expand all @FOO@ substitutions
127e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	 */
12844339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	ptr = line;
12944339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	while (ptr) {
13044339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		name_ptr = strchr(ptr, '@');
13144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		if (!name_ptr)
132e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o			break;	/* No more */
133e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		if (*(++name_ptr) == '@') {
134e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o			/*
135e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o			 * Handle tytso@@mit.edu --> tytso@mit.edu
136e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o			 */
137e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o			memmove(name_ptr-1, name_ptr, strlen(name_ptr)+1);
138e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o			ptr = name_ptr+1;
139e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o			continue;
140e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		}
141e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		end_ptr = strchr(name_ptr, '@');
14244339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		if (!end_ptr)
14344339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			break;
144e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		len = end_ptr - name_ptr;
145e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		replace_name = get_subst_symbol(name_ptr, len, 0);
146e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		if (!replace_name) {
147e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o			ptr = name_ptr;
148e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o			continue;
149e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		}
15044339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		ent = fetch_subst_entry(replace_name);
15144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		if (!ent) {
152efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o			fprintf(stderr, "Unfound expansion: '%s'\n",
15344339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o				replace_name);
15444339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			ptr = end_ptr + 1;
15544339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			continue;
15644339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		}
15744339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o#if 0
15844339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		fprintf(stderr, "Replace name = '%s' with '%s'\n",
15944339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		       replace_name, ent->value);
16044339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o#endif
161e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		ptr = name_ptr-1;
162e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		replace_string(ptr, end_ptr, ent->value);
16398224fbc1db8387da1fe0fd1bb3be25c18be2e98Theodore Ts'o		if ((ent->value[0] == '@') &&
16498224fbc1db8387da1fe0fd1bb3be25c18be2e98Theodore Ts'o		    (strlen(replace_name) == strlen(ent->value)-2) &&
165efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o		    !strncmp(replace_name, ent->value+1,
16698224fbc1db8387da1fe0fd1bb3be25c18be2e98Theodore Ts'o			     strlen(ent->value)-2))
16798224fbc1db8387da1fe0fd1bb3be25c18be2e98Theodore Ts'o			/* avoid an infinite loop */
16898224fbc1db8387da1fe0fd1bb3be25c18be2e98Theodore Ts'o			ptr += strlen(ent->value);
169e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	}
170e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	/*
171e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	 * Now do a second pass to expand ${FOO}
172e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	 */
173e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	ptr = line;
174e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o	while (ptr) {
175e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		name_ptr = strchr(ptr, '$');
176e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		if (!name_ptr)
177e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o			break;	/* No more */
178e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		if (*(++name_ptr) != '{') {
179e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o			ptr = name_ptr;
180e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o			continue;
181e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		}
182e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		name_ptr++;
183e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		end_ptr = strchr(name_ptr, '}');
184e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		if (!end_ptr)
185e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o			break;
186e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		len = end_ptr - name_ptr;
187e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		replace_name = get_subst_symbol(name_ptr, len, '$');
188e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		if (!replace_name) {
189e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o			ptr = name_ptr;
190e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o			continue;
191efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o		}
192e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		ent = fetch_subst_entry(replace_name);
193e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		if (!ent) {
194e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o			ptr = end_ptr + 1;
195e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o			continue;
196e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		}
197e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o#if 0
198e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		fprintf(stderr, "Replace name = '%s' with '%s'\n",
199e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		       replace_name, ent->value);
200e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o#endif
201e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		ptr = name_ptr-2;
202e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		replace_string(ptr, end_ptr, ent->value);
20344339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	}
20444339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o}
20544339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o
20644339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'ostatic void parse_config_file(FILE *f)
20744339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o{
20844339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	char	line[2048];
20944339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	char	*cp, *ptr;
21044339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o
21144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	while (!feof(f)) {
21244339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		memset(line, 0, sizeof(line));
21344339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		if (fgets(line, sizeof(line), f) == NULL)
21444339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			break;
21544339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		/*
21644339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		 * Strip newlines and comments.
21744339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		 */
21844339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		cp = strchr(line, '\n');
21944339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		if (cp)
22044339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			*cp = 0;
22144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		cp = strchr(line, '#');
22244339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		if (cp)
22344339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			*cp = 0;
22444339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		/*
22544339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		 * Skip trailing and leading whitespace
22644339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		 */
22744339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		for (cp = line + strlen(line) - 1; cp >= line; cp--) {
22844339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			if (*cp == ' ' || *cp == '\t')
22944339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o				*cp = 0;
23044339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			else
23144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o				break;
23244339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		}
23344339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		cp = line;
23444339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		while (*cp && isspace(*cp))
23544339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			cp++;
23644339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		ptr = cp;
23744339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		/*
23844339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		 * Skip empty lines
23944339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		 */
24044339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		if (*ptr == 0)
24144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			continue;
24244339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		/*
24344339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		 * Ignore future extensions
24444339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		 */
245e7549ca6280abe5ab5c1934ecfd7d132c7abeb59Theodore Ts'o		if (*ptr == '@')
24644339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			continue;
24744339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		/*
24844339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		 * Parse substitutions
24944339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		 */
25044339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		for (cp = ptr; *cp; cp++)
25144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			if (isspace(*cp))
25244339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o				break;
25344339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		*cp = 0;
25444339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		for (cp++; *cp; cp++)
25544339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			if (!isspace(*cp))
25644339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o				break;
25744339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o#if 0
258913c4e9f1445cd8e10b9342def39eee2a29dcfd0Theodore Ts'o		printf("Substitute: '%s' for '%s'\n", ptr, cp ? cp : "<NULL>");
25944339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o#endif
26044339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		add_subst(ptr, cp);
26144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	}
26244339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o}
26344339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o
26444339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o/*
26544339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o * Return 0 if the files are different, 1 if the files are the same.
26644339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o */
26744339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'ostatic int compare_file(const char *outfn, const char *newfn)
26844339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o{
26945d2161466e32b3e67115951ab1eb7eef25c218aTheodore Ts'o	FILE	*old_f, *new_f;
27044339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	char	oldbuf[2048], newbuf[2048], *oldcp, *newcp;
27144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	int	retval;
27244339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o
27345d2161466e32b3e67115951ab1eb7eef25c218aTheodore Ts'o	old_f = fopen(outfn, "r");
27445d2161466e32b3e67115951ab1eb7eef25c218aTheodore Ts'o	if (!old_f)
27544339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		return 0;
27645d2161466e32b3e67115951ab1eb7eef25c218aTheodore Ts'o	new_f = fopen(newfn, "r");
277f1d6a0797b13c1b1c364ab4ee9b500e5455aeeebBrian Behlendorf	if (!new_f) {
278f1d6a0797b13c1b1c364ab4ee9b500e5455aeeebBrian Behlendorf		fclose(old_f);
27944339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		return 0;
280f1d6a0797b13c1b1c364ab4ee9b500e5455aeeebBrian Behlendorf	}
28144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o
28244339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	while (1) {
28345d2161466e32b3e67115951ab1eb7eef25c218aTheodore Ts'o		oldcp = fgets(oldbuf, sizeof(oldbuf), old_f);
28445d2161466e32b3e67115951ab1eb7eef25c218aTheodore Ts'o		newcp = fgets(newbuf, sizeof(newbuf), new_f);
28544339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		if (!oldcp && !newcp) {
28644339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			retval = 1;
28744339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			break;
28844339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		}
28944339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		if (!oldcp || !newcp || strcmp(oldbuf, newbuf)) {
29044339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			retval = 0;
29144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			break;
29244339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		}
29344339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	}
29445d2161466e32b3e67115951ab1eb7eef25c218aTheodore Ts'o	fclose(old_f);
29545d2161466e32b3e67115951ab1eb7eef25c218aTheodore Ts'o	fclose(new_f);
29644339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	return retval;
29744339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o}
29844339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o
29944339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o
30044339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o
30144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'oint main(int argc, char **argv)
30244339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o{
30344339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	char	line[2048];
30444339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	int	c;
30544339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	FILE	*in, *out;
30644339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	char	*outfn = NULL, *newfn = NULL;
30744339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	int	verbose = 0;
308dd60705665b916c9f67c3bbf86aa6bb620a14ecdTheodore Ts'o	int	adjust_timestamp = 0;
309dd60705665b916c9f67c3bbf86aa6bb620a14ecdTheodore Ts'o	struct stat stbuf;
310dd60705665b916c9f67c3bbf86aa6bb620a14ecdTheodore Ts'o	struct utimbuf ut;
311efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
312dd60705665b916c9f67c3bbf86aa6bb620a14ecdTheodore Ts'o	while ((c = getopt (argc, argv, "f:tv")) != EOF) {
31344339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		switch (c) {
31444339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		case 'f':
31544339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			in = fopen(optarg, "r");
31644339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			if (!in) {
31744339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o				perror(optarg);
31844339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o				exit(1);
31944339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			}
32044339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			parse_config_file(in);
32144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			fclose(in);
32244339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			break;
323dd60705665b916c9f67c3bbf86aa6bb620a14ecdTheodore Ts'o		case 't':
324dd60705665b916c9f67c3bbf86aa6bb620a14ecdTheodore Ts'o			adjust_timestamp++;
325dd60705665b916c9f67c3bbf86aa6bb620a14ecdTheodore Ts'o			break;
32644339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		case 'v':
32744339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			verbose++;
32844339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			break;
32944339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		default:
330efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o			fprintf(stderr, "%s: [-f config-file] [file]\n",
33144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o				argv[0]);
33244339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			break;
33344339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		}
33444339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	}
33544339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	if (optind < argc) {
33644339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		in = fopen(argv[optind], "r");
33744339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		if (!in) {
33844339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			perror(argv[optind]);
33944339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			exit(1);
34044339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		}
34144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		optind++;
34244339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	} else
34344339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		in = stdin;
344efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
34544339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	if (optind < argc) {
34644339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		outfn = argv[optind];
34745d2161466e32b3e67115951ab1eb7eef25c218aTheodore Ts'o		newfn = (char *) malloc(strlen(outfn)+20);
34844339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		if (!newfn) {
34944339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			fprintf(stderr, "Memory error!  Exiting.\n");
35044339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			exit(1);
35144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		}
35244339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		strcpy(newfn, outfn);
35344339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		strcat(newfn, ".new");
35444339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		out = fopen(newfn, "w");
35544339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		if (!out) {
35644339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			perror(newfn);
35744339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			exit(1);
35844339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		}
35944339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	} else {
36044339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		out = stdout;
36144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		outfn = 0;
36244339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	}
363efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
36444339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	while (!feof(in)) {
36544339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		if (fgets(line, sizeof(line), in) == NULL)
36644339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			break;
36744339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		substitute_line(line);
36844339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		fputs(line, out);
36944339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	}
37044339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	fclose(in);
37144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	fclose(out);
37244339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	if (outfn) {
3733f5ef9642bc08bf2a9088a0ec58ec9b0abadf0a6Andreas Dilger		struct stat st;
37444339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		if (compare_file(outfn, newfn)) {
37544339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			if (verbose)
37644339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o				printf("No change, keeping %s.\n", outfn);
377dd60705665b916c9f67c3bbf86aa6bb620a14ecdTheodore Ts'o			if (adjust_timestamp) {
378dd60705665b916c9f67c3bbf86aa6bb620a14ecdTheodore Ts'o				if (stat(outfn, &stbuf) == 0) {
379dd60705665b916c9f67c3bbf86aa6bb620a14ecdTheodore Ts'o					if (verbose)
380dd60705665b916c9f67c3bbf86aa6bb620a14ecdTheodore Ts'o						printf("Updating modtime for %s\n", outfn);
381dd60705665b916c9f67c3bbf86aa6bb620a14ecdTheodore Ts'o					ut.actime = stbuf.st_atime;
382dd60705665b916c9f67c3bbf86aa6bb620a14ecdTheodore Ts'o					ut.modtime = time(0);
383dd60705665b916c9f67c3bbf86aa6bb620a14ecdTheodore Ts'o					if (utime(outfn, &ut) < 0)
384dd60705665b916c9f67c3bbf86aa6bb620a14ecdTheodore Ts'o						perror("utime");
385dd60705665b916c9f67c3bbf86aa6bb620a14ecdTheodore Ts'o				}
386dd60705665b916c9f67c3bbf86aa6bb620a14ecdTheodore Ts'o			}
38744339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			unlink(newfn);
38844339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		} else {
38944339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			if (verbose)
39044339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o				printf("Creating or replacing %s.\n", outfn);
39144339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o			rename(newfn, outfn);
39244339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o		}
3933f5ef9642bc08bf2a9088a0ec58ec9b0abadf0a6Andreas Dilger		/* set read-only to alert user it is a generated file */
3943f5ef9642bc08bf2a9088a0ec58ec9b0abadf0a6Andreas Dilger		if (stat(outfn, &st) == 0)
3953f5ef9642bc08bf2a9088a0ec58ec9b0abadf0a6Andreas Dilger			chmod(outfn, st.st_mode & ~0222);
39644339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	}
39744339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o	return (0);
39844339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o}
39944339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o
40044339bdff87584b72a2ade7d3a1426e3335f2167Theodore Ts'o
401